# Rice Box Two-Screen Order Display — Field of Study Handoff

**Status:** Working interface and live KDS data engine
**Purpose of this handoff:** Explain the current screen format, data piping, and daemon behavior for design discussion.

## Current interface preview

The Cloudflare-hosted preview now supports both live and fictional modes.

Live Heights data:

- **Preview home:** https://pickup-preview.riceboxed.com
- **Screen 01 — In the Kitchen:** https://pickup-preview.riceboxed.com/kitchen/
- **Screen 02 — Ready at Pickup:** https://pickup-preview.riceboxed.com/ready/

Fixed fictional data for repeatable design review:

- **Screen 01 — Demo:** https://pickup-preview.riceboxed.com/kitchen/?demo=1
- **Screen 02 — Demo:** https://pickup-preview.riceboxed.com/ready/?demo=1

Add `?location=river_oaks`, `?location=rice_village`, or `?location=hedwig` to either live screen URL to inspect another store. The live preview connects from Cloudflare to the daemon's customer-safe SSE endpoint; demo mode stays entirely inside the interface.

## System structure

Rice Box already has one KDS daemon serving the retail fleet. It is the only order-state engine.

```text
Toast order_updated webhook
          ↓
Rice Box KDS daemon
          ├── validates and routes the order by store
          ├── merges only the newest Toast order state
          ├── reconciles against Toast every 30 seconds
          ├── classifies each order as in-kitchen or ready
          └── produces a customer-safe public state
                         ↓
                Full-state SSE stream
                         ↓
          Cloudflare public-endpoint relay
                         ↓
              Two-screen interface
              ├── Screen 01: In the Kitchen
              └── Screen 02: Ready at Pickup
```

The interface does not contain Toast logic. It renders the daemon's public data contract. Cloudflare hosts the interface files; the KDS daemon hosts the live order data.

## Two-screen format

### Screen 01 — Your Order Is in the Kitchen

Shows every active order that Toast has not yet marked ready.

Each order displays:

- Toast order number
- First name plus last initial
- Order source

### Screen 02 — Ready at Pickup

Shows every active order that Toast has marked ready.

Each order displays:

- Toast order number
- First name plus last initial
- Order source
- Handoff destination

## All orders pass through the system

The public projection includes every Toast order lane:

| Order source | Public label | Current handoff destination |
|---|---|---|
| Dine-in | DINE IN | FRONT COUNTER |
| Register-entered takeout | ORDERED HERE | CUSTOMER PICKUP |
| Rice Box app/web pickup | RICE BOX ONLINE | CUSTOMER PICKUP |
| Phone order | PHONE ORDER | CUSTOMER PICKUP |
| Rice Box delivery | RICE BOX DELIVERY | DELIVERY PICKUP |
| DoorDash | DOORDASH | DOORDASH ZONE |
| Uber Eats / Postmates | UBER EATS | UBER EATS ZONE |
| ezCater | EZCATER | CATERING PICKUP |
| Grubhub | GRUBHUB | DELIVERY PICKUP |
| Favor | FAVOR | DELIVERY PICKUP |
| Unrecognized delivery source | OTHER DELIVERY | DELIVERY PICKUP |

Dine-in guests therefore see that their order is being prepared and when it becomes ready, using the same two-screen flow as every other order.

## Public data endpoints

The interface reads the customer-safe state from the daemon host.

### Current state

```text
GET /api/public-state?location=<store>
```

### Live stream

```text
GET /api/public-stream?location=<store>
```

The live stream uses Server-Sent Events. It sends the complete current public state immediately after connection and after each order change.

Supported location keys:

- `heights`
- `river_oaks`
- `rice_village`
- `hedwig`
- Clear Lake will join the same structure when its Toast location is active.

There is one deployment and one interface system. Each store screen opens the same interface with its own location key.

## Public state shape

```json
{
  "generated_at": "2026-07-11T15:00:00-05:00",
  "location": "heights",
  "mode": "live",
  "screens": {
    "kitchen": [
      {
        "order_number": "142",
        "display_name": "Jordan P.",
        "source_key": "ordered_here",
        "source_label": "ORDERED HERE",
        "pickup_zone": "CUSTOMER PICKUP",
        "public_status": "making"
      },
      {
        "order_number": "144",
        "display_name": "Riley A.",
        "source_key": "dine_in",
        "source_label": "DINE IN",
        "pickup_zone": "FRONT COUNTER",
        "public_status": "making"
      }
    ],
    "ready": [
      {
        "order_number": "139",
        "display_name": "Taylor M.",
        "source_key": "doordash",
        "source_label": "DOORDASH",
        "pickup_zone": "DOORDASH ZONE",
        "public_status": "ready",
        "platform_code": "91AF"
      }
    ]
  }
}
```

`platform_code` is optional and appears only when a useful short third-party code can be parsed.

## Daemon rules

- One daemon receives and routes Toast events for every retail store.
- Webhooks provide the immediate state change.
- A 30-second Toast poll reconciles missed or delayed events.
- Orders are merged by Toast `modifiedDate`, so an older event cannot move the board backward.
- Screen placement is controlled by Toast fulfillment status.
- An estimated time never marks an order ready.
- `NEW` and `HOLD` are treated as in-kitchen queue state.
- `SENT`, `IN_PROGRESS`, and `FIRED` are treated as in the kitchen.
- Only `READY` moves an order to the Ready screen.
- Ready orders remain visible for the daemon's configured ready-hold window.
- Full surnames, internal timing, item details, and raw Toast data are excluded from the public projection.
- The browser reconnects automatically if the SSE connection drops.
- The current interface shifts between relaxed, dense, and high-density rows as order volume changes.
- Boards above 16 orders automatically rotate through readable pages every seven seconds rather than compressing rows beyond legibility.

## Hosting distinction

```text
Cloudflare Pages
  Hosts the interface files and relays only /api/public-state and /api/public-stream.

KDS daemon host
  Receives Toast webhooks, reconciles orders, owns order state, and serves the public API/SSE stream.
```

The Cloudflare preview can connect live to the current daemon or run from embedded fictional orders with `?demo=1`. The relay keeps browsers on the public `pickup-preview.riceboxed.com` origin instead of asking them to connect directly to the Mini's Tailscale address. Moving the daemon from the Mac Mini to an always-on cloud service will change the relay origin, not the interface contract or Field of Study's rendering logic.

## Discussion points

- Final physical wording and placement for customer, delivery, catering, and dine-in handoff zones
- Whether `FRONT COUNTER` is the final dine-in destination language
- How the two displays align with the physical shelf and command-center layout
- How newly ready orders should announce themselves visually
- Maximum useful information density at the installed screen size and viewing distance
