- Prepaid credit system: org wallet, debit on usage, chat gate, admin credit console - Engine UI: /manager, /tasks, /tasks/[id], /workforce, /dashboard, /traces pages - Direct task creation (HTTP POST /tasks, MCP tasks_create) at pending_manager_review - Pause/resume/cancel/answer actions in engine API and UI - Employee cap (7 per org default), review pipeline guard (active reviewer required) - Scheduler: wide window prevents org starvation; archived employees excluded from cap - Tenant isolation: project-id cross-org 404, engine never uses another tenant's sandbox - Order route fix: manager built with pipeline states + employee profiles - Contract extension: ModelGrantPort.get_org_policy with DefaultOrgPolicy - Engine event types in @agy/contracts (task.step, task.gate, run.log, run.tool, team.changed) - api-engine.ts typed client; api-credit.ts client - Alembic migration c4d5e6f7a8b9: prepaid credit + engine UI tables - 859 tests passed, 1 skipped; ruff/mypy/tsc/eslint/vitest all green Refs: PLAN-v2.md §9 (T1–T43), todo-v2-final.md
397 lines
23 KiB
Markdown
397 lines
23 KiB
Markdown
# Smart Organization — پلتفرم نیروی کار هوش مصنوعی
|
||
|
||
نسخهٔ وب مستقل و چندسازمانی محصول. این پروژه **کاملاً جدا از ربات تلگرام** است و
|
||
هیچ فایلی از ریشهٔ مخزن را در runtime خود import نمیکند.
|
||
|
||
- پلن محصول و معماری: [`PLAN.md`](./PLAN.md)
|
||
- چکلیست اجرایی کامل: [`TODO.md`](./TODO.md)
|
||
- یادداشت زیرساخت فعلی (فقط مرجع): [`docs/current-infra-notes.md`](./docs/current-infra-notes.md)
|
||
|
||
---
|
||
|
||
## ۱. محصول چیست
|
||
|
||
یک وب اپلیکیشن چندسازمانی برای «نیروی کار هوش مصنوعی سازمانی».
|
||
|
||
**کاربر نهایی اینها را میبیند:** سازمان، مدیر هوش مصنوعی، کارمندهای هوش مصنوعی،
|
||
پروژه، وظیفه، فایل/خروجی، مصرف و پرداخت.
|
||
|
||
**کاربر نهایی اینها را نمیبیند:** نام مدل، provider، `base_url`، API key، قیمت خام
|
||
provider. اینها فقط در **Admin Console** و فقط برای مالک سامانه قابل مدیریتاند.
|
||
|
||
پلتفرم سه لایهٔ نقش دارد:
|
||
|
||
1. **مالک سامانه (platform owner)** — **دقیقاً یک حساب** و صاحب کل سیستم. اکانتهای
|
||
agy، مدلها، routing policy، تعرفهها، sandbox templateها، مشاهدهٔ کل مصرف، و
|
||
ساخت/تنزل **مدیران**. agy تنها ارائهدهندهٔ مدل سامانه است و بخش جداگانهٔ
|
||
«ارائهدهندهها» وجود ندارد.
|
||
2. **مدیر (platform manager)** — حسابی که فقط مالک سامانه میسازد. هر مدیر
|
||
میتواند **سازمانهای خودش را بسازد** (و مالک آنها شود) یا با **دعوت** صاحب
|
||
سازمان، در سازمان مدیران دیگر عضو شود. مدیر به کنسول مالک سامانه دسترسی ندارد.
|
||
3. **کاربر عادی (platform user)** — سازمان نمیسازد؛ فقط داخل سازمانهایی که با
|
||
دعوت به آنها پیوسته کار میکند.
|
||
|
||
**ثبتنام عمومی وجود ندارد.** حسابها از دو مسیر ساخته میشوند:
|
||
|
||
- **ساخت مستقیم توسط مالک سامانه** در `/admin/users` (برای مدیر یا کاربر عادی) که
|
||
یک رمز موقت یکبارمصرف برمیگرداند؛
|
||
- **پذیرش لینک دعوت**: دعوتشده اگر حساب نداشته باشد، در همان صفحه رمز خودش را
|
||
تعیین میکند و حساب ساخته میشود. اگر حساب داشته باشد باید اول وارد شود — یک
|
||
لینک دعوت هرگز جای reset رمز را نمیگیرد.
|
||
|
||
«فقط یک مالک» یک قاعدهٔ دیتابیسی است: ایندکس یکتای جزئی روی
|
||
`users.platform_role = 'owner'`، پس حتی یک درج مستقیم هم نمیتواند مالک دوم بسازد.
|
||
جابهجایی صندلی مالکیت فقط با `POST /admin/transfer-ownership` انجام میشود که در
|
||
یک تراکنش، مالک فعلی را به مدیر تنزل میدهد و جانشین را مالک میکند.
|
||
|
||
**اعتبار پیشپرداخت.** سازمانها با اعتبار پیشپرداخت کار میکنند. مالک سامانه در `/admin/credits` به هر سازمان اعتبار میدهد و هر رکورد مصرف (مدل، sandbox و بازتاب حافظه) بهمحض ثبت، از کیف پول همان سازمان کم میشود. وقتی موجودی به صفر یا کمتر برسد، کارهای آن سازمان متوقف میشوند و گفتگوی مدیر هم مدل را صدا نمیزند. کارهای متوقفشده پس از شارژ خودکار ادامه نمییابند؛ با دکمهٔ «ادامه» دستی و از همان مرحله ادامه داده میشوند.
|
||
|
||
---
|
||
|
||
## ۲. پیشنیازها
|
||
|
||
| ابزار | نسخه |
|
||
|---|---|
|
||
| Node.js | >= 20 |
|
||
| pnpm | 9.x |
|
||
| Python | 3.13 |
|
||
| Docker + Compose | برای postgres/redis |
|
||
|
||
فعالسازی pnpm در صورت نبود:
|
||
|
||
```bash
|
||
corepack enable pnpm
|
||
corepack prepare pnpm@9.12.0 --activate
|
||
```
|
||
|
||
---
|
||
|
||
## ۳. راهاندازی سریع
|
||
|
||
```bash
|
||
# ۱) نصب وابستگیهای JS
|
||
pnpm install
|
||
|
||
# ۲) ساخت venv پایتون برای backend
|
||
pnpm api:venv
|
||
|
||
# ۳) کپی فایل env و پر کردن مقادیر (پیشفرضها همه mock هستند)
|
||
cp .env.example .env
|
||
|
||
# ۴) بالا آوردن postgres و redis
|
||
docker compose -f infra/docker/docker-compose.yml up -d postgres redis
|
||
|
||
# ۵) اجرای migration و seed
|
||
pnpm db:migrate
|
||
pnpm db:seed
|
||
|
||
# ۶) اجرای همزمان frontend و backend
|
||
pnpm dev
|
||
```
|
||
|
||
آدرسها پس از اجرا:
|
||
|
||
- Frontend: <http://localhost:3000>
|
||
- API: <http://localhost:8000>
|
||
- API docs (Swagger): <http://localhost:8000/docs>
|
||
- Health: <http://localhost:8000/health>
|
||
|
||
### حسابهای نمونه (فقط محیط توسعه)
|
||
|
||
`pnpm db:seed` دو حساب میسازد:
|
||
|
||
| نقش | ایمیل | رمز | چه میبیند |
|
||
|---|---|---|---|
|
||
| مالک سامانه (admin console) | `owner@example.com` | `owner12345` | کنسول مالک سامانه، بدون هیچ سازمانی |
|
||
| مدیر نمونه | `demo@example.com` | `demo12345` | سازمان نمونه که خودش مالک آن است |
|
||
|
||
> مالک سامانه **عضو هیچ سازمانی نمیشود** — او مستأجرها را از کنسول میبیند، نه از
|
||
> داخل دادهشان. برای دیدن داشبورد سازمانی با حساب مدیر نمونه وارد شوید.
|
||
>
|
||
> اینها رمزهای **توسعه** هستند و در `app/seed.py` سختکد شدهاند. هیچوقت در
|
||
> production از اینها استفاده نکنید و `JWT_SECRET` / `ENCRYPTION_KEY` واقعی
|
||
> بگذارید (نگهبان config در حالت production مقادیر placeholder را رد میکند).
|
||
>
|
||
> نکته: دامنهٔ ایمیل عمداً `example.com` است. اگر `.local` یا `.test` بگذارید،
|
||
> `email-validator` آن را رد میکند و حساب ساخته میشود ولی **ورود به آن ناممکن
|
||
> است**. `tests/test_seed.py` همین را تضمین میکند.
|
||
|
||
### اجرای کل استک با Docker
|
||
|
||
```bash
|
||
docker compose -f infra/docker/docker-compose.yml up --build
|
||
```
|
||
|
||
---
|
||
|
||
## ۴. اسکریپتها
|
||
|
||
| دستور | کار |
|
||
|---|---|
|
||
| `pnpm dev` | اجرای همزمان Next.js و FastAPI |
|
||
| `pnpm build` | build فرانتاند |
|
||
| `pnpm lint` | ESLint (web) + ruff (api) |
|
||
| `pnpm typecheck` | tsc (web) + mypy (api) |
|
||
| `pnpm test` | vitest (web) + pytest (api) |
|
||
| `pnpm format` | Prettier (web) + ruff format (api) |
|
||
| `pnpm db:migrate` | `alembic upgrade head` |
|
||
| `pnpm db:seed` | دادههای نمونه (platform owner، کاربر نمونه، سازمان، templateها) |
|
||
| `pnpm api:venv` | ساخت venv پایتون |
|
||
| `pnpm worker:billing` | یک پاس worker صورتحساب |
|
||
| `pnpm worker:ai-runtime` | یک پاس worker اجرای taskها |
|
||
| `pnpm worker:sandbox-gateway` | یک پاس پاکسازی sessionهای بیاستفاده |
|
||
|
||
---
|
||
|
||
## ۵. معماری
|
||
|
||
### ۵.۱ سبک معماری
|
||
|
||
- **Clean Architecture** + **Hexagonal / Ports & Adapters**
|
||
- **DDD** برای مرزبندی bounded contextها
|
||
- **Event-Driven** برای billing، audit و observability (الگوی Outbox)
|
||
- **Modular Monolith** در فاز اول — microservice زودهنگام ممنوع
|
||
|
||
قاعدهٔ سخت: لایهٔ `domain` هیچ dependency به FastAPI، SQLAlchemy، Redis، HTTP یا
|
||
provider خارجی ندارد. فقط `application` و `infrastructure` به آن وابستهاند، نه برعکس.
|
||
|
||
### ۵.۲ Bounded Contextها
|
||
|
||
`identity` · `billing` · `ai_control` · `workforce` · `sandbox` · `knowledge` ·
|
||
`audit` · `projects` · `platform`
|
||
|
||
### ۵.۳ Ports الزامی
|
||
|
||
`ModelProviderPort` · `PaymentProviderPort` · `SandboxProviderPort` ·
|
||
`GitProviderPort` · `DomainRouterPort` · `StoragePort` · `VectorStorePort` ·
|
||
`NotificationPort` · `AuditPort` · `UsageLedgerPort`
|
||
|
||
هر port حداقل یک adapter **mock** دارد تا کل استک بدون هیچ credential واقعی اجرا شود.
|
||
|
||
### ۵.۴ جریان درخواست
|
||
|
||
```text
|
||
Browser → Web (Next.js/BFF) → API (FastAPI)
|
||
├── Domain Modules
|
||
├── Event Bus / Outbox → Workers
|
||
├── AI Runtime → Model Providers
|
||
├── Sandbox Gateway → E2B / Daytona
|
||
└── Billing Processor → Stripe
|
||
```
|
||
|
||
---
|
||
|
||
## ۶. ساختار پوشه
|
||
|
||
```text
|
||
web/
|
||
PLAN.md پلن محصول و معماری
|
||
TODO.md چکلیست اجرایی
|
||
README.md همین فایل
|
||
package.json اسکریپتهای ریشه
|
||
pnpm-workspace.yaml تعریف workspace
|
||
.env.example نمونهٔ env (هیچ secret واقعی ندارد)
|
||
apps/
|
||
web/ Next.js + TypeScript (UI)
|
||
api/ FastAPI + SQLAlchemy (backend)
|
||
services/
|
||
ai-runtime/ worker اجرای Agent
|
||
sandbox-gateway/ wrapper ایزولهسازی اجرا
|
||
billing-worker/ پردازش usage و invoice
|
||
packages/
|
||
contracts/ تایپها و قراردادهای مشترک
|
||
ui/ componentهای پایه (design system)
|
||
infra/
|
||
docker/ docker-compose
|
||
migrations/ محل migrationها
|
||
docs/
|
||
architecture/ مستندات معماری
|
||
product/ مستندات محصول
|
||
current-infra-notes.md
|
||
```
|
||
|
||
---
|
||
|
||
## ۷. کجا کد بنویسیم
|
||
|
||
| میخواهم... | محل |
|
||
|---|---|
|
||
| صفحه یا component UI بسازم | `apps/web/src/app` یا `apps/web/src/features` |
|
||
| component پایه/design system | `packages/ui` |
|
||
| endpoint جدید بسازم | `apps/api/app/interfaces/http` |
|
||
| use case بنویسم | `apps/api/app/application` |
|
||
| منطق دامنه بنویسم | `apps/api/app/domain/<context>` |
|
||
| adapter یا اتصال به سرویس بیرونی | `apps/api/app/infrastructure` |
|
||
| worker پسزمینه بنویسم | `apps/api/app/workers` (پوستهٔ اجرا در `services/<name>`) |
|
||
| خطا ثبت/پاکسازی کنم | `apps/api/app/core/redact.py` + `apps/api/app/infrastructure/error_log.py` |
|
||
| قرارداد مشترک front/back | `packages/contracts` |
|
||
|
||
**ممنوع:** نوشتن هر کد جدید در فایلهای ریشهٔ مخزن (`bot.py`, `web_panel.py`,
|
||
`bot_menus.py`, `bot_messages.py`) و هر وابستگی به `telegram`, `chat_id`,
|
||
`callback_data`, `InlineKeyboardMarkup`.
|
||
|
||
---
|
||
|
||
## ۸. سرویسهای خارجی و حالت mock
|
||
|
||
همهٔ سرویسهای بیرونی پیشفرض روی `mock` هستند. برای فعالسازی واقعی، این envها را
|
||
پر کنید:
|
||
|
||
| قابلیت | env | مقادیر |
|
||
|---|---|---|
|
||
| Git | `GIT_PROVIDER` | `mock` \| `gitea` |
|
||
| Workspace گیت | `GIT_WORKSPACE` | `fake` (پیشفرض، برای تست) \| `local` (git روی host) |
|
||
| دامنهٔ تست | `DOMAIN_ROUTER` | `mock` \| `caddy` |
|
||
| دامنهٔ سفارشی | `ALLOW_CUSTOM_DOMAINS` | `false` (پیشفرض) \| `true` |
|
||
| Sandbox | `SANDBOX_PROVIDER` | `mock` \| `docker` \| `daytona` \| `e2b` |
|
||
| استقرار روی شبکهٔ خصوصی | `DEPLOY_ALLOW_PRIVATE_HOSTS` | `false` (پیشفرض)؛ `true` فقط برای مقصدی در شبکهٔ خصوصی که قابل اعتماد است |
|
||
| MCP gateway | `MCP_GATEWAY_ENABLED` | `true` (پیشفرض) \| `false` |
|
||
| پرداخت | `PAYMENT_PROVIDER` | `mock` \| `stripe` |
|
||
| اعتبار اولیهٔ سازمانهای جدید | `BILLING_STARTING_CREDIT` | عدد؛ پیشفرض `0` (یعنی به سازمان جدید اعتباری داده نمیشود) |
|
||
|
||
اگر credential واقعی نداریم، **قابلیت حذف نمیشود**: مدل دیتابیس، interface، UI و
|
||
adapter mock کامل ساخته میشود و adapter واقعی پشت همین flag آماده میماند.
|
||
|
||
با پیشفرضها (`mock`، `fake` و `false`) تستها بدون docker، git یا شبکه اجرا میشوند.
|
||
|
||
**حالت واقعی (real mode):** وقتی سامانه باید روی یک host واقعی با docker و caddy اجرا شود، این envها را تنظیم کنید:
|
||
|
||
```bash
|
||
SANDBOX_PROVIDER=docker GIT_WORKSPACE=local DOMAIN_ROUTER=caddy GIT_PROVIDER=gitea
|
||
```
|
||
|
||
نیازمندیهای host در این حالت:
|
||
|
||
- `docker` یا `podman` در `PATH` (با `SANDBOX_DOCKER_BIN` انتخاب میشود). کد کاربر فقط داخل کانتینرهای سختشده اجرا میشود: `--read-only`، کاربر غیر root، `--cap-drop ALL`، و محدودیت CPU، حافظه و PID.
|
||
- `git` نسخهٔ 2.20 یا جدیدتر در `PATH`. git را خود پلتفرم اجرا میکند؛ hookها غیرفعالاند و اعتبارنامهها هرگز در argv یا URL نمیآیند.
|
||
- `caddy` در `PATH` و این خط در Caddyfile: `import /etc/caddy/agy-preview/*.caddy`. بدون این خط adapter اجرا نمیشود، تا یک موفقیت کاذب گزارش نشود.
|
||
- اجازهٔ بدون رمز برای `caddy reload --config <file>` به کاربر سرویس (روی systemd با sudoers یا polkit، نه با root).
|
||
- پوشههای قابلنوشتن با فضای کافی زیر `SANDBOX_WORKSPACES_ROOT` و `ARTIFACTS_ROOT` (پیشفرض `./.data/…`). پاکسازی خودکار `runs/`، `artifacts/` و فایلهای پشتیبان FTP هنوز پیاده نشده است.
|
||
- هدف استقرار `ftps` (TLS صریح) است. هدف `ftp` ساده پذیرفته میشود، ولی بدون رمزنگاری است.
|
||
- تستهای یکپارچگی docker و استقرار با `SANDBOX_DOCKER_IT=1` و `DEPLOY_IT=1` فعال میشوند و بدون آنها رد (skip) میشوند.
|
||
|
||
### ارائهدهندهٔ agy (Google Antigravity) — تنها ارائهدهندهٔ مدل
|
||
|
||
agy کلید API ندارد؛ **اکانت**ها هویت Google هستند و از طریق OAuth وارد
|
||
میشوند. کاتالوگ مدلها در seed ساخته میشود و همان اول فعال است. برای شروع:
|
||
|
||
1. با حساب مالک سامانه وارد کنسول مدیریت شوید و از
|
||
`/admin/agy-accounts` → «افزودن اکانت agy» شروع کنید: لینک احراز هویت گوگل
|
||
باز میشود، بعد از تأیید، URL بازگشت را از نوار آدرس مرورگر کپی و Paste
|
||
کنید (صفحهٔ مقصد عمداً بارگذاری نمیشود؛ پارامترها همانجا هستند).
|
||
2. در `/admin/models` زنجیرهٔ افزودن مدل کاملاً انتخابی است: ارائهدهنده
|
||
(agy) → اکانت → مدل (کاتالوگ لحظهای و زندهٔ همان اکانت) → افورت استدلال
|
||
(فقط برای مدلهای استدلالی). هیچ نام مدلی دستی تایپ نمیشود و مشتری نام مدل
|
||
را هرگز نمیبیند.
|
||
|
||
هر تعداد اکانت Google که بخواهید اضافه کنید. پول چرخشی، بار را بین اکانتها
|
||
پخش میکند و اکانتی که ۴۲۹ گرفته تا پایان پنجرهٔ سهمیهٔ آن کنار گذاشته
|
||
میشود (هم در حافظه و هم در دیتابیس، تا workerها همان تصویر را ببینند).
|
||
refresh tokenها فقط encrypted at rest ذخیره میشوند و هیچوقت از API
|
||
برنمیگردند.
|
||
|
||
---
|
||
|
||
## ۹. Workerهای پسزمینه
|
||
|
||
پنج process پسزمینه وجود دارد: چهار worker و یک MCP gateway. همه در `apps/api/app/workers/` پیاده شدهاند (MCP gateway در `apps/api/app/interfaces/mcp/`) و `services/<name>` پوستهٔ اجرای آنهاست:
|
||
|
||
| worker | کار | دستور |
|
||
|---|---|---|
|
||
| `billing-worker` | جمعبندی usage ledger به فاکتور draft (هر دوره یکبار، idempotent)، و در همان پاس حذف نرم درسهای حافظهای منقضیشده (بهجز موارد pin شده) | `pnpm worker:billing` |
|
||
| `ai-runtime` | برداشتن taskهای در صف و اجرای آنها از مسیر run engine، و یک `Scheduler.tick()` در هر پاس (فاصلهٔ پاسها با `ENGINE_TICK_SECONDS`) | `pnpm worker:ai-runtime` |
|
||
| `sandbox-gateway` | متوقفکردن sessionهای بیاستفاده، حذف containerهای یتیم با label `smart-org.*`، و ثبت audit | `pnpm worker:sandbox-gateway` |
|
||
| `delivery` | اجرای pipeline runهای در صف (از checkout تا route) و بررسی ریموتها برای pushهای بیرونی هر `DELIVERY_POLL_SECONDS` | `pnpm worker:delivery` |
|
||
|
||
**پیشپرداخت:** پاس `ai-runtime` تسکهای سازمانی را که کیف پول آنها صفر، منفی یا نامشخص است، پیش از خرج کردن هر turn متوقف میکند. این تسکها پس از شارژ دستی ادامه داده میشوند.
|
||
|
||
**MCP gateway** یک سرویس مداوم است که با `pnpm mcp:dev` اجرا میشود. عاملهای بیرونی AI با توکنهای محدود به یک سازمان به آن وصل میشوند. جزئیات در `services/mcp-gateway/README.md`.
|
||
|
||
هر دستور worker **یک پاس** اجرا میکند و خارج میشود (شکل مناسب cron). برای اجرای مستمر `--loop` بدهید:
|
||
|
||
```bash
|
||
cd apps/api && .venv/bin/python -m app.workers billing --loop --interval 3600
|
||
```
|
||
|
||
**اصل مهم:** workerها هیچ منطق تجاری ندارند. `ai-runtime`، `sandbox-gateway` و `delivery` سرویسهای خود را از همان builderهای `app/application/container*.py` میسازند که HTTP API میسازد، پس آنها و API هرگز نمیتوانند دربارهٔ اینکه کدام adapter پشت یک port است اختلاف داشته باشند. `billing-worker` مستقیم از repositoryها استفاده میکند. جزئیات هر کدام در `services/*/README.md`.
|
||
|
||
---
|
||
|
||
## ۱۰. اصول تغییرناپذیر
|
||
|
||
1. اجرای کد کاربر یا agent روی host اصلی **ممنوع** — فقط از مسیر Sandbox Gateway.
|
||
2. هر endpoint چندسازمانی باید `organization_id` را enforce کند.
|
||
3. هیچ secret، token یا API key در frontend یا لاگ چاپ نمیشود.
|
||
4. هر عملیات destructive باید confirmation و audit log داشته باشد.
|
||
5. مدل و provider از دید کاربر عادی پنهان است.
|
||
6. هر مصرفی در usage ledger داخلی ثبت میشود (Stripe فقط adapter است).
|
||
|
||
---
|
||
|
||
## ۱۱. کنسول خطا
|
||
|
||
هر خطایی که سامانه بگیرد — در درخواست HTTP، در worker پسزمینه، یا در زمان
|
||
راهاندازی — با جزئیات کامل در جدول `error_events` ثبت میشود و در
|
||
`/admin/errors` (فقط مالک سامانه) قابل مشاهده است.
|
||
|
||
**چه چیزی ثبت میشود**
|
||
|
||
| منبع | چه زمانی | شدت |
|
||
| --- | --- | --- |
|
||
| استثنای مدیریتنشده و خطاهای ۵xx | همیشه | `critical` / `error` |
|
||
| `ValueError` بدون نوع مشخص | همیشه | `warning` |
|
||
| سایر پاسخهای ۴xx | فقط با `ERROR_LOG_CLIENT_ERRORS=1` | `warning` |
|
||
|
||
۴xx بهصورت پیشفرض ثبت نمیشود چون یک API عمومی دائماً ۴۰۴ از اسکنرها
|
||
میگیرد و ثبت همهٔ آنها خطاهای واقعی را زیر خود دفن میکند. خطاهای ۵xx
|
||
همیشه ثبت میشوند، مستقل از این تنظیم.
|
||
|
||
**هر رکورد چه چیزی دارد**
|
||
|
||
- `kind`، `error_type`، `message` و `stack` (ردِّ کامل خطا)
|
||
- `method`، `path`، `status_code` و `request_id`
|
||
- `organization_id` و `user_id` (پس از احراز هویت)
|
||
- `fingerprint` — هش پایدار از هویت خطا، برای گروهبندی
|
||
- `metadata_json` — جزئیات اضافی (مثلاً `task_id`)
|
||
|
||
**گروهبندی و رسیدگی**
|
||
|
||
خطاهای یکسان بر اساس `fingerprint` در یک ردیف جمع میشوند، پس یک باگ که ۴۰۰۰
|
||
بار رخ داده یک خط با شمارنده است، نه ۴۰۰۰ خط. `fingerprint` عمداً سازمان و
|
||
کاربر را در نظر نمیگیرد: یک باگ که دو مستأجر را میزند هنوز یک باگ است.
|
||
بستن یک گروه همهٔ رخدادهای باز آن را میبندد و در audit log ثبت میشود.
|
||
|
||
**پاکسازی خودکار secretها**
|
||
|
||
هیچ خطایی بدون عبور از `app/core/redact.py` ذخیره نمیشود. سه لایه:
|
||
کلیدهایی که معنایشان secret است (`password`، `api_key`، …)، الگوهای
|
||
شناختنی (JWT، `Bearer`، `scheme://user:pass@host`، `sk-…`، `ghp_…`)، و
|
||
خودِ مقادیر secret تنظیمشده در `settings`. یک لاگ خطا که رمز عبور ذخیره کند
|
||
از نداشتن لاگ خطا بدتر است.
|
||
|
||
**استفاده از `request_id`**
|
||
|
||
هر پاسخ `X-Request-ID` دارد و هر بدنهٔ خطا هم همان شناسه را در
|
||
`error.request_id` برمیگرداند. کاربر میتواند فقط همین یک رشته را گزارش کند
|
||
تا دقیقاً یک رکورد پیدا شود.
|
||
|
||
```bash
|
||
# ۵۰۰ بگیر، سپس با همان شناسه رکورد را پیدا کن
|
||
curl -i http://localhost:8000/api/whatever -H "X-Request-ID: my-trace"
|
||
curl "http://localhost:8000/api/admin/errors?search=my-trace" -H "Authorization: Bearer $OWNER_TOKEN"
|
||
```
|
||
|
||
**اجرای دستی workerها و ثبت خطا**
|
||
|
||
خطای یک pass کامل با `source=worker` ثبت میشود و exit code غیرصفر میدهد تا
|
||
cron متوجه شود. خطای یک task مشخص نیز با `task_id` و سازمان مربوطه ثبت
|
||
میشود.
|
||
|
||
---
|
||
|
||
## ۱۲. مستندات
|
||
|
||
- [`docs/architecture/overview.md`](./docs/architecture/overview.md) — نمای کلی معماری
|
||
- [`docs/security-checklist.md`](./docs/security-checklist.md) — چکلیست امنیتی
|
||
- [`docs/current-infra-notes.md`](./docs/current-infra-notes.md) — زیرساخت فعلی (مرجع)
|