Skip to content

PRD: POS & kitchen order

ModuleSalePRD IDPRD-KIT-001
StatusReady to devFEATKIT · BANA-1430
EpicPlaneBANA-1561
Date2026-03-23Versionv1.0
Packages@nx/saleURDKIT
SurfaceSale · POS
OwnerPhát Nguyễn

TL;DR

Sends F&B order items to the kitchen as tickets, routes them to named preparation stations, and tracks cooking in real time - no reloads, no polling. Per-item statuses auto-advance the ticket; void-and-resend means a sent item is never edited in place.

1. Context & Problem

Orders already covers cart → checkout → payment, but full-service F&B needs the back-of-house half. Today there is no kitchen-side entity: items live only on the order, so the kitchen has no work queue, no per-item cooking state, and no way to push status back to the floor. For the HKD/SME restaurants and cafés BANA targets, that gap blocks the most common F&B pattern - fire to kitchen, cook, serve - making the POS useless beyond a quick counter.

This increment builds kitchen order management (KDS) on top of the existing order lifecycle: tickets sent from an order to the kitchen, named stations to route them, per-item cooking statuses, and live status propagation via real-time updates.

2. Goals & Non-Goals

Goals

  • Send order items to the kitchen as a ticket with line items, with an idempotent send so a duplicate fire never produces a second ticket (KIT).
  • A full ticket lifecycle (PENDING → PROCESSING → READY → COMPLETED / VOIDED) and a per-item cooking lifecycle (PENDING → COOKING → READY → SERVED / VOIDED).
  • Auto-progression - the ticket status advances automatically from its item statuses.
  • Void-and-resend semantics - a sent item is voided and re-fired, never edited in place.
  • Named kitchen stations per merchant (STA) - the station entity is built; the category-routing and per-station printer fields exist on the model but are not yet consumed by the backend (the station to fire to is chosen by the caller, and printing/auto-print is a front-end concern).
  • Real-time updates to kitchen displays and dashboards on ticket create / update / complete.
  • A per-item cooking-status change emits an event that drives downstream stock consumption - in the current code stock is consumed when an item reaches ready (marking an item served does not itself trigger consumption).

Non-Goals

  • A dedicated kitchen display application - this delivers the back end plus the POS front end only (Planned).
  • Refund / return flow and stock-mutation internals - owned by Inventory.
  • Table-layout / seating management (Planned).
  • POS shift sessions (POS) - listed for area completeness; session handling is not part of this increment.

3. Success Metrics

MetricTarget / signal
Real-time freshnessKitchen displays reflect a status change with no manual reload; real-time fan-out on every create / update / complete
Send integrityZero duplicate tickets for a repeated fire (idempotent send holds under retries)
Auto-progression accuracyTicket status always matches the rollup of its item statuses
Routing coverageItems land at the station mapped to their product category (target; category routing is not yet wired in the backend - the firing station is chosen by the caller)
Service correctnessA cooking-status change reliably triggers stock consumption exactly once (consumption fires when an item reaches ready in the current code)

4. Personas & Use Cases

PersonaGoal in this feature
CashierFire order items to the kitchen and see when they are ready to serve
Kitchen staffWork a live ticket queue, progress items cooking → ready → served, void mistakes
Manager / OwnerConfigure stations, category routing, and per-station printers

Core flow: cashier fires items → ticket appears on the station's display → kitchen staff move items cooking → ready → served, ticket auto-progresses, floor sees status live. Mistakes are voided and re-fired, never edited.

5. User Stories

  • As a cashier, I want to send order items to the kitchen in one action, so the back-of-house gets a work ticket immediately.
  • As a cashier, I want a repeated fire to be idempotent, so a double-tap never duplicates a ticket.
  • As kitchen staff, I want each item to carry its own cooking status, so I can track a multi-item ticket precisely.
  • As kitchen staff, I want the ticket to auto-progress from its items, so I don't maintain a separate ticket state by hand.
  • As kitchen staff, I want to void and resend a sent item, so corrections never silently mutate an in-flight ticket.
  • As a manager, I want to route product categories to named stations with their own printer config, so each station only sees and prints its own work. (The routing and printer fields exist on the station model but are not yet acted on by the backend.)
  • As a cashier, I want kitchen status to update displays in real time, so the floor knows when to serve without asking.

6. Functional Requirements

