Domain Model
Tất cả schema được định nghĩa trong
@nx/core/src/models/schemas/{public,allocation}/và được re-export. Bảng catalog nằm trong schemapublic; bảng allocation nằm trong schemaallocation. Cột đa hình dùnggeneratePrincipalColumnDefs; cột chung quagenerateCommonColumnDefs<TMetadata>().
1. ERD đầy đủ
2. Cột chung
| Cột | Type | Ghi chú |
|---|---|---|
id | text | PK, Snowflake |
identifier | text | Mã con người có tiền tố (P, PV, M, …) |
createdAt / modifiedAt | timestamptz | — |
createdBy / modifiedBy | text | Audit người dùng |
deletedAt | timestamptz | Soft-delete |
metadata | jsonb | Túi mở rộng có kiểu ($type<TMetadata>()) |
3. Thực thể
3.1 Product
| Thuộc tính | Giá trị |
|---|---|
| Bảng | Product (public) |
| Nguồn | core/.../public/product/schema.ts |
| Soft-delete | có |
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
slug | text | ✓ | Unique partial theo merchantId |
status | text | ✓ | ProductStatuses; mặc định ACTIVATED |
merchantId | text | ✓ | Chủ sở hữu |
taxGroupId | text | Ref nhóm thuế (được taxation tiêu thụ) | |
parentId | text | Phân cấp / nhóm variant | |
referenceId | text | Ref ngoài / đồng bộ |
3.2 ProductVariant
| Thuộc tính | Giá trị |
|---|---|
| Bảng | ProductVariant (public) |
| Nguồn | core/.../public/product-variant/schema.ts |
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
slug | text | ✓ | — |
isDefault | boolean | ✓ | Variant mặc định của product (mặc định false) |
dateFrom / dateTo | timestamptz | Khoảng hiệu lực | |
status | text | ✓ | ProductVariantStatuses; mặc định ACTIVATED |
type | text | ✓ | ProductVariantTypes; mặc định STORABLE — bộ phân biệt cấu trúc |
uom | jsonb | IUomRole { base, purchase, sale } | |
productId | text | ✓ | Product cha |
typeđiều khiển tồn kho & gói — xem §4.1. Giá không lưu ở đây (nằm trong@nx/pricing).
3.3 ProductInfo / ProductIdentifier
ProductInfo (đa hình generatePrincipalColumnDefs — principal = Product hoặc ProductVariant): name (i18n), description (i18n).
ProductIdentifier (đa hình): scheme (TProductIdentifierScheme — SYSTEM / SKU / BARCODE / …), identifier (text). Scheme SYSTEM được tự sinh khi tạo aggregate.
3.4 ProductOption / ProductOptionValue / ProductVariantOption
| Bảng | Trường chính |
|---|---|
ProductOption | productId, key, name (i18n), sequence |
ProductOptionValue | optionId, value, name (i18n), sequence |
ProductVariantOption | productVariantId, optionId, optionValueId — liên kết một variant với một giá trị cho mỗi option |
3.5 ProductBundler
| Thuộc tính | Giá trị |
|---|---|
| Bảng | ProductBundler (public) |
| Nguồn | core/.../public/product-bundler/{schema,constants}.ts |
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
type | text | ✓ | ProductBundlerTypes COMBO / ADDON / FBT; mặc định COMBO |
leadVariantId | text | ✓ | Variant host / combo |
relatedVariantId | text | ✓ | Thành phần / addon / gợi ý |
quantity | numeric | ✓ | Mặc định 1 |
basis | text | ProductBundlerBasises — ghi đè giá FBT; null trên COMBO/ADDON | |
basisValue | numeric | Số tiền/phần trăm ghi đè | |
sequence | int | ✓ | Sắp xếp (mặc định 0) |
Unique partial trên
(type, leadVariantId, relatedVariantId). Bảng đơn này biểu diễn quan hệ COMBO/ADDON/FBT — chúng không phải là variant type. Xem ADR-0003.
3.6 Merchant
| Thuộc tính | Giá trị |
|---|---|
| Bảng | Merchant (public) |
| Nguồn | core/.../public/merchant/{schema,constants}.ts |
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
slug | text | ✓ | Unique partial theo organizerId |
name / description | i18n | name ✓ | — |
status | text | ✓ | MerchantStatuses; mặc định ACTIVATED |
currency | text | ✓ | Mặc định VND |
businessType | text | ✓ | BusinessTypes; mặc định HOUSEHOLD |
industry | text | ✓ | MerchantIndustry; mặc định FNB |
isHeadquarter | boolean | ✓ | Mặc định false |
location | jsonb | helper location() | |
taxMethod | text | TaxMethods (ví dụ DIRECT) | |
parentId | text | Phân cấp | |
organizerId | text | ✓ | Chủ sở hữu |
metadata.tax | jsonb | { taxCode, cityCode?, districtCode?, wardsCode?, fullName?, addressLine? } — thu thập MST (CDC → TaxInfo) | |
metadata.eInvoice[] | jsonb | thông tin đăng nhập provider hóa đơn điện tử | |
metadata.finance.accounts[] | jsonb | tài khoản tài chính được seed | |
metadata.onboarding | jsonb | Partial<Record<TMerchantOnboardingStep, boolean>> |
3.7 Organizer
slug (unique), identifier, status (OrganizerStatuses; mặc định ACTIVATED), name (i18n), description (i18n), location, parentId, headquarterMerchantId.
3.8 SaleChannel / SaleChannelProduct
SaleChannel: slug, identifier, status (mặc định ACTIVATED), name (i18n), description (i18n), merchantId, parentId.
SaleChannelProduct (join): productId, saleChannelId. Bị xóa cascade bởi DeletionPolicyService khi một kênh bị gỡ.
3.9 Category
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
name / description | i18n | name ✓ | — |
status | text | CategoryStatuses | |
discriminationType | text | TCategoryDiscriminationType (nhãn nhóm FE) | |
identifier | text | ✓ | — |
merchantId | text | null ⇒ category SYSTEM (dùng chung theo businessType) | |
parentId | text | Phân cấp tự tham chiếu |
Category.typechỉ là nhóm FE — nó không điều khiển hành vi tồn kho/bán.
3.10 Configuration
| Trường | Type | Bắt buộc | Mô tả |
|---|---|---|---|
principalType / principalId | text | Phạm vi chủ sở hữu (null ⇒ SYSTEM) | |
code | text | ✓ | Mã config; định dạng tích hợp provider {type}:{provider}:{action}:{credentialType} |
group | text | ✓ | ConfigurationGroups |
status | text | ✓ | ConfigurationStatuses |
environment | text | Phạm vi theo môi trường | |
credential | text | Ciphertext AES-256-GCM (che trong response) |
Unique partial trên
(group, code, principalId, principalType, environment).
3.11 Device / DiscriminationType / ReceiptTemplate / Setting
| Bảng | Trường chính |
|---|---|
Device | status (mặc định NEW), name (i18n), code, type, merchantId, hardwareInfo/softwareInfo (jsonb), pin, vendor |
DiscriminationType | scope, status, name (i18n), type, parentId, merchantId |
ReceiptTemplate | principal đa hình, name, locale, paperWidth, fontSize, isDefault, content (jsonb TReceiptContent) |
Setting | principal đa hình, status, túi giá trị metadata có kiểu |
3.12 Allocation (schema allocation)
| Bảng | Trường chính |
|---|---|
AllocationLayout | sơ đồ mặt bằng cấp cao nhất |
AllocationZone | name (i18n), layoutId, parentId (tự tham chiếu), style (jsonb) |
AllocationUnit | name (i18n), zoneId, placement/style (jsonb), capacity, status |
AllocationUsage(mức chiếm dụng) do@nx/salesở hữu và thay đổi; commerce chỉ sở hữu layout tĩnh.
4. Enum Status & Type
4.1 ProductVariantTypes
Nguồn:
core/.../public/product-variant/constants.ts.
| Giá trị | Const | Lưu kho | BOM |
|---|---|---|---|
000_STORABLE | STORABLE | ✓ | — |
100_CONSUMABLE | CONSUMABLE | — | — |
200_SERVICE | SERVICE | — | — |
300_KIT | KIT | — | ✓ (qua Material) |
301_COMBO | COMBO | — | ✓ (qua ProductVariant) |
400_MANUFACTURED | MANUFACTURED | ✓ | ✓ |
Tập helper: STOCKABLE_SET = {STORABLE, MANUFACTURED}, BOMABLE_SET = {KIT, COMBO, MANUFACTURED}.
4.2 ProductBundlerTypes
| Giá trị | Const | Ý nghĩa |
|---|---|---|
000_COMBO | COMBO | relatedVariantId là thành phần của combo |
100_ADDON | ADDON | addon miễn phí gắn vào variant host |
200_FBT | FBT | gợi ý "thường được mua cùng nhau" (có hướng) |
4.3 Status vòng đời
| Enum | Giá trị |
|---|---|
ProductStatuses / ProductVariantStatuses | DRAFT, ACTIVATED, DEACTIVATED, ARCHIVED |
MerchantStatuses / OrganizerStatuses / SaleChannelStatuses | tái dùng Statuses gồm ACTIVATED (mặc định) |
MerchantOnboardingSteps | BUSINESS, FINANCE_ACCOUNT (300), TAX_INFO (400), PRODUCT |
5. Bất biến xuyên thực thể
| Bất biến | Thực thi |
|---|---|
| Product aggregate là atomic (Product + Info + SYSTEM identifier + liên kết kênh + variant mặc định) | Một TX duy nhất trong ProductCreateService |
| Merchant aggregate atomic (merchant + policy + identifier + categories + channels) | Một TX duy nhất trong MerchantService |
| Onboarding tạo Organizer + Merchant + 2 PolicyDefinitions + SaleChannel mặc định một cách atomic | TX OrganizerService.onBoarding |
Product.slug unique theo merchantId; Merchant.slug unique theo organizerId | DB unique partial (deletedAt IS NULL) |
Sao chép sản phẩm đa merchant chỉ chạy khi syncMerchantIds.length > 0 | Bảo vệ ProductAggregate*Listener.pushJobToQueue |
Thông tin thuế merchant nằm trong metadata.tax, không phải cột; TaxInfo có thẩm quyền downstream | Merge metadata MerchantService → CDC |
| Thông tin đăng nhập provider không bao giờ trả về plaintext | EncryptService + giá trị hiển thị được che |
Tính duy nhất của Configuration | unique partial (group, code, principalId, principalType, environment) |
Hàng ProductBundler unique theo (type, leadVariantId, relatedVariantId) | DB unique partial |
6. Hành vi Soft-delete
| Thực thể | Soft-delete | Ghi chú |
|---|---|---|
| Tất cả thực thể commerce | ✓ | đánh dấu deletedAt; unique partial loại trừ hàng đã soft-delete |
| Bảo vệ xóa | — | DeletionPolicyService chặn xóa khi có lịch sử bán / chính sách nghiêm ngặt; archive thay vì xóa |