PRD: Reservations
| Module | Orders (CORE-07) | PRD ID | PRD-RSV-001 |
| Status | Shipped | Owner | Orders squad |
| Date | 2026-05-29 | Version | v1.0 |
| Packages | @nx/sale · apps/sale-renderer · apps/sale-main | URD | RSV |
TL;DR
Lets a full-service venue take table bookings ahead of service - guest, party size, date/time, table/room - drive them through a clear booking lifecycle, and turn a booking into a live order on check-in without re-keying. The floor view and zone availability stay in sync in real time, so hosts always know which tables are held, confirmed, or seated.
1. Context & Problem
Full-service F&B venues take table bookings before service: a host records the guest, party size, and a date/time, then seats the party on arrival. KICKO's order flow has no first-class booking entity, so a future booking and its eventual order are disconnected - the host re-keys the order at the table, holds on a zone/unit are invisible, and the floor view cannot show what is reserved versus seated. This blocks the host workflow a full-service venue depends on and makes table utilisation impossible to track.
This feature introduces a Reservation entity in @nx/sale with its own lifecycle, source/occasion metadata, and a zone/unit (table/room) hold via the allocation-usage model, connecting the booking to the live order on check-in.
2. Goals & Non-Goals
Goals
- A reservation entity capturing guest name, phone, party size, and date/time, scoped to the merchant.
- A booking lifecycle:
PENDING → CONFIRMED → CHECKED_IN / CANCELLED. - Source tracking (phone, walk-in, online, other) and occasion tagging (birthday, anniversary, business, etc.).
- Auto-spawn and link a sale order on check-in, so the booking becomes the live order without re-keying.
- Zone/unit (table/room) holds via snapshot allocation usage, with real-time socket updates to the floor view.
Non-Goals
- Table-layout / seating management - Planned, separate from booking.
- A dedicated kitchen display application.
- Order templates and delivery order tracking.
3. Success Metrics
| Metric | Target / signal |
|---|---|
| Re-key elimination | 100% of checked-in reservations spawn and link a sale order (no manual order creation at the table) |
| Floor accuracy | Zone/unit availability reflects active reservation holds with no stale entries |
| Real-time sync | Reservation and zone updates propagate to the floor view via socket within the live session |
| Booking conversion | Share of confirmed reservations that reach CHECKED_IN trends up per merchant |
4. Personas & Use Cases
| Persona | Goal in this feature |
|---|---|
| Host | Take and manage bookings, hold the right table, check guests in |
| Cashier | Continue the spawned order from check-in without re-entry |
| Manager / Owner | See table holds and booking activity on the floor view |
Core scenarios: a host creates a reservation for a guest (party size, date/time, table) → confirms it → on arrival checks the party in → a sale order is spawned and linked, the table hold is recorded, and the floor view updates live.
5. User Stories
- As a host, I want to create a reservation with guest name, phone, party size, and date/time, so the booking is recorded against the merchant.
- As a host, I want to confirm or cancel a booking, so its lifecycle reflects what will actually happen.
- As a host, I want to tag the source and occasion of a booking, so the venue can prepare and report on it.
- As a host, I want to hold a specific table/room for a booking, so the floor view shows it as reserved.
- As a host, I want check-in to spawn and link a sale order, so the seated party's order continues from the booking without re-keying.
- As a manager, I want the floor view and zone availability to update in real time, so holds and seatings are always current.
6. Functional Requirements
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Create a reservation with guest name, phone, party size, and date/time, scoped to the merchant | URD-RSV-001 |
| FR-2 | Lifecycle PENDING → CONFIRMED → CHECKED_IN / CANCELLED | URD-RSV-002 |
| FR-3 | Source tracking: phone, walk-in, online, other | URD-RSV-003 |
| FR-4 | Occasion tagging: birthday, anniversary, business, etc. | URD-RSV-004 |
| FR-5 | On check-in, spawn and link a sale order to the reservation | URD-RSV-005 |
| FR-6 | Table/room (zone/unit) association via snapshot allocation usage; filter by unitId and zoneId | URD-RSV-001 |
| FR-7 | Real-time socket fan-out for reservation usage and zones to keep the floor view and zone availability live | URD-RSV-002 |
Full requirement text and acceptance criteria live in the Orders URD. This PRD references them rather than restating them.
7. Non-Functional Requirements
| Area | Requirement |
|---|---|
| Data integrity | A checked-in reservation and its linked sale order are written together; allocation usage is snapshotted so a hold is never lost |
| Tenancy & authz | All operations scoped per merchant (x-merchant-id); reservation actions are permission-gated |
| Performance / scale | List/filter of SaleOrder + Reservation uses optimized querying; createdAt surfaced for list ordering |
| Real-time | Reservation usage/zone changes emit socket events for the floor view within the session |
| i18n | User-facing labels/statuses are bilingual ({ en, vi }) |
8. UX & Flows
Front-of-house surfaces live in apps/sale-renderer (Reservation Sheet, detail view, create-from-list, date/time editing, socket listeners); a Tauri ReservationService/pub lives in apps/sale-main.
9. Data & Domain
| Entity | Role |
|---|---|
Reservation | The booking - guest details, party size, date/time, source, occasion, status, optional linked sale order |
| Allocation usage | Snapshot record holding the reserved zone/unit (table/room) for the reservation |
SaleOrder | Spawned and linked on check-in so the booking becomes the live order |
Conceptual only - full schema and invariants in the sale domain model.
10. Dependencies & Assumptions
Depends on
- Sale Order (URD-ORD) - check-in spawns and links a sale order.
- Zone/unit allocation model - table/room holds use the allocation-usage snapshot.
- Real-time socket layer - floor view and zone availability are kept live via socket fan-out.
Assumptions
- The merchant defines zones/units (tables/rooms) that a reservation can hold.
- A host operates the front-of-house surface in
apps/sale-renderer/apps/sale-main.
11. Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| A hold could diverge from the booking on partial failure | Allocation usage is snapshotted with the reservation; check-in writes booking + sale order together |
| No table-layout / seating management | Out of scope this increment; reservation holds a zone/unit but layout is Planned |
| Stale zone availability if a socket event is missed | Floor view reconciles on reservation usage/zone fan-out; revisit if drift is observed |
| Cancellation after a hold | Lifecycle supports CANCELLED with batch complete/cancel of usage to release the hold |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P2 (F&B extensions) - see Orders URD feature catalog |
| Rollout | All F&B merchants; no feature flag |
| Migration | New entity; allocation-usage columns extended for zone/unit binding |
| Launch criteria | Create → confirm → check-in verified end-to-end; sale order spawned and linked; zone hold and socket fan-out verified live |
| Monitoring | Reservation volume per merchant, check-in conversion, zone-hold consistency, socket fan-out delivery |
13. FAQ
Does check-in create the order automatically? Yes - checking a reservation in spawns and links a sale order, so the seated party's order continues from the booking without re-keying.
Can a reservation hold a specific table or room? Yes - a reservation associates a zone/unit via a snapshot allocation usage; lists can filter by unitId and zoneId.
What happens to the table hold if a booking is cancelled? The lifecycle supports CANCELLED with batch complete/cancel of usage, releasing the held zone/unit.
Does this include drag-and-drop table-layout management? No - table-layout / seating management is Planned and separate from booking; this feature holds a zone/unit but does not manage the floor layout.
How does the floor view stay current? Reservation usage and zone changes emit socket events, keeping the floor view and zone availability live during the session.
References
- URD: Orders - Reservations
- Builds on: Sale Order
- Module: Orders - overview + traceability
- Developer: @nx/sale · domain model