M1. Transfer domain model and status machine
Create server-side transfer aggregate with states draft, requested, approved, dispatched, received, reconciled, cancelled.
Engineering plan
Implementation plan for adding restaurant-to-restaurant stock transfers across central kitchen, prep kitchen, and storefront inventory ledgers. Optimized for the engineer picking up backend and UI work this sprint.
Milestones
Use the filter to isolate the track you are actively implementing. Default view shows the full dependency order.
Create server-side transfer aggregate with states draft, requested, approved, dispatched, received, reconciled, cancelled.
Add source-location reservation on approval and destination receipt posting on receive. Prevent negative stock and duplicate dispatch posting.
Expose create, list, approve, dispatch, and receive endpoints with line-level variance notes and actor attribution.
Ship request composer for managers, dispatch checklist for source site, and receipt confirmation for destination site with barcode fallback.
Enable for central kitchen, Midtown, and Riverside. Measure transfer cycle time, variance rate, and manual stock adjustments avoided.
Cut over from spreadsheet-based transfers, freeze ad hoc adjustment shortcut, and document exception handling for damaged or partial receipts.
Working model
Keep business logic aligned to this order. Reservation happens before physical dispatch.
Manager selects source, destination, line items, need-by date, and justification.
Source approver validates available stock; system reserves requested quantity.
Picker confirms packed quantity, prints slip, and posts dispatch event once.
Destination records received quantity, flags variance, and posts receipt into local stock.
Target dates
State machine, actor roles, audit trail schema, feature flag scaffolding.
Reservation writer, negative stock guardrails, migration rehearsal on staging copy.
Create, approve, dispatch, receive endpoints plus transfer list and detail surfaces.
Approval queue, dispatch checklist, receipt variance screen, printable transfer slip.
Three-site pilot with shadow reconciliation and daily review of variance events.
Enable all stores, retire spreadsheet flow, and publish support runbook and training.
Schema
| Table | Key columns | Purpose |
|---|---|---|
inventory_transfers |
id, source_location_id, dest_location_id, status, requested_by, approved_by |
Header record for lifecycle, actors, timing, and feature-flag rollout metadata. |
inventory_transfer_lines |
transfer_id, ingredient_id, uom, requested_qty, packed_qty, received_qty |
Line-level quantities, variance notes, and receiving outcomes. |
inventory_reservations |
reservation_id, transfer_id, location_id, ingredient_id, qty_reserved |
Separates reserved stock from on-hand stock after approval, before dispatch. |
inventory_transfer_events |
event_id, transfer_id, event_type, actor_id, idempotency_key, payload_json |
Immutable audit history for approval, dispatch, receipt, reconciliation, and cancellation. |
API contract
Keep writes explicit and idempotent. The client must never patch stock directly.
Required: sourceLocationId, destinationLocationId, needByDate,
lines[], reasonCode. Reject if source and destination match.
Approval reserves stock. Dispatch accepts packedQty per line and requires an
Idempotency-Key header to prevent duplicate stock postings.
Receiving may post less than packed quantity. Any variance over 5% requires a reason code and creates a follow-up reconciliation task.
Rollout stages
| Stage | Audience | Guardrails | Success metric |
|---|---|---|---|
| Stage 0: Internal staging | Engineering + ops QA | Seeded stock data, synthetic transfers, migration rollback ready | All contract tests green, no ledger drift after replay |
| Stage 1: Pilot shadow mode | 3 locations, no accounting cutover | Spreadsheet remains source of truth for 3 days | Variance between system and manual log below 2% |
| Stage 2: Pilot authoritative | Same 3 locations | Ops manager approves all transfers, daily exception review | Median cycle time under 45 minutes |
| Stage 3: Regional rollout | All city stores | Feature flag by location, support runbook live | Manual stock adjustments reduced by 60% |
Retrying dispatch after a flaky network response could double-deduct source inventory.
Mitigation: Require idempotency keys and store dispatch event hash before ledger mutation.
Manual stock adjustments at source location may conflict with reserved quantities.
Mitigation: Show reserved vs available in adjustment tooling and block negative available stock.
Destination managers often receive from phones in back-of-house areas with weak connectivity.
Mitigation: Large step-by-step receipt UI, offline draft capture, and printable dispatch slip.
Teams may not know whether missing quantity should be re-shipped, adjusted, or discarded.
Mitigation: Force a variance reason and create reconciliation task automatically.
Store leads are used to spreadsheet transfers and may bypass the new flow during rush periods.
Mitigation: Limit legacy shortcut after GA and publish a one-page training guide.
Existing stock movement reports may omit transfer reservations and show confusing deltas.
Mitigation: Add transfer event dimensions before pilot review starts.
Acceptance criteria
Open questions
Can any destination manager request from any source site, or do transfers need a regional approval matrix?
Some ingredients move in cases while stores count eaches. Should conversion happen at request time or receipt time?
Do we need a photo attachment or signature capture on dispatch for third-party runners?
Should cross-location transfers create accounting entries immediately, or continue as operational-only movements?