← Dev Blog / Building the League Series

Episode 10  ·  Building the League Series

Building at Both Ends

One format brings a single curious golfer onto a course for the first time. The other brings teams from across the country together for a week. Right now, we're building both at once.

Most of the platform work described in this blog so far has lived at a single scale: one league, one city, one season at a time. Right now there are two builds in progress that pull the platform in opposite directions simultaneously. One scales the format down to its smallest possible unit — a single player, no team, no commitment beyond showing up. The other scales it up to its largest — teams from across the country, converging for a week, fighting through pool play into an elimination bracket for a national title.

Different audiences. Different timelines. Completely different engineering problems. But both come from the same underlying question: what does the NTMGL look like once it's not just a DFW league running one season a year?

"The Fall Session asks: how do we make this as easy as possible to try once? The National Tournament asks: how do we make this worth flying across the country for? They're opposite questions, and the platform has to answer both."

— Brian Hackney, Founder

The Fall Session — Solving for One

The business reasoning behind the Fall Session was covered in Episode 8 — it removes the team-formation barrier that keeps curious golfers from ever trying the format. The technical reasoning is simpler than it sounds, because most of the platform doesn't change at all. The scoring engine, the handicap system, and the GameDay interface all work identically whether a "team" has eight players or one. What changes is entirely in the scheduling layer.

The original schedule generator — the one that produced four matchups instead of two back in Episode 2 — was built around a fixed assumption: a small number of teams playing a double round-robin across a full season, each team playing every other team twice. That assumption breaks immediately for individual play, where you might have fifteen or twenty players who all need to rotate through different opponents every week without anyone playing the same person twice in a row, and without anyone sitting out more often than anyone else.

The fix borrows from a much older scheduling technique than anything in the original generator: the circle method, used for generating balanced round-robin pairings for any even number of competitors. Players are arranged conceptually in a circle; one half rotates against the other each round, guaranteeing that every player faces a new opponent every week until the rotation completes. One player stays fixed in position while everyone else rotates around them each round. The result is a complete schedule where every player faces every other player exactly once before anyone repeats — and if the roster is odd, the bye slot rotates fairly through the field instead of always landing on the same person.

Everything downstream of the schedule is unchanged. An IndividualMatch already existed as the atomic scoring unit inside a ScheduledMatch — the Fall Session just creates an IndividualMatch directly, without a parent team matchup wrapping it. GameDay doesn't know or care that there's no team context; it renders the same scorecard either way. That's the real payoff of having built the scoring engine as a clean, isolated service back in Episode 3 — extending it to a new format barely touches it at all.

The National Tournament — Solving for Many

The National Tournament is a different order of problem entirely. The concept: held twice a year, a week-long event that brings teams and players in from around the country. Every team is guaranteed at least four to five matches through round-robin pool play within their division, and the top teams from each division advance into a single-elimination bracket to determine a national champion.

National Tournament Format

What every team is guaranteed — and what they're playing for

  • Held twice each year — a recurring national championship, not a one-time event
  • Teams and players travel in from markets across the country, not just the league's home markets
  • A full week-long event — pool play and elimination rounds compressed into days, not a season
  • Teams are grouped into divisions for round-robin pool play
  • Every team is guaranteed 4–5 matches through pool play — no team travels across the country to play one match and go home
  • The top teams from each division advance to a single-elimination bracket that determines the national champion

The guaranteed-matches rule is the most important design decision in the entire format, and it's a business decision before it's a technical one. Nobody flies a team across the country, books hotel rooms for a week, and pays travel costs for the possibility of being eliminated after a single match. The pool play structure exists specifically so that every team gets meaningful competitive volume regardless of how the bracket eventually shakes out. The platform has to guarantee that promise structurally, not just hope the schedule works out that way.

The event flow runs in four stages: division pool play first, where teams grouped into divisions play every other team in their division — guaranteeing 4–5 matches regardless of outcome. Pool play results then determine standings within each division, with tiebreakers ranking teams for bracket seeding. The highest-seeded teams from every division qualify for the elimination bracket — pool play is over, and every remaining match matters completely. Finally, a cross-division single-elimination bracket determines the national champion. Lose once and the tournament is over for that team.

The Data Model Problem

The platform already had two of the three pieces this format needs. The playoff bracket engine — built in the aftermath of Season 1, with SVG connectors, seeding logic, and a live bracket view — already exists and was designed generically enough to seed from any ranked list of teams, not just a single season's standings. The ScheduledMatch and IndividualMatch structures already handle the actual match scoring regardless of context.

