# طرح دیتابیس (Database Schema)

> Reference only. Architecture rules → [database-architecture.md](../architecture/database-architecture.md).  
> Dual memberships → [ADR-007](../architecture/adr/ADR-007.md) · [Glossary](../glossary.md).

## بخش ۱ — دیتابیس Core Platform (`core_platform_db`) — فاز ۱

همه مدل‌ها با SQLAlchemy 2.x و Alembic پیاده شده‌اند. شناسه‌ها از نوع UUID و
زمان‌ها timezone-aware هستند.

### جدول `tenants`
| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| name | varchar(255) | نام مستأجر (`business_name` در onboarding) |
| slug | varchar(100) unique | شناسه یکتا برای resolve |
| status | enum | `draft` / `pending_activation` / `active` / `suspended` / `archived` (+ مقادیر قدیمی `inactive`/`deleted` برای سازگاری) |
| owner_user_id | UUID null | مالک (از Identity Service) |
| business_type | varchar(100) null | نوع کسب‌وکار (فاز ۴ — onboarding) |
| default_locale | varchar(20) | پیش‌فرض `fa-IR` |
| timezone | varchar(50) | پیش‌فرض `Asia/Tehran` |
| primary_color | varchar(20) null | برندینگ |
| secondary_color | varchar(20) null | برندینگ |
| logo_url | varchar(500) null | برندینگ |
| favicon_url | varchar(500) null | برندینگ |
| onboarding_completed | bool | پیش‌فرض `false`؛ با `POST .../complete` به `true` تغییر می‌کند |
| created_at, updated_at | timestamptz | |

ایندکس‌ها: `slug` (unique)، `status`.

> فیلدهای `business_type` تا `onboarding_completed` در migration `0005_tenant_onboarding`
> اضافه شده‌اند (فاز ۴ — Tenant Onboarding).

### جدول `domains`
| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| tenant_id | UUID (FK→tenants) | |
| domain | varchar(255) unique | |
| domain_type | enum | subdomain / custom_domain |
| is_verified | bool | |
| verified_at | timestamptz null | |
| is_primary | bool | دامنهٔ اصلی/پیش‌فرض tenant (زیردامنهٔ خودکار onboarding) — فاز ۴ |
| verification_status | enum | `pending` / `verified` / `failed` — فاز ۴ |
| created_at | timestamptz | |

ایندکس‌ها: `domain` (unique)، `tenant_id`.

### جدول `plans`
id, code(unique), name, description, is_active, created_at. ایندکس: `code`.

### جدول `features`
id, feature_key(unique), name, description, service_key, is_active.
ایندکس‌ها: `feature_key` (unique)، `service_key`.
مثال feature_key: `accounting.invoice.create`، `crm.lead.create`،
`ecommerce.product.create`، `live_chat.widget.enable`، `ai_assistant.chat.reply`.

### جدول `plan_features`
id, plan_id(FK), feature_id(FK), limit_value(null=نامحدود),
limit_period(enum: day/month/year/total), is_enabled.
محدودیت یکتا: (plan_id, feature_id). ایندکس‌ها روی هر دو کلید خارجی.

### جدول `tenant_subscriptions`
id, tenant_id(FK), plan_id(FK), status(enum: trialing/active/past_due/
canceled/expired), starts_at, ends_at, trial_ends_at, created_at.
ایندکس‌ها: `tenant_id`، `status`.

### جدول `tenant_feature_access`
override سفارشی دسترسی: id, tenant_id(FK), feature_id(FK), is_enabled,
custom_limit_value(null=نامحدود), used_value, reset_at.
محدودیت یکتا: (tenant_id, feature_id). ایندکس‌ها روی هر دو کلید خارجی.

### جدول `service_registry`
id, service_key(unique), name, base_url, status(enum), health_check_url,
created_at. ایندکس: `service_key`.

### جدول `module_registry`
id, module_key(unique), name, description, is_system_module, is_active.
ایندکس: `module_key`.

