ADR-0001. Polymorphic InventoryItem (itemType + itemId)
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-01-15 |
| Deciders | inventory-team |
| Supersedes | — |
Context
- BANA has two distinct things to track stock for:
Material(raw ingredients) andProductVariant(sellable SKUs). - Both share the same downstream stock model (
InventoryStock,InventoryTracking, locations, identifiers, vendor catalog). - Need exactly one bucket per
(merchant × principal × location × lot × serial)regardless of principal type.
Decision
Introduce a single InventoryItem row keyed by (merchantId, itemType, itemId) where itemType ∈ {MATERIAL, PRODUCT_VARIANT} (generated via generatePrincipalColumnDefs({ discriminator: 'item' })). InventoryStock references inventoryItemId; InventoryTracking references inventoryStockId (and through it, the item). Principals (Material, ProductVariant) are never referenced directly from the stock model.
Consequences
| Pros | Cons |
|---|---|
| Single stock bucket model regardless of principal | No DB-level FK to principal — service must validate itemType + itemId |
Easy to add BUNDLE, KIT, etc. without schema migration | Polymorphic queries can't use a single FK index |
InventoryStockRepository.adjustStock works uniformly | Idempotent upsert (ensureInventoryItem) requires service-layer lookup |
| Sale + PO flows are agnostic to principal type | Casts/discriminants needed in service layer |
Alternatives Considered
| Option | Pros | Cons | Why rejected |
|---|---|---|---|
Separate MaterialStock + ProductVariantStock tables | Strong DB-level FKs | Two parallel implementations of adjustStock, tracking, identifiers | Maintenance cost; duplicates whenever stock model evolves |
InventoryStock directly references both materialId + productVariantId (nullable) | One table | XOR constraint complex; queries always filter on type | Half-rejected pattern, not used in Drizzle ecosystem |
Bundle into Product umbrella with subtype | OO-friendly | Mixes catalog (Product) with stock (Inventory) — wrong layer | Conflates concerns |
References
core/src/models/schemas/inventory/inventory-item/schema.tsinventory/src/services/inventory.service.ts:96-110(loadPrincipalRefs)