Average player age at registration; age-matched round 1 for bracket-only tournaments
Optional age on signup and the desk. Auto-generated brackets pair neighbours by age with byes spread down the sheet; teams without an age are placed at random, fully random when no ages exist. Release 0.6.0. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01MB7nCCAscYsb3zzkT6LHZi
This commit is contained in:
1 parent
3f60a39e45
commit
103c221a12
10 files changed
+114
-19
No files matched your search
+2
-2
@@ -9,7 +9,7 @@ All pages are server-rendered HTML except where noted. `<slug>` is the URL-safe
|
||||
| GET | `/` | List of tournaments. |
|
||||
| GET | `/healthz` | `{ ok, tournaments, uptime }` JSON. Used by the Docker healthcheck. |
|
||||
| GET | `/t/<slug>` | The QR landing page. Registration form while phase is `checkin`; otherwise the live board / results (client-rendered from state JSON). |
|
||||
| POST | `/t/<slug>/register` | Form fields `name`, `captain`, `phone`, `players`, `playerNames` (newline-separated). 303 to the team page on success, 400 with the form re-rendered on error. |
|
||||
| POST | `/t/<slug>/register` | Form fields `name`, `captain`, `phone`, `players`, `avgAge` (optional, 5–99), `playerNames` (newline-separated). 303 to the team page on success, 400 with the form re-rendered on error. |
|
||||
| GET | `/t/<slug>/teams/<id>` | The same personalized board addressed by public team id; this is what team-name links use. |
|
||||
| GET | `/t/<slug>/team/<code>` | Personalized board for the team with that 4-character code. `?new=1` shows the post-registration confirmation instead. |
|
||||
| GET | `/t/<slug>/display` | TV display mode of the board. |
|
||||
@@ -78,7 +78,7 @@ All organizer routes require the session cookie set by `/admin/login` (or Cloudf
|
||||
| POST | `/admin/t/<slug>/phase` | `phase` = `checkin` / `closed` / `live` / `final` | Change phase. `live` requires generated play and starts court assignment. |
|
||||
| POST | `/admin/t/<slug>/banner` | `banner` | Set (or clear with empty) the persistent banner. |
|
||||
| POST | `/admin/t/<slug>/broadcast` | `text` | One-time alert to all team pages. |
|
||||
| POST | `/admin/t/<slug>/generate` | `what=pools`, `poolSize` — or `what=bracket`, `perPool`, `wildcards`, `type` (`single`/`double`), `thirdPlace` — or `what=manual`, `type`, `thirdPlace`, `a1`,`b1`,`a2`,`b2`,… (team ids per round-1 match; empty = bye) | Generate pools or bracket, automatically or from hand-picked pairs. |
|
||||
| POST | `/admin/t/<slug>/generate` | `what=pools`, `poolSize` — or `what=bracket`, `perPool`, `wildcards`, `type` (`single`/`double`), `thirdPlace`, `byAge` (bracket-only: age-matched round 1, random where no age) — or `what=manual`, `type`, `thirdPlace`, `a1`,`b1`,`a2`,`b2`,… (team ids per round-1 match; empty = bye) | Generate pools or bracket, automatically or from hand-picked pairs. |
|
||||
| POST | `/admin/t/<slug>/regenerate` | | Clear all generated play (only before any score). |
|
||||
| POST | `/admin/t/<slug>/score` | `match`, `sets` (`"21-18, 19-21, 15-9"`) | Record or correct a result. Validated against the rules. |
|
||||
| POST | `/admin/t/<slug>/live` | `match`, `a`, `b` | Update the running score of a live match (JSON, used by the score pad). |
|
||||
|
||||
@@ -12,14 +12,14 @@ Everything an organizer does happens at `/admin` on a phone or laptop. Sign in w
|
||||
|
||||
## Check-in
|
||||
|
||||
Teams scan the code and fill in team name, captain, mobile, number of players, optional player names. They get a private team link on the confirmation screen with a "Text it to myself" button. The team link shows their schedule, record, and alerts all day.
|
||||
Teams scan the code and fill in team name, captain, mobile, number of players, an optional average player age, and optional player names. They get a private team link on the confirmation screen with a "Text it to myself" button. The team link shows their schedule, record, and alerts all day.
|
||||
|
||||
From the desk you can rename a team, fix the captain or player count, remove a team, add a walk-up team, and set seeds (1 = strongest). Seeds decide pool placement (snake order) and bracket placement. If you don't seed, registration order is used.
|
||||
|
||||
## Starting play
|
||||
|
||||
1. **Close registration.** The public page switches to the roster and "schedule coming."
|
||||
2. **Generate pools** (pick the pool size) or, for bracket-only, generate the bracket. You can clear and regenerate freely until the first score is entered. A late team? Clear generated play, add the team, regenerate.
|
||||
2. **Generate pools** (pick the pool size) or, for bracket-only, generate the bracket. For bracket-only days, "Match round 1 by similar age" (on by default) sorts teams by the average age they gave at registration and pairs neighbours, drops teams without an age in at random, and spreads byes so second-round opponents are close in age too; untick it to use seed order. You can clear and regenerate freely until the first score is entered. A late team? Clear generated play, add the team, regenerate.
|
||||
To decide the first-round matchups yourself, open **Build the bracket by hand**: one row per round-1 match with a team picker on each side, pre-filled with standard seeding. Leave a side as "bye" to give the other team a walkover. Every team must appear exactly once; winners of matches 1 and 2 meet next, 3 and 4 meet, and so on down the sheet.
|
||||
3. **Go live.** The engine immediately assigns the first matches to the courts. Teams whose match is next see "on deck for Court 2, ~15 min" on their team page and the public board.
|
||||
|
||||
|
||||
Reference in new issue
Block a user