Skip to content

ADR-0003. Trường phân biệt type của product variant + quan hệ ProductBundler

TrườngGiá trị
StatusAccepted
Ngày2026-04-10
Người quyết địnhPhat Nguyen
Thay thế-

Bối cảnh

  • Catalog phải biểu diễn nhiều hành vi khác nhau: 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 (định mức nguyên vật liệu), combo ảo, addon miễn phí, và gợi ý "thường được mua cùng nhau".
  • Một mô hình trước đây đã nạp chồng Category.type (COMBO/ADDON/FBT) để điều khiển hành vi tồn kho và bán hàng. Cách này dễ vỡ: phân loại lại một sản phẩm có thể lật nó qua lại giữa vật lý và ảo, trong khi category về bản chất chỉ là chuyện gom nhóm ở phía FE.
  • Inventory và sale cần một tín hiệu cấu trúc duy nhất, ổn định để trả lời "cái này có lưu kho không?" và "khi bán nó có tách thành các thành phần không?".

Quyết định

Tách vấn đề này thành một trường phân biệt cấu trúc theo từng variant và một bảng quan hệ riêng:

  1. ProductVariant.type (ProductVariantTypes, core/.../public/product-variant/constants.ts) là trường phân biệt cấu trúc duy nhất:
    • STORABLE (mặc định) / MANUFACTURED → có lưu kho (STOCKABLE_SET).
    • CONSUMABLE / SERVICE → không lưu kho.
    • KIT / COMBO / MANUFACTURED → có BOM (BOMABLE_SET).
    • COMBO là ảo - không có InventoryItem; khi thêm vào giỏ nó tách thành các variant thành phần.
  2. ProductBundler là bảng quan hệ duy nhất cho COMBO / ADDON / FBT (ProductBundlerTypes), khóa theo (type, leadVariantId, relatedVariantId). ADDON và FBT là quan hệ, không phải type của variant - một addon variant là một PV vật lý thông thường; chính hàng quan hệ mới biến nó thành addon.
  3. Category.type trở thành nhãn gom nhóm FE thuần tuý - không có gì trong inventory/sale rẽ nhánh dựa trên nó nữa.

Việc tách combo khi thêm vào giỏ được triển khai trong @nx/sale / @nx/inventory - xem ADR liên package.

Hệ quả

ƯuNhược
Tín hiệu cấu trúc ổn định, độc lập với việc phân loạiHai khái niệm (type của variant và type của bundler) - không được gộp lẫn
Phân loại lại một sản phẩm là an toàn (không thể lật vật lý↔ảo)Cần migration để backfill type từ dữ liệu cũ dựa trên category
Một bảng quan hệ bao quát gọn COMBO/ADDON/FBT với basis giá tuỳ chọnTính có hướng của FBT đòi hỏi một hàng cho mỗi chiều
Inventory chỉ khởi tạo item cho các variant thuộc STOCKABLE_SETConsumer phải đọc các helper ProductVariantTypes, không phải category

Phương án đã cân nhắc

Tùy chọnƯuNhượcVì sao bị từ chối
Giữ Category.type làm trường phân biệtKhông phải đổi schemaDễ vỡ; phân loại lại làm lật hành vi; trộn lẫn việc gom nhóm với cấu trúcĐây chính là nguyên nhân gốc của lỗi đang được sửa
Mỗi quan hệ một bảng riêng (combo/addon/FBT)Tường minhBa bảng gần như giống hệt nhau; logic trùng lặpMột bảng ProductBundler với cột type đơn giản hơn
Dùng cờ boolean trên ProductVariant (isCombo, isKit…)Đơn giảnCác cờ loại trừ lẫn nhau mô hình hoá một enum hữu hạn rất kémMột enum type có kiểu duy nhất mới đú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
  • Liên package: developer/packages/inventory/decisions/0006-combo-explosion-at-cart-add

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.