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.
System topology
Three-tier data flow
1. Terminal (browser)
The POS frontend connects to the hub via WebSocket. On every order change, the terminal sends anORDER_SNAPSHOT message containing the full order state. It does not talk to Odoo directly in hub mode.
Key modules (in nu_pos_react/src/realtime/):
hubTransport.ts— ImplementsSyncTransportfor hub modehub/hubConnection.ts— WebSocket lifecycle with auto-reconnecthub/hubDiscovery.ts— Resolves hub URL from bootstrap config
2. Hub (Raspberry Pi)
The hub is a stateless-except-SQLite Node.js service that:- Authenticates terminals via Odoo session validation
- Enforces single-writer order ownership through leases
- Persists order snapshots with optimistic versioning
- Broadcasts changes to all other connected terminals
- Forwards events to Odoo in the background
nu_pos_hub/src/):
handlers/— Message handlers (auth, lease, order, table)storage/— SQLite stores (orders, leases, events, tables)leasing/leaseManager.ts— Lease business logicupstream/forwarder.ts— Background event drain to Odoo
3. Odoo (cloud)
Odoo is the system of record. The hub forwards order events via the existing/pos-react/api/orders/{create,update} endpoints. These are idempotent by pos_reference, so re-forwarding is safe.
Direct mode vs hub mode
| Aspect | Direct mode | Hub mode |
|---|---|---|
| Connection | HTTP polling (2s interval) | WebSocket (real-time) |
| Conflict prevention | Local tab locks only | Distributed leases via hub |
| Cross-terminal updates | Poll-based (2-15s delay) | Instant broadcast |
| Offline support | localStorage outbox | localStorage outbox + hub reconnect |
| Infrastructure | None (just Odoo) | Raspberry Pi running hub |
| Odoo calls | Each terminal calls Odoo | Hub is sole Odoo gateway |
| Activation | Default | Odoo config: nu_hub_enabled = True |
SyncTransport interface (see transport layer), so the UI code is identical regardless of mode.
Component ownership
The frontend does not import
@nu/sync-protocol directly. Instead, transport.ts defines OrderSnapshotData (a mirror of the protocol’s OrderSnapshot) to avoid coupling the browser bundle to the Node.js protocol package.