Skip to content

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:

  1. SDK Platform Limitations:
  2. Stripe Terminal React Native SDK: Only works with native iOS/Android apps, NOT compatible with web browsers, PWAs, or React web apps
  3. Stripe Terminal JavaScript SDK: Designed for web browsers, compatible with Chrome, Safari, Firefox, Edge
  4. Tap to Pay: Only available via iOS SDK and Android SDK, NOT available for browser-based applications

  5. Card Reader Requirements:

  6. 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
  7. Bluetooth Readers: BBPOS WisePad 3, Chipper 2X BT
    • Require native SDK (iOS/Android) for Bluetooth pairing
    • NOT compatible with browser-based JavaScript SDK
  8. Verifone P400: Legacy device, no longer recommended by Stripe

  9. Browser Compatibility:

  10. JavaScript SDK works in: Chrome, Safari, Firefox, Edge (desktop and mobile browsers)
  11. Requires HTTPS for security
  12. 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:

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:

  1. Reader Setup (One-time per event):

    Door Staff → Check-in App → Settings → Connect Card Reader
    → Reader discovered → Connection established
    

  2. Door Sale Flow:

    Walk-up Customer → Door Sales Tab → Select Tickets → Enter Customer Info
    → Tap "Process Payment" → Insert/Tap Card → Payment Authorized
    → Ticket Generated → QR Code/Receipt Shown/Emailed
    → Check In Customer (automatic)
    

  3. Error Handling:

    Payment Declined → Show Error → Retry or Cancel
    Network Error → Queue for Retry → Notify Staff
    

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:

  1. Phase 1: Add Stripe Terminal SDK and connection flow
  2. Install dependencies
  3. Create terminal service wrapper
  4. Build reader connection UI
  5. Test reader discovery

  6. Phase 2: Build door sales UI

  7. Create door sales tab
  8. Implement ticket selection
  9. Add customer info form
  10. Build payment flow UI

  11. Phase 3: Backend integration

  12. Create connection token endpoint
  13. Build payment intent creation endpoint
  14. Implement order creation for door sales
  15. Add ticket generation

  16. Phase 4: Testing and polish

  17. Test payment flows
  18. Error handling
  19. Receipt generation
  20. 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:

  1. Terminal SDK Connection Test:
  2. Build minimal HTML page with Terminal SDK
  3. Test reader discovery and connection
  4. Verify payment flow works
  5. Estimate: 4 hours

  6. Offline Queue Test:

  7. Test payment queuing when offline
  8. Verify sync when connection restored
  9. 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 activeTab type 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 methods
  • apps/checkin/src/components/DoorSales/TicketSelection.test.tsx - Ticket selection logic
  • apps/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:

python manage.py migrate tickets <previous_migration_number>
- 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:

  1. Development (Local):
  2. Docker Compose environment
  3. Stripe test mode
  4. Terminal SDK simulator (no hardware)
  5. Duration: 2-3 weeks (development phase)

  6. Staging:

  7. Staging server matching production config
  8. Stripe test mode
  9. Physical card reader for testing
  10. Test data: 3-5 sample shows
  11. Duration: 1 week (testing phase)

  12. Production - Pilot:

  13. Single show with expected walk-up traffic
  14. Stripe live mode
  15. Feature flag enabled for pilot show only
  16. Door staff trained on new feature
  17. Duration: 1 event (pilot test)

  18. Production - Full Rollout:

  19. Feature flag enabled for all shows
  20. Multiple card readers if needed
  21. Documentation published
  22. 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:

  1. Payment Metrics:
  2. Door sales transaction volume (per show, per hour)
  3. Payment success rate (target: > 95%)
  4. Payment failure rate by reason (card declined, network error, etc.)
  5. Average payment processing time (target: < 5 seconds)
  6. Total door revenue per show

  7. Technical Metrics:

  8. Reader connection uptime (target: > 99%)
  9. API endpoint response times
  10. Error rate on door sales endpoints (target: < 1%)
  11. Queue length for offline transactions
  12. Database query performance

  13. User Experience Metrics:

  14. Time from ticket selection to payment complete (target: < 60 seconds)
  15. Customer drop-off rate during payment
  16. Receipt email delivery rate
  17. 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:

  1. User Guides:
  2. "Door Sales Quick Start Guide" - 2-page PDF for door staff
  3. "Card Reader Setup Guide" - Step-by-step with screenshots
  4. "Troubleshooting Common Issues" - FAQ format
  5. Video tutorial: "Processing Your First Door Sale" (5 minutes)

  6. Technical Documentation:

  7. API reference for door sales endpoints
  8. Terminal SDK integration guide
  9. Database schema changes
  10. Deployment runbook
  11. 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:

  1. Level 1: Door staff self-service
  2. Consult quick start guide
  3. Basic troubleshooting (restart reader, check internet)

  4. Level 2: Producer/event support contact

  5. Email: support@piquetickets.com
  6. Response time: 1 hour during event hours

  7. Level 3: Engineering team

  8. On-call engineer for critical issues
  9. Response time: 15 minutes for critical alerts

  10. Level 4: Stripe support

  11. For reader hardware issues
  12. 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

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):

  1. Register Reader in Stripe Dashboard:
  2. Log into Stripe Dashboard → Terminal → Readers
  3. Click "Register reader"
  4. Follow on-screen instructions to pair reader
  5. Assign reader to location (create location if needed: e.g., "Main Venue - Box Office")
  6. Note the reader ID (e.g., tmr_xxx)

  7. Configure Reader:

  8. Connect reader to power
  9. Connect to WiFi (follow reader's on-screen prompts)
  10. Update firmware if prompted (critical for security)
  11. Test print receipt to verify printer works

  12. Test Payment:

  13. Open check-in app in test mode
  14. Connect to reader via app
  15. Process test payment with test card: 4242 4242 4242 4242
  16. Verify order created in admin panel
  17. Verify receipt prints correctly

Event Day Setup (Per Event):

  1. Physical Setup:
  2. Place reader at box office/door station
  3. Connect to power (or ensure battery charged)
  4. Verify WiFi connection (check signal strength)
  5. Place receipt paper roll (carry extras)

  6. App Setup:

  7. Open check-in app on tablet/laptop
  8. Navigate to Settings → Connect Reader
  9. Select reader from list
  10. Verify "Connected" status shown

  11. Readiness Check:

  12. Process test transaction (use Stripe test card in test mode, or small real transaction)
  13. Verify receipt prints
  14. 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_overview results

Next Steps

  1. Review this document with stakeholders (product, engineering, operations)
  2. Approve hardware purchase (Stripe Reader S700, $299 + accessories)
  3. Allocate development resources (1 developer, 3 weeks)
  4. Set pilot event date (target: 4-6 weeks from approval)
  5. 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