Scanner Verify (ActiveCAMT)
A checklist to confirm the QR check-in flow still works AND that medical data isn't
leaked by role. Gating here spans 4 layers (src/proxy.ts, src/lib/admin-access.ts,
the scan API, the scanner UI) — a change to one can silently break another. Verify
behavior, don't assume.
The flow (what you're verifying)
signQrToken(userId) (src/lib/qr-token.ts, ~5-min window + ~30s grace) → student shows QR → scanner POST /api/admin/scan (rate-limited ~300/min) → ScannerService.processScan (src/modules/events/scanner.service.ts) → pre-registered path (atomic UPDATE … WHERE status='registered') or walk-in path (row-lock + quota recount, totalCap = quota + quotaWalkIn, ON CONFLICT DO NOTHING) → attendance write + AuditService.logAction.
Setup
Use /db-local to bring up activecamt-db and seed-author for fake students/events, then npm run dev (or /run). Exercise with seeded data only — never real attendees.
Cases to verify
- Pre-registered check-in — a
registeredstudent scans → status flips toattended. Scan again → no double count (theWHERE status='registered'guard holds). - Walk-in — a non-registered student scans an event with walk-in capacity → admitted up to
quota + quotaWalkIn; the next over-cap walk-in is rejected. Concurrent walk-ins must not exceed cap (row-lock + recount). - Token validity — an expired token (past window+grace) is rejected; a tampered token is rejected; the intended manual/legacy fallback still works.
- PDPA medical gating by role (CRITICAL) — log in as each role and inspect the actual JSON of the scan response (Network tab), not just the UI:
super_admin/admin→ may include medical detail.registration/organizer/smo→ only the medical signal, never detail — and confirm anypending_confirmation/nested payload doesn't smuggle detail into JSON that the UI happens to hide.
- SMO confinement —
smocan reach/admin/scanneronly;action=score/action=lookupare rejected server-side for non-SCORING_ROLES. - Audit — every successful check-in writes an
audit_logsrow.
Hard rules
- Local data only — never test against prod attendees/PII.
- The PDPA check (#4) must inspect the network response per role, because a leak can be invisible in the UI but present in the JSON.
Output
Pass/fail per case (1–6), with case #4 (medical gating by role) and #2 (quota race) called out explicitly. For deeper coverage, pair with test-author (unit tests for qr-token + admin-access) and pdpa-access-guard (static review, including its route+audit checklist). /verify is the general live-run skill; this is its scanner-specialized recipe.