Back to projects
UTM Billiards Club Platform
Sole-built the official club platform from scratch, replacing a static Linktree with a production Next.js app serving 320+ members, complete with live Elo rankings, computer-vision match-sheet parsing, and a 2v2 bracket generator.
The Problem
The UTM Billiards Club had no digital infrastructure beyond a Linktree. Execs spent 1-2 hours manually transcribing paper match sheets into ranking spreadsheets, tournament brackets were managed ad hoc, and there was no central place for members to check standings, sign up for events, or get club information.
My Role
Founding sole developer and club tech lead, owning product, architecture, roadmap, and weekly delivery end-to-end from May 2025 to present.
The Approach
- Built a Next.js 15 / React / TypeScript platform across 12 routes (about 6,500 lines of hand-written app code, 80 commits), with a Google Sheets CSV ETL pipeline that parses, filters, privacy-masks member data, and caches results in localStorage with a 10-minute TTL so execs can update rankings without touching code.
- Engineered a computer-vision image-to-data pipeline that ingests photos of paper match sheets, extracts player names, student IDs, and the declared winner, validates the winner against the two players listed, and uses student ID lookup to reduce OCR misreads, then writes structured records into the ranking workflow.
- Built tournament tooling including a 2v2 bracket generator with team/player modes, randomization, BYE handling, and save/load state, plus an embedded AI chatbot and a scalable JSON-driven event architecture with date-based rendering that auto-splits upcoming and past events.
- Designed a 5-tier live Elo ranking system on top of the ETL pipeline, giving members a real-time leaderboard that updates each term without any manual developer intervention.
Key Decisions
- Chose Google Sheets as the data source rather than a custom database because club execs already managed rankings there, so a CSV ETL pull with localStorage TTL caching let the non-technical exec team remain the source of truth without a backend migration or login system.
- Built the computer-vision pipeline with explicit validation (winner must be one of the two named players, student ID cross-lookup to correct OCR drift) rather than trusting raw model output directly, because a ranking system is only useful if members trust its accuracy.
- Kept the entire stack on a single Next.js deployment with no separate backend service, which trades some architectural separation for zero DevOps overhead for a club project with no budget and a single developer on call.
Impact & Results
- Computer-vision match-sheet pipeline cut a 1-2 hour manual transcription task to under 3 minutes with zero errors in the scoped workflow.
- Platform serves 320+ members (club users) across 12 routes, handling live leaderboard updates and tournament sign-ups each term.
- Replaced the club's static Linktree with a production platform the club runs on week-to-week, with no developer involvement needed for routine ranking updates.
The Stack
Next.js 15TypeScriptReactTailwind v4Google Sheets APIReact Three Fiberp5.jsVercel
What I Learned
- Owning a product with real users sharpens prioritisation instincts in a way side projects don't: when 320 people check your leaderboard each week, a ranking bug is an urgent fix, not a backlog item, and that accountability changes how carefully you design validation logic.
- I learned that raw git contribution numbers (line counts, file counts) can be misleading and that the defensible, trustworthy number to present is the hand-written app code, about 6,500 lines of TypeScript/React, not raw git stats that include generated files and churn.
- If I were starting over I would introduce a lightweight Supabase backend earlier to decouple the data pipeline from the client-side ETL, which would make the privacy-masking layer server-enforced rather than client-enforced and open the door to richer analytics without changing the exec workflow.