### جدول `tenant_module_access`
id, tenant_id(FK), module_id(FK), is_enabled, enabled_at, disabled_at.
محدودیت یکتا: (tenant_id, module_id). ایندکس: `tenant_id`.

### جدول `internal_service_tokens`
id, service_key, token_hash(unique), scopes, expires_at, is_active, created_at.
فقط hash توکن ذخیره می‌شود. ایندکس‌ها: `service_key`، `token_hash`.

### جدول `outbox_events`
id, event_type, aggregate_type, aggregate_id, tenant_id, payload(JSON),
status(enum: pending/processed/failed), retry_count, created_at, processed_at.
ایندکس‌ها: `status`، `tenant_id`.

### جدول `inbox_events`
id, event_id(unique), source_service, event_type, tenant_id, payload(JSON),
processed_at. ایندکس‌ها: `event_id`، `tenant_id`.

### جدول `audit_logs`
id, tenant_id, actor_user_id, action, resource_type, resource_id,
metadata(JSON), ip_address, user_agent, created_at.
ایندکس‌ها: `tenant_id`، `created_at`.

### جدول `users` (OTP + لینک SSO — فاز ۳)
| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| mobile | varchar(15) unique | شماره موبایل (09xxxxxxxxx) — **الزامی** |
| keycloak_sub | varchar(100) null unique | لینک به کاربر Keycloak (SSO) |
| email | varchar(255) null | ایمیل (اختیاری، برای لینک SSO) |
| mobile_verified | bool | تأیید OTP — true پس از verify موفق |
| role | enum | user / pending_tenant_admin / tenant_admin / platform_admin |
| status | enum | active / inactive / suspended |
| current_tenant_id | UUID null (FK→tenants, `ON DELETE SET NULL`) | tenant انتخاب‌شده جاری کاربر — فاز ۴ |
| created_at, updated_at | timestamptz | |

ایندکس‌ها: `mobile` (unique)، `keycloak_sub` (unique)، `status`.

**نقش‌ها بر اساس context OTP:**
- `public` → `user` (ثبت‌نام عمومی)
- `admin` → `pending_tenant_admin` (پنل ادمین tenant)
- `PLATFORM_ADMIN_MOBILES` → `platform_admin`

### جدول `tenant_memberships` (فاز ۴ — Tenant Onboarding)

> **توجه:** این جدول در `core_platform_db` است و با جدول هم‌نام در
> `identity_access_db` (بخش ۳ همین سند) **کاملاً متفاوت و بدون ارتباط
> مستقیم** است. جدول Core عضویت واقعی کاربر↔workspace را برای جریان
> onboarding/authorization مدیریت می‌کند.

| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| tenant_id | UUID (FK→tenants, cascade) | |
| user_id | UUID (FK→users, cascade) | |
| role | enum | `platform_admin` / `tenant_owner` / `tenant_admin` / `tenant_editor` / `tenant_viewer` |
| status | enum | `active` / `invited` / `disabled` |
| is_owner | bool | فقط یک یا چند owner فعال در هر tenant (حداقل یکی الزامی) |
| created_at, updated_at | timestamptz | |

محدودیت یکتا: `(tenant_id, user_id)`. ایندکس‌ها: `tenant_id`، `user_id`، `role`، `status`.

**قواعد:**
- هنگام `POST /onboarding/tenant`، کاربر سازنده به‌صورت خودکار عضویت
  `tenant_owner` / `is_owner=true` / `status=active` می‌گیرد.
- `POST /onboarding/tenant/{id}/complete` بررسی می‌کند که حداقل یک owner
  فعال وجود داشته باشد؛ در غیر این صورت خطای `owner_required`.
- کاربر می‌تواند در آینده چند عضویت (چند tenant) داشته باشد؛ `users.current_tenant_id`
  مشخص می‌کند کدام‌یک «جاری» است.

