nu_pos_hub/
Startup sequence
nu_pos_hub/src/index.ts initializes all components in order:
- Load configuration from environment
- Initialize SQLite database (WAL mode)
- Create storage layers (orders, leases, events, tables, table locks)
- Create lease manager with revoke callback
- Create table lock manager with revoke callback
- Create Odoo adapter and forwarder
- Wire up message handlers
- Start HTTP server (health, status, events, dashboard)
- Start WebSocket server (attached to HTTP server)
- Start periodic tasks (lease tick, forwarder, status broadcast)
- Start mDNS advertisement (if enabled)
- Register graceful shutdown handlers (SIGTERM, SIGINT)
Configuration
nu_pos_hub/src/config.ts — All settings via environment variables:
Storage layer
All stores use the same SQLite database with WAL mode for concurrent reads.SQLite schema
SQLite pragmas
Store APIs
Transport-level PING/PONG
The WebSocket server handles{"type":"PING"} messages at the transport level before routing to protocol handlers. It responds immediately with {"type":"PONG"}. This keeps connections alive through proxies and NAT without requiring protocol-level message definitions.
Message handlers
Auth handler
handlers/authHandler.ts
- Receives raw WebSocket +
AUTHmessage - Validates session token against Odoo:
POST /pos-react/api/sessionwith the token as cookie - On success: creates
TerminalInfo, registers in terminal registry, sendsAUTH_OK - On failure: sends
AUTH_FAIL, connection is not registered
Lease handler
handlers/leaseHandler.ts — Delegates to LeaseManager (see leasing):
LEASE_ACQUIRE→leaseManager.acquire()→ sendsLEASE_GRANTEDorLEASE_DENIEDLEASE_RELEASE→leaseManager.release()→ appendslease_releaseeventLEASE_HEARTBEAT→leaseManager.heartbeat()→ renews lease expiry
Order handler
handlers/orderHandler.ts — The core sync handler:
- Verify terminal holds lease for
posReference - Check
baseVersion >= storedVersion(else sendCONFLICT) - Upsert order in SQLite (version increments)
- Append
order_snapshotevent to log (forwarded=0) - Broadcast
ORDER_UPDATEDto all terminals except sender - If
snapshot.tableIdis set: update table status (occupied, oravailableif paid)
Table lock handler
handlers/tableLockHandler.ts — Delegates to TableLockManager (see table locking):
TABLE_LOCK_ACQUIRE→ grants or denies, broadcastsTABLE_LOCKS_STATEon grantTABLE_LOCK_RELEASE→ broadcastsTABLE_LOCK_RELEASEDTABLE_LOCK_HEARTBEAT→ sendsTABLE_LOCK_REVOKEDon failureTABLE_LOCK_FORCE_ACQUIRE→ Server-side role check → evicts current holder, grants to requester
Floor plan handler
handlers/floorPlanHandler.ts — Broadcasts floor plan changes to other terminals:
FLOOR_PLAN_UPDATE→ BroadcastsFLOOR_PLAN_CHANGEDto all terminals except sender (includesfloorId,tables,layoutMode?)
Terminal registry
server/terminalRegistry.ts — In-memory map of connected terminals:
register(), remove(), send(), broadcast(), count(), getAll().
Odoo adapter
upstream/odooAdapter.ts — Converts snapshots to Odoo format and forwards.
Snapshot transformation
Voided lines (
isVoided: true) are filtered out before forwarding.
Endpoint selection
- New orders (no
odooId):POST /pos-react/api/orders/create - Existing orders (has
odooId):POST /pos-react/api/orders/update
pos_reference.
HTTP endpoints
Periodic tasks
Graceful shutdown
OnSIGTERM or SIGINT:
- Stop all periodic timers
- Stop forwarder
- Stop mDNS
- Close HTTP server
- Close SQLite database
- Exit process