Phase 1 Spec: Master Data Init + Tenant Onboarding (Catalog-first)
0. Mục tiêu Phase 1
Mục tiêu
Có màn quản trị Master Data để khởi tạo dữ liệu mặc định “full” (seed) cho hệ thống — dùng cho vận hành/dev/QA/khách hàng mới.
Có luồng khởi tạo Tenant từ trạng thái “đã login nhưng chưa có tenant”:
- User chọn Catalog Template (UI kiểu “thư viện” có phân loại nhóm)
- Điền thông tin tenant cần thiết
- Bấm tạo tenant → hệ thống provision tenant + binding user thành Tenant Admin
- Hệ thống đưa user vào Workspace và cho phép switch tenant (token tenant-bound)
Không làm trong Phase 1 (để tránh loãng)
- Không làm đầy đủ “taxonomy master data ngành nghề” (industry taxonomy) như MDM nâng cao (để Phase 2+).
- Không làm “tùy biến behavior module theo BusinessType” sâu (state machine phức tạp, shipping rules phức tạp…) — Phase 1 chỉ cần khung enablement + default policy.
- Không làm miniapp.
1. Khái niệm & Invariants (bắt buộc)
1.1 Auth/Tenant invariants
- Login trả Identity Token: chỉ định danh user, không có tenantId.
- Khi user chọn tenant (switch) → backend trả Tenant Token: có
tenantId. - API tenant-scoped reject cứng nếu token không có tenantId.
- Các API “tenant provisioning / create tenant / list templates” là tenantless (skip tenant check).
1.2 BusinessType invariants (đã chốt)
BusinessType = Business Model Profile (taxonomy TBD)
BusinessType quyết định:
- Enablement: module bật/tắt
- Behavior variants: policy theo module (shipping on/off, order lifecycle template, appointment enabled…)
BusinessType nằm trên Catalog/CatalogProfile:
- Tenant chọn BusinessType (hoặc dùng default)
- CatalogProfile phải phù hợp capability của BusinessType
1.3 Catalog vs CatalogProfile
- Catalog: product schema/master (entity cốt lõi: Product, Category, Attribute, Variant…)
- CatalogProfile: cấu hình “middle layer” gắn tenant với catalog template + rules/attribute sets/constraints.
2. Actor / RBAC (Phase 1)
Roles
- SYSTEM_ADMIN: quản trị hệ thống, seed master data, quản lý templates.
- ORG_ADMIN / PLATFORM_ADMIN (optional): có thể gộp SYSTEM_ADMIN trong Phase 1.
- TENANT_CREATOR: được phép tạo tenant mới (mặc định: user nào login cũng tạo được, hoặc giới hạn bởi policy).
- TENANT_ADMIN: quản trị tenant sau khi tạo.
Permissions (gợi ý Phase 1)
SYS_MD_INIT: init/reset master dataSYS_TEMPLATE_MANAGE: quản lý catalog templates / business type templatesTENANT_CREATE: tạo tenantTENANT_VIEW,TENANT_MANAGE: quản trị tenant
Phase 1 có thể “đơn giản hoá”: SYSTEM_ADMIN full quyền, còn user thường chỉ có
TENANT_CREATEnếu cho phép.
3. Data Model (Phase 1)
3.1 System Master Data Seed
SeedSet
idcode(e.g.FULL_DEFAULT)nameversion(semver hoặc integer)descriptionstatus:DRAFT | ACTIVE | DEPRECATEDchecksum(đảm bảo idempotent)createdAt,updatedAt
SeedRun (audit vận hành)
idseedSetCode,seedSetVersionmode:DRY_RUN | APPLYstatus:RUNNING | SUCCESS | FAILEDstartedByUserIdstats:logRef(link tới log chi tiết)createdAt,finishedAt
Phase 1: đủ để vận hành và rollback logic dựa trên idempotency.
3.2 BusinessType (Business Model Profile)
BusinessTypeTemplate (system-defined)
idcode(e.g.STANDARD_RETAIL,SERVICE_APPOINTMENT,DIGITAL_GOODS)name,descriptionversioncapabilities:modules: map{ moduleKey: boolean }policies: map{ policyKey: string | number | boolean }
status:ACTIVE | DEPRECATEDcreatedAt,updatedAt
TenantBusinessProfile (tenant binding)
tenantIdactiveTemplateIdeffectiveCapabilities(optional snapshot)overrides(optional; Phase 1 có thể khóa override = empty)updatedAt
Phase 1 tối thiểu: chọn template + computed effective.
3.3 Catalog Template / CatalogProfile
CatalogTemplate (system-defined library item)
idcodenamedescriptiongroupTags: string[] (để phân loại “thư viện”: Retail, F&B, Services, Pharmacy…)preview:defaultAttributeSetsdefaultUnits,defaultTaxes(optional)status:ACTIVE | HIDDENcreatedAt,updatedAt
CatalogProfile (tenant-level)
idtenantIdcatalogTemplateIdbusinessTypeTemplateId(derived from TenantBusinessProfile hoặc explicit)attributePolicy(constraints theo business type)createdAt,updatedAt
Phase 1 user “chắc chỉ cần chọn catalog” → BusinessType có thể default
STANDARDcho tenant mới, hoặc CatalogTemplate córecommendedBusinessTypeCode.
3.4 Tenant & Provisioning
Tenant
idnameslug(unique)status:PROVISIONING | ACTIVE | SUSPENDEDtimezone,locale,currencyownerUserIdcreatedAt,updatedAt
TenantProvisionJob
idtenantIdrequestId(idempotency)status:QUEUED | RUNNING | SUCCESS | FAILEDsteps: list (seed catalog, create roles, bind user, init workspace…)error(if failed)createdAt,updatedAt
4. Backend API Contracts (Phase 1)
4.1 System Admin — Master Data Init
GET /admin/master-data/seed-sets
- Auth: SYSTEM_ADMIN
- Response: list
SeedSet(code/version/status/description)
POST /admin/master-data/initialize
- Auth: SYSTEM_ADMIN
- Body:
seedSetCode: string (defaultFULL_DEFAULT)mode:DRY_RUN | APPLY(default APPLY)force: boolean (default false)
- Behavior:
- Idempotent theo
(seedSetCode, version, checksum)trừ khiforce=true - Tạo
SeedRun
- Idempotent theo
- Response:
seedRunId,status,stats(nếu dry-run) hoặcjobId
GET /admin/master-data/seed-runs/:id
- Auth: SYSTEM_ADMIN
- Response: SeedRun + trạng thái + logRef
Phase 1 không khuyến nghị endpoint “reset toàn bộ” trừ khi môi trường dev. Nếu cần, phải có confirm key + audit.
4.2 System Admin — Template Library (Catalog/BusinessType)
Catalog Template
- GET
/admin/catalog-templates - POST
/admin/catalog-templates - PATCH
/admin/catalog-templates/:id - (Optional) POST
/admin/catalog-templates/:id/publish
BusinessType Template
- GET
/admin/business-types - POST
/admin/business-types - PATCH
/admin/business-types/:id - (Optional) POST
/admin/business-types/:id/publish
Phase 1 có thể seed sẵn 3–5 templates tiêu chuẩn.
4.3 Tenant Onboarding (Tenantless)
GET /onboarding/catalog-templates
- Auth: Authenticated (identity token)
- Purpose: portal hiển thị “thư viện template”
- Query:
q(search)group(filter tag)status=ACTIVE
- Response: list
CatalogTemplate(id, name, description, groupTags, preview)
POST /tenants
- Auth: Authenticated (identity token) + permission
TENANT_CREATE(policy) - Headers:
Idempotency-Key(bắt buộc) → tránh create trùng khi user double-click
- Body:
tenant:catalogTemplateId(required)businessTypeTemplateId(optional, Phase 1 có thể auto)
- Behavior:
- Validate slug unique
- Create
TenantstatusPROVISIONING - Create
TenantBusinessProfile(default template) - Create
CatalogProfile(bind template) - Enqueue
TenantProvisionJob - Bind user →
TENANT_ADMINmembership
- Response:
tenantId,jobId,status=PROVISIONING
GET /tenants/:tenantId/provisioning
- Auth: identity token (owner) OR system admin
- Response: job status + steps
POST /tenants/:tenantId/activate (optional)
- Nếu provisioning async, activate khi job success.
- Phase 1 có thể auto activate.
Phase 1 Progress Trackers
Backend
- [x] PR-BE-03: Provision worker (Scheduled interval, stale lock reset, 6-state logic matching enum)
- [x] PR-BE-04: API Rate limits (IP + Identity based) & Onboarding Flags (
TENANT_CREATE_OPENoverride mapped to UI/auth/me).
Frontend
- [x] PR-FE-01: Portal Workspace (Idempotency Key headers, UI state mapping for
GET /provisioningand tenant-context routing switch upon SUCCESS). - [ ] PR-FE-02: Wizard UI Refinement (4-step layout transition, strict form validation hookup, preview cards).
4.4 Auth helper endpoints (tenantless)
- GET
/auth/me(identity token): trảavailableTenants+ roles global + flags. - POST
/auth/switch-tenant: nhậntenantId→ trả tenant token.
5. Portal UX Spec (Phase 1)
5.1 Màn “Master Data Initialization” (System Admin)
Entry
- Menu: System Admin → Master Data → Initialization
UI states
- Status panel
- Seed status:
NOT_INITIALIZED | INITIALIZED (version) | OUTDATED - Last SeedRun (success/failed, time, by whom)
- Seed status:
- SeedSet list
FULL_DEFAULTlà lựa chọn mặc định (full)- Có mô tả nội dung: units, currencies, payment methods, default roles, default templates…
- Action
- Button:
Initialize (Full Default) - Toggle:
Dry-run - Confirm modal: yêu cầu nhập “CONFIRM” + hiển thị cảnh báo môi trường
- Button:
- Progress
- Hiển thị SeedRun status + stats, link xem log
Rules
- Chỉ SYSTEM_ADMIN thấy màn này.
- Apply seed là idempotent (tránh người bấm nhiều lần làm loạn).
5.2 Luồng “Create Tenant” (Tenantless onboarding)
Bối cảnh User đã login (identity token) nhưng chưa có tenant / hoặc muốn tạo tenant mới.
Entry points
/workspacehiển thị:- List tenants user có quyền truy cập
- CTA:
Create new tenant(nếu policy cho phép)
Wizard steps
Step 1 — Choose Catalog Template (Library UI)
- UI giống “thư viện template”
- Có: Search box, Filter theo
groupTags(chips), Cards: cover + highlights + sample categories, Sort. - Selecting a template → next step
- Empty state: “No template found”
Step 2 — Tenant Information
- Form fields tối thiểu:
- Tenant Name (required)
- Slug (required, unique)
- Timezone (default user locale)
- Locale (vi-VN default)
- Currency (VND default)
- Contact, Address (optional)
- Validation: slug regex + uniqueness check (async), name length
- Form fields tối thiểu:
Step 3 — Review & Create
- Summary: Catalog template selected, Tenant info, (BusinessType default: STANDARD) hiển thị read-only (Phase 1)
- Button: Create
Step 4 — Provisioning Progress
- Show job status: queued/running/success/failed, steps list
- On success: CTA:
Go to workspace+ auto refresh tenants list
Behavior & routing rules
- State A: Unauthenticated → redirect
/login - State B: Authenticated but no active tenant: allowed
/workspace, onboarding pages. module routes redirect/workspace. - State C: Active tenant selected: full module routes as permitted
6. Enforcement & Behavior: BusinessType (Phase 1)
6.1 Enablement
- Khi tenant active, backend trả
effectiveCapabilities(modules enabled). - Portal dùng nó để: hide menu module disabled, chặn route module disabled (show “Not enabled”).
6.2 Backend guard/policy check
- Mỗi module entry service phải có
assertModuleEnabled(moduleKey) - Nếu disabled: trả
403 FEATURE_DISABLED(hoặc 409) với message chuẩn.
7. Validation & Error Handling (chuẩn chung)
7.1 Error format (gợi ý)
{
"code": "TENANT_SLUG_TAKEN",
"message": "Tenant slug already exists",
"details": { "field": "slug" },
"traceId": "..."
}7.2 Errors quan trọng Phase 1
TENANT_SLUG_TAKEN(409)CATALOG_TEMPLATE_NOT_FOUND(404)TENANT_CREATE_FORBIDDEN(403)SEED_ALREADY_APPLIED(409) (trừ force)SEED_RUN_FAILED(500)PROVISIONING_FAILED(500/409)
8. Audit & Observability (vận hành thật)
- Mọi action nhạy cảm (master data init/apply, create tenant, change business type)
- Lưu audit:
actorUserId, action, targetId, timestamp, diff summary - Provisioning job có logRef + steps metrics.
9. Test Plan (Phase 1)
Backend integration tests (P0)
- Create tenant idempotency: same Idempotency-Key → không tạo tenant thứ 2
- Create tenant validates slug unique
- Onboarding endpoints không cần tenant token
- Tenant-scoped endpoint reject nếu chỉ có identity token
- Switch tenant → token có tenantId → gọi tenant-scoped OK
Portal smoke tests
- Login →
/workspace(tenant null) - Create tenant wizard full flow
- Provisioning success → tenant xuất hiện → switch tenant
- Module routes bị chặn khi tenant null