Story 2.4: Ticket/QR Code Page - Wireframe
Story: Epic 2, Story 2.4 - Event Registration Flow (Ticket Display)
Visual Wireframe
Mobile View (Primary Interface)
βββββββββββββββββββββββββββββββββββββββββββ
β β MY TICKET β
βββββββββββββββββββββββββββββββββββββββββββ€
β β
β ποΈ SPRING CONFERENCE 2025 β
β Cloud Native Architecture β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β π
MAY 15, 2025 β
β β° 08:30 - 18:00 β
β π KURSAAL BERN β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββ β
β β β β
β β ββββββββββββββββ β β
β β ββ QR CODE ββββ β β
β β ββββββββββββββββ β β
β β ββββββββββββββββ β β
β β ββββββββββββββββ β β
β β β β
β β Scan at event entrance β β
β β β β
β βββββββββββββββββββββββββββββββββ β
β β
β β
REGISTRATION CONFIRMED β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β π€ ATTENDEE INFORMATION β
β β
β Name: John Smith β
β Email: john.smith@company.ch β
β Company: TechCorp AG β
β β
β Ticket ID: BAT-2025-1234 β
β Issued: March 1, 2025 14:30 β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β π± QUICK ACTIONS β
β β
β βββββββββββββββββββββββββββββββββββ β
β β π Add to Apple Wallet β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β π€ Add to Google Wallet β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β π¨οΈ Print Ticket β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β πΎ Download PDF β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β π€ Share Ticket β β
β βββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β βΉοΈ CHECK-IN INSTRUCTIONS β
β β
β β’ Arrive 15 minutes early β
β β’ Have this QR code ready to scan β
β β’ Check-in desk opens at 08:00 β
β β’ Name tag will be provided β
β β
β π [Get Directions to Venue] β
β π [View Event Details] β
β π€ [View Speaker Lineup] β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β βοΈ MANAGE TICKET β
β β
β [βοΈ Update Registration] β
β [π Transfer Ticket] β
β [β Cancel Registration] β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β π This is your personal ticket. β
β Do not share publicly. β
β β
β Need help? events@batbern.ch β
β β
βββββββββββββββββββββββββββββββββββββββββββ
Desktop View
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BATbern Upcoming Events My Tickets [π€ John] β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β
β β ποΈ YOUR EVENT TICKET β β
β β β β
β β Spring Conference 2025: Cloud Native Architecture β β
β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββ TICKET βββββββββββ¬ββββββ ATTENDEE INFO ββββββββββββββββββββββββββ β
β β β β β
β β π
MAY 15, 2025 β π€ Name: John Smith β β
β β β° 08:30 - 18:00 β π§ Email: john.smith@company.ch β β
β β π Kursaal Bern β π’ Company: TechCorp AG β β
β β Kornhausstrasse 3 β π« Ticket: BAT-2025-1234 β β
β β 3013 Bern β π
Issued: March 1, 2025 14:30 β β
β β β β β
β β β β
REGISTRATION CONFIRMED β β
β β βββββββββββββββββββ β β β
β β β β β βββββββββββββββββββββββββββββββββββββββββ β β
β β β ββββββββ β β β β
β β β ββββββββ β β π± SAVE TO MOBILE WALLET β β
β β β ββββββββ β β β β
β β β ββββββββ β β [π Apple Wallet] [π€ Google Wallet] β β
β β β β β β β
β β β Scan at entranceβ β πΎ DOWNLOAD & PRINT β β
β β β β β β β
β β βββββββββββββββββββ β [πΎ Download PDF] [π¨οΈ Print Ticket] β β
β β β β β
β β BAT-2025-1234 β π€ SHARE β β
β β β β β
β β β [π§ Email] [π Copy Link] β β
β β β β β
β βββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββ CHECK-IN INSTRUCTIONS βββββββ¬ββββββ QUICK LINKS βββββββββββββββββ β
β β β β β
β β β Arrive 15 minutes early β π Get Directions to Venue β β
β β β Have QR code ready to scan β π View Full Event Details β β
β β β Check-in desk opens at 08:00 β π€ View Speaker Lineup β β
β β β Name tag will be provided β π
Add to Calendar β β
β β β Lunch & refreshments included β π₯ See Who's Attending β β
β β β β β
β ββββββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββ β
β β
β βββββββ MANAGE TICKET βββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β
β β [βοΈ Update Registration] [π Transfer Ticket] [β Cancel Registration]β β
β β β β
β β π This is your personal ticket. Keep it secure and do not share β β
β β the QR code publicly to prevent unauthorized access. β β
β β β β
β β Need help? Contact events@batbern.ch β β
β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Interactive Elements
QR Code Display
- Large QR Code: Center-aligned, high-contrast QR code (300x300px mobile, 400x400px desktop)
- Encodes:
{"registrationId": "uuid", "eventId": "uuid", "attendeeId": "uuid", "checksum": "hash"} - High error correction level (30% redundancy)
- Scannable from 1 meter distance
- Auto-adjusts brightness for optimal scanning
- Encodes:
- Tap to Enlarge (Mobile): Taps QR code to view full-screen for easier scanning
- Auto-Refresh: QR code regenerates on page load with timestamp to prevent screenshot reuse
Mobile Wallet Integration
- π Add to Apple Wallet: Generates Apple Wallet pass (.pkpass file)
- iOS devices only (button hidden on Android)
- Pass includes QR code, event details, location with map
- Lock screen notification 1 hour before event
- Auto-updates if event details change
- π€ Add to Google Wallet: Generates Google Wallet pass
- Android devices only (button hidden on iOS)
- Pass includes QR code, event details, location
- Notification before event
Download & Print Actions
- πΎ Download PDF: Downloads printable ticket PDF
- Includes QR code, event details, check-in instructions
- Optimized for A4 and Letter paper sizes
- Grayscale-friendly for B&W printers
- π¨οΈ Print Ticket: Opens browser print dialog
- Pre-formatted print-friendly view
- No headers/footers, optimized layout
Share Ticket
- π€ Share Ticket: Opens sharing modal with options:
- Email: Send ticket to another email address (with warning about security)
- Copy Link: Copy secure ticket link to clipboard
- Transfer: Transfer ownership to another person (see Transfer flow below)
- Security Warning: βShare carefully - anyone with this link can check inβ
Navigation Links
- [Get Directions]: Opens map app (Google Maps/Apple Maps) with venue location
- [View Event Details]: Navigate to Event Details page
- [View Speaker Lineup]: Navigate to Current Event Landing Page, speaker section
- [Add to Calendar]: Downloads .ics calendar file or opens calendar integration
Ticket Management
- [Update Registration]: Navigate to edit registration form
- [Transfer Ticket]: Opens transfer modal (see Transfer flow below)
- [Cancel Registration]: Opens cancellation confirmation modal
Functional Requirements Met
- FR6 (Event Access & Registration): Provides QR code ticket for event check-in and access verification
- FR15 (Mobile-Optimized Experience): Mobile-first design with offline-capable PWA, wallet integration
- FR14 (Personal Engagement): Personal ticket with attendee details, save to wallet, calendar integration
- NFR1 (Responsive Design): Optimized for mobile devices (primary use case) with desktop fallback
Technical Notes
QR Code Generation & Security
- Format: QR Code encoding JSON with registration ID, event ID, attendee ID, timestamp, HMAC signaturejson
{ "registrationId": "reg-uuid-1234", "eventId": "event-uuid-5678", "attendeeId": "user-uuid-9012", "timestamp": "2025-05-15T08:30:00Z", "checksum": "sha256-hmac-signature" } - Security: HMAC signature prevents QR code forgery, timestamp prevents replay attacks
- Expiry: QR code valid for 24 hours before event, refreshes on page load
- Validation: Backend validates signature, checks registration status, prevents duplicate check-ins
Mobile Wallet Passes
- Apple Wallet (.pkpass):
- Uses PassKit format with Apple Developer certificate
- Includes QR code as barcode, event details, logo, colors
- Location-based notification when near venue
- Push notifications for event updates
- Expiry: Auto-removes 7 days after event
- Google Wallet:
- Uses Google Pay API with signed JWT
- Includes QR code, event details, logo
- Location-based notification when near venue
- Auto-updates with push capability
- Expiry: Auto-removes after event
Offline Capability (PWA)
- Service Worker: Caches ticket page and QR code for offline access
- Offline Banner: Shows βOffline mode - ticket cachedβ when no network
- Auto-Sync: Syncs ticket updates when network restored
- Critical Data Cached: QR code, event details, attendee info stored in IndexedDB
PDF Ticket Generation
- Server-Side Rendering: Backend generates PDF with QR code, event branding
- Format: A4/Letter optimized, grayscale-friendly
- Content:
- Event name, date, time, location with map
- QR code (center, large size)
- Attendee details
- Check-in instructions
- Footer: BATbern branding, contact info
Print Optimization
- CSS Print Styles: Hide navigation, optimize layout for print
- Print-Friendly View: Single-page layout with QR code centered
- Grayscale Mode: Ensures QR code readable in B&W
Ticket Transfer Workflow
- Transfer Modal:
- Enter recipient email address
- Optional message to recipient
- Confirm transfer (warning: βYou will lose access to this ticketβ)
- Backend Process:
- Creates new registration for recipient
- Invalidates current ticket QR code
- Sends email to recipient with new ticket link
- Sends confirmation to original attendee
- Restrictions: Transfer allowed up to 24 hours before event
API Requirements
Initial Page Load APIs
- GET /api/v1/events/{eventId}/registrations/{registrationId}?include=ticket,event.venue
- Authorization: Required (authenticated user, must own registration)
- Path params:
eventId,registrationId - Query params:
include=ticket,event.venue(to embed ticket and venue data) - Returns: Complete registration with embedded ticket and event datajson
{ "registrationId": "reg-uuid", "eventId": "event-uuid", "attendeeId": "user-uuid", "status": "CONFIRMED", "ticket": { "ticketId": "BAT-2025-1234", "qrCodeData": { "registrationId": "reg-uuid", "eventId": "event-uuid", "attendeeId": "user-uuid", "timestamp": "2025-05-15T08:30:00Z", "checksum": "sha256-hmac" }, "qrCodeImageUrl": "https://cdn.batbern.ch/qr/...", "issuedAt": "2025-03-01T14:30:00Z", "canTransfer": true, "canCancel": true, "walletPassUrls": { "appleWallet": "https://api.batbern.ch/wallet/apple/...", "googleWallet": "https://api.batbern.ch/wallet/google/..." } }, "attendee": { "firstName": "John", "lastName": "Smith", "email": "john.smith@company.ch", "company": "TechCorp AG" }, "event": { "title": "Spring Conference 2025: Cloud Native Architecture", "eventDate": "2025-05-15T08:30:00Z", "endTime": "2025-05-15T18:00:00Z", "venue": { "name": "Kursaal Bern", "address": "Kornhausstrasse 3, 3013 Bern", "coordinates": {"lat": 46.9479, "lng": 7.4474} } } } - Used for: Display all ticket information, generate QR code, enable wallet integration
- Consolidation: Single endpoint with includes replaces multiple calls (Story 1.17)
User Action APIs
-
GET /api/v1/events/{eventId}/registrations/{registrationId}/ticket.pdf
- Triggered by: [Download PDF] button
- Authorization: Required (authenticated user, must own registration)
- Returns: PDF file download with ticket, QR code, and embedded event/venue details
- Used for: Downloads printable ticket PDF with QR code
- Consolidation: Nested under Events/Registrations API (Story 1.17)
-
GET /api/v1/integrations/wallet/apple?registrationId={registrationId}
- Triggered by: [Add to Apple Wallet] button
- Authorization: Required (authenticated user, must own registration)
- Query params:
registrationId - Returns: Apple Wallet pass file (.pkpass)
- Used for: Downloads Apple Wallet pass with QR code
- Consolidation: Uses consolidated Integrations API (Story 1.27)
-
GET /api/v1/integrations/wallet/google?registrationId={registrationId}
- Triggered by: [Add to Google Wallet] button
- Authorization: Required (authenticated user, must own registration)
- Query params:
registrationId - Returns: Google Wallet save URL (redirect)
- Used for: Redirects to Google Wallet save flow
- Consolidation: Uses consolidated Integrations API (Story 1.27)
-
POST /api/v1/events/{eventId}/registrations/{registrationId}/transfer
- Triggered by: [Transfer Ticket] β Confirm transfer in modal
- Authorization: Required (authenticated user, must own registration)
- Payload:json
{ "recipientEmail": "recipient@example.com", "message": "Looking forward to seeing you there!", "confirmTransfer": true } - Validation:
- Recipient email: Required, valid email format, not same as current owner
- Transfer deadline: Must be >24 hours before event
- Canβt transfer already transferred ticket
- Response:json
{ "transferId": "transfer-uuid", "originalRegistrationId": "reg-uuid-old", "newRegistrationId": "reg-uuid-new", "recipientEmail": "recipient@example.com", "transferredAt": "2025-04-01T10:00:00Z", "expiresAt": "2025-04-02T10:00:00Z" } - Used for: Transfer ticket ownership to another person, invalidate current ticket
- Consolidation: Nested under Events/Registrations API (Story 1.17)
-
POST /api/v1/content/share
- Triggered by: [Share Ticket] β Email or Copy Link
- Authorization: Required (authenticated user, must own registration)
- Payload:json
{ "contentType": "ticket", "method": "email" | "link", "registrationId": "reg-uuid", "recipientEmail": "friend@example.com", "message": "Check out my ticket!" } - Response:json
{ "shareUrl": "https://batbern.ch/tickets/secure-token-abc123", "expiresAt": "2025-05-16T00:00:00Z" } - Used for: Generate shareable ticket link (read-only, expires after event)
- Consolidation: Uses consolidated Content API for sharing features (Story 1.20)
-
PATCH /api/v1/events/{eventId}/registrations/{registrationId}
- Triggered by: [Update Registration] button
- Authorization: Required (authenticated user, must own registration)
- Payload: Partial registration updates (e.g., dietary requirements, company, etc.)
- Used for: Edit registration details
- Consolidation: Uses PATCH for partial updates (Story 1.17)
-
DELETE /api/v1/events/{eventId}/registrations/{registrationId}
- Triggered by: [Cancel Registration] β Confirm cancellation in modal
- Authorization: Required (authenticated user, must own registration)
- Response:json
{ "registrationId": "reg-uuid", "status": "CANCELED", "canceledAt": "2025-04-01T15:00:00Z", "refundAmount": 0, "message": "Sorry to see you go! Registration canceled successfully." } - Used for: Cancel registration, invalidate ticket, send cancellation email
- Consolidation: Nested under Events API (Story 1.17)
-
POST /api/v1/events/{eventId}/registrations/{registrationId}/refresh-ticket
- Triggered by: Page load, or manual refresh (every 5 minutes in background)
- Authorization: Required (authenticated user, must own registration)
- Returns: New QR code data with updated timestamp and signature
- Used for: Refresh QR code to prevent screenshot reuse, update timestamp
- Consolidation: Nested under Events/Registrations API (Story 1.17)
Navigation Map
Primary Navigation Actions
-
β Close button (Mobile) β Navigate back
- Target: Previous page (Registration Confirmation or Event Details)
- Action: Browser back navigation
- Context: No state change
-
[My Tickets] (Desktop top nav) β Navigate to Tickets List
- Target: User dashboard with all tickets
- Action: Shows all userβs event tickets
- Context: User ID
-
[Get Directions to Venue] β External map service
- Opens: Google Maps (Android/Web) or Apple Maps (iOS)
- Context: Venue coordinates and address
- Behavior: Opens in new tab or native map app
-
[View Event Details] β Navigate to Event Details page
- Target: Event Details - Attendee View (story-5.2-event-details-attendee-view.md)
- Context: eventId
- Behavior: Full page navigation
-
[View Speaker Lineup] β Navigate to Current Event Landing Page
- Target: Current Event Landing Page, speaker section
- Context: eventId, anchor #speakers
- Behavior: Full page navigation with scroll
Download & Wallet Actions
-
[Download PDF] β File download
- Action: Downloads PDF ticket file
- Filename:
BATbern-Ticket-{EventName}-{Date}.pdf - Behavior: Browser download
-
[Print Ticket] β Browser print dialog
- Action: Opens print dialog with optimized print view
- Behavior: Native browser print
-
[Add to Apple Wallet] β Wallet pass download
- Action: Downloads .pkpass file
- Behavior: iOS prompts to add to Wallet app
- Error: Show βOnly available on iOS devicesβ if not iOS
-
[Add to Google Wallet] β Redirect to Google Wallet
- Action: Redirects to Google Wallet save URL
- Behavior: Opens Google Wallet app or web interface
- Error: Show βOnly available on Android devicesβ if not Android
Share Actions
-
[Share Ticket] β Opens Share Modal
- Modal with options:
- Email ticket to someone
- Copy secure link
- Transfer ownership
- Behavior: Modal overlay on same page
- No navigation
- Modal with options:
-
[Email] (in Share Modal) β Opens Email Form
- Modal with email input field
- Sends read-only ticket link to recipient
- Warning: βThis doesnβt transfer ownershipβ
- Behavior: Sends email, closes modal, shows success toast
-
[Copy Link] (in Share Modal) β Clipboard action
- Action: Copies secure ticket URL to clipboard
- Toast: βLink copied! Valid until {event end date}β
- Behavior: No navigation, closes modal
Ticket Management
-
[Update Registration] β Navigate to Edit Registration
- Target: Event Registration Form (edit mode)
- Context: registrationId, pre-filled data
- Behavior: Full page navigation
-
[Transfer Ticket] β Opens Transfer Modal
- Modal with transfer form:
- Recipient email input
- Message field (optional)
- Warnings about losing access
- Confirm button
- Behavior: Modal overlay on same page
- Modal with transfer form:
-
Transfer Confirmation β Processes transfer
- API call to transfer ticket
- On success:
- Shows success message: βTicket transferred to {email}β
- Invalidates current ticket (QR code grayed out)
- Shows βThis ticket has been transferredβ status
- Link: βTransfer canceled? Contact supportβ
- Behavior: Modal closes, page updates to show transferred state
-
[Cancel Registration] β Opens Cancellation Modal
- Confirmation modal with warnings:
- βAre you sure you want to cancel?β
- βYou will lose access to this eventβ
- βThis action cannot be undoneβ
- Free event notice: βNo refund (free event)β
- Options: [Keep Ticket] [Cancel Registration]
- Behavior: Modal overlay
- Confirmation modal with warnings:
-
Cancellation Confirmed β Processes cancellation
- API call to cancel registration
- On success:
- Shows cancellation confirmation
- Invalidates ticket (QR code removed)
- Navigate to cancellation confirmation page
- Behavior: Redirects to confirmation page
Event-Driven Navigation
-
Ticket Transferred (by user) β Show Transferred State
- Ticket marked as transferred
- QR code grayed out or removed
- Message: βThis ticket was transferred to {email} on {date}β
- CTA: [View My Other Tickets]
- No navigation: State update on same page
-
Ticket Canceled (by user) β Show Canceled State
- Ticket marked as canceled
- QR code removed
- Message: βThis registration was canceled on {date}β
- CTA: [Register Again] [View Other Events]
- No navigation: State update on same page
-
Event Canceled (by organizer) β Show Event Canceled State
- Banner: ββ οΈ This event has been canceledβ
- Ticket status: CANCELED
- Message: βYouβll receive a full refund within 5-7 daysβ
- CTA: [View Other Events]
- No navigation: State update on same page
-
Event Date Changed β Show Update Notification
- Banner: βπ Event date has been updatedβ
- Shows old date β new date
- Message: βYour ticket is still valid. Re-download to update calendar.β
- CTA: [Download Updated Ticket] [Update Calendar]
- No navigation: State update with notification
Error States & Redirects
-
Invalid Ticket Access (401) β Redirect to Login
- Condition: Unauthenticated user tries to access ticket
- Target: Login Screen (story-1.2-login-screen.md)
- Context: Return URL to this ticket page
- Behavior: Redirect with βPlease sign in to view your ticketβ
-
Unauthorized Ticket Access (403) β Show Error Page
- Condition: User tries to access someone elseβs ticket
- Display: βYou donβt have permission to view this ticketβ
- CTA: [View My Tickets]
- Behavior: Error page, no access granted
-
Ticket Not Found (404) β Show Error Page
- Condition: Invalid registration ID or ticket deleted
- Display: βTicket not found or no longer validβ
- CTA: [View My Tickets] [Browse Events]
- Behavior: Error page
-
QR Code Generation Failed β Show Error State
- Display: βUnable to generate QR code. Please try again.β
- CTA: [Retry] [Download PDF Instead]
- Fallback: Show ticket ID as text barcode
- Behavior: Inline error with retry option
Responsive Design Considerations
Mobile Layout (<768px) - Primary Interface
- Full-Screen QR Code: Tap QR code to view full-screen for easier scanning
- Stacked Layout: All elements stack vertically with priority order:
- Event title & date
- QR code (large, center)
- Confirmation status
- Attendee info
- Quick actions (wallet, download, print)
- Check-in instructions
- Management options
- Sticky Header: Close button (β) and βMY TICKETβ title sticky at top
- Large Tap Targets: All buttons 44px minimum height
- Auto-Brightness: Screen brightness auto-increases when QR code visible
- Lock Screen: PWA shows QR code on lock screen 1 hour before event
Tablet Layout (768-1024px)
- 2-Column Layout: QR code on left, attendee info & actions on right
- Larger QR Code: 350x350px for easier scanning from distance
- Side-by-side Actions: Wallet buttons and download options in rows
Desktop Layout (>1024px)
- 3-Column Layout:
- Left: QR code and ticket ID
- Center: Attendee info and actions
- Right: Check-in instructions and quick links
- Maximum Width: 1200px container, centered
- Print Button Prominent: Desktop users more likely to print
Mobile-Specific Interactions
- Tap QR Code: Opens full-screen QR code view (landscape supported)
- Brightness Boost: Auto-increase screen brightness when QR displayed
- Wallet Integration: Native iOS/Android wallet integration
- Haptic Feedback: Vibration on successful download/save to wallet
- Lock Screen Widget: PWA shows QR code on lock screen 1 hour before event
- Offline Mode: Full ticket cached for offline access (service worker)
- Screenshot Detection: Warning if user takes screenshot (security reminder)
Accessibility Notes
ARIA Labels & Roles
- QR Code Image:
<img alt="QR code for event check-in" role="img"> - Ticket Status:
<div role="status" aria-live="polite">Registration Confirmed</div> - Action Buttons: Each button has descriptive aria-label
aria-label="Add ticket to Apple Wallet"aria-label="Download printable PDF ticket"
- Security Notice:
<aside role="note" aria-label="Security information">
Keyboard Navigation
- Tab Order: Header β QR code β Action buttons β Links β Management options
- Enter/Space: Activate all buttons
- Escape: Close modals (share, transfer, cancel)
- Focus Indicators: High-contrast 3px blue outline on all interactive elements
Screen Reader Support
- QR Code Alternative: Text-based ticket ID announced for screen reader users
- Status Announcements: Registration status, transfer status, cancellation status announced
- Button Context: βDownload PDF ticket for Spring Conference 2025β
- Warning Messages: Security warnings and transfer confirmations announced clearly
Visual Indicators
- High Contrast QR Code: Black on white with 21:1 contrast ratio
- Status Colors:
- Green checkmark for confirmed (with text βConfirmedβ)
- Red for canceled (with text βCanceledβ)
- Gray for transferred (with text βTransferredβ)
- Color + Icon: All status indicators use both color and icon
- Large Text: Event title 24px, ticket details 16px minimum
Reduced Motion
- Respect Preferences: No animations if user prefers reduced motion
- Static Display: QR code doesnβt animate or pulse
- Instant Transitions: Modals appear instantly without slide-in
State Management
Local Component State
qrCodeSize: number- Dynamically calculated QR code size based on viewportisFullScreenQr: boolean- Full-screen QR code modal statebrightnessBoostActive: boolean- Screen brightness boost stateshowShareModal: boolean- Share modal visibilityshowTransferModal: boolean- Transfer modal visibilityshowCancelModal: boolean- Cancellation modal visibilitytransferEmail: string- Transfer recipient email inputtransferMessage: string- Transfer message inputisDownloading: boolean- Download in progress stateofflineMode: boolean- Offline PWA state
Global State (Zustand Store)
auth.user- Current authenticated usertickets.current- Current ticket being displayedtickets.list- List of all userβs ticketsui.brightness- Screen brightness setting
Server State (React Query)
- Query Keys:
['ticket', registrationId]- Ticket data (5 min stale time)['event', eventId]- Event details (5 min stale time)
- Mutations:
transferTicket- Transfer ticket to another personcancelTicket- Cancel registrationrefreshQrCode- Refresh QR code with new timestamp
Real-Time Updates
- WebSocket Connection: Subscribe to ticket status changes
- Event:
TICKET_TRANSFERREDβ Update UI to show transferred state - Event:
EVENT_CANCELEDβ Update UI to show event canceled - Event:
EVENT_UPDATEDβ Show notification banner with changes
- Event:
- Background Sync: Refresh QR code every 5 minutes (security)
- Offline Sync: Queue transfer/cancel actions when offline, sync when online
PWA Caching
- Service Worker: Caches ticket page HTML, CSS, JS
- IndexedDB: Stores ticket data, QR code, event details
- Cache Strategy: Network-first with cache fallback
- Cache Expiry: Clear cache 24 hours after event
Form Validation Rules
Transfer Ticket Modal
Field-Level Validations
- Recipient Email:
- Required: Cannot be empty
- Format: Must be valid email address
- Not self: Cannot transfer to own email
- Pattern: RFC 5322 email validation
- Message (optional):
- Max Length: 500 characters
- Sanitization: Strip HTML tags
Form-Level Validations
- Transfer Deadline: Must be >24 hours before event
- Error: βTicket cannot be transferred within 24 hours of eventβ
- Already Transferred: Ticket can only be transferred once
- Error: βThis ticket has already been transferredβ
- Event Ended: Cannot transfer after event
- Error: βCannot transfer ticket for past eventβ
Share Ticket Modal
Field-Level Validations
- Recipient Email (for email share):
- Required if method is βemailβ
- Format: Valid email address
- Max Length: 254 characters
Form-Level Validations
- None - sharing is informational, not ownership transfer
Edge Cases & Error Handling
Empty States
-
No Ticket Found:
- Display: βTicket not found or you donβt have permission to view itβ
- CTA: [View My Tickets] [Browse Events]
-
Ticket List Empty (for user):
- Display: βYou donβt have any tickets yetβ
- CTA: [Browse Upcoming Events]
Loading States
- Initial Page Load: Skeleton screen with placeholder QR code
- QR Code Generating: Spinner overlay on QR code area
- PDF Downloading: Progress bar or spinner on download button
- Wallet Pass Generating: Loading spinner on wallet button
- Transfer Processing: Spinner on confirm button, disable form
Error States
-
QR Code Generation Failed:
- Display: ββ οΈ Unable to generate QR code. Show ticket ID at check-in.β
- Fallback: Display ticket ID as large text
- CTA: [Retry] [Contact Support]
-
PDF Download Failed:
- Toast: βUnable to download PDF. Please try again.β
- CTA: [Retry Download]
- Fallback: Screenshot ticket page
-
Wallet Integration Failed:
- Toast: βUnable to add to wallet. Try downloading PDF instead.β
- CTA: [Download PDF]
-
Transfer Failed (API Error):
- Display: βTransfer failed. Please try again or contact support.β
- Keep modal open with form data
- CTA: [Retry] [Cancel]
-
Network Error (Offline):
- Banner: βYouβre offline. Showing cached ticket.β
- QR code still visible (cached)
- Disable: Transfer, Cancel, Update buttons
- Enable: Download PDF (if cached), Print
Ticket Status Edge Cases
-
Ticket Already Used (Checked In):
- Status badge: ββ Checked Inβ
- Message: βYou checked in at {time}β
- QR code: Still visible (for exit/re-entry if allowed)
-
Duplicate Check-In Attempt:
- Handled by backend: Reject duplicate scan
- User sees: βAlready checked inβ message at venue
- No client-side change
-
Ticket Transferred by Someone Else:
- Status: βTRANSFERRED TO YOUβ
- Message: βThis ticket was transferred to you by {original owner}β
- QR code: New code for new owner
- Action: [Accept Transfer] (if requires confirmation)
-
Event Postponed:
- Banner: βπ Event postponed to {new date}β
- Message: βYour ticket is still validβ
- CTA: [Update Calendar] [Download Updated PDF]
-
Venue Changed:
- Banner: βπ Venue changed to {new venue}β
- Message: βYour ticket is still validβ
- CTA: [Get Directions] [Update Calendar]
Security Edge Cases
-
Screenshot Detected (Mobile):
- Toast: ββ οΈ Donβt share your QR code publicly. Keep it secure.β
- Analytics: Log screenshot event
-
QR Code Expired:
- Auto-refresh QR code every 5 minutes
- If refresh fails: Show expired warning
- CTA: [Refresh QR Code]
-
Suspicious Activity (multiple devices accessing same ticket):
- Email alert to owner: βYour ticket was accessed from {location}β
- Banner on page: βYour ticket was recently viewed on another deviceβ
- CTA: [Secure My Account]
Event Capacity Edge Cases
- Event Oversold (unlikely but possible):
- All tickets remain valid
- Organizers handle at venue
- No client-side impact
Time-Based Edge Cases
-
Viewing Ticket After Event:
- Status: βEVENT ENDEDβ
- Message: βThank you for attending!β
- QR code: Still visible (for records)
- CTA: [View Event Photos] [View Recordings] [View Other Events]
-
Viewing Ticket 1 Hour Before Event:
- Reminder banner: βπ Event starts in 1 hour!β
- CTA: [Get Directions] [Check-in Now]
- Lock screen notification (PWA)
Change Log
| Date | Version | Description | Author |
|---|---|---|---|
| 2025-10-04 | 1.0 | Initial wireframe creation for Ticket/QR page | Sally (UX) |
Review Notes
Stakeholder Feedback
Awaiting stakeholder review
Design Iterations
Initial design based on event registration flow and mobile-first ticket access requirements
Open Questions
-
QR Code Refresh Frequency: How often should QR code refresh for security?
- Current: Every 5 minutes in background
- Alternative: Only on page load, or on manual refresh
- Recommendation: Every 5 minutes to prevent screenshot reuse, with 24-hour validity
-
Ticket Transfer Restrictions: Should ticket transfer be allowed at all?
- Current: Allowed up to 24 hours before event
- Concerns: Abuse, scalping (though free event), name mismatch at check-in
- Recommendation: Allow transfer with email verification, log all transfers
-
Screenshot Security: Should we prevent screenshots or just warn?
- Current: Warn with toast notification
- Alternative: Technical prevention (DRM, screenshot blocking)
- Recommendation: Warning only - UX friction vs. security trade-off
-
Offline Access Duration: How long should ticket stay cached offline?
- Current: Until 24 hours after event
- Alternative: 7 days after event, or until manually cleared
- Recommendation: 24 hours after event, then prompt to clear cache
-
Multiple Device Access: Should users be warned if ticket accessed from multiple devices?
- Current: Yes - email alert sent
- Concerns: False positives (user switches devices)
- Recommendation: Alert only if >3 devices within 1 hour (suspicious pattern)
-
Check-In History: Should ticket show check-in timestamp after user checks in?
- Current: Yes - ββ Checked in at {time}β
- Use case: Re-entry, exit tracking, user confirmation
- Recommendation: Yes - helpful for attendee and organizer
Implementation Priority: π΄ HIGH - Critical for event access and attendee check-in. Required for MVP.
Dependencies:
- Event Registration Flow (Story 2.4) β
- Registration Confirmation Page (Story 2.4) β
- QR Code generation service (backend)
- Apple Wallet / Google Wallet integration APIs
- PDF generation service
- PWA service worker for offline caching
Related Screens:
- Registration Confirmation Page (story-2.4-registration-confirmation.md) β
- Event Details - Attendee View (story-5.2-event-details-attendee-view.md)
- Event Registration Flow (story-2.4-event-registration.md)
- User Dashboard with ticket list (future)