Components
PCloudflare Pages
Static React dashboard plus a same-origin /api proxy. It holds no Cloudflare token, and browser credentials stay on the adopter’s Pages origin.
WWorker + D1
Authorization, validation, scrypt auth, AES-GCM integration secrets, audit trails, attendance, exports, and provider calls.
πRaspberry Pi + R503
LAN-limited first pairing, loopback-only operational tools, serial sensor I/O, local mappings, atomic offline queue, protected networking/maintenance, and hashed bearer pairing.
Security invariants
- Every organization query is scoped to installation
primary.
- Admin and Operator permissions are enforced by Worker routes, not only hidden in UI.
- Sessions are HMAC-signed, HTTP-only, Secure, SameSite cookies with an eight-hour lifetime; protected requests reload active status and role from D1.
- Google OAuth uses signed ten-minute state and validates issuer, audience, verified email, and active user membership.
- Local passwords use salted scrypt (N=32768, r=8, p=1).
- Integration credentials use AES-256-GCM with a per-installation Worker secret.
- Provider verification challenges expire after ten minutes and store only SHA-256 hashes; unverified credentials cannot run operational email or Discord workflows.
- Pairing codes and kiosk credentials are stored remotely only as SHA-256 hashes.
- Meeting windows cannot overlap, allowing the Worker to resolve a kiosk scan to at most one meeting.
- Remote kiosk recovery accepts four enumerated, device-scoped commands and no shell text or arbitrary arguments.
- CSV export neutralizes spreadsheet formula prefixes before quoting cells.
Verification and source reference
CI runs workspace typechecks, Node unit tests, Worker runtime tests, production builds, dependency auditing, and sanitizer checks. Read docs/ARCHITECTURE.md, docs/SECURITY.md, and docs/BACKUP-RESTORE.md in the repository for durable technical detail.