#RequirementURD ref
FR-1Send order items to the kitchen - creates a ticket with item linesURD-KIT-001
FR-2Idempotent send - a duplicate send produces the same ticketURD-KIT-002
FR-3Ticket lifecycle PENDING → PROCESSING → READY → COMPLETED / VOIDEDURD-KIT-003
FR-4Per-item cooking lifecycle PENDING → COOKING → READY → SERVED / VOIDEDURD-KIT-004
FR-5Ticket status auto-progresses from its item statusesURD-KIT-005
FR-6Changes use void-and-resend - sent items are not edited in placeURD-KIT-006
FR-7Rush flag and per-order sequence for ticket orderingURD-KIT-007
FR-8Real-time updates to kitchen displays and dashboardsURD-KIT-008
FR-9A cooking-status change emits an event that triggers stock consumption - in the current code consumption fires when an item reaches ready, not on servedURD-KIT-009
FR-10Create named stations per merchant (i18n)URD-STA-001
FR-11Route product categories to stations - data model only: the category-routing field exists but is not yet consumed by the backend (the firing station is chosen by the caller)URD-STA-002
FR-12Per-station printer config with auto-print - data model only: the printer/auto-print fields exist but are not yet consumed by the backendURD-STA-003

Full requirement text and acceptance criteria live in the Orders URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Real-timeTicket create / update / complete fan out via real-time updates; the POS front end subscribes for live status
IdempotencySend is keyed so retries collapse to a single ticket; no duplicate kitchen work
Tenancy & authzAll operations confined to the user's own merchant; permission-gated
Data integrityTicket status is always a deterministic rollup of item statuses; corrections are void-and-resend, never in-place edits
ConsistencySend and lifecycle transitions are transactional; partial failures don't leave orphan tickets
i18nStation names and user-facing statuses are bilingual ({ en, vi })

8. UX & Flows

Key surface: the kitchen-ticket views live in the POS front end, which subscribes to the real-time stream for live ticket/item status; station and routing config is managed per merchant.

9. Data & Domain

EntityRole
Kitchen ticketThe ticket sent to the kitchen - status, rush flag, per-order sequence, station assignment
Kitchen ticket lineA ticket line - references the order item, carries its own cooking status
Preparation stationA named preparation area (i18n); carries category-routing and printer-config fields on the model that are not yet consumed by the backend

Conceptual only - full schema and invariants in the sale domain model.

10. Dependencies & Assumptions

Depends on

  • Sale Order (URD-ORD) - tickets are fired from order items.
  • Product categories (Product) - station routing maps categories to stations.
  • Inventory (Inventory) - a per-item cooking-status change triggers stock consumption (consumed when the item reaches ready in the current code).
  • Real-time transport - for live status fan-out.

Assumptions

  • The merchant runs a full-service F&B flow (fire-to-kitchen), not counter-only.
  • Stations and category routing are configured before items are fired.
  • Clients (e.g. the POS front end) hold an active real-time subscription to receive live updates.

11. Risks & Open Questions

Risk / questionMitigation / status
Duplicate fire creating two ticketsSend is idempotent via key; retries collapse to one ticket
Ticket status drifting from item statusesStatus is a deterministic auto-rollup, not hand-maintained
Editing a sent item in placeDisallowed by design - void-and-resend is the only correction path
Missed real-time update leaving a stale displayDisplays subscribe to create / update / complete; reconnect re-syncs
No dedicated KDS app yetBack end + POS front-end surface ships now; standalone KDS app is Planned

12. Release Plan & Launch Criteria

AspectPlan
PhaseP2 - see Orders feature catalog (KIT, STA Built)
RolloutAll merchants; no feature flag
MigrationNew kitchen entities; no data backfill
Launch criteriaFire → ticket → cooking → ready/served verified end-to-end; idempotent send holds; auto-progression matches item statuses; live updates reach the POS front end; stock consumption fires on the cooking-status event (currently on ready). Automatic category-to-station routing and per-station auto-print are not yet wired
MonitoringTicket volume per merchant, send error / duplicate rate, real-time delivery health, served-to-stock consumption consistency

13. FAQ

Can a sent kitchen item be edited? No - sent items are never edited in place. Use void-and-resend: void the item and fire a new one.

What happens if a fire is sent twice? Nothing duplicates - send is idempotent by key, so a repeated fire resolves to the same ticket.

How does the ticket status change? It auto-progresses from its item statuses; there is no separate hand-maintained ticket state.

Where do tickets show up? On the routed station's display in the POS front end, updated live via real-time updates - no reload needed. A dedicated KDS app is Planned.

Does the cooking flow move stock? Yes - a per-item cooking-status change emits an event that Inventory acts on; in the current code stock is consumed when an item reaches ready (the served status does not itself trigger consumption). Stock consumption is owned by Inventory.

Is this the POS shift session feature? No - POS sessions (URD-POS) belong to the same feature line but are a separate increment; this PRD covers kitchen tickets and stations.

References

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