Skip to content
4 clubs
Committed to the Aug 2026 pilot
10+ sports
Built for most one-on-one and doubles club sports
5 formats
Single-elim, double-elim, round robin, Swiss, group knockout
3 channels
Email, push notifications, and Discord webhooks

The problem

School chess and badminton clubs run ladders and tournaments on spreadsheets and group chats. Ratings drift, match history gets lost, and there's no fair, transparent way to seed a bracket. ClubLadders replaces that with a real product: clubs create invite codes, add members or guest players, record singles and doubles matches, maintain Elo history, run tournaments, and preserve historical results even when a player later claims an account.

What I built

  • Production Next.js + FastAPI platform with Google OAuth, signed HTTP-only session cookies, invite-code onboarding, and public/private club controls.
  • Competition workflows for singles, doubles, tournaments, club-vs-club challenges, leaderboards, seasons, scheduled sessions, announcements, and notifications.
  • Responsive interaction system with immediate action feedback, touch-friendly controls, focused modal flows, motion restraint, and reduced-motion support so dense club operations remain understandable across devices.
  • Production operations including analytics events, admin moderation, account export/deletion, maintenance mode, rate-limit abuse handling, and cached read-only PWA support.

Technical highlights

Guest-player claim flow

Players can be added to matches before they ever register. I modeled this with an XOR CHECKconstraint and an atomic claim transaction, so when an unregistered player later signs up, their Elo rating and complete match history transfer over intact — with no double-counting or orphaned records.

Deterministic Elo replay

Every player starts at 1200 Elo, with provisional K-factors for early games, lower stable K-factors after that, draw support, margin multipliers for score-based sports, and partner-adjusted doubles Elo. When a match is edited, deleted, or a rating anchor changes, the system replays match and tournament history chronologically so corrections do not create rating drift.

Interaction design across devices

I designed the interface around direct feedback and predictable spatial behavior: controls stay close to what they affect, destructive actions use focused confirmation flows, and mobile layouts preserve the same task hierarchy as desktop. Transitions use short, restrained movement, while reduced-motion preferences remove nonessential motion without removing useful status feedback.

Win-probability model (ML)

I trained a logistic-regression win-probability model on exported pre-match features using scikit-learn, and evaluated it with ROC-AUC and log loss. It surfaces a predicted probability for upcoming matchups — my CS & AI coursework applied to a real product.

Tested & CI-backed

A pytest integration suite runs against PostgreSQL 16 in GitHub Actions CI with Alembic migrations, covering auth, clubs, matches, Elo, tournaments, account deletion, bans, admin roles, push, Discord, analytics, sessions, seasons, exports, and security workflows.

Analytics and validation

Product validation

I used pilot commitments as the primary validation signal: four clubs agreed to test the product before the August 2026 rollout. That shaped the MVP around fast onboarding, transparent leaderboards, guest-player support, and match logging that works for both casual club play and organized tournaments.

Observability and analytics

The frontend uses Vercel Analytics and Speed Insights, while the backend records custom analytics events for product and admin workflows. That gives me enough visibility to debug onboarding, match recording, tournament usage, notification behavior, and abuse-control flows without relying only on server logs.

Model and reliability checks

For the win-probability model, I evaluate exported matchup features with ROC-AUC and log loss instead of relying on accuracy alone. For platform reliability, the backend has health checks, scheduled maintenance jobs, DB connection retries, SQLAlchemy pool pre-ping/recycle, Render keepalive pings, and regression tests for correctness-sensitive flows such as archived-member match recording.

Stack

Next.jsReactTypeScriptInteraction DesignAccessible MotionFastAPIPythonPostgreSQLRedisSQLAlchemyAlembicscikit-learnGoogle OAuthVercelRenderNeonPush NotificationsDiscord WebhooksGitHub Actions

See it in action

ClubLadders is live and piloting with four clubs this August.

Visit clubladders.com