style: correct coding style with rubocop linter

This commit is contained in:
kbe
2025-09-05 12:02:44 +02:00
parent 46c8faf10c
commit 15e3c7dff5
40 changed files with 121 additions and 1663 deletions

View File

@@ -1,157 +0,0 @@
# Application.js Size Optimization Guide
## Current Issue
The `application.js` bundle is 1.4MB (2.3MB with source maps), which is significantly larger than recommended.
## Root Causes
1. **Single bundle includes everything**: All dependencies, React, controllers, and components
2. **No code splitting**: Everything is bundled into one file
3. **Development dependencies**: Alpine.js and other dev tools included
4. **No minification/optimization**: Source maps and uncompressed code
## Optimization Strategies
### 1. Split Bundles (Recommended)
Create separate bundles for different parts of the application:
**Update package.json build scripts:**
```json
{
"scripts": {
"build": "npm run build:main && npm run build:components",
"build:main": "esbuild app/javascript/application.js --bundle --minify --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets",
"build:components": "esbuild app/javascript/components/*.* --bundle --minify --format=esm --outdir=app/assets/builds/components --public-path=/assets --loader:.js=jsx",
"build:css": "postcss ./app/assets/stylesheets/application.postcss.css -o ./app/assets/builds/application.css"
}
}
```
### 2. Remove Unused Dependencies
**package.json optimization:**
```json
{
"dependencies": {
"@hotwired/stimulus": "^3.2.2",
"@hotwired/turbo-rails": "^8.0.13",
"@radix-ui/react-slot": "^1.2.3",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"esbuild": "^0.25.4",
"postcss": "^8.5.3",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.4",
"tailwindcss-animate": "^1.0.7"
}
}
```
**Remove these from devDependencies:**
- `alpinejs` - if not used
- `@types/alpinejs` - if Alpine.js removed
- `cssnano` - if using Tailwind's built-in minification
- `pm2` - production deployment tool
### 3. Dynamic Imports (Code Splitting)
**Update application.js:**
```javascript
// Instead of importing everything statically
import "@hotwired/turbo-rails"
import "./controllers"
// Use dynamic imports for heavy components
const loadComponent = async (componentName) => {
const { default: component } = await import(`./components/${componentName}`)
return component
}
```
### 4. Tree Shaking & Minification
**Enhanced build command:**
```json
{
"build": "esbuild app/javascript/application.js --bundle --minify --tree-shaking --drop:console --drop:debugger --sourcemap=external --format=esm --outdir=app/assets/builds --public-path=/assets"
}
```
### 5. Separate Vendor Bundle
**Create vendor.js:**
```javascript
// app/javascript/vendor.js
import "react"
import "react-dom"
import "@radix-ui/react-slot"
```
**Update build to create vendor bundle:**
```json
{
"build:vendor": "esbuild app/javascript/vendor.js --bundle --minify --format=esm --outdir=app/assets/builds --public-path=/assets",
"build:app": "esbuild app/javascript/application.js --bundle --minify --external:react --external:react-dom --format=esm --outdir=app/assets/builds --public-path=/assets"
}
```
### 6. Conditional Loading
**Lazy load heavy components:**
```javascript
// app/javascript/application.js
if (document.querySelector('[data-controller="shadcn-test"]')) {
import('./controllers/shadcn_test_controller')
}
```
### 7. Production Optimization Checklist
**Step 1: Analyze bundle size**
```bash
npm install --save-dev webpack-bundle-analyzer
npx esbuild app/javascript/application.js --bundle --analyze
```
**Step 2: Implement optimizations**
```bash
# Remove unused dependencies
npm uninstall alpinejs @types/alpinejs cssnano pm2
# Update build scripts
npm run build
```
**Step 3: Verify size reduction**
Should reduce from 1.4MB to ~200-400KB
## Quick Fix Commands
```bash
# 1. Remove Alpine.js (if unused)
npm uninstall alpinejs @types/alpinejs
# 2. Update build with optimization
npm install --save-dev esbuild@latest
# 3. Modify package.json scripts
# (Copy the optimized scripts above)
# 4. Build with optimization
npm run build
```
## Expected Results
- **Before**: 1.4MB application.js
- **After**: 200-400KB with code splitting
- **Vendor bundle**: ~100KB (cached)
- **App bundle**: ~100-300KB (dynamic)
## Monitoring
Add bundle size monitoring to CI/CD:
```json
{
"size-limits": {
"app/assets/builds/application.js": "500kb",
"app/assets/builds/application.css": "50kb"
}
}

View File

@@ -1,363 +0,0 @@
# Aperonight - Technical Architecture
## Overview
Aperonight is a Ruby on Rails web application designed for proposing night parties in Paris and allowing event makers to create their own events. The application serves two primary user groups:
### For Customers:
- View upcoming and past parties
- Book tickets with customizable bundles (simple entry, VIP, group passes, etc.)
- Complete secure payments via credit card, PayPal, or bank transfer
- Access mobile-friendly interface for ticket management
- Receive unique, scannable tickets (QR codes)
### For Promoters:
- Create and schedule parties
- Define custom ticket bundles and pricing
- Aggregate events from external platforms (Shogun, Bizouk, Weezevent)
- Scan tickets at events using mobile devices
## Technical Architecture
### 1. Database Schema
```ruby
# User - Handles both customers and promoters
create_table :users do |t|
t.string :email
t.string :password_digest
t.string :role # customer or promoter
t.timestamps
end
# Event - Events created by promoters
create_table :events do |t|
t.string :name
t.text :description
t.datetime :start_time
t.datetime :end_time
t.string :location
t.integer :promoter_id
t.timestamps
end
# TicketType - Customizable bundles defined by promoters
create_table :ticket_types do |t|
t.string :name
t.text :description
t.decimal :price
t.integer :event_id
t.timestamps
end
# Ticket - Individual ticket instances purchased by customers
create_table :tickets do |t|
t.string :uuid
t.string :qr_code
t.integer :event_id
t.integer :user_id
t.integer :ticket_type_id
t.boolean :used, default: false
t.timestamps
end
# Payment - Transaction records for ticket purchases
create_table :payments do |t|
t.string :payment_method # credit_card, paypal, bank_account
t.string :transaction_id
t.integer :user_id
t.integer :ticket_id
t.decimal :amount
t.timestamps
end
```
### 2. Core Models
```ruby
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :tickets
has_many :payments
has_many :parties, foreign_key: 'promoter_id'
end
class Event < ApplicationRecord
belongs_to :promoter, class_name: 'User'
has_many :tickets
has_many :ticket_types
end
class TicketType < ApplicationRecord
belongs_to :event
has_many :tickets
end
class Ticket < ApplicationRecord
belongs_to :event
belongs_to :user
belongs_to :ticket_type
has_one :payment
before_create :generate_uuid_and_qr_code
private
def generate_uuid_and_qr_code
self.uuid = SecureRandom.uuid
self.qr_code = RQRCode::QRCode.new(self.uuid).as_svg
end
end
class Payment < ApplicationRecord
belongs_to :user
belongs_to :ticket
enum payment_method: {
credit_card: 'credit_card',
paypal: 'paypal',
bank_account: 'bank_account'
}
after_create :process_payment
private
def process_payment
case self.payment_method
when 'credit_card'
process_stripe_payment
when 'paypal'
process_paypal_payment
when 'bank_account'
process_bank_account_payment
end
end
end
```
### 3. Key Controllers
#### Parties Controller
```ruby
class PartiesController < ApplicationController
before_action :authenticate_user!
before_action :set_event, only: [:show, :edit, :update, :destroy]
def index
@parties = Event.all
end
def show
@ticket_types = @event.ticket_types
end
def new
@event = Event.new
@event.ticket_types.build
end
def create
@event = current_user.parties.build(event_params)
if @event.save
redirect_to @event, notice: 'Event was successfully created.'
else
render :new
end
end
private
def set_event
@event = Event.find(params[:id])
end
def event_params
params.require(:event).permit(
:name, :description, :start_time, :end_time, :location,
ticket_types_attributes: [:id, :name, :description, :price, :_destroy]
)
end
end
```
#### Tickets Controller
```ruby
class TicketsController < ApplicationController
before_action :authenticate_user!
before_action :set_event, only: [:new, :create]
def new
@ticket = Ticket.new
end
def create
@ticket = current_user.tickets.build(ticket_params)
if @ticket.save
redirect_to @ticket, notice: 'Ticket was successfully booked.'
else
render :new
end
end
def scan
end
def validate
qr_code = params[:qr_code]
ticket = Ticket.find_by(qr_code: qr_code)
if ticket && !ticket.used
ticket.update(used: true)
render json: { valid: true }
else
render json: { valid: false }
end
end
private
def set_event
@event = Event.find(params[:event_id])
end
def ticket_params
params.require(:ticket).permit(:ticket_type_id, :event_id)
end
end
```
### 4. Payment Integration
#### Stripe Configuration
```ruby
# config/initializers/stripe.rb
Rails.configuration.stripe = {
publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
secret_key: ENV['STRIPE_SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
```
#### PayPal Configuration
```ruby
# config/initializers/paypal.rb
PayPal::SDK.configure({
mode: ENV['PAYPAL_MODE'], # 'sandbox' or 'live'
client_id: ENV['PAYPAL_CLIENT_ID'],
client_secret: ENV['PAYPAL_CLIENT_SECRET']
})
```
### 5. Frontend Considerations
#### Mobile Ticket Scanning
```erb
<!-- app/views/tickets/scan.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>Scan Ticket</title>
<script src="https://unpkg.com/html5-qrcode"></script>
</head>
<body>
<h1>Scan Ticket</h1>
<div id="reader" width="500"></div>
<div id="result"></div>
<script>
function docReady(fn) {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
docReady(function () {
var resultContainer = document.getElementById('result');
var lastResult, countResults = 0;
function onScanSuccess(qrCodeMessage) {
if (qrCodeMessage !== lastResult) {
++countResults;
lastResult = qrCodeMessage;
resultContainer.innerHTML = `<span class="label">Last scanned QR Code: </span> <a href="${qrCodeMessage}">${qrCodeMessage}</a>`;
fetch('/tickets/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({ qr_code: qrCodeMessage })
})
.then(response => response.json())
.then(data => {
if (data.valid) {
resultContainer.innerHTML += '<p>Ticket is valid.</p>';
} else {
resultContainer.innerHTML += '<p>Ticket is invalid.</p>';
}
})
.catch(error => {
console.error('Error:', error);
});
}
}
var html5QrcodeScanner = new Html5QrcodeScanner(
"reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess);
});
</script>
</body>
</html>
```
### 6. Routes Configuration
```ruby
# config/routes.rb
Rails.application.routes.draw do
devise_for :users
resources :parties do
resources :ticket_types, only: [:new, :create, :edit, :update, :destroy]
end
resources :ticket_types, only: [:index, :show]
resources :tickets do
resources :payments, only: [:new, :create]
collection do
post 'validate'
end
end
get 'paypal_success', to: 'payments#paypal_success'
get 'paypal_cancel', to: 'payments#paypal_cancel'
get 'tickets/scan', to: 'tickets#scan'
root 'parties#index'
end
```
## Implementation Recommendations
### Authentication & Authorization
- Use Devise for user authentication
- Implement Pundit or CanCanCan for role-based access control
- Distinguish clearly between customer and promoter permissions
### Payment Processing
- Integrate Stripe for credit card payments
- Add PayPal support through official SDK
- Consider Plaid for bank account integration
### Performance & Scalability
- Implement Redis for caching frequently accessed data
- Use CDN for static assets (images, CSS, JS)
- Employ background job processing (Sidekiq) for emails and payments
- Optimize database queries with proper indexing
### Security Considerations
- Validate all user inputs
- Sanitize HTML output to prevent XSS
- Secure payment processing with PCI compliance
- Implement rate limiting for API endpoints
- Regular security audits and dependency updates

View File

@@ -1,142 +0,0 @@
Cette conversation a été générée avec Duck.ai (https://duck.ai) à l'aide du modèle Mistral Small 3 d'Mistral AI. Les chats IA peuvent afficher des informations inexactes ou offensantes (voir https://duckduckgo.com/duckai/privacy-terms pour en savoir plus).
====================
Message 1 sur 2 de l'utilisateur - 16/08/2025, 08:06:58:
In a git Ruby on Rails web project, how to name branches?
Mistral Small 3:
Naming branches in a Git Ruby on Rails web project (or any Git project) is an important aspect of maintaining a clean and understandable repository. Here are some best practices for naming branches:
1. **Use Descriptive Names**: The branch name should clearly describe the purpose or the feature being worked on. This helps other developers understand the context of the branch at a glance.
2. **Use Hyphens or Underscores**: Use hyphens (`-`) or underscores (`_`) to separate words in the branch name. This makes the name more readable.
3. **Prefix with the Type of Change**: Prefix the branch name with a type indicator such as `feature`, `bugfix`, `hotfix`, `release`, `chore`, `refactor`, `docs`, etc. This helps in categorizing the branches.
4. **Keep It Short but Meaningful**: While being descriptive, try to keep the branch name short to avoid clutter.
5. **Avoid Special Characters**: Stick to alphanumeric characters and hyphens/underscores. Avoid using special characters like `@`, `#`, `$`, etc.
6. **Use Lowercase Letters**: Consistently use lowercase letters to avoid case sensitivity issues.
Here are some examples of well-named branches:
- `feature/user-authentication`
- `bugfix/login-issue`
- `hotfix/critical-bug`
- `release/v1.2.0`
- `chore/update-dependencies`
- `refactor/user-model`
- `docs/update-readme`
### Example Workflow
1. **Creating a New Feature Branch**:
```sh
git checkout -b feature/user-authentication
```
2. **Creating a Bugfix Branch**:
```sh
git checkout -b bugfix/login-issue
```
3. **Creating a Hotfix Branch**:
```sh
git checkout -b hotfix/critical-bug
```
4. **Creating a Release Branch**:
```sh
git checkout -b release/v1.2.0
```
5. **Creating a Chore Branch**:
```sh
git checkout -b chore/update-dependencies
```
6. **Creating a Refactor Branch**:
```sh
git checkout -b refactor/user-model
```
7. **Creating a Docs Branch**:
```sh
git checkout -b docs/update-readme
```
By following these guidelines, you can maintain a well-organized and understandable branch structure in your Git repository, making collaboration and code management much easier.
--------------------
Message 2 sur 2 de l'utilisateur - 16/08/2025, 08:08:31:
Is it a good practice to use main, develop and functionnal names for branches?
Mistral Small 3:
Using `main`, `develop`, and feature branches is a common and widely accepted practice in Git workflows, particularly in the context of the Git Flow or GitHub Flow methodologies. Here's a breakdown of these branches and why they are useful:
1. **`main` Branch**:
- **Purpose**: The `main` branch (or sometimes called `master`) is the stable branch that always contains the production-ready code. It represents the current state of the project that is deployed to production.
- **Usage**: This branch should only contain code that has been thoroughly tested and is ready for release. It is typically protected to prevent direct commits and requires pull requests for changes.
- **Example**: `git checkout main`
2. **`develop` Branch**:
- **Purpose**: The `develop` branch is used for integrating features and preparing for the next release. It serves as a staging area for features that are in progress but not yet ready for production.
- **Usage**: Developers merge their feature branches into `develop` for integration testing. This branch can be less stable than `main` but should still be in a reasonably good state.
- **Example**: `git checkout develop`
3. **Feature Branches**:
- **Purpose**: Feature branches are used to develop new features, bug fixes, or any other isolated work. Each feature branch is created from `develop` and merged back into `develop` once the work is complete.
- **Usage**: These branches allow for parallel development without interfering with the stability of `develop` or `main`. They are typically named descriptively, as discussed earlier (e.g., `feature/user-authentication`, `bugfix/login-issue`).
- **Example**: `git checkout -b feature/user-authentication`
### Example Workflow
1. **Create a Feature Branch**:
```sh
git checkout develop
git pull origin develop
git checkout -b feature/user-authentication
```
2. **Develop the Feature**:
- Make changes, commit them, and push the branch to the remote repository.
```sh
git add .
git commit -m "Add user authentication feature"
git push origin feature/user-authentication
```
3. **Merge the Feature Branch into `develop`**:
- Once the feature is complete and tested, create a pull request to merge it into `develop`.
```sh
git checkout develop
git pull origin develop
git merge feature/user-authentication
git push origin develop
```
4. **Prepare for Release**:
- When preparing for a new release, create a release branch from `develop`.
```sh
git checkout -b release/v1.2.0
```
5. **Merge Release Branch into `main`**:
- After testing the release branch, merge it into `main` and tag the release.
```sh
git checkout main
git merge release/v1.2.0
git tag -a v1.2.0 -m "Release version 1.2.0"
git push origin main --tags
```
### Benefits
- **Stability**: The `main` branch remains stable and always contains production-ready code.
- **Integration**: The `develop` branch allows for continuous integration of features, making it easier to test and integrate new work.
- **Isolation**: Feature branches isolate work, allowing multiple developers to work on different features simultaneously without conflicts.
Using `main`, `develop`, and feature branches is a good practice as it helps maintain a clean, organized, and manageable repository, facilitating better collaboration and code management.

View File

@@ -1,322 +0,0 @@
# Backend Checkout Handling Improvements
Based on your current Stripe integration, here are key improvements for robust checkout handling:
## 1. Enhanced Inventory Management with Concurrency Protection
The current implementation doesn't prevent overselling during concurrent purchases.
Add database-level concurrency protection:
```ruby
# app/controllers/events_controller.rb
def checkout
cart_data = JSON.parse(params[:cart] || "{}")
if cart_data.empty?
redirect_to event_path(@event.slug, @event), alert: "Veuillez sélectionner au moins un billet"
return
end
# Use transaction with row-level locking for inventory protection
ActiveRecord::Base.transaction do
line_items = []
order_items = []
cart_data.each do |ticket_type_id, item|
# Lock the ticket type row to prevent race conditions
ticket_type = @event.ticket_types.lock.find_by(id: ticket_type_id)
next unless ticket_type
quantity = item["quantity"].to_i
next if quantity <= 0
# Check real-time availability with locked row
sold_count = ticket_type.tickets.count
available = ticket_type.quantity - sold_count
if quantity > available
redirect_to event_path(@event.slug, @event), alert: "Plus que #{available} billets disponibles pour #{ticket_type.name}"
return
end
# Create line items and order data
line_items << {
price_data: {
currency: "eur",
product_data: {
name: "#{@event.name} - #{ticket_type.name}",
description: ticket_type.description
},
unit_amount: ticket_type.price_cents
},
quantity: quantity
}
order_items << {
ticket_type_id: ticket_type.id,
ticket_type_name: ticket_type.name,
quantity: quantity,
price_cents: ticket_type.price_cents
}
end
if order_items.empty?
redirect_to event_path(@event.slug, @event), alert: "Commande invalide"
return
end
# Create Stripe session only after inventory validation
session = Stripe::Checkout::Session.create({
payment_method_types: ["card"],
line_items: line_items,
mode: "payment",
success_url: payment_success_url(event_id: @event.id, session_id: "{CHECKOUT_SESSION_ID}"),
cancel_url: event_url(@event.slug, @event),
customer_email: current_user.email,
metadata: {
event_id: @event.id,
user_id: current_user.id,
order_items: order_items.to_json
}
})
redirect_to session.url, allow_other_host: true
end
rescue ActiveRecord::RecordNotFound
redirect_to event_path(@event.slug, @event), alert: "Type de billet introuvable"
rescue Stripe::StripeError => e
redirect_to event_path(@event.slug, @event), alert: "Erreur de traitement du paiement : #{e.message}"
end
```
## 2. Webhook Handler for Reliable Payment Confirmation
Create a dedicated webhook endpoint for more reliable payment processing:
### Routes Configuration
```ruby
# config/routes.rb
post '/webhooks/stripe', to: 'webhooks#stripe'
```
### Webhooks Controller
```ruby
# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :verify_stripe_signature
def stripe
case @event.type
when 'checkout.session.completed'
handle_successful_payment(@event.data.object)
when 'payment_intent.payment_failed'
handle_failed_payment(@event.data.object)
end
head :ok
end
private
def handle_successful_payment(session)
# Process ticket creation in background job for reliability
CreateTicketsJob.perform_later(session.id)
end
def handle_failed_payment(session)
Rails.logger.error "Payment failed for session: #{session.id}"
# Add any additional handling for failed payments
end
def verify_stripe_signature
payload = request.body.read
sig_header = request.env['HTTP_STRIPE_SIGNATURE']
begin
@event = Stripe::Webhook.construct_event(
payload, sig_header, ENV['STRIPE_WEBHOOK_SECRET']
)
rescue JSON::ParserError, Stripe::SignatureVerificationError => e
Rails.logger.error "Stripe webhook signature verification failed: #{e.message}"
head :bad_request
end
end
end
```
## 3. Background Job for Ticket Creation
Use background jobs to prevent timeouts and improve reliability:
```ruby
# app/jobs/create_tickets_job.rb
class CreateTicketsJob < ApplicationJob
queue_as :default
retry_on StandardError, wait: :exponentially_longer, attempts: 5
def perform(session_id)
session = Stripe::Checkout::Session.retrieve(session_id)
return unless session.payment_status == 'paid'
# Prevent duplicate processing
return if Ticket.exists?(stripe_session_id: session_id)
order_items = JSON.parse(session.metadata['order_items'])
user = User.find(session.metadata['user_id'])
event = Event.find(session.metadata['event_id'])
ActiveRecord::Base.transaction do
order_items.each do |item|
ticket_type = TicketType.find(item['ticket_type_id'])
item['quantity'].times do
ticket = Ticket.create!(
user: user,
ticket_type: ticket_type,
status: 'active',
stripe_session_id: session_id, # Prevent duplicates
price_cents: item['price_cents'] # Store historical price
)
# Send email asynchronously
TicketMailer.purchase_confirmation(ticket).deliver_later
end
end
end
end
end
```
## 4. Enhanced Error Handling & Recovery in Payment Success
Improve the payment success handler with better error recovery:
```ruby
# app/controllers/events_controller.rb - Enhanced payment_success method
def payment_success
session_id = params[:session_id]
event_id = params[:event_id]
# Validate parameters
unless session_id.present? && event_id.present?
redirect_to dashboard_path, alert: "Paramètres de confirmation manquants"
return
end
begin
@tickets = Ticket.includes(:ticket_type, :event)
.where(stripe_session_id: session_id, user: current_user)
if @tickets.any?
# Tickets already created (webhook processed first)
@event = @tickets.first.event
render 'payment_success'
else
# Fallback: create tickets synchronously if webhook failed
session = Stripe::Checkout::Session.retrieve(session_id)
if session.payment_status == 'paid'
CreateTicketsJob.perform_now(session_id)
redirect_to payment_success_path(session_id: session_id, event_id: event_id)
else
redirect_to dashboard_path, alert: "Le paiement n'est pas encore confirmé"
end
end
rescue Stripe::StripeError => e
logger.error "Stripe error in payment_success: #{e.message}"
redirect_to dashboard_path, alert: "Erreur de confirmation de paiement"
rescue => e
logger.error "Unexpected error in payment_success: #{e.message}"
redirect_to dashboard_path, alert: "Une erreur inattendue s'est produite"
end
end
```
## 5. Database Schema Improvements
Add migration for better payment tracking:
```ruby
# db/migrate/xxx_add_payment_tracking_to_tickets.rb
class AddPaymentTrackingToTickets < ActiveRecord::Migration[7.0]
def change
add_column :tickets, :stripe_session_id, :string
add_column :tickets, :purchased_at, :timestamp, default: -> { 'CURRENT_TIMESTAMP' }
add_index :tickets, :stripe_session_id, unique: true
add_index :tickets, [:user_id, :purchased_at]
end
end
```
## 6. Security Considerations
1. **Rate Limiting**: Add rate limiting to checkout endpoints
2. **CSRF Protection**: Already implemented ✅
3. **Input Validation**: Validate all cart data thoroughly
4. **Audit Logging**: Log all payment attempts and outcomes
5. **PCI Compliance**: Never store card data (Stripe handles this) ✅
## 7. Monitoring & Observability
Add metrics tracking to monitor checkout performance:
```ruby
# Add to ApplicationController or EventsController
around_action :track_checkout_metrics, only: [:checkout]
private
def track_checkout_metrics
start_time = Time.current
begin
yield
# Log successful checkout
Rails.logger.info("Checkout completed", {
event_id: @event&.id,
user_id: current_user&.id,
duration: Time.current - start_time
})
rescue => e
# Log failed checkout
Rails.logger.error("Checkout failed", {
event_id: @event&.id,
user_id: current_user&.id,
error: e.message,
duration: Time.current - start_time
})
raise
end
end
```
## Summary of Improvements
Your ticket checkout system is already well-implemented with Stripe integration! The enhancements above will make it production-ready:
### Critical Improvements
1. Add database row locking to prevent overselling during concurrent purchases
2. Implement Stripe webhooks for reliable payment processing
3. Use background jobs for ticket creation to prevent timeouts
4. Add duplicate prevention with stripe_session_id tracking
### Security & Reliability
5. Enhanced error recovery with fallback ticket creation
6. Comprehensive logging for debugging and monitoring
7. Database schema improvements for better payment tracking
### Key Files to Modify
- `app/controllers/events_controller.rb` - Add inventory locking
- `app/controllers/webhooks_controller.rb` - New webhook handler
- `app/jobs/create_tickets_job.rb` - Background ticket creation
- Migration for `stripe_session_id` field
These enhancements will make your checkout system robust for high-traffic scenarios and edge cases.

View File

@@ -1,103 +0,0 @@
# Theme Rules & Color Palette - Aperonight
Extracted from `app/views/pages/home.html.erb`
## Color Palette
### Primary Colors
- **Indigo**: `#4338ca` (rgb(67, 56, 202)) - Used in hero gradient
- **Purple**: `#8b5cf6` (rgb(139, 92, 246)) - Primary brand color
- **Pink**: `#ec4899` (rgb(236, 72, 153)) - Accent color
### Background Gradients
- **Hero**: `bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700`
- **CTA**: `bg-gradient-to-r from-purple-900 via-indigo-900 to-pink-900`
- **Cards**: `bg-gradient-to-br from-gray-800 to-gray-900`
- **Buttons**: `bg-gradient-to-r from-purple-600 to-pink-600`
### Text Colors
- **White**: `text-white` - Primary text
- **Gray-200**: `text-gray-200` - Secondary text
- **Gray-300**: `text-gray-300` - Subtle text
- **Gray-400**: `text-gray-400` - Muted text
- **Transparent gradient**: `text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400` - Special highlight
### Background Colors
- **Gray-900**: `bg-gray-900` - Main background
- **Black**: `bg-black` - Overlay backgrounds
- **Gray-800**: `bg-gray-800` - Card backgrounds
- **White/Transparent**: `bg-white bg-opacity-10 backdrop-blur-sm` - Glass effect
## Spacing & Layout
### Hero Section
- **Height**: `min-h-[70vh]`
- **Max-width**: `max-w-7xl mx-auto`
- **Padding**: `px-4 sm:px-6 lg:px-8`
### Grid Layouts
- **Responsive**: `grid-cols-1 md:grid-cols-2 lg:grid-cols-3`
- **Gap**: `gap-8` standard spacing
### Padding Classes
- **Section**: `py-16`, `py-20`
- **Card**: `p-4`, `p-6`, `p-8`
- **Button**: `py-3`, `py-4`, `px-6`, `px-8`
## Typography
### Font Sizes
- **Hero Title**: `text-5xl md:text-7xl`
- **Section Title**: `text-4xl`
- **Card Title**: `text-2xl`
- **Body**: `text-xl`, `text-lg`
- **Small**: `text-sm`
### Font Weights
- **Bold**: `font-bold` (headings)
- **Semibold**: `font-semibold` (buttons, important text)
- **Medium**: `font-medium` (labels)
## Interactive States
### Hover Effects
- **Scale**: `hover:scale-105`
- **Transition**: `transition-all duration-300`
- **Button Hover**: `hover:from-purple-700 hover:to-pink-700`
- **Glass Hover**: `hover:bg-opacity-20`
### Shadows
- **Default**: `shadow-lg`
- **Strong**: `shadow-xl`
- **Card**: `shadow-2xl`
## Border Radius
- **Buttons**: `rounded-full` (pill-shaped)
- **Cards**: `rounded-2xl`
- **Inputs**: `rounded-lg`
## Icon Colors
- **Primary**: `text-white` (on colored backgrounds)
- **Accent**: `text-purple-400`, `text-pink-400`
- **Muted**: `text-gray-400`
## Usage Examples
### Primary Button
```html
class="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white font-semibold py-4 px-8 rounded-full transition-all duration-300 transform hover:scale-105 shadow-lg"
```
### Card Background
```html
class="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl overflow-hidden hover:transform hover:scale-105 transition-all duration-300 shadow-xl"
```
### Hero Gradient
```html
class="bg-gradient-to-br from-indigo-900 via-purple-800 to-pink-700"
```
### Glass Effect
```html
class="bg-white bg-opacity-10 backdrop-blur-sm border border-white border-opacity-30"