Somebody always sat out twice. Somebody always got the same partner.
Running a social round robin meant one person juggling names on a whiteboard, guessing who should play next and tallying scores by hand. Pairings drifted, sit-outs weren't fair, and nobody trusted the standings at the end of the night.
- ×Rotations planned on a whiteboard
- ×Same partners, same opponents
- ×Scores tallied by hand
- ×Results lost when the session ended
- →Fair rotations generated in a tap
- →New partners before any repeats
- →Scores entered from any phone
- →Results emailed and saved to profiles
Six versions in two years
Every version was used at real sessions, and each one fixed what players complained about in the last. The algorithm survived every rewrite. Almost nothing else did.
- Oct 2024iOS · SwiftPickleball SchedulerFirst attempt: an iPhone app to plan one group's rotation.
- Oct 2024iOS · SwiftUITwo SwiftUI rewritesRebuilt twice the same month to get the pairing logic right.
- Dec 2024HTML · JavaScriptWeb versionMoved to the browser so anyone in the group could open it.
- 2025Python · FlaskPB SchedulerThe first server version, run at sessions.
- Oct 2025Flask · PostgreSQLShuttleSchedulerOpened up to badminton, with saved players and finals.
- Oct 2025 to nowFlask · PostgreSQL · RailwaycourtScoreRebuilt and rebranded: accounts, guests, three modes, live scores.
What it does
Three tournament modes exist because three different organizers asked for three different things, not because a roadmap said so.
Run the event
- →Rotating, fixed-team and manual modes
- →Groups, playoff brackets and best-of formats
- →Co-admins and an organizer-only score lock
- →No account needed to start as a guest
Play the event
- →Scores entered from any phone
- →Live standings and finals
- →Share link for spectators
- →Installable app with push notifications
After the event
- →Results emailed to every player
- →Global leaderboard and player profiles
- →Tournament history and PDF export
- →Super-admin portal for oversight
Fair rotations for any number of players.
The scheduler is the piece that started it all. For every game it decides who plays, who partners whom and who they face, so that over a session everyone gets a fair share of games and new partners before anyone repeats.
Players who sat out the last game get priority for the next one.
A pair can only team up again once both have partnered everyone else.
Teams that already met are avoided while new match-ups exist.
Every score updates standings on every phone in the room.
Engineering decisions
Pure algorithm
The scheduler is plain functions with no database calls, so it's tested on its own.
Guests first
Anyone can run a full event without signing up, then claim it later.
Locked results
Organizers can lock scores so a finished game can't be quietly edited.
Self-cleaning
Unclaimed guest events expire on a schedule, handled by a cron job.
Email that lands
Results go out through Mailgun with a fallback provider.
Feels native
A service worker and push notifications let it install and behave like an app.



It started with one group's sessions and now runs full tournaments.
courtScore has scored 198 games for 63 players across more than 30 tournaments. I still run it, and I keep shipping what players and organizers ask for.
