- users.is_platform_owner → users.platform_role (owner|manager|user) با مهاجرت d4e5f6a7b8c9 و backfill. ایندکس یکتای جزئی uq_single_platform_owner تضمین میکند دقیقاً یک مالک وجود داشته باشد — در سطح دیتابیس، نه فقط در کد. - ثبتنام عمومی حذف شد (POST /auth/signup). حسابها فقط با POST /admin/users (فقط مالک، با رمز موقت یکبارمصرف) یا با پذیرش لینک دعوت ساخته میشوند. در مسیر دعوت، اگر حساب وجود نداشته باشد خودِ دعوتشده رمز تعیین میکند؛ اگر وجود داشته باشد لینک هرگز جای reset رمز را نمیگیرد. - ساخت سازمان فقط برای مالک و مدیران؛ کاربر عادی با دعوت عضو میشود. - تنزل یا حذف مدیر، سازمانهایش را به مالک سامانه منتقل میکند (مالکیت + عضویت، با audit). حساب مالک از API تغییرناپذیر است؛ جابهجایی صندلی فقط با POST /admin/transfer-ownership و در یک تراکنش انجام میشود. - افزودن POST /auth/change-password برای تبدیل رمز موقت به رمز خصوصی. - فرانت: صفحهٔ /admin/users، صفحهٔ /account، بازنویسی /accept-invite، حذف /signup، گارد /onboarding برای کاربر عادی، و نشان نقش پلتفرم در پوستهٔ اپ. - PRAGMA foreign_keys=ON برای SQLite تا ON DELETE CASCADE در dev و prod یکسان رفتار کند (پیشتر حذف کاربر، عضویتهایش را یتیم میگذاشت). - تست: ۳۰۰ تست بکاند (شامل tests/test_platform_hierarchy.py با ۲۲ تست) و ۶۴ تست فرانتاند؛ ruff، mypy، tsc، eslint و build تمیز.
1476 lines
47 KiB
Markdown
1476 lines
47 KiB
Markdown
# TODO اجرای کامل نسخه وب مستقل Smart Organization
|
|
|
|
> **وضعیت (بهروزرسانی نهایی):** پیادهسازی کامل شده است.
|
|
>
|
|
> - بکاند: **۲۱۶ تست سبز**، `ruff check` تمیز، `mypy` روی **۹۰ فایل** بدون خطا.
|
|
> - فرانتاند: **۴۵ تست سبز**، `next lint` بدون هشدار، `tsc --noEmit` تمیز.
|
|
> - دو migration در `apps/api/alembic/versions/` ساخته و با `alembic check`
|
|
> تأیید شد که هیچ drift ندارد. مسیر upgrade و downgrade هر دو تست شدهاند.
|
|
> - workerها (`billing-worker`, `ai-runtime`, `sandbox-gateway`) واقعی و تستشدهاند.
|
|
> - مستندات: `docs/architecture/overview.md` و `docs/security-checklist.md` نوشته شدند.
|
|
>
|
|
> **افزودهٔ بعد از بستن مراحل (درخواست کاربر):** ثبت کامل خطا در دیتابیس.
|
|
> هر خطایی — در HTTP، در worker، در راهاندازی — با جزئیات کامل
|
|
> (ردِّ خطا، `request_id`، سازمان، کاربر، مسیر، اثر انگشت) در جدول
|
|
> `error_events` ذخیره میشود و در `/admin/errors` قابل مشاهده و رسیدگی است.
|
|
> هیچ خطایی بدون پاکسازی secret ذخیره نمیشود (`app/core/redact.py`).
|
|
>
|
|
> **افزودهٔ بعد از بستن مراحل (درخواست کاربر):** پالت فرمان (`⌘K`) و صفحهٔ
|
|
> `/admin/usage`.
|
|
>
|
|
> **افزودهٔ بعد از بستن مراحل (درخواست کاربر):** Motion system. یک واژگان
|
|
> مشترک در `apps/web/src/app/globals.css` — شش `@keyframes` و شش کلاس
|
|
> `.anim-*` بههمراه `.anim-stagger` برای ورود آبشاری — و همهٔ مدتزمانها
|
|
> پشت custom property. در `packages/ui/src/index.tsx` روی Button، Card،
|
|
> Stat، Loading/Empty/ErrorState، UsageBar، Timeline، Modal، Drawer، Table،
|
|
> ToastStack و ArtifactViewer اعمال شده و ریشهٔ هر صفحهٔ `(app)` با
|
|
> `.anim-stagger` وارد میشود. `prefers-reduced-motion` مدتزمانها را به
|
|
> ۰.۰۱ms میرساند تا وضعیت پایانی حفظ شود. قرارداد motion در
|
|
> `src/test/motion.test.tsx` Tests میشود تا بازنویسی بعدی آن را بیصدا
|
|
> حذف نکند.
|
|
>
|
|
> **افزودهٔ بعد از بستن مراحل (درخواست کاربر):** ساختار مالکیت پلتفرم. **دقیقاً یک
|
|
> مالک سامانه** وجود دارد که صاحب کل سیستم است و تنها او میتواند **مدیر** بسازد؛
|
|
> هر مدیر میتواند سازمانهای خودش را بسازد یا با دعوت در سازمان مدیران دیگر عضو
|
|
> شود. جزئیات:
|
|
>
|
|
> - `users.is_platform_owner` (boolean) جای خود را به `platform_role`
|
|
> (`owner` | `manager` | `user`) داد، با مهاجرت `d4e5f6a7b8c9` و backfill.
|
|
> - «فقط یک مالک» یک قاعدهٔ دیتابیسی است: ایندکس یکتای جزئی
|
|
> `uq_single_platform_owner ... WHERE platform_role = 'owner'`.
|
|
> - **ثبتنام عمومی حذف شد** (`POST /auth/signup` وجود ندارد). حسابها از
|
|
> `POST /admin/users` (فقط مالک) یا از پذیرش لینک دعوت ساخته میشوند؛ در مسیر
|
|
> دعوت، اگر حساب وجود نداشته باشد خود دعوتشده رمز تعیین میکند، و اگر وجود
|
|
> داشته باشد لینک هرگز جای reset رمز را نمیگیرد.
|
|
> - ساخت سازمان فقط برای مالک و مدیران مجاز است؛ کاربر عادی با دعوت عضو میشود.
|
|
> - تنزل یا حذف یک مدیر، سازمانهایش را به مالک سامانه منتقل میکند (مالکیت +
|
|
> عضویت، با audit). حساب مالک از API قابل تنزل/غیرفعال/حذف نیست؛ جابهجایی
|
|
> صندلی فقط با `POST /admin/transfer-ownership`.
|
|
> - فرانتاند: صفحهٔ جدید `/admin/users`، صفحهٔ `/signup` حذف شد، صفحهٔ
|
|
> `/accept-invite` برای ساخت حساب بازنویسی شد، و لینک «ساخت سازمان جدید» برای
|
|
> کاربران عادی پنهان است.
|
|
> - تستها: `tests/test_platform_hierarchy.py` (۲۲ تست) + بهروزرسانی
|
|
> `test_auth.py`, `test_invites.py`, `test_seed.py`, `test_realtime.py`؛
|
|
> جمع بکاند از ۲۱۶ به **۳۰۰ تست** و فرانتاند از ۴۵ به **۶۴ تست** رسید.
|
|
> `PRAGMA foreign_keys=ON` برای SQLite فعال شد تا `ON DELETE CASCADE` در dev و
|
|
> prod یکسان رفتار کند (پیشتر حذف کاربر، عضویتهایش را یتیم میگذاشت).
|
|
>
|
|
> **چیزهایی که عمداً باز ماندهاند:** در `docs/security-checklist.md` دو مورد
|
|
> «⚠️ بدون تست اختصاصی» علامت خوردهاند (نبود secret در frontend، و مقدار پیشفرض
|
|
> `NetworkPolicy.DENY_ALL`). هر دو کنترل در کد درست کار میکنند، فقط تست مستقل
|
|
> ندارند. هیچکدام شکاف امنیتی فعال نیست.
|
|
>
|
|
> **نکتهٔ صداقت:** چکباکسهای زیر **معیارهای پذیرش**، **§۲۲**، **§۲۳** و **§۰.۲**
|
|
> علامت خوردهاند چون مستقیماً تأیید شدهاند. بندهای ریزتر داخل بدنهٔ هر مرحله
|
|
> (۵۰۰ بند توصیفی) بهعنوان شرح کار باقی ماندهاند و علامت نخوردهاند؛ ادعای
|
|
> تأیید تکتک آنها بدون شاهد، خودش یک نقض صداقت مستندسازی میبود.
|
|
|
|
این فایل برای اجرای مرحلهبهمرحله توسط یک عامل کدنویس سبک مثل **DeepSeek v4.1 Flash** نوشته شده است.
|
|
هدف: ساخت نسخه وب مستقل و کامل محصول، بدون وابستگی runtime به ربات تلگرام فعلی.
|
|
|
|
> فایل مرجع محصول و معماری: `web/PLAN.md`
|
|
> محل مجاز توسعه: فقط داخل پوشه `web/` مگر در مواردی که صراحتاً گفته شده است.
|
|
> زبان رابط کاربری: فارسی، راستبهچپ، حرفهای، سریع و ساده.
|
|
> نکته مهم: سیستم فعلی already کدهایی برای **route دامنههای تست** و **Git/Gitea** دارد. در نسخه وب جدید همه سازمانها/کاربران باید بتوانند از این امکانات از طریق وب استفاده کنند، اما کد جدید نباید به تلگرام وابسته شود.
|
|
|
|
---
|
|
|
|
## 0. قوانین قطعی قبل از شروع
|
|
|
|
### 0.1 محدودیتهای اصلی
|
|
|
|
- [ ] هیچ قابلیت جدیدی را داخل فایلهای قدیمی ریشه پروژه مثل `bot.py`، `web_panel.py`، `bot_menus.py`، `bot_messages.py` پیادهسازی نکن.
|
|
- [ ] نسخه جدید باید داخل `web/` ساخته شود.
|
|
- [ ] هیچ منطق جدیدی نباید به `telegram`, `chat_id`, `callback_data`, `InlineKeyboardMarkup`, `MessageHandler`, `CallbackQueryHandler` وابسته باشد.
|
|
- [ ] اگر لازم است از منطق فعلی Git یا domain routing استفاده شود، فقط آن را به عنوان reference بخوان و در `web/` یک abstraction تمیز و مستقل بساز.
|
|
- [ ] هیچ API key، token، secret، credential یا password را در frontend یا لاگها چاپ نکن.
|
|
- [ ] اجرای کد کاربر یا agent روی host اصلی ممنوع است؛ همه چیز باید از مسیر Sandbox Gateway عبور کند.
|
|
- [ ] برای هر عملیات destructive مثل حذف سازمان، حذف repo، حذف دامنه، حذف sandbox یا پاککردن artifact باید confirmation و audit log وجود داشته باشد.
|
|
- [ ] هر endpoint چندسازمانی باید `organization_id` را enforce کند؛ هیچ کاربر نباید داده سازمان دیگر را ببیند.
|
|
|
|
### 0.2 تعریف Done برای کل پروژه
|
|
|
|
پروژه زمانی کامل است که:
|
|
|
|
- [x] کاربر بدون تلگرام ثبتنام و ورود کند.
|
|
- [x] کاربر بتواند سازمان بسازد و عضو دعوت کند.
|
|
- [x] مدیر سامانه بتواند provider/model/routing/price را پنهانی مدیریت کند.
|
|
- [x] کاربر عادی مدل خام نبیند؛ فقط مدیر و کارمندان AI را ببیند.
|
|
- [x] سازمان بتواند پروژه بسازد.
|
|
- [x] هر پروژه بتواند repo خصوصی Git داشته باشد.
|
|
- [x] هر پروژه بتواند یک دامنه تست/preview بگیرد.
|
|
- [x] هر پروژه بتواند یک محیط اجرای ایزوله بگیرد.
|
|
- [x] کاربر بتواند با Manager Chat صحبت کند و task بسازد.
|
|
- [x] یک task واقعی توسط AI worker اجرا شود.
|
|
- [x] usage event برای model call، sandbox runtime، storage/artifact و tool call ثبت شود.
|
|
- [x] داشبورد مصرف، run history، audit log و billing قابل مشاهده باشد.
|
|
- [x] build، lint، typecheck و تستهای اصلی بدون خطا اجرا شوند.
|
|
|
|
---
|
|
|
|
## 1. شناخت کد فعلی فقط برای reference
|
|
|
|
کد فعلی نباید runtime پایه نسخه جدید باشد، اما این فایلها را برای فهم زیرساخت بخوان:
|
|
|
|
- [ ] `caddy_manager.py`
|
|
- کار فعلی: مدیریت Caddy reverse proxy و ساخت route برای subdomain.
|
|
- نکات مهم:
|
|
- دامنه wildcard فعلی: `msa.artacloud.ir`
|
|
- فقط hostهای تکlabel زیر این دامنه مجاز هستند.
|
|
- target فقط باید `localhost:<port>` یا `127.0.0.1:<port>` باشد.
|
|
- قبل از reload، Caddyfile validate میشود.
|
|
- [ ] `port_registry.py`
|
|
- کار فعلی: تخصیص port و ledger مالکیت subdomain.
|
|
- نکات مهم:
|
|
- port range فعلی: `8080-8999`
|
|
- protected ports شامل `3000`, `35555`, `35556`, `35557`, `80`, `443`, `5432`, `6379` و موارد سیستمی است.
|
|
- جدول مفهومی `subdomain_registry` برای جلوگیری از hijack دامنه وجود دارد.
|
|
- هر پروژه حداکثر چند subdomain میگیرد؛ مقدار فعلی `MAX_SUBDOMAINS_PER_PROJECT = 5` است.
|
|
- [ ] `git_manager.py`
|
|
- کار فعلی: ساخت repo خصوصی Gitea، credential پروژه، git sync/commit/push، lock repo.
|
|
- نکات مهم:
|
|
- Gitea URL از config خوانده میشود.
|
|
- repo باید private باشد.
|
|
- credential پروژه باید per owner/project پایدار و collision-free باشد.
|
|
- [ ] `gitea_api.py`
|
|
- کار فعلی: API سبک برای PR، issue، comment و merge.
|
|
- نکات مهم:
|
|
- token نباید در خروجی یا prompt دیده شود.
|
|
- PR workflow و issue ingestion قابل استفاده برای نسخه جدید است.
|
|
|
|
### خروجی این مرحله
|
|
|
|
- [ ] در `web/docs/current-infra-notes.md` خلاصهای 1 تا 2 صفحهای از domain routing و Git فعلی بنویس.
|
|
- [ ] صراحتاً بنویس که نسخه جدید این کدها را مستقیماً import نمیکند، بلکه adapter مستقل خودش را میسازد.
|
|
|
|
---
|
|
|
|
## 2. ساختار پروژه داخل web
|
|
|
|
### 2.1 ساخت پوشهها
|
|
|
|
داخل `web/` این ساختار را بساز:
|
|
|
|
```text
|
|
web/
|
|
TODO.md
|
|
PLAN.md
|
|
README.md
|
|
package.json
|
|
pnpm-workspace.yaml
|
|
apps/
|
|
web/
|
|
api/
|
|
services/
|
|
ai-runtime/
|
|
sandbox-gateway/
|
|
billing-worker/
|
|
packages/
|
|
contracts/
|
|
ui/
|
|
infra/
|
|
docker/
|
|
migrations/
|
|
docs/
|
|
architecture/
|
|
product/
|
|
current-infra-notes.md
|
|
```
|
|
|
|
### 2.2 README اولیه
|
|
|
|
- [ ] در `web/README.md` بنویس:
|
|
- محصول چیست.
|
|
- چطور dev server اجرا میشود.
|
|
- چطور test/lint/typecheck اجرا میشود.
|
|
- معماری کلی چیست.
|
|
- کجا باید کد frontend/backend/worker نوشته شود.
|
|
|
|
### 2.3 package manager
|
|
|
|
- [ ] از `pnpm` استفاده کن.
|
|
- [ ] root `package.json` باید scriptهای زیر داشته باشد:
|
|
- `dev`
|
|
- `build`
|
|
- `lint`
|
|
- `typecheck`
|
|
- `test`
|
|
- `format`
|
|
- `db:migrate`
|
|
- `db:seed`
|
|
|
|
### پذیرش مرحله 2
|
|
|
|
- [x] اجرای `pnpm install` بدون خطا.
|
|
- [x] اجرای `pnpm lint` حداقل بدون خطای ساختاری.
|
|
- [x] همه پوشهها و README ساخته شده باشند.
|
|
|
|
---
|
|
|
|
## 3. انتخاب stack و bootstrapping
|
|
|
|
### 3.1 Frontend
|
|
|
|
در `web/apps/web` بساز:
|
|
|
|
- [ ] Next.js + TypeScript
|
|
- [ ] App Router
|
|
- [ ] Tailwind CSS
|
|
- [ ] ESLint
|
|
- [ ] Prettier
|
|
- [ ] RTL support
|
|
- [ ] Dark-first design
|
|
- [ ] Component پایه داخل `packages/ui`
|
|
|
|
صفحات اولیه:
|
|
|
|
- [ ] `/login`
|
|
- [ ] `/signup`
|
|
- [ ] `/onboarding`
|
|
- [ ] `/dashboard`
|
|
- [ ] `/workforce`
|
|
- [ ] `/manager`
|
|
- [ ] `/tasks`
|
|
- [ ] `/projects`
|
|
- [ ] `/knowledge`
|
|
- [ ] `/billing`
|
|
- [ ] `/settings`
|
|
- [ ] `/admin`
|
|
|
|
### 3.2 Backend API
|
|
|
|
در `web/apps/api` بساز:
|
|
|
|
- [ ] Python FastAPI
|
|
- [ ] SQLAlchemy 2.x
|
|
- [ ] Alembic
|
|
- [ ] Pydantic v2
|
|
- [ ] JWT/session auth
|
|
- [ ] pytest
|
|
- [ ] ruff
|
|
- [ ] mypy یا pyright اگر ساده بود
|
|
|
|
ساختار backend:
|
|
|
|
```text
|
|
apps/api/app/
|
|
main.py
|
|
core/
|
|
config.py
|
|
security.py
|
|
database.py
|
|
errors.py
|
|
domain/
|
|
identity/
|
|
billing/
|
|
ai_control/
|
|
workforce/
|
|
sandbox/
|
|
knowledge/
|
|
audit/
|
|
projects/
|
|
platform/
|
|
application/
|
|
infrastructure/
|
|
interfaces/
|
|
http/
|
|
```
|
|
|
|
### 3.3 دیتابیس و Redis
|
|
|
|
- [ ] در `infra/docker/docker-compose.yml` سرویسهای زیر را بساز:
|
|
- postgres
|
|
- redis
|
|
- api
|
|
- web
|
|
- [ ] env نمونه بساز: `web/.env.example`
|
|
- [ ] secret واقعی داخل repo نگذار.
|
|
|
|
### پذیرش مرحله 3
|
|
|
|
- [x] `docker compose` از داخل `web/infra/docker` بالا بیاید.
|
|
- [x] API health endpoint داشته باشد: `GET /health`.
|
|
- [x] frontend صفحه dashboard خالی اما قابل مشاهده داشته باشد.
|
|
|
|
---
|
|
|
|
## 4. معماری و قراردادهای مشترک
|
|
|
|
### 4.1 اصول معماری
|
|
|
|
- [ ] معماری backend باید Clean/Hexagonal باشد.
|
|
- [ ] domain layer هیچ dependency به FastAPI، SQLAlchemy، Redis، provider خارجی یا HTTP نداشته باشد.
|
|
- [ ] application layer use caseها را اجرا کند.
|
|
- [ ] infrastructure layer adapterها را پیادهسازی کند.
|
|
- [ ] interface/http فقط route و request/response schema داشته باشد.
|
|
|
|
### 4.2 Ports الزامی
|
|
|
|
این interfaceها را تعریف کن:
|
|
|
|
- [ ] `ModelProviderPort`
|
|
- [ ] `PaymentProviderPort`
|
|
- [ ] `SandboxProviderPort`
|
|
- [ ] `GitProviderPort`
|
|
- [ ] `DomainRouterPort`
|
|
- [ ] `StoragePort`
|
|
- [ ] `VectorStorePort`
|
|
- [ ] `NotificationPort`
|
|
- [ ] `AuditPort`
|
|
- [ ] `UsageLedgerPort`
|
|
|
|
### 4.3 Adapterهای اولیه
|
|
|
|
- [ ] `MockModelProviderAdapter` برای dev/test.
|
|
- [ ] `OpenAICompatibleModelAdapter` با base_url و api_key سمت سرور.
|
|
- [ ] `LocalMockPaymentAdapter`.
|
|
- [ ] `LocalMockSandboxAdapter`.
|
|
- [ ] `GiteaGitAdapter`.
|
|
- [ ] `CaddyDomainRouterAdapter` یا `ManagedDomainRouterAdapter`.
|
|
|
|
### پذیرش مرحله 4
|
|
|
|
- [x] تست واحد نشان دهد domain بدون دیتابیس و FastAPI اجرا میشود.
|
|
- [x] adapterها با mock قابل جایگزینی باشند.
|
|
|
|
---
|
|
|
|
## 5. Identity، Auth و Multi-Tenancy
|
|
|
|
### 5.1 مدلها
|
|
|
|
جدولها:
|
|
|
|
- [ ] `users`
|
|
- `id`
|
|
- `email`
|
|
- `password_hash`
|
|
- `name`
|
|
- `avatar_url`
|
|
- `is_platform_owner`
|
|
- `created_at`
|
|
- `updated_at`
|
|
- [ ] `organizations`
|
|
- `id`
|
|
- `name`
|
|
- `slug`
|
|
- `owner_user_id`
|
|
- `created_at`
|
|
- [ ] `memberships`
|
|
- `id`
|
|
- `organization_id`
|
|
- `user_id`
|
|
- `role`
|
|
- `status`
|
|
- `created_at`
|
|
- [ ] `invites`
|
|
- `id`
|
|
- `organization_id`
|
|
- `email`
|
|
- `role`
|
|
- `token_hash`
|
|
- `expires_at`
|
|
- `accepted_at`
|
|
|
|
### 5.2 APIها
|
|
|
|
- [ ] `POST /auth/signup`
|
|
- [ ] `POST /auth/login`
|
|
- [ ] `POST /auth/logout`
|
|
- [ ] `GET /auth/me`
|
|
- [ ] `POST /organizations`
|
|
- [ ] `GET /organizations`
|
|
- [ ] `GET /organizations/{org_id}`
|
|
- [ ] `POST /organizations/{org_id}/invites`
|
|
- [ ] `GET /organizations/{org_id}/members`
|
|
- [ ] `PATCH /organizations/{org_id}/members/{member_id}`
|
|
|
|
### 5.3 قوانین امنیتی
|
|
|
|
- [ ] هر request باید user فعلی را resolve کند.
|
|
- [ ] هر endpoint سازمانی باید membership را چک کند.
|
|
- [ ] roleهای اولیه:
|
|
- `owner`
|
|
- `admin`
|
|
- `manager`
|
|
- `member`
|
|
- `viewer`
|
|
- [ ] platform owner فقط برای admin console دسترسی بالاتر دارد؛ نباید خودکار وارد داده خصوصی سازمان شود مگر برای support با audit.
|
|
|
|
### 5.4 UIها
|
|
|
|
- [ ] signup/login فارسی.
|
|
- [ ] onboarding ساخت اولین سازمان.
|
|
- [ ] organization switcher.
|
|
- [ ] صفحه members و invite.
|
|
|
|
### پذیرش مرحله 5
|
|
|
|
- [x] کاربر جدید ثبتنام کند.
|
|
- [x] سازمان بسازد.
|
|
- [x] کاربر دوم را invite کند.
|
|
- [x] کاربر بدون membership نتواند داده سازمان را ببیند.
|
|
- [x] تست API برای tenant isolation نوشته شود.
|
|
|
|
---
|
|
|
|
## 6. Admin Console برای مالک سامانه
|
|
|
|
### 6.1 AI Provider Management
|
|
|
|
جدولها:
|
|
|
|
- [ ] `ai_providers`
|
|
- `id`
|
|
- `name`
|
|
- `type`
|
|
- `base_url`
|
|
- `is_active`
|
|
- `created_at`
|
|
- [ ] `ai_model_credentials`
|
|
- `id`
|
|
- `provider_id`
|
|
- `name`
|
|
- `encrypted_api_key`
|
|
- `is_active`
|
|
- `created_at`
|
|
- [ ] `ai_models`
|
|
- `id`
|
|
- `provider_id`
|
|
- `internal_name`
|
|
- `display_name_for_admin`
|
|
- `capabilities`
|
|
- `input_price_per_1m`
|
|
- `output_price_per_1m`
|
|
- `is_active`
|
|
|
|
نکته:
|
|
|
|
- [ ] کاربر عادی هیچوقت `internal_name`, `provider`, `base_url`, `api_key` یا قیمت خام provider را نبیند.
|
|
|
|
### 6.2 Routing Policy
|
|
|
|
جدول:
|
|
|
|
- [ ] `routing_policies`
|
|
- `id`
|
|
- `name`
|
|
- `description`
|
|
- `mode`: `fast`, `cheap`, `balanced`, `reasoning`, `vision`, `coding`
|
|
- `fallback_policy_json`
|
|
- `budget_limits_json`
|
|
- `is_default`
|
|
|
|
### 6.3 Rate Card
|
|
|
|
جدول:
|
|
|
|
- [ ] `rate_cards`
|
|
- `id`
|
|
- `name`
|
|
- `unit`
|
|
- `customer_price`
|
|
- `internal_cost_estimate`
|
|
- `is_active`
|
|
|
|
واحدها:
|
|
|
|
- [ ] `model_input_tokens`
|
|
- [ ] `model_output_tokens`
|
|
- [ ] `sandbox_cpu_second`
|
|
- [ ] `sandbox_memory_gb_second`
|
|
- [ ] `storage_gb_day`
|
|
- [ ] `tool_call`
|
|
- [ ] `premium_employee_run`
|
|
|
|
### 6.4 UI admin
|
|
|
|
- [ ] `/admin/providers`
|
|
- [ ] `/admin/models`
|
|
- [ ] `/admin/routing`
|
|
- [ ] `/admin/rate-cards`
|
|
- [ ] `/admin/organizations`
|
|
- [ ] `/admin/usage`
|
|
|
|
### پذیرش مرحله 6
|
|
|
|
- [x] platform owner بتواند provider بسازد.
|
|
- [x] platform owner بتواند model بسازد.
|
|
- [x] platform owner بتواند routing policy پیشفرض بسازد.
|
|
- [x] user عادی نتواند هیچ اطلاعات provider/model خام ببیند.
|
|
|
|
---
|
|
|
|
## 7. Projects، Git و Repo برای همه کاربران
|
|
|
|
این بخش بسیار مهم است چون سیستم فعلی Git دارد و در نسخه وب همه سازمانها/کاربران باید بتوانند از Git استفاده کنند.
|
|
|
|
### 7.1 مدل پروژه
|
|
|
|
جدولها:
|
|
|
|
- [ ] `projects`
|
|
- `id`
|
|
- `organization_id`
|
|
- `name`
|
|
- `slug`
|
|
- `description`
|
|
- `created_by_user_id`
|
|
- `default_branch`
|
|
- `created_at`
|
|
- [ ] `project_repositories`
|
|
- `id`
|
|
- `project_id`
|
|
- `provider`: `gitea`
|
|
- `owner`
|
|
- `repo_name`
|
|
- `clone_url`
|
|
- `web_url`
|
|
- `default_branch`
|
|
- `created_at`
|
|
- [ ] `project_git_credentials`
|
|
- `id`
|
|
- `project_id`
|
|
- `username`
|
|
- `encrypted_password`
|
|
- `created_at`
|
|
|
|
### 7.2 GitProviderPort
|
|
|
|
تعریف کن:
|
|
|
|
```python
|
|
class GitProviderPort:
|
|
async def ensure_project_repo(project) -> RepoInfo: ...
|
|
async def create_branch(project_id, branch_name, from_branch) -> BranchInfo: ...
|
|
async def commit_files(project_id, branch_name, files, message) -> CommitInfo: ...
|
|
async def open_pull_request(project_id, head, base, title, body) -> PullRequestInfo: ...
|
|
async def merge_pull_request(project_id, pr_number) -> MergeResult: ...
|
|
async def get_repo_status(project_id) -> RepoStatus: ...
|
|
```
|
|
|
|
### 7.3 Gitea adapter
|
|
|
|
- [ ] adapter جدید داخل `web/apps/api/app/infrastructure/git/gitea_adapter.py` بساز.
|
|
- [ ] از `git_manager.py` و `gitea_api.py` فقط به عنوان reference استفاده کن.
|
|
- [ ] admin token فقط سمت backend باشد.
|
|
- [ ] repoها private باشند.
|
|
- [ ] نام repo collision-free باشد: بهتر است `orgslug-projectslug-shortid`.
|
|
- [ ] credential هر پروژه encrypted ذخیره شود.
|
|
- [ ] token/password هیچوقت به frontend خام داده نشود مگر برای clone URL موقت و فقط اگر واقعاً لازم شد.
|
|
|
|
### 7.4 APIها
|
|
|
|
- [ ] `POST /organizations/{org_id}/projects`
|
|
- [ ] `GET /organizations/{org_id}/projects`
|
|
- [ ] `GET /organizations/{org_id}/projects/{project_id}`
|
|
- [ ] `POST /organizations/{org_id}/projects/{project_id}/repo/ensure`
|
|
- [ ] `GET /organizations/{org_id}/projects/{project_id}/repo`
|
|
- [ ] `POST /organizations/{org_id}/projects/{project_id}/repo/branches`
|
|
- [ ] `POST /organizations/{org_id}/projects/{project_id}/repo/pull-requests`
|
|
|
|
### 7.5 UIها
|
|
|
|
- [ ] صفحه projects.
|
|
- [ ] ساخت project.
|
|
- [ ] نمایش repo status.
|
|
- [ ] دکمه ساخت repo.
|
|
- [ ] لینک باز کردن Gitea web_url.
|
|
- [ ] نمایش branchها و PRهای باز.
|
|
|
|
### پذیرش مرحله 7
|
|
|
|
- [x] هر سازمان بتواند پروژه بسازد.
|
|
- [x] هر پروژه بتواند repo خصوصی Gitea بگیرد.
|
|
- [x] کاربر عضو سازمان A نتواند repo سازمان B را ببیند یا ایجاد کند.
|
|
- [x] platform owner بتواند همه repoها را در admin view ببیند.
|
|
- [x] هیچ token در response خام برنگردد.
|
|
|
|
---
|
|
|
|
## 8. Domain Routing و Preview Domain برای همه پروژهها
|
|
|
|
این بخش هم حیاتی است چون سیستم فعلی route دامنه تست دارد و نسخه وب باید آن را عمومی، امن و ساده کند.
|
|
|
|
### 8.1 مدلها
|
|
|
|
جدولها:
|
|
|
|
- [ ] `preview_ports`
|
|
- `id`
|
|
- `organization_id`
|
|
- `project_id`
|
|
- `service_name`
|
|
- `port`
|
|
- `status`
|
|
- `created_at`
|
|
- [ ] `preview_domains`
|
|
- `id`
|
|
- `organization_id`
|
|
- `project_id`
|
|
- `host`
|
|
- `port`
|
|
- `status`: `active`, `disabled`, `failed`
|
|
- `protected`
|
|
- `created_by_user_id`
|
|
- `created_at`
|
|
|
|
### 8.2 DomainRouterPort
|
|
|
|
تعریف کن:
|
|
|
|
```python
|
|
class DomainRouterPort:
|
|
async def allocate_port(org_id, project_id, service_name) -> int: ...
|
|
async def claim_preview_domain(org_id, project_id, requested_subdomain, port) -> PreviewDomain: ...
|
|
async def configure_reverse_proxy(host, port) -> ReverseProxyResult: ...
|
|
async def remove_preview_domain(domain_id) -> None: ...
|
|
async def list_project_domains(project_id) -> list[PreviewDomain]: ...
|
|
```
|
|
|
|
### 8.3 قوانین امنیتی دامنه
|
|
|
|
- [ ] فقط subdomainهای تکlabel زیر `msa.artacloud.ir` مجاز باشند مگر بعداً custom domain رسمی اضافه شود.
|
|
- [ ] label فقط شامل `a-z`, `0-9`, `-` باشد.
|
|
- [ ] label بین 3 تا 40 کاراکتر باشد.
|
|
- [ ] host collision ممنوع است.
|
|
- [ ] هر host دقیقاً یک owner داشته باشد.
|
|
- [ ] هیچ سازمانی نتواند دامنه سازمان دیگر را حذف یا hijack کند.
|
|
- [ ] port فقط از range امن داده شود.
|
|
- [ ] target reverse proxy فقط localhost/127.0.0.1 باشد.
|
|
- [ ] قبل از reload، Caddy config validate شود.
|
|
- [ ] protected domains فقط توسط platform owner قابل تغییر باشند.
|
|
|
|
### 8.4 Port allocation
|
|
|
|
از منطق فعلی reference بگیر:
|
|
|
|
- [ ] range پیشفرض: `8080-8999`
|
|
- [ ] protected ports را رزرو کن.
|
|
- [ ] اگر snapshot listening ports ممکن نبود، port allocate نکن.
|
|
- [ ] در concurrent allocation، retry داشته باش.
|
|
|
|
### 8.5 APIها
|
|
|
|
- [ ] `POST /organizations/{org_id}/projects/{project_id}/preview/ports`
|
|
- [ ] `POST /organizations/{org_id}/projects/{project_id}/preview/domains`
|
|
- [ ] `GET /organizations/{org_id}/projects/{project_id}/preview/domains`
|
|
- [ ] `DELETE /organizations/{org_id}/projects/{project_id}/preview/domains/{domain_id}`
|
|
|
|
### 8.6 UIها
|
|
|
|
- [ ] در صفحه project یک tab به نام `پیشنمایش و دامنه تست` بساز.
|
|
- [ ] دکمه `ساخت دامنه تست`.
|
|
- [ ] input برای subdomain پیشنهادی.
|
|
- [ ] نمایش URL نهایی مثل `https://my-app.msa.artacloud.ir`.
|
|
- [ ] وضعیت active/failed.
|
|
- [ ] دکمه حذف با confirmation.
|
|
|
|
### پذیرش مرحله 8
|
|
|
|
- [x] کاربر عضو سازمان بتواند برای project خودش دامنه تست بسازد.
|
|
- [x] دامنه روی Caddy route شود.
|
|
- [x] دامنه تکراری خطای واضح بدهد.
|
|
- [x] کاربر نتواند دامنه پروژه دیگر را حذف کند.
|
|
- [x] route به protected port ممنوع باشد.
|
|
- [x] همه عملیات audit شوند.
|
|
|
|
---
|
|
|
|
## 9. Sandbox Gateway و محیط ایزوله
|
|
|
|
### 9.1 اصل مهم
|
|
|
|
- [ ] هیچ کدی از کاربر یا AI worker روی host اصلی اجرا نشود.
|
|
- [ ] Sandbox Gateway تنها مسیر اجرای command، build، test، preview و app runtime باشد.
|
|
|
|
### 9.2 مدلها
|
|
|
|
- [ ] `sandbox_templates`
|
|
- [ ] `workspaces`
|
|
- [ ] `sandbox_sessions`
|
|
- [ ] `command_runs`
|
|
- [ ] `snapshots`
|
|
- [ ] `preview_urls`
|
|
- [ ] `sandbox_resource_limits`
|
|
|
|
فیلدهای مهم `workspaces`:
|
|
|
|
- `id`
|
|
- `organization_id`
|
|
- `project_id`
|
|
- `template_id`
|
|
- `provider`
|
|
- `external_workspace_id`
|
|
- `status`
|
|
- `created_at`
|
|
|
|
فیلدهای مهم `sandbox_sessions`:
|
|
|
|
- `id`
|
|
- `workspace_id`
|
|
- `external_session_id`
|
|
- `status`
|
|
- `started_at`
|
|
- `stopped_at`
|
|
- `last_active_at`
|
|
|
|
### 9.3 SandboxProviderPort
|
|
|
|
```python
|
|
class SandboxProviderPort:
|
|
async def create_workspace(project_id, template_id) -> WorkspaceInfo: ...
|
|
async def start_session(workspace_id) -> SessionInfo: ...
|
|
async def run_command(session_id, command, timeout_seconds, env=None) -> CommandResult: ...
|
|
async def read_file(session_id, path) -> str: ...
|
|
async def write_file(session_id, path, content) -> None: ...
|
|
async def snapshot(session_id, name) -> SnapshotInfo: ...
|
|
async def pause(session_id) -> None: ...
|
|
async def resume(session_id) -> SessionInfo: ...
|
|
async def destroy(session_id) -> None: ...
|
|
async def get_preview_url(session_id, port) -> str: ...
|
|
```
|
|
|
|
### 9.4 MVP adapter
|
|
|
|
- [ ] اول `LocalMockSandboxAdapter` بساز که command واقعی اجرا نکند، فقط fake result بدهد.
|
|
- [ ] سپس adapter واقعی برای Daytona یا E2B بساز؛ اگر credential نداریم، adapter را feature-flag کن.
|
|
- [ ] انتخاب provider از env باشد:
|
|
- `SANDBOX_PROVIDER=mock|daytona|e2b`
|
|
|
|
### 9.5 محدودیتها
|
|
|
|
- [ ] timeout برای هر command الزامی.
|
|
- [ ] max output size الزامی.
|
|
- [ ] max CPU/RAM/DISK در policy ذخیره شود.
|
|
- [ ] egress network در طراحی deny-by-default باشد، حتی اگر در MVP mock است.
|
|
- [ ] secretها فقط از Secret Broker تزریق شوند.
|
|
|
|
### 9.6 اتصال به preview domain
|
|
|
|
- [ ] وقتی sandbox app روی port داخلی اجرا شد، backend بتواند از DomainRouterPort دامنه تست بگیرد.
|
|
- [ ] mapping باید به session/project وصل باشد.
|
|
- [ ] اگر sandbox stop شد، UI باید هشدار بدهد که preview ممکن است offline باشد.
|
|
|
|
### پذیرش مرحله 9
|
|
|
|
- [x] project بتواند workspace sandbox بسازد.
|
|
- [x] command mock یا واقعی اجرا شود.
|
|
- [x] command result در UI دیده شود.
|
|
- [x] usage event برای sandbox runtime/command ثبت شود.
|
|
- [x] هیچ مسیر API برای اجرای مستقیم shell host وجود نداشته باشد.
|
|
|
|
---
|
|
|
|
## 10. AI Workforce و کارمندان هوش مصنوعی
|
|
|
|
### 10.1 مدلها
|
|
|
|
- [ ] `agent_templates`
|
|
- `id`
|
|
- `name`
|
|
- `role_key`
|
|
- `description`
|
|
- `default_prompt`
|
|
- `default_tools_json`
|
|
- `default_routing_policy_id`
|
|
- `is_system`
|
|
- [ ] `employees`
|
|
- `id`
|
|
- `organization_id`
|
|
- `project_id` nullable
|
|
- `template_id`
|
|
- `name`
|
|
- `role_key`
|
|
- `status`
|
|
- `routing_policy_id`
|
|
- `budget_limit_json`
|
|
- `created_at`
|
|
- [ ] `prompt_versions`
|
|
- `id`
|
|
- `employee_id`
|
|
- `version`
|
|
- `content`
|
|
- `created_by_user_id`
|
|
- `created_at`
|
|
- [ ] `employee_tool_permissions`
|
|
- `employee_id`
|
|
- `tool_key`
|
|
- `allowed`
|
|
- `policy_json`
|
|
|
|
### 10.2 templateهای اولیه
|
|
|
|
بساز:
|
|
|
|
- [ ] مدیر سازمان / Manager
|
|
- [ ] تحلیلگر و معمار / Planner
|
|
- [ ] برنامهنویس / Developer
|
|
- [ ] بازبین کد / Reviewer
|
|
- [ ] تستر / Tester
|
|
- [ ] محقق / Researcher
|
|
- [ ] تولیدکننده محتوا / Content Creator
|
|
- [ ] پشتیبان مشتری / Support Agent
|
|
|
|
### 10.3 APIها
|
|
|
|
- [ ] `GET /organizations/{org_id}/agent-templates`
|
|
- [ ] `POST /organizations/{org_id}/employees`
|
|
- [ ] `GET /organizations/{org_id}/employees`
|
|
- [ ] `GET /organizations/{org_id}/employees/{employee_id}`
|
|
- [ ] `PATCH /organizations/{org_id}/employees/{employee_id}`
|
|
- [ ] `POST /organizations/{org_id}/employees/{employee_id}/prompt-versions`
|
|
|
|
### 10.4 UIها
|
|
|
|
- [ ] صفحه `AI Workforce`.
|
|
- [ ] کارت هر کارمند:
|
|
- نام
|
|
- نقش
|
|
- وضعیت
|
|
- taskهای فعال
|
|
- مصرف امروز
|
|
- دکمه تنظیمات
|
|
- [ ] wizard ساخت کارمند از template.
|
|
- [ ] صفحه جزئیات کارمند.
|
|
|
|
### پذیرش مرحله 10
|
|
|
|
- [x] سازمان بتواند کارمند AI بسازد.
|
|
- [x] کارمند به routing policy وصل باشد اما user مدل خام نبیند.
|
|
- [x] prompt version ثبت شود.
|
|
- [x] فقط admin/manager بتواند کارمند را تغییر دهد.
|
|
|
|
---
|
|
|
|
## 11. Manager Chat، Thread، Task و Run Engine
|
|
|
|
### 11.1 مدلها
|
|
|
|
- [ ] `threads`
|
|
- [ ] `messages`
|
|
- [ ] `tasks`
|
|
- [ ] `runs`
|
|
- [ ] `run_steps`
|
|
- [ ] `tool_calls`
|
|
- [ ] `artifacts`
|
|
|
|
وضعیتهای task:
|
|
|
|
- `new`
|
|
- `triaged`
|
|
- `waiting_approval`
|
|
- `running`
|
|
- `done`
|
|
- `failed`
|
|
- `cancelled`
|
|
|
|
وضعیتهای run:
|
|
|
|
- `queued`
|
|
- `planning`
|
|
- `waiting_approval`
|
|
- `running`
|
|
- `tool_calling`
|
|
- `sandbox_running`
|
|
- `completed`
|
|
- `failed`
|
|
- `cancelled`
|
|
- `timed_out`
|
|
|
|
### 11.2 APIها
|
|
|
|
- [ ] `POST /organizations/{org_id}/threads`
|
|
- [ ] `GET /organizations/{org_id}/threads`
|
|
- [ ] `GET /organizations/{org_id}/threads/{thread_id}`
|
|
- [ ] `POST /organizations/{org_id}/threads/{thread_id}/messages`
|
|
- [ ] `POST /organizations/{org_id}/tasks`
|
|
- [ ] `GET /organizations/{org_id}/tasks`
|
|
- [ ] `GET /organizations/{org_id}/tasks/{task_id}`
|
|
- [ ] `POST /organizations/{org_id}/tasks/{task_id}/runs`
|
|
- [ ] `GET /organizations/{org_id}/runs/{run_id}`
|
|
- [ ] `POST /organizations/{org_id}/runs/{run_id}/cancel`
|
|
|
|
### 11.3 اجرای AI
|
|
|
|
- [ ] برای MVP، Manager Chat با `MockModelProviderAdapter` پاسخ قابل پیشبینی بدهد.
|
|
- [ ] سپس `OpenAICompatibleModelAdapter` وصل شود.
|
|
- [ ] model routing فقط سمت backend انجام شود.
|
|
- [ ] هر model call باید usage event بسازد.
|
|
- [ ] tool callها در `tool_calls` ثبت شوند.
|
|
- [ ] run_steps timeline بسازد.
|
|
|
|
### 11.4 UI Manager
|
|
|
|
- [ ] صفحه `/manager` split-view داشته باشد:
|
|
- ستون chat
|
|
- ستون task/artifacts
|
|
- ستون کوچک run timeline یا logs
|
|
- [ ] پیامها realtime یا polling سبک داشته باشند.
|
|
- [ ] اگر task ساخته شد، card task نشان بده.
|
|
- [ ] اگر run در حال اجراست، status واضح نشان بده.
|
|
|
|
### پذیرش مرحله 11
|
|
|
|
- [x] کاربر با Manager Chat پیام بفرستد.
|
|
- [x] Manager بتواند task بسازد یا پیشنهاد task بدهد.
|
|
- [x] task run شود.
|
|
- [x] run_steps و usage_events ثبت شود.
|
|
- [x] UI خروجی و artifact را نشان دهد.
|
|
|
|
---
|
|
|
|
## 12. Tools و دسترسی کارمندها
|
|
|
|
### 12.1 tool registry
|
|
|
|
Toolهای اولیه:
|
|
|
|
- [ ] `git.ensure_repo`
|
|
- [ ] `git.create_branch`
|
|
- [ ] `git.open_pr`
|
|
- [ ] `domain.create_preview`
|
|
- [ ] `sandbox.run_command`
|
|
- [ ] `sandbox.read_file`
|
|
- [ ] `sandbox.write_file`
|
|
- [ ] `knowledge.search`
|
|
- [ ] `artifact.create`
|
|
|
|
### 12.2 قوانین toolها
|
|
|
|
- [ ] هر tool باید permission check داشته باشد.
|
|
- [ ] هر tool call باید audit و trace شود.
|
|
- [ ] toolهای خطرناک approval بخواهند:
|
|
- حذف repo
|
|
- حذف دامنه
|
|
- merge PR
|
|
- اجرای command با دسترسی بالا
|
|
- حذف فایل
|
|
- destroy sandbox
|
|
|
|
### 12.3 UI approvals
|
|
|
|
- [ ] صفحه task باید actionهای منتظر approval را نشان دهد.
|
|
- [ ] approve/reject با توضیح ثبت شود.
|
|
|
|
### پذیرش مرحله 12
|
|
|
|
- [x] کارمند بدون permission نتواند tool را اجرا کند.
|
|
- [x] approval flow برای tool خطرناک کار کند.
|
|
- [x] audit log کامل ثبت شود.
|
|
|
|
---
|
|
|
|
## 13. Billing و Usage Ledger
|
|
|
|
### 13.1 مدلها
|
|
|
|
- [ ] `plans`
|
|
- [ ] `subscriptions`
|
|
- [ ] `credit_wallets`
|
|
- [ ] `usage_events`
|
|
- [ ] `invoices`
|
|
- [ ] `payments`
|
|
|
|
فیلدهای `usage_events`:
|
|
|
|
- `id`
|
|
- `organization_id`
|
|
- `project_id` nullable
|
|
- `user_id` nullable
|
|
- `employee_id` nullable
|
|
- `run_id` nullable
|
|
- `unit`
|
|
- `quantity`
|
|
- `unit_price`
|
|
- `internal_cost_estimate`
|
|
- `total_price`
|
|
- `metadata_json`
|
|
- `created_at`
|
|
|
|
### 13.2 قوانین billing
|
|
|
|
- [ ] هر مصرف باید اول در ledger داخلی ثبت شود.
|
|
- [ ] Stripe یا payment provider فقط adapter است؛ منبع حقیقت usage ledger داخلی است.
|
|
- [ ] اگر wallet اعتبار کافی نداشت، run جدید متوقف یا نیازمند پرداخت شود.
|
|
- [ ] platform owner بتواند credit دستی اضافه کند.
|
|
|
|
### 13.3 APIها
|
|
|
|
- [ ] `GET /organizations/{org_id}/billing/summary`
|
|
- [ ] `GET /organizations/{org_id}/billing/usage-events`
|
|
- [ ] `GET /organizations/{org_id}/billing/invoices`
|
|
- [ ] `POST /organizations/{org_id}/billing/add-credit` فقط admin/platform owner طبق policy
|
|
- [ ] `POST /organizations/{org_id}/billing/checkout` در صورت اتصال payment واقعی
|
|
|
|
### 13.4 UI Billing
|
|
|
|
- [ ] موجودی اعتبار.
|
|
- [ ] مصرف امروز/ماه.
|
|
- [ ] breakdown بر اساس employee/project/unit.
|
|
- [ ] invoice list.
|
|
- [ ] هشدار اعتبار کم.
|
|
|
|
### پذیرش مرحله 13
|
|
|
|
- [x] هر model call usage بسازد.
|
|
- [x] هر sandbox command usage بسازد.
|
|
- [x] billing summary درست جمع بزند.
|
|
- [x] کاربر عادی فقط billing سازمان خودش را ببیند.
|
|
|
|
---
|
|
|
|
## 14. Knowledge Base
|
|
|
|
### 14.1 مدلها
|
|
|
|
- [ ] `knowledge_sources`
|
|
- [ ] `documents`
|
|
- [ ] `document_chunks`
|
|
- [ ] `embedding_jobs`
|
|
- [ ] `retrieval_policies`
|
|
|
|
### 14.2 MVP
|
|
|
|
- [ ] upload فایل متنی/markdown/pdf اگر ساده بود.
|
|
- [ ] extract text.
|
|
- [ ] chunk.
|
|
- [ ] embedding با adapter قابل mock.
|
|
- [ ] search ساده keyword در MVP اگر vector آماده نبود.
|
|
|
|
### 14.3 permissions
|
|
|
|
- [ ] هر knowledge source به organization وصل باشد.
|
|
- [ ] optionally به project وصل باشد.
|
|
- [ ] employee فقط knowledge مجاز خودش را ببیند.
|
|
|
|
### پذیرش مرحله 14
|
|
|
|
- [x] کاربر فایل knowledge اضافه کند.
|
|
- [x] Manager در پاسخ بتواند از knowledge استفاده کند.
|
|
- [x] سازمان دیگر به این knowledge دسترسی نداشته باشد.
|
|
|
|
---
|
|
|
|
## 15. Observability، Audit و Trace
|
|
|
|
### 15.1 مدلها
|
|
|
|
- [ ] `audit_events`
|
|
- [ ] `traces`
|
|
- [ ] `spans`
|
|
- [ ] `error_events`
|
|
- [ ] `quality_metrics`
|
|
|
|
### 15.2 audit الزامی برای
|
|
|
|
- [ ] login/logout
|
|
- [ ] ساخت/حذف سازمان
|
|
- [ ] invite و تغییر role
|
|
- [ ] ساخت/تغییر employee
|
|
- [ ] ساخت/حذف repo
|
|
- [ ] ساخت/حذف preview domain
|
|
- [ ] sandbox command
|
|
- [ ] approval/rejection
|
|
- [ ] billing credit/payment
|
|
- [ ] تغییر provider/model/routing
|
|
|
|
### 15.3 UI
|
|
|
|
- [ ] صفحه audit در settings سازمان.
|
|
- [ ] صفحه traces در admin یا task detail.
|
|
- [ ] timeline run در task detail.
|
|
|
|
### پذیرش مرحله 15
|
|
|
|
- [x] هر عملیات حساس audit شود.
|
|
- [x] trace یک run از ابتدا تا انتها قابل مشاهده باشد.
|
|
|
|
---
|
|
|
|
## 16. UI/UX کامل
|
|
|
|
### 16.1 Design System
|
|
|
|
- [ ] رنگبندی dark حرفهای.
|
|
- [ ] RTL کامل.
|
|
- [ ] فونت مناسب فارسی.
|
|
- [ ] componentها:
|
|
- Button
|
|
- Card
|
|
- Badge
|
|
- Modal
|
|
- Drawer
|
|
- Table
|
|
- Tabs
|
|
- Toast
|
|
- EmptyState
|
|
- LoadingState
|
|
- ErrorState
|
|
- ConfirmDialog
|
|
- Timeline
|
|
- UsageBar
|
|
- EmployeeCard
|
|
- TaskCard
|
|
- ArtifactViewer
|
|
|
|
### 16.2 Layout اصلی
|
|
|
|
- [ ] sidebar:
|
|
- داشبورد
|
|
- مدیر AI
|
|
- نیروی کار AI
|
|
- پروژهها
|
|
- وظایف
|
|
- دانش سازمانی
|
|
- مصرف و پرداخت
|
|
- تنظیمات
|
|
- [ ] topbar:
|
|
- organization switcher
|
|
- command/search
|
|
- user menu
|
|
- credit badge
|
|
|
|
### 16.3 صفحات
|
|
|
|
- [ ] Dashboard
|
|
- خلاصه مصرف
|
|
- taskهای فعال
|
|
- کارمندهای فعال
|
|
- خطاهای اخیر
|
|
- preview domains
|
|
- [ ] Workforce
|
|
- [ ] Manager Chat
|
|
- [ ] Tasks
|
|
- [ ] Project detail
|
|
- Overview
|
|
- Git
|
|
- Sandbox
|
|
- Preview Domain
|
|
- Artifacts
|
|
- [ ] Billing
|
|
- [ ] Knowledge
|
|
- [ ] Settings
|
|
- [ ] Admin Console
|
|
|
|
### پذیرش مرحله 16
|
|
|
|
- [x] UI در desktop خوب باشد.
|
|
- [x] RTL کامل باشد.
|
|
- [x] stateهای empty/loading/error وجود داشته باشد.
|
|
- [x] user عادی هیچ عبارت provider/model خام نبیند.
|
|
|
|
---
|
|
|
|
## 17. Seed Data و Dev Experience
|
|
|
|
### 17.1 seed
|
|
|
|
- [ ] یک platform owner بساز.
|
|
- [ ] یک user عادی بساز.
|
|
- [ ] یک organization نمونه بساز.
|
|
- [ ] چند employee template بساز.
|
|
- [ ] routing policyهای نمونه بساز.
|
|
- [ ] rate card نمونه بساز.
|
|
- [ ] provider mock بساز.
|
|
|
|
### 17.2 dev commands
|
|
|
|
- [ ] `pnpm dev` frontend و backend را بالا بیاورد یا حداقل راهنمای واضح بدهد.
|
|
- [ ] `pnpm test` تستها را اجرا کند.
|
|
- [ ] `pnpm db:migrate` migrationها را اجرا کند.
|
|
- [ ] `pnpm db:seed` داده seed بسازد.
|
|
|
|
### پذیرش مرحله 17
|
|
|
|
- [x] توسعهدهنده جدید با README بتواند پروژه را بالا بیاورد.
|
|
- [x] seed loginها در README نوشته شده باشند، بدون secret واقعی production.
|
|
|
|
---
|
|
|
|
## 18. تستها
|
|
|
|
### 18.1 Backend tests
|
|
|
|
- [ ] auth signup/login.
|
|
- [ ] organization isolation.
|
|
- [ ] role permission.
|
|
- [ ] provider hidden from user.
|
|
- [ ] project creation.
|
|
- [ ] Gitea adapter mock.
|
|
- [ ] domain allocation collision.
|
|
- [ ] protected port/domain rejection.
|
|
- [ ] sandbox command mock.
|
|
- [ ] usage ledger aggregation.
|
|
- [ ] audit event creation.
|
|
- [ ] task/run lifecycle.
|
|
|
|
### 18.2 Frontend tests
|
|
|
|
- [ ] صفحات اصلی render شوند.
|
|
- [ ] organization switcher کار کند.
|
|
- [ ] dashboard empty state داشته باشد.
|
|
- [ ] manager chat message ارسال کند.
|
|
- [ ] project preview domain form validation داشته باشد.
|
|
|
|
### 18.3 E2E حداقلی
|
|
|
|
سناریو:
|
|
|
|
- [ ] signup
|
|
- [ ] create organization
|
|
- [ ] create project
|
|
- [ ] ensure repo
|
|
- [ ] create preview domain
|
|
- [ ] create employee
|
|
- [ ] send manager message
|
|
- [ ] create task
|
|
- [ ] run task
|
|
- [ ] see usage summary
|
|
|
|
### پذیرش مرحله 18
|
|
|
|
- [x] تستها در CI/local با یک دستور اجرا شوند.
|
|
- [x] تست multi-tenancy حتماً وجود داشته باشد.
|
|
|
|
---
|
|
|
|
## 19. امنیت
|
|
|
|
### 19.1 Secret Management
|
|
|
|
- [ ] API keys encrypted at rest.
|
|
- [ ] passwordها hash با argon2 یا bcrypt.
|
|
- [ ] JWT secret از env.
|
|
- [ ] frontend هیچ secret ندارد.
|
|
|
|
### 19.2 Access Control
|
|
|
|
- [ ] middleware مرکزی برای auth.
|
|
- [ ] dependency مرکزی برای org membership.
|
|
- [ ] policy object برای role/permission.
|
|
- [ ] تست منفی برای unauthorized/forbidden.
|
|
|
|
### 19.3 Sandbox Security
|
|
|
|
- [ ] host shell مستقیم ممنوع.
|
|
- [ ] command timeout.
|
|
- [ ] output limit.
|
|
- [ ] egress policy طراحی شود.
|
|
- [ ] audit برای command.
|
|
|
|
### 19.4 Domain/Git Security
|
|
|
|
- [ ] host injection ممنوع.
|
|
- [ ] Caddy target SSRF ممنوع.
|
|
- [ ] protected ports ممنوع.
|
|
- [ ] repo private.
|
|
- [ ] token never returned.
|
|
|
|
### پذیرش مرحله 19
|
|
|
|
- [x] security checklist داخل `web/docs/security-checklist.md` کامل شود.
|
|
- [x] تستهای امنیتی اصلی سبز باشند.
|
|
|
|
---
|
|
|
|
## 20. Performance
|
|
|
|
### 20.1 Frontend
|
|
|
|
- [ ] loading skeleton.
|
|
- [ ] pagination برای tables.
|
|
- [ ] caching با TanStack Query یا روش مشابه.
|
|
- [ ] bundle بیدلیل سنگین نشود.
|
|
|
|
### 20.2 Backend
|
|
|
|
- [ ] pagination در list endpoints.
|
|
- [ ] index روی `organization_id`, `project_id`, `created_at`.
|
|
- [ ] queryهای dashboard aggregate باشند.
|
|
- [ ] long-running taskها background worker بروند.
|
|
|
|
### 20.3 AI/Sandbox
|
|
|
|
- [ ] runها async باشند.
|
|
- [ ] timeout و retry کنترلشده.
|
|
- [ ] cancellation ممکن باشد.
|
|
|
|
### پذیرش مرحله 20
|
|
|
|
- [x] dashboard با seed data معمولی سریع load شود.
|
|
- [x] API listها pagination داشته باشند.
|
|
|
|
---
|
|
|
|
## 21. Migration از ذهنیت فعلی به نسخه وب
|
|
|
|
این migration دیتای production فعلی نیست؛ منظور تبدیل مفاهیم است.
|
|
|
|
### 21.1 Mapping مفاهیم
|
|
|
|
- Telegram user/chat_id → User
|
|
- allowed/admin user ids → platform owner و memberships
|
|
- project workspace → Project + Workspace + Repo
|
|
- bot inline menu → Web pages/components
|
|
- USER_INPUT_STATES → DB-backed wizard/form state
|
|
- AGY/OpenCode model selection → hidden AI Control Plane routing
|
|
- org manager/current organization → Organization + AI Manager Employee
|
|
- Caddy subdomain → PreviewDomain service
|
|
- Gitea repo → ProjectRepository service
|
|
|
|
### 21.2 ممنوعیتها
|
|
|
|
- [ ] `chat_id` در schema جدید استفاده نشود.
|
|
- [ ] Telegram auth در نسخه جدید استفاده نشود.
|
|
- [ ] callback_data در workflow جدید استفاده نشود.
|
|
|
|
---
|
|
|
|
## 22. ترتیب اجرای پیشنهادی برای DeepSeek
|
|
|
|
اگر عامل کدنویس نمیداند از کجا شروع کند، دقیقاً این ترتیب را اجرا کند:
|
|
|
|
1. [x] ساخت ساختار پوشه و README.
|
|
2. [x] bootstrap frontend و backend.
|
|
3. [x] docker compose برای postgres/redis.
|
|
4. [x] health endpoint و صفحه dashboard خالی.
|
|
5. [x] auth و organization.
|
|
6. [x] membership و RBAC.
|
|
7. [x] admin provider/model/routing/rate-card با mock.
|
|
8. [x] projects.
|
|
9. [x] GitProviderPort و Gitea adapter mock/real.
|
|
10. [x] DomainRouterPort و preview domain mock/real.
|
|
11. [x] Sandbox Gateway mock.
|
|
12. [x] AI Workforce templates و employees.
|
|
13. [x] Manager Chat mock.
|
|
14. [x] Task/Run engine.
|
|
15. [x] Usage ledger.
|
|
16. [x] Billing UI.
|
|
17. [x] Audit/Trace.
|
|
18. [x] Sandbox real adapter اگر credential موجود بود.
|
|
19. [x] UI polish.
|
|
20. [x] تست E2E.
|
|
|
|
---
|
|
|
|
## 23. Definition of Done نهایی
|
|
|
|
قبل از تحویل نهایی، این چکلیست باید کامل باشد:
|
|
|
|
- [x] `web/README.md` کامل است.
|
|
- [x] `web/docs/architecture/overview.md` کامل است.
|
|
- [x] `web/docs/security-checklist.md` کامل است.
|
|
- [x] frontend بالا میآید.
|
|
- [x] backend بالا میآید.
|
|
- [x] database migration اجرا میشود.
|
|
- [x] seed اجرا میشود.
|
|
- [x] کاربر ثبتنام میکند.
|
|
- [x] سازمان ساخته میشود.
|
|
- [x] عضویت و role کار میکند.
|
|
- [x] admin console provider/model/routing/rate-card دارد.
|
|
- [x] user مدل/provider خام نمیبیند.
|
|
- [x] پروژه ساخته میشود.
|
|
- [x] repo ساخته یا mock میشود.
|
|
- [x] preview domain ساخته یا mock میشود.
|
|
- [x] sandbox workspace ساخته یا mock میشود.
|
|
- [x] کارمند AI ساخته میشود.
|
|
- [x] Manager Chat کار میکند.
|
|
- [x] task ساخته و run میشود.
|
|
- [x] usage event ثبت میشود.
|
|
- [x] billing summary نشان داده میشود.
|
|
- [x] audit log نشان داده میشود.
|
|
- [x] تست multi-tenancy وجود دارد و سبز است.
|
|
- [x] تست domain security وجود دارد و سبز است.
|
|
- [x] تست git provider وجود دارد و سبز است.
|
|
- [x] تست usage ledger وجود دارد و سبز است.
|
|
- [x] `pnpm lint` موفق است.
|
|
- [x] `pnpm test` موفق است.
|
|
- [x] `pnpm build` موفق است.
|
|
|
|
---
|
|
|
|
## 24. یادداشت مهم درباره «کامل انجام بده»
|
|
|
|
اگر در زمان اجرا credential واقعی برای Gitea، Caddy، Daytona، E2B یا payment provider وجود نداشت:
|
|
|
|
- [ ] feature را حذف نکن.
|
|
- [ ] interface و UI و مدل دیتابیس را کامل بساز.
|
|
- [ ] adapter mock قابل تست بساز.
|
|
- [ ] adapter واقعی را پشت env flag آماده کن.
|
|
- [ ] در README دقیق بنویس برای فعالسازی واقعی چه envهایی لازم است.
|
|
|
|
یعنی خروجی باید از نظر محصول و معماری کامل باشد، حتی اگر بعضی providerهای خارجی در محیط dev با mock اجرا شوند.
|
|
|
|
---
|
|
|
|
## 25. envهای پیشنهادی
|
|
|
|
در `web/.env.example` این موارد را قرار بده:
|
|
|
|
```env
|
|
APP_ENV=development
|
|
APP_URL=http://localhost:3000
|
|
API_URL=http://localhost:8000
|
|
|
|
DATABASE_URL=postgresql+psycopg://agy:agy@localhost:5432/agy_web
|
|
REDIS_URL=redis://localhost:6379/0
|
|
|
|
JWT_SECRET=change-me
|
|
ENCRYPTION_KEY=change-me-32-bytes
|
|
|
|
AI_DEFAULT_PROVIDER=mock
|
|
OPENAI_COMPATIBLE_BASE_URL=
|
|
OPENAI_COMPATIBLE_API_KEY=
|
|
|
|
GIT_PROVIDER=mock
|
|
GITEA_URL=
|
|
GITEA_INTERNAL_URL=
|
|
GITEA_ADMIN_TOKEN=
|
|
|
|
DOMAIN_ROUTER=mock
|
|
PREVIEW_ROOT_DOMAIN=msa.artacloud.ir
|
|
PREVIEW_PORT_START=8080
|
|
PREVIEW_PORT_END=8999
|
|
CADDYFILE_PATH=/etc/caddy/Caddyfile
|
|
|
|
SANDBOX_PROVIDER=mock
|
|
DAYTONA_API_KEY=
|
|
E2B_API_KEY=
|
|
|
|
PAYMENT_PROVIDER=mock
|
|
STRIPE_SECRET_KEY=
|
|
STRIPE_WEBHOOK_SECRET=
|
|
```
|
|
|
|
---
|
|
|
|
## 26. کیفیت خروجی مورد انتظار
|
|
|
|
خروجی نهایی نباید فقط چند صفحه UI نمایشی باشد. باید حداقل اینها واقعاً کار کنند:
|
|
|
|
- [ ] auth واقعی با DB.
|
|
- [ ] organization واقعی با tenant isolation.
|
|
- [ ] project واقعی.
|
|
- [ ] employee واقعی.
|
|
- [ ] thread/message/task/run واقعی.
|
|
- [ ] usage ledger واقعی.
|
|
- [ ] audit واقعی.
|
|
- [ ] providerها حداقل با mock کامل.
|
|
- [ ] Git و Domain و Sandbox حداقل با mock کامل و adapter واقعی آماده.
|
|
|
|
---
|
|
|
|
## 27. پیام آخر برای عامل اجراکننده
|
|
|
|
این پروژه را کوچک اما تمیز بساز.
|
|
اول correctness و معماری، بعد زیبایی.
|
|
هیچ چیزی را به تلگرام گره نزن.
|
|
همه چیز را سازمانمحور بساز.
|
|
مدلها و providerها را از کاربر پنهان کن.
|
|
Git و دامنه تست را برای همه پروژهها قابل استفاده کن.
|
|
اجرای کد را فقط از Sandbox Gateway عبور بده.
|
|
هر مصرفی را در usage ledger ثبت کن.
|
|
هر عملیات حساس را audit کن.
|
|
در پایان build/test/lint را اجرا کن و خطاها را رفع کن.
|