mjalmoudy94 717e53a7ce نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی
مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت.
تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
2026-10-13 00:39:28 +03:30

AGY Web — پلتفرم نیروی کار هوش مصنوعی

نسخهٔ وب مستقل و چندسازمانی محصول. این پروژه کاملاً جدا از ربات تلگرام است و هیچ فایلی از ریشهٔ مخزن را در runtime خود import نمی‌کند.


۱. محصول چیست

یک وب اپلیکیشن چندسازمانی برای «نیروی کار هوش مصنوعی سازمانی».

کاربر نهایی این‌ها را می‌بیند: سازمان، مدیر هوش مصنوعی، کارمندهای هوش مصنوعی، پروژه، وظیفه، فایل/خروجی، مصرف و پرداخت.

کاربر نهایی این‌ها را نمی‌بیند: نام مدل، provider، base_url، API key، قیمت خام provider. این‌ها فقط در Admin Console و فقط برای مالک سامانه قابل مدیریت‌اند.

پلتفرم سه لایهٔ نقش دارد:

  1. مالک سامانه (platform owner) — providerها، مدل‌ها، routing policy، تعرفه‌ها، sandbox templateها، مشاهدهٔ کل مصرف.
  2. مدیر سازمان مشتری — ساخت سازمان، دعوت عضو، پروژه، فعال‌سازی کارمند، مصرف.
  3. عضو سازمان — گفتگو با مدیر/کارمند، ساخت task، آپلود فایل، دیدن خروجی.

۲. پیش‌نیازها

ابزار نسخه
Node.js >= 20
pnpm 9.x
Python 3.13
Docker + Compose برای postgres/redis

فعال‌سازی pnpm در صورت نبود:

corepack enable pnpm
corepack prepare pnpm@9.12.0 --activate

۳. راه‌اندازی سریع

# ۱) نصب وابستگی‌های 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

آدرس‌ها پس از اجرا:

حساب‌های نمونه (فقط محیط توسعه)

pnpm db:seed دو حساب می‌سازد و هر دو عضو سازمان نمونه هستند، پس بعد از ورود بلافاصله یک داشبورد پر می‌بینید:

نقش ایمیل رمز
کاربر نمونه demo@example.com demo12345
مالک سامانه (admin console) owner@example.com owner12345

این‌ها رمزهای توسعه هستند و در app/seed.py سخت‌کد شده‌اند. هیچ‌وقت در production از این‌ها استفاده نکنید و JWT_SECRET / ENCRYPTION_KEY واقعی بگذارید (نگهبان config در حالت production مقادیر placeholder را رد می‌کند).

نکته: دامنهٔ ایمیل عمداً example.com است. اگر .local یا .test بگذارید، email-validator آن را رد می‌کند و حساب ساخته می‌شود ولی ورود به آن ناممکن است. tests/test_seed.py همین را تضمین می‌کند.

اجرای کل استک با Docker

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 واقعی اجرا شود.

۵.۴ جریان درخواست

Browser → Web (Next.js/BFF) → API (FastAPI)
                                  ├── Domain Modules
                                  ├── Event Bus / Outbox → Workers
                                  ├── AI Runtime        → Model Providers
                                  ├── Sandbox Gateway   → E2B / Daytona
                                  └── Billing Processor → Stripe

۶. ساختار پوشه

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 مقادیر
مدل AI_DEFAULT_PROVIDER mock | openai_compatible
Git GIT_PROVIDER mock | gitea
دامنهٔ تست DOMAIN_ROUTER mock | caddy
Sandbox SANDBOX_PROVIDER mock | daytona | e2b
پرداخت PAYMENT_PROVIDER mock | stripe

اگر credential واقعی نداریم، قابلیت حذف نمی‌شود: مدل دیتابیس، interface، UI و adapter mock کامل ساخته می‌شود و adapter واقعی پشت همین flag آماده می‌ماند.


۹. Workerهای پس‌زمینه

سه worker وجود دارد. همه در apps/api/app/workers/ پیاده شده‌اند و services/<name> پوستهٔ اجرای آن‌هاست:

worker کار دستور
billing-worker جمع‌بندی usage ledger به فاکتور draft (هر دوره یک‌بار، idempotent) pnpm worker:billing
ai-runtime برداشتن taskهای در صف و اجرای آن‌ها از مسیر run engine pnpm worker:ai-runtime
sandbox-gateway متوقف‌کردن sessionهای بی‌استفاده و ثبت audit pnpm worker:sandbox-gateway

هر دستور یک پاس اجرا می‌کند و خارج می‌شود (شکل مناسب cron). برای اجرای مستمر --loop بدهید:

cd apps/api && .venv/bin/python -m app.workers billing --loop --interval 3600

اصل مهم: workerها هیچ منطق تجاری ندارند. هر سه از app/application/container.py همان سرویس‌هایی را می‌سازند که HTTP API می‌سازد، پس worker و API هرگز نمی‌توانند دربارهٔ اینکه کدام adapter پشت یک port است اختلاف داشته باشند. جزئیات هر کدام در 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 برمی‌گرداند. کاربر می‌تواند فقط همین یک رشته را گزارش کند تا دقیقاً یک رکورد پیدا شود.

# ۵۰۰ بگیر، سپس با همان شناسه رکورد را پیدا کن
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 و سازمان مربوطه ثبت می‌شود.


۱۲. مستندات

S
Description
Smart Org v2
Readme
1.5 MiB
Languages
Python 73.5%
TypeScript 26.3%
CSS 0.1%