Visitor sign in kiosk: multi-site, badge printing, WWCC expiry warnings, admin accounts with 2FA

This commit is contained in:
2026-09-02 16:45:48 +10:00
parent ff9f51eaf9
commit 8c97c314e0
11 changed files with 211 additions and 247 deletions
+27 -22
View File
@@ -115,19 +115,23 @@ whatever space the clock leaves over. The setting applies to the site name too,
uploaded. SVG is deliberately not accepted:
it can carry script, and this file is served to every kiosk.
**Colours.** Three are settable:
**Colours.** Four are settable:
| Setting | Where it shows |
|---|---|
| Bar and buttons | The top bar, the Sign in door, primary buttons, the confirmation mark |
| Sign out | The Sign out door and the signed-out confirmation |
| Page background | Behind everything, with card and rule colours derived from it |
| Body text | Headings, answers, and the source for the softer label colour |
Everything else is worked out from those three. In particular the **text colour on a coloured
background is chosen by contrast**, not fixed — pick a pale yellow for the bar and the text on
it turns dark automatically, instead of staying white and becoming unreadable. Card, border and
body-text colours follow the page colour, so a dark background gives a usable dark theme rather
than white boxes.
Two things are still worked out rather than set. **Text on a coloured background** is chosen by
contrast, so a pale yellow bar gets dark text instead of unreadable white. And the **muted colour**
used for field labels and hints is your body text mixed towards the background only as far as it
can go while still clearing WCAG AA at 4.5:1 — a fixed grey looks fine on the default background
and vanishes on a custom one, which is the usual cause of text that blends in.
The site editor shows the contrast ratio as you type and warns below 4.5:1. Aim for 7:1 or better
on a kiosk people read standing up.
Leave a colour box empty to fall back to the default. Anything that is not a six-digit hex value
is ignored rather than applied.
@@ -310,28 +314,29 @@ database and retried every minute, so a dropped internet connection never blocks
6. Restart, then **Admin → System → Test the sheet connection**. Both tabs and their headers
are created the first time.
### Two tabs, two jobs
### What the sheet holds
The spreadsheet gets two tabs, both created automatically:
**Only the people currently on site.** One tab, rewritten in full whenever anyone signs in or
out. Nothing is appended, so there is no history to scroll past while you are standing in a car
park counting heads — the top row says `On site now — 3 people — updated 31/08/26, 14:12`, and
everything under it is someone still in the building.
**On site now** — rewritten every time anyone signs in or out, so it only ever lists the people
currently in the building. No filtering, no scrolling to the bottom. The top row shows a head
count and the time it was last updated, so you can tell at a glance whether it is live. This is
the tab to bookmark on the phones that matter and to open at the assembly point.
Rewriting rather than patching is deliberate: a failed update can never leave a stale name on the
evacuation list, because whatever is on the tab is what the database said at the time shown. If a
write fails the tab is marked stale and rewritten on the next pass, once a minute. It also
refreshes every 15 minutes on its own to keep the "on site for" column honest.
**Visitor log** — append only. Every sign in and sign out, forever, with times in and out.
This is the record you go back through weeks later.
The **full visit history stays in the application** — searchable under **Visit log** in the admin
console, and downloadable as CSV. It is not sent to Google, which keeps visitor contact details
and movement history off a cloud service that only exists here for the evacuation case.
Rename them with `SHEETS_LOG_TAB` and `SHEETS_ONSITE_TAB`. Names with spaces are fine.
Every row carries the site name, so one spreadsheet covers every site.
The live tab is rebuilt from the database rather than edited row by row, so it is self-healing:
if a write fails, the next one puts everything right. It also refreshes every 15 minutes on its
own to keep the *On site for* column honest, and rebuilds at startup in case anyone signed out
while the container was down. **Admin → System → Rebuild the live list** forces it.
**Bookmark the sheet on the phones that would actually be used in an evacuation, and check it
after setup.** A sheet nobody can find is not a safety measure.
Anything you type into these tabs by hand will be overwritten. The sheet is a mirror, not the
source of truth — nothing is ever read back from it. Every row carries the site name, so one
spreadsheet covers every site.
*Upgrading from an earlier version:* the old "Visitor log" tab is left alone but no longer
written to. Delete it by hand when you are ready.
## Recurring visitors and PINs