Public Access
Claude Context
This commit is contained in:
1 parent
d998b6731e
commit
5cf885d683
3 files changed
+286
No files matched your search
@@ -0,0 +1,71 @@
|
||||
# visitor-signin — architecture
|
||||
|
||||
Current state of the design. Established 2026-09-23 (first recorded session). When a later
|
||||
session changes something here, edit the relevant section and note the date and reason.
|
||||
|
||||
## Process layout
|
||||
One Node process in one container:
|
||||
- HTTPS listener on container port 3000 (kiosk, admin, APIs).
|
||||
- Plain-HTTP helper on 3001: serves the CA certificate and redirects everything else to HTTPS.
|
||||
- Background jobs in-process: photo retention purge, optional nightly auto sign-out, daily
|
||||
certificate renewal check, Google Sheet sync retries.
|
||||
|
||||
## Data
|
||||
- SQLite at `/data/visitors.db` (bind-mounted `./data`), WAL mode.
|
||||
- Photos on disk under `/data/photos/YYYY/MM/`; banners under `/data/branding/`; certs under
|
||||
`/data/certs/`.
|
||||
- Migrations are additive and idempotent (`addColumn` in `src/db.js`) — never destructive.
|
||||
- `visits` denormalises name, contact, host and site name, so history survives deletion of the
|
||||
related records.
|
||||
|
||||
## Identity and access
|
||||
- Admin accounts: email + scrypt password + TOTP (RFC 6238), eight one-shot recovery codes.
|
||||
Roles `owner` (manages admins and sites) and `admin` (optionally scoped to one site).
|
||||
Optional email-domain restriction. First account created once from `ADMIN_BOOTSTRAP_*`.
|
||||
- Recurring visitors: mobile number is the username; PIN is 4 digits, stored AES-256-GCM
|
||||
encrypted with a keyed HMAC `pin_lookup` for uniqueness. Phone, email and PIN are each unique.
|
||||
- `APP_SECRET` keys sessions, PIN encryption and `pin_lookup`. Changing it breaks every PIN.
|
||||
|
||||
## Multi-site
|
||||
- `sites` owns: people to visit (`hosts`), badge settings, printer settings, branding.
|
||||
- A kiosk is bound to a site by `/?site=<slug>` (remembered in the tablet's local storage) or a
|
||||
first-run picker; a single-site install never asks.
|
||||
- Sign in, sign out and duplicate detection are scoped per site.
|
||||
|
||||
## TLS
|
||||
- Local CA (10 years) + server certificate (398 days), generated by the container with openssl.
|
||||
- Server cert renews inside 30 days and is hot-swapped with `setSecureContext`; the CA is never
|
||||
replaced except by an explicit `--force`, so devices trust it once.
|
||||
- Reissue is triggered by a change in `HTTPS_HOSTNAMES` (tracked in `certs/.hostnames.json`),
|
||||
not by the full SAN list, because the container's own bridge IP changes between restarts.
|
||||
- CA distributed as PEM `.crt`, DER `.cer` (required by Jamf Pro) and a zip bundle (browsers
|
||||
block bare certificate downloads).
|
||||
|
||||
## Printing
|
||||
- The server renders the badge (`src/printer.js`, `@napi-rs/canvas`) at 300 dpi, 696 dots across
|
||||
(QL-820NWB head width on a 62 mm roll), and sends it with `brother_ql` over TCP 9100.
|
||||
- Photos are halftoned in the renderer (Floyd–Steinberg by default) so preview equals print.
|
||||
- The loaded roll is an explicit per-site setting (`printer_label`: `62` or `62red`). `62red`
|
||||
always adds `--red`; without it the job is monochrome and the printer refuses it.
|
||||
- Sign in waits up to `PRINT_SIGNIN_WAIT_MS` for the print; on failure the kiosk falls back to a
|
||||
browser print of the HTML badge (`src/sites.js`).
|
||||
- `brother_ql`'s network backend never reads the socket and the QL-820NWB does not answer status
|
||||
requests on 9100, so the server cannot confirm a label came out. Brother Status Monitor on a
|
||||
connected PC is the source of truth for refusals.
|
||||
|
||||
## Google Sheet
|
||||
- Evacuation mirror only: one tab ("On site now"), rewritten in full on every sign in/out and
|
||||
every 15 minutes. No history is sent to Google; history lives in the app (Visit log, CSV).
|
||||
- A failed write marks the tab stale and is retried; it never blocks the kiosk.
|
||||
|
||||
## Front end
|
||||
- Three separate documents: kiosk (`index.html`), login (`login.html`), console (`admin.html`).
|
||||
- Kiosk theming is per site: four chosen colours, the rest derived with WCAG contrast rules.
|
||||
- HTML/JS/CSS served with `Cache-Control: no-cache` so an upgrade is never masked by a cached
|
||||
console.
|
||||
|
||||
## Deployment
|
||||
- Author on Windows, deploy on an Ubuntu docker host from the `deploy` branch with
|
||||
`git reset --hard origin/deploy` (the host is a mirror, never merges).
|
||||
- `docker-entrypoint.sh` fixes ownership of the bind-mounted `/data`, then drops to `node`.
|
||||
- `pull_policy: build` — the image is always built locally.
|
||||
Reference in new issue
Block a user