Run the door offline

Pull the bundle before doors, queue scans on the device, and sync the batch back afterwards.

Owned by Venue Manager · 11 steps · about 20 minutes

Why this exists

Offline is a first-class mode here, not a degraded fallback. The assumption behind the design is that a warehouse door will lose the network at exactly the wrong moment, and that a queue of two hundred people is not the time to discover it. So the device is prepared before doors: a manager pulls a bundle containing the night's valid pass payloads, their time-code secrets, the revocation list, the verification key fingerprints and a snapshot of who is already checked in.

That bundle is the reason offline sync has a stricter permission than scanning itself. Anyone who can scan can scan; but the bundle is replayable credentials for the entire venue, so pulling it needs a venue_manager-or-above session naming a reader, or the reader's own provisioned device token. A plain door_staff session gets a 403, and the scanner page hides the control from them rather than teasing it — they see a badge reading bundle: manager only. That is not distrust of the person on the door, it is a decision about which device a venue's whole credential set is allowed to land on.

The second half is the sync. Offline scans are queued in the browser with a client-generated id, and pushed back as a batch of up to five hundred. The server trusts the results in that batch — it does not re-validate them, because the device was the thing that made the decision — but it replays the check-in state changes in scanned-at order and dedupes on the client id. So syncing twice is safe, and a scan that arrives late still lands in the right place in the night's timeline.

The trap, and you must teach it explicitly: the built scanner queues every offline scan as green / ok. It does not validate anything locally against the bundle. Offline mode on this build means 'let everyone in and record it', not 'validate against the bundle'. That is a deliberate simplification of the reference UI, and it means offline mode is a decision about crowd flow, not a security-neutral toggle.

Before you start

  • A venue manager or admin session for the bundle (door staff cannot pull it).
  • An event in announced, on_sale, sold_out or in_progress with issued passes.
  • A reader selected on the scanner — the sync endpoints require one.

Practise with

PersonaEmailPasswordNote
venue_managermanager@club.test manager123shift lead: implies door_staff, plus intake, sales, guest list, marketing
door_staffdoor@club.test door123door shift account: scanner + guest list, nothing else
adminadmin@club.test admin123the only account that can touch money, identity and contracts

Steps 1–4 — Venue Manager

their manual →
  1. 1
    Well before doors, sign in on the door device as the manager, pick the reader, and pick the event in the Event (for door bundle) dropdown.
    /scanner access
    Expected result Both dropdowns set, and a Download door bundle button — visible because you are a manager.
    Watch out for If you see a badge reading bundle: manager only instead of the button, you are signed in as door staff. Swap the session before the queue starts, not during it.
  2. 2
    Press Download door bundle. The page stores it in the device's local storage and the status badge changes to show how many passes came down.
    Expected result A badge reading bundle: N passes.
    Watch out for The bundle never contains the raw signing key — HMAC is symmetric, so publishing it would let the device mint credentials. It ships key fingerprints only, which are enough to notice a rotation and nothing else.
  3. 3
    Confirm the live push feed is running: the badge next to the reader picker should read push: live with a cursor number. This is the long-poll that tells a device about revocations and check-ins that happened elsewhere.
    Expected result push: live @ some number, refreshing every few seconds.
    Watch out for The push feed needs the same manager-or-token permission as the bundle. On a door_staff session it reads push: manager only and never polls — so a door staff device will not learn about a mid-shift revocation on its own.
  4. 4
    Brief the door before you hand the device over: while Offline mode is ticked, every scan is accepted and queued. Nobody is turned away by the device.
    Expected result The person on the door understands they are recording, not validating.
    Watch out for This is the single most important sentence in this workflow. Do not leave Offline mode ticked because it 'feels faster' — you have turned the door into a counter.

Steps 5–7 — Door Staff

their manual →

Actually works the queue in offline mode and presses Sync now when the network returns.

  1. 5
    When the network drops, tick Offline mode and keep scanning. The queue counter next to it climbs with every scan.
    /scanner access
    Expected result Each scan shows a green panel reading Queued (offline) with queued offline in place of a latency figure.
    Watch out for Queued (offline) is not a verdict. It means 'stored on this phone', nothing more. Watch the queue counter — if it stops climbing, the browser storage has a problem and you are now admitting people with no record at all.
  2. 6
    As soon as the network returns, untick Offline mode and press Sync now.
    Expected result The status badge changes to a sync line with the accepted count and the duplicate count.
    Watch out for Do not clear the browser data, close the tab into oblivion, or hand the device to the next shift before syncing. The queue lives in that browser and nowhere else.
  3. 7
    Understand what a duplicate means: every queued scan carries a client-generated id, and the server skips any id it has already stored. Pressing Sync now twice is harmless.
    Expected result Duplicates counted separately from accepted, and no double entries.
    Watch out for A scan queued without a client id is skipped entirely and reported as a conflict. If accepted plus duplicates does not equal what you scanned, say so — the difference is people you admitted with no log row.

Steps 8–9 — Venue Manager

their manual →
  1. 8
    After the sync, pull the scan log for the event and look at the offline flag column to see which rows arrived by batch.
    Expected result Synced rows flagged as offline, carrying their original scanned-at time rather than the sync time.
    Watch out for Batch scans keep the time they happened, which is why the door timeline still makes sense afterwards. If you see a wall of identical timestamps, someone queued without a real clock.
  2. 9
    Check the Readers table's cache column — push lag and last bundle time — to confirm the device really did sync and is not quietly stale.
    /admin/access access
    Expected result A recent last-sync time against that reader.
    Watch out for Conflicts reported by a batch are worth reading, not dismissing. The common one is a serial that was already checked in, which the server records without double-counting the entry — usually two devices scanning one queue.

Steps 10–11 — Admin

their manual →

Provisions the reader device tokens that make a device able to sync without any session at all.

  1. 10
    For a permanent door device, provision a reader properly instead of relying on a manager session. The creation response contains the device token, and that is the only time it is ever shown.
    /api/access/readers POST access
    Expected result A reader row and a one-time device token.
    Watch out for Copy the token then — the API never shows it again, and rotating is the supported way to get a working one. Do NOT treat that as the token being unrecoverable: it is still held in the reader row, so anyone with database or admin-console access can still obtain it. Rotate whenever a device leaves your control, not only when you have lost the copy.
  2. 11
    If a device is lost, rotate its token rather than deleting the reader.
    /api/access/readers/{reader_id}/rotate-token POST access
    Expected result A new token; the old one stops authenticating immediately.
    Watch out for Deleting the reader would orphan its scan history. Rotate, always — the reader row is the identity that the night's log hangs off.