Đặc tả vòng đời Tenant của BNG Booking Platform — chứng minh mô hình multi-tenant / white-label hoạt động thật. Nguồn sự thật code: provisioning/provisioning-service.ts (transition + audit), booking-service.ts (assertTenantActive — cổng booking), prisma/schema.prisma (tenants.status). Kiểm chứng E2E: src/__tests__/tenant-provisioning-e2e.test.ts, src/__tests__/ops-tenant.test.ts.
Tenant là gì
Tenant = một tenants row (đơn vị thuê / thương hiệu white-label). Booking, Inventory, Reservation đều tenant-scoped. Beta-5 thêm cột tenants.status (migration 20260706000000_add_tenant_status, additive DEFAULT 'active').
Trạng thái
Trạng thái
Ý nghĩa
Booking chạy?
provisioned
Đã tạo, chưa kích hoạt (chưa mở bán).
❌ (cổng chặn → 403)
active
Đang hoạt động — booking chạy bình thường.
✅
suspended
Tạm ngưng. Thuận nghịch.
❌ (403 — inventory/key không bị xoá)
archived
Đóng vĩnh viễn. Terminal.
❌ (403)
Cổng Tenant (booking):BookingService.assertTenantActive chặn availability/booking khi tenant != active ⇒ TENANT_INACTIVE (HTTP 403). Đặt ở BookingService (không ở auth) vì bảng tenants là RLS-FORCE: auth chạy TRƯỚC khi có tenant context nên không đọc được tenants. Cổng chạy TRONG tenant context (đã `SET LOCAL app.current_tenant`) ⇒ RLS-safe. Tương thích ngược: tenant không có row lifecycle (legacy/chưa provision qua Beta-5) giữ hành vi cũ; chỉ chặn tenant đã có row và không active.
Transition KHÔNG hợp lệ (⇒ TENANT_INVALID_TRANSITION, exit 2)
provisioned → suspended (phải active trước).
provisioned → active qua reactivateTenant (sai ngữ nghĩa — dùng activateTenant).
suspended → active qua activateTenant (sai ngữ nghĩa — dùng reactivateTenant).
Bất kỳ transition nào từarchived (terminal).
Tenant không tồn tại ⇒ TENANT_NOT_FOUND (exit 2).
Invariant
Terminal:archived không có transition ra.
Suspend thuận nghịch: suspend chỉ đổi tenants.status — không xoá inventory/key/reservation ⇒ reactivate khôi phục nguyên trạng, cùng API key booking lại được.
Cổng booking = tenant status: nguồn sự thật cho "booking chạy không" là tenants.status = active. Không đường vòng.
Độc lập với Partner (Beta-4): suspend Tenant không đụng Partner status/key; suspend Partner không đụng Tenant status. Hai cổng độc lập, xếp tầng (một request qua cả hai).