ADR-0003. Bộ phân biệt type của product variant + quan hệ ProductBundler
| Trường | Giá trị |
|---|---|
| Status | Accepted |
| Ngày | 2026-04-10 |
| Người quyết định | commerce-team, inventory-team |
| Thay thế | — |
Bối cảnh
- Catalog phải biểu diễn nhiều hành vi: hàng vật lý có tồn kho, hàng tiêu hao không lưu kho, dịch vụ, kit/hàng sản xuất (bill-of-materials), combo ảo, addon miễn phí, và gợi ý "thường được mua cùng nhau".
- Một mô hình trước đó nạp chồng
Category.type(COMBO/ADDON/FBT) để điều khiển hành vi tồn kho và bán. Điều này dễ vỡ: re-categorize một sản phẩm có thể lật nó giữa vật lý và ảo, và category về cơ bản là mối quan tâm nhóm FE. - Inventory và sale cần một tín hiệu cấu trúc đơn, ổn định cho "cái này có lưu kho không?" và "nó có nổ tung thành thành phần khi bán không?".
Quyết định
Tách mối quan tâm thành một bộ phân biệt cấu trúc theo từng variant và một bảng quan hệ riêng:
ProductVariant.type(ProductVariantTypes,core/.../public/product-variant/constants.ts) là bộ phân biệt cấu trúc duy nhất:STORABLE(mặc định) /MANUFACTURED→ lưu kho (STOCKABLE_SET).CONSUMABLE/SERVICE→ không lưu kho.KIT/COMBO/MANUFACTURED→ có BOM (BOMABLE_SET).COMBOlà ảo — không cóInventoryItem; nó nổ tung khi thêm vào giỏ thành các variant thành phần.
ProductBundlerlà bảng quan hệ đơn cho COMBO / ADDON / FBT (ProductBundlerTypes), khóa theo(type, leadVariantId, relatedVariantId). ADDON và FBT là quan hệ, không phải variant type — một addon variant là một PV vật lý thông thường; hàng quan hệ làm nó thành addon.Category.typetrở thành nhãn nhóm FE thuần túy — không có gì trong inventory/sale rẽ nhánh theo nó.
Việc nổ combo khi thêm vào giỏ được triển khai trong @nx/sale / @nx/inventory — xem ADR cross-package.
Hệ quả
| Ưu | Nhược |
|---|---|
| Tín hiệu cấu trúc ổn định độc lập với phân loại | Hai khái niệm (variant type + bundler type) — không được gộp lẫn |
| Re-categorize một sản phẩm an toàn (không thể lật vật lý↔ảo) | Cần migration để backfill type từ dữ liệu dựa-trên-category cũ |
Một bảng quan hệ bao quát gọn COMBO/ADDON/FBT với basis giá tùy chọn | Tính có hướng FBT yêu cầu một hàng cho mỗi hướng |
Inventory seed item chỉ cho variant STOCKABLE_SET | Consumer phải đọc helper ProductVariantTypes, không phải category |
Phương án đã cân nhắc
| Tùy chọn | Ưu | Nhược | Vì sao bị từ chối |
|---|---|---|---|
Giữ Category.type làm bộ phân biệt | Không đổi schema | Dễ vỡ; re-categorize lật hành vi; gộp nhóm với cấu trúc | Nguyên nhân gốc của bug đang được sửa |
| Bảng riêng cho mỗi quan hệ (combo/addon/FBT) | Tường minh | Ba bảng gần như giống nhau; logic trùng lặp | Một ProductBundler với type đơn giản hơn |
Cờ boolean trên ProductVariant (isCombo, isKit…) | Đơn giản | Cờ loại trừ lẫn nhau mô hình hóa enum hữu hạn kém | Một enum type có kiểu đơn là đúng theo code style |
Tham khảo
packages/core/src/models/schemas/public/product-variant/constants.ts(ProductVariantTypes,STOCKABLE_SET,BOMABLE_SET)packages/core/src/models/schemas/public/product-bundler/{schema,constants}.ts- Cross-package:
developer/packages/inventory/decisions/0006-combo-explosion-at-cart-add