Integration
1. Sister Services
| Sister | Direction | Surface | Auth | Failure Mode | Idempotency |
|---|---|---|---|---|---|
@nx/sale | ← | Kafka PAYMENT_SUCCESS | — | at-least-once delivery; consumer skips processed via tracking lookup | (SALE_ORDER, saleOrderId, stockId) |
@nx/sale | ← | Kafka KITCHEN_TICKET_ITEM_STATUS_CHANGED | — | at-least-once | per (saleOrderId, kitchenTicketItemId, materialId) |
@nx/sale | → | Kafka MATERIAL_STOCK_CHANGED | — | post-commit fire-and-forget | per stock event id |
@nx/finance | → | Kafka PURCHASE_ORDER_RECEIVED | — | post-commit fire-and-forget; only when payments[] non-empty | (POREC, purchaseOrderId) consumer-side |
@nx/commerce | ← | HTTP — direct call to InventoryService.createInventoryForProductVariant / updateInventoryForProductVariant (in shared TX) | JWT (service-to-service) | TX rollback on failure | ensureInventoryItem |
@nx/commerce (CDC) | ← | Kafka CDC nx.seller.public.product_variant (Debezium) | — | at-least-once | ensureInventoryItem is idempotent |
@nx/identity (CDC) | ← | Kafka CDC nx.seller.public.merchant (Debezium) | — | at-least-once | ensureDefaultLocation idempotent |
@nx/identity | → | HTTP — JWT verification via JWKS (/jw-certs) | JWT | retry / circuit-break (gateway) | request-id propagated |
@nx/identity | → | HTTP — PolicyDefinitionService permission lookup | JWT | Redis cache fallback | per (role, action) |
@nx/signal | → | WebSocket emission via ApplicationWebSocketComponent | — | best-effort delivery | none (broadcast) |
2. External Systems
N/A — inventory does not call any external (third-party) APIs directly. All third-party integrations (e.g., e-invoice, payment) are owned by other packages.
3. Critical Cross-Service Flows
3.1 Sale Payment → Stock Deduction (most critical)
Contract:
- Sale guarantees
PAYMENT_SUCCESSis emitted exactly once per status transition (post-commit). - Inventory guarantees idempotent processing per
(saleOrderId, stockId). - Material reservation runs after product deduction within the same handler call (sequential, not parallel).
3.2 PO Receive → Finance Expense Recording
Contract:
- Stock + tracking + vendor snapshot are atomic (single TX).
- Kafka emit happens AFTER commit — if emit fails, finance is notified via reconciliation job (TBD), not in-band rollback.
- Finance treats
PURCHASE_ORDER_RECEIVEDas authoritative: idempotent on(POREC, purchaseOrderId).
3.3 Merchant Onboarding → Default Location Seed
Contract: idempotent. Re-delivery causes no-op.
3.4 ProductVariant Create → Inventory Seed
Two parallel paths:
Path A — direct HTTP (synchronous, in commerce's TX):
Path B — CDC (asynchronous, retroactive):
Both paths converge on the same idempotent ensureInventoryItem upsert.
4. Contract Stability
| Surface | Stability | Versioning |
|---|---|---|
HTTP /v1/api/inventory/* | stable | URL prefix /v1/ |
Kafka topic payment.success | stable | payload field-additive only |
Kafka topic purchase-order.received | stable | payload field-additive only |
Kafka topic material.stock-changed | beta | may add fields |
Kafka topic material.transferred | beta | — |
CDC topics (nx.seller.public.*) | stable | controlled by Debezium config |
WebSocket topic observation/inventory/inventory-stock | stable | room paths versioned |