13 KiB
EuchreCamp
A comprehensive tournament management and partnership analytics system for the card game Euchre.
Overview
EuchreCamp is a full-stack Ruby web application built with Hanami 2.1 that provides:
- Tournament Management: Create and manage round-robin, single elimination, double elimination, and Swiss-style tournaments
- Partnership Analytics: Track partnership performance, win rates, and Elo changes between players
- Player Profiles: Display individual player statistics and partnership breakdowns
- Admin Dashboard: Centralized management interface for tournaments, players, and matches
- Authentication & Authorization: Role-based access control with player, tournament_admin, and club_admin roles
Quick Start
Prerequisites
- Ruby 3.3.3 (managed by mise or rbenv)
- Node.js 22+ (for asset compilation)
- SQLite3
- Bundler
Installation
- Clone the repository:
git clone <repository-url>
cd euchre_camp
- Install dependencies:
bundle install
npm install
- Set up the database:
bundle exec rake db:migrate
- Compile assets:
./node_modules/.bin/esbuild app/assets/css/app.css --bundle --outfile=public/assets/app-GVDAEYEC.css
- Start the server:
bundle exec puma -p 3000 -e development
Accessing the Application
- Main Page: http://localhost:3000
- Admin Dashboard: http://localhost:3000/admin
- Rankings: http://localhost:3000/rankings
- Login: http://localhost:3000/login
Development
Project Structure
euchre_camp/
├── app/
│ ├── actions/ # Hanami actions (controllers)
│ ├── assets/ # CSS, JavaScript, images
│ ├── repositories/ # ROM repositories for data access
│ ├── services/ # Business logic (Elo calculator, partnership tracker)
│ ├── templates/ # ERB view templates
│ ├── views/ # Hanami view objects
│ └── action.rb # Base action class with auth helpers
├── config/
│ ├── routes.rb # Application routes
│ ├── app.rb # Hanami app configuration
│ └── assets.js # Asset compilation configuration
├── db/
│ ├── migrate/ # Database migrations
│ └── euchre_camp.db # SQLite database
├── lib/
│ └── euchre_camp/ # Domain models and entities
├── spec/
│ └── acceptance/ # RSpec acceptance tests
└── public/
└── assets/ # Compiled assets
Running the Application
Development mode (with auto-reload):
bundle exec puma -p 3000 -e development
Production mode:
bundle exec puma -p 3000 -e production
Database Management
Run migrations:
bundle exec rake db:migrate
Rollback last migration:
bundle exec rake db:migrate[<version>]
Reset database:
bundle exec rake db:reset
Testing
Run all acceptance tests:
bundle exec rspec spec/acceptance/
Run specific test:
bundle exec rspec spec/acceptance/tournament_partnership_spec.rb:280
Run with documentation:
bundle exec rspec spec/acceptance/ --format documentation
Run Playwright mobile responsiveness tests:
# Start the server
bundle exec hanami server --port 2300 &
# Run Playwright tests
bundle exec rspec spec/playwright/mobile_responsiveness_spec.rb
Test with Playwright MCP (browser automation):
- Start the Hanami server:
bundle exec hanami server --port 2300 - Use opencode with Playwright MCP tools to:
- Navigate to pages
- Take screenshots
- Test responsive layouts
- Verify mobile UI elements
Assets
Compile CSS for development:
./node_modules/.bin/esbuild app/assets/css/app.css --bundle --outfile=public/assets/app-GVDAEYEC.css
Watch for changes (requires separate process):
./node_modules/.bin/esbuild app/assets/css/app.css --bundle --outfile=public/assets/app-GVDAEYEC.css --watch
Features
Tournament Management
Creating a Tournament
- Navigate to Admin Dashboard (
/admin) - Click "Create Tournament"
- Enter tournament details:
- Name
- Format (round-robin, single elimination, double elimination, Swiss)
- Number of teams/players
- Register participants
- Generate schedule
- Record match results
Tournament Formats
- Round-Robin: Each team plays every other team once
- Single Elimination: Lose once and you're out
- Double Elimination: Must lose twice to be eliminated
- Swiss: Pairings based on win-loss records
Partnership Analytics
Tracking Partnerships
The system automatically tracks:
- Games played together
- Win/loss records
- Elo changes per partnership
- Partnership win rates
Viewing Partnership Data
- Visit any player's profile page (
/players/:id/profile) - Scroll to "Partnership Performance" section
- View statistics for each partner
Player Profiles
Each player profile displays:
- Current Elo rating
- Total games played
- Win rate
- Partnership statistics
- Recent games timeline
Admin Dashboard
The admin dashboard provides:
- Quick statistics (total players, active tournaments, recent matches)
- Quick action buttons for common tasks
- Recent matches table
- Links to all admin sections
Authentication & Authorization
User Roles
| Role | Permissions |
|---|---|
| Player | Edit own profile, record own matches within 5 minutes |
| Tournament Admin | Create/manage tournaments, edit matches in their tournaments (no time limit) |
| Club Admin | Full access to edit/delete any record, manage all players and tournaments |
Login/Logout
Login:
- Navigate to
/login - Enter email and password
- Click "Login"
Logout:
- Click "Logout" in navigation bar
Admin User Creation
To create an admin user, use the provided script:
ruby scripts/create_admin.rb <email> <password>
Example:
ruby scripts/create_admin.rb david@dhg.lol admin
This will:
- Create a player profile
- Create a user account with
club_adminrole - Mark the account as confirmed
Manual SQL Alternative:
If you prefer to create users manually via SQL:
- Access the database:
sqlite3 db/euchre_camp.db - Generate a BCrypt password hash:
ruby -e "require 'bcrypt'; puts BCrypt::Password.create('your_password')" - Insert a user record:
INSERT INTO players (name, rating) VALUES ('PlayerName', 1000); INSERT INTO users (player_id, email, password_digest, role, confirmed, created_at, updated_at) VALUES (1, 'user@example.com', '$2b$12$...', 'club_admin', 1, datetime('now'), datetime('now'));
API Reference
Routes
Public Routes
GET /- Redirects to rankingsGET /rankings- Player rankingsGET /players/:id- Player profileGET /players/:id/profile- Player profile with partnershipsGET /players/:id/schedule- Player tournament schedule
Authentication Routes
GET /login- Login formPOST /auth/login- Process loginGET /logout- Logout and clear session
Admin Routes (Require Authentication)
GET /admin- Admin dashboardGET /admin/players- List all playersGET /admin/players/new- Add new player formPOST /admin/players- Create new playerGET /admin/players/:id/edit- Edit player formPATCH /admin/players/:id- Update playerDELETE /admin/players/:id- Delete playerGET /admin/matches- List all matchesGET /admin/matches/new- Record match formPOST /admin/matches- Create matchGET /admin/matches/:id/edit- Edit match formPATCH /admin/matches/:id- Update matchGET /admin/matches/upload- CSV upload formPOST /admin/matches/process_upload- Process CSV uploadGET /admin/tournaments- List all tournamentsGET /admin/tournaments/new- Create tournament formPOST /admin/tournaments- Create tournamentGET /admin/tournaments/:id- Tournament detailsGET /admin/tournaments/:id/edit- Edit tournament formPATCH /admin/tournaments/:id- Update tournamentDELETE /admin/tournaments/:id- Delete tournamentPOST /admin/tournaments/:id/participants- Add participantDELETE /admin/tournaments/:id/participants/:player_id- Remove participantPOST /admin/tournaments/:id/teams- Create teamGET /admin/tournaments/:id/teams/:team_id/edit- Edit team formPATCH /admin/tournaments/:id/teams/:team_id- Update teamDELETE /admin/tournaments/:id/teams/:team_id- Delete teamPOST /admin/tournaments/:id/schedule- Generate scheduleGET /admin/tournaments/:id/rounds/:round_id- View round matchupsGET /admin/tournaments/:id/results- Tournament resultsPOST /admin/tournaments/:id/results- Save resultsPOST /admin/tournaments/:id/complete- Complete tournament
Database Schema
Tables
- players: Player information and ratings
- users: Authentication and authorization
- events: Tournaments and events
- event_participants: Player participation in tournaments
- teams: Teams in tournaments
- tournament_rounds: Tournament rounds
- bracket_matchups: Matchups per round
- matches: Individual match results
- elo_snapshots: Elo rating history
- partnership_games: Partnership occurrence tracking
- partnership_stats: Aggregated partnership statistics
Common Tasks
Adding a New Player
- Navigate to Admin Dashboard
- Click "Add Player"
- Enter name and initial rating (default 1000)
- Click "Create Player"
Recording a Match
- Navigate to Admin Dashboard
- Click "Record Match Result"
- Select players for Team 1 and Team 2
- Enter scores
- Click "Create Match"
Creating a Tournament
- Navigate to Admin Dashboard
- Click "Create Tournament"
- Enter tournament details
- Register participants
- Generate schedule
- Start recording results
Editing a Match
Within 5 minutes (any user):
- Navigate to
/admin/matches - Click "Edit" next to the match
- Update scores
- Click "Update Match"
Anytime (tournament admin or club admin):
- Same process as above, no time restriction
Troubleshooting
Common Issues
Server won't start:
- Check if port 3000 is already in use:
lsof -i :3000 - Kill existing process:
kill -9 <PID> - Try a different port:
bundle exec puma -p 3001
CSS not loading:
- Recompile assets:
./node_modules/.bin/esbuild app/assets/css/app.css --bundle --outfile=public/assets/app-GVDAEYEC.css - Clear browser cache
Database errors:
- Run migrations:
bundle exec rake db:migrate - Reset database:
bundle exec rake db:reset
Authorization errors:
- Ensure you're logged in
- Check user role in database
Debugging
Check server logs:
tail -f /tmp/puma.log
Check database:
sqlite3 db/euchre_camp.db
sqlite> .tables
sqlite> SELECT * FROM users;
Development Workflow
Making Changes
- Create a feature branch:
git checkout -b feature/your-feature - Make changes to code
- Run tests:
bundle exec rspec spec/acceptance/ - Commit with conventional commit message
- Push to remote:
git push origin feature/your-feature - Create pull request
Commit Message Format
<type>: <description>
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changesrefactor: Code refactoringtest: Test changeschore: Build/dependency changes
Code Style
- Follow existing code patterns in the project
- Use ROM (Ruby Object Mapper) for database access
- Keep business logic in services
- Use dependency injection in actions
- Write acceptance tests for new features
Deployment
Production Environment
- Set production environment variables:
export HANAMI_ENV=production
export DATABASE_URL=sqlite:///path/to/prod.db
export SESSION_SECRET=<secure-random-string>
- Compile assets for production:
./node_modules/.bin/esbuild app/assets/css/app.css --bundle --outfile=public/assets/app-GVDAEYEC.css
- Run migrations:
bundle exec rake db:migrate
- Start server:
bundle exec puma -p 3000 -e production
Using a Process Manager
Using systemd:
[Unit]
Description=EuchreCamp
After=network.target
[Service]
Type=simple
User=deploy
WorkingDirectory=/var/www/euchre_camp
Environment=HANAMI_ENV=production
ExecStart=/usr/local/bin/bundle exec puma -C config/puma.rb
Restart=always
[Install]
WantedBy=multi-user.target
Using PM2 (Node.js):
pm2 start bundle exec -- puma -C config/puma.rb
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests to ensure they pass
- Submit a pull request
License
MIT License - see LICENSE file for details
Credits
Built with:
- Hanami 2.1
- ROM (Ruby Object Mapper)
- SQLite3
- RSpec
- Puma