Skip to main content
The frontend sync integration consists of three layers:
  1. State machine (syncMachine) — Tracks transport state, lease state, and outbox depth
  2. Provider (RealtimeProvider) — Creates the transport, wires event handlers, bridges to UI state
  3. 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 events
  • transport.onConflict() → Shows conflict dialog via SyncUIProvider
  • transport.onLeaseRevoked() → Sends LEASE_LOST to sync machine
  • transport.onOrderUpdated() → Applies remote order update to local state
  • transport.onReconnecting() → Sets isReconnecting in SyncUIProvider (shows overlay)
  • transport.onReconnected() → Clears isReconnecting (hides overlay)
  • transport.onStateChange() to disconnected while isReconnecting → Sets reconnectionFailed (session expired)
  • Browser online/offline events → ONLINE/OFFLINE to 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() with accept_remote strategy
  • “Keep Mine” → Dismisses dialog, allows user to manually resolve

SyncOverlay

Component connecting SyncUIProvider state to visible UI:
  • Renders ConflictDialog when conflict is non-null
  • Renders ReconnectionOverlay for sleep/wake recovery (see below)
  • Shows a destructive toast when leaseRevoked is 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 OrderSnapshotData from active order on every state change → sends ORDER_SNAPSHOT via transport (with hash-based change detection to avoid redundant sends)
  • Inbound SYNC_INIT: Applies full order reconciliation on connect (gated on hydrated to wait for IndexedDB restore)
  • Inbound ORDER_UPDATED: Applies remote snapshots via applyRemoteSnapshot({ posReference, snapshot }) — auto-creates orders for the active table, closes orders with paid/closed status or empty lines
  • Lease lifecycle: Acquires lease when active order has items + posReference, releases on switch/unmount
  • Deletion detection: Sends closed snapshot 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 with paid/closed status 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_UPDATE when the current terminal saves layout changes
APPLY_SYNC_INIT is a destructive full reconciliation that prunes all hubSynced orders not in the payload. Never use it for single-order updates — use APPLY_REMOTE_SNAPSHOT instead (safe single-order upsert).

How everything connects

i18n

Translations are in the sync namespace (src/i18n/locales/{en,es}.json):