# طرح دیتابیس (Database Schema) ## بخش ۱ — دیتابیس 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` می‌سازد. ## بخش ۲ — طراحی اولیه دیتابیس سرویس‌های آینده (بدون migration) > این‌ها فقط طراحی مفهومی‌اند؛ در فازهای بعدی هر سرویس دیتابیس مستقل خود را > با ستون `tenant_id` در جداول بیزینسی خواهد داشت. - **accounting_db:** accounts (۴ سطحی)، journal_entries، journal_lines، cost_centers، projects، invoices، payments، taxes، reports. - **crm_db:** customers، leads، opportunities، pipelines، stages، tasks، activities، automations. - **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. هر سرویس دسترسی قابلیت‌ها را از 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`.