M2: Editor & Live — Scoring, Progression, SSE, SVG-Bracket, Sharing - #3
Merged
Merged
Conversation
…ring Implements milestone M2 (core) from docs/PLAN.md, built via an orchestrated multi-agent pass + a 5-lens adversarial review (blocker + all majors folded in). Unlike M0/M1 this was type-checked for real: the toolchain is now installed, so `tsc --noEmit` passes for shared, api and web, and the shared tests pass (2/2). Backend (apps/api): - bracket/progression.ts: pure winner advancement, bye auto-advance and round-robin standings (win=3/draw=1/loss=0, stable tiebreak). - tournaments: score endpoint (owner or SCORE link) with single-elim progression, bye seating on create, status recompute; PATCH /design; @sse /events backed by a per-tournament EventsService (process-local). - viewerCanScore is derived per request so the public page only offers scoring when actually authorized. Frontend (apps/web): - bracket/: SVG-styled BracketView, MatchNode, StandingsTable, StageView and token->CSS-var design mapping with presets. - ScoreableMatch + inline scoring; SharePanel (capability links); public live view/score route /t/[id]?token=; EventSource live refresh hook. - Owner editor page composes the bracket, theme controls and sharing. Review fixes: - Rename the SSE handler (was a duplicate `events` identifier — TS2300 blocker). - Reject re-scoring a COMPLETED match (would strand advanced winners); the UI hides the form for completed matches accordingly. - Round-robin matches are now scoreable on both owner and public pages via a shared RoundRobinMatches component. - Re-sync score inputs on live updates; share a single detailKey; move link query keys out of the detail subtree; standings empty-state; force-dynamic on the public route; participantId standings tiebreak. Type fixes found by tsc: drop the unresolved `express` Request import (minimal inline request shape); drop the non-existent next-auth/jwt augmentation and guard the session callback assignments. Tooling: commit pnpm-lock.yaml; set onlyBuiltDependencies in pnpm-workspace.yaml (prisma/esbuild/sharp) so installs don't fail on ignored build scripts; ignore *.tsbuildinfo and next-env.d.ts. Deferred to M2.1/M3 (see docs/PLAN.md): link expiry/revoke, full theme editor + saved-theme library, drag-reseeding, double-elim progression, SSE multi-replica. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 15, 2026
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.
Setzt Meilenstein M2 (Kern) aus
docs/PLAN.mdum: den „Turnier-durchspielen"-Loop. Orchestrierter Multi-Agent-Build (4 Slices) + adversariales 5-Perspektiven-Review; Blocker + alle Majors eingearbeitet.Was drin ist
Backend (
apps/api)bracket/progression.ts— pure Winner-Advancement, Bye-Auto-Advance, Round-Robin-Standings (3/1/0, stabiler Tiebreak).tournaments— Scoring (Owner oder SCORE-Link) mit Single-Elim-Progression, Bye-Seeding beim Create, Status-Recompute;PATCH /design;@Sse /eventsüber prozess-lokalenEventsService.viewerCanScorewird pro Request abgeleitet → die öffentliche Seite bietet Scoring nur, wenn wirklich berechtigt.Frontend (
apps/web)bracket/— SVG-BracketView,MatchNode,StandingsTable,StageView, Token→CSS-Var-Mapping + Presets.ScoreableMatch(inline Scoring),SharePanel(Capability-Links), öffentliche Live-View/Score-Route/t/[id]?token=, EventSource-Live-Refresh.Review-Fixes
events-Identifier im Controller (TS2300) → SSE-Handler umbenannt.COMPLETEDaus.RoundRobinMatches-Komponente).detailKey; Link-Query-Keys aus dem detail-Subtree; Standings-Empty-State;force-dynamic.express-Import → minimaler Inline-Request-Typ; nicht existentenext-auth/jwt-Augmentation entfernt + Session-Callback abgesichert.Tooling
pnpm-lock.yamleingecheckt;onlyBuiltDependenciesinpnpm-workspace.yamlgesetzt (prisma/esbuild/sharp), damitpnpm installnicht an ignorierten Build-Skripten scheitert;*.tsbuildinfo+next-env.d.tsignoriert.Verschoben auf M2.1/M3 (dokumentiert)
Link-Expiry/Revoke, voller Theme-Editor + Saved-Theme-Bibliothek, Drag-Reseeding, double-elim-Progression, SSE-Multi-Replica.
Typecheck ≠ Runtime. Ungetestet zur Laufzeit: der SSE-Stream durch den BFF (EventSource sendet keine Header → Session-Cookie +
?token), der Auth.js-v5-Login/Sync, und das SVG-Bracket-Layout visuell.pnpm --filter @tournamentify/api prisma:migratefür die erste Migration nicht vergessen.🤖 Generated with Claude Code