> ## 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.

# Sync hub

> How real-time synchronization works between POS terminals.

The sync hub (`nu_pos_hub/`) is a Node.js WebSocket broker that keeps multiple POS terminals in sync. It uses SQLite in WAL mode for persistence.

## Architecture

```
┌──────────┐     ┌──────────┐     ┌──────────┐
│ Terminal  │────▶│          │────▶│  Odoo    │
│    A      │◀────│ Sync Hub │◀────│  Backend │
└──────────┘     │ (WS+SQL) │     └──────────┘
┌──────────┐     │          │
│ Terminal  │────▶│          │
│    B      │◀────│          │
└──────────┘     └──────────┘
```

Terminals connect via WebSocket. The hub:

* Broadcasts order snapshots between terminals
* Manages table locks (exclusive access per table)
* Manages leases (terminal session tracking)
* Forwards completed orders upstream to Odoo
* **Finalizes orders** — when a terminal completes payment, the hub calls Odoo's `hub_finalize_snapshot` to create the order with payments, NCF, and full fiscal processing

## Protocol

The sync protocol (`nu_pos_sync_protocol/`) defines all message types using Zod schemas:

* **Terminal → Hub**: `ORDER_SNAPSHOT`, `TABLE_LOCK_ACQUIRE`, `TABLE_LOCK_RELEASE`, `HEARTBEAT`, etc.
* **Hub → Terminal**: `ORDER_UPDATED`, `SYNC_INIT`, `TABLE_LOCK_GRANTED`, `TABLE_LOCK_DENIED`, `LEASE_GRANTED`, etc.

## Table locking

Each table has an exclusive lock. Only one terminal can edit a table's orders at a time.

| Parameter               | Value      |
| ----------------------- | ---------- |
| Lock TTL                | 45 seconds |
| Heartbeat interval      | 15 seconds |
| Disconnect grace period | 10 seconds |

Managers can force-acquire a lock held by another terminal.

<Note>
  Locking is disabled when offline — `acquireTableLock` returns granted immediately, and the system falls back to optimistic conflict resolution.
</Note>

## Transport abstraction

The frontend uses a `SyncTransport` interface (`realtime/transport.ts`) that supports two implementations:

* **`directTransport`** — Polling + outbox queue (fallback mode)
* **`hubTransport`** — WebSocket connection to the sync hub

The factory `createTransport()` reads `nu_hub_enabled` / `nu_hub_url` from bootstrap config to select the implementation.

## Configuration

Enable the hub in Odoo POS configuration:

* `nu_hub_enabled` — Toggle hub sync on/off
* `nu_hub_url` — WebSocket URL of the hub
* `nu_hub_fallback_ip` — Fallback IP when primary URL is unreachable
