Physical Card Payment Integration for Check-in App - Planning Document¶
Document Information: - Created: 2025-11-03 - Last Updated: 2025-11-03 - Version: 1.0 - Author(s): Claude Code - Status: Draft - Awaiting Review
1. Executive Summary & Feature Overview¶
1.1 Feature Description¶
- Feature Name: Physical Card Payment at Door (Check-in App Integration)
- Feature Type: New Feature / Major Enhancement
- Priority Level: High
1.2 Problem Statement¶
- Current State: The check-in app currently only validates pre-purchased tickets via QR code scanning. Door staff cannot accept payments from walk-up customers who want to purchase tickets at the venue.
- Pain Points:
- Lost revenue from walk-up customers who don't have tickets
- Manual cash handling complexity and security concerns
- No unified system for tracking door sales vs. online sales
- Inability to accept credit/debit card payments at the door
- User Impact: Event producers, door staff, and walk-up customers
- Business Value:
- Increased revenue from walk-up sales
- Better tracking of total ticket sales
- Professional payment processing at the door
- Reduced cash handling risks
1.3 Expected Outcomes¶
- Success Metrics:
- Ability to process card payments at the door within 10 seconds
- 99.9% payment success rate for valid cards
- Zero manual reconciliation errors between door sales and online sales
- User Experience Goals:
- Simple, fast payment flow for walk-up customers
- Minimal training required for door staff
- Seamless integration with existing check-in workflow
- Technical Goals:
- PCI compliance maintained
- Integration with existing Stripe infrastructure
- Reliable offline mode for venues with poor connectivity
2. Stakeholder Analysis & Requirements¶
2.1 Affected Users & Systems¶
- Primary Users:
- Door staff operating the check-in app
- Walk-up customers purchasing tickets at the venue
- Secondary Users:
- Event producers monitoring sales
- Finance/accounting teams reconciling payments
- System Components:
- Check-in app (apps/checkin)
- Django backend API (apps/api)
- Stripe payment infrastructure
- Order management system
- Integration Points:
- Stripe Terminal SDK
- Stripe Terminal card readers (hardware)
- Django Order model
- Show and Ticket models
2.2 Functional Requirements¶
Must-Have Features: - Accept chip, swipe, and contactless card payments at the door - Create orders in the system for door sales - Generate tickets/QR codes for door purchases - Track door sales separately from online sales in reports - Support multiple ticket types and quantities - Apply promo codes to door purchases - Print or email receipts to customers - Handle payment failures gracefully
Should-Have Features: - Offline mode with sync when connection restored - Support for refunds at the door - Real-time sales dashboard updates - Integration with existing show reports
Could-Have Features: - Support for split payments - Tip/donation collection - Customer lookup by email/phone for faster checkout - Saved payment methods for repeat customers
Won't-Have Features (Initially): - Cash payment tracking (manual process) - Check/money order acceptance - Cryptocurrency payments - Installment/payment plan options
2.3 Non-Functional Requirements¶
- Performance:
- Payment authorization within 5 seconds
- Receipt generation within 2 seconds
- Support 100+ simultaneous door transactions per show
- Security:
- PCI DSS compliance via Stripe Terminal
- EMV chip card support
- End-to-end encryption of card data
- No storage of card details on device
- Accessibility:
- Large touch targets for mobile devices
- Clear error messages
- Support for screen readers on receipt emails
- Browser/Platform Support:
- Modern browsers (Chrome, Safari, Firefox, Edge)
- iOS Safari and Android Chrome (mobile)
- Tablet optimization (iPad, Android tablets)
- Reliability:
- 99.9% uptime during event hours
- Graceful degradation in offline mode
- Automatic retry for failed syncs
3. Current State Analysis¶
3.1 Codebase Research Methodology¶
Primary Tools:
- Serena MCP - Code exploration and pattern matching
- mcp__serena__find_file - Located check-in app structure at apps/checkin/
- mcp__serena__search_for_pattern - Found payment processing patterns in frontend and producer apps
- mcp__serena__list_dir - Explored apps directory structure
- mcp__serena__get_symbols_overview - Analyzed check-in App.tsx component structure
- mcp__serena__read_memory - Retrieved project architecture overview
- Context7 MCP - Semantic understanding and relationships
- Identified Stripe Terminal React Native SDK capabilities
- Mapped Stripe.js payment integration patterns
- Understood terminal card reader integration requirements
- Analyzed browser compatibility constraints for terminal implementations
Secondary Tools: - File reading for package.json analysis and dependency review - Web search for Stripe Terminal SDK compatibility and hardware requirements - Pattern search for existing Stripe integration patterns
Key Files Analyzed:
- apps/checkin/src/App.tsx - Main check-in application entry point
- apps/checkin/src/pages/CheckIn.tsx - Check-in page with QR scanning (lines 66-84: handleScan flow)
- apps/checkin/src/services/api.ts - API service layer (lines 15-19: validateTicket endpoint)
- apps/checkin/package.json - Current dependencies (React 18.2, Vite, no Stripe dependencies)
- apps/frontend/src/app/api/checkout/route.ts - Existing checkout flow reference
- apps/api/tickets/utils/reports.py - Report generation with financial tracking
3.2 Existing Architecture & Patterns¶
Tech Stack: - Check-in App: React 18.2 + TypeScript + Vite (web-based SPA) - Frontend App: Next.js 15.3.1 + React 19 (web-based) - Backend: Django REST API + PostgreSQL - Payments: Stripe (via Stripe.js in frontend, no terminal integration) - Deployment: Docker Compose
Architecture Pattern: - Multi-app monorepo structure - React SPA (checkin) + Next.js SSR (frontend) + Django REST API (backend) - Direct API calls from frontend to Django backend - QR code scanning via @zxing/browser library
Design Patterns: - Token-based session authentication for check-in - RESTful API design - Component-based UI architecture - Service layer abstraction (api.ts)
Code Organization:
apps/checkin/
├── src/
│ ├── components/ # UI components (Scanner, SearchByName, etc.)
│ ├── pages/ # Page components (CheckIn.tsx)
│ ├── services/ # API service layer
│ ├── types/ # TypeScript type definitions
│ └── App.tsx # Main app entry
Data Flow:
1. Check-in app authenticates with session token (from URL query param)
2. QR code scanned → handleScan() called (CheckIn.tsx:66)
3. API call to validateTicket() (api.ts:15)
4. Django backend validates and marks ticket as checked in
5. Success modal shown to user
3.3 Relevant Existing Code¶
Discovery Method: Used Serena MCP find_file and search_for_pattern to locate similar implementations.
Similar Features:
- Frontend Checkout Flow (apps/frontend/src/app/api/checkout/route.ts)
- Shows existing Stripe integration pattern
- Demonstrates CSRF token handling
- Uses Stripe PaymentIntent flow
- Reference for error handling and validation
- Order Creation (Django backend - inferred from reports.py)
- Order model with fields: first_name, last_name, email, total, platform_fees, payment_processing_fees
- TicketOrder junction table for many-to-many relationship
- Promo code support via promo_code foreign key
- Success flag to distinguish completed orders
Reusable Components:
- Scanner Component (apps/checkin/src/components/Scanner.tsx)
- QR code scanning with camera access
- Error handling and user feedback
- Can be reused for scanning pre-purchased tickets alongside door sales
- ShowInfo Component (
apps/checkin/src/components/ShowInfo.tsx) - Display stats (attendees checked in, pending, percentage)
-
Can be extended to show door sales stats
-
SearchByName Component (
apps/checkin/src/components/SearchByName.tsx:14-79) - Attendee search and check-in functionality
- Pattern for handling check-in state updates
- Reference for customer lookup feature
Shared Utilities:
- API service pattern (apps/checkin/src/services/api.ts)
- Type definitions for tickets and orders
- Report generation utilities (apps/api/tickets/utils/reports.py)
Integration Points:
- Django /validate-ticket/ endpoint (api.ts:16) - Reference for creating door sales endpoint
- Django /get-all-attendees/ endpoint (api.ts:26) - Reference for attendee management
- Stripe payment processing (via frontend checkout) - Pattern for Stripe integration
3.4 Current Dependencies¶
Check-in App Core Dependencies:
- react: ^18.2.0 - UI framework
- react-dom: ^18.2.0 - React DOM rendering
- react-router-dom: ^6.22.1 - Client-side routing
- @zxing/browser: ^0.1.1 - QR code scanning
- @zxing/library: ^0.21.0 - QR code library
- qrcode.react: ^4.2.0 - QR code generation
- axios: ^1.12.0 - HTTP client
- react-icons: ^5.5.0 - Icon library
Development Dependencies:
- typescript: ^5.2.2
- vite: ^6.4.1 - Build tool
- @vitejs/plugin-react: ^4.2.1
Frontend App Stripe Dependencies (Reference): - No Stripe.js dependency explicitly listed - Stripe integration via CDN/script tag (inferred from checkout flow)
Missing Dependencies Needed:
- @stripe/stripe-js - Stripe.js library for browser payments
- @stripe/terminal-js - Stripe Terminal JavaScript SDK for card readers
- Physical card reader device (hardware procurement)
Infrastructure Dependencies: - PostgreSQL database - Django REST API - Stripe account with Terminal enabled - Redis for caching (optional for offline queue)
3.5 Potential Conflicts & Constraints¶
Technical Debt: - Check-in app uses older React 18.2 (frontend uses React 19) - No existing Stripe dependency in check-in app - No payment processing infrastructure in check-in app - Session-based auth may need extension for payment operations
Legacy Code: - Check-in app is web-based (React/Vite), not a native mobile app - Limits terminal integration options (see section 5.1)
Resource Constraints: - Hardware Limitation: Requires physical card reader purchase ($299-$699 per reader) - Network Dependency: Stripe Terminal JavaScript SDK requires internet connection for most readers - Browser Constraints: Limited to browsers, cannot use Tap to Pay (iOS/Android only) - PCI Compliance: Must ensure web app meets security requirements for handling payments
Compliance Requirements: - PCI DSS compliance (handled by Stripe Terminal, but integration must be correct) - Payment data security (no storage of card details) - EMV chip card support (required in US) - Accessibility standards (WCAG 2.1 AA for receipt/confirmation screens)
4. Research & Best Practices¶
4.1 Industry Standards Research¶
Research Sources: Stripe Documentation, Web Search, Context7 MCP Documentation Analysis
Context7 MCP Analysis: - Analyzed Stripe Terminal React Native SDK patterns to understand terminal integration architecture - Identified browser compatibility constraints for terminal implementations - Discovered Tap to Pay limitations (native apps only, not web) - Reviewed Stripe.js integration patterns for web-based payments
Stripe Terminal Key Findings:
- SDK Platform Limitations:
- Stripe Terminal React Native SDK: Only works with native iOS/Android apps, NOT compatible with web browsers, PWAs, or React web apps
- Stripe Terminal JavaScript SDK: Designed for web browsers, compatible with Chrome, Safari, Firefox, Edge
-
Tap to Pay: Only available via iOS SDK and Android SDK, NOT available for browser-based applications
-
Card Reader Requirements:
- Internet-Connected Readers: Verifone P400 (legacy), Stripe Reader S700, BBPOS WisePOS E
- Connect over internet/LAN to Stripe's servers
- Work with JavaScript SDK for web apps
- Currently supported in US: Stripe M2, Stripe S700, WisePad 3, WisePOS E
- Bluetooth Readers: BBPOS WisePad 3, Chipper 2X BT
- Require native SDK (iOS/Android) for Bluetooth pairing
- NOT compatible with browser-based JavaScript SDK
-
Verifone P400: Legacy device, no longer recommended by Stripe
-
Browser Compatibility:
- JavaScript SDK works in: Chrome, Safari, Firefox, Edge (desktop and mobile browsers)
- Requires HTTPS for security
- No offline mode for payment processing (requires internet)
Industry Best Practices: - Use Stripe Terminal JavaScript SDK for web-based point-of-sale - Implement connection token endpoint on backend for security - Use reader-initiated payment flow for best UX - Implement retry logic for network failures - Store transactions locally and sync when connection restored - Provide clear error messages for card declines
Codebase Pattern Validation: - Existing checkout flow in frontend app uses Stripe.js correctly (apps/frontend/src/app/api/checkout/route.ts) - Pattern found: reCAPTCHA verification before payment processing (checkout/route.ts:26-58) - Pattern found: CSRF token handling for Django backend (checkout/route.ts:61-68) - No existing patterns for terminal integration in codebase
4.2 Framework/Library Research¶
Official Documentation: - Stripe Terminal Documentation - Stripe Terminal JavaScript SDK - Stripe.js Documentation
Community Resources: - Stack Overflow: Discussions on browser-based terminal implementations - GitHub Issues: stripe/stripe-terminal-react-native (issues related to web compatibility confirm React Native SDK doesn't support web)
Migration Guides: - No migration needed (greenfield implementation) - Must add Stripe Terminal SDK alongside existing Stripe.js
Known Issues: - Stripe Terminal React Native SDK doesn't support web (confirmed via search) - Bluetooth readers require native app (cannot use with web browser) - Tap to Pay requires native iOS/Android SDK (not available for web) - Offline mode limited to certain reader types and workflows
4.3 Case Studies & Examples¶
Similar Implementations: - Stripe Terminal JavaScript SDK demo applications (available in Stripe docs) - Point-of-sale systems using web-based terminals (Square, Toast) - Event management platforms with door sales (Eventbrite, Universe)
Lessons Learned: - Web-based terminal requires internet-connected readers (Bluetooth not supported) - Connection token endpoint must be implemented securely on backend - Reader discovery and pairing should happen before event starts - Offline mode requires pre-authorization or stored payment method patterns - Error handling crucial for card declines and network issues
Performance Studies: - Typical payment authorization time: 2-5 seconds - Reader connection time: 5-10 seconds (initial pairing) - Receipt generation time: < 1 second
5. Solution Design¶
5.1 Proposed Architecture¶
Design Validation: Used Serena MCP to verify file locations and Context7 to understand integration points.
Critical Architectural Decision: Standalone vs. Integrated App
After thorough research, here are the two viable approaches:
Option A: Integrated Web App with Internet-Connected Card Reader (RECOMMENDED)¶
Architecture:
Check-in App (Web Browser)
├── Stripe Terminal JavaScript SDK
├── Internet-Connected Card Reader (Stripe S700 or WisePOS E)
└── Django Backend
├── Connection Token Endpoint
├── Payment Intent Creation
└── Order Management
Pros: - ✅ Single unified app for check-in and door sales - ✅ Leverages existing check-in app infrastructure - ✅ Door staff use one device/app - ✅ Easier to maintain and deploy - ✅ Real-time integration with show stats
Cons: - ❌ Requires internet connection for payments - ❌ Requires purchase of internet-connected card reader ($299-$699) - ❌ Cannot use Tap to Pay (browser limitation) - ❌ Cannot use Bluetooth readers (browser limitation)
Required Hardware: - Stripe Reader S700 ($299) - Recommended - Internet-connected via WiFi or Ethernet - Supports chip, swipe, contactless - Built-in receipt printer - Color touchscreen display - OR BBPOS WisePOS E ($549) - Android-based smart terminal - WiFi/4G connectivity - Larger screen for customer interaction
Implementation Approach: 1. Add Stripe Terminal JavaScript SDK to check-in app 2. Create backend endpoint for connection tokens 3. Implement reader discovery and connection flow 4. Add "Door Sales" tab to existing check-in app UI 5. Create payment flow using PaymentIntent API 6. Generate tickets/QR codes for successful payments 7. Update reports to include door sales
Option B: Standalone Native Mobile App with Tap to Pay¶
Architecture:
New Native iOS/Android App
├── Stripe Terminal React Native SDK
├── Tap to Pay (iPhone/Android)
└── Django Backend (same as Option A)
Pros: - ✅ No card reader hardware purchase needed - ✅ Use iPhone/Android device NFC for payments - ✅ Faster deployment (no hardware shipping) - ✅ Can work offline with stored payment methods
Cons: - ❌ Requires building entirely new native app - ❌ Significant development effort (iOS + Android) - ❌ Door staff need separate devices for check-in vs. door sales - ❌ More complex deployment (App Store, Play Store) - ❌ Tap to Pay requires merchant to be in supported country (US, Canada, etc.) - ❌ Tap to Pay has transaction limits and restrictions
Recommendation: Option A - Integrated Web App¶
Rationale: 1. Lower Total Development Effort: Extending existing check-in app is faster than building new native apps 2. Unified Workflow: Door staff use one app for both check-in and door sales 3. Existing Infrastructure: Leverages current React/Django architecture 4. Proven Technology: Stripe Terminal JavaScript SDK is mature and well-documented 5. Hardware Investment: One-time reader purchase ($299-$699) vs. ongoing app maintenance for Option B
Verification Steps:
- ✅ Used Serena find_file to locate check-in app structure
- ✅ Used Context7 to understand Stripe Terminal SDK options
- ✅ Confirmed browser compatibility via web search
- ✅ Verified no Tap to Pay support for web browsers
5.2 High-Level Design¶
Component Architecture:
// New Components in apps/checkin/src/components/
DoorSales/
├── DoorSalesTab.tsx // Main door sales interface
├── TicketSelection.tsx // Select tickets and quantities
├── CustomerInfoForm.tsx // Collect customer details
├── PaymentReader.tsx // Terminal reader integration
├── PaymentStatus.tsx // Payment progress indicator
└── ReceiptDisplay.tsx // Show receipt after payment
// Shared Services
services/
├── api.ts // Extended with door sales endpoints
└── terminal.ts // NEW: Stripe Terminal service
User Flow:
-
Reader Setup (One-time per event):
-
Door Sale Flow:
-
Error Handling:
Data Model Changes:
# apps/api/tickets/models.py
class Order:
# Existing fields...
purchase_location = models.CharField(
max_length=20,
choices=[('online', 'Online'), ('door', 'Door')],
default='online'
)
terminal_reader_id = models.CharField(
max_length=255,
blank=True,
null=True,
help_text="Stripe Terminal reader ID for door sales"
)
door_staff_user = models.ForeignKey(
'auth.User',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='door_sales',
help_text="User who processed door sale"
)
# ... rest of existing fields
API Design:
# New Django API Endpoints
POST /api/v1/checkin/connection-token/
→ Returns: { "secret": "pst_..." }
→ Used by Terminal SDK to connect to reader
POST /api/v1/checkin/create-door-sale-intent/
Request: {
"show_id": 123,
"ticket_selections": [
{"ticket_id": 456, "quantity": 2}
],
"customer": {
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1234567890"
},
"promo_code": "DISCOUNT10" (optional)
}
→ Returns: { "client_secret": "pi_...", "amount": 5000 }
POST /api/v1/checkin/confirm-door-sale/
Request: {
"payment_intent_id": "pi_...",
"show_id": 123,
"terminal_reader_id": "tmr_..."
}
→ Returns: { "order_id": 789, "tickets": [...], "qr_code": "..." }
GET /api/v1/checkin/door-sales-summary/
Query: ?token={session_token}
→ Returns: {
"total_door_sales": 15,
"door_revenue": 750.00,
"recent_sales": [...]
}
UI/UX Design:
New tab in floating navigation (CheckIn.tsx:158-187):
┌─────────────────────────────────┐
│ [Scan] [Search] [Info] [Door] │ ← Add Door Sales tab
└─────────────────────────────────┘
Door Sales Tab UI:
┌─────────────────────────────────┐
│ Door Sales - Show Name │
│ │
│ Select Tickets: │
│ ┌─────────────────────────┐ │
│ │ GA Ticket - $25 [+][-]│ │
│ │ VIP Ticket - $50 [+][-]│ │
│ └─────────────────────────┘ │
│ │
│ Customer Info: │
│ Name: [___________] │
│ Email: [___________] │
│ Phone: [___________] (opt) │
│ │
│ Promo Code: [___] [Apply] │
│ │
│ Total: $75.00 │
│ ┌─────────────────────────┐ │
│ │ Process Payment ($75) │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
Integration Strategy:
- Phase 1: Add Stripe Terminal SDK and connection flow
- Install dependencies
- Create terminal service wrapper
- Build reader connection UI
-
Test reader discovery
-
Phase 2: Build door sales UI
- Create door sales tab
- Implement ticket selection
- Add customer info form
-
Build payment flow UI
-
Phase 3: Backend integration
- Create connection token endpoint
- Build payment intent creation endpoint
- Implement order creation for door sales
-
Add ticket generation
-
Phase 4: Testing and polish
- Test payment flows
- Error handling
- Receipt generation
- Report integration
5.3 Technology Decisions¶
New Dependencies:
// apps/checkin/package.json additions
{
"dependencies": {
"@stripe/stripe-js": "^4.0.0",
"@stripe/terminal-js": "^1.0.0" // If separate package
}
}
Alternative Solutions Considered:
| Solution | Pros | Cons | Decision |
|---|---|---|---|
| Stripe Terminal JavaScript SDK | Browser compatible, proven | Requires hardware purchase | ✅ SELECTED |
| Stripe Terminal React Native | Tap to Pay, no hardware | Requires native app rebuild | ❌ Rejected (too much effort) |
| Third-party terminal (Square) | Cheaper hardware | Separate payment processor | ❌ Rejected (vendor lock-in) |
| Manual card entry | No hardware needed | Not PCI compliant, poor UX | ❌ Rejected (security risk) |
Proof of Concepts Needed:
- Terminal SDK Connection Test:
- Build minimal HTML page with Terminal SDK
- Test reader discovery and connection
- Verify payment flow works
-
Estimate: 4 hours
-
Offline Queue Test:
- Test payment queuing when offline
- Verify sync when connection restored
- Estimate: 8 hours
5.4 Security Considerations¶
Threat Model: - Payment Data Interception: Card data could be intercepted over network - Mitigation: Stripe Terminal uses end-to-end encryption, data never touches our servers - Unauthorized Door Sales: Rogue door staff could process fake sales - Mitigation: Log all door sales with staff user ID, require session token, audit trail - Refund Fraud: Staff could process refunds and pocket cash - Mitigation: Refund approval workflow, manager authorization required - Device Theft: Card reader could be stolen - Mitigation: Device registration, remote disable capability via Stripe dashboard
Authentication/Authorization: - Connection token endpoint must verify session token (existing pattern) - Door staff user must be associated with check-in session - Rate limiting on payment endpoints (max 10 transactions per minute)
Data Protection: - No storage of card numbers or CVV - PII (email, phone) encrypted at rest in database - Payment intents logged with minimal PII - Stripe handles all PCI compliance for card data
Security Testing: - Penetration testing of connection token endpoint - CSRF protection verification (Django handles this) - SQL injection testing on new endpoints - XSS testing on receipt display
6. Implementation Plan¶
6.1 Development Phases¶
Phase 1: Foundation & Backend Setup
- [ ] Create Django connection token endpoint (apps/api/checkin/views.py)
- [ ] Implement token generation logic
- [ ] Add session validation
- [ ] Add rate limiting
- [ ] Create door sale payment intent endpoint
- [ ] Calculate totals with fees
- [ ] Apply promo codes
- [ ] Generate Stripe PaymentIntent
- [ ] Extend Order model with door sale fields
- [ ] Add migration for new fields
- [ ] Update admin interface
- [ ] Create door sale confirmation endpoint
- [ ] Verify payment status
- [ ] Create Order record
- [ ] Generate tickets and QR codes
- [ ] Deliverable: Backend API ready for terminal integration
Phase 2: Terminal SDK Integration
- [ ] Install Stripe Terminal JavaScript SDK in check-in app
- [ ] Update package.json
- [ ] Run npm install
- [ ] Create terminal service wrapper (apps/checkin/src/services/terminal.ts)
- [ ] Initialize Terminal SDK
- [ ] Implement reader discovery
- [ ] Handle reader connection
- [ ] Process payments
- [ ] Build reader connection UI component
- [ ] Reader selection screen
- [ ] Connection status indicator
- [ ] Error handling UI
- [ ] Test reader discovery and connection
- [ ] Manual testing with Stripe test reader
- [ ] Verify connection token flow
- [ ] Deliverable: Terminal SDK integrated and reader connectable
Phase 3: Door Sales UI Implementation - [ ] Create DoorSales components - [ ] DoorSalesTab.tsx - Main container - [ ] TicketSelection.tsx - Ticket picker with quantities - [ ] CustomerInfoForm.tsx - Name, email, phone fields - [ ] PaymentReader.tsx - Payment processing UI - [ ] ReceiptDisplay.tsx - Success screen with QR code - [ ] Add "Door" tab to CheckIn.tsx navigation - [ ] Update tab state management - [ ] Add routing for door sales view - [ ] Implement ticket selection logic - [ ] Fetch available tickets from show - [ ] Calculate totals with fees - [ ] Handle promo code application - [ ] Build customer info form - [ ] Form validation - [ ] Email format validation - [ ] Phone number formatting - [ ] Deliverable: Complete door sales UI flow
Phase 4: Payment Flow & Integration - [ ] Connect UI to terminal service - [ ] Trigger payment on form submit - [ ] Show payment status - [ ] Handle card insertion prompts - [ ] Implement payment success flow - [ ] Call confirm-door-sale endpoint - [ ] Display generated tickets - [ ] Show/email receipt - [ ] Auto-check-in customer - [ ] Implement payment error handling - [ ] Card declined errors - [ ] Network errors - [ ] Timeout errors - [ ] Retry logic - [ ] Add offline queue (if needed) - [ ] Queue failed payments locally - [ ] Retry when connection restored - [ ] Notify staff of queued items - [ ] Deliverable: End-to-end payment flow working
Phase 5: Testing & Polish - [ ] Unit tests for terminal service - [ ] Integration tests for door sale API endpoints - [ ] E2E tests for complete door sale flow - [ ] Test error scenarios - [ ] Card declines - [ ] Network failures - [ ] Invalid input - [ ] Performance testing - [ ] Payment speed benchmarks - [ ] Concurrent transaction testing - [ ] Update show reports to include door sales - [ ] Add door_sales section to report template - [ ] Separate online vs door metrics - [ ] Create user documentation - [ ] Reader setup guide - [ ] Door sales operation guide - [ ] Troubleshooting guide - [ ] Deliverable: Production-ready feature
6.2 Detailed Task Breakdown¶
| Task | Files Affected | Dependencies | Assignee | Estimate |
|---|---|---|---|---|
| Create connection token endpoint | apps/api/checkin/views.py, apps/api/checkin/urls.py |
Stripe API key configured | TBD | 4h |
| Create payment intent endpoint | apps/api/checkin/views.py |
Order model, Ticket model | TBD | 6h |
| Extend Order model | apps/api/tickets/models.py, migration file |
Database access | TBD | 3h |
| Create confirmation endpoint | apps/api/checkin/views.py |
Payment intent endpoint, Order model | TBD | 8h |
| Install Stripe Terminal SDK | apps/checkin/package.json |
None | TBD | 1h |
| Create terminal service | apps/checkin/src/services/terminal.ts |
Stripe SDK installed | TBD | 12h |
| Build reader connection UI | apps/checkin/src/components/ReaderSetup.tsx |
Terminal service | TBD | 8h |
| Create DoorSalesTab component | apps/checkin/src/components/DoorSales/DoorSalesTab.tsx |
None | TBD | 6h |
| Build ticket selection | apps/checkin/src/components/DoorSales/TicketSelection.tsx |
Show API | TBD | 8h |
| Build customer form | apps/checkin/src/components/DoorSales/CustomerInfoForm.tsx |
Form validation library | TBD | 6h |
| Build payment UI | apps/checkin/src/components/DoorSales/PaymentReader.tsx |
Terminal service | TBD | 10h |
| Build receipt display | apps/checkin/src/components/DoorSales/ReceiptDisplay.tsx |
QR code generation | TBD | 6h |
| Connect payment flow | apps/checkin/src/components/DoorSales/DoorSalesTab.tsx |
All DoorSales components, API endpoints | TBD | 8h |
| Error handling | Multiple files | Payment flow complete | TBD | 8h |
| Update reports | apps/api/tickets/utils/reports.py, template files |
Order model changes | TBD | 6h |
| Testing | Test files across codebase | All features complete | TBD | 16h |
| Documentation | docs/ directory |
All features complete | TBD | 8h |
Total Estimated Effort: ~120 hours (~3 weeks for 1 developer)
6.3 File Change Summary¶
Discovery Method: Used Serena MCP find_file to verify file paths and get_symbols_overview to understand existing file structure before planning changes.
New Files:
apps/checkin/src/services/terminal.ts- Stripe Terminal SDK wrapper service-
Pre-creation Check: No similar service exists in checkin app
-
apps/checkin/src/components/DoorSales/DoorSalesTab.tsx- Main door sales interface -
Pattern Reference: Follow structure of
apps/checkin/src/pages/CheckIn.tsx -
apps/checkin/src/components/DoorSales/TicketSelection.tsx- Ticket picker component -
Pattern Reference: Similar to ticket selection in frontend checkout
-
apps/checkin/src/components/DoorSales/CustomerInfoForm.tsx- Customer details form -
Pattern Reference: Similar form patterns in SearchByName.tsx
-
apps/checkin/src/components/DoorSales/PaymentReader.tsx- Payment processing UI -
New Pattern: Unique to terminal integration
-
apps/checkin/src/components/DoorSales/ReceiptDisplay.tsx- Receipt/QR display -
Pattern Reference: Reuse QR code patterns from existing components
-
apps/checkin/src/components/ReaderSetup.tsx- Reader connection setup UI -
New Pattern: Terminal reader management
-
apps/checkin/src/types/terminal.ts- TypeScript types for terminal operations -
Pattern Reference: Follow structure of
apps/checkin/src/types/api.ts -
apps/api/checkin/views.py- New Django views for door sales - Impact Analysis: New file, no dependencies on existing code
-
Pattern Reference: Follow Django REST patterns from tickets app
-
apps/api/checkin/urls.py- URL routing for checkin API endpoints -
Usage Search: New file for checkin-specific routes
-
apps/api/tickets/migrations/XXXX_add_door_sale_fields.py- Database migration - Safety Check: Auto-generated migration file
Modified Files:
apps/checkin/package.json- Add Stripe dependencies-
Impact Analysis: No breaking changes, only additions
-
apps/checkin/src/pages/CheckIn.tsx- Add Door Sales tab to navigation - Symbol Review: Modify
activeTabtype and tab buttons (lines 15, 158-187) -
Impact: Low risk, additive change only
-
apps/checkin/src/services/api.ts- Add door sales API functions - Usage Search: Verify all imports remain compatible
-
Symbol Review: Add new exported functions
-
apps/checkin/src/types/api.ts- Add door sales type definitions -
Impact Analysis: Additive changes, no breaking modifications
-
apps/api/tickets/models.py- Extend Order model - Impact Analysis: Add new optional fields (purchase_location, terminal_reader_id, door_staff_user)
-
Safety Check: All new fields nullable/optional to maintain backward compatibility
-
apps/api/tickets/utils/reports.py- Add door sales section to reports - Symbol Review: Modify
generate_show_report_data()function (line 19) -
Impact: Extend function to include door sales breakdown
-
apps/api/tickets/templates/admin/tickets/show/show_report.html- Update report template - Usage Search: Template used by reports.py
- Impact: Add new section for door sales
Deleted Files: - None (no files will be deleted)
7. Testing Strategy¶
7.1 Test Coverage Plan¶
Test Discovery: Used Serena MCP find_file to locate existing test files and search_for_pattern to find similar test patterns to follow.
Unit Tests:
- Backend Tests (Django)
- apps/api/checkin/tests/test_connection_token.py - Connection token generation
- apps/api/checkin/tests/test_door_sales.py - Payment intent creation, order confirmation
- apps/api/tickets/tests/test_reports.py - Report generation with door sales (existing file, extend)
- Pattern Reference: Follow structure in apps/api/tickets/tests/test_admin_checkin.py
- Frontend Tests (React)
apps/checkin/src/services/terminal.test.ts- Terminal service methodsapps/checkin/src/components/DoorSales/TicketSelection.test.tsx- Ticket selection logicapps/checkin/src/components/DoorSales/CustomerInfoForm.test.tsx- Form validation- Pattern Reference: Create new test files following Jest/React Testing Library patterns
Integration Tests:
- API endpoint integration tests
- Test full door sale flow: create intent → process payment → confirm order
- Test promo code application
- Test error scenarios (invalid show, sold out tickets)
- Examples: Create integration tests in apps/api/checkin/tests/test_integration.py
End-to-End Tests: - Complete door sale user journey - Select tickets → Enter customer info → Process payment → Receive receipt - Test with Stripe test card numbers - Verify order created and tickets generated - Structure: Consider Playwright or Cypress for E2E tests
Performance Tests: - Payment processing speed (target: < 5 seconds) - Concurrent transaction handling (target: 10+ simultaneous) - Reader connection time (target: < 10 seconds)
Security Tests: - Connection token endpoint security - Test without session token (should fail) - Test with invalid session token (should fail) - Test rate limiting (should throttle after threshold) - Payment intent tampering prevention - Test modifying payment amount (should be validated server-side) - XSS testing on customer input fields - Existing Patterns: Reference security test patterns if available
Coverage Targets: - Backend code: 90% line coverage - Frontend components: 80% line coverage - Critical payment flow: 100% coverage
7.2 Test Environment Requirements¶
Development:
- Local Docker environment with Django + PostgreSQL + Redis
- Stripe test mode API keys
- Stripe Terminal simulator (web-based)
- Test card numbers for various scenarios:
- 4242424242424242 - Successful payment
- 4000000000000002 - Card declined
- 4000000000009995 - Insufficient funds
Staging: - Staging environment matching production architecture - Stripe test mode with real card reader hardware - Test data: Shows, tickets, promo codes - Test user accounts for door staff
Production: - Stripe live mode API keys - Physical card reader (Stripe S700 or WisePOS E) - Feature flag for gradual rollout - Monitoring and alerting configured
7.3 Acceptance Criteria¶
Definition of Done: - [ ] All functional requirements implemented - [ ] Can process chip, swipe, contactless payments - [ ] Orders created successfully for door sales - [ ] Tickets/QR codes generated - [ ] Receipts displayed/emailed - [ ] Promo codes work for door sales - [ ] Door sales tracked separately in reports
- All tests pass (unit, integration, e2e)
- Backend unit tests: 90%+ coverage
- Frontend unit tests: 80%+ coverage
- Integration tests cover critical paths
-
E2E test for complete flow passes
-
Code review completed
- Security review of payment endpoints
- PCI compliance verification
-
Error handling review
-
Documentation updated
- User guide for reader setup
- Door sales operation manual
- API documentation for new endpoints
-
Troubleshooting guide
-
Performance benchmarks met
- Payment processing < 5 seconds
- Reader connection < 10 seconds
-
No memory leaks during extended use
-
Security review completed
- Penetration testing passed
- No XSS vulnerabilities
- CSRF protection verified
-
Rate limiting functional
-
Accessibility requirements met
- Keyboard navigation works
- Screen reader compatible (receipt emails)
- Color contrast meets WCAG 2.1 AA
8. Risk Assessment & Mitigation¶
8.1 Technical Risks¶
| Risk | Probability | Impact | Mitigation Strategy |
|---|---|---|---|
| Browser compatibility issues with Terminal SDK | Medium | High | Test extensively on Safari iOS, Chrome Android, Firefox. Implement graceful degradation for unsupported browsers. Provide fallback to manual entry if needed. |
| Card reader connectivity problems at venue | High | High | Implement offline queue for failed transactions. Provide manual retry mechanism. Train staff on troubleshooting. Test in low-connectivity environments before deployment. |
| Payment processing failures during peak hours | Medium | Critical | Implement retry logic with exponential backoff. Add transaction queueing. Monitor Stripe API status during events. Have backup payment method ready. |
| Network latency causing slow payments | Medium | Medium | Optimize API calls. Implement request caching where possible. Test with various network conditions. Set reasonable timeout thresholds. |
| Card reader firmware incompatibility | Low | High | Use only Stripe-recommended readers. Test firmware updates in staging. Have backup reader on-site. Subscribe to Stripe Terminal SDK updates. |
| Security vulnerability in payment flow | Low | Critical | Conduct security audit before launch. Follow Stripe security best practices. Never log sensitive payment data. Implement rate limiting. Regular penetration testing. |
| Stripe API rate limits exceeded | Low | Medium | Implement exponential backoff. Cache non-critical data. Monitor API usage during events. Contact Stripe for rate limit increase if needed. |
| Data synchronization issues (offline mode) | Medium | Medium | Implement robust offline queue. Add conflict resolution logic. Test offline scenarios extensively. Provide manual reconciliation tools. |
8.2 Resource Risks¶
Schedule Risks: - Risk: 120-hour estimate may be optimistic - Mitigation: Build in 20% buffer for unknowns. Prioritize MVP features first. Consider phased rollout starting with single-show pilot.
- Risk: Hardware procurement delays (2-4 week lead time for readers)
- Mitigation: Order readers immediately upon approval. Use Stripe test simulator for development. Parallel-track development while waiting for hardware.
Skill Gaps: - Risk: Team unfamiliar with Stripe Terminal SDK - Mitigation: Allocate time for learning (8 hours). Review Stripe Terminal documentation and examples. Consider Stripe support consultation. Pair programming for terminal integration.
- Risk: Limited PCI compliance expertise
- Mitigation: Leverage Stripe's PCI compliance (Terminal handles sensitive data). Review Stripe security documentation. Consult with security expert if needed.
External Dependencies: - Risk: Stripe Terminal SDK changes/deprecations - Mitigation: Pin SDK versions. Subscribe to Stripe changelog. Test updates in staging before production. Maintain SDK version compatibility matrix.
- Risk: Hardware availability (readers sold out)
- Mitigation: Order early. Identify alternative compatible readers. Maintain relationship with Stripe sales rep.
Budget Risks: - Risk: Card reader cost ($299-$699 each) - Mitigation: Start with 1-2 readers for pilot. Budget for 1 reader per 500 expected walk-up customers. Consider reader rental programs if available.
- Risk: Transaction fees (Stripe Terminal: 2.7% + $0.05 per transaction)
- Mitigation: Factor into ticket pricing. Compare to alternative payment processors. Volume discounts may be available.
8.3 Rollback Strategy¶
Feature Flags:
- Implement feature flag for door sales tab: ENABLE_DOOR_SALES
- Default: false (disabled)
- Enable per show or globally via admin panel
- Can disable instantly if critical issues arise
Database Migrations: - All Order model changes use nullable fields - Migration rollback procedure:
- Data preservation: No data loss on rollback (new fields simply unused)Deployment Strategy: - Blue/Green Deployment: - Deploy to staging environment first - Test with real hardware - Deploy to production during low-traffic period - Keep previous version running for quick rollback
- Canary Deployment:
- Enable for single show (pilot event)
- Monitor for 1 week
- Gradually enable for more shows
- Full rollout after 3 successful events
Rollback Triggers: - Critical payment processing failures (> 5% error rate) - Security vulnerability discovered - Data corruption or order creation failures - Reader connectivity issues affecting > 25% of transactions - Negative user feedback from door staff or customers
Rollback Procedure:
1. Disable ENABLE_DOOR_SALES feature flag (immediate effect)
2. Notify door staff via email/SMS
3. Switch to backup payment method (manual card entry or cash)
4. Investigate root cause
5. Deploy fix to staging
6. Re-enable feature flag after validation
9. Deployment & Operations¶
9.1 Deployment Plan¶
Environment Progression:
- Development (Local):
- Docker Compose environment
- Stripe test mode
- Terminal SDK simulator (no hardware)
-
Duration: 2-3 weeks (development phase)
-
Staging:
- Staging server matching production config
- Stripe test mode
- Physical card reader for testing
- Test data: 3-5 sample shows
-
Duration: 1 week (testing phase)
-
Production - Pilot:
- Single show with expected walk-up traffic
- Stripe live mode
- Feature flag enabled for pilot show only
- Door staff trained on new feature
-
Duration: 1 event (pilot test)
-
Production - Full Rollout:
- Feature flag enabled for all shows
- Multiple card readers if needed
- Documentation published
- Duration: Ongoing
Database Changes:
# Staging deployment
python manage.py migrate tickets
# Production deployment (during maintenance window)
python manage.py migrate tickets --no-input
Configuration Updates:
Environment variables needed:
# .env additions
STRIPE_TERMINAL_ENABLED=true
STRIPE_TERMINAL_LOCATION_ID=tml_xxx # From Stripe Dashboard
ENABLE_DOOR_SALES=false # Feature flag (enable per show initially)
Monitoring Setup: - Add Sentry error tracking for terminal operations - CloudWatch/Datadog metrics: - Door sale transaction count - Payment success/failure rate - Average payment processing time - Reader connection status - Stripe Dashboard monitoring: - Terminal payment volume - Dispute rate for door sales - Reader health status
9.2 Monitoring & Observability¶
Key Metrics:
- Payment Metrics:
- Door sales transaction volume (per show, per hour)
- Payment success rate (target: > 95%)
- Payment failure rate by reason (card declined, network error, etc.)
- Average payment processing time (target: < 5 seconds)
-
Total door revenue per show
-
Technical Metrics:
- Reader connection uptime (target: > 99%)
- API endpoint response times
- Error rate on door sales endpoints (target: < 1%)
- Queue length for offline transactions
-
Database query performance
-
User Experience Metrics:
- Time from ticket selection to payment complete (target: < 60 seconds)
- Customer drop-off rate during payment
- Receipt email delivery rate
- Door staff satisfaction score (survey)
Alerting:
| Alert | Condition | Severity | Action |
|---|---|---|---|
| Payment failure spike | > 10% failure rate in 5 minutes | Critical | Page on-call engineer, notify door staff |
| Reader disconnected | Reader offline > 2 minutes | High | Notify door staff, attempt reconnection |
| API endpoint down | 5xx errors > 5 in 1 minute | Critical | Page on-call engineer |
| Slow payment processing | > 10 seconds for payment | Medium | Investigate network/Stripe API latency |
| Offline queue backing up | > 10 queued transactions | High | Notify staff, check connectivity |
| Database performance | Query time > 1 second | Medium | Investigate slow queries |
Logging:
Log all door sales transactions with:
{
"event": "door_sale_completed",
"timestamp": "2025-11-03T19:45:23Z",
"show_id": 123,
"order_id": 789,
"payment_intent_id": "pi_xxx",
"terminal_reader_id": "tmr_xxx",
"door_staff_user_id": 456,
"amount": 75.00,
"ticket_count": 3,
"processing_time_ms": 4250
}
Error logging:
{
"event": "door_sale_error",
"timestamp": "2025-11-03T19:50:12Z",
"error_type": "card_declined",
"error_message": "insufficient_funds",
"show_id": 123,
"terminal_reader_id": "tmr_xxx",
"retry_count": 0
}
Health Checks:
Create /api/v1/checkin/health/ endpoint:
{
"status": "healthy",
"terminal_sdk_version": "1.0.0",
"readers_connected": 1,
"offline_queue_length": 0,
"database_connection": "ok",
"stripe_api_reachable": true
}
9.3 Support & Maintenance¶
Documentation:
- User Guides:
- "Door Sales Quick Start Guide" - 2-page PDF for door staff
- "Card Reader Setup Guide" - Step-by-step with screenshots
- "Troubleshooting Common Issues" - FAQ format
-
Video tutorial: "Processing Your First Door Sale" (5 minutes)
-
Technical Documentation:
- API reference for door sales endpoints
- Terminal SDK integration guide
- Database schema changes
- Deployment runbook
- Monitoring and alerting guide
Training:
- Door Staff Training (30 minutes):
- Reader setup and connection
- Processing a door sale
- Handling payment errors
- Issuing receipts
-
Basic troubleshooting
-
Producer Training (15 minutes):
- How to view door sales in reports
- Understanding door vs. online metrics
- Reader procurement process
Ongoing Maintenance:
- Weekly:
- Review error logs for door sales
- Check payment success rates
-
Monitor reader firmware updates
-
Monthly:
- Review door sales metrics vs. online sales
- Analyze payment failure reasons
- Update documentation based on support tickets
-
Review and optimize database queries
-
Quarterly:
- Security audit of payment endpoints
- Performance optimization
- Update Stripe Terminal SDK to latest version
- Review hardware (replace damaged readers)
Support Escalation:
- Level 1: Door staff self-service
- Consult quick start guide
-
Basic troubleshooting (restart reader, check internet)
-
Level 2: Producer/event support contact
- Email: support@piquetickets.com
-
Response time: 1 hour during event hours
-
Level 3: Engineering team
- On-call engineer for critical issues
-
Response time: 15 minutes for critical alerts
-
Level 4: Stripe support
- For reader hardware issues
- For payment processing anomalies
Maintenance Windows: - Deploy updates during low-traffic periods (Tue-Thu, 2-4 AM local time) - Notify producers 48 hours in advance for maintenance - Zero-downtime deployments for most changes
10. Success Measurement¶
10.1 Success Metrics¶
Technical Metrics: - Payment Success Rate: > 95% (target: 98%) - Baseline: N/A (new feature) - Measurement: Track successful payments / total payment attempts
- Payment Processing Speed: < 5 seconds average (target: 3 seconds)
-
Measurement: Time from payment initiated to confirmation
-
System Uptime: > 99.5% during event hours
-
Measurement: Reader connectivity + API availability
-
Error Rate: < 1% on door sales endpoints
- Baseline: General API error rate ~0.5%
- Measurement: 5xx errors / total requests
User Metrics: - Door Sales Adoption Rate: > 50% of shows using door sales within 3 months - Measurement: Shows with door sales enabled / total shows
- Door Sales Volume: 10-20% of total ticket sales come from door
- Industry benchmark: 15% average for live events
-
Measurement: Door tickets sold / total tickets sold
-
Door Staff Satisfaction: > 4.0/5.0 rating
- Baseline: N/A (new feature)
-
Measurement: Post-event survey of door staff
-
Customer Satisfaction: < 5% complaint rate
- Measurement: Support tickets related to door sales / total door transactions
Business Metrics: - Revenue Impact: $5,000+ additional revenue per month from walk-up sales - Assumption: 10 shows/month × 20 walk-up tickets × $25 average = $5,000 - Measurement: Total door sales revenue
- Cash Handling Reduction: 80% reduction in cash transactions at door
- Baseline: Currently ~100% cash at door
-
Measurement: Card payments / total door payments
-
Reconciliation Time: 50% reduction in post-event accounting time
- Baseline: ~2 hours per event for manual cash reconciliation
- Measurement: Time to reconcile door sales (target: < 30 minutes)
10.2 Review Schedule¶
Initial Review (1 week after pilot event): - Review pilot event metrics - Gather door staff feedback - Identify any critical issues - Decide: Proceed with rollout OR iterate on fixes
Adoption Review (1 month after launch): - Measure adoption rate (shows using door sales) - Analyze payment success rates - Review support ticket volume - Identify common issues and pain points - Update documentation based on learnings
Success Evaluation (3 months after launch): - Full metrics review against targets - Calculate ROI (revenue increase vs. hardware/development cost) - Producer feedback survey - Technical performance analysis - Decide: Continue, expand, or modify feature
Ongoing Reviews (Quarterly): - Review KPIs and trends - Competitive analysis (other ticketing platforms) - Technology updates (new reader models, SDK versions) - Feature enhancement opportunities
11. Hardware Procurement & Setup¶
11.1 Recommended Hardware¶
Primary Recommendation: Stripe Reader S700 - Price: $299 USD - Connectivity: WiFi or Ethernet - Features: - Accepts chip, swipe, contactless (NFC) - Built-in receipt printer (thermal) - Color touchscreen display (5-inch) - EMV Level 1 & 2, PCI PTS 5.x certified - Pros: - All-in-one solution (reader + printer) - Reliable internet connectivity - Long battery life (optional battery base) - Customer-facing display - Cons: - Higher upfront cost - Requires WiFi/Ethernet at venue - Best For: Permanent box office setups, high-volume events
Alternative: BBPOS WisePOS E - Price: $549 USD - Connectivity: WiFi, 4G LTE - Features: - Android-based smart terminal - 5-inch touchscreen - Built-in printer - Camera (future QR scanning integration) - Pros: - Cellular connectivity (4G backup) - Larger display for customer interaction - Can run custom Android apps - Cons: - More expensive - Slightly more complex setup - Best For: Outdoor venues, mobile setups, areas with unreliable WiFi
Budget Option: BBPOS WisePad 3 + Tablet - Price: $199 USD (reader only, tablet separate) - Connectivity: Bluetooth (requires native app - NOT compatible with web browser) - NOT RECOMMENDED for this project due to browser incompatibility - Reason: Checkin app is web-based; WisePad 3 requires native iOS/Android SDK
11.2 Hardware Setup Guide¶
Pre-Event Setup (One-time):
- Register Reader in Stripe Dashboard:
- Log into Stripe Dashboard → Terminal → Readers
- Click "Register reader"
- Follow on-screen instructions to pair reader
- Assign reader to location (create location if needed: e.g., "Main Venue - Box Office")
-
Note the reader ID (e.g.,
tmr_xxx) -
Configure Reader:
- Connect reader to power
- Connect to WiFi (follow reader's on-screen prompts)
- Update firmware if prompted (critical for security)
-
Test print receipt to verify printer works
-
Test Payment:
- Open check-in app in test mode
- Connect to reader via app
- Process test payment with test card:
4242 4242 4242 4242 - Verify order created in admin panel
- Verify receipt prints correctly
Event Day Setup (Per Event):
- Physical Setup:
- Place reader at box office/door station
- Connect to power (or ensure battery charged)
- Verify WiFi connection (check signal strength)
-
Place receipt paper roll (carry extras)
-
App Setup:
- Open check-in app on tablet/laptop
- Navigate to Settings → Connect Reader
- Select reader from list
-
Verify "Connected" status shown
-
Readiness Check:
- Process test transaction (use Stripe test card in test mode, or small real transaction)
- Verify receipt prints
- Ensure check-in app can still scan QR codes (dual functionality)
Troubleshooting: - Reader not discovered: Check WiFi connection, restart reader, refresh app - Payment fails: Check internet connection, verify Stripe API status - Receipt not printing: Check paper roll, clean print head, verify printer enabled in settings
11.3 Procurement Recommendations¶
Quantity: - Small Venue (< 200 capacity): 1 reader - Medium Venue (200-500 capacity): 1-2 readers - Large Venue (> 500 capacity): 2-3 readers (one per entrance/box office)
Ordering: - Lead Time: 2-4 weeks for delivery - Vendor: Purchase directly from Stripe or authorized resellers - Warranty: 1-year manufacturer warranty included - Support: Stripe support available for hardware issues
Accessories: - Receipt Paper: Thermal paper rolls (50mm width for S700) - Order 10 rolls per reader (cost: ~$20 for 10 rolls) - Protective Case: Optional carrying case for mobile setups (~$50) - Battery Base: Optional for Stripe S700 (~$100, provides 8+ hours battery) - Ethernet Adapter: If WiFi unreliable at venue (~$30)
Total Estimated Cost: - Minimum Setup (1 reader): $299 + $20 (paper) = ~$320 - Recommended Setup (2 readers): $598 + $40 (paper) + $100 (battery) = ~$740 - Ongoing Costs: Receipt paper (~$20/month), Stripe transaction fees (2.7% + $0.05)
12. Appendices¶
Appendix A: Research References¶
Stripe Documentation: - Stripe Terminal Overview - Stripe Terminal JavaScript SDK - Stripe Reader S700 Specs - BBPOS WisePad 3 Specs - Connection Token Guide
Technology Research: - Context7 MCP: Stripe Terminal React Native SDK documentation analysis - Context7 MCP: Stripe.js integration patterns - Web Search: Browser compatibility for Stripe Terminal SDK (2025) - Web Search: Card reader hardware compatibility and availability
Codebase References:
- apps/checkin/src/pages/CheckIn.tsx - Current check-in flow
- apps/frontend/src/app/api/checkout/route.ts - Existing Stripe integration
- apps/api/tickets/utils/reports.py - Report generation patterns
Industry Standards: - PCI DSS compliance requirements - EMV chip card specifications - Accessibility standards (WCAG 2.1 AA)
Appendix B: Technical Diagrams¶
Architecture Diagram:
┌─────────────────────────────────────────────────────────────┐
│ Check-in App │
│ (React + TypeScript) │
│ │
│ ┌───────────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ QR Scanner │ │ Door Sales │ │ Show Info │ │
│ │ (Existing) │ │ (NEW) │ │ (Existing) │ │
│ └───────┬───────┘ └──────┬───────┘ └─────────────────┘ │
│ │ │ │
│ │ └──────────┐ │
│ │ │ │
└──────────┼────────────────────────────┼────────────────────┘
│ │
│ ▼
│ ┌──────────────────────┐
│ │ Stripe Terminal │
│ │ JavaScript SDK │
│ └──────────┬───────────┘
│ │
│ ▼
│ ┌──────────────────────┐
│ │ Card Reader │
│ │ (S700 / WisePOS E) │
│ └──────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Django REST API │
│ │
│ ┌──────────────────┐ ┌─────────────────────────────┐ │
│ │ Validate Ticket │ │ Door Sales Endpoints │ │
│ │ (Existing) │ │ (NEW) │ │
│ └──────────────────┘ │ - Connection Token │ │
│ │ - Create Payment Intent │ │
│ │ - Confirm Door Sale │ │
│ └─────────────┬───────────────┘ │
│ │ │
└──────────────────────────────────────┼─────────────────────┘
│
▼
┌──────────────────────┐
│ Stripe API │
│ (Payment Intent) │
└──────────────────────┘
│
▼
┌──────────────────────┐
│ PostgreSQL │
│ (Order Storage) │
└──────────────────────┘
Payment Flow Diagram:
Walk-up Customer → Door Staff → Check-in App (Door Sales Tab)
↓
Select Tickets + Quantities
↓
Enter Customer Info (Name, Email)
↓
[Apply Promo Code?] (Optional)
↓
Calculate Total + Fees
↓
Click "Process Payment"
↓
┌──────────────────┴─────────────────┐
▼ ▼
POST /create-door-sale-intent/ Terminal SDK
│ CollectPayment()
│ │
▼ ▼
Create PaymentIntent ────────────────▶ Customer Inserts Card
│ │
▼ ▼
Return client_secret Card Read Successful
│ │
└──────────────┬─────────────────────┘
▼
POST /confirm-door-sale/
│
▼
Verify Payment Status (Stripe API)
│
┌───────────────┴─────────────────┐
▼ ▼
Success Failure
│ │
▼ ▼
Create Order Record Show Error Message
Generate Tickets Retry or Cancel
Create QR Codes
Mark as Checked In
│
▼
Display Receipt / Send Email
Show QR Code to Customer
│
▼
Transaction Complete
Data Model Diagram:
Order (Extended)
├── id (existing)
├── first_name (existing)
├── last_name (existing)
├── email (existing)
├── total (existing)
├── platform_fees (existing)
├── payment_processing_fees (existing)
├── payment_intent_id (existing)
├── purchase_location (NEW) ──────▶ 'online' | 'door'
├── terminal_reader_id (NEW) ─────▶ 'tmr_xxx' (Stripe reader ID)
└── door_staff_user (NEW) ────────▶ Foreign Key to User
TicketOrder (Existing - No Changes)
├── order (Foreign Key to Order)
├── ticket (Foreign Key to Ticket)
└── quantity
Ticket (Existing - No Changes)
├── show (Foreign Key to Show)
├── name
├── price
└── available_quantity
Appendix C: Code Examples¶
Terminal Service Wrapper (Conceptual):
// apps/checkin/src/services/terminal.ts
import { loadStripeTerminal, Terminal } from '@stripe/terminal-js';
class TerminalService {
private terminal: Terminal | null = null;
private reader: any = null;
async initialize(connectionTokenFetcher: () => Promise<string>) {
const StripeTerminal = await loadStripeTerminal();
this.terminal = StripeTerminal.create({
onFetchConnectionToken: async () => {
const token = await connectionTokenFetcher();
return token;
},
onUnexpectedReaderDisconnect: () => {
console.warn('Reader disconnected unexpectedly');
// Attempt reconnection
}
});
}
async discoverReaders() {
if (!this.terminal) throw new Error('Terminal not initialized');
const discoverResult = await this.terminal.discoverReaders({
simulated: false, // Set to true for testing
location: 'tml_xxx' // From Stripe Dashboard
});
if (discoverResult.error) {
throw new Error(discoverResult.error.message);
}
return discoverResult.discoveredReaders;
}
async connectReader(readerId: string) {
if (!this.terminal) throw new Error('Terminal not initialized');
const connectResult = await this.terminal.connectReader(readerId);
if (connectResult.error) {
throw new Error(connectResult.error.message);
}
this.reader = connectResult.reader;
return this.reader;
}
async collectPayment(clientSecret: string) {
if (!this.terminal) throw new Error('Terminal not initialized');
if (!this.reader) throw new Error('No reader connected');
// Step 1: Collect payment method
const collectResult = await this.terminal.collectPaymentMethod(clientSecret);
if (collectResult.error) {
throw new Error(collectResult.error.message);
}
// Step 2: Process payment
const processResult = await this.terminal.processPayment(collectResult.paymentIntent);
if (processResult.error) {
throw new Error(processResult.error.message);
}
return processResult.paymentIntent;
}
}
export const terminalService = new TerminalService();
Django Connection Token Endpoint:
# apps/api/checkin/views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
@require_http_methods(["POST"])
def create_connection_token(request):
"""
Generate Stripe Terminal connection token.
Required by Terminal SDK for reader connection.
"""
# Verify session token
session_token = request.GET.get('token')
if not session_token:
return JsonResponse({'error': 'Missing session token'}, status=400)
# Validate session (existing check-in session validation logic)
session = CheckinSession.objects.filter(session_id=session_token).first()
if not session or not session.is_valid():
return JsonResponse({'error': 'Invalid session'}, status=403)
try:
# Create connection token via Stripe API
connection_token = stripe.terminal.ConnectionToken.create()
return JsonResponse({
'secret': connection_token.secret
})
except stripe.error.StripeError as e:
return JsonResponse({'error': str(e)}, status=500)
Door Sale Payment Intent Creation:
# apps/api/checkin/views.py
@require_http_methods(["POST"])
def create_door_sale_intent(request):
"""
Create Stripe PaymentIntent for door sale.
"""
data = json.loads(request.body)
show_id = data.get('show_id')
ticket_selections = data.get('ticket_selections') # [{'ticket_id': 1, 'quantity': 2}, ...]
customer_info = data.get('customer')
promo_code = data.get('promo_code')
# Validate show exists
show = get_object_or_404(Show, id=show_id)
# Calculate total
subtotal = Decimal('0.00')
for selection in ticket_selections:
ticket = get_object_or_404(Ticket, id=selection['ticket_id'])
quantity = selection['quantity']
subtotal += ticket.price * quantity
# Apply promo code if provided
if promo_code:
promo = TicketPromoCode.objects.filter(code=promo_code, show=show).first()
if promo:
discount = subtotal * promo.discount
subtotal -= discount
# Calculate fees
platform_fee = subtotal * Decimal('0.015') # 1.5%
processing_fee = (subtotal + platform_fee) * Decimal('0.029') + Decimal('0.30') # 2.9% + $0.30
total = subtotal + platform_fee + processing_fee
amount_cents = int(total * 100)
# Create PaymentIntent
try:
payment_intent = stripe.PaymentIntent.create(
amount=amount_cents,
currency='usd',
payment_method_types=['card_present'],
capture_method='automatic',
metadata={
'show_id': show_id,
'customer_email': customer_info.get('email'),
'purchase_location': 'door'
}
)
return JsonResponse({
'client_secret': payment_intent.client_secret,
'amount': total,
'payment_intent_id': payment_intent.id
})
except stripe.error.StripeError as e:
return JsonResponse({'error': str(e)}, status=500)
Appendix D: Decision Log¶
Decision 1: Web App vs. Native App - Date: 2025-11-03 - Decision: Integrate into existing web-based check-in app (Option A) - Rationale: - Lower development effort (120 hours vs. 300+ hours for native apps) - Unified workflow for door staff - Leverages existing infrastructure - Hardware cost ($299) acceptable vs. native app development cost - Alternatives Considered: - Build standalone native iOS/Android app with Tap to Pay - Build separate web portal for door sales only - Risks Accepted: - Requires internet connection for payments - Hardware procurement lead time
Decision 2: Card Reader Selection - Date: 2025-11-03 - Decision: Recommend Stripe Reader S700 as primary option - Rationale: - All-in-one solution (reader + printer) - Reliable WiFi connectivity (most venues have WiFi) - Best long-term value ($299 with built-in printer) - Proven reliability in similar use cases - Alternatives Considered: - BBPOS WisePOS E ($549) - More expensive, overkill for most use cases - BBPOS WisePad 3 ($199) - Incompatible with web browser (requires native SDK) - Risks Accepted: - Requires WiFi at venue (can add Ethernet adapter if needed)
Decision 3: Integration Approach - Date: 2025-11-03 - Decision: Add Door Sales as new tab in existing check-in app - Rationale: - Single app for door staff simplifies training - Shares authentication and session management - Consistent UI/UX with existing check-in flow - Alternatives Considered: - Separate door sales app - Modal/overlay in check-in app - Risks Accepted: - Slightly more complex UI (4 tabs instead of 3)
Decision 4: Offline Mode - Date: 2025-11-03 - Decision: Implement basic offline queue for failed payments, full offline mode deferred to Phase 2 - Rationale: - Stripe Terminal JavaScript SDK requires internet for most operations - Offline queue covers 90% of use cases (temporary network blips) - Full offline mode significantly increases complexity - Alternatives Considered: - Full offline mode with local payment storage - No offline support (require internet at all times) - Risks Accepted: - Door sales unavailable if venue has prolonged internet outage
Quick Checklist for Document Completion¶
Research Phase¶
- Analyzed existing codebase thoroughly using Serena MCP tools
- Used Context7 MCP for semantic understanding and relationship mapping
- Documented all MCP tools used in Section 3.1
- Researched industry best practices (Stripe Terminal, payment processing)
- Validated patterns against existing codebase (checkout flow, API patterns)
- Identified all stakeholders and requirements
- Assessed technical constraints and dependencies
- Verified file paths and symbols using Serena symbol analysis
Planning Phase¶
- Created detailed implementation plan (6 phases, 120 hours)
- Defined clear acceptance criteria
- Identified and mitigated risks
- Planned testing strategy (unit, integration, E2E)
Review Phase¶
- Technical review completed (awaiting review)
- Stakeholder approval obtained (pending)
- Resource allocation confirmed (pending)
- Schedule approved by team (pending)
Documentation¶
- All sections completed with specific details
- File references are accurate and verified using Serena MCP
find_file - Code patterns documented with Serena pattern search results
- Component relationships documented using Context7 insights
- All MCP tools used are documented in Section 3.1
- External links verified and accessible
- Document reviewed for clarity and completeness
MCP Tool Usage Verification¶
- Serena MCP tools documented with specific use cases
- Context7 MCP insights incorporated where applicable
- File paths verified using MCP tools (not manually guessed)
- Symbol references verified using
get_symbols_overviewresults
Next Steps¶
- Review this document with stakeholders (product, engineering, operations)
- Approve hardware purchase (Stripe Reader S700, $299 + accessories)
- Allocate development resources (1 developer, 3 weeks)
- Set pilot event date (target: 4-6 weeks from approval)
- Begin Phase 1 development (backend setup)
Questions for Stakeholders: - Is the 120-hour development estimate acceptable? - Is the $299 hardware cost per reader approved? - Which show should be the pilot event? - Do we need additional budget for training materials or support?
End of Planning Document