Skip to content

PRD: POS & kitchen order

ModuleOrders (CORE-07)PRD IDPRD-KIT-001
StatusShippedOwnerOrders squad
Date2026-03-23Versionv1.0
Packages@nx/sale · @nx/core · apps/sale-rendererURDKIT · STA · POS

TL;DR

Lets a full-service F&B venue push order items to the kitchen as tickets and watch them move through cooking in real time, without anyone reloading a screen. Tickets route to named preparation stations, progress through per-item cooking statuses that auto-advance the ticket, and use void-and-resend so a sent item is never edited in place. The result: the back-of-house gets a live, accurate work queue and the floor sees status the moment the kitchen touches it.

1. Context & Problem

Orders already covers the cart-to-checkout-to-payment lifecycle, but a full-service F&B venue needs the back-of-house half: order items must reach the kitchen, progress through cooking, and update preparation displays without anyone reloading a screen. Today there is no kitchen-side entity at all - items live only on the sale order, so the kitchen has no work queue, no per-item cooking state, and no way to push status back to the floor. For HKD/SME restaurants and cafés that KICKO targets, that gap blocks the most common F&B service pattern (fire to kitchen, cook, serve), making the POS unusable beyond a quick-counter till.

This increment builds kitchen order management (KDS) on top of the existing sale order lifecycle: tickets sent from a sale order to the kitchen, named stations to route them, per-item cooking statuses, and live status propagation over WebSocket.

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 with product-category routing and per-station printer config (STA).
  • Real-time updates to kitchen displays and dashboards on ticket create / update / complete.
  • Marking an item served triggers downstream stock consumption.

Non-Goals

  • A dedicated kitchen display application - this delivers the backend plus the apps/sale-renderer surface 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 schema/services are not part of this increment.

3. Success Metrics

MetricTarget / signal
Real-time freshnessKitchen displays reflect a status change with no manual reload; WebSocket 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
Service correctnessMarking an item served reliably triggers stock consumption exactly once

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 scenarios: a cashier fires items to the kitchen → a ticket appears on the routed station's display → kitchen staff move items cooking → ready → served, the ticket auto-progresses, and the floor sees status live; a mistaken item is voided and re-fired rather than 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.
  • 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-9Marking an item served triggers stock consumptionURD-KIT-009
FR-10Create named stations per merchant (i18n)URD-STA-001
FR-11Route product categories to stationsURD-STA-002
FR-12Per-station printer config with auto-printURD-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 over WebSocket; apps/sale-renderer subscribes for live status
IdempotencySend is keyed so retries collapse to a single ticket; no duplicate kitchen work
Tenancy & authzAll operations scoped per merchant (x-merchant-id); gated by sale/kitchen permissions
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 apps/sale-renderer, which subscribes to the WebSocket stream for live ticket/item status; station and routing config is managed per merchant.

9. Data & Domain

EntityRole
KitchenTicketThe ticket sent to the kitchen - status, rush flag, per-order sequence, station assignment
KitchenTicketItemA ticket line - references the order item, carries its own cooking status
KitchenStationA named preparation area (i18n) with category routing and printer config

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 served item triggers stock consumption.
  • Real-time transport (@nx/sale WebSocket) - 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. apps/sale-renderer) hold an active WebSocket 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 WebSocket update leaving a stale displayDisplays subscribe to create / update / complete; reconnect re-syncs
No dedicated KDS app yetBackend + apps/sale-renderer 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
MigrationSale-schema migrations for the new kitchen entities; no data backfill
Launch criteriaFire → ticket → station routing → cooking → served verified end-to-end; idempotent send holds; auto-progression matches item statuses; live updates reach apps/sale-renderer
MonitoringTicket volume per merchant, send error / duplicate rate, WebSocket 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 apps/sale-renderer, updated live over WebSocket - no reload needed. A dedicated KDS app is Planned.

Does serving an item move stock? Yes - marking an item served triggers downstream stock consumption (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.