A little SvelteKit 5 web app to help organise social 5-a-side [football] leagues.
Features include:
- League Management
- Subdomain-based league registration.
- Access-controlled league isolation.
- Mailgun integration for sending email (Access code recovery).
- Player Management
- View and manage player availability.
- Waiting list after a limit is reached.
- Moving players between lists.
- Player renaming capability.
- Quick-access player information modals.
- Team Management
- Generate random teams, either completely random or using player ELO as seeds.
- AI-generated team logos using OpenAI's Images API (Requires an OpenAI API Key, disabled by default).
- Provisional rating system ensures balanced teams even with new players.
- Multi-iteration team generation algorithm that maximises team variance and balance using attack/defense ratings.
- Visual indicators for provisional vs. established players.
- Team attack/defense rating displays.
- Replay team draws for dramatic effect.
- Players can be moved from a team to the waiting list (and vice versa), removed, renamed, or marked as a no-show.
- Quick-access team information modals.
- Discipline
- Automatic suspension of players after no-shows.
- Game Scheduling and Score Tracking
- Generate a round-robin home-away match schedule and track results.
- Match Centre page for live stats tracking (goals, attack/defence contributions, and saves).
- Individual goal-scorer tracking with interactive popover UI (league + knockout matches).
- Standings table based on match results.
- Knockout tournament generation with teams seeded by standings.
- Stars of the Day awards players with the most contributions across a session's league and knockout cup phases.
- Player Rankings
- Cumulative player rankings based on team performances and consistency.
- Player ELO with provisional ratings system for new players (<5 sessions).
- Attack/defense ratings displayed on player profiles and teams.
- Individual attack/defence ratings derived from team goals for/against across sessions.
- Performance tracking: league positions, cup progress, win streaks, and achievements.
- Player profile modals - ranking details, history, profile photos (Admin-approved), and performance stats accessible throughout the app.
- Champions hall: tracks league and cup winners (yearly and all-time views).
- Golden boot: tracks league and cup goal scorers (yearly and all-time views).
- Annually reset rankings to keep competition fresh and motivating.
- Year Recap
- An annual highlight reel of the league
- Individual Categories
- Team Categories
- Fun/Stats Categories
- Background Music
Data is stored as JSON files in the data directory. For dev, make sure it exists in the root of the project.
For development (needs Node.js):
npm ci- Ensures dependencies are installed.npm run dev- Starts the dev server. The app is available at http://localhost:5173.npm run dev -- --host- Starts the dev server and allows access from other devices on your network (useful for mobile testing, or if you're using WSL).npm test- Runs all tests (backend + frontend).npm run test:backend- Runs backend tests only.npm run test:frontend- Runs frontend tests only.npm run check- Type checking.npm run lint- Code linting.npm run format- Code formatting.
Since leagues are registered/accessed on subdomains, it's useful to set up your hosts file to test locally:
# Add to /etc/hosts (Linux/Mac) or C:\Windows\System32\drivers\etc\hosts (Windows)
127.0.0.1 leagr.local
127.0.0.1 league1.leagr.local
127.0.0.1 league2.leagr.local
# If you're using WSL, you need the WSL Network IP
172.21.184.1 leagr.local
172.21.184.1 league1.leagr.localThen you can access the app at http://leagr.local:5173, http://league1.leagr.local:5173, etc.
The application includes rudimentary security features to prevent abuse:
- ALLOWED_ORIGIN: Comma-separated list of allowed origins for cross-origin requests
- Only specified origins can access the API endpoints
- Example:
https://your-production-url.com,http://localhost:3000
- API_KEY: Required for all API endpoint access
- Must be provided via
X-API-KEYheader - Example:
a1b2c3d4-e5f6-7890-abcd-ef1234567890
- Each league has a unique access code
- To access the league, the access code must be provided in a "code" query parameter, or the user is redirected to a login page
- Access code must be included in an Authorization header of API requests
- Access codes can be reset if an organiser/owner email is set up for the league
- Built-in rate limiting: 60 requests per minute per IP address
- Automatically blocks excessive requests with HTTP 429 status
The application includes comprehensive automated testing:
- 1000+ tests covering backend logic and frontend components
- Backend tests use Node environment (unit and integration tests)
- Frontend tests use jsdom environment (component and store tests)
- Automated test execution runs before every deployment
- Tests must pass before deployment succeeds
For production (needs Docker):
- Build a docker image with a production build of the app
- Note: Automated tests run during the build process and must pass
docker build -t leagr:latest- Run the docker container (The app will be available at http://localhost:3000)
docker run -d \
--name leagr \
--restart unless-stopped \
-p 3000:3000 \
-v /path/to/data/on/host:/app/data \
-v /path/to/logs/on/host:/app/logs \
-e ALLOWED_ORIGIN="https://your-production-url.com,http://localhost:3000" \
-e API_KEY="a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-e APP_URL="https://your-production-url.com" \
-e MAILGUN_SENDING_KEY="your-mailgun-sending-key" \
-e MAILGUN_DOMAIN="your-mailgun-domain.com" \
-e BODY_SIZE_LIMIT=6291456 \
-e LOG_LEVEL="info" \
-e OPENAI_API_KEY="sk-..." \
leagr:latestExpose the app to the internet by configuring your web server or reverse proxy (e.g. Nginx, Apache) to forward requests to port 3000.
Environment Variables:
ALLOWED_ORIGIN: Comma-separated allowed origins (required for CORS protection)API_KEY: Secure API key for endpoint access (required for API authentication)APP_URL: The base URL of your application (used for generating links in emails)MAILGUN_SENDING_KEY: Mailgun API key for sending emailsMAILGUN_DOMAIN: Mailgun domain for sending emailsBODY_SIZE_LIMIT: Maximum request body size in bytes (default: 524288 / 512KB). Set to 6291456 (6MB) for avatar uploadsLOGS_DIR: Directory path for application logs (default: /app/logs). Mount as volume for persistent logsLOG_LEVEL: The level of logging messages to keep in the application log. Possible values: debug, info, warn, or error (default: info)OPENAI_API_KEY: An active OpenAI API Key for team logo generation
Notes:
- Replace
/path/to/data/on/hostwith the actual path to the data directory on your host machine - Replace
/path/to/logs/on/hostwith the actual path to the logs directory on your host machine - Replace
a1b2c3d4-e5f6-7890-abcd-ef1234567890with a secure, randomly generated API key - Replace the allowed origins, app URL with your actual domain(s)
- Replace Mailgun credentials with your actual Mailgun account details
- The
BODY_SIZE_LIMITis set to 6MB (6291456 bytes) to support avatar uploads up to 5MB
This project is licensed under the MIT License - see the LICENSE file for details.