Register all active platform services and base features in core DB so admin can manage them, add delivery/hospitality/sports-center backend phases, update apps catalog and production deploy tooling. Co-authored-by: Cursor <cursoragent@cursor.com>
310 lines
16 KiB
Markdown
310 lines
16 KiB
Markdown
# طرح دیتابیس (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`.
|
||
> delivery_db پیادهسازی شده — Phase 10.1 drivers:
|
||
> `delivery_organizations`, `delivery_hubs`, `delivery_roles`, `delivery_permissions`,
|
||
> `external_provider_configs`, `routing_engine_registrations`, `delivery_configurations`,
|
||
> `delivery_settings`, `delivery_audit_logs`,
|
||
> `drivers`, `driver_credentials`, `driver_documents`, `driver_lifecycle_events`, `outbox_events`.
|
||
> experience_db پیادهسازی شده — Phase 11.0–11.4:
|
||
> `experience_workspaces`, `experience_locale_profiles`, `external_provider_configs`,
|
||
> `render_engine_registrations`, `experience_configurations`, `experience_settings`,
|
||
> `experience_roles`, `experience_permissions`, `experience_audit_logs`,
|
||
> `experience_sites`, `experience_pages`, `experience_site_domains`,
|
||
> `experience_components`, `experience_component_versions`, `experience_page_component_placements`,
|
||
> `experience_themes`, `experience_layouts`, `experience_site_theme_assignments`,
|
||
> `experience_page_layout_assignments`, `experience_templates`,
|
||
> `experience_template_versions`, `experience_template_instantiations`.
|
||
- **ecommerce_db:** products، categories، inventory، orders، order_items،
|
||
payments، shipments، discounts، carts.
|
||
- **experience_db:** sites، pages، page_types، components، component_versions،
|
||
themes، layouts، templates، locales، media_refs، forms، surveys،
|
||
appointment_pages، publish_states، domain_bindings، seo_meta، bundles،
|
||
feature_toggles، widgets، audit/config shells (از Phase 11.0).
|
||
- **website_builder_db:** (historical scaffold) sites، pages، blocks، forms، menus، media، content — prefer `experience_db`.
|
||
- **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`.
|
||
|