- State machine (
syncMachine) — Tracks transport state, lease state, and outbox depth - Provider (
RealtimeProvider) — Creates the transport, wires event handlers, bridges to UI state - UI components — Visual indicators for sync status, conflict dialogs, lease notifications
Sync state machine
nu_pos_react/src/state/machines/syncMachine.ts
An XState machine managing the sync lifecycle:
States
Context
Events
RealtimeProvider
nu_pos_react/src/app/providers/RealtimeProvider.tsx
The main sync orchestrator. Creates the transport on mount and wires all event handlers:
Event wiring
transport.onStateChange()→ Maps transport state to sync machine eventstransport.onConflict()→ Shows conflict dialog viaSyncUIProvidertransport.onLeaseRevoked()→ SendsLEASE_LOSTto sync machinetransport.onOrderUpdated()→ Applies remote order update to local statetransport.onReconnecting()→ SetsisReconnectinginSyncUIProvider(shows overlay)transport.onReconnected()→ ClearsisReconnecting(hides overlay)transport.onStateChange()todisconnectedwhileisReconnecting→ SetsreconnectionFailed(session expired)- Browser
online/offlineevents →ONLINE/OFFLINEto sync machine
Provider tree
SyncUIProvider wraps RealtimeProvider so that the realtime layer can push events into the UI context.
UI components
SyncStatusIndicator
A compact badge reading from the sync machine context:
When
outboxDepth > 0, the badge shows a count of pending items.
ConflictDialog
Modal dialog shown on version conflicts:- “Load Latest” → Calls
reconcile()withaccept_remotestrategy - “Keep Mine” → Dismisses dialog, allows user to manually resolve
SyncOverlay
Component connectingSyncUIProvider state to visible UI:
- Renders
ConflictDialogwhenconflictis non-null - Renders
ReconnectionOverlayfor sleep/wake recovery (see below) - Shows a destructive toast when
leaseRevokedis non-null (“Manager took over this order”)
ReconnectionOverlay
nu_pos_react/src/features/sales/components/reconnection-overlay.tsx
A full-screen blocking overlay shown during sleep/wake WebSocket recovery. Reads isReconnecting and reconnectionFailed from SyncUIProvider:
The overlay uses
z-50 with a semi-transparent backdrop to block interaction during reconnection.
TableLockedDialog
Floor plan modal shown when a table lock is denied:- “Dismiss” — Close dialog, release any pending lock
- “Take Over” (managers only) — Force-acquire the lock
TableLockGuard
Renderless component on the order page managing table lock lifecycle:- Releases the lock on unmount
- Re-acquires the lock after WebSocket reconnect
- Redirects to the floor plan if the lock is revoked
Bridge components
Renderless components that wire hub transport events into the POS reducer. Must be rendered inside both<POSProvider> and <SyncTransportContext.Provider>.
HubOrderBridge
nu_pos_react/src/realtime/HubOrderBridge.tsx — Used on the order page:
- Outbound: Builds
OrderSnapshotDatafrom active order on every state change → sendsORDER_SNAPSHOTvia transport (with hash-based change detection to avoid redundant sends) - Inbound
SYNC_INIT: Applies full order reconciliation on connect (gated onhydratedto wait for IndexedDB restore) - Inbound
ORDER_UPDATED: Applies remote snapshots viaapplyRemoteSnapshot({ posReference, snapshot })— auto-creates orders for the active table, closes orders withpaid/closedstatus or empty lines - Lease lifecycle: Acquires lease when active order has items + posReference, releases on switch/unmount
- Deletion detection: Sends
closedsnapshot to hub when local orders are removed
FloorPlanSyncBridge
nu_pos_react/src/realtime/FloorPlanSyncBridge.tsx — Used on the floor plan page:
- Inbound
SYNC_INIT: Full reconciliation (same as HubOrderBridge) - Inbound
ORDER_UPDATED: Applies remote snapshots so table occupation status stays current across terminals. Closes orders withpaid/closedstatus or empty lines
FloorPlanStructureSyncBridge
nu_pos_react/src/realtime/FloorPlanStructureSyncBridge.tsx — Used on the floor plan page:
- Inbound
FLOOR_PLAN_CHANGED: Updates floor plan table positions and structure when another terminal edits the layout - Outbound: Sends
FLOOR_PLAN_UPDATEwhen the current terminal saves layout changes
How everything connects
i18n
Translations are in thesync namespace (src/i18n/locales/{en,es}.json):