mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
---
|
||||
description: "SnapOtter की मोनोरेपो संरचना, ऐप और पैकेज आर्किटेक्चर, अनुरोध जीवनचक्र, और संसाधन फ़ुटप्रिंट।"
|
||||
i18n_source_hash: 9e8f80499a37
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: c218fe161fec
|
||||
---
|
||||
|
||||
# Architecture {#architecture}
|
||||
|
||||
SnapOtter एक मोनोरेपो है जिसे pnpm workspaces और Turborepo के साथ प्रबंधित किया जाता है। यह एक 3-कंटेनर Docker Compose स्टैक के रूप में परिनियोजित होता है: SnapOtter ऐप इमेज, PostgreSQL 17, और Redis 8।
|
||||
|
||||
## Project structure {#project-structure}
|
||||
|
||||
```
|
||||
snapotter/
|
||||
├── apps/
|
||||
│ ├── api/ # Fastify backend
|
||||
│ ├── web/ # React + Vite frontend
|
||||
│ └── docs/ # This VitePress site
|
||||
├── packages/
|
||||
│ ├── image-engine/ # Sharp-based image operations
|
||||
│ ├── media-engine/ # FFmpeg spawn + progress parsing
|
||||
│ ├── doc-engine/ # qpdf, LibreOffice, ghostscript wrappers
|
||||
│ ├── ai/ # Python AI model bridge
|
||||
│ └── shared/ # Types, constants, i18n
|
||||
└── docker/ # Dockerfile and Compose config
|
||||
```
|
||||
|
||||
## Packages {#packages}
|
||||
|
||||
### `@snapotter/image-engine` {#snapotter-image-engine}
|
||||
|
||||
[Sharp](https://sharp.pixelplumbing.com/) पर बनी मुख्य इमेज प्रोसेसिंग लाइब्रेरी। यह सभी नॉन-AI ऑपरेशन संभालती है: resize, crop, rotate, flip, convert, compress, strip metadata, और रंग समायोजन (brightness, contrast, saturation, grayscale, sepia, invert, color channels)।
|
||||
|
||||
इस पैकेज की कोई नेटवर्क डिपेंडेंसी नहीं है और यह पूरी तरह इन-प्रोसेस चलता है।
|
||||
|
||||
### `@snapotter/ai` {#snapotter-ai}
|
||||
|
||||
एक ब्रिज लेयर जो ML ऑपरेशन के लिए Python स्क्रिप्ट को कॉल करती है। पहले उपयोग पर, ब्रिज एक स्थायी Python डिस्पैचर प्रक्रिया शुरू करता है जो भारी लाइब्रेरी (PIL, NumPy, MediaPipe, rembg) को पहले से इम्पोर्ट कर लेता है ताकि बाद के AI कॉल इम्पोर्ट ओवरहेड को छोड़ दें। यदि डिस्पैचर अभी तैयार नहीं है, तो ब्रिज प्रति अनुरोध एक नई Python सबप्रोसेस स्पॉन करने पर वापस लौट आता है।
|
||||
|
||||
**मॉडल पहले से लोड नहीं होते।** प्रत्येक टूल स्क्रिप्ट अनुरोध के समय डिस्क से अपने मॉडल वेट लोड करती है और अनुरोध समाप्त होने पर उन्हें त्याग देती है। पूर्ण मेमोरी प्रोफ़ाइल के लिए [Resource footprint](#resource-footprint) देखें।
|
||||
|
||||
समर्थित ऑपरेशन: बैकग्राउंड हटाना (rembg/BiRefNet), अपस्केलिंग (RealESRGAN), चेहरा धुंधला करना (MediaPipe), चेहरा सुधार (GFPGAN/CodeFormer), ऑब्जेक्ट मिटाना (LaMa ONNX), OCR (PaddleOCR/Tesseract), कलराइज़ेशन (DDColor), नॉइज़ हटाना, रेड आई हटाना, फ़ोटो रीस्टोरेशन, पासपोर्ट फ़ोटो जनरेशन, पारदर्शिता फ़िक्सिंग (BiRefNet HR-matting), और कंटेंट-अवेयर रीसाइज़ (Go caire बाइनरी)।
|
||||
|
||||
Python स्क्रिप्ट `packages/ai/python/` में रहती हैं। Docker इमेज बिल्ड के दौरान सभी मॉडल वेट पूर्व-डाउनलोड कर लेती है ताकि कंटेनर पूरी तरह ऑफ़लाइन काम करे।
|
||||
|
||||
### `@snapotter/shared` {#snapotter-shared}
|
||||
|
||||
साझा TypeScript प्रकार, स्थिरांक (जैसे `APP_VERSION` और टूल परिभाषाएँ), और i18n अनुवाद स्ट्रिंग्स जो फ़्रंटएंड और बैकएंड दोनों द्वारा उपयोग की जाती हैं।
|
||||
|
||||
## Applications {#applications}
|
||||
|
||||
### API (`apps/api`) {#api-apps-api}
|
||||
|
||||
एक Fastify v5 सर्वर जो पाँच मोडैलिटी (image, video, audio, PDF, file) में 241 टूल रूट प्रकट करता है, जो निम्न को संभालता है:
|
||||
- फ़ाइल अपलोड, अस्थायी वर्कस्पेस प्रबंधन, और स्थायी फ़ाइल स्टोरेज
|
||||
- संस्करण श्रृंखलाओं के साथ उपयोगकर्ता फ़ाइल लाइब्रेरी (`user_files` तालिका) - प्रत्येक प्रोसेस किया गया परिणाम अपनी स्रोत फ़ाइल से वापस लिंक होता है और रिकॉर्ड करता है कि कौन सा टूल लागू किया गया था, Files पेज के लिए स्वतः-जनरेट किए गए थंबनेल के साथ
|
||||
- टूल निष्पादन (प्रत्येक टूल अनुरोध को इमेज इंजन या AI ब्रिज पर रूट करता है)
|
||||
- पाइपलाइन ऑर्केस्ट्रेशन (कई टूल को क्रमिक रूप से श्रृंखलाबद्ध करना)
|
||||
- BullMQ जॉब क्यू के माध्यम से समवर्तीता नियंत्रण के साथ बैच प्रोसेसिंग (पूल: image, media, ai, docs, system)
|
||||
- उपयोगकर्ता प्रमाणीकरण, RBAC (पूर्ण अनुमति सेट के साथ admin/user भूमिकाएँ), API कुंजी प्रबंधन, और रेट लिमिटिंग
|
||||
- Teams प्रबंधन - केवल-admin CRUD; उपयोगकर्ताओं को उनके प्रोफ़ाइल पर `team` फ़ील्ड के माध्यम से एक टीम को सौंपा जाता है
|
||||
- रनटाइम सेटिंग्स - `settings` तालिका में एक key-value स्टोर जो पुनः परिनियोजन के बिना `disabledTools`, `enableExperimentalTools`, `loginAttemptLimit`, और अन्य परिचालन नियंत्रण संभालता है
|
||||
- डेटाबेस-समर्थित सेटिंग्स के माध्यम से कस्टम ब्रांडिंग और रनटाइम प्राथमिकताएँ
|
||||
- `/api/docs` पर Scalar/OpenAPI दस्तावेज़ीकरण
|
||||
- प्रोडक्शन में निर्मित फ़्रंटएंड को एक SPA के रूप में सर्व करना
|
||||
|
||||
मुख्य डिपेंडेंसी: Fastify, Drizzle ORM (pg-core, node-postgres), Sharp, BullMQ, ioredis, सत्यापन के लिए Zod।
|
||||
|
||||
सर्वर SIGTERM/SIGINT पर सुशोभित शटडाउन संभालता है: यह HTTP कनेक्शन को खाली करता है, BullMQ वर्कर को रोकता है, Python डिस्पैचर को बंद करता है, और डेटाबेस कनेक्शन बंद करता है।
|
||||
|
||||
### Web (`apps/web`) {#web-apps-web}
|
||||
|
||||
Vite के साथ बनाया गया एक React 19 सिंगल-पेज ऐप। स्टेट प्रबंधन के लिए Zustand, स्टाइलिंग के लिए Tailwind CSS v4, और आइकन के लिए Lucide का उपयोग करता है। REST और SSE (प्रगति ट्रैकिंग के लिए) पर API के साथ संवाद करता है।
|
||||
|
||||
पेजों में एक टूल वर्कस्पेस, स्थायी अपलोड और परिणामों के प्रबंधन के लिए एक Files पेज, एक ऑटोमेशन/पाइपलाइन बिल्डर, और एक admin सेटिंग्स पैनल शामिल हैं।
|
||||
|
||||
निर्मित फ़्रंटएंड प्रोडक्शन में Fastify बैकएंड द्वारा सर्व किया जाता है, इसलिए Docker कंटेनर में कोई अलग वेब सर्वर नहीं है।
|
||||
|
||||
### Docs (`apps/docs`) {#docs-apps-docs}
|
||||
|
||||
यह VitePress साइट। `main` पर पुश होने पर स्वचालित रूप से Cloudflare Pages पर परिनियोजित।
|
||||
|
||||
## How a request flows {#how-a-request-flows}
|
||||
|
||||
1. उपयोगकर्ता वेब UI में एक टूल चुनता है और एक फ़ाइल अपलोड करता है।
|
||||
2. फ़्रंटएंड फ़ाइल और सेटिंग्स के साथ `/api/v1/tools/:section/:toolId` पर एक multipart POST भेजता है।
|
||||
3. API रूट इनपुट को Zod के साथ सत्यापित करता है, फिर प्रोसेसिंग डिस्पैच करता है।
|
||||
4. मानक टूल के लिए, जॉब को उपयुक्त BullMQ पूल (मोडैलिटी के आधार पर image, media, या docs) में क्यू में डाला जाता है। इन-प्रोसेस BullMQ वर्कर EXIF मेटाडेटा के आधार पर इमेज को स्वतः-ओरिएंट करता है, टूल के प्रोसेस फ़ंक्शन को चलाता है, और परिणाम लौटाता है।
|
||||
5. AI टूल के लिए, TypeScript ब्रिज स्थायी Python डिस्पैचर को एक अनुरोध भेजता है (या फ़ॉलबैक के रूप में एक नई सबप्रोसेस स्पॉन करता है), इसके समाप्त होने की प्रतीक्षा करता है, और आउटपुट फ़ाइल पढ़ता है।
|
||||
6. जॉब प्रगति PostgreSQL में `jobs` तालिका में बनी रहती है ताकि स्टेट कंटेनर पुनरारंभ के दौरान बना रहे। वास्तविक समय अपडेट `/api/v1/jobs/:jobId/progress` पर SSE के माध्यम से वितरित किए जाते हैं।
|
||||
7. API एक `jobId` और `downloadUrl` लौटाता है। उपयोगकर्ता `/api/v1/download/:jobId/:filename` से प्रोसेस की गई फ़ाइल डाउनलोड करता है।
|
||||
|
||||
पाइपलाइनों के लिए, API प्रत्येक चरण के आउटपुट को अगले के इनपुट के रूप में फ़ीड करता है, उन्हें क्रमिक रूप से चलाता है।
|
||||
|
||||
बैच प्रोसेसिंग के लिए, API प्रति-चरण चाइल्ड जॉब के साथ BullMQ फ़्लो का उपयोग करता है और सभी प्रोसेस की गई फ़ाइलों के साथ एक ZIP फ़ाइल लौटाता है।
|
||||
|
||||
## Resource footprint {#resource-footprint}
|
||||
|
||||
SnapOtter को कम निष्क्रिय मेमोरी उपयोग के लिए डिज़ाइन किया गया है। स्टार्टअप पर कुछ भी पहले से लोड या गर्म नहीं रखा जाता।
|
||||
|
||||
### At idle {#at-idle}
|
||||
|
||||
Node.js/Fastify प्रक्रिया, PostgreSQL, और Redis चल रहे हैं। सामान्य निष्क्रिय RAM तीनों कंटेनरों में **~200-300 MB** है (Node.js प्रक्रिया, Postgres, और Redis)। कोई Python प्रक्रिया नहीं, मेमोरी में कोई मॉडल वेट नहीं।
|
||||
|
||||
### What starts, and when {#what-starts-and-when}
|
||||
|
||||
| घटक | कब शुरू होता है | सक्रिय रहते समय मेमोरी |
|
||||
|-----------|-------------|---------------------|
|
||||
| Fastify सर्वर + Postgres + Redis | कंटेनर शुरू | कुल ~200-300 MB |
|
||||
| BullMQ वर्कर | कंटेनर शुरू (इन-प्रोसेस) | प्रति पूल एक वर्कर (image, media, ai, docs, system) |
|
||||
| Python डिस्पैचर | पहला AI टूल अनुरोध | Python इंटरप्रेटर + पूर्व-इम्पोर्ट की गई लाइब्रेरी (PIL, NumPy, MediaPipe, rembg) - कोई मॉडल वेट नहीं |
|
||||
| AI मॉडल वेट | विशिष्ट टूल के अनुरोध के दौरान | डिस्क से लोड, अनुरोध समाप्त होने पर मुक्त |
|
||||
|
||||
### Model loading {#model-loading}
|
||||
|
||||
सभी मॉडल वेट फ़ाइलें (कुल मिलाकर कई GB) हर समय `/opt/models/` में डिस्क पर रहती हैं। प्रत्येक AI टूल स्क्रिप्ट केवल अपने स्वयं के मॉडल को एक अनुरोध की अवधि के लिए मेमोरी में लोड करती है, फिर उन्हें रिलीज़ कर देती है। कुछ स्क्रिप्ट इंफ़रेंस के बाद स्पष्ट रूप से `del model` और `torch.cuda.empty_cache()` को कॉल करती हैं ताकि यह सुनिश्चित हो सके कि मेमोरी तुरंत वापस दी जाए।
|
||||
|
||||
अनुरोधों के बीच कोई मॉडल कैश नहीं है। एक ही AI टूल को लगातार चलाने से हर बार मॉडल फिर से लोड होता है। यह हर AI अनुरोध पर एक मॉडल-लोड विलंब की कीमत पर निष्क्रिय मेमोरी को शून्य के करीब रखता है।
|
||||
|
||||
### First AI request cold start {#first-ai-request-cold-start}
|
||||
|
||||
जब कंटेनर शुरू होता है तो Python डिस्पैचर नहीं चल रहा होता। पहला AI अनुरोध समानांतर में दो चीज़ें ट्रिगर करता है: डिस्पैचर बैकग्राउंड में गर्म होना शुरू होता है, और अनुरोध स्वयं एक बार की Python सबप्रोसेस स्पॉन पर वापस लौट आता है। एक बार डिस्पैचर तैयार होने का संकेत देता है, तो बाद के सभी AI अनुरोध सीधे इसका उपयोग करते हैं और सबप्रोसेस स्पॉन लागत को छोड़ देते हैं।
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
description: "सभी SnapOtter एनवायरनमेंट वेरिएबल्स डिफ़ॉल्ट के साथ। auth, स्टोरेज, AI मॉडल, एनालिटिक्स, और अधिक कॉन्फ़िगर करें।"
|
||||
i18n_source_hash: 8e9e9ca2840c
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 6de48963490c
|
||||
---
|
||||
|
||||
# Configuration {#configuration}
|
||||
|
||||
सभी कॉन्फ़िगरेशन एनवायरनमेंट वेरिएबल्स के माध्यम से किया जाता है। हर वेरिएबल का एक उचित डिफ़ॉल्ट होता है, इसलिए SnapOtter उनमें से किसी को सेट किए बिना बॉक्स से बाहर काम करता है।
|
||||
|
||||
## Environment variables {#environment-variables}
|
||||
|
||||
### Server {#server}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `PORT` | `1349` | सर्वर जिस पोर्ट पर सुनता है। |
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | प्रति IP प्रति मिनट अधिकतम अनुरोध। रेट लिमिटिंग अक्षम करने के लिए 0 पर सेट करें। |
|
||||
| `CORS_ORIGIN` | (empty) | CORS के लिए अल्पविराम-पृथक अनुमत मूल, या केवल-समान-मूल के लिए खाली। |
|
||||
| `LOG_LEVEL` | `info` | लॉग वर्बोसिटी। इनमें से एक: `fatal`, `error`, `warn`, `info`, `debug`, `trace`। |
|
||||
| `TRUST_PROXY` | `true` | एक रिवर्स प्रॉक्सी से `X-Forwarded-For` हेडर पर भरोसा करें। यदि प्रॉक्सी के पीछे नहीं है तो `false` पर सेट करें। |
|
||||
|
||||
### Authentication {#authentication}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `AUTH_ENABLED` | `false` | लॉगिन की आवश्यकता के लिए `true` पर सेट करें। Docker इमेज `true` पर डिफ़ॉल्ट होती है। |
|
||||
| `DEFAULT_USERNAME` | `admin` | प्रारंभिक admin अकाउंट के लिए उपयोगकर्ता नाम। केवल पहली बार चलने पर उपयोग किया जाता है। |
|
||||
| `DEFAULT_PASSWORD` | `admin` | प्रारंभिक admin अकाउंट के लिए पासवर्ड। पहली बार लॉगिन के बाद इसे बदलें। |
|
||||
| `MAX_USERS` | `0` (unlimited) | पंजीकृत उपयोगकर्ता अकाउंट की अधिकतम संख्या। असीमित के लिए 0 पर सेट करें। |
|
||||
| `SESSION_DURATION_HOURS` | `168` | घंटों में लॉगिन सत्र जीवनकाल (डिफ़ॉल्ट 7 दिन है)। |
|
||||
| `SKIP_MUST_CHANGE_PASSWORD` | - | पहली बार लॉगिन पर बाध्य पासवर्ड-परिवर्तन प्रॉम्प्ट को बायपास करने के लिए किसी भी गैर-खाली मान पर सेट करें |
|
||||
|
||||
### Storage {#storage}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `STORAGE_MODE` | `local` | `local` या `s3`। S3/MinIO के लिए s3_storage फ़ीचर वाले लाइसेंस की आवश्यकता होती है। |
|
||||
| `DATABASE_URL` | `postgres://snapotter:snapotter@postgres:5432/snapotter` | PostgreSQL कनेक्शन स्ट्रिंग। |
|
||||
| `REDIS_URL` | `redis://redis:6379` | Redis कनेक्शन स्ट्रिंग (BullMQ जॉब क्यू के लिए उपयोग की जाती है)। |
|
||||
| `WORKSPACE_PATH` | `./tmp/workspace` | प्रोसेसिंग के दौरान अस्थायी फ़ाइलों के लिए डायरेक्टरी। स्वचालित रूप से साफ़ की जाती है। |
|
||||
| `FILES_STORAGE_PATH` | `./data/files` | स्थायी उपयोगकर्ता फ़ाइलों (अपलोड की गई इमेज, सहेजे गए परिणाम) के लिए डायरेक्टरी। |
|
||||
|
||||
### Embedded mode {#embedded-mode}
|
||||
|
||||
इमेज को बिना किसी `DATABASE_URL` और बिना किसी `REDIS_URL` के चलाएँ और यह कंटेनर के अंदर अपना स्वयं का PostgreSQL 17 और Redis शुरू करता है, जो लूपबैक से बंधा हुआ है, सारा डेटा `/data` वॉल्यूम पर। यह त्वरित शुरुआत, होमलैब, और 1.x से अपग्रेड के लिए एकल-कमांड `docker run` अनुभव को बहाल करता है। यह एक सुविधा पथ है, न कि एक प्रोडक्शन परिनियोजन: प्रोडक्शन के लिए, अलग PostgreSQL और Redis के साथ 3-कंटेनर Compose स्टैक चलाएँ। Embedded मोड को कंटेनर को रूट के रूप में चलाने की आवश्यकता होती है और यह मनमाने-UID रनटाइम (OpenShift, Kubernetes `runAsNonRoot`) के साथ असंगत है; वहाँ Compose का उपयोग करें।
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `EMBEDDED` | `auto` | तब स्वतः-सक्षम होता है जब `DATABASE_URL` और `REDIS_URL` दोनों अनसेट हों। इसे अक्षम करने के लिए `0` पर सेट करें (तब ऐप तेज़ी से विफल हो जाता है यदि कोई बाहरी `DATABASE_URL`/`REDIS_URL` सेट नहीं है, बजाय चुपचाप एक इन-कंटेनर डेटाबेस शुरू करने के)। |
|
||||
| `REDIS_MAXMEMORY` | `512mb` | एम्बेडेड Redis के लिए मेमोरी कैप (केवल embedded मोड)। Raspberry Pi जैसे मेमोरी-सीमित होस्ट पर इसे कम करें। |
|
||||
|
||||
1.x से अपग्रेड करना: अपनी पुरानी `snapotter.db` को वॉल्यूम में `/data/snapotter.db` पर रखें और embedded मोड इसे पहली बार बूट होने पर एम्बेडेड PostgreSQL में आयात करता है। आयात एक बार चलता है; बाद के बूट इसे छोड़ देते हैं।
|
||||
|
||||
टेलीमेट्री नोट: embedded मोड किसी भी अन्य कॉन्फ़िगरेशन की तरह इमेज के एनालिटिक्स डिफ़ॉल्ट को विरासत में लेता है। प्रकाशित इमेज एनालिटिक्स चालू के साथ शिप होती है; इसे अक्षम करने के लिए `--build-arg SNAPOTTER_ANALYTICS=off` के साथ बिल्ड करें, या इन-ऐप admin ऑप्ट-आउट का उपयोग करें।
|
||||
|
||||
### Processing limits {#processing-limits}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | मेगाबाइट में प्रति अपलोड अधिकतम फ़ाइल आकार। असीमित के लिए 0 पर सेट करें। |
|
||||
| `MAX_BATCH_SIZE` | `100` | एकल बैच अनुरोध में फ़ाइलों की अधिकतम संख्या। असीमित के लिए 0 पर सेट करें। |
|
||||
| `CONCURRENT_JOBS` | `0` (auto) | समानांतर में चलने वाले बैच जॉब की संख्या। उपलब्ध CPU कोर के आधार पर स्वतः-पहचान के लिए 0 पर सेट करें। |
|
||||
| `MAX_MEGAPIXELS` | `0` (unlimited) | मेगापिक्सेल में अनुमत अधिकतम इमेज रिज़ॉल्यूशन। असीमित के लिए 0 पर सेट करें। |
|
||||
| `MAX_WORKER_THREADS` | `0` (auto) | इमेज प्रोसेसिंग के लिए अधिकतम वर्कर थ्रेड। उपलब्ध CPU कोर के आधार पर स्वतः-पहचान के लिए 0 पर सेट करें। |
|
||||
| `PROCESSING_TIMEOUT_S` | `0` (no limit) | सेकंड में प्रति अनुरोध अधिकतम प्रोसेसिंग समय। बिना टाइमआउट के लिए 0 पर सेट करें। |
|
||||
| `MAX_PIPELINE_STEPS` | `20` | एक पाइपलाइन में अधिकतम चरणों की संख्या। बिना सीमा के लिए 0 पर सेट करें। |
|
||||
| `MAX_CANVAS_PIXELS` | `0` (no limit) | आउटपुट इमेज के लिए पिक्सेल में अधिकतम कैनवास आकार। बिना सीमा के लिए 0 पर सेट करें। |
|
||||
| `MAX_SVG_SIZE_MB` | `0` (unlimited) | मेगाबाइट में अधिकतम SVG फ़ाइल आकार। असीमित के लिए 0 पर सेट करें। |
|
||||
| `MAX_SPLIT_GRID` | `100` | इमेज स्प्लिट टूल के लिए अधिकतम ग्रिड आयाम। |
|
||||
| `MAX_PDF_PAGES` | `0` (unlimited) | PDF-to-image रूपांतरण के लिए PDF पृष्ठों की अधिकतम संख्या। असीमित के लिए 0 पर सेट करें। |
|
||||
|
||||
### Cleanup {#cleanup}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `FILE_MAX_AGE_HOURS` | `72` | बिना सहेजे प्रोसेसिंग परिणाम (कच्चे अपलोड और टूल आउटपुट) स्वचालित हटाने से पहले कितने समय तक रखे जाते हैं। जिन फ़ाइलों को आप स्पष्ट रूप से Files लाइब्रेरी में सहेजते हैं वे प्रभावित नहीं होतीं और तब तक बनी रहती हैं जब तक आप उन्हें हटा नहीं देते। |
|
||||
| `CLEANUP_INTERVAL_MINUTES` | `60` | क्लीनअप जॉब कितनी बार चलता है। |
|
||||
|
||||
### Appearance {#appearance}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `DEFAULT_THEME` | `light` | नए सत्रों के लिए डिफ़ॉल्ट थीम। `light` या `dark`। |
|
||||
| `DEFAULT_LOCALE` | `en` | डिफ़ॉल्ट इंटरफ़ेस भाषा। |
|
||||
| `DEFAULT_TOOL_VIEW` | `sidebar` | डिफ़ॉल्ट टूल लेआउट। `sidebar` या `fullscreen`। |
|
||||
|
||||
### Docker permissions {#docker-permissions}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `PUID` | `999` | कंटेनर प्रक्रिया को इस UID के रूप में चलाएँ। बाइंड माउंट के लिए अपने होस्ट उपयोगकर्ता से मिलान करने के लिए सेट करें (`id -u`)। |
|
||||
| `PGID` | `999` | कंटेनर प्रक्रिया को इस GID के रूप में चलाएँ। बाइंड माउंट के लिए अपने होस्ट समूह से मिलान करने के लिए सेट करें (`id -g`)। |
|
||||
|
||||
## Docker example {#docker-example}
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
ports:
|
||||
- "1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=changeme
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MAX_UPLOAD_SIZE_MB=200
|
||||
- CONCURRENT_JOBS=4
|
||||
- FILE_MAX_AGE_HOURS=12
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
## Volumes {#volumes}
|
||||
|
||||
Docker Compose स्टैक चार वॉल्यूम का उपयोग करता है:
|
||||
|
||||
- `/data` (app) - AI मॉडल, Python venv, और उपयोगकर्ता फ़ाइलें। अपलोड की गई फ़ाइलों और इंस्टॉल किए गए AI बंडलों को पुनरारंभ के दौरान रखने के लिए इसे माउंट करें।
|
||||
- `/tmp/workspace` (app) - प्रोसेस की जा रही फ़ाइलों के लिए अस्थायी स्टोरेज। यह क्षणिक हो सकता है, लेकिन इसे माउंट करने से कंटेनर की लिखने योग्य लेयर भरने से बचती है।
|
||||
- `SnapOtter-pgdata` (postgres) - PostgreSQL डेटा डायरेक्टरी। यह सभी रिलेशनल डेटा (users, settings, pipelines, jobs, audit log) रखती है। `pg_dump` या वॉल्यूम स्नैपशॉट के माध्यम से बैकअप लें।
|
||||
- `SnapOtter-redisdata` (redis) - टिकाऊ जॉब क्यू के लिए Redis append-only फ़ाइल।
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
description: "SnapOtter में योगदान कैसे करें। बग रिपोर्ट, फ़ीचर अनुरोध, पुल रिक्वेस्ट और CLA आवश्यकताएँ।"
|
||||
i18n_source_hash: 528802503035
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: cf867a422a1c
|
||||
---
|
||||
|
||||
# योगदान {#contributing}
|
||||
|
||||
योगदान में आपकी रुचि के लिए धन्यवाद। यह गाइड बताती है कि आप कैसे भाग ले सकते हैं, हम क्या स्वीकार करते हैं और शुरुआत कैसे करें।
|
||||
|
||||
## योगदान के तरीके {#ways-to-contribute}
|
||||
|
||||
### इशू (किसी सेटअप की आवश्यकता नहीं) {#issues-no-setup-required}
|
||||
|
||||
- **बग रिपोर्ट** - कुछ टूट गया है? पुनरुत्पादन के चरणों के साथ एक [बग रिपोर्ट](https://github.com/snapotter-hq/snapotter/issues/new?template=bug_report.yml) खोलें।
|
||||
- **फ़ीचर अनुरोध** - कोई विचार है? एक [चर्चा](https://github.com/snapotter-hq/snapotter/discussions/new?category=ideas) शुरू करें ताकि समुदाय अपनी राय दे सके और उसे अपवोट कर सके।
|
||||
- **अनुवाद इशू** - कोई गलत या अनुपलब्ध अनुवाद दिखा? एक [अनुवाद इशू](https://github.com/snapotter-hq/snapotter/issues/new?template=translation.yml) खोलें।
|
||||
- **दस्तावेज़ीकरण इशू** - डॉक्स में कुछ गड़बड़ है? एक [दस्तावेज़ीकरण इशू](https://github.com/snapotter-hq/snapotter/issues/new?template=documentation.yml) खोलें।
|
||||
|
||||
### कोड (CLA आवश्यक) {#code-requires-cla}
|
||||
|
||||
हम इनके लिए पुल रिक्वेस्ट स्वीकार करते हैं:
|
||||
|
||||
| प्रकार | प्रक्रिया |
|
||||
|------|---------|
|
||||
| बग फ़िक्स | सीधे एक PR खोलें (यदि कोई इशू मौजूद है तो उसे लिंक करें) |
|
||||
| नए अनुवाद | सीधे एक PR खोलें ([अनुवाद गाइड](/hi/guide/translations) देखें) |
|
||||
| दस्तावेज़ीकरण सुधार | सीधे एक PR खोलें |
|
||||
| टेस्ट कवरेज सुधार | सीधे एक PR खोलें |
|
||||
| नए टूल या फ़ीचर | पहले एक [चर्चा](https://github.com/snapotter-hq/snapotter/discussions/new?category=ideas) शुरू करें; कोड लिखने से पहले एक मेंटेनर स्वीकृत विचारों को एक ट्रैक किए गए इशू में बदल देता है |
|
||||
| रीफ़ैक्टर या आर्किटेक्चर बदलाव | पहले एक [चर्चा](https://github.com/snapotter-hq/snapotter/discussions/new?category=ideas) शुरू करें और कोड लिखने से पहले मेंटेनर की मंज़ूरी की प्रतीक्षा करें |
|
||||
|
||||
### हम क्या स्वीकार नहीं करेंगे {#what-we-will-not-accept}
|
||||
|
||||
- CI/CD वर्कफ़्लो, रिलीज़ कॉन्फ़िग या लिंटर/कंपाइलर कॉन्फ़िग में बदलाव
|
||||
- हस्ताक्षरित [Contributor License Agreement](#contributor-license-agreement) के बिना PR
|
||||
- 400 से अधिक लाइनों के बदलाव वाले PR (बड़े काम को छोटे PR में बाँटें)
|
||||
- ऐसे फ़ीचर जिन पर पहले चर्चा और स्वीकृति नहीं हुई
|
||||
- पूर्व चर्चा के बिना `packages/ai/` में बदलाव
|
||||
|
||||
## Contributor License Agreement {#contributor-license-agreement}
|
||||
|
||||
आपका पहला PR मर्ज करने से पहले, आपको हमारा [Individual CLA](https://github.com/snapotter-hq/snapotter/blob/main/CLA.md) हस्ताक्षरित करना होगा। यह एक बार की आवश्यकता है।
|
||||
|
||||
**क्यों:** SnapOtter दोहरे-लाइसेंस वाला है (AGPLv3 + कमर्शियल)। CLA हमें आपके योगदान को दोनों लाइसेंसों के तहत वितरित करने का अधिकार देता है। आप अपने काम के पूर्ण कॉपीराइट स्वामित्व को बनाए रखते हैं।
|
||||
|
||||
**कैसे:** जब आप अपना पहला PR खोलेंगे, तो CLA Assistant बॉट एक लिंक के साथ टिप्पणी करेगा। उस पर क्लिक करें, समझौते की समीक्षा करें और अपने GitHub खाते से हस्ताक्षर करें। इसमें 30 सेकंड लगते हैं।
|
||||
|
||||
यदि आप अपने नियोक्ता की ओर से योगदान कर रहे हैं और आपका नियोक्ता आपके काम पर IP अधिकार रखता है, तो सबमिट करने से पहले एक Corporate CLA की व्यवस्था करने के लिए contact@snapotter.com से संपर्क करें।
|
||||
|
||||
## शुरुआत करना {#getting-started}
|
||||
|
||||
### पूर्वापेक्षाएँ {#prerequisites}
|
||||
|
||||
- Node.js 22+
|
||||
- pnpm 9+
|
||||
- Python 3.11+ (केवल AI टूल के लिए)
|
||||
- Docker (वैकल्पिक, पूर्ण इंटीग्रेशन टेस्टिंग के लिए)
|
||||
|
||||
### सेटअप {#setup}
|
||||
|
||||
```bash
|
||||
# Fork and clone
|
||||
git clone https://github.com/<your-username>/snapotter.git
|
||||
cd snapotter
|
||||
|
||||
# Start Postgres + Redis for local dev
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Start dev servers (web on :1349, API on :13490)
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### चेक चलाना {#running-checks}
|
||||
|
||||
PR सबमिट करने से पहले, सुनिश्चित करें कि सभी चेक स्थानीय रूप से पास होते हैं:
|
||||
|
||||
```bash
|
||||
pnpm lint # Biome lint + format check
|
||||
pnpm typecheck # TypeScript across monorepo
|
||||
pnpm test # Vitest unit + integration tests
|
||||
```
|
||||
|
||||
## पुल रिक्वेस्ट प्रक्रिया {#pull-request-process}
|
||||
|
||||
1. रेपो को फ़ोर्क करें और `main` (`feat/my-feature` या `fix/issue-123`) से एक ब्रांच बनाएँ
|
||||
2. [conventional commits](https://www.conventionalcommits.org/) का उपयोग करते हुए केंद्रित, समीक्षा-योग्य कमिट में अपने बदलाव करें
|
||||
3. अपने बदलावों के लिए टेस्ट जोड़ें या अपडेट करें
|
||||
4. स्थानीय रूप से `pnpm lint && pnpm typecheck && pnpm test` चलाएँ
|
||||
5. `main` के विरुद्ध एक PR खोलें और टेम्पलेट भरें
|
||||
6. यदि संकेत दिया जाए तो CLA पर हस्ताक्षर करें
|
||||
7. CI के पास होने और एक मेंटेनर की समीक्षा की प्रतीक्षा करें
|
||||
|
||||
### समीक्षा से अपेक्षाएँ {#review-expectations}
|
||||
|
||||
- हमारा लक्ष्य 7 दिनों के भीतर PR पर प्रतिक्रिया देना है
|
||||
- छोटे, केंद्रित PR की समीक्षा तेज़ी से होती है
|
||||
- यदि 7 दिनों में आपको कोई जवाब न मिले, तो थ्रेड पर पिंग करते हुए एक टिप्पणी छोड़ें
|
||||
- हम बदलावों का अनुरोध कर सकते हैं, एक अलग तरीका सुझा सकते हैं, या यदि PR परियोजना की दिशा से मेल नहीं खाता तो उसे बंद कर सकते हैं
|
||||
|
||||
### आपके PR के मर्ज होने के बाद {#after-your-pr-is-merged}
|
||||
|
||||
आपका योगदान अगली रिलीज़ में शामिल किया जाएगा और चेंजलॉग में श्रेय दिया जाएगा।
|
||||
|
||||
## अच्छे पहले इशू {#good-first-issues}
|
||||
|
||||
कुछ काम करने के लिए ढूँढ रहे हैं? शुरुआती-अनुकूल कार्यों के लिए हमारे [good first issues](https://github.com/snapotter-hq/snapotter/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) देखें, या बड़े कामों के लिए [help wanted](https://github.com/snapotter-hq/snapotter/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) देखें जहाँ हमें समुदाय की मदद की सराहना होगी।
|
||||
|
||||
## कोड शैली {#code-style}
|
||||
|
||||
- Biome फ़ॉर्मेटिंग और लिंटिंग संभालता है (डबल कोट्स, सेमीकोलन, 2-स्पेस इंडेंट)
|
||||
- प्री-कमिट हुक स्वचालित रूप से स्टेज की गई फ़ाइलों पर `biome check --write` चलाता है
|
||||
- यदि लिंटर शिकायत करता है, तो कोड ठीक करें (Biome कॉन्फ़िग में बदलाव न करें)
|
||||
- हर जगह ES modules (`import`/`export`)
|
||||
- Conventional commits: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`
|
||||
|
||||
पूर्ण आर्किटेक्चर विवरण के लिए, [Developer Guide](/hi/guide/developer) देखें।
|
||||
|
||||
## सुरक्षा {#security}
|
||||
|
||||
**सुरक्षा कमज़ोरियों के लिए कोई सार्वजनिक PR या इशू न खोलें।** उन्हें [GitHub Security Advisories](https://github.com/snapotter-hq/snapotter/security/advisories/new) के माध्यम से या contact@snapotter.com पर ईमेल करके निजी तौर पर रिपोर्ट करें। पूर्ण विवरण के लिए [SECURITY.md](https://github.com/snapotter-hq/snapotter/blob/main/SECURITY.md) देखें।
|
||||
|
||||
## प्रश्न? {#questions}
|
||||
|
||||
- [Documentation](https://docs.snapotter.com/)
|
||||
- [Discord](https://discord.gg/hr3s7HPUsr)
|
||||
- [GitHub Discussions](https://github.com/snapotter-hq/snapotter/discussions)
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
description: "SnapOtter के लिए PostgreSQL डेटाबेस स्कीमा, टेबल, माइग्रेशन और बैकअप प्रक्रियाएँ।"
|
||||
i18n_source_hash: b37398ae91a3
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 5592d4435806
|
||||
---
|
||||
|
||||
# डेटाबेस {#database}
|
||||
|
||||
SnapOtter डेटा स्थायित्व के लिए [Drizzle ORM](https://orm.drizzle.team/) (pg-core / node-postgres) के साथ PostgreSQL 17 का उपयोग करता है। स्कीमा `apps/api/src/db/schema.ts` में परिभाषित है।
|
||||
|
||||
कनेक्शन `DATABASE_URL` एनवायरनमेंट वेरिएबल के माध्यम से कॉन्फ़िगर किया जाता है (डिफ़ॉल्ट `postgres://snapotter:snapotter@postgres:5432/snapotter`)। Docker Compose में, Postgres कंटेनर अपना डेटा `SnapOtter-pgdata` नामित वॉल्यूम में संग्रहीत करता है।
|
||||
|
||||
## टेबल {#tables}
|
||||
|
||||
### users {#users}
|
||||
|
||||
उपयोगकर्ता खातों को संग्रहीत करता है। `DEFAULT_USERNAME` और `DEFAULT_PASSWORD` से पहले रन पर स्वचालित रूप से बनाया जाता है।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `username` | varchar | अद्वितीय, आवश्यक |
|
||||
| `passwordHash` | varchar | scrypt हैश |
|
||||
| `role` | varchar | `admin`, `editor`, या `user` |
|
||||
| `mustChangePassword` | boolean | अनिवार्य पासवर्ड रीसेट फ़्लैग |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
| `updatedAt` | timestamp | अंतिम अपडेट समय |
|
||||
|
||||
### sessions {#sessions}
|
||||
|
||||
सक्रिय लॉगिन सत्र। प्रत्येक पंक्ति एक सत्र टोकन को एक उपयोगकर्ता से जोड़ती है।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | varchar | प्राथमिक कुंजी (सत्र टोकन) |
|
||||
| `userId` | uuid | `users.id` के लिए फ़ॉरेन कुंजी |
|
||||
| `expiresAt` | timestamp | समाप्ति समय |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
|
||||
### teams {#teams}
|
||||
|
||||
उपयोगकर्ताओं को व्यवस्थित करने के लिए समूह। एडमिन उपयोगकर्ताओं को टीमों में असाइन कर सकते हैं।
|
||||
|
||||
| कॉलम | प्रकार | विवरण |
|
||||
|--------|------|-------------|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `name` | varchar (अद्वितीय, अधिकतम 50 वर्ण) | टीम का नाम |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
|
||||
### api_keys {#api-keys}
|
||||
|
||||
प्रोग्रामेटिक एक्सेस के लिए API कुंजियाँ। कच्ची कुंजी निर्माण पर एक बार दिखाई जाती है; केवल हैश संग्रहीत किया जाता है।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `userId` | uuid | `users.id` के लिए फ़ॉरेन कुंजी |
|
||||
| `keyHash` | varchar | कुंजी का scrypt हैश |
|
||||
| `name` | varchar | उपयोगकर्ता द्वारा दिया गया लेबल |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
| `lastUsedAt` | timestamp | प्रत्येक प्रमाणित अनुरोध पर अपडेट किया जाता है |
|
||||
|
||||
कुंजियाँ `si_` से उपसर्गित होती हैं जिसके बाद 96 हेक्स वर्ण होते हैं (48 रैंडम बाइट्स)।
|
||||
|
||||
### pipelines {#pipelines}
|
||||
|
||||
सहेजे गए टूल चेन जिन्हें उपयोगकर्ता UI में बनाते हैं।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `name` | varchar | पाइपलाइन का नाम |
|
||||
| `description` | varchar | वैकल्पिक विवरण |
|
||||
| `steps` | jsonb | `{ toolId, settings }` ऑब्जेक्ट का ऐरे |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
|
||||
### user_files {#user-files}
|
||||
|
||||
संस्करण-श्रृंखला ट्रैकिंग के साथ स्थायी फ़ाइल लाइब्रेरी। प्रत्येक प्रोसेसिंग चरण जो एक परिणाम सहेजता है, एक नई पंक्ति बनाता है जो `parentId` के माध्यम से अपने पैरेंट से जुड़ी होती है, जिससे एक संस्करण वृक्ष बनता है।
|
||||
|
||||
| कॉलम | प्रकार | विवरण |
|
||||
|--------|------|-------------|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `userId` | uuid | users के लिए FK (CASCADE DELETE) |
|
||||
| `originalName` | varchar | मूल अपलोड फ़ाइलनाम |
|
||||
| `storedName` | varchar | डिस्क पर फ़ाइलनाम |
|
||||
| `mimeType` | varchar | MIME प्रकार |
|
||||
| `size` | integer | बाइट्स में फ़ाइल का आकार |
|
||||
| `width` | integer | px में छवि की चौड़ाई |
|
||||
| `height` | integer | px में छवि की ऊँचाई |
|
||||
| `version` | integer | संस्करण संख्या (1 = मूल) |
|
||||
| `parentId` | uuid या null | user_files के लिए FK (पैरेंट संस्करण) |
|
||||
| `toolChain` | jsonb | इस संस्करण को बनाने के लिए क्रम में लागू किए गए टूल ID |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
|
||||
### jobs {#jobs}
|
||||
|
||||
प्रगति रिपोर्टिंग और सफ़ाई के लिए प्रोसेसिंग जॉब को ट्रैक करता है।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `type` | varchar | टूल या पाइपलाइन पहचानकर्ता |
|
||||
| `status` | varchar | `queued`, `processing`, `completed`, या `failed` |
|
||||
| `progress` | real | 0.0-1.0 अंश |
|
||||
| `inputFiles` | jsonb | इनपुट फ़ाइल पथों का ऐरे |
|
||||
| `outputPath` | varchar | परिणाम फ़ाइल का पथ |
|
||||
| `settings` | jsonb | उपयोग की गई टूल सेटिंग्स |
|
||||
| `error` | varchar | विफल होने पर त्रुटि संदेश |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
| `completedAt` | timestamp | पूर्ण होने का समय |
|
||||
|
||||
### settings {#settings}
|
||||
|
||||
सर्वर-व्यापी सेटिंग्स के लिए की-वैल्यू स्टोर जिन्हें एडमिन UI से बदल सकते हैं।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `key` | varchar | प्राथमिक कुंजी |
|
||||
| `value` | varchar | सेटिंग मान |
|
||||
| `updatedAt` | timestamp | अंतिम अपडेट समय |
|
||||
|
||||
### roles {#roles}
|
||||
|
||||
सूक्ष्म अनुमतियों वाली कस्टम भूमिकाएँ।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `name` | varchar | अद्वितीय भूमिका नाम |
|
||||
| `description` | varchar | वैकल्पिक विवरण |
|
||||
| `permissions` | jsonb | अनुमति स्ट्रिंग्स का ऐरे |
|
||||
| `createdAt` | timestamp | बनाने का समय |
|
||||
|
||||
### audit_log {#audit-log}
|
||||
|
||||
सुरक्षा-प्रासंगिक क्रिया लॉग।
|
||||
|
||||
| कॉलम | प्रकार | नोट्स |
|
||||
|---|---|---|
|
||||
| `id` | uuid | प्राथमिक कुंजी |
|
||||
| `userId` | uuid | users के लिए FK |
|
||||
| `action` | varchar | क्रिया प्रकार |
|
||||
| `details` | jsonb | क्रिया-विशिष्ट डेटा |
|
||||
| `createdAt` | timestamp | क्रिया का समय |
|
||||
|
||||
## माइग्रेशन {#migrations}
|
||||
|
||||
Drizzle स्कीमा माइग्रेशन संभालता है। माइग्रेशन फ़ाइलें `apps/api/drizzle/` में रहती हैं। विकास के दौरान:
|
||||
|
||||
```bash
|
||||
cd apps/api
|
||||
npx drizzle-kit generate # generate a migration from schema changes
|
||||
npx drizzle-kit migrate # apply pending migrations
|
||||
```
|
||||
|
||||
प्रोडक्शन में, लंबित माइग्रेशन स्टार्टअप पर स्वचालित रूप से लागू किए जाते हैं।
|
||||
|
||||
## बैकअप और रिस्टोर {#backup-and-restore}
|
||||
|
||||
रिलेशनल डेटाबेस Postgres कंटेनर के `SnapOtter-pgdata` वॉल्यूम में रहता है, ऐप के `/data` वॉल्यूम में नहीं।
|
||||
|
||||
**विकल्प 1: pg_dump (अनुशंसित)**
|
||||
|
||||
```bash
|
||||
# Dump the database while the stack is running
|
||||
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
|
||||
|
||||
# Restore into a fresh database
|
||||
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
|
||||
```
|
||||
|
||||
**विकल्प 2: वॉल्यूम स्नैपशॉट**
|
||||
|
||||
```bash
|
||||
# Stop the stack, then snapshot the pgdata volume
|
||||
docker compose down
|
||||
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
|
||||
```
|
||||
|
||||
### 1.x (SQLite) से माइग्रेट करना {#migrating-from-1-x-sqlite}
|
||||
|
||||
SnapOtter 1.x से अपग्रेड करने की अपनी अलग गाइड है: [Upgrading from 1.x to 2.0](./upgrading) देखें। संक्षेप में, अपने मौजूदा `/data` वॉल्यूम का पुनः उपयोग करें और 2.0 पहले बूट पर `/data/snapotter.db` का स्वतः पता लगाकर उसे इम्पोर्ट करता है (या इसे स्पष्ट रूप से इंगित करने के लिए `SQLITE_MIGRATE_PATH` सेट करें)। पहले पूरे `/data` वॉल्यूम का बैकअप लें, केवल `snapotter.db` का नहीं: 1.x SQLite WAL मोड का उपयोग करता है, इसलिए एक रुका हुआ कंटेनर अक्सर अपना अधिकांश डेटा एक लगभग-खाली `snapotter.db` के बगल में `snapotter.db-wal` में छोड़ देता है।
|
||||
@@ -0,0 +1,571 @@
|
||||
---
|
||||
description: "SnapOtter को Docker के साथ प्रोडक्शन में डिप्लॉय करें। हार्डवेयर आवश्यकताएँ, GPU सेटअप, और Nginx, Traefik, तथा Cloudflare के लिए रिवर्स प्रॉक्सी कॉन्फ़िग।"
|
||||
i18n_source_hash: 6b6957060fa6
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 8348cd795918
|
||||
---
|
||||
|
||||
# Deployment {#deployment}
|
||||
|
||||
SnapOtter एक 3-कंटेनर Docker Compose स्टैक के रूप में डिप्लॉय होता है: SnapOtter ऐप इमेज, PostgreSQL 17, और Redis 8। ऐप इमेज **linux/amd64** (AI त्वरण के लिए NVIDIA CUDA के साथ) और **linux/arm64** (CPU) को सपोर्ट करती है, इसलिए यह Intel/AMD सर्वरों, Apple Silicon Macs, और Raspberry Pi 4/5 जैसे ARM डिवाइसों पर मूल रूप से चलती है। VA-API, Quick Sync, या OpenCL के माध्यम से Intel/AMD iGPU त्वरण आज AI इन्फ़रेंस के लिए सपोर्ट नहीं किया जाता।
|
||||
|
||||
GPU सेटअप, Docker Compose उदाहरणों, और वर्शन पिनिंग के लिए [Docker Image](./docker-tags) देखें।
|
||||
|
||||
## Quick Start (CPU) {#quick-start-cpu}
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml - Copy this file and run: docker compose up -d
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest
|
||||
container_name: SnapOtter
|
||||
ports:
|
||||
- "1349:1349" # Web UI + API
|
||||
volumes:
|
||||
- SnapOtter-data:/data # AI models, user files (PERSISTENT)
|
||||
- SnapOtter-workspace:/tmp/workspace # Temp processing files (can be tmpfs)
|
||||
environment:
|
||||
# --- Authentication ---
|
||||
- AUTH_ENABLED=true # Set to false to disable login entirely
|
||||
- DEFAULT_USERNAME=admin # First-run admin username
|
||||
- DEFAULT_PASSWORD=admin # First-run admin password (you'll be forced to change it)
|
||||
|
||||
# --- Database + Queue ---
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
|
||||
# --- Limits (set 0 for unlimited) ---
|
||||
# - MAX_UPLOAD_SIZE_MB=100 # Per-file upload limit in MB
|
||||
# - MAX_BATCH_SIZE=100 # Max files per batch request
|
||||
# - RATE_LIMIT_PER_MIN=1000 # API rate limit per IP, default shown (0 = disabled)
|
||||
# - MAX_USERS=0 # Max user accounts
|
||||
|
||||
# --- Networking ---
|
||||
# - TRUST_PROXY=true # Trust X-Forwarded-For headers (set false if not behind a proxy)
|
||||
|
||||
# --- Bind mount permissions ---
|
||||
# - PUID=1000 # Match your host user's UID (run: id -u)
|
||||
# - PGID=1000 # Match your host user's GID (run: id -g)
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
shm_size: "2gb" # Needed for Python ML shared memory
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: SnapOtter-postgres
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter # Change this for non-local deployments
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
container_name: SnapOtter-redis
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
SnapOtter-data: # Named volume - Docker manages permissions automatically
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
इसके बाद ऐप `http://localhost:1349` पर उपलब्ध होता है।
|
||||
|
||||
> **Docker Hub रेट लिमिट?** GitHub Container Registry से पुल करने के लिए `snapotter/snapotter:latest` को `ghcr.io/snapotter-hq/snapotter:latest` से बदलें। दोनों रजिस्ट्री हर रिलीज़ पर वही इमेज प्राप्त करती हैं।
|
||||
|
||||
## Quick Start (NVIDIA CUDA) {#quick-start-nvidia-cuda}
|
||||
|
||||
AI टूल (बैकग्राउंड हटाना, अपस्केलिंग, फ़ेस एन्हांसमेंट, OCR) पर NVIDIA CUDA त्वरण के लिए:
|
||||
|
||||
```yaml
|
||||
# docker-compose-gpu.yml - Requires: NVIDIA GPU + nvidia-container-toolkit
|
||||
# Install toolkit: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
container_name: SnapOtter
|
||||
ports:
|
||||
- "1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=admin
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
shm_size: "2gb" # Required for PyTorch CUDA shared memory
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all # Or set to 1 for a specific GPU
|
||||
capabilities: [gpu]
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: SnapOtter-postgres
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
container_name: SnapOtter-redis
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose-gpu.yml up -d
|
||||
```
|
||||
|
||||
लॉग में CUDA डिटेक्शन की जाँच करें:
|
||||
|
||||
```bash
|
||||
docker logs SnapOtter 2>&1 | head -20
|
||||
# Look for: [gpu] CUDA available via torch
|
||||
```
|
||||
|
||||
## Hardware Requirements {#hardware-requirements}
|
||||
|
||||
ये संख्याएँ कई तरह के सिस्टमों पर किए गए बेंचमार्क से आती हैं, एक आधुनिक amd64 वर्कस्टेशन (NVIDIA RTX 4070 के साथ) से लेकर एक Raspberry Pi तक, जिनमें से हर एक पर पूरा टूल कैटलॉग चलाया गया और असली न्यूनतम सीमा खोजने के लिए Docker रिसोर्स लिमिट को स्वीप किया गया।
|
||||
|
||||
### Quick Reference {#quick-reference}
|
||||
|
||||
| टियर | उपयोग परिदृश्य | CPU | RAM | GPU | स्टोरेज |
|
||||
|------|----------|-----|-----|-----|---------|
|
||||
| न्यूनतम | इमेज, फ़ाइलें, और हल्के PDF टूल; एकल उपयोगकर्ता; छोटे बैच | 2 कोर | 2 GB | कोई नहीं | ~7 GB |
|
||||
| अनुशंसित | वीडियो, PDF, और CPU पर AI सहित सभी पाँच मोडैलिटी; बैच; कुछ उपयोगकर्ता | 4 कोर | 4 GB | कोई नहीं | ~25 GB |
|
||||
| पूर्ण | GPU AI सहित सब कुछ तेज़ गति से; बड़े बैच; अनेक उपयोगकर्ता | 6-8 कोर | 8 GB | NVIDIA 8 GB+ VRAM (12 GB आरामदायक) | ~35 GB |
|
||||
|
||||
**आर्किटेक्चर: केवल 64-बिट** (`linux/amd64` या `linux/arm64`)। SnapOtter Intel/AMD सर्वरों, Apple Silicon Macs, और 64-बिट ARM बोर्डों पर मूल रूप से चलता है, जिनमें **Raspberry Pi 4 और 5** (4-8 GB) शामिल हैं। यह 32-बिट ARM (`armv7`/`armhf`) पर **नहीं** चलता, इसके लिए कोई इमेज बनाई ही नहीं जाती, और न ही Pi Zero जैसे 512 MB-श्रेणी के बोर्डों पर, जो मेमोरी की न्यूनतम सीमा से नीचे हैं (नीचे देखें)।
|
||||
|
||||
### Minimum (इमेज, फ़ाइलें, और हल्के PDF टूल; कोई AI नहीं) {#minimum-image-files-and-light-pdf-tools-no-ai}
|
||||
|
||||
| रिसोर्स | आवश्यकता |
|
||||
|---|---|
|
||||
| CPU | 2 कोर |
|
||||
| RAM | 2 GB |
|
||||
| डिस्क | ~5.5 GB (इमेज) + डेटा वॉल्यूम |
|
||||
| GPU | आवश्यक नहीं |
|
||||
|
||||
सभी 222 गैर-AI कैटलॉग टूल - इमेज (रिसाइज़, क्रॉप, कन्वर्ट, कंप्रेस, एडजस्ट, वॉटरमार्क), वीडियो (ट्रिम, म्यूट, रीमक्स), ऑडियो (कन्वर्ट, नॉर्मलाइज़, ट्रिम), PDF (मर्ज, स्प्लिट, कंप्रेस, रोटेट, प्रोटेक्ट), फ़ाइल रूपांतरण, और समर्पित रूपांतरण प्रीसेट - मामूली हार्डवेयर पर चलते हैं। अधिकांश ऑपरेशन एक बड़ी फ़ाइल पर भी एक सेकंड से काफ़ी कम समय में पूरे हो जाते हैं: एक 2.7 MB इमेज ~0.05 s में रिसाइज़ होती है और ~2 s में WebP में री-एनकोड होती है।
|
||||
|
||||
मेमोरी की न्यूनतम सीमा असली है, यह एक Docker रिसोर्स-लिमिट स्वीप से आती है: **512 MB स्टैक शुरू नहीं कर सकता** (एक अकेली इमेज रिसाइज़ भी मार दी जाती है), **1 GB** एकल-फ़ाइल ऑपरेशन संभालता है पर मल्टी-फ़ाइल बैच में मेमोरी खत्म हो जाती है, और **2 GB / 2 कोर** सबसे छोटा कॉन्फ़िगरेशन है जो बैच को आराम से संभालता है।
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2'
|
||||
memory: 2G
|
||||
```
|
||||
|
||||
**एकमात्र CPU-भारी अपवाद वीडियो री-एनकोडिंग है।** स्ट्रीम-कॉपी ऑपरेशन (ट्रिम, म्यूट, कंटेनर रीमक्स) तत्काल होते हैं, पर किसी अलग कोडेक में ट्रांसकोडिंग CPU-बद्ध है। एक 1080p / 45-सेकंड क्लिप को VP9 (WebM) में री-एनकोड करने में एक तेज़ आधुनिक CPU पर लगभग **~40 s**, Apple Silicon पर ~45 s, एक पुराने मोबाइल 4-कोर पर ~80 s, और एक पुराने 4-कोर सर्वर पर **~130 s** लगते हैं। यदि आपका वर्कलोड वीडियो-भारी है, तो CPU कोर और क्लॉक स्पीड को प्राथमिकता दें, या कंटेनर की `cpus:` लिमिट बढ़ाएँ, शिप किया गया compose ऐप को डिफ़ॉल्ट रूप से 4 कोर पर सीमित करता है (GPU compose पर 8)।
|
||||
|
||||
### Recommended (CPU पर AI टूल) {#recommended-ai-tools-on-cpu}
|
||||
|
||||
| रिसोर्स | आवश्यकता |
|
||||
|---|---|
|
||||
| CPU | 4 कोर |
|
||||
| RAM | 4 GB |
|
||||
| डिस्क | 3 GB (इमेज) + 24 GB (AI मॉडल) + वर्कस्पेस |
|
||||
| GPU | आवश्यक नहीं (CPU फ़ॉलबैक) |
|
||||
|
||||
**AI बंडल इंस्टॉल करना ही RAM को 4 GB तक पहुँचाता है।** बिना किसी AI इंस्टॉल के ऐप लगभग 360 MB पर निष्क्रिय रहता है; सभी सात बंडल इंस्टॉल होने पर यह ~2.6 GB रेज़िडेंट रखता है, क्योंकि Python AI साइडकार स्टार्टअप पर अपने मॉडल (बैकग्राउंड हटाना, अपस्केलिंग, OCR, ट्रांसक्रिप्शन, फ़ेस डिटेक्शन, रीस्टोरेशन) पहले से लोड करता है। गैर-AI इंस्टॉल हल्के रहते हैं; AI इंस्टॉल को ≥4 GB चाहिए।
|
||||
|
||||
अधिकांश AI टूल CPU पर पूरी तरह उपयोगी हैं; कुछ को वास्तव में GPU चाहिए। एक आधुनिक 4-कोर CPU पर मापा गया:
|
||||
|
||||
| AI टूल | CPU समय | CPU पर उपयोगी? |
|
||||
|---|---|---|
|
||||
| फ़ेस डिटेक्शन (blur-faces, smart-crop, red-eye), noise-removal | 1 s से कम | हाँ |
|
||||
| OCR, ट्रांसक्रिप्शन, सबटाइटल | 1-3 s | हाँ |
|
||||
| Colorize, फ़ेस एन्हांसमेंट | ~10 s | हाँ |
|
||||
| बैकग्राउंड हटाना / बदलना / ब्लर | ~29 s | हाँ (आपको इंतज़ार करना होगा) |
|
||||
| AI अपस्केल (RealESRGAN) | ~33 s छोटी; बड़ी इमेजों पर मिनट | सीमांत, GPU दृढ़ता से अनुशंसित |
|
||||
| फ़ोटो रीस्टोरेशन (पूरी पाइपलाइन) | कई मिनट | नहीं, GPU या एक तेज़ मल्टी-कोर CPU चाहिए |
|
||||
|
||||
SnapOtter जानबूझकर इन मॉडल डाउनलोड को Docker इमेज में नहीं बेक करता। AI बंडल केवल तभी खींचे जाते हैं जब कोई व्यवस्थापक संबंधित टूल सक्षम करता है, इन्हें स्थायी `/data/ai` वॉल्यूम में संग्रहीत किया जाता है, और उसी मॉडल स्टैक पर निर्भर हर टूल द्वारा साझा किया जाता है। इससे अंतिम कंटेनर इमेज छोटी रहती है, जबकि एक पूर्ण AI इंस्टॉलेशन नीचे दी गई बड़ी स्टोरेज संख्याओं तक पहुँच सकता है।
|
||||
|
||||
कुछ टूल एक से अधिक साझा बंडल पर निर्भर होते हैं। उदाहरण के लिए, Passport Photo को `background-removal` और `face-detection` दोनों चाहिए; यदि `background-removal` पहले से इंस्टॉल है, तो Passport Photo सक्षम करने पर केवल गायब `face-detection` बंडल डाउनलोड होता है। यही पुनः उपयोग सभी AI टूलों पर लागू होता है।
|
||||
|
||||
AI मॉडल डाउनलोड आकार:
|
||||
|
||||
| बंडल | डिस्क आकार |
|
||||
|---|---|
|
||||
| बैकग्राउंड हटाना | 4-5 GB |
|
||||
| अपस्केल + फ़ेस एन्हांस + नॉइज़ हटाना | 5-6 GB |
|
||||
| फ़ेस डिटेक्शन | 200-300 MB |
|
||||
| ऑब्जेक्ट इरेज़र + Colorize | 1-2 GB |
|
||||
| OCR | 5-6 GB |
|
||||
| फ़ोटो रीस्टोरेशन | 4-5 GB |
|
||||
| **सभी बंडल** | **~24 GB** |
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '4'
|
||||
memory: 4G
|
||||
```
|
||||
|
||||
### Full (NVIDIA CUDA पर AI टूल) {#full-ai-tools-on-nvidia-cuda}
|
||||
|
||||
| रिसोर्स | आवश्यकता |
|
||||
|---|---|
|
||||
| CPU | 6-8 कोर (GPU AI के साथ भी वीडियो तैयारी + समवर्तीता CPU पर चलती है) |
|
||||
| RAM | 8 GB |
|
||||
| GPU | 8+ GB VRAM वाला NVIDIA (12 GB अनुशंसित) |
|
||||
| डिस्क | कुल ~35 GB |
|
||||
|
||||
एक NVIDIA GPU (CUDA) भारी AI मॉडलों को नाटकीय रूप से तेज़ कर देता है। एक RTX 4070 बनाम एक आधुनिक CPU पर मापा गया:
|
||||
|
||||
| AI टूल | GPU के साथ तेज़ी | टिप्पणियाँ |
|
||||
|---|---|---|
|
||||
| AI अपस्केल (RealESRGAN 2×) | **~47×** | सबसे बड़ा फ़ायदा, एक सेकंड से कम बनाम ~33 s (बड़ी इमेजों पर मिनट) |
|
||||
| फ़ेस एन्हांसमेंट (CodeFormer) | **~12×** | ~0.9 s बनाम ~11 s |
|
||||
| ट्रांसक्रिप्शन (Whisper) | ~4.5× | |
|
||||
| बैकग्राउंड हटाना / बदलना / ब्लर | ~4× | GPU पर ~7 s बनाम CPU पर ~29 s |
|
||||
| Colorize | ~1.8× | |
|
||||
| OCR, फ़ेस डिटेक्शन, red-eye, noise-removal | ~1× | CPU पर पहले से तेज़, GPU मदद नहीं करता |
|
||||
| फ़ोटो रीस्टोरेशन | कोई नहीं | GPU पर भी CPU-बद्ध (0% GPU उपयोग); यहाँ GPU से ज़्यादा एक तेज़ CPU मायने रखता है |
|
||||
|
||||
GPU के लायक टूल हैं **अपस्केल, फ़ेस एन्हांसमेंट, ट्रांसक्रिप्शन, और बैकग्राउंड हटाना**। फ़ेस डिटेक्शन, OCR, और red-eye CPU-बद्ध हैं और पहले से तेज़ हैं, इसलिए GPU कुछ नहीं जोड़ता।
|
||||
|
||||
फ़ेस एन्हांसमेंट के साथ अपस्केल के दौरान चरम VRAM उपयोग 7.5 GB तक पहुँचता है। एक 6 GB NVIDIA GPU अधिकांश AI टूलों के लिए अलग-अलग काम करता है पर अपस्केल पर विफल होगा। 8-12 GB VRAM सब कुछ संभालता है।
|
||||
|
||||
VA-API, Quick Sync, या OpenCL के माध्यम से Intel/AMD iGPU त्वरण आज AI इन्फ़रेंस के लिए सपोर्ट नहीं किया जाता। कंटेनर में `/dev/dri` को मैप करने से AI GPU त्वरण सक्षम नहीं होता; NVIDIA CUDA उपलब्ध न होने पर SnapOtter AI टूलों को CPU पर चलाएगा।
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '4'
|
||||
memory: 8G
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
```
|
||||
|
||||
### Concurrent Users {#concurrent-users}
|
||||
|
||||
डिफ़ॉल्ट 4-कोर-सीमित ऐप कंटेनर के विरुद्ध समानांतर इमेज-रिसाइज़ अनुरोध:
|
||||
|
||||
| समवर्ती अनुरोध | औसत प्रतिक्रिया समय | त्रुटियाँ |
|
||||
|---|---|---|
|
||||
| 1 | 0.4s | 0 |
|
||||
| 5 | 1.2s | 0 |
|
||||
| 10 | 2.1s | 0 |
|
||||
|
||||
जैसे-जैसे वर्कर पूल संतृप्त होता है, प्रतिक्रिया समय बिना किसी त्रुटि के उप-रैखिक रूप से घटता है। ऐप कंटेनर की `cpus:` लिमिट बढ़ाने से (या अधिक कोर वाले होस्ट का उपयोग करने से) यह सीमा ऊपर उठती है। ध्यान दें कि भारी जॉब (वीडियो ट्रांसकोड, CPU AI) अपनी पूरी अवधि के लिए एक वर्कर को पकड़े रखते हैं, इसलिए CPU का आकार अपने अपेक्षित समवर्ती भारी जॉब की संख्या के अनुसार तय करें, केवल अनुरोध संख्या के अनुसार नहीं।
|
||||
|
||||
### Supported Image Formats {#supported-image-formats}
|
||||
|
||||
SnapOtter **55+ इनपुट फ़ॉर्मैट** और **14 आउटपुट फ़ॉर्मैट** को सपोर्ट करता है, जिनमें 20+ कैमरा ब्रांडों की RAW फ़ाइलें, पेशेवर फ़ॉर्मैट (PSD, EPS, OpenEXR, HDR), आधुनिक कोडेक (JPEG XL, AVIF, HEIC, QOI), और वैज्ञानिक/गेमिंग फ़ॉर्मैट (FITS, DDS) शामिल हैं।
|
||||
|
||||
हर सपोर्टेड फ़ॉर्मैट, उपयोग किए गए डिकोडर, और उपलब्ध क्वालिटी नियंत्रणों के विवरण के लिए [पूर्ण फ़ॉर्मैट सूची](/hi/guide/supported-formats) देखें।
|
||||
|
||||
### Known Limitations {#known-limitations}
|
||||
|
||||
- **Content-aware resize** caire बाइनरी की एक सीमा के कारण बड़ी इमेजों (>5 MP) पर क्रैश हो जाता है। छोटी इमेजों के साथ ठीक काम करता है।
|
||||
- **HEIF डिकोड** में 13-23 सेकंड लगते हैं। HEIC (Apple का वेरिएंट) 0.3-0.9 सेकंड पर बहुत तेज़ है।
|
||||
- **OCR जापानी** एक PaddlePaddle MKLDNN बग के कारण CPU पर विफल हो जाता है। GPU पर काम करता है।
|
||||
- **Upscale** छोटी इमेजों से परे किसी भी चीज़ के लिए CPU पर टाइम आउट हो जाता है। व्यावहारिक उपयोग के लिए GPU आवश्यक है।
|
||||
- **CodeFormer** फ़ेस एन्हांसमेंट GFPGAN से काफ़ी धीमा है (GPU पर 53s बनाम 2s)। अधिकांश उपयोग परिदृश्यों के लिए GFPGAN अनुशंसित है।
|
||||
|
||||
## Volumes {#volumes}
|
||||
|
||||
| माउंट / वॉल्यूम | उद्देश्य | आवश्यक? |
|
||||
|---|---|---|
|
||||
| `/data` (ऐप) | AI मॉडल, Python venv, उपयोगकर्ता फ़ाइलें | **हाँ**, इसके बिना फ़ाइल हानि |
|
||||
| `/tmp/workspace` (ऐप) | अस्थायी प्रोसेसिंग फ़ाइलें (स्वतः-साफ़) | अनुशंसित |
|
||||
| `SnapOtter-pgdata` (postgres) | PostgreSQL डेटा डायरेक्टरी (उपयोगकर्ता, सेटिंग्स, पाइपलाइन, जॉब) | **हाँ**, इसके बिना डेटा हानि |
|
||||
| `SnapOtter-redisdata` (redis) | टिकाऊ जॉब क्यू के लिए Redis append-only फ़ाइल | अनुशंसित |
|
||||
|
||||
### Bind mounts vs. named volumes {#bind-mounts-vs-named-volumes}
|
||||
|
||||
**नामित वॉल्यूम** (अनुशंसित), Docker स्वचालित रूप से अनुमतियाँ प्रबंधित करता है:
|
||||
```yaml
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
```
|
||||
|
||||
**बाइंड माउंट**, आप अनुमतियाँ प्रबंधित करते हैं। अपने होस्ट उपयोगकर्ता से मिलाने के लिए `PUID`/`PGID` सेट करें:
|
||||
```yaml
|
||||
volumes:
|
||||
- ./SnapOtter-data:/data
|
||||
environment:
|
||||
- PUID=1000 # Your host UID (run: id -u)
|
||||
- PGID=1000 # Your host GID (run: id -g)
|
||||
```
|
||||
|
||||
### Storage permissions {#storage-permissions}
|
||||
|
||||
SnapOtter रनटाइम पर दो स्थानों पर लिखता है: `/data` (उपयोगकर्ता फ़ाइलें, लॉग, AI मॉडल और Python venv) और `/tmp/workspace` (अस्थायी प्रोसेसिंग स्क्रैच)। दोनों उस उपयोगकर्ता द्वारा लिखने योग्य होने चाहिए जिसके रूप में कंटेनर चलता है। यदि कोई एक नहीं है, तो कंटेनर स्टार्टअप पर **तुरंत विफल हो जाता है**, एक संदेश के साथ जो डायरेक्टरी, चल रहे UID/GID, और इसे कैसे ठीक करें बताता है, बजाय "healthy" के रूप में बूट होकर फिर पहले अपलोड पर एक रहस्यमय त्रुटि के साथ विफल होने के।
|
||||
|
||||
अनुमतियाँ कैसे संभाली जाती हैं यह इस पर निर्भर करता है कि कंटेनर कैसे लॉन्च किया गया है:
|
||||
|
||||
**डिफ़ॉल्ट (root के रूप में शुरू, `snapotter` पर गिरता है)**, एंट्रीपॉइंट root के रूप में शुरू होता है, माउंट किए गए वॉल्यूम के स्वामित्व को ठीक करता है, फिर `gosu` के माध्यम से अनप्रिविलेज्ड `snapotter` उपयोगकर्ता पर गिर जाता है। नामित वॉल्यूम बिना किसी कॉन्फ़िगरेशन के काम करते हैं। बाइंड माउंट के लिए, `PUID`/`PGID` को अपने होस्ट उपयोगकर्ता (ऊपर) पर सेट करें ताकि यह जो फ़ाइलें लिखे उनका स्वामित्व आपका हो।
|
||||
|
||||
**Kubernetes / OpenShift (`runAsUser` के माध्यम से गैर-root)**, सीधे एक गैर-root उपयोगकर्ता के रूप में लॉन्च होने पर, कंटेनर स्वयं वॉल्यूम को chown नहीं कर सकता, इसलिए ऑर्केस्ट्रेटर को उन्हें लिखने योग्य बनाना होगा। `fsGroup` सेट करें:
|
||||
|
||||
```yaml
|
||||
securityContext:
|
||||
runAsUser: 999
|
||||
runAsGroup: 999
|
||||
fsGroup: 999 # makes mounted volumes writable by the pod
|
||||
```
|
||||
|
||||
इमेज की लिखने योग्य डायरेक्टरियाँ GID 0 द्वारा समूह-स्वामित्व वाली और समूह-लिखने योग्य हैं, इसलिए एक **मनमाने UID** प्लस root अनुपूरक समूह (OpenShift डिफ़ॉल्ट) के साथ चलने वाला पॉड बिना किसी `chown` के लिख सकता है।
|
||||
|
||||
**TrueNAS Scale (और अन्य "विदेशी UID" सेटअप)**, TrueNAS ऐप्स को एक गैर-root उपयोगकर्ता (अक्सर `568:568`) के रूप में चलाता है और एक अलग उपयोगकर्ता के स्वामित्व वाले होस्ट डेटासेट माउंट करता है, इसलिए न तो एंट्रीपॉइंट और न ही `fsGroup` उन्हें स्वयं लिखने योग्य बनाता है। एक चुनें:
|
||||
|
||||
- **ऐप को root के रूप में चलाएँ** (अनुशंसित), ऐप के उपयोगकर्ता को अनसेट छोड़ दें या इसे `0` पर सेट करें, और डिफ़ॉल्ट एंट्रीपॉइंट को अनुमतियाँ ठीक करने और `snapotter` पर गिरने दें।
|
||||
- **UID `999` के रूप में चलाएँ**, ऐप के उपयोगकर्ता/समूह को `999:999` (SnapOtter का बिल्ट-इन `snapotter` उपयोगकर्ता) पर सेट करें ताकि यह इमेज के स्वामित्व से मेल खाए।
|
||||
- होस्ट डेटासेट को उस UID पर **`chown`** करें जिसके रूप में कंटेनर चलता है, TrueNAS शेल से:
|
||||
|
||||
```bash
|
||||
# Use the UID from the startup error (or run `id` inside the container)
|
||||
chown -R 568:568 /mnt/<pool>/<dataset>
|
||||
```
|
||||
|
||||
स्टार्टअप त्रुटि उपयोग करने के लिए सटीक UID बताती है, इसलिए सबसे तेज़ रास्ता है ऐप को एक बार शुरू करना, संदेश पढ़ना, फिर तदनुसार `chown` करना (या उपयोगकर्ता समायोजित करना)।
|
||||
|
||||
## Environment Variables {#environment-variables}
|
||||
|
||||
| वेरिएबल | डिफ़ॉल्ट | विवरण |
|
||||
|---|---|---|
|
||||
| `AUTH_ENABLED` | `true` | लॉगिन आवश्यकता सक्षम/अक्षम करें |
|
||||
| `DEFAULT_USERNAME` | `admin` | प्रारंभिक व्यवस्थापक उपयोगकर्ता नाम |
|
||||
| `DEFAULT_PASSWORD` | `admin` | प्रारंभिक व्यवस्थापक पासवर्ड (पहले लॉगिन पर बदलना अनिवार्य) |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | प्रति-फ़ाइल अपलोड सीमा |
|
||||
| `MAX_BATCH_SIZE` | `100` | प्रति बैच अनुरोध अधिकतम फ़ाइलें |
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | प्रति IP प्रति मिनट API अनुरोध (अक्षम करने के लिए 0 सेट करें) |
|
||||
| `MAX_USERS` | `0` (असीमित) | अधिकतम उपयोगकर्ता खाते |
|
||||
| `TRUST_PROXY` | `true` | रिवर्स प्रॉक्सी से X-Forwarded-For हेडर पर भरोसा करें |
|
||||
| `PUID` | `999` | इस UID के रूप में चलाएँ (बाइंड माउंट अनुमतियों के लिए) |
|
||||
| `PGID` | `999` | इस GID के रूप में चलाएँ (बाइंड माउंट अनुमतियों के लिए) |
|
||||
| `LOG_LEVEL` | `info` | लॉग वर्बोसिटी: fatal, error, warn, info, debug, trace |
|
||||
| `CONCURRENT_JOBS` | `0` (auto) | अधिकतम समानांतर AI प्रोसेसिंग जॉब |
|
||||
| `SESSION_DURATION_HOURS` | `168` | लॉगिन सत्र जीवनकाल (7 दिन) |
|
||||
| `CORS_ORIGIN` | (खाली) | अल्पविराम-पृथक अनुमत ऑरिजिन, या समान-ऑरिजिन के लिए खाली |
|
||||
|
||||
## Health Check {#health-check}
|
||||
|
||||
कंटेनर में एक बिल्ट-इन हेल्थ चेक शामिल है:
|
||||
|
||||
```bash
|
||||
# Check container health status
|
||||
docker inspect --format='{{.State.Health.Status}}' SnapOtter
|
||||
|
||||
# Manual health check
|
||||
curl http://localhost:1349/api/v1/health
|
||||
# {"status":"healthy","version":"x.y.z"}
|
||||
```
|
||||
|
||||
## Reverse Proxy {#reverse-proxy}
|
||||
|
||||
SnapOtter डिफ़ॉल्ट रूप से `TRUST_PROXY=true` सेट करता है ताकि रेट लिमिटिंग और लॉगिंग `X-Forwarded-For` हेडर से असली क्लाइंट IP का उपयोग करें।
|
||||
|
||||
### Nginx {#nginx}
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name images.example.com;
|
||||
|
||||
# Match MAX_UPLOAD_SIZE_MB (0 = nginx default 1M, so set high for unlimited)
|
||||
client_max_body_size 500M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:1349;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SSE support (batch progress, feature install progress)
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Nginx Proxy Manager {#nginx-proxy-manager}
|
||||
|
||||
1. एक नया Proxy Host जोड़ें
|
||||
2. Domain Name को अपने डोमेन पर सेट करें
|
||||
3. Scheme को `http` पर, Forward Hostname को `SnapOtter` (या अपने कंटेनर IP) पर, Forward Port को `1349` पर सेट करें
|
||||
4. WebSocket सपोर्ट सक्षम करें
|
||||
5. Advanced के अंतर्गत, जोड़ें: `client_max_body_size 500M;` और `proxy_buffering off;`
|
||||
|
||||
### Traefik {#traefik}
|
||||
|
||||
```yaml
|
||||
# Add these labels to the SnapOtter service in docker-compose.yml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.snapotter.rule=Host(`images.example.com`)"
|
||||
- "traefik.http.routers.snapotter.entrypoints=websecure"
|
||||
- "traefik.http.routers.snapotter.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.snapotter.loadbalancer.server.port=1349"
|
||||
# Increase upload limit (default 2MB is too low)
|
||||
- "traefik.http.middlewares.snapotter-body.buffering.maxRequestBodyBytes=524288000"
|
||||
- "traefik.http.routers.snapotter.middlewares=snapotter-body"
|
||||
```
|
||||
|
||||
### Caddy {#caddy}
|
||||
|
||||
```txt
|
||||
images.example.com {
|
||||
reverse_proxy localhost:1349 {
|
||||
flush_interval -1
|
||||
transport http {
|
||||
read_timeout 300s
|
||||
write_timeout 300s
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`flush_interval -1` रिस्पॉन्स बफ़रिंग को अक्षम करता है, जो SSE प्रगति इवेंट (बैच प्रोसेसिंग, AI टूल, फ़ीचर इंस्टॉल) के लिए आवश्यक है। विस्तारित टाइमआउट बड़ी फ़ाइल अपलोड को Caddy द्वारा कनेक्शन जल्दी बंद किए बिना पूरा होने देते हैं।
|
||||
|
||||
### Cloudflare Tunnels {#cloudflare-tunnels}
|
||||
|
||||
```bash
|
||||
cloudflared tunnel --url http://localhost:1349
|
||||
```
|
||||
|
||||
नोट: Cloudflare की फ़्री योजनाओं पर 100 MB अपलोड सीमा है। मिलाने के लिए `MAX_UPLOAD_SIZE_MB=100` सेट करें।
|
||||
|
||||
## CI/CD {#ci-cd}
|
||||
|
||||
GitHub रिपॉज़िटरी में तीन वर्कफ़्लो हैं:
|
||||
|
||||
- **ci.yml** - हर push और PR पर स्वचालित रूप से चलता है। लिंट, टाइपचेक, टेस्ट, बिल्ड करता है, और Docker इमेज को वैलिडेट करता है (बिना push किए)।
|
||||
- **release.yml** - `workflow_dispatch` के माध्यम से मैन्युअल रूप से ट्रिगर होता है। एक वर्शन टैग और GitHub रिलीज़ बनाने के लिए semantic-release चलाता है, फिर एक मल्टी-आर्च Docker इमेज (amd64 + arm64) बनाता है और Docker Hub (`snapotter/snapotter`) तथा GitHub Container Registry (`ghcr.io/snapotter-hq/snapotter`) पर push करता है।
|
||||
- **deploy-docs.yml** - `main` पर push होने पर इस दस्तावेज़ीकरण साइट को बनाता है और Cloudflare Pages पर डिप्लॉय करता है।
|
||||
|
||||
एक रिलीज़ बनाने के लिए, GitHub UI में **Actions > Release > Run workflow** पर जाएँ, या चलाएँ:
|
||||
|
||||
```bash
|
||||
gh workflow run release.yml
|
||||
```
|
||||
|
||||
Semantic-release कमिट इतिहास से वर्शन निर्धारित करता है। `latest` Docker टैग हमेशा सबसे हाल की रिलीज़ की ओर इंगित करता है।
|
||||
|
||||
## Analytics {#analytics}
|
||||
|
||||
SnapOtter में बग पकड़ने और फ़ीचर सुधारने में मदद के लिए अनाम उत्पाद एनालिटिक्स (टूल उपयोग पैटर्न, त्रुटि रिपोर्ट) शामिल है। यह डिफ़ॉल्ट रूप से चालू है। आपकी फ़ाइलें, फ़ाइल नाम, और व्यक्तिगत डेटा कभी इसका हिस्सा नहीं होते। SnapOtter एनालिटिक्स अक्षम होने पर भी सामान्य रूप से काम करता है।
|
||||
|
||||
### Disabling analytics {#disabling-analytics}
|
||||
|
||||
रनटाइम ऑप्ट-आउट एक-क्लिक व्यवस्थापक टॉगल है। Settings > System > Privacy खोलें और Anonymous Product Analytics बंद कर दें। यह पूरे इंस्टेंस के लिए तुरंत रुक जाता है, किसी रीबिल्ड की आवश्यकता नहीं।
|
||||
|
||||
एक ऐसी इमेज के लिए जो कभी एनालिटिक्स उत्सर्जित नहीं कर सकती, रिपॉज़िटरी क्लोन करके और रीबिल्ड करके बिल्ड-टाइम हार्ड-ऑफ़ सेट करें:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/snapotter-hq/SnapOtter.git
|
||||
cd SnapOtter
|
||||
docker compose -f docker/docker-compose.yml build --build-arg SNAPOTTER_ANALYTICS=off
|
||||
docker compose -f docker/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
या अपने मौजूदा `docker-compose.yml` में बिल्ड आर्ग जोड़ें:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
snapotter:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
args:
|
||||
SNAPOTTER_ANALYTICS: "off"
|
||||
```
|
||||
@@ -0,0 +1,234 @@
|
||||
---
|
||||
description: "SnapOtter में स्थानीय विकास सेटअप, कमांड, कोड परंपराएँ, और एक नया टूल कैसे जोड़ें।"
|
||||
i18n_source_hash: cb03724d2829
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: c6b1b3537584
|
||||
---
|
||||
|
||||
# डेवलपर गाइड {#developer-guide}
|
||||
|
||||
एक स्थानीय विकास वातावरण कैसे सेट करें और SnapOtter में कोड योगदान कैसे करें।
|
||||
|
||||
## पूर्वापेक्षाएँ {#prerequisites}
|
||||
|
||||
- [Node.js](https://nodejs.org/) 22+
|
||||
- [pnpm](https://pnpm.io/) 9+ (`corepack enable && corepack prepare pnpm@latest --activate`)
|
||||
- [Docker](https://www.docker.com/) (स्थानीय Postgres + Redis, कंटेनर बिल्ड, और AI फ़ीचर के लिए आवश्यक)
|
||||
- Git
|
||||
|
||||
Python 3.10+ केवल तभी आवश्यक है जब आप AI/ML साइडकार (बैकग्राउंड हटाना, अपस्केलिंग, OCR) पर काम कर रहे हों।
|
||||
|
||||
## सेटअप {#setup}
|
||||
|
||||
```bash
|
||||
git clone https://github.com/snapotter-hq/snapotter.git
|
||||
cd snapotter
|
||||
docker compose -f docker-compose.dev.yml up -d # start Postgres + Redis
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
यह दो डेव सर्वर शुरू करता है:
|
||||
|
||||
| सेवा | URL | नोट्स |
|
||||
|----------|--------------------------|------------------------------------|
|
||||
| फ़्रंटएंड | http://localhost:1349 | Vite डेव सर्वर, /api को प्रॉक्सी करता है |
|
||||
| बैकएंड | http://localhost:13490 | Fastify API (प्रॉक्सी के माध्यम से एक्सेस) |
|
||||
|
||||
अपने ब्राउज़र में http://localhost:1349 खोलें। `admin` / `admin` के साथ लॉगिन करें। पहले लॉगिन पर आपको पासवर्ड बदलने के लिए कहा जाएगा।
|
||||
|
||||
## प्रोजेक्ट संरचना {#project-structure}
|
||||
|
||||
```
|
||||
apps/
|
||||
api/ Fastify backend
|
||||
web/ Vite + React frontend
|
||||
docs/ VitePress documentation (this site)
|
||||
packages/
|
||||
shared/ Constants, types, i18n strings
|
||||
image-engine/ Sharp-based image operations
|
||||
media-engine/ FFmpeg spawn + progress parsing
|
||||
doc-engine/ qpdf, LibreOffice, ghostscript wrappers
|
||||
ai/ Python sidecar bridge for ML models
|
||||
tests/
|
||||
unit/ Vitest unit tests
|
||||
integration/ Vitest integration tests (full API)
|
||||
e2e/ Playwright end-to-end specs
|
||||
fixtures/ Small test images
|
||||
```
|
||||
|
||||
## कमांड {#commands}
|
||||
|
||||
```bash
|
||||
pnpm dev # start frontend + backend
|
||||
pnpm build # build all workspaces
|
||||
pnpm typecheck # TypeScript check across monorepo
|
||||
pnpm lint # Biome lint + format check
|
||||
pnpm lint:fix # auto-fix lint + format
|
||||
pnpm test # unit + integration tests
|
||||
pnpm test:unit # unit tests only
|
||||
pnpm test:integration # integration tests only
|
||||
pnpm test:e2e # Playwright e2e tests
|
||||
pnpm test:coverage # tests with coverage report
|
||||
```
|
||||
|
||||
## कोड परंपराएँ {#code-conventions}
|
||||
|
||||
- डबल कोट्स, सेमीकोलन, 2-स्पेस इंडेंटेशन (Biome द्वारा लागू)
|
||||
- सभी वर्कस्पेस में ES modules
|
||||
- semantic-release के लिए [Conventional commits](https://www.conventionalcommits.org/)
|
||||
- सभी API इनपुट सत्यापन के लिए Zod
|
||||
- Biome, TypeScript, या एडिटर कॉन्फ़िग फ़ाइलों में कोई बदलाव नहीं। कोड ठीक करें, लिंटर नहीं।
|
||||
|
||||
## डेटाबेस {#database}
|
||||
|
||||
Drizzle ORM (pg-core) के माध्यम से PostgreSQL 17. स्थानीय डेव के लिए Postgres और Redis का चलना आवश्यक है - उन्हें इसके साथ शुरू करें:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
यह आपको पोर्ट 5432 पर Postgres और पोर्ट 6379 पर Redis देता है। फिर माइग्रेशन जनरेट और लागू करें:
|
||||
|
||||
```bash
|
||||
cd apps/api
|
||||
npx drizzle-kit generate # generate a migration from schema changes
|
||||
npx drizzle-kit migrate # apply pending migrations
|
||||
```
|
||||
|
||||
स्कीमा `apps/api/src/db/schema.ts` में परिभाषित है। टेबल: users, sessions, settings, jobs, apiKeys, pipelines, teams, userFiles, roles, auditLog।
|
||||
|
||||
## एक नया टूल जोड़ना {#adding-a-new-tool}
|
||||
|
||||
हर टूल एक ही पैटर्न का अनुसरण करता है। यहाँ एक न्यूनतम उदाहरण है।
|
||||
|
||||
### 1. बैकएंड रूट {#_1-backend-route}
|
||||
|
||||
`apps/api/src/routes/tools/my-tool.ts` बनाएँ:
|
||||
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { createToolRoute } from "../tool-factory.js";
|
||||
|
||||
const settingsSchema = z.object({
|
||||
intensity: z.number().min(0).max(100).default(50),
|
||||
});
|
||||
|
||||
export function registerMyTool(app: FastifyInstance) {
|
||||
createToolRoute(app, {
|
||||
toolId: "my-tool",
|
||||
settingsSchema,
|
||||
async process(inputBuffer, settings, filename) {
|
||||
// Use sharp or other libraries to process the image
|
||||
const sharp = (await import("sharp")).default;
|
||||
const result = await sharp(inputBuffer)
|
||||
// ... your processing logic
|
||||
.toBuffer();
|
||||
|
||||
return {
|
||||
buffer: result,
|
||||
filename: filename.replace(/\.[^.]+$/, ".png"),
|
||||
contentType: "image/png",
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
फिर इसे `apps/api/src/routes/tools/index.ts` में रजिस्टर करें।
|
||||
|
||||
### 2. फ़्रंटएंड सेटिंग्स कंपोनेंट {#_2-frontend-settings-component}
|
||||
|
||||
`apps/web/src/components/tools/my-tool-settings.tsx` बनाएँ:
|
||||
|
||||
```tsx
|
||||
import { useState } from "react";
|
||||
import { useToolProcessor } from "@/hooks/use-tool-processor";
|
||||
import { useFileStore } from "@/stores/file-store";
|
||||
|
||||
export function MyToolSettings() {
|
||||
const { files } = useFileStore();
|
||||
const { processFiles, processing, error, downloadUrl } =
|
||||
useToolProcessor("my-tool");
|
||||
|
||||
const [intensity, setIntensity] = useState(50);
|
||||
|
||||
const handleProcess = () => {
|
||||
processFiles(files, { intensity });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* your controls here */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleProcess}
|
||||
disabled={files.length === 0 || processing}
|
||||
data-testid="my-tool-submit"
|
||||
className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50"
|
||||
>
|
||||
Process
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
फिर इसे `apps/web/src/lib/tool-registry.tsx` पर फ़्रंटएंड टूल रजिस्ट्री में रजिस्टर करें:
|
||||
|
||||
```tsx
|
||||
// Add the lazy import
|
||||
const MyToolSettings = lazy(() =>
|
||||
import("@/components/tools/my-tool-settings").then((m) => ({
|
||||
default: m.MyToolSettings,
|
||||
})),
|
||||
);
|
||||
|
||||
// Add to the toolRegistry Map
|
||||
["my-tool", { displayMode: "before-after", Settings: MyToolSettings }],
|
||||
```
|
||||
|
||||
डिस्प्ले मोड: `"side-by-side"`, `"before-after"`, `"live-preview"`, `"no-comparison"`, `"interactive-crop"`, `"interactive-eraser"`, `"no-dropzone"`।
|
||||
|
||||
### 3. i18n प्रविष्टि {#_3-i18n-entry}
|
||||
|
||||
`packages/shared/src/i18n/en.ts` में जोड़ें:
|
||||
|
||||
```ts
|
||||
"my-tool": {
|
||||
name: "My Tool",
|
||||
description: "Short description of what this tool does",
|
||||
},
|
||||
```
|
||||
|
||||
### 4. टेस्ट {#_4-tests}
|
||||
|
||||
अपने एक्शन बटन में एक `data-testid` एट्रिब्यूट जोड़ें (जैसा ऊपर दिखाया गया है) ताकि e2e टेस्ट इसे विश्वसनीय रूप से लक्षित कर सकें।
|
||||
|
||||
## Docker बिल्ड {#docker-builds}
|
||||
|
||||
पूर्ण प्रोडक्शन इमेज को स्थानीय रूप से बनाएँ:
|
||||
|
||||
```bash
|
||||
docker build -f docker/Dockerfile -t snapotter:latest .
|
||||
```
|
||||
|
||||
तेज़ रीबिल्ड के लिए BuildKit कैश माउंट का उपयोग करें:
|
||||
|
||||
```bash
|
||||
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
|
||||
```
|
||||
|
||||
## एनवायरनमेंट वेरिएबल {#environment-variables}
|
||||
|
||||
पूर्ण सूची के लिए [Configuration guide](/hi/guide/configuration) देखें। विकास के लिए मुख्य वेरिएबल:
|
||||
|
||||
| वेरिएबल | डिफ़ॉल्ट | विवरण |
|
||||
|-----------------------------|-----------|------------------------------------------------|
|
||||
| `AUTH_ENABLED` | `true` | प्रमाणीकरण सक्षम/अक्षम करें |
|
||||
| `DEFAULT_USERNAME` | `admin` | डिफ़ॉल्ट एडमिन उपयोगकर्ता नाम |
|
||||
| `DEFAULT_PASSWORD` | `admin` | डिफ़ॉल्ट एडमिन पासवर्ड |
|
||||
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | अनिवार्य पासवर्ड बदलाव छोड़ें (केवल CI/डेव) |
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | प्रति मिनट API दर सीमा (0 = अक्षम) |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | MB में अधिकतम अपलोड आकार (0 = असीमित) |
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
description: "SnapOtter Docker image टैग, GPU बेंचमार्क, वर्शन पिनिंग, और AMD64 तथा ARM64 के लिए मल्टी-प्लेटफ़ॉर्म समर्थन।"
|
||||
i18n_source_hash: 148b3608e11a
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 5b607c2591dd
|
||||
---
|
||||
|
||||
# Docker Image {#docker-image}
|
||||
|
||||
SnapOtter एक single Docker image के रूप में उपलब्ध है। इसे अकेले चलाएँ तो यह loopback interface पर एक embedded PostgreSQL 17 और Redis शुरू कर देता है (embedded mode); production के लिए, इसे Compose के साथ अलग PostgreSQL 17 और Redis 8 containers के साथ चलाएँ। app image सभी platforms पर काम करता है।
|
||||
|
||||
## Quick start {#quick-start}
|
||||
|
||||
```bash
|
||||
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
कोई `DATABASE_URL` सेट न होने पर, यह embedded mode में चलता है: PostgreSQL और Redis container के भीतर loopback पर शुरू होते हैं, और सारा data `SnapOtter-data` volume के अंतर्गत रहता है। बाहरी services का उपयोग करने के लिए `DATABASE_URL` और `REDIS_URL` सेट करें (जैसा [Compose](#docker-compose) stack करता है)। देखें [Configuration](/hi/guide/configuration#embedded-mode)।
|
||||
|
||||
## NVIDIA CUDA acceleration {#nvidia-cuda-acceleration}
|
||||
|
||||
image में amd64 पर NVIDIA CUDA समर्थन शामिल है। यदि आपके पास [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) स्थापित के साथ एक NVIDIA GPU है, तो `--gpus all` जोड़ें:
|
||||
|
||||
```bash
|
||||
docker run -d --name SnapOtter --gpus all -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
image runtime पर CUDA का स्वतः पता लगा लेता है। `--gpus all` के बिना, या जब CUDA अनुपलब्ध हो, AI tools CPU पर चलते हैं। दोनों ही स्थिति में वही image।
|
||||
|
||||
VA-API, Quick Sync, या OpenCL के माध्यम से Intel/AMD iGPU acceleration फ़िलहाल SnapOtter AI inference के लिए समर्थित नहीं है। `/dev/dri` को container में map करने से render device उजागर हो सकता है, लेकिन जब तक CUDA उपलब्ध न हो, AI runtime फिर भी CPU का ही उपयोग करेगा।
|
||||
|
||||
### Benchmarks {#benchmarks}
|
||||
|
||||
एक NVIDIA RTX 4070 (12 GB VRAM) पर 572x1024 JPEG portrait के साथ परीक्षित।
|
||||
|
||||
#### Warm performance {#warm-performance}
|
||||
|
||||
| Tool | CPU | GPU | Speedup |
|
||||
|------|-----|-----|---------|
|
||||
| Background removal (u2net) | 2,415ms | 879ms | 2.7x |
|
||||
| Background removal (isnet) | 2,457ms | 1,137ms | 2.2x |
|
||||
| Upscale 2x | 350ms | 309ms | 1.1x |
|
||||
| Upscale 4x | 910ms | 310ms | 2.9x |
|
||||
| OCR (PaddleOCR) | 137ms | 94ms | 1.5x |
|
||||
| Face blur | 139ms | 122ms | 1.1x |
|
||||
|
||||
#### Cold start (container start के बाद पहला अनुरोध) {#cold-start-first-request-after-container-start}
|
||||
|
||||
| Tool | CPU | GPU | Speedup |
|
||||
|------|-----|-----|---------|
|
||||
| Background removal | 22,286ms | 4,792ms | 4.7x |
|
||||
| Upscale 2x | 3,957ms | 2,318ms | 1.7x |
|
||||
| OCR (PaddleOCR) | 1,469ms | 1,090ms | 1.3x |
|
||||
|
||||
### CUDA health check {#cuda-health-check}
|
||||
|
||||
पहले AI अनुरोध के बाद, admin health endpoint CUDA GPU status की रिपोर्ट देता है:
|
||||
|
||||
```
|
||||
GET /api/v1/admin/health
|
||||
{"ai": {"gpu": true}}
|
||||
```
|
||||
|
||||
## Docker Compose {#docker-compose}
|
||||
|
||||
पूर्ण Compose stack में app, PostgreSQL 17, और Redis 8 शामिल हैं। पूरे `docker-compose.yml` के लिए [Deployment](/hi/guide/deployment) देखें। एक न्यूनतम उदाहरण:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
ports:
|
||||
- "1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
Docker Compose के माध्यम से NVIDIA CUDA acceleration के लिए, SnapOtter service में deploy section जोड़ें:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
```
|
||||
|
||||
## Version pinning {#version-pinning}
|
||||
|
||||
| Tag | Description |
|
||||
|-----|------------|
|
||||
| `latest` | नवीनतम release |
|
||||
| `1.11.0` | सटीक version |
|
||||
| `1.11` | 1.11.x में नवीनतम patch |
|
||||
| `1` | 1.x में नवीनतम minor |
|
||||
|
||||
## Platforms {#platforms}
|
||||
|
||||
| Architecture | GPU support | Notes |
|
||||
|---|---|---|
|
||||
| linux/amd64 | NVIDIA CUDA | AI tools के लिए पूर्ण CUDA acceleration |
|
||||
| linux/arm64 | केवल CPU | Raspberry Pi 4/5, Docker Desktop के माध्यम से Apple Silicon |
|
||||
|
||||
## पिछले टैग से migration {#migration-from-previous-tags}
|
||||
|
||||
यदि आप `:cuda` tag का उपयोग कर रहे थे, तो `:latest` पर स्विच करें और `--gpus all` रखें। वही GPU support, एकीकृत image।
|
||||
|
||||
आपका data और settings volumes में संरक्षित रहते हैं।
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
description: "SnapOtter को एक ही कमांड में Docker के साथ इंस्टॉल करें। इसमें Docker Compose सेटअप, सोर्स से बिल्ड करना, और एक पूर्ण फ़ीचर अवलोकन शामिल है।"
|
||||
i18n_source_hash: 4536d4558b8e
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: bc1ecfa22bef
|
||||
---
|
||||
|
||||
# Getting Started {#getting-started}
|
||||
|
||||
::: tip इंस्टॉल करने से पहले आज़माएँ
|
||||
[demo.snapotter.com](https://demo.snapotter.com) पर पूरा UI एक्सप्लोर करें, कोई साइनअप या इंस्टॉल आवश्यक नहीं।
|
||||
:::
|
||||
|
||||
## Quick Start {#quick-start}
|
||||
|
||||
```bash
|
||||
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
यह एकल कंटेनर वह सब कुछ चलाता है जिसकी उसे ज़रूरत है: बिना कोई `DATABASE_URL` सेट किए, यह लूपबैक इंटरफ़ेस पर अपना खुद का PostgreSQL और Redis शुरू करता है (एंबेडेड मोड) और सारा डेटा `SnapOtter-data` वॉल्यूम में रखता है। यह SnapOtter को आज़माने या किसी homelab पर सेल्फ़-होस्ट करने का सबसे तेज़ तरीका है। प्रोडक्शन के लिए, नीचे दिया गया [Docker Compose](#docker-compose) स्टैक चलाएँ, जो PostgreSQL और Redis को उनके अपने कंटेनरों में रखता है। एंबेडेड मोड root के रूप में चलता है (डिफ़ॉल्ट) और जैसे ही आप `DATABASE_URL` सेट करते हैं, यह स्वचालित रूप से बंद हो जाता है।
|
||||
|
||||
पहले लॉगिन पर आपसे अपना पासवर्ड बदलने को कहा जाएगा।
|
||||
|
||||
::: tip अनाम उत्पाद एनालिटिक्स
|
||||
SnapOtter में डिफ़ॉल्ट रूप से अनाम उत्पाद एनालिटिक्स शामिल है। इसे बंद करने के लिए, **Settings → System → Privacy** खोलें और **Anonymous Product Analytics** को बंद कर दें। यह पूरे इंस्टेंस के लिए तुरंत रुक जाता है।
|
||||
|
||||
आप किसी रीबिल्ड के बिना इंस्टेंस के लिए सभी टेलीमेट्री अक्षम करने के लिए एनवायरनमेंट वेरिएबल `SNAPOTTER_TELEMETRY=0` भी सेट कर सकते हैं (`false` और `off` भी काम करते हैं)।
|
||||
|
||||
त्रुटि मॉनिटरिंग [Sentry](https://sentry.io) द्वारा संचालित है, जो अपने ओपन-सोर्स प्रोग्राम के माध्यम से SnapOtter को प्रायोजित करता है।
|
||||
|
||||
क्या संग्रहीत किया जाता है इसके विवरण के लिए, [SnapOtter क्या संग्रहीत करता है](/hi/guide/telemetry) देखें।
|
||||
:::
|
||||
|
||||
::: tip NVIDIA CUDA त्वरण
|
||||
NVIDIA CUDA-त्वरित बैकग्राउंड हटाने, अपस्केलिंग, OCR, फ़ेस एन्हांसमेंट, और रीस्टोरेशन के लिए `--gpus all` जोड़ें:
|
||||
|
||||
```bash
|
||||
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
[NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) आवश्यक है। CUDA अनुपलब्ध होने पर स्वचालित रूप से CPU पर फ़ॉलबैक करता है। VA-API, Quick Sync, या OpenCL के माध्यम से Intel/AMD iGPU त्वरण आज AI इन्फ़रेंस के लिए सपोर्ट नहीं किया जाता। बेंचमार्क के लिए [Docker Tags](/hi/guide/docker-tags) देखें।
|
||||
:::
|
||||
|
||||
::: details GHCR पर भी
|
||||
```bash
|
||||
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snapotter-hq/snapotter:latest
|
||||
```
|
||||
|
||||
दोनों रजिस्ट्री हर रिलीज़ पर वही इमेज प्रकाशित करती हैं।
|
||||
:::
|
||||
|
||||
## Docker Compose {#docker-compose}
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest
|
||||
ports:
|
||||
- "1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=admin
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
सभी एनवायरनमेंट वेरिएबल के लिए [Configuration](/hi/guide/configuration) देखें।
|
||||
|
||||
## Build from Source {#build-from-source}
|
||||
|
||||
**पूर्वापेक्षाएँ:** Node.js 22+, pnpm 9+, Docker (Postgres + Redis के लिए), Python 3.10+ (AI फ़ीचर के लिए), Git।
|
||||
|
||||
```bash
|
||||
git clone https://github.com/snapotter-hq/SnapOtter.git
|
||||
cd SnapOtter
|
||||
docker compose -f docker-compose.dev.yml up -d # start Postgres + Redis
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
- फ़्रंटएंड: [http://localhost:1349](http://localhost:1349)
|
||||
- बैकएंड: [http://localhost:13490](http://localhost:13490)
|
||||
|
||||
## What You Can Do {#what-you-can-do}
|
||||
|
||||
### File Processing (200+ Tools) {#file-processing-200-tools}
|
||||
|
||||
| मोडैलिटी | संख्या | उदाहरण टूल |
|
||||
|----------|-------|---------------|
|
||||
| **Image** | 105 | Resize, Crop, Compress, Convert, Remove Background, Upscale, OCR, Watermark, Collage, Colorize, GIF Tools, format presets |
|
||||
| **Video** | 57 | Trim, Crop, Compress, Convert, Merge, Extract Audio, Auto Subtitles, Video to GIF, Resize, Stabilize, format presets |
|
||||
| **Audio** | 27 | Trim, Merge, Convert, Normalize, Noise Reduction, Transcribe, Pitch Shift, Fade, Ringtone Maker, format presets |
|
||||
| **PDF / Document** | 42 | Merge, Split, Compress, OCR, Watermark, Redact, Word to PDF, Excel to PDF, Rotate, Protect, Repair |
|
||||
| **Files** | 10 | CSV to JSON, JSON to XML, Merge CSVs, Split CSV, Create ZIP, Extract ZIP, Chart Maker, YAML/JSON |
|
||||
|
||||
### Pipelines {#pipelines}
|
||||
|
||||
टूलों को बहु-चरणीय वर्कफ़्लो में जोड़ें और उन्हें एक इमेज या पूरे बैच पर लागू करें:
|
||||
|
||||
1. साइडबार में **Pipelines** खोलें।
|
||||
2. चरण जोड़ें (कोई भी टूल, कोई भी सेटिंग)।
|
||||
3. एक अकेली फ़ाइल पर चलाएँ, या एक साथ पूरे बैच पर।
|
||||
4. बाद में पुनः उपयोग के लिए पाइपलाइन सहेजें।
|
||||
|
||||
पाइपलाइन डिफ़ॉल्ट रूप से 20 चरणों की अनुमति देती हैं। सीमा को असीमित करने के लिए `MAX_PIPELINE_STEPS=0` सेट करें।
|
||||
|
||||
### File Library {#file-library}
|
||||
|
||||
आप जो भी फ़ाइल प्रोसेस करते हैं उसे अपनी **Files** लाइब्रेरी में सहेजा जा सकता है। SnapOtter पूरा वर्शन इतिहास ट्रैक करता है ताकि आप मूल अपलोड से अंतिम आउटपुट तक हर प्रोसेसिंग चरण का पता लगा सकें।
|
||||
|
||||
सहेजना स्पष्ट है: लाइब्रेरी में सहेजे गए परिणाम तब तक रखे जाते हैं जब तक आप उन्हें हटा नहीं देते, जबकि आप जिन परिणामों को प्रोसेस करते हैं और असहेजे छोड़ देते हैं वे 72 घंटे बाद स्वचालित रूप से साफ़ कर दिए जाते हैं (`FILE_MAX_AGE_HOURS` के माध्यम से कॉन्फ़िगर करने योग्य)।
|
||||
|
||||
### REST API & API Keys {#rest-api-api-keys}
|
||||
|
||||
हर टूल HTTP के माध्यम से सुलभ है:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:1349/api/v1/tools/image/resize \
|
||||
-H "Authorization: Bearer si_<your-api-key>" \
|
||||
-F "file=@photo.jpg" \
|
||||
-F 'settings={"width":800,"height":600,"fit":"cover"}'
|
||||
```
|
||||
|
||||
**Settings → API Keys** के अंतर्गत API कुंजियाँ उत्पन्न करें। सभी एंडपॉइंट के लिए [REST API reference](/hi/api/rest) देखें, या इंटरैक्टिव संदर्भ के लिए [http://localhost:1349/api/docs](http://localhost:1349/api/docs) पर जाएँ।
|
||||
|
||||
### Multi-User & Teams {#multi-user-teams}
|
||||
|
||||
रोल-आधारित एक्सेस नियंत्रण के साथ अनेक उपयोगकर्ता सक्षम करें:
|
||||
|
||||
- **Admin**: पूर्ण एक्सेस, उपयोगकर्ता, टीम, सेटिंग्स, सभी फ़ाइलें/पाइपलाइन/API कुंजियाँ प्रबंधित करें
|
||||
- **User**: टूल उपयोग करें, अपनी फ़ाइलें/पाइपलाइन/API कुंजियाँ प्रबंधित करें
|
||||
|
||||
उपयोगकर्ताओं को समूहित करने के लिए **Settings → Teams** के अंतर्गत टीम बनाएँ।
|
||||
|
||||
`AUTH_ENABLED=true` सेट करें (या बिना लॉगिन के एकल-उपयोगकर्ता/स्व-उपयोग के लिए `false`)।
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
description: "OpenID Connect के साथ Single Sign-On सेटअप करें। Keycloak, Authentik, Google, और अन्य OIDC providers के लिए चरण-दर-चरण गाइड।"
|
||||
i18n_source_hash: 4296343b3cc5
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 02d341718711
|
||||
---
|
||||
|
||||
# OIDC / Single Sign-On {#oidc-single-sign-on}
|
||||
|
||||
SnapOtter single sign-on के लिए OpenID Connect (OIDC) का समर्थन करता है। Users स्थानीय username/password authentication के बजाय (या उसके साथ-साथ) Keycloak, Authentik, या Google जैसे किसी बाहरी identity provider से login कर सकते हैं।
|
||||
|
||||
::: tip यह भी देखें
|
||||
[SAML SSO](/hi/guide/saml) | [SCIM Provisioning](/hi/guide/scim) | [Users, Roles और Permissions](/hi/guide/users-roles)
|
||||
:::
|
||||
|
||||
## Quick start {#quick-start}
|
||||
|
||||
अपने `docker-compose.yml` में ये environment variables जोड़ें:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
environment:
|
||||
EXTERNAL_URL: "https://photos.example.com"
|
||||
OIDC_ENABLED: "true"
|
||||
OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
|
||||
OIDC_CLIENT_ID: "snapotter"
|
||||
OIDC_CLIENT_SECRET: "your-secret-here"
|
||||
```
|
||||
|
||||
आपके provider के लिए redirect URI हमेशा यही होता है:
|
||||
|
||||
```
|
||||
${EXTERNAL_URL}/api/auth/oidc/callback
|
||||
```
|
||||
|
||||
उदाहरण के लिए, यदि `EXTERNAL_URL` `https://photos.example.com` है, तो अपने provider का redirect URI `https://photos.example.com/api/auth/oidc/callback` के रूप में configure करें।
|
||||
|
||||
## Configuration reference {#configuration-reference}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `OIDC_ENABLED` | `false` | OIDC login सक्षम करें। login page पर एक "Sign in with SSO" बटन दिखाई देता है। |
|
||||
| `OIDC_ISSUER_URL` | | Provider का issuer URL। OIDC Discovery (`/.well-known/openid-configuration`) का समर्थन करना चाहिए। |
|
||||
| `OIDC_CLIENT_ID` | | आपके provider के साथ पंजीकृत OAuth client ID। |
|
||||
| `OIDC_CLIENT_SECRET` | | OAuth client secret। |
|
||||
| `OIDC_SCOPES` | `openid profile email` | अनुरोध करने के लिए scopes की space-separated सूची। |
|
||||
| `OIDC_AUTO_CREATE_USERS` | `true` | पहली OIDC login पर स्वतः एक स्थानीय user account बनाएँ। |
|
||||
| `OIDC_DEFAULT_ROLE` | `user` | स्वतः बनाए गए OIDC users को सौंपी गई role। `admin`, `editor`, या `user` में से एक। |
|
||||
| `OIDC_AUTO_LINK_USERS` | `false` | यदि email पता मेल खाता है तो किसी OIDC पहचान को मौजूदा स्थानीय user से जोड़ें। |
|
||||
| `OIDC_PROVIDER_NAME` | | login बटन पर दिखाया गया display नाम (उदा. "Keycloak", "Google")। यदि खाली हो, तो बटन "SSO" कहता है। |
|
||||
| `OIDC_CLOCK_TOLERANCE` | `30` | token validation के लिए सेकंड में clock skew सहनशीलता। |
|
||||
| `OIDC_USERNAME_CLAIM` | `preferred_username` | नए accounts के लिए username के रूप में उपयोग किया जाने वाला ID token claim। |
|
||||
| `EXTERNAL_URL` | | वह सार्वजनिक URL जहाँ SnapOtter पहुँच योग्य है। सही redirect URI बनाने के लिए OIDC के लिए आवश्यक। |
|
||||
| `COOKIE_SECRET` | स्वतः-जनरेटेड | session cookies पर हस्ताक्षर करने के लिए secret। अनेक replicas चलाते समय इसे स्पष्ट रूप से सेट करें। |
|
||||
|
||||
## Provider guides {#provider-guides}
|
||||
|
||||
### Keycloak {#keycloak}
|
||||
|
||||
1. एक नया realm बनाएँ (या किसी मौजूदा का उपयोग करें)।
|
||||
2. **Clients** पर जाएँ और एक नया client बनाएँ:
|
||||
- **Client ID**: `snapotter`
|
||||
- **Client authentication**: On (confidential)
|
||||
- **Authentication flow**: Standard flow (Authorization Code)
|
||||
3. client के **Settings** टैब के अंतर्गत, **Valid redirect URIs** को अपने callback URL पर सेट करें (उदा. `https://photos.example.com/api/auth/oidc/callback`)।
|
||||
4. **Credentials** टैब से **Client secret** कॉपी करें।
|
||||
5. `OIDC_ISSUER_URL` को `https://keycloak.example.com/realms/your-realm` पर सेट करें।
|
||||
|
||||
### Authentik {#authentik}
|
||||
|
||||
1. admin interface में, **Applications > Providers** पर जाएँ और एक नया **OAuth2/OpenID Provider** बनाएँ।
|
||||
- **Client type**: Confidential
|
||||
- **Redirect URIs**: आपका callback URL
|
||||
- **Signing key**: कोई मौजूदा key चुनें या एक बनाएँ
|
||||
2. एक **Application** बनाएँ और उसे provider से लिंक करें।
|
||||
3. provider settings से **Client ID** और **Client Secret** कॉपी करें।
|
||||
4. `OIDC_ISSUER_URL` को `https://authentik.example.com/application/o/snapotter/` पर सेट करें (अंत का slash मायने रखता है)।
|
||||
|
||||
### Google {#google}
|
||||
|
||||
1. [Google Cloud Console](https://console.cloud.google.com/) पर जाएँ।
|
||||
2. एक project बनाएँ (या किसी मौजूदा को चुनें)।
|
||||
3. **APIs & Services > OAuth consent screen** पर जाएँ और उसे configure करें।
|
||||
4. **APIs & Services > Credentials** पर जाएँ और एक **OAuth 2.0 Client ID** बनाएँ:
|
||||
- **Application type**: Web application
|
||||
- **Authorized redirect URIs**: आपका callback URL
|
||||
5. **Client ID** और **Client secret** कॉपी करें।
|
||||
6. `OIDC_ISSUER_URL` को `https://accounts.google.com` पर सेट करें।
|
||||
7. `OIDC_USERNAME_CLAIM` को `email` पर सेट करें (Google `preferred_username` प्रदान नहीं करता)।
|
||||
|
||||
## User provisioning {#user-provisioning}
|
||||
|
||||
### Auto-create {#auto-create}
|
||||
|
||||
जब `OIDC_AUTO_CREATE_USERS` `true` हो (डिफ़ॉल्ट), तो जब कोई पहली बार OIDC के माध्यम से login करता है तब एक स्थानीय user account बनाया जाता है। username `OIDC_USERNAME_CLAIM` द्वारा निर्दिष्ट claim से लिया जाता है, और role `OIDC_DEFAULT_ROLE` पर सेट होती है।
|
||||
|
||||
यदि username टकराव होता है, तो एक संख्यात्मक suffix जोड़ा जाता है (उदा. `jane` `jane_2` बन जाता है)।
|
||||
|
||||
### Auto-link {#auto-link}
|
||||
|
||||
जब `OIDC_AUTO_LINK_USERS` `true` हो, तो यदि email पते मेल खाते हैं तो SnapOtter किसी OIDC पहचान को मौजूदा स्थानीय account से जोड़ देता है। यह तब उपयोगी है जब आपके पास पहले से बनाए गए user accounts हैं और आप चाहते हैं कि वे अपना data खोए बिना SSO का उपयोग शुरू करें।
|
||||
|
||||
::: warning
|
||||
auto-link केवल तभी सक्षम करें जब आप अपने OIDC provider पर email पतों को सत्यापित करने के लिए भरोसा करते हों। एक असत्यापित email किसी को दूसरे user के account पर कब्ज़ा करने की अनुमति दे सकता है।
|
||||
:::
|
||||
|
||||
### स्थानीय login को अक्षम करना {#disabling-local-login}
|
||||
|
||||
OIDC स्थानीय username/password login को अक्षम नहीं करता। दोनों विधियाँ उपलब्ध रहती हैं। यदि OIDC provider पहुँच से बाहर हो तो Admins अब भी स्थानीय credentials से login कर सकते हैं।
|
||||
|
||||
## Self-signed certificates {#self-signed-certificates}
|
||||
|
||||
यदि आपका OIDC provider एक self-signed या निजी CA certificate का उपयोग करता है, तो CA bundle को container में mount करें और `NODE_EXTRA_CA_CERTS` को उस पर इंगित करें:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
volumes:
|
||||
- ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
|
||||
environment:
|
||||
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
|
||||
OIDC_ENABLED: "true"
|
||||
OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
|
||||
OIDC_CLIENT_ID: "snapotter"
|
||||
OIDC_CLIENT_SECRET: "your-secret-here"
|
||||
```
|
||||
|
||||
::: danger
|
||||
`NODE_TLS_REJECT_UNAUTHORIZED=0` सेट न करें। यह सभी TLS verification को अक्षम कर देता है और एक सुरक्षा जोखिम है।
|
||||
:::
|
||||
|
||||
## Troubleshooting {#troubleshooting}
|
||||
|
||||
### Redirect URI mismatch {#redirect-uri-mismatch}
|
||||
|
||||
सबसे आम त्रुटि। आपका provider जो अपेक्षा करता है और SnapOtter जो भेजता है, उनके बीच इन अंतरों की जाँच करें:
|
||||
|
||||
- `http` बनाम `https` - scheme बिल्कुल मेल खाना चाहिए
|
||||
- अंत का slash - कुछ providers इस बारे में सख्त होते हैं
|
||||
- Port number - यदि यह non-standard हो तो port शामिल करें
|
||||
- Path - `/api/auth/oidc/callback` होना चाहिए
|
||||
|
||||
`EXTERNAL_URL` को दोबारा जाँचें। यह उस URL से मेल खाना चाहिए जो users अपने browser में टाइप करते हैं।
|
||||
|
||||
### UNABLE_TO_VERIFY_LEAF_SIGNATURE {#unable-to-verify-leaf-signature}
|
||||
|
||||
OIDC provider एक ऐसे certificate का उपयोग कर रहा है जिस पर Node.js भरोसा नहीं करता। ऊपर [Self-signed certificates](#self-signed-certificates) देखें।
|
||||
|
||||
### Clock skew त्रुटियाँ {#clock-skew-errors}
|
||||
|
||||
यदि आपके server की घड़ी और OIDC provider की घड़ी असंगत हैं, तो token validation विफल हो सकती है। `OIDC_CLOCK_TOLERANCE` बढ़ाएँ (डिफ़ॉल्ट 30 सेकंड है)। एक बेहतर समाधान दोनों मशीनों पर NTP चलाना है।
|
||||
|
||||
### "OIDC provider unreachable" {#oidc-provider-unreachable}
|
||||
|
||||
SnapOtter startup पर और login के दौरान provider का discovery document लाता है। जाँचें:
|
||||
|
||||
- Docker container के भीतर से DNS resolution (`docker exec snapotter nslookup auth.example.com`)
|
||||
- container और provider के बीच Firewall नियम
|
||||
- `OIDC_ISSUER_URL` मान - यह server से पहुँच योग्य होना चाहिए, केवल आपके browser से नहीं
|
||||
|
||||
### Missing claims {#missing-claims}
|
||||
|
||||
यदि login के बाद usernames या emails खाली हैं, तो हो सकता है आपका provider अपेक्षित claims न लौटा रहा हो। सत्यापित करें:
|
||||
|
||||
- `OIDC_SCOPES` में configure किए गए scopes में `profile` और `email` शामिल हैं
|
||||
- provider को ID token में `OIDC_USERNAME_CLAIM` द्वारा निर्दिष्ट claim शामिल करने के लिए configure किया गया है
|
||||
- कुछ providers को claims जारी करने के लिए स्पष्ट mapper/scope configuration की आवश्यकता होती है
|
||||
@@ -0,0 +1,224 @@
|
||||
---
|
||||
description: "SnapOtter के लिए SAML 2.0 Single Sign-On सेटअप करें। Okta, Azure AD / Entra ID, Google Workspace, और अन्य SAML identity providers के लिए चरण-दर-चरण गाइड।"
|
||||
i18n_source_hash: 33dfb8b02a22
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: f14eea5bfa2f
|
||||
---
|
||||
|
||||
# SAML SSO {#saml-sso}
|
||||
|
||||
SnapOtter single sign-on के लिए SAML 2.0 का समर्थन करता है। Users स्थानीय username/password authentication के बजाय किसी बाहरी identity provider (Okta, Azure AD / Entra ID, Google Workspace, या किसी मानक SAML 2.0 IdP) के माध्यम से login कर सकते हैं।
|
||||
|
||||
::: tip Enterprise feature
|
||||
SAML SSO के लिए `saml_sso` feature के साथ एक **team** या **enterprise** license आवश्यक है। यदि `SAML_ENABLED=true` बिना एक वैध license के सेट किया गया हो, तो SAML routes को चुपचाप छोड़ दिया जाता है और एक चेतावनी लॉग की जाती है।
|
||||
:::
|
||||
|
||||
## पूर्वापेक्षाएँ {#prerequisites}
|
||||
|
||||
- एक सार्वजनिक URL पर पहुँच योग्य एक चालू SnapOtter instance
|
||||
- `EXTERNAL_URL` उस सार्वजनिक URL पर सेट (उदा. `https://photos.example.com`)
|
||||
- `saml_sso` feature के साथ एक team या enterprise license key
|
||||
- आपके SAML identity provider तक Admin पहुँच
|
||||
|
||||
## Quick start {#quick-start}
|
||||
|
||||
अपने `docker-compose.yml` में ये environment variables जोड़ें:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
snapotter:
|
||||
image: snapotter/snapotter:latest
|
||||
environment:
|
||||
EXTERNAL_URL: "https://photos.example.com"
|
||||
SNAPOTTER_LICENSE_KEY: "your-license-key"
|
||||
SAML_ENABLED: "true"
|
||||
SAML_IDP_SSO_URL: "https://idp.example.com/sso/saml"
|
||||
SAML_IDP_CERTIFICATE: |
|
||||
MIICpDCCAYwCCQDU+pQ4pHgSpDANBgkqhkiG9w0BAQsFADAUMRIw
|
||||
...your IdP's signing certificate in PEM format...
|
||||
EAYHKoZIzj0CAQYFK4EEACIDYgAE
|
||||
```
|
||||
|
||||
container को पुनः आरंभ करें। login page पर एक "Sign in with SAML" बटन (या `SAML_PROVIDER_NAME` द्वारा सेट किया गया label) दिखाई देता है।
|
||||
|
||||
## Configuration reference {#configuration-reference}
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `SAML_ENABLED` | `false` | SAML login सक्षम करें। |
|
||||
| `SAML_IDP_SSO_URL` | | IdP का SSO endpoint URL। SAML सक्षम होने पर **आवश्यक**। |
|
||||
| `SAML_IDP_CERTIFICATE` | | PEM format में IdP का X.509 signing certificate (certificate का text ही, कोई file path नहीं)। SAML सक्षम होने पर **आवश्यक**। |
|
||||
| `EXTERNAL_URL` | | वह सार्वजनिक URL जहाँ SnapOtter पहुँच योग्य है। SAML सक्षम होने पर **आवश्यक**। |
|
||||
| `SAML_ENTITY_ID` | `${EXTERNAL_URL}/api/auth/saml/metadata` | IdP को भेजा गया SP Entity ID / Audience URI। |
|
||||
| `SAML_CALLBACK_URL` | `${EXTERNAL_URL}/api/auth/saml/callback` | Assertion Consumer Service (ACS) URL। |
|
||||
| `SAML_AUTO_CREATE_USERS` | `true` | पहली SAML login पर स्वतः एक स्थानीय user account बनाएँ। |
|
||||
| `SAML_AUTO_LINK_USERS` | `false` | यदि email पता मेल खाता है तो किसी SAML पहचान को मौजूदा स्थानीय user से जोड़ें। |
|
||||
| `SAML_DEFAULT_ROLE` | `user` | स्वतः बनाए गए SAML users को सौंपी गई role। `admin`, `editor`, या `user` में से एक। |
|
||||
| `SAML_PROVIDER_NAME` | | frontend पर SAML login बटन के लिए display label (उदा. "Okta", "Azure AD")। यदि खाली हो, तो बटन "SAML" कहता है। |
|
||||
| `SAML_USERNAME_ATTRIBUTE` | | username के रूप में उपयोग किया जाने वाला SAML assertion attribute। यदि खाली हो, तो email local-part, फिर NameID पर वापस चला जाता है। |
|
||||
| `SAML_EMAIL_ATTRIBUTE` | `email` | user के email पते के रूप में उपयोग किया जाने वाला SAML assertion attribute। |
|
||||
|
||||
यदि `SAML_ENABLED=true` और तीन आवश्यक variables (`SAML_IDP_SSO_URL`, `SAML_IDP_CERTIFICATE`, `EXTERNAL_URL`) में से कोई भी अनुपस्थित हो, तो server आरंभ होने से मना कर देता है।
|
||||
|
||||
::: details Security notes
|
||||
`wantAuthnResponseSigned` और `wantAssertionsSigned` दोनों `true` पर hardcoded हैं। SnapOtter बिना हस्ताक्षर वाली या अनुचित रूप से हस्ताक्षरित SAML responses को अस्वीकार कर देता है। किसी भरोसेमंद IdP से आई assertions को email-verified माना जाता है।
|
||||
|
||||
केवल SP-initiated login समर्थित है। SnapOtter IdP-initiated (unsolicited) login या Single Logout (SLO) का समर्थन नहीं करता। SnapOtter से logout करने पर user IdP से logout नहीं होता।
|
||||
:::
|
||||
|
||||
## SP metadata और URLs {#sp-metadata-and-urls}
|
||||
|
||||
आपके IdP को SnapOtter से तीन मानों की आवश्यकता होती है:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **ACS URL** (Assertion Consumer Service) | `${EXTERNAL_URL}/api/auth/saml/callback` |
|
||||
| **Entity ID** / **Audience URI** | `${EXTERNAL_URL}/api/auth/saml/metadata` |
|
||||
| **SP Metadata** (XML) | `GET ${EXTERNAL_URL}/api/auth/saml/metadata` |
|
||||
|
||||
उदाहरण के लिए, यदि `EXTERNAL_URL` `https://photos.example.com` है:
|
||||
|
||||
- ACS URL: `https://photos.example.com/api/auth/saml/callback`
|
||||
- Entity ID: `https://photos.example.com/api/auth/saml/metadata`
|
||||
- Metadata endpoint: `https://photos.example.com/api/auth/saml/metadata` (XML लौटाता है)
|
||||
|
||||
कुछ IdPs SP metadata URL को सीधे import कर सकते हैं, जो ACS URL और Entity ID को स्वतः भर देता है।
|
||||
|
||||
## Provider setup {#provider-setup}
|
||||
|
||||
### Okta {#okta}
|
||||
|
||||
1. Okta admin console में, **Applications > Create App Integration** पर जाएँ।
|
||||
2. **SAML 2.0** चुनें और **Next** पर क्लिक करें।
|
||||
3. एक नाम सेट करें (उदा. "SnapOtter") और **Next** पर क्लिक करें।
|
||||
4. SAML settings configure करें:
|
||||
- **Single sign-on URL**: आपका ACS URL (उदा. `https://photos.example.com/api/auth/saml/callback`)
|
||||
- **Audience URI (SP Entity ID)**: आपका Entity ID (उदा. `https://photos.example.com/api/auth/saml/metadata`)
|
||||
- **Name ID format**: EmailAddress
|
||||
- **Application username**: Email
|
||||
5. **Attribute Statements** के अंतर्गत, `email` को `user.email` पर mapped करके जोड़ें।
|
||||
6. **Next**, फिर **Finish** पर क्लिक करें।
|
||||
7. **Sign On** टैब पर जाएँ, **View SAML setup instructions** पर क्लिक करें, और कॉपी करें:
|
||||
- **Identity Provider Single Sign-On URL** को `SAML_IDP_SSO_URL` में
|
||||
- **X.509 Certificate** को `SAML_IDP_CERTIFICATE` में
|
||||
|
||||
### Azure AD / Entra ID {#azure-ad-entra-id}
|
||||
|
||||
1. Azure portal में, **Microsoft Entra ID > Enterprise applications > New application** पर जाएँ।
|
||||
2. **Create your own application** पर क्लिक करें, इसे "SnapOtter" नाम दें, और **Integrate any other application you don't find in the gallery** चुनें।
|
||||
3. **Single sign-on > SAML** पर जाएँ और **Basic SAML Configuration** section पर **Edit** क्लिक करें:
|
||||
- **Identifier (Entity ID)**: आपका Entity ID (उदा. `https://photos.example.com/api/auth/saml/metadata`)
|
||||
- **Reply URL (ACS URL)**: आपका ACS URL (उदा. `https://photos.example.com/api/auth/saml/callback`)
|
||||
4. **SAML Certificates** के अंतर्गत, **Certificate (Base64)** डाउनलोड करें।
|
||||
5. **Set up SnapOtter** के अंतर्गत, **Login URL** कॉपी करें।
|
||||
6. `SAML_IDP_SSO_URL` को Login URL पर और `SAML_IDP_CERTIFICATE` को डाउनलोड किए गए certificate की सामग्री पर सेट करें।
|
||||
7. **Users and groups** के अंतर्गत application को users या groups सौंपें।
|
||||
|
||||
### Google Workspace {#google-workspace}
|
||||
|
||||
1. Google Admin console में, **Apps > Web and mobile apps > Add app > Add custom SAML app** पर जाएँ।
|
||||
2. app को "SnapOtter" नाम दें और **Continue** पर क्लिक करें।
|
||||
3. **Google Identity Provider details** page पर, **SSO URL** कॉपी करें और **Certificate** डाउनलोड करें। **Continue** पर क्लिक करें।
|
||||
4. Service Provider विवरण configure करें:
|
||||
- **ACS URL**: आपका ACS URL (उदा. `https://photos.example.com/api/auth/saml/callback`)
|
||||
- **Entity ID**: आपका Entity ID (उदा. `https://photos.example.com/api/auth/saml/metadata`)
|
||||
- **Name ID format**: EMAIL
|
||||
- **Name ID**: Basic Information > Primary email
|
||||
5. **Continue**, फिर **Finish** पर क्लिक करें।
|
||||
6. अपने organizational units के लिए app को **ON** करें।
|
||||
7. `SAML_IDP_SSO_URL` को step 3 के SSO URL पर और `SAML_IDP_CERTIFICATE` को डाउनलोड किए गए certificate की सामग्री पर सेट करें।
|
||||
|
||||
### Generic SAML 2.0 IdP {#generic-saml-2-0-idp}
|
||||
|
||||
किसी भी SAML 2.0 अनुरूप identity provider के लिए:
|
||||
|
||||
1. अपने IdP में एक नया SAML application/service provider बनाएँ।
|
||||
2. **ACS URL** को `${EXTERNAL_URL}/api/auth/saml/callback` पर सेट करें।
|
||||
3. **Entity ID** / **Audience** को `${EXTERNAL_URL}/api/auth/saml/metadata` पर सेट करें।
|
||||
4. IdP को `email` नामक attribute में user का email भेजने के लिए configure करें (या अपने IdP के attribute नाम से मेल खाने के लिए `SAML_EMAIL_ATTRIBUTE` सेट करें)।
|
||||
5. **IdP SSO URL** और **signing certificate** को `SAML_IDP_SSO_URL` और `SAML_IDP_CERTIFICATE` में कॉपी करें।
|
||||
|
||||
## User provisioning {#user-provisioning}
|
||||
|
||||
### Auto-create {#auto-create}
|
||||
|
||||
जब `SAML_AUTO_CREATE_USERS` `true` हो (डिफ़ॉल्ट), तो जब कोई पहली बार SAML के माध्यम से login करता है तब एक स्थानीय user account बनाया जाता है। role `SAML_DEFAULT_ROLE` पर सेट होती है।
|
||||
|
||||
username इस क्रम में लिया जाता है:
|
||||
|
||||
1. `SAML_USERNAME_ATTRIBUTE` द्वारा निर्दिष्ट assertion attribute का मान (यदि सेट और मौजूद हो)
|
||||
2. email पते का local-part (`@` से पहले का सब कुछ)
|
||||
3. SAML NameID
|
||||
|
||||
यदि username टकराव होता है, तो एक संख्यात्मक suffix जोड़ा जाता है (उदा. `jane` `jane_2` बन जाता है)।
|
||||
|
||||
### Auto-link {#auto-link}
|
||||
|
||||
जब `SAML_AUTO_LINK_USERS` `true` हो, तो यदि email पते मेल खाते हैं तो SnapOtter किसी SAML पहचान को मौजूदा स्थानीय account से जोड़ देता है। यह तब उपयोगी है जब आपके पास पहले से बनाए गए user accounts हैं और आप चाहते हैं कि वे अपना data खोए बिना SSO का उपयोग शुरू करें।
|
||||
|
||||
::: warning
|
||||
auto-link केवल तभी सक्षम करें जब आप अपने SAML IdP पर email पतों को सत्यापित करने के लिए भरोसा करते हों। किसी गलत configure किए गए IdP से आया एक असत्यापित email किसी को दूसरे user के account पर कब्ज़ा करने की अनुमति दे सकता है।
|
||||
:::
|
||||
|
||||
### Attribute mapping {#attribute-mapping}
|
||||
|
||||
| SnapOtter field | Source | Configuration |
|
||||
|---|---|---|
|
||||
| Email | Assertion attribute | `SAML_EMAIL_ATTRIBUTE` (default: `email`) |
|
||||
| Username | Assertion attribute, email, या NameID | `SAML_USERNAME_ATTRIBUTE` (ऊपर दिया derivation क्रम देखें) |
|
||||
| External ID | NameID | हमेशा SAML NameID, configurable नहीं |
|
||||
|
||||
## SSO enforcement {#sso-enforcement}
|
||||
|
||||
यदि आप चाहते हैं कि सभी users SAML (या OIDC) के माध्यम से login करें और स्थानीय password login को रोकें, तो SSO enforcement सक्षम करें:
|
||||
|
||||
1. सुनिश्चित करें कि `sso_enforcement` enterprise feature licensed है (team और enterprise plans पर उपलब्ध)।
|
||||
2. **Admin Settings > Security** में, **SSO Enforcement** को on टॉगल करें।
|
||||
3. एक **break-glass username** सेट करें: यह वह एकमात्र स्थानीय account है जो अब भी password से login कर सकता है, IdP के पहुँच से बाहर होने पर आपातकालीन पहुँच के लिए।
|
||||
|
||||
जब SSO enforcement सक्रिय हो, तो किसी भी स्थानीय login प्रयास (break-glass user को छोड़कर) पर "Local password login is disabled. Please use SSO." संदेश के साथ एक 403 त्रुटि लौटती है।
|
||||
|
||||
::: tip
|
||||
SSO enforcement सक्षम करने से पहले हमेशा एक break-glass username configure करें। इसके बिना, यदि आपका IdP डाउन हो जाता है तो आप SnapOtter से बाहर लॉक हो सकते हैं।
|
||||
:::
|
||||
|
||||
## OIDC के साथ SAML का उपयोग करना {#using-saml-alongside-oidc}
|
||||
|
||||
SAML और OIDC को एक साथ सक्षम किया जा सकता है। जब दोनों सक्रिय हों, तो login page हर provider के लिए अलग बटन दिखाता है (`SAML_PROVIDER_NAME` और `OIDC_PROVIDER_NAME` द्वारा labeled)। Users किसी भी विधि से login कर सकते हैं।
|
||||
|
||||
दोनों providers समान auto-create, auto-link, और SSO enforcement settings को स्वतंत्र रूप से साझा करते हैं: हर एक के अपने `*_AUTO_CREATE_USERS`, `*_AUTO_LINK_USERS`, और `*_DEFAULT_ROLE` variables होते हैं।
|
||||
|
||||
## Troubleshooting {#troubleshooting}
|
||||
|
||||
### Assertion validation failed {#assertion-validation-failed}
|
||||
|
||||
SAML response signature या assertion signature सत्यापित नहीं की जा सकी। जाँचें:
|
||||
|
||||
- `SAML_IDP_CERTIFICATE` में certificate आपके IdP में वर्तमान signing certificate से मेल खाता है (certificates rotate होते हैं, इसलिए expiry की जाँच करें)
|
||||
- certificate PEM format में है (`-----BEGIN CERTIFICATE-----` से शुरू होता है)
|
||||
- certificate पूरा text है, कोई file path नहीं
|
||||
- आपके IdP में configure किए गए ACS URL और Entity ID SnapOtter के मानों से बिल्कुल मेल खाते हैं (scheme, host, port, path)
|
||||
|
||||
### Missing attributes {#missing-attributes}
|
||||
|
||||
यदि login के बाद usernames या emails खाली हैं, तो हो सकता है आपका IdP अपेक्षित attributes न भेज रहा हो। जाँचें:
|
||||
|
||||
- आपका IdP एक `email` attribute (या जो भी `SAML_EMAIL_ATTRIBUTE` सेट किया गया हो) जारी करने के लिए configure किया गया है
|
||||
- यदि `SAML_USERNAME_ATTRIBUTE` का उपयोग कर रहे हैं, तो सत्यापित करें कि वह attribute assertion में शामिल है
|
||||
- कुछ IdPs को claims जारी करने से पहले स्पष्ट attribute mapping configuration की आवश्यकता होती है
|
||||
|
||||
### Clock skew {#clock-skew}
|
||||
|
||||
SAML assertions में timestamp conditions (`NotBefore`, `NotOnOrAfter`) शामिल होती हैं। यदि आपके server की घड़ी और IdP की घड़ी असंगत हैं, तो assertion validation विफल हो जाती है। घड़ियों को संरेखित रखने के लिए दोनों मशीनों पर NTP चलाएँ।
|
||||
|
||||
### "SAML is enabled via env but saml_sso enterprise feature is not licensed" {#saml-is-enabled-via-env-but-saml-sso-enterprise-feature-is-not-licensed}
|
||||
|
||||
यह चेतावनी server logs में तब दिखाई देती है जब `SAML_ENABLED=true` लेकिन license में `saml_sso` feature शामिल नहीं है। अपना license key और plan सत्यापित करें। `saml_sso` feature team और enterprise plans पर उपलब्ध है।
|
||||
|
||||
### Login redirects back with error {#login-redirects-back-with-error}
|
||||
|
||||
यदि SAML login बटन पर क्लिक करने से एक त्रुटि के साथ login page पर वापस redirect होता है, तो विवरण के लिए server logs जाँचें। सामान्य कारण:
|
||||
|
||||
- IdP SSO URL server से पहुँच से बाहर है
|
||||
- IdP ने authentication अनुरोध अस्वीकार कर दिया (IdP के audit logs जाँचें)
|
||||
- IdP ने एक बिना हस्ताक्षर वाला response लौटाया (SnapOtter को response और assertion दोनों के हस्ताक्षरित होने की आवश्यकता है)
|
||||
@@ -0,0 +1,298 @@
|
||||
---
|
||||
description: "अपने identity provider से SnapOtter में users और groups को sync करने के लिए SCIM 2.0 provisioning सेट करें। Okta, Azure AD / Entra ID, और custom integrations को कवर करता है।"
|
||||
i18n_source_hash: bbd50119ec12
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: cec58a6b3f0c
|
||||
---
|
||||
|
||||
# SCIM Provisioning {#scim-provisioning}
|
||||
|
||||
SnapOtter स्वचालित user और group provisioning के लिए SCIM 2.0 (System for Cross-domain Identity Management) लागू करता है। आपका identity provider user accounts को स्वचालित रूप से बना, अपडेट, निष्क्रिय, और पुनः सक्रिय कर सकता है और group memberships को sync कर सकता है।
|
||||
|
||||
::: tip Enterprise feature
|
||||
SCIM provisioning के लिए `scim` feature वाली एक **enterprise** license आवश्यक है। यह team plan पर उपलब्ध नहीं है। इस feature के बिना, सभी SCIM endpoints (discovery को छोड़कर) 403 लौटाते हैं।
|
||||
:::
|
||||
|
||||
## Prerequisites {#prerequisites}
|
||||
|
||||
- एक चालू SnapOtter instance जो एक public URL पर पहुँच योग्य हो
|
||||
- `scim` feature वाली एक enterprise license key
|
||||
- SnapOtter तक admin access (SCIM token जनरेट या रद्द करने के लिए `users:manage` permission आवश्यक है)
|
||||
- आपके identity provider की provisioning settings तक admin access
|
||||
|
||||
## Quick start {#quick-start}
|
||||
|
||||
1. एक SCIM bearer token जनरेट करें:
|
||||
|
||||
```bash
|
||||
curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
|
||||
-H "Cookie: snapotter-session=YOUR_SESSION" \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
Response में token होता है। इसे तुरंत सहेजें; इसे फिर से प्राप्त नहीं किया जा सकता।
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "a1b2c3d4e5f6...",
|
||||
"message": "Save this token - it cannot be retrieved again"
|
||||
}
|
||||
```
|
||||
|
||||
2. अपने identity provider में, SCIM provisioning को इनके साथ configure करें:
|
||||
- **Base URL**: `https://photos.example.com/api/v1/scim/v2`
|
||||
- **Authentication**: Bearer token (step 1 का token पेस्ट करें)
|
||||
|
||||
## Authentication {#authentication}
|
||||
|
||||
SCIM endpoints एक समर्पित Bearer token का उपयोग करते हैं, जो user sessions और API keys से अलग है।
|
||||
|
||||
### Generating a token {#generating-a-token}
|
||||
|
||||
`POST /api/v1/enterprise/scim/token` एक नया SCIM token जनरेट करता है। इस endpoint के लिए `users:manage` permission वाला एक वैध session आवश्यक है।
|
||||
|
||||
Token plaintext में ठीक एक बार लौटाया जाता है। SnapOtter केवल एक scrypt hash संग्रहीत करता है। यदि आप token खो देते हैं, तो उसे रद्द करें और एक नया जनरेट करें।
|
||||
|
||||
एक समय में केवल एक SCIM token सक्रिय रहता है। एक नया token जनरेट करने से पिछला token बदल जाता है।
|
||||
|
||||
### Revoking a token {#revoking-a-token}
|
||||
|
||||
`DELETE /api/v1/enterprise/scim/token` वर्तमान SCIM token को रद्द करता है। इस endpoint के लिए भी `users:manage` आवश्यक है।
|
||||
|
||||
### Rate limiting {#rate-limiting}
|
||||
|
||||
SCIM endpoints प्रति token प्रति मिनट 1000 requests तक rate-limited हैं। इस सीमा से अधिक होने पर HTTP 429 लौटाया जाता है।
|
||||
|
||||
## Supported resources {#supported-resources}
|
||||
|
||||
| SCIM resource | SnapOtter concept | Create | Read | Update | Delete |
|
||||
|---|---|---|---|---|---|
|
||||
| User | User account | Yes | Yes | Yes | Soft delete |
|
||||
| Group | Team | Yes | Yes | Yes | Yes |
|
||||
|
||||
::: warning
|
||||
SCIM Groups SnapOtter **teams** से मैप होते हैं, roles से नहीं। SCIM किसी user की role सेट नहीं कर सकता। SCIM के माध्यम से बनाए गए सभी users को `user` role सौंपी जाती है। किसी user की role बदलने के लिए, SnapOtter admin UI का उपयोग करें।
|
||||
:::
|
||||
|
||||
## User operations {#user-operations}
|
||||
|
||||
### Create user {#create-user}
|
||||
|
||||
`POST /api/v1/scim/v2/Users`
|
||||
|
||||
`authProvider` को `scim` पर सेट करके और `user` role के साथ एक नया user account बनाता है। User को Default team में सौंपा जाता है। यदि `active` `false` है, तो इसके बजाय role को `disabled` पर सेट किया जाता है।
|
||||
|
||||
आवश्यक attributes: `userName`. वैकल्पिक: `externalId`, `emails`, `active` (default `true`).
|
||||
|
||||
### List and filter users {#list-and-filter-users}
|
||||
|
||||
`GET /api/v1/scim/v2/Users`
|
||||
|
||||
users की एक paginated सूची लौटाता है। `startIndex` और `count` query parameters का समर्थन करता है (अधिकतम 200 results प्रति page)।
|
||||
|
||||
Filtering केवल इन attributes पर `eq` (equals) का समर्थन करती है:
|
||||
|
||||
- `userName eq "jane"`
|
||||
- `externalId eq "ext-12345"`
|
||||
|
||||
अन्य filter operators और attributes HTTP 400 लौटाते हैं।
|
||||
|
||||
### Get user {#get-user}
|
||||
|
||||
`GET /api/v1/scim/v2/Users/:id`
|
||||
|
||||
किसी user को उसके SnapOtter user ID द्वारा एकल रूप में लौटाता है।
|
||||
|
||||
### Replace user {#replace-user}
|
||||
|
||||
`PUT /api/v1/scim/v2/Users/:id`
|
||||
|
||||
user के attributes को बदल देता है। `userName`, `externalId`, `emails`, और `active` का समर्थन करता है। Username परिवर्तनों को conflicts के लिए जाँचा जाता है (409 यदि नया username किसी अन्य user द्वारा लिया गया है)।
|
||||
|
||||
### Patch user {#patch-user}
|
||||
|
||||
`PATCH /api/v1/scim/v2/Users/:id`
|
||||
|
||||
SCIM PatchOp का उपयोग करके आंशिक अपडेट। समर्थित operations:
|
||||
|
||||
| Operation | Paths |
|
||||
|---|---|
|
||||
| `replace` | `active`, `userName`, `externalId`, `emails`, `emails[type eq "work"].value`, `name.formatted`, `displayName` |
|
||||
| `add` | `replace` के समान |
|
||||
| `remove` | `externalId`, `emails` |
|
||||
|
||||
`name.formatted` और `displayName` paths संगतता के लिए स्वीकार किए जाते हैं लेकिन उनका कोई स्थायी प्रभाव नहीं होता (SnapOtter एक अलग display name संग्रहीत नहीं करता)।
|
||||
|
||||
Valueless `replace` operations (जहाँ value एक object है जिसमें `path` नहीं है) भी समर्थित हैं, keys `userName`, `externalId`, `emails`, और `active` के साथ।
|
||||
|
||||
### Deactivate user (soft delete) {#deactivate-user-soft-delete}
|
||||
|
||||
`DELETE /api/v1/scim/v2/Users/:id`
|
||||
|
||||
SnapOtter SCIM के माध्यम से users को hard-delete नहीं करता। इसके बजाय, DELETE एक soft deactivation करता है:
|
||||
|
||||
1. user की role उसके वर्तमान मान (जैसे `editor`) से `disabled:editor` में बदल दी जाती है, मूल role को संरक्षित करते हुए।
|
||||
2. user का password साफ़ कर दिया जाता है।
|
||||
3. सभी सक्रिय sessions रद्द कर दिए जाते हैं।
|
||||
4. सभी API keys रद्द कर दी जाती हैं।
|
||||
|
||||
user अब log in नहीं कर सकता या किसी API key का उपयोग नहीं कर सकता। उनका data (files, history) बरकरार रहता है।
|
||||
|
||||
### Reactivate user {#reactivate-user}
|
||||
|
||||
पहले से निष्क्रिय किए गए user को पुनः सक्रिय करने के लिए, `active: true` के साथ एक `PUT` या `PATCH` request भेजें। SnapOtter deactivation से पहले की मूल role को पुनर्स्थापित करता है (जैसे `disabled:editor` फिर से `editor` बन जाता है)। यदि मूल role निर्धारित नहीं की जा सकती, तो यह `user` पर वापस आ जाती है।
|
||||
|
||||
::: details उदाहरण: PATCH के माध्यम से deactivate और reactivate
|
||||
```json
|
||||
// Deactivate
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
"Operations": [
|
||||
{ "op": "replace", "path": "active", "value": false }
|
||||
]
|
||||
}
|
||||
|
||||
// Reactivate
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
"Operations": [
|
||||
{ "op": "replace", "path": "active", "value": true }
|
||||
]
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## Group operations {#group-operations}
|
||||
|
||||
SCIM Groups SnapOtter teams से मैप होते हैं। एक group बनाने से एक team बनती है। Group membership नियंत्रित करती है कि कोई user किस team से संबंधित है।
|
||||
|
||||
### Create group {#create-group}
|
||||
|
||||
`POST /api/v1/scim/v2/Groups`
|
||||
|
||||
आवश्यक: `displayName`. वैकल्पिक: `members` (`{ value: userId }` का array)।
|
||||
|
||||
### List and filter groups {#list-and-filter-groups}
|
||||
|
||||
`GET /api/v1/scim/v2/Groups`
|
||||
|
||||
Filtering केवल `displayName eq "..."` का समर्थन करती है। `startIndex` और `count` के साथ paginated (अधिकतम 200 results प्रति page)।
|
||||
|
||||
### Get group {#get-group}
|
||||
|
||||
`GET /api/v1/scim/v2/Groups/:id`
|
||||
|
||||
### Replace group {#replace-group}
|
||||
|
||||
`PUT /api/v1/scim/v2/Groups/:id`
|
||||
|
||||
group name और पूरी membership सूची को बदल देता है। नई सूची में न होने वाले मौजूदा members को Default team में स्थानांतरित कर दिया जाता है।
|
||||
|
||||
### Patch group {#patch-group}
|
||||
|
||||
`PATCH /api/v1/scim/v2/Groups/:id`
|
||||
|
||||
इन operations का समर्थन करता है:
|
||||
|
||||
| Operation | Path | Effect |
|
||||
|---|---|---|
|
||||
| `add` | `members` | users को team में जोड़ता है |
|
||||
| `remove` | `members[value eq "userId"]` | user को Default team में स्थानांतरित करता है |
|
||||
| `replace` | `displayName` | team का नाम बदलता है |
|
||||
| `replace` | `members` | सभी members को बदल देता है (हटाए गए members Default team में चले जाते हैं) |
|
||||
|
||||
### Delete group {#delete-group}
|
||||
|
||||
`DELETE /api/v1/scim/v2/Groups/:id`
|
||||
|
||||
team को हटा देता है। हटाई गई team के सभी members को Default team में स्थानांतरित कर दिया जाता है। users को निष्क्रिय या हटाया नहीं जाता।
|
||||
|
||||
## IdP setup {#idp-setup}
|
||||
|
||||
### Okta {#okta}
|
||||
|
||||
1. Okta admin console में, अपना SnapOtter application खोलें (या एक बनाएँ)।
|
||||
2. **Provisioning** tab पर जाएँ और **Configure API Integration** क्लिक करें।
|
||||
3. **Enable API Integration** चेक करें और दर्ज करें:
|
||||
- **Base URL**: `https://photos.example.com/api/v1/scim/v2`
|
||||
- **API Token**: ऊपर जनरेट किया गया SCIM bearer token
|
||||
4. **Test API Credentials** क्लिक करें, फिर **Save** क्लिक करें।
|
||||
5. **Provisioning > To App** के तहत, सक्षम करें:
|
||||
- **Create Users**
|
||||
- **Update User Attributes**
|
||||
- **Deactivate Users**
|
||||
6. **Push Groups** के तहत, configure करें कि कौन से Okta groups को SnapOtter teams के रूप में sync करना है।
|
||||
|
||||
### Azure AD / Entra ID {#azure-ad-entra-id}
|
||||
|
||||
1. Azure portal में, अपने SnapOtter enterprise application पर जाएँ।
|
||||
2. **Provisioning** पर जाएँ और **Provisioning Mode** को **Automatic** पर सेट करें।
|
||||
3. **Admin Credentials** के तहत, दर्ज करें:
|
||||
- **Tenant URL**: `https://photos.example.com/api/v1/scim/v2`
|
||||
- **Secret Token**: ऊपर जनरेट किया गया SCIM bearer token
|
||||
4. **Test Connection** क्लिक करें, फिर **Save** क्लिक करें।
|
||||
5. **Mappings** के तहत, user और group attribute mappings को configure करें। Defaults आमतौर पर काम करते हैं, लेकिन सत्यापित करें कि `userName` इच्छानुसार `userPrincipalName` या `mail` पर मैप होता है।
|
||||
6. **Provisioning Status** को **On** पर सेट करें और सहेजें।
|
||||
|
||||
Azure एक निश्चित sync cycle पर users और groups को provision करता है (आमतौर पर हर 40 मिनट में)।
|
||||
|
||||
## Discovery endpoints {#discovery-endpoints}
|
||||
|
||||
ये तीन endpoints authentication के बिना उपलब्ध हैं और SCIM server की क्षमताओं का वर्णन करते हैं:
|
||||
|
||||
| Endpoint | Description |
|
||||
|---|---|
|
||||
| `GET /api/v1/scim/v2/ServiceProviderConfig` | Server capabilities और supported features |
|
||||
| `GET /api/v1/scim/v2/Schemas` | User और Group schema definitions |
|
||||
| `GET /api/v1/scim/v2/ResourceTypes` | उपलब्ध resource types (User, Group) |
|
||||
|
||||
`ServiceProviderConfig` इन क्षमताओं का विज्ञापन करता है:
|
||||
|
||||
| Feature | Supported |
|
||||
|---|---|
|
||||
| Patch | Yes |
|
||||
| Bulk | No |
|
||||
| Filter | Yes (अधिकतम 200 results, केवल `eq` operator) |
|
||||
| Change password | No |
|
||||
| Sort | No |
|
||||
| ETag | No |
|
||||
|
||||
## Limitations {#limitations}
|
||||
|
||||
- **Filtering**: केवल `eq` operator समर्थित है। Complex filters, `and`/`or` operators, `co` (contains), और `sw` (starts with) लागू नहीं किए गए हैं।
|
||||
- **Bulk operations**: समर्थित नहीं।
|
||||
- **Sort और ETag**: समर्थित नहीं।
|
||||
- **Roles**: SCIM SnapOtter roles सौंप नहीं सकता। सभी provisioned users को `user` role मिलती है।
|
||||
- **MAX_USERS**: SCIM user creation पर `MAX_USERS` environment variable सीमा लागू नहीं होती। यदि आपको user counts सीमित करने की आवश्यकता है, तो अपने IdP में assignments प्रबंधित करें।
|
||||
- **One token**: एक समय में केवल एक SCIM token सक्रिय हो सकता है। यदि कई IdPs को SCIM access की आवश्यकता है, तो उन्हें token साझा करना होगा।
|
||||
- **Groups are teams**: SCIM Groups teams के अनुरूप होते हैं, roles या permission groups के नहीं।
|
||||
|
||||
## Troubleshooting {#troubleshooting}
|
||||
|
||||
### 403 "SCIM provisioning requires an enterprise license with the scim feature" {#_403-scim-provisioning-requires-an-enterprise-license-with-the-scim-feature}
|
||||
|
||||
आपकी license में `scim` feature शामिल नहीं है, या कोई license configure नहीं है। SCIM के लिए एक enterprise plan license आवश्यक है। सत्यापित करें कि `SNAPOTTER_LICENSE_KEY` सेट है और license में `scim` feature शामिल है।
|
||||
|
||||
### 401 "Bearer token required" {#_401-bearer-token-required}
|
||||
|
||||
SCIM request में एक `Authorization: Bearer <token>` header शामिल नहीं था। अपने IdP की provisioning configuration जाँचें।
|
||||
|
||||
### 401 "Invalid token" {#_401-invalid-token}
|
||||
|
||||
Token संग्रहीत hash से मेल नहीं खाता। यह तब होता है जब token रद्द कर दिया गया और फिर से जनरेट किया गया। अपने IdP की provisioning settings में token अपडेट करें।
|
||||
|
||||
### 401 "SCIM not configured" {#_401-scim-not-configured}
|
||||
|
||||
अभी तक कोई SCIM token जनरेट नहीं किया गया है। एक बनाने के लिए `POST /api/v1/enterprise/scim/token` endpoint का उपयोग करें।
|
||||
|
||||
### 409 "User already exists" / "userName already taken" {#_409-user-already-exists-username-already-taken}
|
||||
|
||||
समान username वाला एक user पहले से मौजूद है। यह तब हो सकता है जब कोई IdP किसी विफल create को पुनः प्रयास करता है। SnapOtter admin panel में डुप्लिकेट usernames की जाँच करें।
|
||||
|
||||
### 429 "SCIM rate limit exceeded" {#_429-scim-rate-limit-exceeded}
|
||||
|
||||
IdP प्रति मिनट 1000 से अधिक requests भेज रहा है। यह आमतौर पर एक बड़े प्रारंभिक sync के दौरान होता है। अधिकांश IdPs rate limit window रीसेट होने के बाद स्वचालित रूप से पुनः प्रयास करते हैं। यदि समस्या बनी रहती है, तो अपने IdP का provisioning sync interval जाँचें।
|
||||
|
||||
### Users deprovisioned but not removed from the UI {#users-deprovisioned-but-not-removed-from-the-ui}
|
||||
|
||||
SCIM DELETE एक soft deactivation है। निष्क्रिय किए गए users अभी भी admin user सूची में disabled status के साथ दिखाई देते हैं। यह डिज़ाइन के अनुसार है ताकि उनका data संरक्षित रहे। उनकी role `disabled:<original-role>` के रूप में दिखाई देती है।
|
||||
@@ -0,0 +1,339 @@
|
||||
---
|
||||
description: "SnapOtter के लिए सुरक्षा हार्डनिंग गाइड। कंटेनर सुरक्षा, नेटवर्क आइसोलेशन, Docker secrets, Kubernetes डिप्लॉयमेंट, और अनुपालन आर्टिफ़ैक्ट।"
|
||||
i18n_source_hash: 986f7658430c
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: cc08062b0496
|
||||
---
|
||||
|
||||
# Security & Hardening {#security-hardening}
|
||||
|
||||
SnapOtter फ़ाइलों को पूरी तरह आपके इन्फ़्रास्ट्रक्चर पर प्रोसेस करता है। यह प्रोजेक्ट को बेहतर बनाने में मदद के लिए डिफ़ॉल्ट रूप से अनाम, सामग्री-रहित उत्पाद एनालिटिक्स और क्रैश रिपोर्ट भेजता है। यह कभी आपकी फ़ाइलें, फ़ाइल नाम, फ़ाइल सामग्री, OCR आउटपुट, इमेज मेटाडेटा, या दस्तावेज़ टेक्स्ट नहीं भेजता। वैकल्पिक फ़ीडबैक केवल तभी भेजा जाता है जब कोई उपयोगकर्ता उसे सबमिट करता है, केवल तभी जब एनालिटिक्स सक्षम हो, और संपर्क फ़ील्ड केवल स्पष्ट संपर्क सहमति के साथ ही शामिल होते हैं। एक व्यवस्थापक Settings > System > Privacy के अंतर्गत एक क्लिक में एनालिटिक्स और फ़ीडबैक कैप्चर बंद कर सकता है, किसी रीबिल्ड की आवश्यकता नहीं। फ़ाइल प्रोसेसिंग हमेशा आपके कंटेनर के अंदर ही रहती है।
|
||||
|
||||
कंटेनर एक समर्पित गैर-root उपयोगकर्ता (`snapotter`) के रूप में चलता है, जिसमें न्यूनतम आवश्यक सेट को छोड़कर सभी Linux क्षमताएँ हटा दी जाती हैं। पूर्ण भेद्यता प्रकटीकरण नीति और सुरक्षा आर्किटेक्चर के लिए, GitHub पर [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) देखें।
|
||||
|
||||
## Container Hardening {#container-hardening}
|
||||
|
||||
[डिफ़ॉल्ट docker-compose.yml](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) में प्रोडक्शन सुरक्षा हार्डनिंग शामिल है। यहाँ हर विकल्प का विवरण और यह क्यों मायने रखता है:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
ports:
|
||||
# Bind to localhost only for internet-facing deployments:
|
||||
- "127.0.0.1:1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_PASSWORD=change-me-immediately
|
||||
- RATE_LIMIT_PER_MIN=1000
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
# --- Resource limits ---
|
||||
mem_limit: 6g # Prevents runaway memory from crashing the host
|
||||
memswap_limit: 6g # No swap - fail fast instead of degrading the host
|
||||
cpus: 4 # Cap CPU usage to 4 cores
|
||||
pids_limit: 512 # Prevents fork bombs
|
||||
|
||||
# --- Capability restrictions ---
|
||||
cap_drop:
|
||||
- ALL # Drop ALL Linux capabilities first
|
||||
cap_add:
|
||||
- CHOWN # Needed for volume permission setup
|
||||
- SETUID # Needed for gosu privilege drop (root -> snapotter)
|
||||
- SETGID # Needed for gosu privilege drop
|
||||
- DAC_OVERRIDE # Needed for volume permission setup
|
||||
- FOWNER # Needed for volume permission setup
|
||||
|
||||
# --- Logging ---
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "50m" # Rotate logs at 50 MB
|
||||
max-file: "5" # Keep 5 rotated log files
|
||||
|
||||
# --- Health check ---
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "--max-time", "5", "http://localhost:1349/api/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
|
||||
shm_size: "2gb" # Required for Python ML shared memory
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
### Why `no-new-privileges` Is Not Set {#why-no-new-privileges-is-not-set}
|
||||
|
||||
`security_opt: [no-new-privileges:true]` को जानबूझकर छोड़ दिया गया है। एंट्रीपॉइंट वॉल्यूम स्वामित्व ठीक करने के लिए root के रूप में शुरू होता है, फिर [gosu](https://github.com/tianon/gosu) के माध्यम से `snapotter` उपयोगकर्ता पर गिर जाता है, जिसके लिए setuid आवश्यक है। एक बार विशेषाधिकार गिरना पूरा हो जाने पर, प्रक्रिया `snapotter` के रूप में चलती है, जिसमें ऊपर सूचीबद्ध पाँच को छोड़कर सभी क्षमताएँ हटा दी जाती हैं।
|
||||
|
||||
यदि आप सीधे गैर-root के रूप में चलाने के लिए Kubernetes या Docker के `--user` फ़्लैग का उपयोग करते हैं (gosu को बायपास करते हुए), तो `no-new-privileges` को सक्षम करना सुरक्षित है।
|
||||
|
||||
### Why `read_only` Is Not Set {#why-read-only-is-not-set}
|
||||
|
||||
`read_only: true` सेट नहीं है क्योंकि PUID/PGID रीमैपिंग स्टार्टअप पर `/etc/passwd` और `/etc/group` पर लिखती है। यदि आप PUID/PGID के बजाय Docker के `--user` फ़्लैग या Kubernetes `runAsUser` का उपयोग करते हैं, तो आप सुरक्षित रूप से एक read-only रूट फ़ाइलसिस्टम सक्षम कर सकते हैं।
|
||||
|
||||
## Network Isolation {#network-isolation}
|
||||
|
||||
सामान्य संचालन के दौरान, कंटेनर **शून्य आउटबाउंड नेटवर्क कनेक्शन** बनाता है। सारी फ़ाइल प्रोसेसिंग बंडल की गई लाइब्रेरियों का उपयोग करके स्थानीय रूप से होती है।
|
||||
|
||||
```
|
||||
Browser --> Reverse Proxy (TLS) --> SnapOtter container --> (nothing)
|
||||
```
|
||||
|
||||
एकमात्र अपवाद **AI मॉडल डाउनलोड** है: जब कोई उपयोगकर्ता UI के माध्यम से एक AI फ़ीचर बंडल इंस्टॉल करता है, तो कंटेनर Hugging Face से पहले से बना बंडल आर्काइव डाउनलोड करता है, साथ ही GitHub Releases, Google Storage, और PyPI से कुछ अलग-अलग मॉडल फ़ाइलें। ये डाउनलोड प्रति बंडल एक बार होते हैं और `/data` वॉल्यूम में संग्रहीत किए जाते हैं।
|
||||
|
||||
**फ़ायरवॉल अनुशंसाएँ:**
|
||||
|
||||
| परिदृश्य | आउटबाउंड नियम |
|
||||
|---|---|
|
||||
| Air-gapped (कोई AI नहीं) | कंटेनर से सभी आउटबाउंड ट्रैफ़िक ब्लॉक करें |
|
||||
| AI बंडल आवश्यक | इंस्टॉल के दौरान `huggingface.co`, `*.xethub.hf.co`, `cdn-lfs.huggingface.co`, `github.com`, `objects.githubusercontent.com`, `storage.googleapis.com`, `pypi.org`, `files.pythonhosted.org` पर HTTPS की अनुमति दें, फिर ब्लॉक करें |
|
||||
| AI इंस्टॉल के बाद | सभी आउटबाउंड ट्रैफ़िक ब्लॉक करें, मॉडल स्थानीय रूप से कैश हो जाते हैं |
|
||||
|
||||
बंडल आर्काइव Hugging Face के Xet स्टोरेज से परोसे जाते हैं, जो `*.xethub.hf.co` एंडपॉइंट पर समानांतर में स्थानांतरित होता है और यही मल्टी-GB बंडल डाउनलोड को तेज़ बनाता है। यदि आपका फ़ायरवॉल `huggingface.co` की अनुमति देता है पर `*.xethub.hf.co` को ब्लॉक करता है, तो इंस्टॉल फिर भी सफल होते हैं पर एक धीमे सिंगल-स्ट्रीम डाउनलोड पर फ़ॉलबैक करते हैं, इसलिए तेज़ रास्ते पर बने रहने के लिए Xet होस्ट को allowlist करें। पूरी तरह ऑफ़लाइन इंस्टॉल इस सबको छोड़ सकते हैं और इसके बजाय [Offline Bundle Import](/hi/guide/deployment) का उपयोग कर सकते हैं।
|
||||
|
||||
रिवर्स प्रॉक्सी कॉन्फ़िगरेशन (Nginx, Traefik, Caddy, Cloudflare Tunnels) के लिए, [Deployment गाइड](/hi/guide/deployment#reverse-proxy) देखें।
|
||||
|
||||
## Docker Secrets {#docker-secrets}
|
||||
|
||||
प्रोडक्शन डिप्लॉयमेंट के लिए, secrets को सादा-टेक्स्ट एनवायरनमेंट वेरिएबल के रूप में पास करने से बचें। एंट्रीपॉइंट Docker के `_FILE` कन्वेंशन को सपोर्ट करता है: एक secret को फ़ाइल के रूप में माउंट करें और संबंधित `_FILE` वेरिएबल को उसके पथ पर सेट करें।
|
||||
|
||||
**सपोर्टेड secrets:**
|
||||
|
||||
| वेरिएबल | `_FILE` समकक्ष |
|
||||
|---|---|
|
||||
| `DEFAULT_PASSWORD` | `DEFAULT_PASSWORD_FILE` |
|
||||
| `COOKIE_SECRET` | `COOKIE_SECRET_FILE` |
|
||||
| `OIDC_CLIENT_SECRET` | `OIDC_CLIENT_SECRET_FILE` |
|
||||
| `S3_ACCESS_KEY_ID` | `S3_ACCESS_KEY_ID_FILE` |
|
||||
| `S3_SECRET_ACCESS_KEY` | `S3_SECRET_ACCESS_KEY_FILE` |
|
||||
| `SNAPOTTER_LICENSE_KEY` | `SNAPOTTER_LICENSE_KEY_FILE` |
|
||||
|
||||
**Docker Compose secrets के साथ उदाहरण:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD_FILE=/run/secrets/snapotter_password
|
||||
- COOKIE_SECRET_FILE=/run/secrets/cookie_secret
|
||||
secrets:
|
||||
- snapotter_password
|
||||
- cookie_secret
|
||||
|
||||
secrets:
|
||||
snapotter_password:
|
||||
file: ./secrets/snapotter_password.txt
|
||||
cookie_secret:
|
||||
file: ./secrets/cookie_secret.txt
|
||||
```
|
||||
|
||||
::: tip
|
||||
Docker Compose secrets (Swarm के बिना) के लिए Compose v2.23 या बाद का संस्करण आवश्यक है।
|
||||
:::
|
||||
|
||||
## Kubernetes Deployment {#kubernetes-deployment}
|
||||
|
||||
एंट्रीपॉइंट पता लगाता है कि कंटेनर पहले से गैर-root के रूप में चल रहा है (उदा., Kubernetes `runAsUser` के माध्यम से) और स्वचालित रूप से gosu विशेषाधिकार गिरना छोड़ देता है। उस स्थिति में यह माउंट किए गए वॉल्यूम को स्वयं chown नहीं कर सकता, इसलिए यह सत्यापित करता है कि वे लिखने योग्य हैं और यदि नहीं हैं तो कार्रवाई-योग्य मार्गदर्शन के साथ जल्दी बाहर निकल जाता है, `fsGroup` और विदेशी-UID सेटअप (TrueNAS, OpenShift) के लिए [Storage permissions](/hi/guide/deployment#storage-permissions) देखें।
|
||||
|
||||
**अनुशंसित Pod SecurityContext:**
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: snapotter
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: snapotter
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: snapotter
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 999
|
||||
runAsGroup: 999
|
||||
fsGroup: 999
|
||||
containers:
|
||||
- name: snapotter
|
||||
image: snapotter/snapotter:latest
|
||||
ports:
|
||||
- containerPort: 1349
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: [ALL]
|
||||
resources:
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 2Gi
|
||||
limits:
|
||||
cpu: "4"
|
||||
memory: 6Gi
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: 1349
|
||||
initialDelaySeconds: 60
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 5
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: 1349
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: workspace
|
||||
mountPath: /tmp/workspace
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: snapotter-data
|
||||
- name: workspace
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 2Gi
|
||||
```
|
||||
|
||||
चूँकि `runAsUser: 999` पॉड स्तर पर सेट है, एंट्रीपॉइंट gosu को पूरी तरह छोड़ देता है। यह `allowPrivilegeEscalation: false` और `drop: [ALL]` क्षमताओं को बिना टकराव के अनुमति देता है।
|
||||
|
||||
रिसोर्स आकार निर्धारण के लिए, [Hardware Requirements](/hi/guide/deployment#hardware-requirements) देखें।
|
||||
|
||||
## Backup and Recovery {#backup-and-recovery}
|
||||
|
||||
स्थायी स्थिति दो वॉल्यूम में विभाजित है:
|
||||
|
||||
| वॉल्यूम | सामग्री | महत्वपूर्ण? |
|
||||
|---|---|---|
|
||||
| `SnapOtter-pgdata` | PostgreSQL डेटाबेस (उपयोगकर्ता, सेटिंग्स, पाइपलाइन, जॉब, ऑडिट लॉग) | हाँ |
|
||||
| `/data` (ऐप वॉल्यूम) | उपयोगकर्ता-अपलोड की गई फ़ाइलें, AI मॉडल, Python venv | आंशिक रूप से (नीचे देखें) |
|
||||
|
||||
`/data` वॉल्यूम के भीतर:
|
||||
|
||||
| पथ | सामग्री | महत्वपूर्ण? |
|
||||
|---|---|---|
|
||||
| `/data/uploads/`, `/data/outputs/` | उपयोगकर्ता फ़ाइलें और प्रोसेसिंग परिणाम | हाँ |
|
||||
| `/data/ai/` | डाउनलोड की गई AI मॉडल फ़ाइलें | नहीं (पुनः-डाउनलोड करने योग्य) |
|
||||
| `/data/venv/` | Python वर्चुअल एनवायरनमेंट | नहीं (स्टार्ट पर पुनर्निर्मित) |
|
||||
|
||||
### Database backup {#database-backup}
|
||||
|
||||
स्टैक चलते समय डेटाबेस का बैकअप लेने के लिए `pg_dump` का उपयोग करें:
|
||||
|
||||
```bash
|
||||
# Dump the database
|
||||
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
|
||||
|
||||
# Restore into a fresh database
|
||||
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
|
||||
```
|
||||
|
||||
वैकल्पिक रूप से, स्टैक बंद करें और `SnapOtter-pgdata` वॉल्यूम का स्नैपशॉट लें:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
|
||||
```
|
||||
|
||||
### User files backup {#user-files-backup}
|
||||
|
||||
```bash
|
||||
# Snapshot the app data volume (excluding re-downloadable AI models)
|
||||
docker run --rm -v SnapOtter-data:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-files.tar.gz \
|
||||
--exclude='ai' --exclude='venv' -C /data .
|
||||
```
|
||||
|
||||
सभी बंडलों में AI मॉडल कुल मिलाकर लगभग 24 GB तक होते हैं। चूँकि वे पुनः-डाउनलोड करने योग्य हैं, स्थान बचाने के लिए बैकअप से `/data/ai/` और `/data/venv/` को बाहर रखें। केवल डेटाबेस और उपयोगकर्ता फ़ाइलें महत्वपूर्ण हैं।
|
||||
|
||||
## Compliance Artifacts {#compliance-artifacts}
|
||||
|
||||
हर SnapOtter रिलीज़ में निम्नलिखित सुरक्षा आर्टिफ़ैक्ट शामिल होते हैं:
|
||||
|
||||
| आर्टिफ़ैक्ट | फ़ॉर्मैट | इसे कहाँ खोजें |
|
||||
|---|---|---|
|
||||
| SBOM (CycloneDX) | JSON | [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases) एसेट: `snapotter-v{version}-sbom.cdx.json` |
|
||||
| SBOM (SPDX) | JSON | [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases) एसेट: `snapotter-v{version}-sbom.spdx.json` |
|
||||
| भेद्यता स्कैन | Trivy JSON | [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases) एसेट: `snapotter-v{version}-trivy.json` |
|
||||
| भेद्यता स्कैन | SARIF | [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) टैब |
|
||||
| स्थैतिक विश्लेषण | CodeQL (JS/TS + Python) | [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) टैब, साप्ताहिक + प्रति PR चलता है |
|
||||
| निर्भरता समीक्षा | GitHub native | प्रति-PR जाँच, उच्च-गंभीरता जोड़ पर विफल |
|
||||
| Python निर्भरता ऑडिट | pip-audit | हर push पर CI रन लॉग |
|
||||
| सुरक्षा नीति | Markdown | रिपॉज़िटरी में [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) |
|
||||
| निर्भरता अद्यतन | Dependabot | npm, pip, Docker, Actions के लिए स्वचालित साप्ताहिक PR |
|
||||
|
||||
**अपना खुद का स्कैन चलाना:**
|
||||
|
||||
रिलीज़ से SBOM डाउनलोड करें और अपने पसंदीदा टूल से इसे स्कैन करें:
|
||||
|
||||
```bash
|
||||
# Scan with Grype using the CycloneDX SBOM
|
||||
grype sbom:snapotter-v1.17.2-sbom.cdx.json
|
||||
|
||||
# Scan with Trivy using the SPDX SBOM
|
||||
trivy sbom snapotter-v1.17.2-sbom.spdx.json
|
||||
|
||||
# Scan the Docker image directly
|
||||
trivy image snapotter/snapotter:1.17.2
|
||||
```
|
||||
|
||||
::: info
|
||||
SBOM और भेद्यता स्कैन उस रिलीज़ के लिए प्रकाशित सटीक इमेज को दर्शाते हैं। डिप्लॉयमेंट के बाद इंस्टॉल किए गए AI मॉडल बंडल SBOM में शामिल नहीं होते क्योंकि वे रनटाइम पर डाउनलोड किए जाते हैं।
|
||||
:::
|
||||
@@ -0,0 +1,239 @@
|
||||
---
|
||||
description: "सभी modalities में समर्थित file formats - 55+ image input formats, video, audio, PDF, और file formats।"
|
||||
i18n_source_hash: e53ecf65be25
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: ce09fe20d2b2
|
||||
---
|
||||
|
||||
# Supported Formats {#supported-formats}
|
||||
|
||||
SnapOtter पाँच modalities में files process करता है: image, video, audio, PDF, और files। यह page सभी समर्थित formats सूचीबद्ध करता है।
|
||||
|
||||
## Image Formats {#image-formats}
|
||||
|
||||
SnapOtter input के लिए 55+ image formats और output के लिए 13 formats का समर्थन करता है।
|
||||
|
||||
## Input Formats {#input-formats}
|
||||
|
||||
### Web Standards (9) {#web-standards-9}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| JPEG | .jpg, .jpeg | Sharp (native) | |
|
||||
| PNG | .png | Sharp (native) | APNG first-frame निकाला गया |
|
||||
| WebP | .webp | Sharp (native) | |
|
||||
| GIF | .gif | Sharp (native) | Animated समर्थित |
|
||||
| AVIF | .avif | Sharp (native) | |
|
||||
| SVG | .svg | Sharp (librsvg) | XXE/SSRF के लिए sanitized |
|
||||
| SVGZ | .svgz | gunzip + Sharp | Gzip bomb protection |
|
||||
| APNG | .apng | Sharp (native) | केवल first frame |
|
||||
| JPEG XL | .jxl | djxl / ImageMagick | Two-tier fallback |
|
||||
|
||||
### Professional (7) {#professional-7}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| TIFF | .tiff, .tif | Sharp (native) | Multi-page समर्थित |
|
||||
| PSD | .psd | ImageMagick | Flattened composite |
|
||||
| EPS | .eps, .epsf | ImageMagick + Ghostscript | 300dpi rasterization, security hardened |
|
||||
| OpenEXR | .exr | ImageMagick | Linear-to-sRGB conversion |
|
||||
| Radiance HDR | .hdr | ImageMagick | Linear-to-sRGB conversion |
|
||||
| DPX | .dpx | ImageMagick | Log-to-sRGB conversion |
|
||||
| Cineon | .cin | ImageMagick | Film/VFX format |
|
||||
|
||||
### Camera RAW (23) {#camera-raw-23}
|
||||
|
||||
| Format | Extensions | Camera Brand | Decoder |
|
||||
|--------|-----------|-------------|---------|
|
||||
| DNG | .dng | Adobe (universal) | exiftool / ImageMagick + LibRaw |
|
||||
| CR2 | .cr2 | Canon (pre-2018) | exiftool / ImageMagick + LibRaw |
|
||||
| CR3 | .cr3 | Canon (2018+) | exiftool / ImageMagick + LibRaw |
|
||||
| NEF | .nef | Nikon | exiftool / ImageMagick + LibRaw |
|
||||
| NRW | .nrw | Nikon (Coolpix) | exiftool / ImageMagick + LibRaw |
|
||||
| ARW | .arw | Sony | exiftool / ImageMagick + LibRaw |
|
||||
| ORF | .orf | Olympus | exiftool / ImageMagick + LibRaw |
|
||||
| RW2 | .rw2 | Panasonic | exiftool / ImageMagick + LibRaw |
|
||||
| RAF | .raf | Fujifilm | exiftool / ImageMagick + LibRaw |
|
||||
| PEF | .pef | Pentax/Ricoh | exiftool / ImageMagick + LibRaw |
|
||||
| 3FR | .3fr | Hasselblad | exiftool / ImageMagick + LibRaw |
|
||||
| IIQ | .iiq | Phase One | exiftool / ImageMagick + LibRaw |
|
||||
| SRW | .srw | Samsung | exiftool / ImageMagick + LibRaw |
|
||||
| X3F | .x3f | Sigma | exiftool / ImageMagick + LibRaw |
|
||||
| RWL | .rwl | Leica | exiftool / ImageMagick + LibRaw |
|
||||
| GPR | .gpr | GoPro | exiftool / ImageMagick + LibRaw |
|
||||
| FFF | .fff | Hasselblad (legacy) | exiftool / ImageMagick + LibRaw |
|
||||
| MRW | .mrw | Minolta | exiftool / ImageMagick + LibRaw |
|
||||
| MEF | .mef | Mamiya | exiftool / ImageMagick + LibRaw |
|
||||
| KDC | .kdc | Kodak | exiftool / ImageMagick + LibRaw |
|
||||
| DCR | .dcr | Kodak | exiftool / ImageMagick + LibRaw |
|
||||
| ERF | .erf | Epson | exiftool / ImageMagick + LibRaw |
|
||||
| PTX | .ptx | Pentax (compact) | exiftool / ImageMagick + LibRaw |
|
||||
|
||||
### Modern Formats (3) {#modern-formats-3}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| JPEG 2000 | .jp2, .j2k, .j2c, .jpc, .jpf, .jpx | opj_decompress / ImageMagick | Digital cinema, medical imaging |
|
||||
| QOI | .qoi | Inline TypeScript codec | Game dev, embedded systems |
|
||||
| HEIC/HEIF | .heic, .heif | heif-convert / heif-dec | iPhone photos |
|
||||
|
||||
### Legacy/System (4) {#legacy-system-4}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| BMP | .bmp | ImageMagick | |
|
||||
| ICO | .ico | ImageMagick | सबसे बड़ी layer निकाली गई |
|
||||
| CUR | .cur | ImageMagick | Windows cursor (ICO variant) |
|
||||
| TGA | .tga | ImageMagick | केवल-extension detection |
|
||||
|
||||
### Scientific and Gaming (2) {#scientific-and-gaming-2}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| FITS | .fits, .fit, .fts | ImageMagick | Astronomy (NASA standard) |
|
||||
| DDS | .dds | ImageMagick | Game textures (DirectX) |
|
||||
|
||||
### Interchange (6) {#interchange-6}
|
||||
|
||||
| Format | Extensions | Decoder | Notes |
|
||||
|--------|-----------|---------|-------|
|
||||
| PPM | .ppm | Sharp (native) | Color pixmap |
|
||||
| PGM | .pgm | Sharp (native) | Grayscale |
|
||||
| PBM | .pbm | Sharp (native) | 1-bit bitmap |
|
||||
| PNM | .pnm | Sharp (native) | Umbrella format |
|
||||
| PAM | .pam | Sharp (native) | Arbitrary map |
|
||||
| PFM | .pfm | Sharp (native) | Float map |
|
||||
|
||||
## Output Formats (13) {#output-formats-13}
|
||||
|
||||
| Format | Encoder | Quality Control | Available In |
|
||||
|--------|---------|----------------|-------------|
|
||||
| JPEG | Sharp native | 1-100 | सभी tools |
|
||||
| PNG | Sharp native | Compression 0-9 | सभी tools |
|
||||
| WebP | Sharp native | 1-100 | सभी tools |
|
||||
| AVIF | Sharp native | 1-100 | सभी tools |
|
||||
| TIFF | Sharp native | 1-100 | Full conversion tools |
|
||||
| GIF | Sharp native | 1-100 | Full conversion tools |
|
||||
| JXL | Sharp native | 1-100 | सभी tools |
|
||||
| HEIC | heif-enc CLI | 1-100 | Full conversion tools |
|
||||
| HEIF | heif-enc CLI | 1-100 | Full conversion tools |
|
||||
| BMP | ImageMagick CLI | Lossless | Convert tool |
|
||||
| ICO | ImageMagick CLI | Lossless | Convert tool |
|
||||
| JP2 | opj_compress CLI | Compression ratio | Convert tool |
|
||||
| QOI | Inline codec | Lossless | Convert tool |
|
||||
|
||||
## Video Formats {#video-formats}
|
||||
|
||||
Video decoding और encoding FFmpeg (static build) द्वारा संभाले जाते हैं, इसलिए हर सामान्य container और codec input पर समर्थित है।
|
||||
|
||||
### Input Containers (15) {#input-containers-15}
|
||||
|
||||
| Format | Extensions | Typical codecs | Notes |
|
||||
|--------|-----------|----------------|-------|
|
||||
| MP4 | .mp4 | H.264, H.265, AV1 | सबसे व्यापक रूप से उपयोग किया जाने वाला container |
|
||||
| QuickTime | .mov | H.264, ProRes | Apple capture/editing |
|
||||
| WebM | .webm | VP8, VP9, AV1 | Royalty-free web format |
|
||||
| Matroska | .mkv | Any | Flexible open container |
|
||||
| AVI | .avi | Various | Legacy Microsoft container |
|
||||
| M4V | .m4v | H.264 | Apple MP4 variant |
|
||||
| AVCHD | .mts | H.264 | Camcorder recordings |
|
||||
| BDAV | .m2ts | H.264 | Blu-ray / AVCHD transport stream |
|
||||
| 3GP | .3gp | H.264, MPEG-4 | Mobile capture |
|
||||
| Flash Video | .flv | H.264, VP6 | Legacy streaming |
|
||||
| Windows Media | .wmv | VC-1, WMV | Windows Media |
|
||||
| MPEG | .mpg, .mpeg | MPEG-1, MPEG-2 | DVD-era video |
|
||||
| MPEG-TS | .ts | MPEG-2, H.264 | Broadcast transport stream |
|
||||
| Ogg | .ogv | Theora | Open Ogg video |
|
||||
|
||||
### Output Formats {#output-formats}
|
||||
|
||||
| Format | Extension | Video codec | Produced by |
|
||||
|--------|-----------|-------------|-------------|
|
||||
| MP4 | .mp4 | H.264 | Convert, compress, और अधिकांश video tools |
|
||||
| QuickTime | .mov | H.264 | Convert Video |
|
||||
| WebM | .webm | VP9 | Convert Video |
|
||||
| GIF | .gif | - | Video to GIF |
|
||||
| WebP | .webp | - | Video to WebP (animated) |
|
||||
|
||||
### Subtitles {#subtitles}
|
||||
|
||||
| Format | Extension | Operations |
|
||||
|--------|-----------|-----------|
|
||||
| SubRip | .srt | Embed, burn-in, extract, auto-generate |
|
||||
| WebVTT | .vtt | Embed, burn-in, extract, auto-generate |
|
||||
| ASS / SSA | .ass | Embed, burn-in (styling का समर्थन करता है) |
|
||||
|
||||
## Audio Formats {#audio-formats}
|
||||
|
||||
Audio भी FFmpeg द्वारा process किया जाता है।
|
||||
|
||||
### Input Formats (11) {#input-formats-11}
|
||||
|
||||
| Format | Extensions | Compression | Notes |
|
||||
|--------|-----------|-------------|-------|
|
||||
| MP3 | .mp3 | Lossy | Universal compatibility |
|
||||
| WAV | .wav | Uncompressed (PCM) | Studio / editing |
|
||||
| FLAC | .flac | Lossless | Open lossless codec |
|
||||
| AAC | .aac | Lossy | Raw AAC stream |
|
||||
| M4A | .m4a | Lossy (AAC) / Lossless (ALAC) | MPEG-4 audio |
|
||||
| Ogg Vorbis | .ogg | Lossy | Open format |
|
||||
| Opus | .opus | Lossy | Modern, low-latency |
|
||||
| WMA | .wma | Lossy | Windows Media Audio |
|
||||
| AIFF | .aiff | Uncompressed (PCM) | Apple uncompressed |
|
||||
| AMR | .amr | Lossy | Speech / mobile |
|
||||
| AC-3 | .ac3 | Lossy | Dolby Digital |
|
||||
|
||||
### Output Formats {#output-formats-1}
|
||||
|
||||
| Format | Extension | Codec | Produced by |
|
||||
|--------|-----------|-------|-------------|
|
||||
| MP3 | .mp3 | LAME | Convert Audio, Extract Audio |
|
||||
| WAV | .wav | PCM | Convert Audio, Extract Audio |
|
||||
| FLAC | .flac | FLAC (lossless) | Convert Audio |
|
||||
| Ogg | .ogg | Vorbis | Convert Audio |
|
||||
| M4A | .m4a | AAC | Convert Audio, Extract Audio |
|
||||
|
||||
## Document Formats {#document-formats}
|
||||
|
||||
Document processing qpdf, LibreOffice, Ghostscript, Pandoc, और WeasyPrint का उपयोग करता है।
|
||||
|
||||
### Input Formats (15) {#input-formats-15}
|
||||
|
||||
| Format | Extensions | Engine | Notes |
|
||||
|--------|-----------|--------|-------|
|
||||
| PDF | .pdf | qpdf, Ghostscript, pdfcpu | Core document format |
|
||||
| Word | .docx, .doc | LibreOffice | Microsoft Word |
|
||||
| Excel | .xlsx, .xls | LibreOffice | Microsoft Excel |
|
||||
| PowerPoint | .pptx, .ppt | LibreOffice | Microsoft PowerPoint |
|
||||
| OpenDocument | .odt, .ods, .odp | LibreOffice | Text, sheet, presentation |
|
||||
| Rich Text | .rtf | LibreOffice | Cross-app rich text |
|
||||
| Plain Text | .txt | LibreOffice, Pandoc | UTF-8 text |
|
||||
| Markdown | .md | Pandoc | CommonMark / GFM |
|
||||
| HTML | .html | WeasyPrint | PDF में rendered |
|
||||
| EPUB | .epub | Pandoc, LibreOffice | E-book format |
|
||||
|
||||
### Output Formats {#output-formats-2}
|
||||
|
||||
| Format | Extensions | Produced by |
|
||||
|--------|-----------|-------------|
|
||||
| PDF | .pdf | Word/Excel/PowerPoint to PDF, Markdown to PDF, HTML to PDF |
|
||||
| PDF/A | .pdf | PDF/A Convert (archival) |
|
||||
| Word | .docx, .odt, .rtf, .txt | Convert Document, PDF to Word, Markdown to Word |
|
||||
| Presentation | .pptx, .odp | Convert Presentation |
|
||||
| Spreadsheet | .xlsx, .ods, .csv | Convert Spreadsheet |
|
||||
| HTML | .html | Markdown to HTML |
|
||||
| EPUB | .epub | Convert to EPUB |
|
||||
| Images | .png, .jpg | PDF to Image |
|
||||
|
||||
## File Formats {#file-formats}
|
||||
|
||||
Data और archive tools structured formats के बीच convert करते हैं और files को bundle करते हैं।
|
||||
|
||||
| Format | Extensions | Conversions |
|
||||
|--------|-----------|-------------|
|
||||
| CSV | .csv | JSON और Excel से/तक; split और merge; XML से |
|
||||
| JSON | .json | CSV, XML, और YAML से/तक |
|
||||
| XML | .xml | JSON से/तक; CSV तक |
|
||||
| YAML | .yaml, .yml | JSON से/तक |
|
||||
| Excel | .xlsx | CSV से/तक |
|
||||
| ZIP | .zip | Archives बनाएँ, contents निकालें |
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: "SnapOtter कौन सा अनाम usage data एकत्र करता है, इसे कब भेजा जाता है, और instance-wide product analytics को कैसे बंद करें।"
|
||||
i18n_source_hash: 5d72dedaeb23
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: cf0c51fe9a2f
|
||||
---
|
||||
|
||||
# What SnapOtter collects {#what-snapotter-collects}
|
||||
|
||||
Anonymous Product Analytics default रूप से चालू है और एक administrator द्वारा पूरे instance के लिए सेट किया जाता है। इसे Settings > System > Privacy के तहत बंद करें।
|
||||
|
||||
## Events we send (when enabled) {#events-we-send-when-enabled}
|
||||
|
||||
- tool_used: tool id, status, duration, category, यह एक AI tool है या नहीं, विफलता पर एक error code।
|
||||
- pipeline_executed: step count, tool ids, batch flag, file count, duration, status।
|
||||
- ai_bundle_action: bundle id, action, duration।
|
||||
- Frontend usage: कौन से tool pages खुलते हैं, जोड़ी गई files (केवल counts), tool शुरू हुआ, downloads, saves, search (केवल result count), batch processed।
|
||||
- Crash reports: error type और केवल file basenames के साथ एक source stack।
|
||||
|
||||
## What we never collect {#what-we-never-collect}
|
||||
|
||||
- File names या paths
|
||||
- File contents
|
||||
- OCR output text
|
||||
- Image metadata (EXIF)
|
||||
- Extracted document text
|
||||
- आपका IP address या account identity
|
||||
|
||||
## Turning it off {#turning-it-off}
|
||||
|
||||
Admins: Settings > System > Privacy, "Anonymous Product Analytics" को बंद कर दें। यह तुरंत रुक जाता है, instance-wide। एक ऐसी image बनाने के लिए जो कभी emit न कर सके, `SNAPOTTER_ANALYTICS=off` build arg सेट करें।
|
||||
@@ -0,0 +1,232 @@
|
||||
---
|
||||
description: "21 समर्थित भाषाएँ और TypeScript-प्रवर्तित i18n सिस्टम का उपयोग करके SnapOtter के लिए अनुवाद कैसे बनाएँ या सुधारें।"
|
||||
i18n_source_hash: 55837d9fdaef
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 6062f7bb34d4
|
||||
---
|
||||
|
||||
# अनुवाद गाइड {#translation-guide}
|
||||
|
||||
SnapOtter बॉक्स से बाहर 21 भाषाओं के साथ आता है। i18n सिस्टम TypeScript-प्रवर्तित लोकेल पूर्णता और डायनामिक कोड-स्प्लिटिंग के साथ एक हल्के कस्टम रनटाइम का उपयोग करता है।
|
||||
|
||||
## समर्थित भाषाएँ {#supported-languages}
|
||||
|
||||
| Code | Language | Native Name | Direction |
|
||||
|------|----------|-------------|-----------|
|
||||
| `en` | अंग्रेज़ी | English | LTR |
|
||||
| `zh-CN` | चीनी (सरलीकृत) | 简体中文 | LTR |
|
||||
| `zh-TW` | चीनी (पारंपरिक) | 繁體中文 | LTR |
|
||||
| `ja` | जापानी | 日本語 | LTR |
|
||||
| `ko` | कोरियाई | 한국어 | LTR |
|
||||
| `es` | स्पेनिश | Español | LTR |
|
||||
| `fr` | फ़्रेंच | Français | LTR |
|
||||
| `it` | इतालवी | Italiano | LTR |
|
||||
| `pt-BR` | पुर्तगाली (ब्राज़ील) | Português (Brasil) | LTR |
|
||||
| `de` | जर्मन | Deutsch | LTR |
|
||||
| `nl` | डच | Nederlands | LTR |
|
||||
| `sv` | स्वीडिश | Svenska | LTR |
|
||||
| `ru` | रूसी | Русский | LTR |
|
||||
| `pl` | पोलिश | Polski | LTR |
|
||||
| `uk` | यूक्रेनी | Українська | LTR |
|
||||
| `ar` | अरबी | العربية | RTL |
|
||||
| `tr` | तुर्की | Türkçe | LTR |
|
||||
| `hi` | हिंदी | हिन्दी | LTR |
|
||||
| `vi` | वियतनामी | Tiếng Việt | LTR |
|
||||
| `id` | इंडोनेशियाई | Bahasa Indonesia | LTR |
|
||||
| `th` | थाई | ไทย | LTR |
|
||||
|
||||
## भाषा पहचान कैसे काम करती है {#how-language-detection-works}
|
||||
|
||||
SnapOtter एक तीन-स्तरीय समाधान क्रम का उपयोग करता है:
|
||||
|
||||
1. **उपयोगकर्ता वरीयता** - `localStorage("snapotter-locale")` में संग्रहीत होती है और प्रमाणित होने पर उपयोगकर्ता सेटिंग्स के साथ सिंक हो जाती है
|
||||
2. **ब्राउज़र ऑटो-डिटेक्ट** - BCP 47 प्रीफ़िक्स मिलान के साथ `navigator.languages` ऐरे को टटोलता है
|
||||
3. **इंस्टेंस डिफ़ॉल्ट** - एडमिन का `DEFAULT_LOCALE` env वेरिएबल (`GET /api/v1/config/locale` से प्राप्त किया गया)
|
||||
4. **अंग्रेज़ी फ़ॉलबैक** - हमेशा उपलब्ध
|
||||
|
||||
उपयोगकर्ता भाषा यहाँ से बदल सकते हैं:
|
||||
- **फ़ुटर Globe सेलेक्टर** (डेस्कटॉप, हमेशा दिखाई देता है)
|
||||
- **लॉगिन पेज** भाषा सेलेक्टर (प्री-ऑथ)
|
||||
- **Settings > General** सेक्शन (प्रति-उपयोगकर्ता वरीयता)
|
||||
- **मोबाइल साइडबार** भाषा ड्रॉपडाउन
|
||||
- **Settings > System** सेक्शन इंस्टेंस-व्यापी डिफ़ॉल्ट सेट करता है (केवल एडमिन)
|
||||
|
||||
## अनुवाद कैसे काम करते हैं {#how-translations-work}
|
||||
|
||||
सभी UI स्ट्रिंग्स `packages/shared/src/i18n/` में रहती हैं। संदर्भ फ़ाइल `en.ts` है, जो ऐप द्वारा उपयोग की जाने वाली हर स्ट्रिंग (~1500 keys) के साथ एक टाइप्ड ऑब्जेक्ट एक्सपोर्ट करती है। अन्य भाषाएँ अलग फ़ाइलें हैं (जैसे, `de.ts`, `fr.ts`) जो समान आकार को एक्सपोर्ट करती हैं।
|
||||
|
||||
`TranslationKeys` टाइप key संरचना को प्रवर्तित करते हुए किसी भी स्ट्रिंग मान को स्वीकार करने के लिए `DeepStringRecord` का उपयोग करता है। TypeScript कंपाइल समय पर किसी भी अनुवाद फ़ाइल में गायब keys को पकड़ लेता है।
|
||||
|
||||
रनटाइम पर केवल सक्रिय लोकेल डायनामिक `import()` के माध्यम से लोड होता है, जिससे मुख्य बंडल छोटा रहता है।
|
||||
|
||||
## कंपोनेंट्स में अनुवादों का उपयोग करना {#using-translations-in-components}
|
||||
|
||||
```tsx
|
||||
import { useTranslation } from "@/contexts/i18n-context";
|
||||
import { format, plural } from "@/lib/format";
|
||||
|
||||
function MyComponent() {
|
||||
const { t, locale, setLocale } = useTranslation();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{t.common.settings}</h1>
|
||||
<p>{format(t.settings.people.deleteConfirm, { username: "admin" })}</p>
|
||||
<p>{plural(count, t.automate.fileCount, t.automate.fileCountPlural)}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## अनुवाद में योगदान देना {#contributing-a-translation}
|
||||
|
||||
हम सीधे अनुवाद PRs का स्वागत करते हैं। आप किसी मौजूदा लोकेल को सुधार सकते हैं या एक नया जोड़ सकते हैं।
|
||||
|
||||
कोड सबमिट किए बिना किसी ग़लत अनुवाद की रिपोर्ट करने के लिए, भाषा, ग़लत स्ट्रिंग और सुझाए गए सुधार के साथ एक [GitHub Issue](https://github.com/snapotter-hq/SnapOtter/issues) खोलें।
|
||||
|
||||
::: tip
|
||||
अनुवाद PRs के लिए पूर्व अनुमोदन की आवश्यकता नहीं होती। रेपो को फ़ोर्क करें, अपने बदलाव करें, और एक PR खोलें। पूरी PR प्रक्रिया और CLA आवश्यकता के लिए [Contributing Guide](/hi/guide/contributing) देखें।
|
||||
:::
|
||||
|
||||
## अनुवाद कैसे बनाएँ या अपडेट करें {#how-to-create-or-update-a-translation}
|
||||
|
||||
### 1. फ़ोर्क और क्लोन करें {#_1-fork-and-clone}
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-username>/snapotter.git
|
||||
cd snapotter
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 2. संदर्भ फ़ाइल कॉपी करें (केवल नई भाषा) {#_2-copy-the-reference-file-new-language-only}
|
||||
|
||||
यदि आप किसी मौजूदा अनुवाद को सुधार रहे हैं तो इस चरण को छोड़ दें।
|
||||
|
||||
```bash
|
||||
cp packages/shared/src/i18n/en.ts packages/shared/src/i18n/XX.ts
|
||||
```
|
||||
|
||||
### 3. स्ट्रिंग्स का अनुवाद करें {#_3-translate-the-strings}
|
||||
|
||||
अपनी नई फ़ाइल खोलें और हर स्ट्रिंग मान का अनुवाद करें। ऑब्जेक्ट संरचना और keys को बिल्कुल समान रखें।
|
||||
|
||||
```ts
|
||||
import type { TranslationKeys } from "./en.js";
|
||||
|
||||
export const xx: TranslationKeys = {
|
||||
common: {
|
||||
upload: "Your translation here",
|
||||
// ... translate all entries
|
||||
},
|
||||
// ... translate all sections
|
||||
} as const;
|
||||
```
|
||||
|
||||
नियम:
|
||||
- ऑब्जेक्ट keys का अनुवाद न करें, केवल स्ट्रिंग मानों का करें
|
||||
- अंत में `as const` रखें
|
||||
- `./en.js` से `TranslationKeys` इम्पोर्ट करें और अपने एक्सपोर्ट को टाइप करें
|
||||
- `{variable}` प्लेसहोल्डर्स को बिल्कुल वैसा ही रखें
|
||||
- ऐरे (`rotatingPhrases`, `progressMessages`) में प्रविष्टियों की संख्या समान होनी चाहिए
|
||||
- इनका अनुवाद न करें: SnapOtter, JPEG, PNG, WebP, EXIF, API, और अन्य तकनीकी शब्द
|
||||
|
||||
### 4. लोकेल रजिस्टर करें (केवल नई भाषा) {#_4-register-the-locale-new-language-only}
|
||||
|
||||
अपने लोकेल को `packages/shared/src/i18n/index.ts` में `SUPPORTED_LOCALES` में जोड़ें:
|
||||
|
||||
```ts
|
||||
{ code: "xx", name: "Language Name", nativeName: "Native Name", dir: "ltr" },
|
||||
```
|
||||
|
||||
### 5. सत्यापित करें {#_5-verify}
|
||||
|
||||
```bash
|
||||
pnpm typecheck # catches missing or mistyped keys
|
||||
pnpm lint # formatting check
|
||||
pnpm dev # manually verify strings appear correctly
|
||||
```
|
||||
|
||||
### 6. सबमिट करें {#_6-submit}
|
||||
|
||||
`main` के विरुद्ध `feat(i18n): add Swedish translation` या `fix(i18n): correct German typos` जैसे शीर्षक के साथ एक PR खोलें। CLA बॉट आपके पहले योगदान पर आपसे साइन करने के लिए कहेगा।
|
||||
|
||||
## नई अनुवाद keys जोड़ना {#adding-new-translation-keys}
|
||||
|
||||
जब कोई नई सुविधा जोड़ते हैं जिसके लिए नई UI स्ट्रिंग्स की आवश्यकता होती है:
|
||||
|
||||
1. पहले `en.ts` (संदर्भ फ़ाइल) में नई keys जोड़ें
|
||||
2. `pnpm typecheck` चलाएँ - नई key गायब होने पर हर लोकेल फ़ाइल विफल हो जाएगी
|
||||
3. सभी लोकेल फ़ाइलों में नई key जोड़ें (अस्थायी फ़ॉलबैक के रूप में अंग्रेज़ी का उपयोग करें)
|
||||
|
||||
## कॉन्फ़िगरेशन {#configuration}
|
||||
|
||||
एनवायरनमेंट वेरिएबल के माध्यम से इंस्टेंस डिफ़ॉल्ट भाषा सेट करें:
|
||||
|
||||
```yaml
|
||||
DEFAULT_LOCALE: "de" # German as the default for all new users
|
||||
```
|
||||
|
||||
## फ़ाइल संदर्भ {#file-reference}
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `packages/shared/src/i18n/en.ts` | अंग्रेज़ी स्ट्रिंग्स (संदर्भ लोकेल, ~1500 keys) |
|
||||
| `packages/shared/src/i18n/index.ts` | `SUPPORTED_LOCALES`, `loadTranslations()`, टाइप एक्सपोर्ट्स |
|
||||
| `packages/shared/src/i18n/<locale>.ts` | प्रति-भाषा अनुवाद फ़ाइलें |
|
||||
| `apps/web/src/contexts/i18n-context.tsx` | `I18nProvider`, `useTranslation()` हुक |
|
||||
| `apps/web/src/lib/format.ts` | `format()`, `plural()`, `formatFileSize()` हेल्पर्स |
|
||||
| `apps/api/src/routes/config.ts` | `GET /api/v1/config/locale` पब्लिक एंडपॉइंट |
|
||||
|
||||
## वेबसाइट, डॉक्स और API संदर्भ का अनुवाद करना {#translating-the-web-surfaces}
|
||||
|
||||
ऊपर बताया गया 21-भाषा समर्थन **ऐप** को कवर करता है। सार्वजनिक वेबसाइट
|
||||
(snapotter.com), यह डॉक्युमेंटेशन साइट, और REST API संदर्भ भी सभी 21 भाषाओं में
|
||||
अनुवादित हैं, एक अलग हैश-गेटेड पाइपलाइन द्वारा जो `packages/shared/src/i18n` से समान टूल नाम और विवरण
|
||||
का पुनः उपयोग करती है, ताकि हर जगह शब्दावली एकसमान बनी रहे।
|
||||
|
||||
### डिफ़ॉल्ट रूप से मशीन-अनुवादित {#machine-translated-by-default}
|
||||
|
||||
वेबसाइट और डॉक्स पर हर ग़ैर-अंग्रेज़ी पेज पहले पास में **मशीन-अनुवादित** होता है
|
||||
(एक Claude Code सत्र द्वारा, किसी तीसरे-पक्ष सेवा द्वारा नहीं) और ऐसा कहने वाला एक
|
||||
छोटा, ख़ारिज करने योग्य बैनर रखता है, जिसमें यहाँ वापस एक लिंक होता है। यह जानबूझकर किया गया है:
|
||||
यह सभी 21 भाषाओं को तेज़ी से और ईमानदारी से भेजता है, फिर समुदाय को उन पेजों को परिष्कृत करने के लिए
|
||||
आमंत्रित करता है जो सबसे अधिक मायने रखते हैं। मशीन अनुवाद अर्थ को पहुँचा देता है;
|
||||
मानव समीक्षा इसे स्वाभाविक रूप से पढ़ने योग्य बनाती है।
|
||||
|
||||
### पाइपलाइन यह कैसे तय करती है कि किसका अनुवाद करना है {#how-the-web-pipeline-decides}
|
||||
|
||||
अंग्रेज़ी स्रोत की हर अनुवाद-योग्य इकाई को हैश किया जाता है, और हैश को उसके अनुवाद के
|
||||
बग़ल में संग्रहीत किया जाता है। हर बार चलने पर पाइपलाइन:
|
||||
|
||||
- किसी भी ऐसी इकाई का अनुवाद करती है जिसका अभी तक कोई अनुवाद नहीं है,
|
||||
- किसी भी ऐसी इकाई को छोड़ देती है जिसका संग्रहीत हैश अभी भी अंग्रेज़ी स्रोत से मेल खाता है,
|
||||
- किसी **मशीन** इकाई का पुनः अनुवाद करती है जब उसका अंग्रेज़ी स्रोत बदलता है,
|
||||
- और किसी **मानव**-परिष्कृत इकाई को `stale` (समीक्षा की आवश्यकता) के रूप में फ़्लैग करती है जब उसका अंग्रेज़ी
|
||||
स्रोत बदलता है, आपके काम को अधिलेखित करने के बजाय।
|
||||
|
||||
### PR के माध्यम से किसी वेब अनुवाद को परिष्कृत करना {#refining-a-web-translation-by-pr}
|
||||
|
||||
आप किसी वेबसाइट, डॉक्स, या API-संदर्भ अनुवाद को उसी तरह सुधारते हैं जैसे आप
|
||||
किसी ऐप लोकेल को सुधारते हैं: जनरेट की गई फ़ाइल को संपादित करके और एक PR खोलकर।
|
||||
|
||||
1. अपनी भाषा के लिए जनरेट किया गया अनुवाद खोजें:
|
||||
- वेबसाइट UI स्ट्रिंग्स: `apps/landing/src/i18n/<locale>.json`
|
||||
- एक डॉक्स पेज: `apps/docs/<locale>/**.md`
|
||||
- API संदर्भ: `apps/api/src/openapi.<locale>.yaml`
|
||||
2. टेक्स्ट संपादित करें। कोड, लिंक, `{placeholders}`, और किसी भी `⸤I18N…⸥` मार्कर को
|
||||
बिल्कुल वैसा ही रखें जैसे वे हैं; पाइपलाइन का वैलिडेटर ऐसे अनुवाद को अस्वीकार करता है जो उन्हें छोड़
|
||||
देता है या पुनः क्रमबद्ध करता है।
|
||||
3. एक PR खोलें। किसी इकाई को संपादित करने से उसकी प्रोवेनेंस `machine` से `human` में बदल जाती है, इसलिए
|
||||
पाइपलाइन बाद के किसी रन पर उसे **कभी अधिलेखित नहीं करेगी**। यदि उसके बाद अंग्रेज़ी स्रोत
|
||||
बदलता है, तो आपकी इकाई को चुपचाप बदलने के बजाय समीक्षा के लिए `stale` फ़्लैग किया जाता है।
|
||||
|
||||
कोड सबमिट किए बिना किसी ग़लत अनुवाद की रिपोर्ट करने के लिए, पेज
|
||||
URL, भाषा, ग़लत टेक्स्ट, और अपने सुझाए गए सुधार के साथ एक
|
||||
[GitHub Issue](https://github.com/snapotter-hq/SnapOtter/issues) खोलें।
|
||||
|
||||
::: tip
|
||||
मेंटेनर अनुवाद पाइपलाइन चलाते हैं; योगदान देने के लिए आपको API key की आवश्यकता नहीं है।
|
||||
बस जनरेट की गई फ़ाइल को संपादित करें और एक PR खोलें। पाइपलाइन कैसे चलती है, इसके लिए
|
||||
[`scripts/i18n/README.md`](https://github.com/snapotter-hq/SnapOtter/blob/main/scripts/i18n/README.md)
|
||||
देखें।
|
||||
:::
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
i18n_source_hash: 9a6abf3fc8ae
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 6122c38692ef
|
||||
---
|
||||
# 1.x से 2.0 में अपग्रेड करना {#upgrading-from-1-x-to-2-0}
|
||||
|
||||
SnapOtter 1.x सब कुछ एक ही SQLite फ़ाइल में संग्रहीत करता था और एक ही container के रूप में चलता था। SnapOtter 2.0 PostgreSQL और Redis का उपयोग करता है। यह गाइड बिना डेटा खोए 1.x इंस्टॉल को 2.0 में ले जाने का तरीका बताती है।
|
||||
|
||||
संक्षेप में: अपने मौजूदा `/data` वॉल्यूम का पुनः उपयोग करें, और 2.0 पहली बूट पर आपके 1.x डेटाबेस को स्वचालित रूप से इम्पोर्ट कर लेता है। आपके उपयोगकर्ता, सहेजी गई फ़ाइलें, सेटिंग्स, API keys और pipelines सब साथ आ जाते हैं। पुराना डेटाबेस कभी संशोधित नहीं होता, इसलिए आप हमेशा रोल बैक कर सकते हैं।
|
||||
|
||||
::: tip हमारे 1.x उपयोगकर्ताओं के लिए एक नोट
|
||||
आप में से कई लोगों ने पहले दिन से SnapOtter पर भरोसा किया है, और आपकी प्रतिक्रिया ने इस रिलीज़ को आकार दिया है। 2.0 अंदरूनी तौर पर बहुत कुछ बदलता है, और यह गाइड इसलिए मौजूद है ताकि यह बदलाव आपको उन चीज़ों में से कुछ भी न खर्च कराए जिनकी आप परवाह करते हैं। आपके अकाउंट, फ़ाइलें, सेटिंग्स, API keys और pipelines साथ आते हैं, और आपका पुराना डेटाबेस कभी नहीं छुआ जाता। हमारे साथ अपग्रेड करने के लिए धन्यवाद।
|
||||
:::
|
||||
|
||||
## शुरू करने से पहले: पूरे `/data` वॉल्यूम का बैकअप लें {#before-you-start-back-up-the-whole-data-volume}
|
||||
|
||||
यह हर बार सबसे पहले करें। **पूरे** `/data` वॉल्यूम का बैकअप लें, केवल `snapotter.db` फ़ाइल का नहीं।
|
||||
|
||||
यह क्यों मायने रखता है, यहाँ बताया गया है। 1.x SQLite को WAL मोड में चलाता है, इसलिए एक रुका हुआ 1.x container अक्सर अपने अधिकांश कमिट किए गए डेटा को `snapotter.db-wal` में छोड़ देता है, जिसके साथ एक लगभग-खाली `snapotter.db` होता है। केवल `snapotter.db` कॉपी करने से एक खाली डेटाबेस कैप्चर होता है और सब कुछ चुपचाप खो जाता है। वॉल्यूम `snapotter.db`, `snapotter.db-wal`, `snapotter.db-shm`, और आपकी `files/` डायरेक्टरी को एक साथ रखता है, और इन्हें एक सेट के रूप में साथ ले जाना चाहिए।
|
||||
|
||||
```bash
|
||||
# Adjust the volume name to match yours (see "Check your volume name" below).
|
||||
docker run --rm -v SnapOtter-data:/data -v "$PWD":/backup \
|
||||
alpine tar czf /backup/snapotter-1x-data.tgz -C /data .
|
||||
```
|
||||
|
||||
## पहले 1.17.2 में अपग्रेड करें {#upgrade-to-1-17-2-first}
|
||||
|
||||
2.0 में जाने से पहले अपने 1.x इंस्टॉल को नवीनतम 1.x रिलीज़ (1.17.2) में अपग्रेड करें। इससे 1.x अपने अंतिम स्कीमा माइग्रेशन चला पाता है, ताकि 2.0 एक ज्ञात, पूर्ण स्कीमा से इम्पोर्ट करे। किसी पुराने 1.x से सीधे 2.0 में अपग्रेड करना समर्थित नहीं है।
|
||||
|
||||
## अपने वॉल्यूम का नाम जाँचें {#check-your-volume-name}
|
||||
|
||||
इम्पोर्टर आपका डेटा केवल तभी देखता है जब 2.0 स्टैक वही वॉल्यूम माउंट करता है जो आपके 1.x इंस्टॉल ने उपयोग किया था। Docker वॉल्यूम नाम केस सेंसिटिव होते हैं, और पुराने README स्निपेट्स में एक लोअरकेस `snapotter-data` का उपयोग होता था जबकि Compose फ़ाइलें `SnapOtter-data` का उपयोग करती हैं। पुष्टि करें कि आपके पास कौन सा है:
|
||||
|
||||
```bash
|
||||
docker volume ls | grep -i snapotter
|
||||
```
|
||||
|
||||
अपने 2.0 कॉन्फ़िगरेशन में ठीक वही नाम उपयोग करें।
|
||||
|
||||
## पथ A: सिंगल container (सबसे तेज़) {#path-a-single-container-quickest}
|
||||
|
||||
यदि आप SnapOtter को एक ही `docker run` के साथ चलाते हैं, तो ऐसा करना जारी रखें। जब आप `DATABASE_URL` या `REDIS_URL` सेट नहीं करते, तो 2.0 container के अंदर एक एम्बेडेड PostgreSQL और Redis बूट करता है, और पहली बूट पर `/data/snapotter.db` को स्वतः-पहचानता और इम्पोर्ट करता है।
|
||||
|
||||
```bash
|
||||
docker run -d --name snapotter -p 1349:1349 \
|
||||
-v SnapOtter-data:/data \
|
||||
snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
लॉग में इस तरह की एक पंक्ति देखें:
|
||||
|
||||
```
|
||||
Imported 1.x SQLite database: {"tables":{"users":2,"teams":1,...},"blobs":{"present":1,"missing":0}}
|
||||
```
|
||||
|
||||
बस इतना ही। अपने मौजूदा क्रेडेंशियल के साथ लॉग इन करें।
|
||||
|
||||
## पथ B: Compose (प्रोडक्शन के लिए अनुशंसित) {#path-b-compose-recommended-for-production}
|
||||
|
||||
2.0 Compose स्टैक तीन सेवाएँ चलाता है (app, Postgres, Redis)। app सेवा के लिए अपने 1.x `/data` वॉल्यूम का पुनः उपयोग करें। app पहली बूट पर `/data/snapotter.db` को स्वतः-पहचानता है और इसे Postgres में इम्पोर्ट करता है।
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
volumes:
|
||||
- SnapOtter-data:/data # your existing 1.x volume
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://:snapotter@redis:6379
|
||||
# ...
|
||||
```
|
||||
|
||||
यदि आप पुराने डेटाबेस को स्पष्ट रूप से इंगित करना चाहें, तो `SQLITE_MIGRATE_PATH=/data/snapotter.db` सेट करें। एक स्पष्ट पथ हमेशा स्वतः-पहचान पर भारी पड़ता है।
|
||||
|
||||
## पहले इम्पोर्ट का पूर्वावलोकन करें (वैकल्पिक) {#preview-the-import-first-optional}
|
||||
|
||||
बिना कुछ लिखे ठीक-ठीक देखने के लिए कि क्या इम्पोर्ट होगा, अपनी डेटाबेस फ़ाइल के विरुद्ध एक ड्राई रन चलाएँ:
|
||||
|
||||
```bash
|
||||
pnpm --filter @snapotter/api migrate:sqlite -- /path/to/snapotter.db --dry-run
|
||||
```
|
||||
|
||||
यह प्रति टेबल पंक्ति गणना, डिस्क पर मिली कितनी सहेजी-गई-लाइब्रेरी फ़ाइलें, और किसी भी जॉब स्थिति को जिसे वह सामान्यीकृत करेगा, प्रिंट करता है। इसे किसी चालू Postgres की आवश्यकता नहीं होती।
|
||||
|
||||
## क्या साथ आता है, और क्या नहीं {#what-carries-over-and-what-does-not}
|
||||
|
||||
साथ आता है:
|
||||
|
||||
- उपयोगकर्ता, और लॉग इन करने की क्षमता। पासवर्ड हैश अपरिवर्तित रहते हैं, इसलिए वही उपयोगकर्ता नाम और पासवर्ड काम करते हैं।
|
||||
- Teams, सेटिंग्स (आपकी इंस्टेंस पहचान सहित), roles, API keys (वे काम करते रहते हैं), और सहेजी गई pipelines।
|
||||
- जॉब इतिहास रिकॉर्ड।
|
||||
- आपकी सहेजी-गई-फ़ाइल लाइब्रेरी, रिकॉर्ड और वास्तविक फ़ाइलें दोनों, क्योंकि `/data/files` वॉल्यूम पर संरक्षित रहता है।
|
||||
|
||||
साथ नहीं आता:
|
||||
|
||||
- लॉगिन सत्र। अपग्रेड के बाद सभी एक बार साइन इन करते हैं। क्रेडेंशियल अपरिवर्तित रहते हैं, इसलिए यह एक बार का पुनः-लॉगिन है, इससे अधिक कुछ नहीं।
|
||||
- पुराने प्रोसेसिंग जॉब की इनपुट और आउटपुट फ़ाइलें। वे एक अस्थायी वर्कस्पेस में रहती थीं और डिज़ाइन के अनुसार चली जाती हैं। जॉब इतिहास रिकॉर्ड बने रहते हैं।
|
||||
- 1.x से प्रति-उपयोगकर्ता एनालिटिक्स-सहमति फ़्लैग, जिनका कोई 2.0 समकक्ष नहीं है (2.0 एनालिटिक्स एक इंस्टेंस-स्तरीय सेटिंग है)।
|
||||
|
||||
## इम्पोर्ट को बंद करना {#turning-the-import-off}
|
||||
|
||||
यदि आप जानबूझकर एक ताज़ा डेटाबेस चाहते हैं, भले ही वॉल्यूम पर एक `snapotter.db` मौजूद हो, तो `SQLITE_MIGRATE_PATH=off` सेट करें।
|
||||
|
||||
## यदि 2.0 इंस्टेंस में आपके पास पहले से डेटा है {#if-you-already-have-data-in-the-2-0-instance}
|
||||
|
||||
इम्पोर्टर केवल एक खाली डेटाबेस में ही चलता है। यदि आपने 2.0 को ताज़ा शुरू किया (डेटा बनाते हुए), फिर बाद में एक पुराना `snapotter.db` माउंट किया, तो 2.0 इसे पहचानेगा लेकिन इम्पोर्ट नहीं करेगा, क्योंकि दो डेटासेट मर्ज करने से IDs टकरा सकती हैं। आपको लॉग में एक चेतावनी दिखेगी। 1.x डेटा इम्पोर्ट करने के लिए आपको एक खाली इंस्टेंस चाहिए:
|
||||
|
||||
- यदि 2.0 इंस्टेंस में केवल डिफ़ॉल्ट एडमिन है (आपने वास्तव में इसका उपयोग नहीं किया), तो स्टैक रोकें, Postgres वॉल्यूम हटाएँ (`SnapOtter-pgdata`), और पुराने `/data` के मौजूद रहते हुए फिर से बूट करें। यह साफ़ इम्पोर्ट कर लेगा। इससे केवल फेंकने-योग्य Postgres डेटा मिटता है, आपका 1.x डेटाबेस नहीं।
|
||||
- यदि 2.0 इंस्टेंस में वास्तविक डेटा है जिसे आप रखना चाहते हैं, तो दोनों डेटासेट स्वतः-मर्ज नहीं किए जा सकते। जो आपको चाहिए उसे एक्सपोर्ट करें और 1.x डेटा को एक अलग ताज़ा डिप्लॉयमेंट में इम्पोर्ट करें।
|
||||
|
||||
## रोल बैक करना {#rolling-back}
|
||||
|
||||
अपग्रेड आपके 1.x `snapotter.db` को कभी संशोधित या हटाता नहीं है। यदि आपको 1.x पर वापस जाना है, तो उसी वॉल्यूम के विरुद्ध 1.x इमेज पुनः डिप्लॉय करें। अपग्रेड के बाद 2.0 में आपने जो कुछ भी बनाया वह Postgres में रहता है और 1.x डेटाबेस में नहीं होगा, इसलिए यदि आप वापस जाने वाले हैं तो तुरंत रोल बैक करें।
|
||||
@@ -0,0 +1,264 @@
|
||||
---
|
||||
description: "SnapOtter में उपयोगकर्ता, बिल्ट-इन और कस्टम roles, permissions, API keys, teams, sessions, और ऑडिट लॉग प्रबंधित करें।"
|
||||
i18n_source_hash: 5e28af686c96
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 0afc852d07c9
|
||||
---
|
||||
|
||||
# उपयोगकर्ता, Roles और Permissions {#users-roles-permissions}
|
||||
|
||||
SnapOtter तीन बिल्ट-इन roles, 17 सूक्ष्म permissions, और वैकल्पिक प्रति-टूल एक्सेस नियंत्रण के साथ कस्टम roles का समर्थन प्रदान करता है। यह पेज पूर्ण अधिकृति मॉडल, API key स्कोपिंग, टीम प्रबंधन, और ऑडिट लॉगिंग को कवर करता है।
|
||||
|
||||
::: tip संबंधित पेज
|
||||
[OIDC / SSO](/hi/guide/oidc) | [SAML SSO](/hi/guide/saml) | [SCIM Provisioning](/hi/guide/scim) | [Security & Hardening](/hi/guide/security)
|
||||
:::
|
||||
|
||||
## उपयोगकर्ता {#users}
|
||||
|
||||
### उपयोगकर्ता बनाना {#creating-users}
|
||||
|
||||
एडमिन एडमिन पैनल या `POST /api/auth/register` एंडपॉइंट के माध्यम से उपयोगकर्ता बना सकते हैं। हर उपयोगकर्ता के पास एक उपयोगकर्ता नाम, role, टीम असाइनमेंट, और एक वैकल्पिक ईमेल पता होता है।
|
||||
|
||||
### डिफ़ॉल्ट एडमिन {#default-admin}
|
||||
|
||||
पहली बार स्टार्टअप पर SnapOtter एक डिफ़ॉल्ट एडमिन अकाउंट बनाता है। क्रेडेंशियल एनवायरनमेंट वेरिएबल से आते हैं:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `DEFAULT_USERNAME` | `admin` | प्रारंभिक एडमिन अकाउंट के लिए उपयोगकर्ता नाम |
|
||||
| `DEFAULT_PASSWORD` | `admin` | प्रारंभिक एडमिन अकाउंट के लिए पासवर्ड |
|
||||
|
||||
डिफ़ॉल्ट एडमिन को पहले लॉगिन पर अपना पासवर्ड बदलना आवश्यक है।
|
||||
|
||||
### प्रमाणीकरण प्रदाता {#authentication-providers}
|
||||
|
||||
उपयोगकर्ता कई विधियों से प्रमाणित हो सकते हैं:
|
||||
|
||||
- **Local** - SnapOtter डेटाबेस में संग्रहीत उपयोगकर्ता नाम और पासवर्ड
|
||||
- **OIDC** - कोई भी OpenID Connect प्रदाता ([OIDC / SSO](/hi/guide/oidc) देखें)
|
||||
- **SAML** - SAML 2.0 पहचान प्रदाता ([SAML SSO](/hi/guide/saml) देखें)
|
||||
- **SCIM** - किसी पहचान प्रदाता से स्वचालित प्रोविज़निंग ([SCIM Provisioning](/hi/guide/scim) देखें)
|
||||
|
||||
### प्रमाणीकरण अक्षम करना {#disabling-authentication}
|
||||
|
||||
प्रमाणीकरण को पूरी तरह अक्षम करने के लिए `AUTH_ENABLED=false` सेट करें। इस मोड में सभी अनुरोधों के लिए `admin` role वाला एक सिंथेटिक अनाम उपयोगकर्ता उपयोग होता है। किसी लॉगिन की आवश्यकता नहीं होती।
|
||||
|
||||
::: warning
|
||||
प्रमाणीकरण अक्षम करने से इंस्टेंस तक पहुँच सकने वाले किसी भी व्यक्ति को पूर्ण एडमिन एक्सेस मिल जाता है। इसका उपयोग केवल भरोसेमंद वातावरण में करें।
|
||||
:::
|
||||
|
||||
## बिल्ट-इन roles {#built-in-roles}
|
||||
|
||||
SnapOtter में तीन बिल्ट-इन roles शामिल हैं। इन्हें संशोधित या हटाया नहीं जा सकता।
|
||||
|
||||
### Admin {#admin}
|
||||
|
||||
सभी 17 permissions। इंस्टेंस पर पूर्ण नियंत्रण।
|
||||
|
||||
`tools:use` `files:own` `files:all` `apikeys:own` `apikeys:all` `pipelines:own` `pipelines:all` `settings:read` `settings:write` `users:manage` `teams:manage` `features:manage` `system:health` `audit:read` `compliance:manage` `webhooks:manage` `security:manage`
|
||||
|
||||
### Editor {#editor}
|
||||
|
||||
7 permissions। सभी टूल का उपयोग कर सकता है और सभी फ़ाइलें व pipelines प्रबंधित कर सकता है, लेकिन एडमिन फ़ंक्शन तक नहीं पहुँच सकता।
|
||||
|
||||
`tools:use` `files:own` `files:all` `apikeys:own` `pipelines:own` `pipelines:all` `settings:read`
|
||||
|
||||
### User {#user}
|
||||
|
||||
5 permissions। टूल का उपयोग कर सकता है और अपने स्वयं के संसाधन प्रबंधित कर सकता है।
|
||||
|
||||
`tools:use` `files:own` `apikeys:own` `pipelines:own` `settings:read`
|
||||
|
||||
## Permissions संदर्भ {#permissions-reference}
|
||||
|
||||
| Permission | Description |
|
||||
|---|---|
|
||||
| `tools:use` | किसी भी प्रोसेसिंग टूल का उपयोग करना |
|
||||
| `files:own` | अपनी फ़ाइलें देखना और प्रबंधित करना |
|
||||
| `files:all` | सभी उपयोगकर्ताओं की फ़ाइलें देखना और प्रबंधित करना |
|
||||
| `apikeys:own` | अपनी API keys बनाना और प्रबंधित करना |
|
||||
| `apikeys:all` | सभी उपयोगकर्ताओं की API keys देखना |
|
||||
| `pipelines:own` | अपनी pipelines बनाना और प्रबंधित करना |
|
||||
| `pipelines:all` | सभी उपयोगकर्ताओं की pipelines देखना और प्रबंधित करना |
|
||||
| `settings:read` | इंस्टेंस सेटिंग्स देखना |
|
||||
| `settings:write` | इंस्टेंस सेटिंग्स संशोधित करना |
|
||||
| `users:manage` | उपयोगकर्ता अकाउंट बनाना, अपडेट करना, और हटाना |
|
||||
| `teams:manage` | teams बनाना, अपडेट करना, और हटाना |
|
||||
| `features:manage` | AI फ़ीचर बंडल इंस्टॉल और प्रबंधित करना |
|
||||
| `system:health` | health और readiness एंडपॉइंट तक पहुँचना |
|
||||
| `audit:read` | ऑडिट लॉग देखना और roles सूचीबद्ध करना |
|
||||
| `compliance:manage` | GDPR लाइफ़साइकल और अनुपालन फ़ीचर प्रबंधित करना |
|
||||
| `webhooks:manage` | आउटबाउंड webhooks कॉन्फ़िगर करना |
|
||||
| `security:manage` | सुरक्षा सेटिंग्स प्रबंधित करना (IP allowlist, SSO प्रवर्तन) |
|
||||
|
||||
## कस्टम roles {#custom-roles}
|
||||
|
||||
`security:manage` permission वाले एडमिन एडमिन पैनल या roles API के माध्यम से कस्टम roles बना सकते हैं। roles सूचीबद्ध करने के लिए `audit:read` आवश्यक है।
|
||||
|
||||
### कस्टम role बनाना {#creating-a-custom-role}
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:1349/api/v1/roles \
|
||||
-H "Authorization: Bearer si_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "reviewer",
|
||||
"description": "Can use tools and view all files",
|
||||
"permissions": ["tools:use", "files:own", "files:all", "settings:read"]
|
||||
}'
|
||||
```
|
||||
|
||||
Role नाम 2-30 अक्षरों के होने चाहिए, लोअरकेस अल्फ़ान्यूमेरिक, हाइफ़न और अंडरस्कोर के साथ।
|
||||
|
||||
### एडमिन-आरक्षित permissions {#admin-reserved-permissions}
|
||||
|
||||
तीन permissions बिल्ट-इन roles के लिए आरक्षित हैं और कस्टम roles को नहीं सौंपी जा सकतीं:
|
||||
|
||||
- `compliance:manage`
|
||||
- `webhooks:manage`
|
||||
- `security:manage`
|
||||
|
||||
roles API इन permissions को शामिल करने वाले किसी भी अनुरोध को अस्वीकार कर देता है। केवल बिल्ट-इन `admin` role के पास इन तक पहुँच है।
|
||||
|
||||
### टूल-स्तरीय permissions {#tool-level-permissions}
|
||||
|
||||
कस्टम roles वैकल्पिक रूप से सीमित कर सकते हैं कि उपयोगकर्ता किन टूल तक पहुँच सकते हैं। दो मोड उपलब्ध हैं:
|
||||
|
||||
| Mode | Behavior | License requirement |
|
||||
|---|---|---|
|
||||
| `category` | मोडैलिटी के अनुसार सीमित करें (image, video, audio, document, file) | कोई नहीं (निःशुल्क) |
|
||||
| `tool` | व्यक्तिगत टूल ID के अनुसार सीमित करें | `per_tool_permissions` enterprise फ़ीचर आवश्यक है |
|
||||
|
||||
जब `tool` मोड सेट होता है लेकिन enterprise फ़ीचर उपलब्ध नहीं होता, तो SnapOtter शालीनता से गिरावट करता है और सभी टूल तक पहुँच की अनुमति देता है।
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "image-only",
|
||||
"permissions": ["tools:use", "files:own"],
|
||||
"toolPermissions": {
|
||||
"mode": "category",
|
||||
"allowed": ["image"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### कस्टम role हटाना {#deleting-a-custom-role}
|
||||
|
||||
जब कोई कस्टम role हटाया जाता है, तो इसे सौंपे गए सभी उपयोगकर्ता स्वचालित रूप से `user` role में पुनः-असाइन कर दिए जाते हैं।
|
||||
|
||||
## Teams {#teams}
|
||||
|
||||
Teams स्टोरेज और रिटेंशन प्रबंधन के लिए उपयोगकर्ताओं को समूहित करती हैं। पहली बार स्टार्टअप पर एक `Default` टीम बनाई जाती है।
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `name` | string | अद्वितीय टीम नाम (1-50 अक्षर) |
|
||||
| `storageQuota` | number | बाइट्स में प्रति-टीम स्टोरेज सीमा (enterprise के बिना काम करती है) |
|
||||
| `retentionHours` | number | इतने घंटों के बाद आउटपुट स्वतः-हटाएँ (`team_retention_overrides` आवश्यक है, enterprise) |
|
||||
| `legalHold` | boolean | टीम सदस्यों की फ़ाइलों के स्वचालित विलोपन को रोकें (`legal_hold` आवश्यक है, enterprise) |
|
||||
|
||||
::: info
|
||||
`Default` टीम को हटाया नहीं जा सकता। जिन teams में अब भी सदस्य हैं उन्हें हटाया नहीं जा सकता। पहले सदस्यों को पुनः-असाइन करें।
|
||||
:::
|
||||
|
||||
## API keys {#api-keys}
|
||||
|
||||
उपयोगकर्ता प्रोग्रामेटिक एक्सेस के लिए API keys जनरेट कर सकते हैं। हर key `si_` प्रीफ़िक्स का उपयोग करती है और निर्माण के समय केवल एक बार दिखाई जाती है।
|
||||
|
||||
### स्कोप्ड permissions {#scoped-permissions}
|
||||
|
||||
API keys वैकल्पिक रूप से एक `permissions` ऐरे ले जा सकती हैं। जब सेट किया जाता है, तो किसी अनुरोध के लिए प्रभावी permissions उपयोगकर्ता के role permissions और key की स्कोप्ड permissions का **intersection** होती हैं। इसका अर्थ है कि एक API key कभी भी उपयोगकर्ता की अपनी permissions से आगे नहीं बढ़ सकती।
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:1349/api/v1/api-keys \
|
||||
-H "Authorization: Bearer si_..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "CI pipeline key",
|
||||
"permissions": ["tools:use", "files:own"],
|
||||
"expiresAt": "2027-01-01T00:00:00Z"
|
||||
}'
|
||||
```
|
||||
|
||||
### समाप्ति {#expiration}
|
||||
|
||||
Keys एक वैकल्पिक `expiresAt` टाइमस्टैम्प स्वीकार करती हैं। समाप्त हो चुकी keys प्रमाणीकरण के समय अस्वीकार कर दी जाती हैं।
|
||||
|
||||
## ऑडिट लॉग {#audit-log}
|
||||
|
||||
SnapOtter सुरक्षा-संबंधी घटनाओं को `audit_log` डेटाबेस टेबल में संग्रहीत एक संरचित ऑडिट लॉग में रिकॉर्ड करता है।
|
||||
|
||||
### ऑडिट लॉग देखना {#viewing-the-audit-log}
|
||||
|
||||
```
|
||||
GET /api/v1/audit-log?page=1&limit=50&action=LOGIN_FAILED&from=2026-01-01T00:00:00Z&to=2026-12-31T23:59:59Z
|
||||
```
|
||||
|
||||
`audit:read` permission आवश्यक है। पेजिनेशन (`page`, `limit`) और फ़िल्टर (`action`, `ip`, `from`, `to`) का समर्थन करता है।
|
||||
|
||||
### टूल ऑपरेशन ऑडिटिंग {#tool-operation-auditing}
|
||||
|
||||
::: warning
|
||||
`TOOL_EXECUTED` घटनाएँ डिफ़ॉल्ट रूप से लॉग **नहीं** होतीं। वे दो पथों में से किसी एक के माध्यम से ऑप्ट-इन हैं:
|
||||
|
||||
1. `auditToolOperations` एडमिन सेटिंग को `true` पर सेट करें।
|
||||
2. `audit_export` फ़ीचर वाला एक सक्रिय लाइसेंस रखें (team और enterprise दोनों प्लान पर उपलब्ध)।
|
||||
|
||||
इनमें से किसी एक के बिना, व्यक्तिगत टूल निष्पादन ऑडिट लॉग में रिकॉर्ड नहीं होते।
|
||||
:::
|
||||
|
||||
### एक्सपोर्ट करना {#exporting}
|
||||
|
||||
```
|
||||
GET /api/v1/enterprise/audit/export?format=csv&from=2026-01-01T00:00:00Z
|
||||
```
|
||||
|
||||
`audit:read` permission और `audit_export` enterprise फ़ीचर आवश्यक है (team और enterprise दोनों प्लान पर उपलब्ध)। CSV और JSON फ़ॉर्मैट का समर्थन करता है, `action`, `actorId`, `targetType`, `targetId`, `from`, और `to` के अनुसार फ़िल्टर किया जाता है।
|
||||
|
||||
### छेड़छाड़-प्रतिरोधी हस्ताक्षर {#tamper-resistant-signing}
|
||||
|
||||
सक्षम होने पर, हर ऑडिट लॉग एंट्री को `DATA_ENCRYPTION_KEY` से व्युत्पन्न एक HMAC के साथ हस्ताक्षरित किया जाता है। इसके लिए आवश्यक है:
|
||||
|
||||
1. अपने एनवायरनमेंट में `DATA_ENCRYPTION_KEY` सेट करना।
|
||||
2. `tamperResistantAudit` एडमिन सेटिंग सक्षम करना।
|
||||
3. `tamper_resistant_audit` फ़ीचर वाला एक enterprise लाइसेंस।
|
||||
|
||||
### रिटेंशन {#retention}
|
||||
|
||||
पुरानी एंट्रियों को स्वचालित रूप से हटाने के लिए `AUDIT_RETENTION_DAYS` सेट करें। डिफ़ॉल्ट `0` है, जिसका अर्थ है कि एंट्रियाँ अनिश्चित काल तक रखी जाती हैं।
|
||||
|
||||
### घटना संदर्भ {#event-reference}
|
||||
|
||||
| Event | Category |
|
||||
|---|---|
|
||||
| `LOGIN_SUCCESS`, `LOGIN_FAILED` | Authentication |
|
||||
| `OIDC_LOGIN_SUCCESS`, `OIDC_LOGIN_FAILED` | Authentication |
|
||||
| `SAML_LOGIN_SUCCESS`, `SAML_LOGIN_FAILED` | Authentication |
|
||||
| `LOGOUT` | Authentication |
|
||||
| `USER_CREATED`, `USER_UPDATED`, `USER_DELETED` | User management |
|
||||
| `PASSWORD_CHANGED`, `PASSWORD_RESET` | User management |
|
||||
| `MFA_ENROLLED`, `MFA_DISABLED`, `MFA_VERIFIED`, `MFA_VERIFY_FAILED` | MFA |
|
||||
| `MFA_CHALLENGE_ISSUED`, `MFA_RECOVERY_USED`, `MFA_RESET` | MFA |
|
||||
| `ROLE_CREATED`, `ROLE_UPDATED`, `ROLE_DELETED` | Roles |
|
||||
| `API_KEY_CREATED`, `API_KEY_DELETED` | API keys |
|
||||
| `SETTINGS_UPDATED`, `IP_ALLOWLIST_UPDATED` | Settings |
|
||||
| `FILE_UPLOADED`, `FILE_DELETED` | Files |
|
||||
| `TOOL_EXECUTED` | Tools (ऑप्ट-इन) |
|
||||
| `SCIM_USER_PROVISIONED`, `SCIM_USER_UPDATED`, `SCIM_USER_DEPROVISIONED` | SCIM |
|
||||
| `SCIM_GROUP_SYNCED` | SCIM |
|
||||
| `LEGAL_HOLD_APPLIED`, `LEGAL_HOLD_RELEASED` | Compliance |
|
||||
| `GDPR_EXPORT_INITIATED`, `GDPR_USER_PURGED`, `GDPR_TEAM_PURGED` | Compliance |
|
||||
| `CONFIG_EXPORTED`, `CONFIG_IMPORTED` | Configuration |
|
||||
|
||||
## सत्र प्रबंधन {#session-management}
|
||||
|
||||
सत्र कुकी-आधारित होते हैं, `SESSION_DURATION_HOURS` द्वारा नियंत्रित (डिफ़ॉल्ट: 168 घंटे / 7 दिन)।
|
||||
|
||||
### Role बदलाव सत्रों को अमान्य करते हैं {#role-changes-invalidate-sessions}
|
||||
|
||||
जब कोई एडमिन किसी उपयोगकर्ता का role बदलता है, तो उस उपयोगकर्ता के सभी सक्रिय सत्र हटा दिए जाते हैं। उपयोगकर्ता को अपनी नई permissions प्राप्त करने के लिए फिर से लॉग इन करना होगा।
|
||||
|
||||
### सुरक्षा गार्ड {#safety-guards}
|
||||
|
||||
- **अंतिम-एडमिन सुरक्षा**: अंतिम शेष एडमिन को किसी निचले role में डिमोट नहीं किया जा सकता। यदि आप ऐसा करने की कोशिश करते हैं तो API एक त्रुटि लौटाता है।
|
||||
- **स्व-विलोपन रोकथाम**: एडमिन API के माध्यम से अपना खुद का अकाउंट नहीं हटा सकते।
|
||||
Reference in New Issue
Block a user