Inventory Service
@nx/inventory owns physical stock for a merchant: locations, items, stock buckets (on-hand / available / reserved), an immutable audit trail, vendor catalog, purchase orders, materials with bill-of-materials recipes, and inventory workflow tickets. It deducts stock when sale payments succeed (Kafka), explodes recipes when kitchen items change status, and emits events to finance on goods receipt.
1. Quick Reference
| Property | Value |
|---|---|
| Package | @nx/inventory |
| Code | SVC-00050-INVENTORY |
| Type | Microservice |
| Runtime | Bun |
| Base Class | VerifierApplication |
| Location | packages/inventory |
| Base Path | /v1/api/inventory |
| Dev Port | 31050 |
| Container Port | 3000 (external 31050) |
| Snowflake ID | 5 |
| DB Schema | inventory (17 tables — see Domain Model) |
| Binding Namespace | @nx/inventory |
2. Purpose & Scope
| Included | Excluded |
|---|---|
| Inventory locations (warehouses) with hierarchy + default-per-merchant | Sale quotation / quota-based reservation (P3) |
| Polymorphic InventoryItem (Material / ProductVariant) | Multi-currency stock valuation |
| Stock buckets (on-hand, available, reserved) per (item, location, lot, serial) | Full barcode-scanning integration (only data model) |
| Immutable InventoryTracking audit log | Stock-count audits with locking |
| 19 fixed tracking types + customizable reasons | Expiry / FEFO / batch tracking enforcement (data only) |
| Vendor + VendorItem M:N catalog with snapshots | Multi-level BOM yield/scrap enforcement |
| Purchase Orders: aggregate API, lifecycle, receive modes | Stock transfer between merchants |
| Materials catalog + recipes (BOM) + runtime explosion | Inventory valuation reports |
| Production orders | Direct mutation of quantityReserved from outside this service |
| Inventory tickets (transfer, adjust, count, return, scrap) | |
| Unit-of-measure 3-level catalog |
3. Tech Stack
External:
| Library | Purpose |
|---|---|
@venizia/ignis | IoC container, DI, BaseService, BaseController, ControllerFactory |
@venizia/ignis-helpers | Logger, KafkaProducerHelper, KafkaConsumerHelper, Redis helper |
@platformatic/kafka | Kafka client (idempotent producer, lz4 compression, ALL acks) |
hono | HTTP server (via IGNIS) |
@hono/zod-openapi | OpenAPI generator from Zod schemas |
@scalar/hono-api-reference | OpenAPI explorer at /doc |
drizzle-orm | DB access via PostgresCoreDataSource |
pg | PostgreSQL driver |
lodash | Utilities |
Internal:
| Package | Purpose |
|---|---|
@nx/core | All schemas, repositories (re-exported), VerifierApplication, KafkaTopics, CDCKafkaTopics, PurchaseOrderStatuses, MaterialRecipeStatuses, MerchantScopedService |
4. Project Structure
packages/inventory/
├── src/
│ ├── application.ts # VerifierApplication subclass
│ ├── index.ts # bootstrapApplication()
│ ├── migrate.ts # bootstrapMigration()
│ ├── common/
│ │ ├── constants.ts # InventoryTrackingNotes, ReceivePurchaseOrderItemModes
│ │ ├── keys.ts # BindingKeys (extends @nx/core)
│ │ ├── rest-paths.ts # 15 RestPaths
│ │ ├── types.ts # local type aliases
│ │ └── websocket.ts # InventoryWebSocketTopics, Rooms
│ ├── components/
│ │ ├── kafka/ # ApplicationKafkaComponent (5 inbound topics)
│ │ └── websocket/ # ApplicationWebSocketComponent
│ ├── controllers/ # 15 controllers (one folder each)
│ ├── datasources/ # PostgresCoreDataSource
│ ├── migrations/processes/ # 5 seed/backfill processes
│ ├── models/ # zod request/response schemas
│ ├── repositories/ # re-exports from @nx/core
│ └── services/ # 19 services
├── package.json
└── tsconfig.json5. Architecture
Detail: see Architecture.
6. Domain Snapshot
Full ERD + per-entity tables: see Domain Model.
7. Surface Summary
REST controllers — full reference rendered live from /v1/api/inventory/doc/openapi.json (live spec — Scalar viewer at /doc, gateway portal):
| Controller | Base path | Lifecycle/aggregate routes |
|---|---|---|
InventoryItemController | /inventory-items | merchant-scoped CRUD |
InventoryLocationController | /inventory-locations | + set-default, activate, deactivate, archive |
InventoryStockController | /inventory-stocks | CRUD |
InventoryTrackingController | /inventory-trackings | read-only CRUD (audit) |
InventoryIdentifierController | /inventory-identifiers | CRUD |
InventoryTicketController | /inventory-tickets | CRUD + lifecycle |
InventoryTicketItemController | /inventory-ticket-items | CRUD |
PurchaseOrderController | /purchase-orders | + aggregate, items, confirm, revert, receive, cancel, complete, close |
MaterialController | /materials | + aggregate |
MaterialIdentifierController | /material-identifiers | CRUD |
MaterialRecipeController | /material-recipes | + aggregate, flatten |
ProductionOrderController | /production-orders | CRUD |
VendorController | /vendors | + aggregate |
VendorItemController | /vendor-items | + set-preferred, activate, deactivate |
UnitOfMeasureController | /unit-of-measures | CRUD (system + merchant-scoped) |
Async surface — full reference in API Events:
| Direction | Channel | Count |
|---|---|---|
| Inbound | Kafka | 5 (PAYMENT_SUCCESS, KITCHEN_TICKET_ITEM_STATUS_CHANGED, MATERIAL_TRANSFERRED, MERCHANT CDC, PRODUCT_VARIANT CDC) |
| Outbound | Kafka | 3 (PURCHASE_ORDER_RECEIVED, MATERIAL_STOCK_CHANGED, MATERIAL_TRANSFERRED) |
| Outbound | WebSocket | 1 topic (observation/inventory/inventory-stock) × 3 room types (merchant / location / item) |
8. Components
| Component | File | Purpose |
|---|---|---|
ApplicationKafkaComponent | src/components/kafka/component.ts | Idempotent producer + consumer (autocommit=false); subscribes to 5 topics; dispatches via _dispatchMessage switch |
ApplicationWebSocketComponent | src/components/websocket/component.ts | Redis-backed WS emitter for stock change broadcasts |
| Redis cache (optional) | bound at BindingKeys.APPLICATION_REDIS_CACHE | Authorization permission cache (lookup by Casbin) |
9. Services
| Service | File | One-liner |
|---|---|---|
InventoryService | inventory.service.ts | Polymorphic principal refs + multi-location seeding + PO receive write |
InventoryWorkerService | inventory-worker.service.ts | Kafka handlers: payment success, material transferred, merchant CDC, product variant CDC |
InventoryStockService | inventory-stock.service.ts | Merchant-scoped CRUD on stock buckets |
InventoryTrackingService | inventory-tracking.service.ts | Merchant-scoped CRUD on audit trail |
InventoryItemService | inventory-item.service.ts | Merchant-scoped CRUD on polymorphic items |
InventoryIdentifierService | inventory-identifier.service.ts | Merchant-scoped CRUD on SKU/barcode/serial identifiers |
InventoryLocationService | inventory-location.service.ts | Locations + setDefault/activate/deactivate/archive lifecycle |
InventoryTicketService | inventory-ticket.service.ts | Merchant-scoped CRUD on workflow tickets |
InventoryTicketItemService | inventory-ticket-item.service.ts | Ticket lines + linked stock adjust |
PurchaseOrderService | purchase-order.service.ts | Full PO lifecycle, aggregate API, receive (OVERRIDE/ACCUMULATIVE) |
PurchaseOrderItemService | purchase-order-item.service.ts | Line item updates + summary recalc |
VendorService | vendor.service.ts | Vendor + aggregate (Vendor + VendorItem batch) |
VendorItemService | vendor-item.service.ts | M:N catalog: setPreferred, activate, deactivate, recordPurchase, batch upsert/omit |
MaterialService | material.service.ts | Material catalog + aggregate (with optional VendorItem batch) |
MaterialIdentifierService | material-identifier.service.ts | SYSTEM/SLUG identifier CRUD |
MaterialRecipeService | material-recipe.service.ts | Recipe (BOM) aggregate + multi-level flatten |
MaterialWorkerService | material-worker.service.ts | Kitchen ticket consume, sale-order material reserve, recipe explosion |
ProductionOrderService | production-order.service.ts | Production order CRUD |
UnitOfMeasureService | unit-of-measure.service.ts | System + merchant UoM catalog |
10. Repositories
| Repository | Source | Notable Custom Methods |
|---|---|---|
InventoryStockRepository | @nx/core | adjustStock — atomic UPDATE with forceNonNegative guard |
InventoryLocationRepository | @nx/core | ensureDefaultLocation, setDefaultAtomic, findParentChain |
InventoryTrackingRepository | @nx/core | (CRUD only — immutable audit, no custom mutators) |
InventoryItemRepository | @nx/core | ensureInventoryItem (idempotent by (merchantId, itemType, itemId)) |
VendorItemRepository | @nx/core | setPreferredAtomic |
PurchaseOrderRepository | @nx/core | updateSummaryFromItems |
InventoryIdentifierRepository | @nx/core | — |
InventoryTicketRepository | @nx/core | — |
InventoryTicketItemRepository | @nx/core | — |
MaterialRepository | @nx/core | — |
MaterialIdentifierRepository | @nx/core | — |
MaterialRecipeRepository | @nx/core | — |
MaterialRecipeItemRepository | @nx/core | — |
ProductionOrderRepository | @nx/core | — |
PurchaseOrderItemRepository | @nx/core | — |
VendorRepository | @nx/core | — |
UnitOfMeasureRepository | @nx/core | — |
ProductRepository, ProductVariantRepository, CategoryRepository, DiscriminationTypeRepository, PermissionRepository, PolicyDefinitionRepository | @nx/core | Cross-package read access |
11. Entry Points
| File | Purpose |
|---|---|
src/index.ts | Service entry → bootstrapApplication() |
src/migrate.ts | Migration entry → bootstrapMigration() |
src/application.ts | Application extends VerifierApplication |
12. Configuration
Env vars + feature flags + seeded data: see Configuration.
13. Operations
Deployment + observability + security + runbook: see Operations.
14. Related Pages
Concepts — why/how the system is shaped:
- Architecture
- Domain Model
- Integration — sale, finance, commerce, identity contracts
Reference — lookup tables:
- API Events
- Configuration
- Operations
- REST endpoints — live OpenAPI at
/v1/api/inventory/doc/openapi.json(live spec — Scalar viewer at/doc, gateway portal)
Features — deep dives:
- Inventory Stock
- Inventory Tracking
- Inventory Location
- Inventory Ticket
- Purchase Order
- Material & BOM
- Vendor & VendorItem
Decisions:
Product module (what this powers):
- Inventory module — business/user view, URD, test cases, PRDs
- Delivery › Traceability Matrix