Skip to content

ADR-0001. Polymorphic InventoryItem (itemType + itemId)

FieldValue
StatusAccepted
Date2026-01-15
Decidersinventory-team
Supersedes

Context

  • BANA has two distinct things to track stock for: Material (raw ingredients) and ProductVariant (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

ProsCons
Single stock bucket model regardless of principalNo DB-level FK to principal — service must validate itemType + itemId
Easy to add BUNDLE, KIT, etc. without schema migrationPolymorphic queries can't use a single FK index
InventoryStockRepository.adjustStock works uniformlyIdempotent upsert (ensureInventoryItem) requires service-layer lookup
Sale + PO flows are agnostic to principal typeCasts/discriminants needed in service layer

Alternatives Considered

OptionProsConsWhy rejected
Separate MaterialStock + ProductVariantStock tablesStrong DB-level FKsTwo parallel implementations of adjustStock, tracking, identifiersMaintenance cost; duplicates whenever stock model evolves
InventoryStock directly references both materialId + productVariantId (nullable)One tableXOR constraint complex; queries always filter on typeHalf-rejected pattern, not used in Drizzle ecosystem
Bundle into Product umbrella with subtypeOO-friendlyMixes catalog (Product) with stock (Inventory) — wrong layerConflates concerns

References

  • core/src/models/schemas/inventory/inventory-item/schema.ts
  • inventory/src/services/inventory.service.ts:96-110 (loadPrincipalRefs)

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