feat(playoffs): season playoff brackets - #50
Merged
ershisan99 merged 3 commits intoJul 7, 2026
Conversation
ChronoFinale
force-pushed
the
feat/playoffs-bracket
branch
from
July 7, 2026 00:01
73364c8 to
e7e08e8
Compare
Contributor
Author
ChronoFinale
force-pushed
the
feat/playoffs-bracket
branch
3 times, most recently
from
July 7, 2026 00:40
baf7bf6 to
c24e1ca
Compare
One single-elimination bracket per season (4-32 players). Only the roster and per-match scores are stored (migration 0015); pairings, advancement, third place, and the champion are derived in a pure, bun-tested module, so displayed state always matches entered results. Best-of-N series semantics (finals can differ): partial scores advance nobody and impossible scores are rejected. Re-seeding clears exactly the results it invalidates. tRPC router behind a new brackets.manage permission (granted per-user in /admin/permissions), with leaderboard player search and published-only public reads.
/playoffs renders the bracket like the league's playoff sheet: mirrored wings converging on a center champion/finals/third-place column, styled with the Balatro pixel font on a dark board. One shared BracketSheet component owns the geometry (the admin board reuses it via a renderMatch prop). Responsive without horizontal scroll: scales to fit, then stacks rounds vertically below a readability floor. Pages are cached and revalidated on demand by admin edits. Defaults to the active season's bracket; older seasons via picker pills and /playoffs/[id].
/admin/brackets (brackets.manage): create is just season + size + format; the bracket itself is the editor. Search the ranked leaderboard or type a name to add players to a pool, drag (or tap) them onto first-round spots, drag between spots to swap. Scores are typed on the match cards, auto-save after typing stops, validate the series format inline, and advance the winner immediately. Roster saves are serialized against races and re-sync from server truth, so a failed save reverts visibly.
ChronoFinale
force-pushed
the
feat/playoffs-bracket
branch
from
July 7, 2026 00:47
c24e1ca to
41d9b18
Compare
ChronoFinale
marked this pull request as ready for review
July 7, 2026 00:51
Collaborator
|
I'm gonna merge this and if something breaks we'll fix ig |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



feat(playoffs): season playoff brackets
What
Season playoff brackets on the site, per Dunk's request to make playoffs more visible.
Public
/playoffstab (desktop nav + mobile menu)m6x11pixel font, connector elbows, gold winner names, crowned champion./playoffs/{id}. Seed names linked to a player are profile links.Admin
/admin/brackets(newbrackets.managepermission)How
brackets,bracket_seeds,bracket_results; single migration 0015). Pairings, advancement, semifinal-losers-to-third-place, and the champion are all derived in a pure bun-tested module (src/lib/bracket.ts) — the displayed bracket can never disagree with entered results, and correcting an old score reflows later rounds.season_idNOT NULL + unique); display names derive from the season registry.Granting access
brackets.managemust be granted per user in/admin/permissions("Manage brackets" under the Playoffs group) — permissions come from each user's stored permissions array, so nobody has bracket access until granted, existing admins included. Dunk logs in once via Discord to appear in the manager. The single permission unlocks only the bracket admin.Follow-up (not in this PR)
Player-profile trophies ("Season X Playoff Champion" badge derived from published bracket results). The groundwork ships here — seeds carry Discord ids — and a working implementation is parked on
feat/profile-trophies-wip.Drive-by
toMatchObjectto thebun:testtype shim (the bracket engine tests use it;typecheckfails without it).Validation
bun test(32),bun run check,bun run typecheck,bun run buildall green. Exercised end-to-end on local dev: created brackets via the admin UI, placed players, entered results, verified propagation/champion, published, checked public pages in both themes and at narrow widths.