# Aperonight - Technical Documentation for AI Agents ## ๐Ÿค– Agent Implementation Guide This document provides technical details for AI agents working on the Aperonight ticket selling system. ## ๐Ÿ—๏ธ System Architecture ### Core Components #### 1. User Management (`app/models/user.rb`) - **Devise Integration**: Complete authentication system with registration, login, password reset - **Professional Users**: `is_professionnal` field for event promoters with enhanced permissions - **Onboarding System**: Multi-step onboarding process with `onboarding_completed` tracking - **Stripe Integration**: `stripe_customer_id` for accounting and invoice management - **Relationships**: Users can create events, purchase tickets, and manage promotion codes - **Validations**: Email format, password strength, optional name fields, company information #### 2. Event System (`app/models/event.rb`) - **States**: `draft`, `published`, `canceled`, `sold_out` with enum management - **Geographic Data**: Latitude/longitude for venue mapping - **Relationships**: Belongs to user, has many ticket types, tickets through ticket types, and orders - **Scopes**: Featured events, published events, upcoming events with proper ordering - **Duplication**: Event duplication functionality for similar events #### 3. Order Management (`app/models/order.rb`) - **Order States**: `draft`, `pending_payment`, `paid`, `completed`, `cancelled`, `expired` - **Payment Processing**: Stripe integration with payment attempt tracking - **Platform Fees**: โ‚ฌ0.50 fixed + 1.5% per ticket automatic calculation - **Expiration**: 15-minute draft order expiration with automatic cleanup - **Promotion Integration**: Support for discount code application - **Invoice Generation**: Automatic Stripe invoice creation for accounting #### 4. Promotion Code System (`app/models/promotion_code.rb`) - **Discount Management**: Fixed amount discounts (stored in cents, displayed in euros) - **Usage Controls**: Per-event and per-user association with usage limits - **Expiration**: Date-based expiration with active/inactive status management - **Validation**: Real-time validation during checkout process - **Tracking**: Complete usage tracking and analytics #### 5. Ticket Management - **TicketType** (`app/models/ticket_type.rb`): Defines ticket categories with pricing, quantity, sale periods - **Ticket** (`app/models/ticket.rb`): Individual tickets with unique QR codes, status tracking, price storage - **Order Association**: Tickets now belong to orders for better transaction management #### 6. Payment Processing (`app/controllers/orders_controller.rb`) - **Order-Based Workflow**: Complete shift from direct ticket purchase to order-based system - **Stripe Integration**: Complete checkout session creation and payment confirmation - **Session Management**: Proper handling of payment success/failure with order and ticket generation - **Security**: Authentication required, cart validation, availability checking - **Invoice Service**: Post-payment invoice generation with StripeInvoiceService ### Database Schema Key Points ```sql -- Users table (enhanced with professional features) CREATE TABLE users ( id bigint PRIMARY KEY, email varchar(255) UNIQUE NOT NULL, encrypted_password varchar(255) NOT NULL, first_name varchar(255), last_name varchar(255), is_professionnal boolean DEFAULT false, onboarding_completed boolean DEFAULT false, stripe_customer_id varchar(255), company_name varchar(255), -- Devise fields: confirmation, reset tokens, etc. ); -- Events table (enhanced with order management) CREATE TABLE events ( id bigint PRIMARY KEY, user_id bigint REFERENCES users(id), name varchar(100) NOT NULL, slug varchar(100) NOT NULL, description text(1000) NOT NULL, venue_name varchar(100) NOT NULL, venue_address varchar(200) NOT NULL, latitude decimal(10,8) NOT NULL, longitude decimal(11,8) NOT NULL, start_time datetime NOT NULL, end_time datetime, state integer DEFAULT 0, -- enum: draft=0, published=1, canceled=2, sold_out=3 featured boolean DEFAULT false, image varchar(500) ); -- Order management system (new core table) CREATE TABLE orders ( id bigint PRIMARY KEY, user_id bigint REFERENCES users(id), event_id bigint REFERENCES events(id), status varchar(255) DEFAULT 'draft', total_amount_cents integer DEFAULT 0, platform_fee_cents integer DEFAULT 0, payment_attempts integer DEFAULT 0, expires_at timestamp, last_payment_attempt_at timestamp, stripe_checkout_session_id varchar(255), stripe_invoice_id varchar(255) ); -- Promotion codes table (new discount system) CREATE TABLE promotion_codes ( id bigint PRIMARY KEY, code varchar(255) UNIQUE NOT NULL, discount_amount_cents integer DEFAULT 0, expires_at datetime, active boolean DEFAULT true, usage_limit integer, uses_count integer DEFAULT 0, user_id bigint REFERENCES users(id), event_id bigint REFERENCES events(id) ); -- Order-promotion code join table CREATE TABLE order_promotion_codes ( order_id bigint REFERENCES orders(id), promotion_code_id bigint REFERENCES promotion_codes(id) ); -- Ticket types define pricing and availability CREATE TABLE ticket_types ( id bigint PRIMARY KEY, event_id bigint REFERENCES events(id), name varchar(255) NOT NULL, description text, price_cents integer NOT NULL, quantity integer NOT NULL, sale_start_at datetime, sale_end_at datetime, requires_id boolean DEFAULT false, minimum_age integer ); -- Individual tickets with QR codes (enhanced with order association) CREATE TABLE tickets ( id bigint PRIMARY KEY, user_id bigint REFERENCES users(id), order_id bigint REFERENCES orders(id), ticket_type_id bigint REFERENCES ticket_types(id), qr_code varchar(255) UNIQUE NOT NULL, price_cents integer NOT NULL, status varchar(255) DEFAULT 'active' -- active, used, expired, refunded ); ``` ## ๐ŸŽฏ Key Implementation Details ### 1. Dashboard Metrics (`app/controllers/pages_controller.rb`) ```ruby # User-specific metrics with optimized queries @booked_events = current_user.tickets .joins(:ticket_type, :event) .where(events: { state: :published }) .count # Event counts for different timeframes @events_today = Event.published .where("DATE(start_time) = ?", Date.current) .count # User's actual booked events (not just count) @user_booked_events = Event.joins(ticket_types: :tickets) .where(tickets: { user: current_user, status: 'active' }) .distinct .limit(5) ``` ### 2. Order Management Flow (`app/controllers/orders_controller.rb`) #### Order Creation and Payment 1. **Cart-to-Order Conversion**: Convert shopping cart to draft order with 15-minute expiration 2. **Platform Fee Calculation**: Automatic calculation of โ‚ฌ0.50 fixed + 1.5% per ticket 3. **Promotion Code Application**: Real-time discount validation and application 4. **Stripe Checkout Session**: Create payment session with order metadata 5. **Payment Retry**: Support for multiple payment attempts with proper tracking ```ruby # Order creation with platform fees def create @order = Order.new(order_params) @order.user = current_user @order.calculate_platform_fee @order.set_expiration if @order.save session = create_stripe_checkout_session(@order) redirect_to session.url, allow_other_host: true else render :new, status: :unprocessable_entity end end # Platform fee calculation def calculate_platform_fee ticket_count = order_items.sum(:quantity) self.platform_fee_cents = 50 + (total_amount_cents * 0.015).to_i end ``` #### Payment Confirmation and Invoice Generation 1. **Order Status Update**: Transition from pending_payment to paid 2. **Ticket Generation**: Create tickets associated with the order 3. **Stripe Invoice Creation**: Async invoice generation for accounting 4. **Promotion Code Usage**: Increment usage counters for applied codes ### 3. Enhanced Stripe Integration #### StripeInvoiceService (`app/services/stripe_invoice_service.rb`) - Post-payment invoice creation with customer management - Line item processing with promotion discounts - PDF invoice URL generation for download - Accounting record synchronization ```ruby class StripeInvoiceService def initialize(order) @order = order end def create_invoice customer = find_or_create_stripe_customer invoice_items = create_invoice_items(customer) invoice = Stripe::Invoice.create({ customer: customer.id, auto_advance: true, collection_method: 'charge_automatically' }) @order.update(stripe_invoice_id: invoice.id) invoice.finalize_invoice end end ``` ### 4. Promotion Code System (`app/models/promotion_code.rb`) #### Code Validation and Application - **Real-time Validation**: Check code validity, expiration, and usage limits - **Discount Calculation**: Apply fixed amount discounts to order totals - **Usage Tracking**: Increment usage counters and prevent overuse - **Event-Specific Codes**: Support for both global and event-specific codes ```ruby def valid_for_use?(user = nil, event = nil) return false unless active? return false if expired? return false if usage_limit_reached? return false if user.present? && !valid_for_user?(user) return false if event.present? && !valid_for_event?(event) true end def apply_discount(total_amount) [total_amount - discount_amount_cents, 0].max end ``` ### 5. Background Job Architecture #### StripeInvoiceGenerationJob - Async invoice creation after successful payment - Retry logic with exponential backoff - Error handling and logging #### ExpiredOrdersCleanupJob - Automatic cleanup of expired draft orders - Database maintenance and hygiene #### EventReminderJob & EventReminderSchedulerJob - Automated event reminder emails - Scheduled notifications for upcoming events ### 6. PDF Ticket Generation (`app/services/ticket_pdf_generator.rb`) ```ruby class TicketPdfGenerator def generate Prawn::Document.new(page_size: [350, 600], margin: 20) do |pdf| # Header with branding pdf.fill_color "2D1B69" pdf.font "Helvetica", style: :bold, size: 24 pdf.text "ApรฉroNight", align: :center # Event details pdf.text ticket.event.name, align: :center # QR Code generation qr_code_data = { ticket_id: ticket.id, qr_code: ticket.qr_code, event_id: ticket.event.id, user_id: ticket.user.id }.to_json qrcode = RQRCode::QRCode.new(qr_code_data) pdf.print_qr_code(qrcode, extent: 120, align: :center) end.render end end ``` ### 7. Frontend Architecture #### Enhanced Stimulus Controllers - **ticket_selection_controller.js**: Advanced cart management with real-time updates - **event_form_controller.js**: Dynamic event creation with location services - **countdown_controller.js**: Order expiration countdown timers - **event_duplication_controller.js**: Event copying functionality - **qr_code_controller.js**: QR code display and scanning #### Order-Based Cart Management - **Session Storage**: Preserves cart state during authentication flows - **Real-time Updates**: Dynamic total calculation with promotion codes - **Validation**: Client-side validation with server-side verification - **Payment Flow**: Seamless integration with Stripe checkout ## ๐Ÿ”ง Development Patterns ### Model Validations ```ruby # Event validations validates :name, presence: true, length: { minimum: 3, maximum: 100 } validates :latitude, numericality: { greater_than_or_equal_to: -90, less_than_or_equal_to: 90 } # Order validations with state management validates :status, presence: true, inclusion: { in: %w[draft pending_payment paid completed cancelled expired] } validate :order_not_expired, on: :create before_validation :set_expiration, on: :create # Promotion code validations validates :code, presence: true, uniqueness: true validates :discount_amount_cents, numericality: { greater_than_or_equal_to: 0 } validate :expiration_date_cannot_be_in_the_past # Ticket QR code generation before_validation :generate_qr_code, on: :create def generate_qr_code loop do self.qr_code = SecureRandom.uuid break unless Ticket.exists?(qr_code: qr_code) end end ``` ### Controller Patterns ```ruby # Authentication for sensitive actions before_action :authenticate_user!, only: [:checkout, :payment_success, :download_ticket] # Professional user authorization before_action :authenticate_professional!, only: [:create_promotion_code] # Strong parameters with nested attributes private def order_params params.require(:order).permit(:promotion_code, order_items_attributes: [:ticket_type_id, :quantity]) end # Platform fee calculation def calculate_platform_fee ticket_count = order_items.sum(:quantity) self.platform_fee_cents = 50 + (total_amount_cents * 0.015).to_i end ``` ### Service Layer Patterns ```ruby # Service for complex business logic class StripeInvoiceService def initialize(order) @order = order end def call customer = find_or_create_stripe_customer create_invoice_items(customer) generate_invoice end private def find_or_create_stripe_customer if @order.user.stripe_customer_id.present? Stripe::Customer.retrieve(@order.user.stripe_customer_id) else customer = Stripe::Customer.create(email: @order.user.email) @order.user.update(stripe_customer_id: customer.id) customer end end end ``` ### View Helpers and Partials - **Metric Cards**: Reusable component for dashboard statistics - **Event Items**: Consistent event display across pages - **Flash Messages**: Centralized notification system - **Order Components**: Reusable order display and management components ## ๐Ÿš€ Deployment Considerations ### Environment Variables ```bash # Required for production STRIPE_PUBLISHABLE_KEY=pk_live_... STRIPE_SECRET_KEY=sk_live_... STRIPE_WEBHOOK_SECRET=whsec_... DATABASE_URL=mysql2://user:pass@host/db RAILS_MASTER_KEY=... # Rails 8 Solid Stack SOLID_QUEUE_IN_PUMA=true SOLID_CACHE_URL=redis://localhost:6379/0 SOLID_CABLE_URL=redis://localhost:6379/1 # Application Configuration PLATFORM_FEE_FIXED_CENTS=50 PLATFORM_FEE_PERCENTAGE=1.5 ORDER_EXPIRATION_MINUTES=15 ``` ### Database Indexes ```sql -- Performance indexes for common queries CREATE INDEX idx_events_published_start_time ON events (state, start_time); CREATE INDEX idx_orders_user_status ON orders (user_id, status); CREATE INDEX idx_orders_expires_at ON orders (expires_at) WHERE status = 'draft'; CREATE INDEX idx_tickets_user_status ON tickets (user_id, status); CREATE INDEX idx_ticket_types_event ON ticket_types (event_id); CREATE INDEX idx_promotion_codes_code ON promotion_codes (code); CREATE INDEX idx_promotion_codes_active_expires ON promotion_codes (active, expires_at); ``` ### Security Considerations - **CSRF Protection**: Rails default protection enabled - **Strong Parameters**: All user inputs filtered - **Authentication**: Devise handles session security - **Payment Security**: Stripe handles sensitive payment data - **Professional User Authorization**: Role-based access control for event promoters - **Order Expiration**: Automatic cleanup of abandoned orders - **Promotion Code Validation**: Server-side validation with usage limits ### Background Jobs ```ruby # Async invoice generation StripeInvoiceGenerationJob.perform_later(order_id) # Cleanup expired orders ExpiredOrdersCleanupJob.perform_later # Event reminders EventReminderSchedulerJob.set(wait_until: event.start_time - 2.hours).perform_later(event_id) ``` ## ๐ŸŒ API Layer ### RESTful Endpoints ```ruby # API Namespacing for external integrations namespace :api do namespace :v1 do resources :events, only: [:index, :show] do resources :ticket_types, only: [:index] end resources :carts, only: [:create, :show, :update] resources :orders, only: [:create, :show, :update] post '/promotion_codes/validate', to: 'promotion_codes#validate' end end ``` ### API Authentication - **Token-based authentication**: API tokens for external integrations - **Rate limiting**: Request throttling for API endpoints - **Versioning**: Versioned API namespace for backward compatibility ## ๐Ÿงช Testing Strategy ### Key Test Cases 1. **User Authentication**: Registration, login, logout flows 2. **Professional User Onboarding**: Multi-step onboarding process 3. **Event Creation**: Validation, state management, relationships 4. **Order Management**: Cart-to-order conversion, payment processing, expiration 5. **Promotion Code System**: Code validation, discount application, usage tracking 6. **PDF Generation**: QR code uniqueness, ticket format 7. **Stripe Integration**: Payment processing, invoice generation 8. **Background Jobs**: Async processing, error handling, retry logic 9. **API Endpoints**: RESTful API functionality and authentication 10. **Dashboard Metrics**: Query accuracy, performance ### Seed Data Structure ```ruby # Creates comprehensive test data users = User.create!([...]) events = Event.create!([...]) ticket_types = TicketType.create!([...]) promotion_codes = PromotionCode.create!([...]) orders = Order.create!([...]) ``` ## ๐Ÿ› ๏ธ Available Development Tools ### AST-Grep for Mass Code Replacement The system has `ast-grep` installed for structural code search and replacement. This tool is particularly useful for: - **Mass refactoring**: Rename methods, classes, or variables across the codebase - **Pattern-based replacements**: Update code patterns using AST matching - **Language-aware transformations**: Safer than regex for code modifications #### Usage Examples: ```bash # Find all method calls to a specific method ast-grep --pattern 'find_by_$FIELD($VALUE)' --lang ruby # Replace method calls with new syntax ast-grep --pattern 'find_by_$FIELD($VALUE)' --rewrite 'find_by($FIELD: $VALUE)' --lang ruby # Search for specific Rails patterns ast-grep --pattern 'validates :$FIELD, presence: true' --lang ruby # Mass rename across multiple files ast-grep --pattern 'old_method_name($$$ARGS)' --rewrite 'new_method_name($$$ARGS)' --lang ruby --update-all # Find all order-related validations ast-grep --pattern 'validates :status, inclusion: { in: \%w[...] }' --lang ruby ``` #### Best Practices: - Always run with `--dry-run` first to preview changes - Use `--lang ruby` for Ruby files to ensure proper AST parsing - Test changes in a branch before applying to main codebase - Particularly useful for Rails conventions and ActiveRecord pattern updates ### Modern Rails 8 Stack - **Solid Queue**: Background job processing - **Solid Cache**: Fast caching layer - **Solid Cable**: Action Cable over Redis - **Propshaft**: Asset pipeline - **Kamal**: Deployment tooling - **Thruster**: Performance optimization ## ๐Ÿ“ Code Style & Conventions - **Ruby Style**: Follow Rails conventions and Rubocop rules - **Database**: Use Rails migrations for all schema changes - **JavaScript**: Stimulus controllers for interactive behavior - **CSS**: Tailwind utility classes with custom components - **Service Layer**: Complex business logic in service objects - **Background Jobs**: Async processing for long-running tasks - **API Design**: RESTful principles with versioning - **Documentation**: Inline comments for complex business logic - **Mass Changes**: Use `ast-grep` for structural code replacements instead of simple find/replace - **Testing**: Comprehensive test coverage for all business logic This architecture provides a solid foundation for a scalable ticket selling platform with proper separation of concerns, security, and user experience, featuring modern Rails 8 capabilities and a comprehensive order management system.