12 KiB
12 KiB
Series Ticketing Implementation
Overview
Comprehensive ticketing system for event series that allows users to purchase a single pass for all events in a series, or optionally register for individual events (drop-in model).
Two Ticketing Models Supported
1. Series-Level Ticketing (Default)
Intent: Registrants attend all sessions in the series
Use cases:
- Workshop series (e.g., 4-week game dev workshop)
- Courses
- Multi-day events
- Any series where commitment to all sessions is expected
How it works:
- Purchase ONE series pass that grants access to ALL events
- Single payment covers the entire series
- Automatic registration for all events upon purchase
- User receives single confirmation email with full schedule
2. Event-Level Ticketing (Drop-in)
Intent: Each event can be attended independently
Use cases:
- Recurring meetups (e.g., monthly community calls)
- Tournaments where sessions are standalone
- Drop-in events where flexibility is key
How it works:
- Each event has its own ticket configuration
- Users register per event, not for the series
- Can attend just one, some, or all events
- Standard event ticketing applies
What Was Built
1. Data Models
New Series Model (server/models/series.js)
Dedicated model for managing event series with:
- Series metadata (title, description, type, dates)
- Full ticket configuration (member/public pricing, capacity)
- Circle-specific pricing overrides
- Early bird pricing support
- Waitlist functionality
- Series registrations tracking
- Event registration references
Enhanced Event Model
Added fields to server/models/event.js:
tickets.requiresSeriesTicket- Flag to indicate series pass is requiredtickets.seriesTicketReference- Reference to Series modelregistrations.ticketType- Added "series_pass" optionregistrations.isSeriesTicketHolder- Boolean flagregistrations.seriesTicketId- Reference to series registration
2. Backend Logic
Series Ticket Utilities (server/utils/tickets.js)
Added 8 new functions:
calculateSeriesTicketPrice()- Pricing with member/circle overridescheckSeriesTicketAvailability()- Real-time availability checkingvalidateSeriesTicketPurchase()- Pre-purchase validationreserveSeriesTicket()- Temporary reservation during checkoutreleaseSeriesTicket()- Release abandoned reservationscompleteSeriesTicketPurchase()- Finalize purchase and update countscheckUserSeriesPass()- Verify if user has valid passregisterForAllSeriesEvents()- Bulk registration across all events
3. API Endpoints
Series Ticket Endpoints
GET /api/series/[id]/tickets/available- Check pass availability and pricingPOST /api/series/[id]/tickets/purchase- Complete series pass purchasePOST /api/series/[id]/tickets/check-eligibility- Verify member statusGET /api/events/[id]/check-series-access- Verify series pass ownership for event
4. Frontend Components
EventSeriesTicketCard.vue
Beautiful purple-themed card displaying:
- Series pass name and pricing
- What's included (all events listed)
- Member savings comparison
- Event schedule preview (first 3 events)
- Availability status
- Member benefit callouts
SeriesPassPurchase.vue
Complete purchase flow component:
- Loads series pass information
- Registration form (name/email)
- Helcim payment integration for paid passes
- Success/error handling with toast notifications
- Automatic registration for all events
- Email confirmation
Updated EventTicketPurchase.vue
Enhanced to detect series pass requirements:
- Checks if event requires series pass
- Shows "Series Pass Required" message with link to series
- Displays "Registered via Series Pass" for pass holders
- Graceful fallback to regular ticketing
5. Email Templates
Series Pass Confirmation Email
Professional HTML email featuring:
- Purple gradient header
- Full series pass details
- Complete event schedule with dates/times
- Member benefit callout (if applicable)
- Transaction ID (if paid)
- "What's Next" guidance
- Dashboard link
6. UI Integration
Updated Series Detail Page (/series/[id].vue)
- New "Get Your Series Pass" section
- Displays SeriesPassPurchase component
- Shows only if
series.tickets.enabledis true - Refreshes data after successful purchase
- User session integration
Configuration Examples
Example 1: Free Member Series, Paid Public
const series = {
id: "coop-game-dev-2025",
title: "Cooperative Game Development Workshop Series",
type: "workshop_series",
tickets: {
enabled: true,
requiresSeriesTicket: true, // Must buy series pass
allowIndividualEventTickets: false,
currency: "CAD",
member: {
available: true,
isFree: true,
name: "Member Series Pass",
description: "Free for Ghost Guild members"
},
public: {
available: true,
price: 100.00,
earlyBirdPrice: 80.00,
earlyBirdDeadline: "2025-11-01T00:00:00Z",
name: "Public Series Pass",
description: "Access to all 4 workshops"
},
capacity: {
total: 30 // Total capacity across all ticket types
}
}
}
Example 2: Circle-Specific Pricing
const series = {
tickets: {
enabled: true,
member: {
isFree: false,
price: 50.00, // Default member price
circleOverrides: {
community: {
isFree: true // Free for community circle
},
founder: {
price: 25.00 // Discounted for founders
},
practitioner: {
price: 10.00 // Heavily discounted
}
}
}
}
}
Example 3: Drop-in Series (Individual Event Tickets)
const series = {
id: "monthly-meetup-2025",
title: "Monthly Community Meetup",
type: "recurring_meetup",
tickets: {
enabled: false, // No series-level tickets
requiresSeriesTicket: false,
allowIndividualEventTickets: true
}
}
// Each event in series has its own tickets config
const event = {
series: {
id: "monthly-meetup-2025",
isSeriesEvent: true
},
tickets: {
enabled: true,
member: {
isFree: true
},
public: {
available: true,
price: 10.00
}
}
}
User Flows
Flow 1: Member Purchases Free Series Pass
- Member visits series page (
/series/coop-game-dev-2025) - Sees "Free for Members" series pass card
- Fills in name/email (pre-filled from session)
- Clicks "Complete Registration"
- System creates series registration
- System registers user for all 4 events automatically
- User receives series pass confirmation email with full schedule
- Page refreshes showing "You're Registered!" status
Flow 2: Public User Purchases Paid Series Pass
- Public user visits series page
- Sees "$100 Series Pass" (or $80 early bird)
- Fills in name/email
- Clicks "Pay $100.00"
- Helcim payment modal opens
- User completes payment
- System processes payment and creates registrations
- User receives confirmation email with transaction ID
- Success toast shows "You're registered for all 4 events"
Flow 3: User with Series Pass Views Individual Event
- User has series pass for "Coop Game Dev Series"
- Visits individual event page (
/events/workshop-1) - EventTicketPurchase component checks series access
- Sees "You're Registered!" with message: "You have access to this event via your series pass for Cooperative Game Development Workshop Series"
- No payment or registration required
Flow 4: User Without Series Pass Views Required Event
- User visits event that requires series pass
- EventTicketPurchase component detects requirement
- Sees purple banner: "Series Pass Required"
- Message explains event is part of series
- "View Series & Purchase Pass" button
- Clicking redirects to series page to buy pass
Database Schema
Series Document Structure
{
_id: ObjectId,
id: "coop-game-dev-2025", // String identifier
slug: "cooperative-game-development-workshop-series",
title: "Cooperative Game Development Workshop Series",
description: "Learn to build co-op games...",
type: "workshop_series",
isVisible: true,
isActive: true,
startDate: ISODate("2025-11-15"),
endDate: ISODate("2025-12-06"),
totalEvents: 4,
tickets: {
enabled: true,
requiresSeriesTicket: true,
currency: "CAD",
member: { /* ... */ },
public: { /* ... */ },
capacity: { total: 30, reserved: 2 }
},
registrations: [
{
memberId: ObjectId,
name: "Jane Doe",
email: "jane@example.com",
ticketType: "member",
ticketPrice: 0,
paymentStatus: "not_required",
registeredAt: ISODate,
eventRegistrations: [
{ eventId: ObjectId, registrationId: ObjectId },
{ eventId: ObjectId, registrationId: ObjectId }
]
}
],
targetCircles: ["founder", "practitioner"],
createdBy: "admin",
createdAt: ISODate,
updatedAt: ISODate
}
Backward Compatibility
✅ Fully backward compatible
- Events without series tickets work as before
- Legacy pricing model still supported
- Existing registrations unaffected
- Series can exist without ticket system enabled
Testing Checklist
Series Pass Purchase
- Member can see free series pass
- Public user sees correct pricing
- Early bird pricing displays correctly
- Helcim payment modal opens for paid passes
- Payment processes successfully
- All events get registrations created
- Confirmation email sends with all events listed
- Capacity decrements correctly
Event Access Control
- User with series pass sees "Registered" on event pages
- User without pass sees "Series Pass Required" message
- Link to series page works correctly
- Individual event tickets disabled when series pass required
Edge Cases
- Already registered users see correct message
- Sold out series shows waitlist option
- Cancelled events don't allow registration
- Payment failures don't create registrations
- Concurrent purchases don't oversell
Future Enhancements
Phase 2 (Planned)
- Series pass transfers between users
- Partial series passes ("Any 3 of 5 workshops")
- Upgrade from individual ticket to series pass
- Series pass refunds and cancellations
- Admin dashboard for series pass holders
- Export attendee lists by series
Phase 3 (Nice to Have)
- Gift series passes
- Group/team series passes
- Installment payment plans
- Series completion certificates
- Recurring series subscriptions
Files Created/Modified
New Files (9)
server/models/series.js- Series data modelserver/api/series/[id]/tickets/available.get.js- Check availabilityserver/api/series/[id]/tickets/purchase.post.js- Purchase series passserver/api/series/[id]/tickets/check-eligibility.post.js- Member checkserver/api/events/[id]/check-series-access.get.js- Verify pass ownershipapp/components/EventSeriesTicketCard.vue- Series pass display cardapp/components/SeriesPassPurchase.vue- Purchase flow componentSERIES_TICKETING_IMPLEMENTATION.md- This documentation
Modified Files (4)
server/models/event.js- Added series ticket fieldsserver/utils/tickets.js- Added 8 series ticket functions (~360 lines)server/utils/resend.js- Added series pass confirmation emailapp/components/EventTicketPurchase.vue- Series pass detectionapp/pages/series/[id].vue- Integrated purchase UI
Total Implementation
- ~1,200 lines of new code
- 9 new files
- 4 modified files
- 4 new API endpoints
- 2 new Vue components
- 8 new utility functions
- 1 new data model
Support
For questions or issues:
- Review this documentation
- Check existing ticketing docs:
HELCIM_TICKET_INTEGRATION.md - Reference project context:
CLAUDE.md
Status: ✅ Implementation Complete
Last Updated: 2025-10-14
Developer: Claude (Anthropic)