A free, open-source platform for managing sports teams. Simplify your season with tools for roster management, scheduling, and team communication.
✅ MVP Complete - Ready for production use with core team management features.
The MVP includes user authentication, team creation, roster management with email invitations, event scheduling, calendar views, and RSVP tracking. See implementation plan for detailed feature documentation.
- Framework: Next.js 15 with App Router and React 19
- Language: TypeScript (required for type safety)
- UI: MUI v7 with Emotion styling
- Database: PostgreSQL (Neon) via Prisma ORM
- Auth: Auth.js (NextAuth.js) v5 with credentials provider
- Email: Mailchimp Transactional Email (future: AWS SES migration)
- Deployment: Vercel with automatic migrations
- Package Manager: Bun (faster than npm/yarn)
- Node.js 22+ - Required for Next.js 15 and React 19
- Bun - Package manager (faster than npm/yarn)
- PostgreSQL Database - Neon recommended for serverless PostgreSQL
- Email Service - Mailchimp Transactional Email account
# 1. Clone the repository
git clone https://github.com/mbeacom/openleague.git
cd openleague
# 2. Install dependencies
bun install
# 3. Copy environment template
cp .env.example .env.local
# 4. Configure environment variables (see Environment Variables section below)
# Edit .env.local with your database and email service credentials
# 5. Validate environment configuration
bun run validate-env
# 6. Set up database
bun run db:migrate
# 7. Start development server
bun run dev
# 8. Open http://localhost:3000Create a .env.local file with the following required variables:
# Database (Neon PostgreSQL)
DATABASE_URL="postgresql://user:password@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require"
# Auth.js Configuration
NEXTAUTH_URL="http://localhost:3000" # Use your domain in production
NEXTAUTH_SECRET="" # Generate with: openssl rand -base64 32
# Email Service (Mailchimp Transactional)
MAILCHIMP_API_KEY="" # Get from Mailchimp Transactional dashboard
EMAIL_FROM="noreply@yourdomain.com" # Your sender email address
# Optional: Analytics (Umami - privacy-friendly)
NEXT_PUBLIC_UMAMI_WEBSITE_ID="" # Get from https://cloud.umami.is
# Optional: For future AWS migration
AWS_REGION="us-east-1"Required Environment Variables:
DATABASE_URL- PostgreSQL connection string with SSLNEXTAUTH_URL- Your application URL (localhost for dev, your domain for production)NEXTAUTH_SECRET- Random 32+ character secret for JWT signingMAILCHIMP_API_KEY- API key for sending emailsEMAIL_FROM- Verified sender email address
Optional Environment Variables:
NEXT_PUBLIC_UMAMI_WEBSITE_ID- Umami analytics website ID (leave empty to disable tracking)
# Development
bun run dev # Start development server with Turbopack
bun run build # Build for production
bun run start # Start production server
bun run lint # Run ESLint
bun run type-check # TypeScript type checking
# Database Management
bun run db:studio # Open Prisma Studio (visual database browser)
bun run db:push # Push schema to database (dev only)
bun run db:migrate # Create and run migrations (development)
bun run db:migrate:deploy # Deploy migrations (production)
bun run db:migrate:reset # Reset database and run all migrations
bun run db:generate # Generate Prisma Client
bun run db:seed # Run seed script (optional)
# Utilities
bun run validate-env # Validate environment variables- Make Schema Changes: Edit
prisma/schema.prisma - Create Migration:
bun run db:migrate(creates migration file and applies it) - Generate Client:
bun run db:generate(updates TypeScript types) - Test Changes:
bun run devand test your changes - Commit: Commit both schema and migration files
- User Authentication: Secure email/password signup and login with Auth.js
- Team Management: Create and manage teams with Admin/Member roles
- Roster Management: Add players with contact information and emergency contacts
- Email Invitations: Send team invitations with unique signup links
- Event Scheduling: Create games and practices with date, time, location, and opponent
- Responsive Calendar: Grid view on desktop, list view on mobile
- RSVP System: Members respond Going/Not Going/Maybe with instant updates
- Attendance Tracking: Admins view attendance summaries and member responses
- Email Notifications: Automatic emails for events, invitations, and RSVP reminders
- Mobile-First Design: Optimized for mobile with touch-friendly interface
- HTTPS Enforced: Secure headers and SSL/TLS encryption
- Input Validation: Zod schemas for all forms and API inputs
- SQL Injection Prevention: Parameterized queries via Prisma ORM
- Session Management: Secure JWT tokens with HTTP-only cookies
- Password Security: bcrypt hashing with cost factor 12
- Authorization: Role-based access control (Admin/Member permissions)
# 1. Make changes to prisma/schema.prisma
# 2. Create and apply migration
bun run db:migrate
# 3. Generate updated Prisma Client
bun run db:generate
# 4. Test your changes
bun run devMigrations are automatically applied during deployment via the postinstall script:
# This runs automatically on Vercel deployment
prisma generate && prisma migrate deploy# Development - creates migration files and applies them
bun run db:migrate
# Production - applies existing migrations only
bun run db:migrate:deploy
# Reset database (destructive - dev only)
bun run db:migrate:reset
# View database in browser
bun run db:studioWhy Neon? Serverless PostgreSQL with database branching, generous free tier, and optimized for Vercel deployments.
-
Create Account: Sign up at console.neon.tech
-
Create Database:
- Click "Create Project"
- Choose a name (e.g., "openleague-prod")
- Select region closest to your users
- Choose PostgreSQL version (latest recommended)
-
Get Connection String:
- Go to your project dashboard
- Click "Connection Details"
- Copy the connection string
- Important: Add
?sslmode=requireto the end
-
Set Environment Variable:
DATABASE_URL="postgresql://user:password@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require" -
Initialize Database:
bun run db:migrate # Creates tables and applies migrations
Database Branching (Optional):
- Create separate branches for development/staging
- Each branch gets its own connection string
- Perfect for testing schema changes safely
Future Migration Path: The application is designed to easily migrate to AWS RDS when you need more advanced features or want to consolidate AWS services.
Why Mailchimp Transactional? Reliable delivery, good free tier, and simple API for transactional emails.
-
Create Account:
- Sign up at mailchimp.com
- Navigate to Transactional Email (formerly Mandrill)
- Or directly at mandrillapp.com
-
Get API Key:
- Go to Settings → SMTP & API Info
- Create a new API key
- Copy the key (starts with
md-)
-
Verify Sender Domain (Recommended):
- Go to Settings → Sending Domains
- Add your domain (e.g.,
yourdomain.com) - Follow DNS verification steps
- This improves deliverability
-
Set Environment Variables:
MAILCHIMP_API_KEY="md-your-api-key-here" EMAIL_FROM="noreply@yourdomain.com" # Must be verified domain
-
Test Email Setup:
bun run validate-env # Validates API key format # Then test by creating a team and sending an invitation
Email Templates Included:
- Team invitations with signup links
- Event notifications (created/updated/cancelled)
- RSVP reminders (48 hours before events)
- Welcome emails for new users
Future Migration Path: The email service is abstracted and can easily migrate to AWS SES when you need higher volume or want to consolidate AWS services.
openleague/
├── app/ # Next.js App Router
│ ├── (auth)/ # Authentication routes (grouped)
│ │ ├── login/page.tsx # Login page
│ │ └── signup/page.tsx # Signup page
│ ├── (dashboard)/ # Protected dashboard routes
│ │ ├── layout.tsx # Dashboard layout with navigation
│ │ ├── page.tsx # Team dashboard
│ │ ├── roster/page.tsx # Roster management
│ │ ├── calendar/page.tsx # Calendar view
│ │ └── events/ # Event management
│ │ ├── [id]/page.tsx # Event details
│ │ └── new/page.tsx # Create event
│ ├── api/ # API routes
│ │ ├── auth/[...nextauth]/ # Auth.js endpoints
│ │ ├── invitations/[token]/ # Invitation acceptance
│ │ └── cron/ # Scheduled jobs (RSVP reminders)
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Landing page
│ └── globals.css # Global styles
│
├── components/ # React components
│ ├── ui/ # Base UI components
│ │ ├── Button.tsx # MUI Button wrapper
│ │ ├── Input.tsx # MUI TextField wrapper
│ │ ├── Card.tsx # MUI Card wrapper
│ │ └── Dialog.tsx # MUI Dialog wrapper
│ ├── features/ # Feature-specific components
│ │ ├── auth/ # Authentication components
│ │ ├── roster/ # Roster management
│ │ ├── calendar/ # Calendar and events
│ │ ├── events/ # Event forms and details
│ │ └── dashboard/ # Dashboard navigation
│ └── providers/ # Context providers
│ ├── SessionProvider.tsx # Auth session provider
│ └── ThemeProvider.tsx # MUI theme provider
│
├── lib/ # Utility functions and configurations
│ ├── actions/ # Next.js Server Actions
│ │ ├── auth.ts # Authentication actions
│ │ ├── team.ts # Team management
│ │ ├── roster.ts # Roster operations
│ │ ├── events.ts # Event CRUD
│ │ ├── rsvp.ts # RSVP operations
│ │ └── invitations.ts # Invitation system
│ ├── auth/ # Authentication configuration
│ │ ├── config.ts # Auth.js configuration
│ │ └── session.ts # Session helpers
│ ├── db/ # Database client
│ │ └── prisma.ts # Prisma client singleton
│ ├── email/ # Email service
│ │ ├── client.ts # Mailchimp client
│ │ └── templates.ts # Email templates
│ ├── utils/ # Utility functions
│ │ ├── validation.ts # Zod schemas
│ │ ├── date.ts # Date formatting
│ │ └── error-handling.ts # Error utilities
│ ├── config/ # Configuration
│ │ └── constants.ts # App constants
│ ├── env.ts # Environment validation
│ └── theme.ts # MUI theme configuration
│
├── prisma/ # Database schema and migrations
│ ├── schema.prisma # Database schema
│ ├── migrations/ # Migration history
│ │ └── [timestamp]_[name]/ # Individual migrations
│ └── seed.ts # Optional seed script
│
├── types/ # TypeScript type definitions
│ ├── auth.ts # Authentication types
│ ├── events.ts # Event types
│ ├── roster.ts # Roster types
│ └── invitations.ts # Invitation types
│
├── public/ # Static assets
│ └── images/ # Image assets
│
├── scripts/ # Utility scripts
│ └── validate-env.js # Environment validation script
│
├── .env.example # Environment variable template
├── .env.local # Local environment (not committed)
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── next.config.ts # Next.js configuration
├── vercel.json # Vercel deployment configuration
└── README.md # This file
- App Router: Uses Next.js 15 App Router for better performance and developer experience
- Server Actions: Primary method for mutations, reducing API route complexity
- Server Components: Default for data fetching, Client Components only when needed
- Prisma ORM: Type-safe database operations with automatic migrations
- MUI v7: Consistent, accessible UI components with custom theming
- Mobile-First: Responsive design optimized for mobile devices
Why Vercel? Optimized for Next.js with automatic builds, edge functions, and seamless integration.
# Ensure your code is committed and pushed to GitHub
git add .
git commit -m "feat: ready for deployment"
git push origin main# Install Vercel CLI
bun add -g vercel
# Deploy from your project directory
vercel
# Follow the prompts:
# - Link to existing project or create new
# - Set up environment variables
# - Deploy- Go to vercel.com and sign in
- Click "New Project"
- Import your GitHub repository
- Configure environment variables (see below)
- Click "Deploy"
In Vercel dashboard or CLI, set these environment variables:
# Database (Production)
DATABASE_URL="postgresql://user:password@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require"
# Auth.js (Production)
NEXTAUTH_URL="https://your-app.vercel.app" # Your actual domain
NEXTAUTH_SECRET="your-32-character-secret" # Same as development or generate new
# Email Service
MAILCHIMP_API_KEY="md-your-api-key"
EMAIL_FROM="noreply@yourdomain.com"
# Optional
AWS_REGION="us-east-1"Migrations run automatically on deployment via the postinstall script in package.json:
{
"scripts": {
"postinstall": "prisma generate && prisma migrate deploy"
}
}This ensures your production database is always up-to-date with your schema.
- In Vercel dashboard, go to your project
- Click "Domains" tab
- Add your custom domain
- Follow DNS configuration instructions
- Update
NEXTAUTH_URLenvironment variable to your custom domain
# Dockerfile (create this file)
FROM oven/bun:1-alpine
WORKDIR /app
# Copy package files and install dependencies to leverage Docker cache
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
# Copy source code
COPY . .
# Generate Prisma client
RUN bunx prisma generate
# Build application
RUN bun run build
EXPOSE 3000
# Start application
CMD ["bun", "run", "start"]# Build and run
docker build -t openleague .
docker run -p 3000:3000 --env-file .env.local openleague- Build the application:
bun run build - Set environment variables on your platform
- Run migrations:
bunx prisma migrate deploy - Start the server:
bun run start
- Environment variables configured
- Database connection tested
- Email service configured and tested
- Custom domain configured (if applicable)
- SSL certificate active
- Database migrations applied
- Application accessible and functional
Built-in Monitoring:
- Vercel Analytics (performance metrics)
- Vercel Logs (application logs)
- Neon Dashboard (database metrics)
- Mailchimp Reports (email delivery)
Recommended Additions:
- Error tracking (Sentry)
- Uptime monitoring (UptimeRobot)
- Performance monitoring (Vercel Speed Insights)
OpenLeague uses GitHub Actions for automated releases:
- Automatic Releases: Push to
maintriggers semantic versioning and GitHub releases - Version Management: Based on conventional commit messages
- Quality Checks: Automated type-checking, linting, and builds
- Changelog Generation: Automatic categorized changelog from commits
See .github/AUTOMATION.md for details.
# Commits determine version bump:
git commit -m "feat: new feature" # Minor bump (0.X.0)
git commit -m "fix: bug fix" # Patch bump (0.0.X)
git commit -m "feat!: breaking" # Major bump (X.0.0)
# Just merge to main - automation handles the rest!
git push origin main# Check your .env.local file exists and has all required variables
bun run validate-env
# Generate a new NEXTAUTH_SECRET
openssl rand -base64 32
# Ensure DATABASE_URL includes ?sslmode=require for Neon
DATABASE_URL="postgresql://user:pass@host/db?sslmode=require"# Test database connection
bunx prisma db pull
# Check if DATABASE_URL is correct
echo $DATABASE_URL
# Ensure Neon database is running (check Neon dashboard)# Reset database (development only - destructive!)
bun run db:migrate:reset
# Or create a new migration
bun run db:migrate
# Check migration status
bunx prisma migrate status# Verify Mailchimp API key is correct
# Check Mailchimp dashboard for API key status
# Ensure EMAIL_FROM domain is verified in Mailchimp
# Test with a simple email first# Run type checking locally
bun run type-check
# Regenerate Prisma client
bun run db:generate
# Clear Next.js cache
rm -rf .next
bun run build# Check Vercel logs for specific error
# Ensure all environment variables are set in Vercel dashboard
# Verify DATABASE_URL is accessible from Vercel
# Test build locally
bun run build
bun run startSlow page loads:
- Check database query performance in Neon dashboard
- Verify images are optimized
- Check Vercel Analytics for bottlenecks
Email delivery issues:
- Check Mailchimp delivery reports
- Verify sender domain reputation
- Ensure EMAIL_FROM domain is properly configured
- Check the logs: Vercel dashboard → Functions → View logs
- Database issues: Neon dashboard → Monitoring
- Email issues: Mailchimp dashboard → Reports
- GitHub Issues: Create an issue with:
- Error message
- Steps to reproduce
- Environment details (Node version, OS, etc.)
When you need more advanced database features or want to consolidate AWS services:
- Export data from Neon using
pg_dump - Create AWS RDS PostgreSQL instance
- Import data using
pg_restore - Update DATABASE_URL environment variable
- Test thoroughly before switching production traffic
The application code requires no changes - only the connection string changes.
When you need higher email volume or AWS consolidation:
- Set up AWS SES and verify domains
- Update email client in
lib/email/client.ts - Replace MAILCHIMP_API_KEY with AWS credentials
- Test email templates with new service
- Monitor delivery rates during transition
The email templates and logic remain the same - only the sending mechanism changes.
Contributions are welcome! Please see CONTRIBUTING.md for:
- Development setup
- Coding conventions
- Commit message format
- PR process
- Release workflow
This project follows Conventional Commits and Semantic Versioning.
OpenLeague is licensed under the Business Source License 1.1 - see LICENSE for full details.
✅ You CAN (No License Needed):
- Use OpenLeague for your league/organization's internal management
- Self-host on your own infrastructure for your own use
- Fork, modify, and customize for your organization
- Share improvements back to the community
- Study the code and learn from it
- Offer OpenLeague as a SaaS to multiple third-party organizations
- Sell OpenLeague-based hosting services commercially
- Build a competing business using OpenLeague code
- Provide OpenLeague as a managed service for profit
🔄 Future License Change:
- On October 4, 2029, this license automatically converts to Apache 2.0
- After that date, all usage restrictions are removed
- This ensures long-term openness while protecting early development
Coming soon - we'll offer a professionally hosted version at openl.app with:
- Zero setup or maintenance
- Automatic updates and backups
- Professional support
- Free tier for small teams
📚 Developer Documentation: openleague.dev
Self-hosting is fully supported and encouraged for your own organization:
# Clone and deploy
git clone https://github.com/mbeacom/openleague.git
cd openleague
bun install
# Configure .env.local with your services
bun run build
bun run startRequirements for self-hosting:
- PostgreSQL database (Neon, Supabase, or self-hosted)
- SMTP service for emails (Mailchimp Transactional, AWS SES, etc.)
- Node.js 22+ hosting environment (Vercel, AWS, etc.)
See SETUP.md for detailed deployment instructions.
Self-hosting is perfect for:
- Tech-savvy leagues who want full control
- Organizations with existing infrastructure
- Teams requiring custom modifications
- Development and testing environments
Interested in offering OpenLeague as a commercial service to multiple organizations?
We offer commercial licenses that allow you to:
- Build and sell OpenLeague-based SaaS products
- Offer managed hosting services commercially
- White-label OpenLeague for your customers
- Receive priority support and partnership opportunities
Contact: mark@openl.app for commercial licensing inquiries.
- Feature Specifications - Detailed requirements, design, and implementation plan
- Setup Progress - Development setup and progress tracking
- Contributing Guide - How to contribute to the project
- Release Process - Release workflow and versioning
- CI/CD Automation - GitHub Actions and automation
- Security Implementation - Security measures and best practices
The application uses Next.js Server Actions for most operations. Key actions include:
- Authentication:
lib/actions/auth.ts- Signup, login, session management - Team Management:
lib/actions/team.ts- Create and manage teams - Roster Operations:
lib/actions/roster.ts- Add, update, delete players - Event Management:
lib/actions/events.ts- CRUD operations for events - RSVP System:
lib/actions/rsvp.ts- Update attendance responses - Invitations:
lib/actions/invitations.ts- Send and manage invitations
The database uses PostgreSQL with Prisma ORM. Key models:
- User: Authentication and user profiles
- Team: Team information and settings
- TeamMember: User-team relationships with roles (Admin/Member)
- Player: Roster entries with contact information
- Event: Games and practices with scheduling details
- RSVP: Attendance responses for events
- Invitation: Email invitations with tokens and expiration
See prisma/schema.prisma for complete schema definition.
- Next.js 15 Documentation - App Router, Server Actions, React 19
- MUI v7 Documentation - Components, theming, customization
- Prisma Documentation - ORM, migrations, client usage
- Auth.js Documentation - Authentication configuration and providers
- Neon Documentation - Serverless PostgreSQL setup and management
- Mailchimp Transactional - Email API and templates
- Vercel Documentation - Deployment, environment variables, functions
- Conventional Commits - Commit message format
- Semantic Versioning - Version numbering scheme
