# FinanceGPT — Developer Guide

این سند معماری داخلی پروژه و نحوهٔ توسعهٔ آن را توضیح می‌دهد. رابط کاربری عمداً ساده و دو‌بخشی است (Forward Messages و Interactions)، اما ساختار داخلی کاملاً ماژولار است.

## اجرا

```bash
python run.py
```

- `run.py` کلاینت فوروارد (Telethon) را روی ترد اصلی اجرا می‌کند و پنل Flask را روی یک ترد daemon.
- پنل: `http://localhost:5000` — ورود پیش‌فرض: `admin / admin123` (در اولین ورود تغییر دهید).
- دیتابیس SQLite در `data/app.db` و کلید رمزنگاری در `data/secret.key` ساخته می‌شوند.

## لایه‌بندی معماری

```
app/
  core/        زیرساخت: database, config, logger, security, state,
               crypto (رمزنگاری اسرار), runtime (event-loop مشترک),
               repository (BaseRepository), exceptions
  models/      مدل‌های SQLAlchemy (هر جدول یک فایل)
  services/    سرویس‌های فوروارد: telegram_service, message_processor, ai_service, bale_service, proxy_service
  telegram/    لایهٔ تلگرام مشترک: dialogs (انتخابگر), client_factory,
               account_manager (ClientPool), access_checker
  accounts/    repository + service اکانت‌ها (Mother/Worker)
  ai/          provider_base, openai_provider, router, repository, service
  interactions/ engine (موتور گفتگو), memory, rate_limiter, stopping,
               prompt, reports, service, repository
  admin/       Flask app factory + routes/ + templates/
```

### اصول

- **Repository Pattern**: `app/core/repository.py::BaseRepository` پایهٔ همهٔ repositoryهاست؛ هر متد یک session کوتاه‌عمر باز/بسته می‌کند.
- **Service Layer**: routeها فقط به serviceها وابسته‌اند، نه مستقیم به repository/engine.
- **Dependency Injection**: serviceها repository را در سازنده می‌گیرند (پیش‌فرض می‌سازند).
- **Async**: کل بخش Interactions روی یک event-loop مشترک (`TelegramRuntime`) اجرا می‌شود؛ تردهای Flask با `run_coroutine_threadsafe` کوروتین‌ها را به آن می‌سپارند.
- **Type Hint / Docstring / Logging**: در تمام ماژول‌های اصلی رعایت شده‌اند.

## مدل اجرای چنداکانتی

- کلاینت فوروارد روی loop ترد اصلی زندگی می‌کند (بدون تغییر).
- اکانت‌های Interactions (Mother + Workerها) روی `TelegramRuntime` (یک ترد daemon با loop دائمی) توسط `AccountManager` ساخته و کش می‌شوند.
- موتور گفتگو (`ConversationEngine`) به‌صورت یک `asyncio.Task` روی همان loop اجرا می‌شود.

```
Flask thread ──run_coroutine_threadsafe──▶ TelegramRuntime loop
                                              ├─ AccountManager: client[account_id]
                                              └─ ConversationEngine.run(interaction_id)
```

## رمزنگاری اسرار

`app/core/crypto.py` یک رمزنگاری متقارن authenticated (SHA-256 keystream + HMAC) بدون وابستگی خارجی فراهم می‌کند که از `data/secret.key` کلید می‌گیرد. `session_string`، `api_id`، `api_hash` اکانت‌ها و `api_key` Providerها **رمزنگاری‌شده** ذخیره می‌شوند. `decrypt` با مقادیر plaintext قدیمی سازگار است (آن‌ها را بدون تغییر بازمی‌گرداند).

## دیتابیس و Migration

- جدول‌ها با `Base.metadata.create_all` ساخته می‌شوند (بدون Alembic).
- **قانون مهم:** فقط جدول‌های **جدید** اضافه کنید؛ ستون‌های جدول‌های موجود را تغییر ندهید (create_all جدول موجود را ALTER نمی‌کند). برای داده‌های پیکربندی‌پذیر از فیلد JSON (`Interaction.config`) استفاده کنید تا بدون migration توسعه‌پذیر بماند.

## موتور گفتگو (`app/interactions/engine.py`)

- ترتیب نوبت round-robin است و هیچ اکانتی دو بار پشت‌سرهم پیام نمی‌دهد.
- هر نوبت: تأخیر (پایه + تصادفی) → بررسی Rate Limiter → ساخت context از حافظه → فراخوانی `AIRouter` → ارسال با کلاینت اکانت → ثبت در DB → به‌روزرسانی snapshot زنده → ارزیابی شرایط پایان.
- کنترل‌ها: `start/pause/resume/stop` از طریق registry درون‌حافظه‌ای (`_controls`) و `pause_event`.
- snapshot زنده در `_live` نگه‌داری و توسط `/interactions/api/live/<id>` خوانده می‌شود.
- در پایان، در صورت فعال بودن، پیام جمع‌بندی ارسال و یک `InteractionReport` ساخته می‌شود.

## افزودن قابلیت جدید (مثال: یک Provider جدید)

1. کلاسی از `app.ai.provider_base.ChatProvider` بسازید و `complete()` را پیاده کنید.
2. در `AIRouter._build_provider` آن را بر اساس `provider_type` انتخاب کنید.
موتور گفتگو تغییری نمی‌کند (اصل Open/Closed).

## افزودن یک بخش جدید به UI

طبق قانون سادگی، هر قابلیت جدید را زیر یکی از دو بخش اصلی قرار دهید (یک blueprint با `url_prefix="/interactions/..."` یا `/forward/..."`) و در `_nav.html` یا منوی فوروارد یک تب اضافه کنید. فقط در صورت مستقل و گستردهٔ بودن، یک بخش اصلی جدید بسازید.

## تست

```bash
# کامپایل ماژول‌ها و قالب‌ها + رندر صفحات
python -m py_compile app/**/*.py
```
برای تست رندر، با `app.test_client()` وارد شوید و صفحات `/interactions/*` را GET کنید (نمونه در تاریخچهٔ توسعه موجود است).