### جدول `plans` و `tenant_subscriptions` (seed پیش‌فرض — فاز ۴)
ساختار جدول‌ها از فاز ۱ بدون تغییر باقی مانده (نگاه کنید به پایین همین
بخش)؛ در فاز ۴ موارد زیر اضافه شد:
- Migration `0005_tenant_onboarding` دو پلن `FREE` و `STARTER` را با
  `ON CONFLICT (code) DO NOTHING` seed می‌کند (idempotent).
- `PlanService.ensure_default_plan()` همان پلن `FREE` را در زمان اجرا نیز
  به‌صورت idempotent تضمین می‌کند (برای محیط‌های SQLite تست که migration
  اجرا نمی‌شود).
- `POST /onboarding/tenant` به‌صورت خودکار یک `tenant_subscriptions` با
  `plan=FREE`، `status=active` می‌سازد.

## بخش ۴ — دیتابیس Accounting (`accounting_db`) — فاز ۵.۱ تا ۵.۶

Migration: `0001_initial` در `backend/services/accounting/alembic/versions/`.

### Foundation (5.1)
`chart_of_accounts`, `accounts`, `currencies`, `exchange_rates`, `fiscal_years`,
`fiscal_periods`, `cost_centers`, `projects`, `dimensions`, `accounting_settings`,
`document_number_sequences`, `tenant_accounting_configurations`

### Posting (5.2)
`vouchers`, `voucher_lines`, `journals`, `journal_entries`, `posting_logs`,
`posting_errors`, `posting_references`, `accounting_audit_logs`

### Ledger (5.3)
`general_ledgers`, `ledger_balances`, `trial_balance_snapshots`, `balance_snapshots`,
`closing_entries`, `opening_entries`, `accounting_calendars`

### Treasury (5.4)
`cash_boxes`, `cash_transactions`, `banks`, `bank_accounts`, `bank_transactions`,
`cheque_books`, `cheques`, `transfers`, `receipt_vouchers`, `payment_vouchers`,
`reconciliations`, `treasury_settings`

### AR/AP (5.5)
`customer_accounts`, `supplier_accounts`, `receivable_invoices`, `payable_invoices`,
`settlements`, `settlement_allocations`, `credit_notes`, `debit_notes`,
`advance_payments`, `advance_receipts`, `customer_statements`, `supplier_statements`,
`aging_snapshots`

### Sales Accounting (5.6)
`sales_posting_profiles`, `accounting_profiles`, `posting_rules`,
`sales_accounting_configurations`, `revenue_recognitions`, `revenue_schedules`,
`accounting_previews`, `posting_simulations`

### Purchase/Inventory (5.7)
`purchase_posting_profiles`, `inventory_posting_profiles`, `inventory_valuation_methods`,
`inventory_valuation_history`, `inventory_cost_adjustments`, `purchase_accounting_configurations`,
`inventory_accounting_configurations`, `inventory_snapshots`

### Fixed Assets (5.8)
`asset_categories`, `asset_groups`, `assets`, `asset_depreciations`, `depreciation_schedules`,
`asset_transfers`, `asset_disposals`, `asset_revaluations`, `asset_impairments`,
`asset_accounting_profiles`, `asset_history`, `asset_locations`

### Payroll (5.9)
`departments`, `positions`, `employees`, `employment_contracts`, `salary_components`,
`payroll_periods`, `payrolls`, `payroll_items`, `benefits`, `allowances`, `deductions`,
`employee_loans`, `employee_advances`, `payroll_accounting_profiles`, `payroll_history`,
`payroll_settlements`

### Reporting (5.10)
`financial_reports`, `report_templates`, `dashboards`, `dashboard_widgets`, `kpis`,
`report_snapshots`, `scheduled_reports`, `report_exports`, `report_history`, `report_configurations`

### Compliance (5.11)
`audit_records`, `audit_history`, `compliance_policies`, `governance_rules`,
`approval_workflows`, `approval_steps`, `approval_requests`, `delegations`,
`risk_records`, `policy_violations`, `evidence`, `retention_policies`, `control_definitions`

همه جداول دارای `tenant_id` (UUID، بدون FK بین DB).

---

