What this app is
Access Control is a staff device app for checking people into an event space by scanning a badge. It is not an attendee-facing registration or ticketing product.
Operators (gate staff) install one private Play app (com.hindavi.accesscontrolapp), pick ADNEC, DMG, Xporience, or Terrapinn, log in, pick a space, scan badges with a Zebra laser or the camera, keep going when the network drops, then export or email a report.
There are no separate client-specific APKs going forward. Older per-client installs (for example the former DMG package) should be uninstalled once during migration, then the single app is used for all events. Operator install + switch steps: docs site /installation and docs/operator-single-app-setup.md.
The selected client’s backend is the system of record for whether a badge is allowed. The phone is the system of record for what this device scanned, including scans that never reached the server. Clients do not share scan/history data — each row is tagged with client_id.
Who it is for
There is no attendee self-registration flow in this app. If a meeting talks about “registration 409”, that is a different product. Do not map those scenarios onto this codebase.
What success looks like on the floor
- Staff pick the correct client (remembered on the device).
- Staff can log in on the event network.
- They can select the correct space.
- A valid badge produces a success sound and is stored on the device.
- An invalid or restricted badge produces an error and is not stored as a successful check-in (on the Home laser path).
- If the network times out, the scan is queued offline and still shows success to the operator so the queue keeps moving.
- Unsynced scans can be flushed later. Logout is blocked until the current space’s offline queue is empty (and the device is online).
- Switching clients is only allowed while logged out. Unsynced scans for the client being left must be synced or wiped first.
Why the product is built this way
Events fail on Wi-Fi, not on happy-path demos. The app is intentionally offline-capable:
- Login and space list require internet. You cannot invent a session.
- The API host (and JWT signing secret) are chosen at launch from the client picker, not at compile time.
- Scanning does not require internet. A timeout or 5xx is treated as “save locally, sync later” on the primary Home laser path.
- Reports are produced from device memory (Redux persisted to AsyncStorage), not from a live server fetch.
- Email is the device mail client (Gmail), not a backend “send report” API.
That is why a backend 500 during a scan can still look like “Successfully Checked in” on the phone. That is not a UI lie by accident. It is the documented fallback so the gate does not stop. Whether that fallback is correct for a given status code is a contract question — see Ownership and Scenarios.
Out of scope (this app)
- Attendee registration / payment
- Wear OS, Live Activities, Dynamic Island, home-screen widgets
- SQLite or MMKV stores
- Background server sync when the app is killed (queue only flushes when a user taps sync / changes space)
- A public attendee-facing website inside this repo (the docs site is operator + team documentation)
How to use this set of docs
Do not invent a sixth “process” document. The hub is the process.