What's missing is the layer in between: a way to group matches into divisions, run round-robin pool play within those divisions, and produce standings that feed into the existing bracket engine as seeding input. That's a new entity model — TournamentEvent and TournamentDivision — sitting alongside the season structure rather than inside it. ScheduledMatch gains an optional TournamentDivisionId and a TournamentRound type (pool play or elimination), both nullable so regular season play is completely unaffected.

Reusing ScheduledMatch rather than building a parallel tournament-specific match entity was a deliberate choice. It means GameDay, the scoring engine, and the verification flow all work identically inside the tournament — a match is a match, regardless of whether it's pool play in week three of a national event or a Tuesday night in a regular DFW season. The only new logic is in how matches get generated, how standings get calculated within a division, and how division standings feed the bracket.

The Scheduling Problem We're Solving Right Now

The hardest unsolved piece, as of this writing, isn't the data model — it's the temporal assumption baked into everything built so far. Every schedule generator the platform has ever run, including the Fall Session rotation, assumes a weekly cadence: one round of matches per week, spread across a season measured in months.

A week-long national tournament breaks that assumption completely. Pool play has to compress several rounds of round-robin matches into a handful of days, with multiple matches happening concurrently across multiple courses, while still guaranteeing every team their four to five matches before the bracket cut. That's a resource allocation problem — course capacity per day, tee time availability, and travel logistics between matches — layered on top of the round-robin generation problem the platform already knows how to solve at a weekly cadence.

Currently Being Solved

Weekly Cadence Doesn't Compress Into a Week

  • The existing schedule generators — both the team double round-robin and the individual rotation — assume one round of play per calendar week
  • The National Tournament needs several rounds of pool play completed within a single week, across multiple courses, without overloading any single venue's daily capacity
  • The approach being built is a course-capacity-aware scheduler — each course declares how many matches it can host per day, and rounds get assigned against that capacity
  • The system flags any division where guaranteed-match commitments can't be met within the available days and courses — before the event starts, not after a team is double-booked on day three

This is the piece of the National Tournament that doesn't have a clean answer yet. It's a genuinely different scheduling problem than anything the platform has solved before, because every previous schedule has had the luxury of spreading matches across months. A week-long event has none of that slack.

Three Formats, Side by Side

With the Fall Session in development and the National Tournament in design, the NTMGL platform is about to support three structurally different competitive formats on the same core engine. The Spring Season runs full team rosters over months at a weekly cadence within a single market. The Fall Session runs individual play with no team, over a few weeks at a weekly cadence, also within a single market. The National Tournament runs full team rosters compressed into a single week at a daily cadence, spanning multiple markets nationally, for a national championship title.

The variation is the point. A platform that can only run one of these formats isn't ready to be a national league. A platform that can run all three on the same scoring engine, the same verification flow, and the same GameDay interface — with only the scheduling and grouping logic changing underneath — is a platform built the right way.

Why Both, Why Now

The Fall Session and the National Tournament sit at opposite ends of the same player journey described in Episode 8's acquisition flywheel. The Fall Session is the easiest possible entry point — try the format once, no team required, minimal commitment. The National Tournament is the aspirational ceiling — the reason a player who's been grinding through DFW spring seasons has something bigger to play for than a local championship.

Building both at the same time is not an accident of scheduling. It's the natural consequence of the "Going National" thesis from Episode 6. A league that's actually national needs an easy front door and a serious back door — a way in for the curious, and a reason to stay for the committed. Neither piece makes sense without the other. The Fall Session without a National Tournament is just a smaller local league. A National Tournament without a Fall Session has no funnel feeding it new markets and new players.

"The Fall Session and the National Tournament are bookends. One brings someone in. The other gives them somewhere to go. Building only one of them would leave the league half-finished."

— Brian Hackney, Founder

Neither build is finished. The Fall Session rotation logic is in active testing ahead of its first run this fall. The National Tournament's data model is built; the course-capacity scheduling problem is still being solved. Both will get their own follow-up episodes once they're live and have real data behind them — including, almost certainly, a bug or two worth writing honestly about.


Next episode: the course partnership pitch — how to approach a golf course general manager, what they actually care about, and the conversation that turns a venue into a partner.

Tags fall session national tournament platform scheduling architecture