## بخش ۲ — طراحی اولیه دیتابیس سرویس‌های آینده (بدون migration)

> accounting_db اکنون پیاده‌سازی شده — جزئیات در بخش ۴ بالا.
> crm_db پیاده‌سازی شده — Phases 6.0–6.3.
> loyalty_db پیاده‌سازی شده — Phase 7.0 foundation:
> `loyalty_programs`, `membership_tiers`, `members`, `point_accounts`,
> `rewards`, `campaigns`, `loyalty_audit_logs`.
> communication_db پیاده‌سازی شده — Phase 8.0–8.10:
> `provider_configs`, `sender_numbers`, `message_templates`, `manual_contacts`,
> `contact_sources`, `messages`, `queue_items`, `delivery_events`, `provider_logs`,
> `otp_challenges`, `webhook_receipts`, `communication_audit_logs`.
- **ecommerce_db:** products، categories، inventory، orders، order_items،
  payments، shipments، discounts، carts.
- **website_builder_db:** sites، pages، blocks، forms، menus، media، content.
- **live_chat_db:** widgets، conversations، messages، agents، routing_rules.
- **ai_assistant_db:** assistants، knowledge_bases، documents، chat_sessions،
  messages، handoffs.
- **smart_messenger_db:** channels، accounts، threads، messages، automations.
- **sms_panel_db:** providers، templates، campaigns، messages، send_queue.
- **link_shortener_db:** links، domains، clicks، campaigns.
- **notification_db:** notifications، channels، templates، delivery_logs.
- **file_storage_db:** files، buckets، access_policies.
- **restaurant_db:** menus، menu_items، tables، orders، kitchen_tickets،
  payments (loyalty via `loyalty_db` / Loyalty service).

هر سرویس دسترسی قابلیت‌ها را از Core (`check_feature_access`) استعلام می‌کند و
هرگز مستقیماً به `core_platform_db` متصل نمی‌شود.

## بخش ۳ — دیتابیس Identity & Access (`identity_access_db`) — فاز ۲

### جدول `user_profiles`
| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| keycloak_sub | varchar unique | شناسه کاربر در Keycloak |
| email | varchar | |
| username | varchar null | |
| display_name | varchar null | |
| mobile | varchar(15) null unique | شماره موبایل — **الزامی برای کاربران جدید** |
| mobile_verified | bool | تأیید OTP |
| mobile_verified_at | timestamptz null | زمان تأیید |
| core_user_id | UUID null | لینک به `core_platform_db.users` |
| status | enum | active / inactive / suspended |
| created_at, updated_at | timestamptz | |

ایندکس‌ها: `keycloak_sub` (unique)، `email`، `mobile` (unique).

**قانون:** کاربر تازه‌ثبت‌نام‌شده تا پیش از `mobile_verified=true` کامل محسوب نمی‌شود.
کاربران SSO قدیمی بدون موبایل باید از `/auth/verify-mobile` تکمیل کنند.

### جدول `tenant_memberships`

> **توجه:** این جدول مربوط به `identity_access_db` (لایهٔ هویت SSO) است و
> **جدول متفاوتی** نسبت به `tenant_memberships` در `core_platform_db` است که
> در بخش ۱ (فاز ۴ — Tenant Onboarding) مستند شده. این دو جدول در دو سرویس/
> دیتابیس جدا زندگی می‌کنند و sync خودکار بین آن‌ها وجود ندارد؛ منبع حقیقت
> (source of truth) برای نقش عملیاتی کاربر در یک workspace، جدول Core است.

| ستون | نوع | توضیح |
| --- | --- | --- |
| id | UUID (PK) | |
| tenant_id | UUID | مرجع به tenant در Core (بدون FK بین DB) |
| user_id | UUID (FK→user_profiles) | |
| role | enum | tenant_admin / tenant_member |
| is_active | bool | |
| joined_at | timestamptz | |

محدودیت یکتا: (tenant_id, user_id). ایندکس‌ها: `tenant_id`, `user_id`.

