← All roasts
DS-003·Product · 2026·1kg

Grand Slam

The registration platform behind Taekwondo Grand Slam. A club keeps one roster of players and coaches, then enters it into any number of competitions — each entry locks in belt, weight, and events the moment it's sent, so the roster stays yours to edit while the entry stays fixed.

Role
Solo · design + build
Year
2026
Category
Product
Weight
1kg
Price
Reserve

Roast
5/5
Notes
Roster-first · Bilingual · Built for the rush
Stack
React 19 · Hono · Cloudflare Workers · D1 · Drizzle

Pulled on 2026 · Best by: always
Visit the live site ↗

The origin

Before this, every tournament started from a blank page — coaches retyping their whole roster, athlete by athlete, each time they entered an event. I wanted the opposite. A club keeps one living roster of its players and coaches, and enters that same roster into as many competitions as it likes. Change a phone number or a belt once and it updates everywhere. But the moment you submit an entry, that entry locks to exactly what you sent — belt, weight, and events fixed in place — so the roster stays yours to keep tidy while each registration remains a faithful record of what was actually entered.

The captain app — one roster of players and coaches, reused across events.

The pull

Registration is where it gets real. A captain opens a competition and every division is a filter away — no cross-referencing a PDF, no guessing which bracket an athlete belongs in. The hard part, invisible when it works, is that the app never decides a division by reading a label: it matches each athlete on gender, age, belt, and weight, and the weight bands are drawn so no two brackets overlap and everyone lands in exactly one. Drafts save as you go, every screen is bilingual with Traditional Chinese first, and organizers get their own side to run the event.

Registration step one — five event types, 567 divisions, filtered by gender, age, and belt.

Step two is where the matching engine shows its hand. The roster becomes a grid — every athlete crossed with every event — and each cell already knows the answer before anyone ticks it: the exact bracket that athlete would land in, or the precise reason they can't enter. Where a bracket comes in open and elite twins, the choice sits right in the cell. Team events start from an anchor: pick the team's lead, the app resolves the division, then only offers teammates who legally fit it — a mixed pair can only ever be one boy and one girl.

The registration roster grid: an expanded athlete row shows live-matched divisions per event, with open/elite tier pills
Step two — every cell resolves an athlete's division before it's ticked; twin brackets offer the open/elite choice inline.
The team builder: an anchor athlete is picked, the division auto-resolves, and only legally matching teammates are listed
Team events — pick an anchor, the division resolves itself, and only teammates who fit it are offered.

The organizer console had to survive a 567-division codebook. Divisions are authored in a real spreadsheet — typed or pasted straight from Excel, cloned from last year in one click — and a validator hunts down any two brackets a single athlete could match at once. If the codebook shifts mid-season, one re-match button re-runs the engine over every confirmed entry. On race week the whole event leaves as four downloads: player, coach, and draw-sheet spreadsheets, plus a zip that streams every ID photo out of storage, each file named to match the sheets.

The admin division editor: a spreadsheet grid of sparring divisions with event tabs, clone-from-tournament and validate buttons
The organizer console — divisions authored like a spreadsheet, with clone-from-last-year and overlap validation.

What came out

Live in production · 567-division flagship event · bilingual captain + admin portals · race-week exports in one click