> ## Documentation Index
> Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How it works

> A plain-English walkthrough of the sync protocol — what happens from login to order saved.

Think of a busy restaurant with tablets at the front door, waiters walking around with handhelds, a cashier terminal, and a kitchen screen. Every device needs to see the same orders in real time. When a waiter adds a burger to Table 5, the kitchen screen needs to know immediately — and so does the cashier.

That's the problem the sync protocol solves: keeping every device in sync, without letting two people step on each other's changes.

## The three pieces

<CardGroup cols={3}>
  <Card title="Terminals (the students)" icon="tablet">
    Tablets and computers running the POS app. Each is a "terminal." They take orders, update tables, and process payments.
  </Card>

  <Card title="Hub (the teacher)" icon="server">
    A Node.js server running on-site (Raspberry Pi). Every terminal connects via WebSocket. The hub decides who edits what, stores every order, and broadcasts updates.
  </Card>

  <Card title="Odoo (the principal's office)" icon="building">
    The cloud business system. The hub batches order updates to Odoo every 5 seconds. Odoo holds the permanent record; the hub handles real-time traffic locally.
  </Card>
</CardGroup>

## Step by step

<Steps>
  <Step title="Logging in (AUTH)">
    A terminal starts up and sends `AUTH { token, deviceId }`. The hub validates the token against Odoo and replies with `AUTH_OK` or `AUTH_FAIL`. On success, the hub immediately sends a `SYNC_INIT` message — a full dump of all active orders so the terminal starts with accurate data.
  </Step>

  <Step title="Locking a table (TABLE_LOCK)">
    Before a waiter can work a table, their terminal asks: `TABLE_LOCK_ACQUIRE { tableId }`. The hub checks:

    * **Free** → `TABLE_LOCK_GRANTED`
    * **Held by another terminal** → `TABLE_LOCK_DENIED { lockedBy }`

    The terminal sends `TABLE_LOCK_HEARTBEAT` every **15 seconds** to keep the lock alive. If a terminal crashes and stops heartbeating, the lock auto-expires after **45 seconds**. A manager can force-take any lock with `TABLE_LOCK_FORCE_ACQUIRE`.
  </Step>

  <Step title="Editing an order (LEASE)">
    Once on the order page, the terminal needs a **lease** — like borrowing a library book. It sends `LEASE_ACQUIRE { posReference, baseVersion }`. The hub grants it with a version number and expiry time. Only the lease holder can send snapshots for that order.

    The terminal heartbeats every **20 seconds** (`LEASE_HEARTBEAT`). The lease expires after **60 seconds** without one.
  </Step>

  <Step title="Saving changes (ORDER_SNAPSHOT)">
    Every edit — adding an item, changing quantity, applying a discount — sends the complete current order as `ORDER_SNAPSHOT`. The hub:

    1. Checks the version number matches (no concurrent edits slipped through)
    2. Saves the snapshot and bumps the version
    3. Broadcasts `ORDER_UPDATED` to **all other connected terminals**

    If the version doesn't match (two terminals somehow edited the same order), the hub returns a `CONFLICT` message with its authoritative snapshot.
  </Step>

  <Step title="Releasing the lease">
    When the waiter navigates away or the order is paid, the terminal sends `LEASE_RELEASE { posReference, finalSnapshot? }`. The hub saves the final snapshot (if provided) and frees the order for other terminals.
  </Step>

  <Step title="Forwarding to Odoo">
    Every **5 seconds**, the hub drains up to 20 recent order events and forwards them to Odoo's `/pos-api/v1/orders/{create,update}` endpoints. Order creation is idempotent by `pos_reference` — re-forwarding is always safe. If Odoo is temporarily down, the hub keeps the event log and retries.
  </Step>
</Steps>

## What's in an order snapshot

An `ORDER_SNAPSHOT` is a complete photo of an order at a point in time:

| Field      | Content                                                                       |
| ---------- | ----------------------------------------------------------------------------- |
| Identity   | `posReference`, `id`, `odooId`                                                |
| Assignment | `tableId`, `partnerId`                                                        |
| Status     | `open` / `sent` / `changed` / `paid`                                          |
| Lines      | Each item: product, qty, price, discount, taxes, void info, kitchen sent time |
| Payments   | Payment method, amount, change                                                |
| Totals     | Subtotal, tax, total                                                          |
| Meta       | `updatedAt`, `terminalId`, `notes`                                            |

## Table status

Tables sync separately from orders. A `TABLE_UPDATE` message sets a table's status (`available`, `occupied`, or `reserved`) and the hub broadcasts `TABLE_UPDATED` to all terminals instantly.

## Why this design

Without the protocol:

* Two waiters could edit the same order — one would silently overwrite the other
* A crashed terminal could hold a lock forever, blocking the whole table
* The kitchen would miss order updates
* The cashier would see stale totals

With the protocol, each of these is covered:

| Problem           | Solution                                                     |
| ----------------- | ------------------------------------------------------------ |
| Concurrent edits  | Order leases — only one writer at a time                     |
| Table conflicts   | Table locks — only one terminal per table                    |
| Stale data        | Broadcast on every change — all terminals update instantly   |
| Crashed terminals | Heartbeat expiry — locks and leases auto-release             |
| Odoo downtime     | Hub event log — changes queue and forward when Odoo recovers |

## Key files

| File                                     | Purpose                                                                         |
| ---------------------------------------- | ------------------------------------------------------------------------------- |
| `nu_pos_sync_protocol/src/messages.ts`   | All message types (Terminal→Hub and Hub→Terminal)                               |
| `nu_pos_sync_protocol/src/snapshots.ts`  | `OrderSnapshot`, `TableStatus` schemas                                          |
| `nu_pos_sync_protocol/src/constants.ts`  | TTLs, heartbeat intervals                                                       |
| `nu_pos_sync_protocol/src/validators.ts` | Zod schemas for runtime validation                                              |
| `nu_pos_hub/`                            | Hub server: WebSocket broker, lease manager, table lock manager, Odoo forwarder |
| `nu_pos_react/src/realtime/`             | Frontend transport and sync bridge                                              |
