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.

The POS system is designed to never block staff from taking orders, regardless of network conditions. Every local action is captured as an idempotent event and safely queued for later delivery.

How offline works

ScenarioBehavior
Odoo down (direct mode)Outbox queues HTTP requests, retries with exponential backoff
Hub down (hub mode)Transport falls back to outbox; orders still editable locally
Internet down (hub mode)Hub still works on LAN; terminals sync via hub normally
Hub + Internet downTerminal works fully offline, outbox accumulates
RecoveryOutbox drains automatically; hub reconciles on reconnect

localStorage outbox

nu_pos_react/src/realtime/sync/outbox.ts The outbox is a queue of pending HTTP actions stored in localStorage under the key pos_sync_outbox. It survives browser refreshes and crashes.

Entry structure

interface OutboxEntry {
  id: string;                    // UUID
  action: "orders/create" | "orders/update";
  payload: Record<string, unknown>;
  createdAt: string;             // ISO timestamp
  attempts: number;              // Number of send attempts
  nextAttemptAt: string | null;  // Earliest retry time
  lastError: string | null;      // Last failure message
}

Queuing

queueOutbound("orders/create", {
  pos_reference: "POS-001-0001-00001",
  lines: [...],
  amount_total: 150.00,
});
Entries are deduplicated by pos_reference: if an entry with the same reference already exists, it’s replaced with the newer payload. This prevents duplicate orders. In hub mode, when connection.send() fails, the snapshot is queued as an outbox entry with an _hubSnapshot field.

Flushing

flushOutbound() processes the queue:
  1. Reads all entries from localStorage
  2. Filters entries where nextAttemptAt <= now (respects backoff)
  3. For each entry, sends POST /pos-react/api/orders/{action} to Odoo
  4. On success: removes entry from queue
  5. On failure: increments attempts, computes next retry time, stores error

Retry backoff

AttemptDelay
11s
22s
34s
48s
516s
6+32s-60s (capped)
After maxRetry attempts (default 8), the entry stays in the queue but won’t be retried until app restart.

Outbox depth monitoring

The transport exposes getOutboxDepth() which returns the current number of pending entries. This is reflected in the sync state machine via OUTBOX_CHANGED events and displayed by the SyncStatusIndicator badge.

Hub-side event log

The hub maintains its own event log for upstream forwarding to Odoo. This is a separate mechanism from the terminal outbox.
CREATE TABLE events (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  type          TEXT NOT NULL,     -- 'order_snapshot', 'table_update', etc.
  pos_reference TEXT,
  terminal_id   TEXT,
  payload       TEXT,              -- JSON
  forwarded     INTEGER DEFAULT 0, -- 0=pending, 1=forwarded to Odoo
  created_at    TEXT DEFAULT (datetime('now'))
);

Forwarder

nu_pos_hub/src/upstream/forwarder.ts drains the event log to Odoo:
  1. Runs every 5 seconds (FORWARD_INTERVAL_MS)
  2. Queries up to 20 pending events (FORWARD_BATCH_SIZE), oldest first
  3. Non-order events are marked as forwarded immediately (no Odoo action needed)
  4. Order snapshot events are forwarded via the Odoo adapter
  5. On success: marks events as forwarded=1
  6. On first failure: logs error, stops processing batch (preserves ordering)
If Odoo is unreachable, the hub authenticates first, then retries. Events accumulate safely in SQLite.

Idempotency

All order operations are idempotent via pos_reference:
  • Odoo’s create endpoint returns the existing order if the reference already exists
  • The hub’s orderStore.upsert() uses INSERT OR REPLACE keyed by pos_reference
  • The outbox deduplicates by pos_reference before queuing
Re-forwarding the same event (after a crash, restart, or retry) is always safe.

Visibility

ToolWhat it shows
SyncStatusIndicator (frontend)Transport state, outbox depth, error indicator
Hub dashboard (http://hub:8766/)Connected terminals, pending forwards, event log
CLI pos-hub statsUptime, terminal count, pending/forwarded events
CLI pos-hub eventsRecent event log with forwarded status