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

128 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# زیرساخت فعلی — یادداشت مرجع
> این سند خلاصهٔ بررسی کد فعلی ربات تلگرام است، فقط برای درک زیرساخت موجود.
> **نسخهٔ وب جدید هیچ‌کدام از این فایل‌ها را import نمی‌کند.** هر قابلیت با یک
> adapter مستقل داخل `web/` بازنویسی می‌شود. این سند صرفاً قراردادها و محدودیت‌هایی
> را ثبت می‌کند که باید در adapterهای جدید حفظ شوند.
---
## ۱. Domain Routing و Preview Domain
منابع بررسی‌شده: `caddy_manager.py` (۲۵۹ خط)، `port_registry.py` (۵۳۱ خط).
### ۱.۱ Caddy
- مسیر فایل: `CADDYFILE_PATH = /etc/caddy/Caddyfile` (یک فایل مشترک سیستمی).
- دامنهٔ wildcard: `WILDCARD_DOMAIN = msa.artacloud.ir`.
- **allowlist سخت‌گیرانهٔ host:** فقط hostهای تک‌label زیر دامنهٔ wildcard مجازند.
الگوی فعلی: `[a-z0-9\-]{1,63}\.msa\.artacloud\.ir`. هر کاراکتری که بتواند از بلوک
سایت خارج شود (آکولاد، کوتیشن، فاصله، newline) رد می‌شود.
- **target فقط local:** الگوی فعلی `(https?://)?(localhost|127\.0\.0\.1):\d{1,5}`.
این برای جلوگیری از SSRF است — نباید هیچ‌وقت به host دیگر proxy شود.
- **چرخهٔ امن نوشتن:** خواندن فایل → ساخت/جایگزینی بلوک → نوشتن → `caddy validate`
→ در صورت خطا **بازگردانی به نسخهٔ قبلی** → `systemctl reload caddy` و در صورت
شکست `caddy reload --config ...`.
- پیدا کردن بلوک سایت با شمارش عمق آکولاد انجام می‌شود (نه regex)، چون بلوک‌ها
تودرتو هستند (`handle`, `route`, `tls`, `header`).
### ۱.۲ Port Registry
دو جدول در SQLite (`data/memory.db`):
| جدول | نقش |
|---|---|
| `port_registry` | `port` (PK)، `user_id`، `project_name`، `service_name`، `subdomain`، `description`، `created_at` — یکتا روی `(user_id, project_name, service_name)` |
| `subdomain_registry` | `host` (PK)، `user_id`، `project_name`، `port`، `protected`، `created_at` — ledger مالکیت دامنه |
قواعد کلیدی که باید در `DomainRouterPort` جدید حفظ شوند:
- محدودهٔ تخصیص port: `8080-8999`.
- `SYSTEM_RESERVED_PORTS = {22, 53, 80, 443, 2019, 3000, 5432, 6379, 8008}`.
- `SYSTEM_PROTECTED_PORTS = {3000, 35555, 35556, 35557} ∪ reserved` — یک پروژهٔ
کاربر هرگز نباید به این‌ها proxy کند، وگرنه سرویس tenant دیگر عمومی می‌شود.
- `MAX_SUBDOMAINS_PER_PROJECT = 5`.
- `SYSTEM_OWNER_PROJECT = "__system__"` برای hostهای بدون مالک شناخته‌شده.
- snapshot پورت‌های listening با `ss -tlnH` گرفته می‌شود. اگر snapshot ممکن نبود
(`None`)، تخصیص **رد می‌شود** — تفاوت «چیزی گوش نمی‌دهد» با «نمی‌دانیم» حفظ می‌شود.
- در تخصیص هم‌زمان، `IntegrityError` گرفته و تا ۵ بار rescan/retry می‌شود.
- هر host دقیقاً یک مالک دارد؛ بدون این ledger هر پروژه می‌توانست دامنهٔ پروژهٔ دیگر را
حذف یا hijack کند.
- hostهایی که قابل انتساب به پروژه نیستند `protected = 1` می‌شوند (فقط admin).
### ۱.۳ تصمیم برای نسخهٔ وب
- `DomainRouterPort` با متدهای `allocate_port` / `claim_preview_domain` /
`configure_reverse_proxy` / `remove_preview_domain` / `list_project_domains`.
- دو adapter: `ManagedDomainRouterAdapter` (mock، بدون لمس Caddy) و
`CaddyDomainRouterAdapter` (واقعی، پشت env flag `DOMAIN_ROUTER=caddy`).
- مالکیت دامنه به `organization_id` + `project_id` در PostgreSQL منتقل می‌شود،
نه `user_id` تلگرام.
---
## ۲. Git / Gitea
منابع بررسی‌شده: `git_manager.py` (۱۰۶۴ خط)، `gitea_api.py` (۲۱۵ خط).
### ۲.۱ تنظیمات فعلی (از `config.py`)
| متغیر | مقدار پیش‌فرض |
|---|---|
| `GITEA_URL` | `https://git.msa.artacloud.ir` (عمومی، برای نمایش) |
| `GITEA_INTERNAL_URL` | `http://127.0.0.1:3000` (برای تماس API) |
| `GITEA_ADMIN_USER` | `root` |
| `GITEA_ADMIN_TOKEN` | خالی — بدون آن همهٔ قابلیت‌های Gitea غیرفعال است |
### ۲.۲ رفتار GitManager
- `ensure_gitea_repo(repo_name, owner, description, private=True)`: اگر repo نبود
می‌سازد، اگر بود و private نبود آن را PATCH می‌کند به private. `auto_init=False`،
`default_branch=main`.
- `generate_project_credentials(project_name, owner_id)`: نام کاربری به شکل
`u{owner_id}_{clean_name[:room]}_{sha1(f"{owner_id}:{project_name}")[:8]}` و رمز
`secrets.token_urlsafe(12)`. هش کوتاه برای جلوگیری از collision دو پروژه با نام
سانیتایز یکسان ضروری است (وگرنه PATCH رمز کاربر مشترک، credential پروژهٔ اول را
بی‌صدا خراب می‌کند). سقف ۳۶ کاراکتر Gitea رعایت می‌شود.
- قفل per-repo (`_RepoLock`) که برای همان asyncio task قابل re-enter است؛
`git_publish`/`git_sync` داخل بخش بحرانی خودشان دوباره lock می‌گیرند، پس
`asyncio.Lock` ساده deadlock می‌داد.
- پاک‌سازی `index.lock` فقط اگر قدیمی‌تر از `STALE_LOCK_AGE_SECONDS = 30` باشد
(حذف lock جوان می‌تواند index را خراب کند).
### ۲.۳ GiteaApiClient
متدها: `create_pr`، `pr_status`، `merge_pr`، `list_open_prs`،
`list_labeled_issues(label="agybot")`، `comment_issue`، `close_issue`.
نکات:
- transport تزریق‌پذیر است (`request` callable) تا تست بدون شبکه اجرا شود.
- token هرگز در هیچ مقدار برگشتی یا prompt قرار نمی‌گیرد؛ `base_url` امن برای نمایش است.
- صفحه‌بندی با cursor `page` انجام می‌شود تا نتایج در یک صفحه بریده نشوند.
- خواندن پیام خطا از `message` / `error` / `errors` (نه فقط `error`).
- برچسب `agybot` روی issue آن را به task سازمانی تبدیل می‌کند.
### ۲.۴ تصمیم برای نسخهٔ وب
- `GitProviderPort` با متدهای `ensure_project_repo` / `create_branch` /
`commit_files` / `open_pull_request` / `merge_pull_request` / `get_repo_status`.
- `GiteaGitAdapter` (واقعی) و `MockGitAdapter` (پیش‌فرض dev).
- نام repo در نسخهٔ وب: `orgslug-projectslug-shortid` (collision-free).
- credential هر پروژه **encrypted at rest** در `project_git_credentials` ذخیره می‌شود؛
token/password هرگز خام به frontend برنمی‌گردد.
- admin token فقط سمت backend می‌ماند.
---
## ۳. جمع‌بندی
| قابلیت فعلی | منبع فعلی | جایگزین در نسخهٔ وب |
|---|---|---|
| Caddy subdomain routing | `caddy_manager.py` | `DomainRouterPort` + `CaddyDomainRouterAdapter` |
| Port/subdomain ledger | `port_registry.py` (SQLite) | جداول `preview_ports` / `preview_domains` (PostgreSQL) |
| Gitea repo + credentials | `git_manager.py` | `GitProviderPort` + `GiteaGitAdapter` |
| PR / issue workflow | `gitea_api.py` | همان port، متدهای PR/issue |
**هیچ‌کدام از این فایل‌ها در runtime نسخهٔ وب import نمی‌شوند.** فقط قراردادها،
الگوهای اعتبارسنجی و قواعد امنیتی بالا به عنوان مرجع استفاده شده‌اند.