Leases enforce single-writer ownership on orders. Only the terminal holding the lease for an order can submit snapshots. This prevents two terminals from concurrently editing the same order and creating divergent state.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 it works
Acquiring a lease
- Terminal opens an order and sends
LEASE_ACQUIRE { posReference, baseVersion } - Hub checks if the order is already leased:
- Not leased — Grant immediately. Returns
LEASE_GRANTED { version, expiresAt } - Leased by same terminal — Grant (re-entrant). Returns current version
- Leased by another terminal — Deny. Returns
LEASE_DENIED { holder, reason }
- Not leased — Grant immediately. Returns
- Terminal must hold a lease before sending
ORDER_SNAPSHOT
Maintaining a lease
- Leases expire after 60 seconds (
LEASE_TTL_MS) without renewal - Terminals send
LEASE_HEARTBEATevery 20 seconds (HEARTBEAT_MS) - Each heartbeat resets the expiry to
now + 60s - If a terminal crashes or loses connection, the lease auto-expires
Releasing a lease
- Terminal sends
LEASE_RELEASE { posReference, finalSnapshot? } - If
finalSnapshotis provided, the hub saves it before releasing - This happens when closing an order, navigating away, or paying
Lease expiry (tick)
The hub runs a periodic tick every 20 seconds:- Query all leases where
expires_at <= now - For each expired lease:
- Load the last known order snapshot
- Send
LEASE_REVOKED { posReference, reason: "Lease expired", snapshot }to the terminal - Delete the lease from storage
- The order is now available for other terminals
Disconnect grace period
When a terminal’s WebSocket disconnects (network drop, browser close):- Hub does not immediately revoke leases
- Instead, sets lease expiry to
now + 10s(grace period) - If the terminal reconnects within 10 seconds, it can resume editing
- If grace period expires, the normal tick process revokes the lease
Manager override
Managers can forcibly take over an order held by another terminal:
Non-managers who attempt to access a held order see a
LEASE_DENIED response. Managers see a confirmation dialog before sending the force-acquire.
Lease storage
Leases are stored in SQLite (nu_pos_hub/src/storage/leaseStore.ts):
grant(), renew(), release(), getExpired(now), getByTerminal(id).
Frontend lease handling
In hub mode,hubTransport.ts manages lease state:
acquireLease()sendsLEASE_ACQUIREand returns aPromise<LeaseResult>that resolves onLEASE_GRANTEDorLEASE_DENIED(or times out after 10 seconds)releaseLease()sendsLEASE_RELEASEand removes from internalheldLeasessetisLeaseHeld()checks the internal setonLeaseRevoked()fires when hub sendsLEASE_REVOKED
directTransport.ts uses local tab-level locks (orderLocks.ts) with a 45-second TTL. No network coordination exists.
Timing summary
| Parameter | Value | Configurable via |
|---|---|---|
| Lease TTL | 60s | HUB_LEASE_TTL_MS env var |
| Heartbeat interval | 20s | HUB_HEARTBEAT_MS env var |
| Disconnect grace | 10s | HUB_GRACE_MS env var |
| Acquire timeout (frontend) | 10s | LEASE_TIMEOUT_MS constant |
| Tick interval (hub) | 20s | Same as heartbeat interval |