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.

Prerequisites

  • Node.js 20+ (node -v to check)
  • Odoo 12 running locally at http://localhost:8069 with a POS session open
  • A terminal with 3 tabs

Step 1: Build the protocol package

The protocol package must be built first since the hub depends on it.
cd nu_pos_sync_protocol
npm install
npm run build

Step 2: Start the hub in dev mode

Open a new terminal tab:
cd nu_pos_hub
npm install
Create a .env file for local development:
.env
ODOO_URL=http://localhost:8069
ODOO_DB=pos
ODOO_USER=admin
ODOO_PASSWORD=admin
HUB_HTTP_PORT=8766
HUB_DB_PATH=./dev.sqlite
HUB_LOG_LEVEL=debug
HUB_MDNS_ENABLED=false
HUB_DEV_AUTH=true
HUB_DEV_AUTH=true enables dev-mode auth bypass. When the frontend sends an empty token, the hub authenticates using its own Odoo credentials instead of rejecting the connection.
Start with tsx (auto-reloads on changes):
npm run dev
Verify it works:
curl http://localhost:8766/health | python3 -m json.tool
Expected output:
{
    "status": "ok",
    "uptime": 5,
    "connectedTerminals": 0,
    "activeLeases": 0,
    "orders": 0,
    "pendingForward": 0,
    "totalForwarded": 0,
    "lastOdooSync": null
}
Open http://localhost:8766/ in a browser to see the live dashboard.

Step 3: Enable hub mode in Odoo

  1. Go to Point of Sale > Configuration
  2. Set nu_hub_enabled = checked
  3. Set nu_hub_url = ws://localhost:8766
  4. Save

Step 4: Start the frontend

Open a third terminal tab:
cd nu_pos_react
NEXT_PUBLIC_HUB_URL=ws://localhost:8766 npm run dev
Open two browser tabs:
  • Tab 1: http://localhost:3000/pos-react/order/?table=1
  • Tab 2: http://localhost:3000/pos-react/order/?table=1
Both tabs should connect to the hub. The dashboard at http://localhost:8766/ should show 2 connected terminals.

Step 5: Test real-time sync

  1. In Tab 1: Add an item to the order
  2. Watch Tab 2: The item should appear within milliseconds
  3. Check the dashboard: 2 terminals, 1 active lease, events flowing

Test leasing

  1. In Tab 1, open an order (acquires a lease)
  2. In Tab 2, try to open the same order
  3. Tab 2 should see a “LEASE_DENIED”
  4. Navigate away in Tab 1 (releases the lease)
  5. Tab 2 can now acquire the lease

Test offline recovery

  1. Stop the hub (Ctrl+C in the hub terminal)
  2. Add items in Tab 1 — they queue in the localStorage outbox
  3. Restart the hub (npm run dev)
  4. The frontend reconnects automatically and flushes the outbox

Development workflow

Terminal 1 (hub):      npm run dev          # auto-reloads on src/ changes
Terminal 2 (frontend): npm run dev          # Next.js hot reload
Terminal 3 (tests):    npm run test         # vitest watch mode
Browser:               http://localhost:8766  # hub dashboard

Inspecting the hub database

The dev SQLite file is at nu_pos_hub/dev.sqlite:
sqlite3 nu_pos_hub/dev.sqlite

# See all orders
SELECT pos_reference, version, terminal_id, updated_at FROM orders;

# See active leases
SELECT pos_reference, terminal_id, role, expires_at FROM leases;

# See pending events
SELECT id, type, pos_reference, forwarded, created_at FROM events ORDER BY id DESC LIMIT 20;

Testing with wscat

Connect to the hub directly to test the protocol:
npx wscat -c ws://localhost:8766
Then send messages manually:
{"type":"AUTH","token":"your-odoo-session-id","deviceId":"test-001"}

Troubleshooting

Build the protocol package first:
cd nu_pos_sync_protocol && npm run build
Make sure Odoo is running and credentials in .env are correct. In dev mode, ensure HUB_DEV_AUTH=true is set.
  1. Is the hub running? curl http://localhost:8766/health
  2. Is nu_hub_enabled set to true?
  3. Check browser DevTools Network tab for WS connections
  4. Look for connection errors in the browser console
  1. Is Odoo reachable? curl http://localhost:8069/web/login
  2. Check hub logs for forwarding errors
  3. Ensure ODOO_USER/ODOO_PASSWORD has POS access
The hub didn’t respond to LEASE_ACQUIRE within 10 seconds. Usually means the hub is overloaded or the message was lost. Check hub logs.
rm nu_pos_hub/dev.sqlite
# Restart the hub — it recreates the database

Environment variable reference

VariableDefaultDescription
ODOO_URLhttp://localhost:8069Odoo instance URL
ODOO_DBposOdoo database name
ODOO_USERadminOdoo user for hub session
ODOO_PASSWORDadminOdoo password
HUB_HTTP_PORT8766HTTP + WebSocket port
HUB_DB_PATH./hub.sqliteSQLite database file
HUB_LOG_LEVELinfoLog level
HUB_MDNS_ENABLEDtruemDNS discovery
HUB_LEASE_TTL_MS60000Lease duration (ms)
HUB_HEARTBEAT_MS20000Heartbeat interval (ms)
HUB_GRACE_MS10000Disconnect grace period (ms)
HUB_FORWARD_INTERVAL_MS5000Odoo drain interval (ms)
HUB_FORWARD_BATCH_SIZE20Events per drain batch
HUB_DEV_AUTHfalseDev-mode auth bypass