Parent
#237
What to build
Implement QR code check-in: system generates a unique QR token per enrollment on confirmation, organizer scans it to check participant in. Token is reusable across event days.
QR Token generation:
- When enrollment transitions to
confirmed: automatically generate a unique token in events_qr_tokens
- Token format: URL-safe random string (32+ chars), unique across all tokens
- Optional
expires_at (nullable — if null, valid for event lifetime)
- One token per enrollment (created once, reused per day)
Extend CheckInAction (qr_code path):
- Input: token string + event_date (date derived from scan time)
- Validates: token exists and belongs to an enrollment in this event
- Validates: enrollment status is
confirmed or checked_in
- Validates: token not expired (
expires_at IS NULL OR expires_at > now())
- Validates: no check-in for this enrollment + date yet
- Creates check-in record with method=qr_code, payload={token: "..."}
- Same status transition logic as other methods
- Dispatches
ParticipantCheckedIn
Admin panel — Scan interface:
- "Scan QR" page/action accessible from Event resource
- Input field for token (simulates scan — actual camera integration is frontend concern)
- Shows participant name + status on successful scan
- Error display for invalid/expired tokens
App panel — QR display:
- "My QR Code" section on enrollment detail (visible when status=confirmed or checked_in)
- Renders QR code image from token (using a QR library or inline SVG generation)
- Shows "Present this QR to the organizer" instruction
Token lifecycle:
- Generated on
confirmed transition
- NOT regenerated on subsequent transitions (e.g., checked_in → stays same token)
- If enrollment is cancelled: token can be soft-invalidated (or just check enrollment status on scan)
Acceptance criteria
Blocked by
Parent
#237
What to build
Implement QR code check-in: system generates a unique QR token per enrollment on confirmation, organizer scans it to check participant in. Token is reusable across event days.
QR Token generation:
confirmed: automatically generate a unique token inevents_qr_tokensexpires_at(nullable — if null, valid for event lifetime)Extend
CheckInAction(qr_code path):confirmedorchecked_inexpires_at IS NULL OR expires_at > now())ParticipantCheckedInAdmin panel — Scan interface:
App panel — QR display:
Token lifecycle:
confirmedtransitionAcceptance criteria
confirmedstatusParticipantCheckedIndomain event dispatchedBlocked by