← All stories

BRANCH · ef-065-kiosk-mode

Kiosk Mode (iPad self-check-in)

EF-065 Persona: Attendee self-service + organizer config Stage: Day-of (kiosk surface) Roots in: native-app-shell + day-of-operations

Native iPad in Kiosk Mode (iOS Guided Access) for unattended self-check-in. Attendees scan their own QR or type their email; iPad doesn't navigate away to other apps; staff can exit via passcode. Combines Guided Access primitives + the trunk's check-in flow with a stripped-down attendee-friendly UI.

Happy path

  1. Staff sets up the iPad.

    Sign into the native app with staff credentials. Open Settings → Kiosk Mode. Set kiosk passcode (6-digit, separate from staff password). Tap "Enter Kiosk Mode" → app guides staff to enable iOS Guided Access (iOS native). Once Guided Access locks the app, attendee-facing UI activates.

  2. Attendee approaches.

    Big "Welcome — please scan your QR or enter your email" screen. Camera viewfinder + email input + numeric keypad alternative. No menu, no other tabs. Volume + sleep buttons disabled (Guided Access).

  3. Attendee scans/enters → confirmation.

    "Welcome, [name]! You're checked in." Auto-dismisses after 5s, returns to welcome screen for the next attendee. Optional: print badge (depends on EF-067 substrate).

  4. Staff exits kiosk.

    Tap-corner-3-times reveals exit prompt. Enter kiosk passcode → exit Guided Access (iOS native triple-press home/power). Returns to staff-mode UI.

Failure modes

Kiosk passcode too short or weak

Trigger: staff enters "1234" or "111111".

Server-side validation: 6 digits, no all-same, no sequential (123456 / 654321). Common-passcode blacklist enforced. Harness: stub weak passcodes, save returns 422, list of rejected patterns.

Attendee tries to navigate away

Trigger: attendee taps URL bar, swipes from edge, presses home button.

Guided Access blocks all navigation. App stays on welcome screen. Harness: physical-device test — gesture attempts don't escape the app.

iPad rotation lock

Trigger: kiosk is mounted in landscape; rotation should be locked.

App enforces orientation lock based on staff's setup choice (portrait or landscape). Rotating the device doesn't reflow. Harness: orientation lock honored.

Email-not-found generic message

Trigger: attendee types an email not on the roster.

"We can't find that email — please see staff." Anti-probing — no leak about what the email's status is (could be unregistered, revoked, cross-event). Same UI for all rejection reasons. Harness: stub email-not-found, generic message visible.

Attendee privacy — no name display before identity confirmed

Trigger: half-typed email autocomplete from prior attendee remains visible.

Each interaction starts with a clean slate — no autocomplete, no autofill, no prior-input visible. iOS Guided Access doesn't leak across sessions. Harness: quick succession of two attendees, second sees no remnant of first.

Camera permission revoked while in kiosk mode

Trigger: parent control or admin restriction toggles camera off mid-event.

App detects, falls back to email-only entry, surfaces a banner "Camera unavailable — please use email entry below." Doesn't crash. Staff can exit kiosk to fix. Harness: revoke camera while kiosked, banner visible, email entry still works.

Network drops during kiosk

Trigger: kiosk-mode iPad goes offline.

Inherits native-app-shell offline contract. Local roster + queue continue working. Confirmation message stays the same — attendee unaware. Sync banner not displayed (kiosk UI is attendee-facing; staff sees it on exit). Harness: offline + check-in attendee, queues locally + confirms.

Already-checked-in attendee at kiosk

Trigger: attendee scans their QR but already checked in earlier.

"You're already checked in. Have a great event!" — friendly tone, no "error" framing. Auto-dismisses. Audit log row: kiosk_already_checked_in for monitoring (lots of these may indicate confused attendees). Harness: stub already-checked-in, friendly message, audit row.

Kiosk exit attempts without passcode

Trigger: someone (attendee, child, security) taps the corner 3 times to attempt exit.

Exit prompt appears. Wrong passcode 3x → 60s lockout. Lockout extends (60s, 300s, 600s) on repeated failure. Harness: 3 wrong attempts, 60s lockout banner.

iPad battery low during event

Trigger: iPad battery drops below 20%.

Subtle staff-only banner appears in the welcome screen footer (visible enough for staff during a sweep, not big enough to alarm attendees). Below 10%, larger warning. Harness: stub battery 15%, subtle banner; stub 5%, larger warning.

App crash recovery

Trigger: app crashes (rare, but possible due to memory pressure).

iOS Guided Access remains active across app relaunch (standard iOS behavior). On relaunch, app detects kiosk-mode flag set and resumes welcome screen automatically without staff intervention. Harness: simulate crash, app relaunches into welcome screen.

Stable test attributes

kiosk-setup-passcode-inputSettings → Kiosk Mode6-digit passcode entry
kiosk-setup-orientation-lockSettings → Kiosk ModePortrait/landscape choice
kiosk-enter-ctaSettings → Kiosk ModeTriggers Guided Access prompt
kiosk-welcome-screenAttendee surfaceBig "Please scan or enter email"
kiosk-cameraWelcomeAlways-on camera viewfinder
kiosk-email-inputWelcomeNumeric keypad alternative
kiosk-confirmationPost-check-in"Welcome, [name]"
kiosk-already-checked-in-messageIf pre-checkedFriendly tone
kiosk-email-not-found-messageIf not on roster"Please see staff" (anti-probing)
kiosk-camera-fallback-bannerIf camera revoked"Use email entry below"
kiosk-exit-prompt3-tap cornerPasscode entry
kiosk-exit-lockout-bannerAfter 3 wrong tries60s+ lockout
kiosk-battery-low-bannerBelow 20% batterySubtle staff-visible
kiosk-battery-critical-bannerBelow 10% batteryLarger warning

Agent test plan

Probe list
- weak-passcode-rejected: stub "1234"/"111111", save 422
- (manual) navigate-away-blocked: physical iPad, gesture/swipe, blocked
- (manual) orientation-locked: physical iPad rotation, no reflow
- email-not-found-generic: stub not-on-roster, generic message visible
- (manual) no-autofill-leak: physical 2-attendee succession, second clean
- camera-revoked-fallback-works: stub revoke, banner + email-entry works
- offline-confirms-locally: device offline, queues + confirms
- already-checked-in-friendly: stub pre-checked, friendly message + audit row
- exit-passcode-required: 3-tap corner, prompt visible, wrong passcode locks out
- (manual) battery-banners-thresholds: physical 15% subtle, 5% larger
- (manual) crash-recovery-resumes-kiosk: simulate crash, relaunches into welcome
- audit-log-kiosk-events: per-check-in audit row tagged kiosk-mode