ADR-0001. InventoryItem đa hình (itemType + itemId)
| Trường | Giá trị |
|---|---|
| Status | Accepted |
| Date | 2026-01-15 |
| Deciders | inventory-team |
| Supersedes | — |
Bối cảnh
- BANA có hai loại đối tượng riêng biệt cần theo dõi stock:
Material(nguyên liệu thô) vàProductVariant(SKU bán được). - Cả hai dùng chung mô hình stock phía dưới (
InventoryStock,InventoryTracking, locations, identifiers, vendor catalog). - Cần đúng một bucket cho mỗi
(merchant × principal × location × lot × serial)bất kể loại principal.
Quyết định
Dùng một bảng InventoryItem duy nhất, key theo (merchantId, itemType, itemId) với itemType ∈ {MATERIAL, PRODUCT_VARIANT} (sinh qua generatePrincipalColumnDefs({ discriminator: 'item' })). InventoryStock tham chiếu inventoryItemId; InventoryTracking tham chiếu inventoryStockId (và qua đó tới item). Principal (Material, ProductVariant) không bao giờ được tham chiếu trực tiếp từ stock model.
Hệ quả
| Pros | Cons |
|---|---|
| Một mô hình stock bucket cho mọi loại principal | Không có FK ở cấp DB tới principal — service phải tự validate itemType + itemId |
Dễ thêm BUNDLE, KIT, v.v. mà không cần migration schema | Query đa hình không thể dùng một index FK duy nhất |
InventoryStockRepository.adjustStock hoạt động đồng nhất | Upsert idempotent (ensureInventoryItem) cần lookup ở service-layer |
| Luồng Sale + PO không phụ thuộc loại principal | Cần cast/discriminant ở service layer |
Phương án thay thế đã cân nhắc
| Phương án | Pros | Cons | Lý do từ chối |
|---|---|---|---|
Tách bảng MaterialStock + ProductVariantStock | FK chặt ở cấp DB | Hai cài đặt song song của adjustStock, tracking, identifiers | Chi phí bảo trì; nhân đôi mỗi khi stock model phát triển |
InventoryStock tham chiếu trực tiếp cả materialId + productVariantId (nullable) | Một bảng | Constraint XOR phức tạp; query luôn phải filter theo type | Pattern nửa-từ-chối, không dùng trong hệ Drizzle |
Gói vào Product umbrella với subtype | OO-friendly | Trộn lẫn catalog (Product) với stock (Inventory) — sai layer | Trộn lẫn concern |
Tham chiếu
core/src/models/schemas/inventory/inventory-item/schema.tsinventory/src/services/inventory.service.ts:96-110(loadPrincipalRefs)