2026-04-22. Fourth cycle of R1 (NIX-OS-67 Phase 3 POS): the cashier can now park a cart
and start a new one for another customer in parallel. Parked carts persist to
cafe.draft_orders (JSONB payload per cart), so a tab crash, browser restart, or
device handover doesn't lose work. Rows auto-cleanup on session close via FK CASCADE.
/cafe/pos/register/N still returns 307 — no regression from the Register refactor
(added initialDrafts + allowDrafts props, unchanged default behavior).
cafe.draft_orders after resume.
20260422200000_cafe_draft_orders — id, tenant_id (FK),
session_id (FK CASCADE), label, payload (JSONB), timestamps. Two indexes.lib/db/draft_orders.ts (new) — listDraftsForSession
(Hyperdrive-safe), upsertDraft (insert-or-update based on provided id),
deleteDraft (tenant + session scoped). DraftPayload +
DraftSummary + rowToSummary exported for client/server
shared shapes.lib/actions/drafts.ts (new) — saveDraftAction,
deleteDraftAction, listDraftsAction. Ownership gate: the
active-cashier cookie's nixSessionId MUST match the target draft's session.Register component — new initialDrafts +
allowDrafts props. When enabled, renders a compact strip above the cart:
Park button (snapshots cart+customer as a draft), plus one pill per parked draft
(click to resume, trash icon to discard). Legacy in-shell /cafe/pos?config=N
flow passes neither prop — drafts strip hidden (no NIX session to persist against).app/(pos-fullscreen)/pos/register/[configId]/page.tsx — fetches
cafe.draft_orders server-side when phase=open + NIX session exists;
passes list into RegisterShell → Register.cafe.draft_orders✓ shape OKLoading…
Loading…