# Database ERD

همه‌ی زمان‌ها UTC و از نوع `DATETIME` هستند. همه‌ی مبالغ `BIGINT` (تومان). وضعیت‌ها `VARCHAR` هستند و با Enumهای PHP اعتبارسنجی می‌شوند (افزودن وضعیت جدید به `ALTER` نیاز ندارد).

```mermaid
erDiagram
    bots ||--o{ bot_users : has
    users ||--o{ bot_users : joins
    users ||--|| wallets : owns
    wallets ||--o{ wallet_transactions : ledger
    users ||--o{ users : "referrer_id"
    users ||--o{ referrals : "referrer / referred"
    referrals ||--o{ referral_transactions : earns
    users ||--o{ channels : owns
    channels ||--o{ channel_members : tracks
    channels ||--o{ channel_links : has
    users ||--o{ campaigns : owns
    channels ||--o{ campaigns : target
    products ||--o{ campaigns : priced_by
    campaigns ||--o{ campaign_links : has
    users ||--o{ campaign_links : "publisher"
    campaign_links ||--o{ campaign_members : brings
    campaigns ||--o{ campaign_members : counts
    users ||--o{ orders : places
    orders ||--|{ order_items : contains
    orders ||--o| campaigns : creates
    users ||--o{ payments : pays
    orders ||--o{ payments : "paid by"
    payments ||--o{ payment_transactions : events
    users ||--o{ withdrawals : requests
    users ||--o{ bank_accounts : has
    users ||--o{ crypto_wallets : has
    users ||--o{ kyc_requests : submits
    users ||--o{ tickets : opens
    tickets ||--o{ ticket_messages : contains
    users ||--o{ notifications : receives
    broadcasts ||--o{ broadcast_recipients : targets
    users ||--o| admins : "is"
    admins ||--o{ admin_roles : has
    roles ||--o{ admin_roles : assigned
    roles ||--o{ role_permissions : grants
    permissions ||--o{ role_permissions : in
    admins ||--o{ audit_logs : writes
    campaigns ||--o{ risk_events : flagged
```

## جداول

| جدول | کلیدها و قیود مهم |
|---|---|
| `bots` | `bot_key` UNIQUE، `telegram_bot_id` UNIQUE، توکن رمزشده |
| `users` | `telegram_id` UNIQUE، `referral_code` UNIQUE، FK `referrer_id→users` |
| `bot_users` | UNIQUE(`bot_id`,`user_id`) |
| `wallets` | `user_id` UNIQUE FK، CHECK(`available>=0`, `pending>=0`, `withdrawable>=0`) |
| `wallet_transactions` | `idempotency_key` UNIQUE، INDEX(`user_id`,`id`)، INDEX(`reference_type`,`reference_id`) |
| `channels` | UNIQUE(`bot_id`,`chat_id`)، FK `owner_id` |
| `channel_members` | UNIQUE(`channel_id`,`telegram_user_id`) |
| `channel_links` | `token` UNIQUE |
| `products` | `product_key` UNIQUE |
| `campaigns` | INDEX(`status`,`expires_at`)، INDEX(`owner_id`,`status`)، CHECK(`completed_count<=capacity`) |
| `campaign_links` | `token` UNIQUE، UNIQUE(`campaign_id`,`publisher_id`)، INDEX(`invite_link`) |
| `campaign_members` | UNIQUE(`campaign_id`,`telegram_user_id`)، INDEX(`earning_status`,`settle_at`) |
| `orders` | `idempotency_key` UNIQUE، INDEX(`user_id`,`status`) |
| `order_items` | FK `order_id` CASCADE |
| `payments` | `token` UNIQUE، `tx_hash` UNIQUE، UNIQUE(`gateway`,`authority`) |
| `payment_transactions` | FK `payment_id`، لاگ رویدادهای درگاه |
| `withdrawals` | `idempotency_key` UNIQUE، INDEX(`status`,`id`)، INDEX(`user_id`,`created_at`) |
| `bank_accounts` | `card_hash` UNIQUE، شماره کارت/شبا رمزشده + Mask |
| `crypto_wallets` | UNIQUE(`user_id`,`network`,`address`) |
| `referrals` | UNIQUE(`referred_id`,`level`)، INDEX(`referrer_id`,`level`) |
| `referral_transactions` | UNIQUE(`referrer_id`,`source_type`,`source_id`,`level`) |
| `kyc_requests` | داده‌ی هویتی رمزشده، INDEX(`status`,`id`) |
| `tickets` / `ticket_messages` | INDEX(`user_id`,`status`) |
| `notifications` | INDEX(`user_id`,`id`)، INDEX(`status`,`id`) |
| `broadcasts` / `broadcast_recipients` | UNIQUE(`broadcast_id`,`user_id`)، INDEX(`broadcast_id`,`status`,`id`) |
| `admins` | `user_id` UNIQUE FK |
| `roles` / `permissions` | `name` UNIQUE |
| `role_permissions` / `admin_roles` | کلید مرکب یکتا |
| `settings` | UNIQUE(`bot_id`,`setting_key`) — `bot_id=0` یعنی سراسری |
| `audit_logs` | INDEX(`admin_id`,`id`)، INDEX(`target_type`,`target_id`) |
| `risk_events` | INDEX(`campaign_id`)، INDEX(`telegram_user_id`) |
| `telegram_updates` | UNIQUE(`bot_id`,`update_id`) — ضد Replay |
| `daily_stats` | UNIQUE(`stat_date`,`bot_id`,`stat_key`) |
| `failed_jobs` | Jobهایی که همه‌ی Retryها را مصرف کرده‌اند |
| `migrations` | تاریخچه‌ی Migration |

## سیاست حذف

- `wallet_transactions`، `payments`، `payment_transactions`، `withdrawals`، `audit_logs`، `referral_transactions` **هرگز** توسط Cleanup حذف نمی‌شوند (FKها `RESTRICT`).
- `telegram_updates`، `notifications` ارسال‌شده، `broadcast_recipients` قدیمی، `failed_jobs` و `risk_events` بررسی‌شده طبق `config/app.php → retention` پاک می‌شوند.
