Wire production domain, CORS for tenant subdomains, celery volume mounts, and nginx reverse proxy configs for apex, API, identity, auth, and wildcard tenants. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
6.4 KiB
Markdown
87 lines
6.4 KiB
Markdown
# آخرین گام انجامشده
|
||
|
||
## فاز ۴ — Tenant Onboarding و Workspace Activation
|
||
|
||
> در بریف پروژه این کار «Phase 3: operationalizing tenant onboarding and
|
||
> workspace activation» نامیده شده؛ در شمارهگذاری داخلی مستندات، چون «فاز
|
||
> ۳» قبلاً به OTP Login + Tenant Management اختصاص داشت، این تحویل **فاز ۴**
|
||
> ثبت شده است (نگاه کنید به `progress.md`).
|
||
|
||
### مسئله
|
||
تا پیش از این فاز، سیستم فقط «هویت + لیست ادمین» بود: کاربر با OTP/SSO وارد
|
||
میشد و از پنل ادمین tenantها را میدید/میساخت، اما هیچ جریان واقعی
|
||
self-service برای اینکه یک کاربر عادی workspace خودش را بسازد، مالک آن شود،
|
||
پلن/دامنه/برندینگ بگیرد و وارد یک داشبورد عملیاتی شود، وجود نداشت.
|
||
|
||
### راهحل
|
||
|
||
**Backend (`core-service`):**
|
||
- جدول جدید `tenant_memberships` (نقش `tenant_owner/tenant_admin/tenant_editor/tenant_viewer/platform_admin`،
|
||
وضعیت `active/invited/disabled`، `is_owner`).
|
||
- چرخهٔ عمر tenant: `draft → pending_activation → active → suspended/archived`.
|
||
- ستونهای برندینگ/پروفایل روی `tenants` + `is_primary`/`verification_status`
|
||
روی `domains` + `current_tenant_id` روی `users`.
|
||
- Seed پلنهای `FREE`/`STARTER` و اتصال خودکار اشتراک `FREE` هنگام ساخت tenant.
|
||
- سرویسهای جدید: `UserService` (یکپارچهسازی resolve کاربر از JWT محلی یا
|
||
کیکلوک)، `MembershipService`، `OnboardingService`، `TenantContextService`.
|
||
- APIهای جدید: `GET /me`, `GET /me/tenants`, `POST /onboarding/tenant`,
|
||
`PATCH .../branding`, `PATCH .../domain`, `POST .../complete`,
|
||
`GET /tenant/current`, `POST /tenant/switch`.
|
||
- Migration `0005_tenant_onboarding` + تستهای `test_onboarding.py` (۷ تست،
|
||
جریان کامل + حالات forbidden/duplicate/owner-required).
|
||
|
||
**Frontend (`frontend`):**
|
||
- `lib/api.ts` با `api.me` / `api.onboarding` / `api.tenantContext`.
|
||
- `hooks/useMe.ts` برای بارگذاری `/api/v1/me`.
|
||
- `app/onboarding/page.tsx` — ویزارد ۴ مرحلهای (کسبوکار → برندینگ → دامنه
|
||
→ بازبینی) با قابلیت ازسرگیری onboarding ناتمام.
|
||
- `app/dashboard/page.tsx` — داشبورد واقعی workspace + redirect خودکار به
|
||
`/onboarding` وقتی `onboarding_required=true`.
|
||
- `components/TenantSwitcher.tsx` — سوییچر ساده چند-workspace.
|
||
|
||
### محدودیتهای عمدی این فاز (خارج از scope)
|
||
- بدون درگاه پرداخت — فقط ساختار provisioning پلن/اشتراک.
|
||
- بدون تأیید واقعی DNS برای دامنهٔ اختصاصی (فقط رکورد `pending`).
|
||
- مسیر قدیمی `POST /admin/tenants` (فاز ۱/۲) بازنویسی نشده و هنوز عضویت/پلن
|
||
خودکار نمیسازد — عمداً دستنخورده ماند تا فازهای قبلی بازسازی نشوند.
|
||
- JIT provisioning کامل کاربر Core از JWT کیکلوک پیاده نشده (کاربر SSO بدون
|
||
رکورد Core فعلاً `403 forbidden` میگیرد؛ نگاه کنید به بخش بعد).
|
||
|
||
---
|
||
|
||
## فاز پیشنهادی بعدی: White-label Runtime Rendering
|
||
|
||
### چرا این فاز و نه یک ماژول بیزینسی؟
|
||
در همین فاز، فیلدهای برندینگ واقعی (`primary_color`, `secondary_color`,
|
||
`logo_url`, `favicon_url`) روی هر tenant ذخیره و در onboarding از کاربر
|
||
گرفته میشوند — اما frontend فعلاً رنگها را فقط از یک فایل استاتیک
|
||
(`public/theme.config.json`) میخواند و **هیچ ارتباطی با tenant واقعی
|
||
resolveشده ندارد**. یعنی خروجی onboarding (برندینگ tenant) هنوز در UI
|
||
اعمال نمیشود. تکمیل این حلقه (ذخیره برند → نمایش برند) از نظر ارزش محصول
|
||
و آمادگی فنی، اولویت بالاتری نسبت به شروع اولین ماژول بیزینسی (Accounting/
|
||
CRM/...) دارد؛ چون:
|
||
1. زیرساخت لازم (فیلدهای دیتابیس، APIهای `TenantContextRead`، CSS
|
||
Variables موجود در frontend) از قبل آماده است — فقط باید به هم وصل شوند.
|
||
2. بدون این حلقه، ادعای «SaaS چندمستأجری white-label» ناقص میماند، در حالی
|
||
که هر ماژول بیزینسی جدید (Accounting/CRM/...) به خودی خود به این زیرساخت
|
||
وابسته نیست.
|
||
3. حل تشخیص tenant از دامنه (subdomain/custom domain) که برای white-label
|
||
لازم است، پیشنیاز طبیعی معماری چندمستأجری برای هر ماژول آینده نیز هست.
|
||
|
||
### پیشنهاد Scope فاز بعدی
|
||
1. **Backend:** endpoint عمومی (بدون نیاز به auth کاربر) برای resolve
|
||
theme بر اساس Host/X-Tenant-Slug، مثلاً
|
||
`GET /api/v1/public/tenant-theme` که `primary_color`, `secondary_color`,
|
||
`logo_url`, `favicon_url`, `business_name` را برمیگرداند (از همان
|
||
middleware تشخیص tenant موجود استفاده کند).
|
||
2. **Frontend:** بارگذاری theme از این endpoint در `ThemeProvider` هنگام
|
||
دسترسی از subdomain/custom domain یک tenant (بهجای/علاوهبر
|
||
`theme.config.json` استاتیک فعلی که برای برند اصلی پلتفرم باقی میماند).
|
||
3. مسیر عمومی مشتری/ویزیتور tenant (بدون نیاز به لاگین) که برند tenant را
|
||
میبیند — زیرساخت لازم برای هر ماژول بیزینسی آینده (مثلاً منوی دیجیتال
|
||
رستوران) که باید در دامنهٔ tenant با ظاهر آن tenant نمایش داده شود.
|
||
4. بعد از این فاز، اولین ماژول بیزینسی واقعی (پیشنهاد: «رستوران / منوی
|
||
دیجیتال» چون در `docs/architecture.md` بهعنوان سرویس فعلی نامبرده شده و
|
||
دیتابیس مفهومی آن (`restaurant_db`) از قبل طراحی شده) روی همین زیرساخت
|
||
white-label ساخته شود.
|