Skip to main content

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.

How conflicts happen

Even with leases, version conflicts can occur:
  • A terminal sends ORDER_SNAPSHOT { baseVersion: 3 } but the hub already has version 4
  • A terminal reconnects after a network drop and sends a stale snapshot
  • Two terminals briefly hold overlapping leases during the disconnect grace period

Version tracking

Every order in the hub has an auto-incrementing version number:
-- orderStore.upsert() increments version on each write
UPDATE orders SET version = version + 1, snapshot = ?, updated_at = datetime('now')
WHERE pos_reference = ?
When a terminal sends ORDER_SNAPSHOT { baseVersion }:
  1. Hub compares baseVersion against the stored version
  2. If baseVersion >= storedVersion: accept, increment version, broadcast
  3. If baseVersion < storedVersion: reject, send CONFLICT { hubVersion, hubSnapshot }

Hub-side conflict detection

In nu_pos_hub/src/handlers/orderHandler.ts:
Terminal sends ORDER_SNAPSHOT { posReference: "ref-1", baseVersion: 2, snapshot }

Hub checks:
  1. Does terminal hold lease for "ref-1"?  -> No: send LEASE_DENIED
  2. Is baseVersion >= stored version?       -> No: send CONFLICT
  3. Accept: upsert (version = stored + 1), broadcast ORDER_UPDATED
The hub always has the authoritative version. Terminals must resolve conflicts before retrying.

Frontend reconciliation

When the terminal receives a CONFLICT message, reconcile() in nu_pos_react/src/realtime/sync/reconcile.ts decides what to do.

Strategies

StrategyWhen usedAction
accept_remoteNo local changes, paid orders, far behindReplace local state with hub snapshot
mergeLocal has new line additions, 1 version behindAppend local-only lines to hub snapshot
keep_local(Reserved for future use)Re-send local version (requires version bump)

Decision flow

CONFLICT received
    |
    +-- No local line changes?      --> accept_remote
    |
    +-- Order is paid?              --> accept_remote
    |
    +-- More than 1 version behind? --> accept_remote
    |
    +-- Local has new lines not in remote?
    |       |
    |       +-- Yes: merge (remote lines + local-only additions)
    |       +-- No:  accept_remote

Merge logic

When a merge is possible (terminal is exactly 1 version behind with local-only line additions):
1

Build remote set

Build a set of remote line IDs
2

Find local-only lines

Find local lines whose IDs are not in the remote set (these are new additions)
3

Concatenate

remote.lines + localOnlyLines
4

Recalculate totals

remote.totals + sum(localOnlyLines)
This handles the common case of two terminals adding items to the same order concurrently.

Example

Hub state (v3):   lines = [A, B, C]
Local state (v2): lines = [A, B, D]    (terminal added D locally)

CONFLICT: baseVersion=2, hubVersion=3

Merge result:     lines = [A, B, C, D]  (hub's C + local's D)

UI integration

When a conflict occurs, the SyncUIProvider shows a ConflictDialog:
  • “Load Latest” — Calls reconcile() with accept_remote, replaces local order state
  • “Keep Mine” — User decides to discard the remote and try to re-send (rare)
The dialog shows the order reference, hub version number, and number of lines in the hub version.

Conflict prevention

The best conflict resolution is prevention. The system minimizes conflicts through:
  1. Leases — Only the lease holder can submit snapshots
  2. Heartbeats — Keep leases alive during active editing
  3. Optimistic versioning — Send baseVersion with every snapshot so the hub can detect staleness
  4. Instant broadcast — Other terminals see changes in real-time, reducing the window for stale edits