Skip to content

M2.1: Saved Themes, Theme-Editor, Link-Expiry/Revoke, Reseeding - #4

Merged
TimGoldbach merged 1 commit into
feat/m2-editor-livefrom
feat/m2_1-polish
Jun 15, 2026
Merged

M2.1: Saved Themes, Theme-Editor, Link-Expiry/Revoke, Reseeding#4
TimGoldbach merged 1 commit into
feat/m2-editor-livefrom
feat/m2_1-polish

Conversation

@TimGoldbach

Copy link
Copy Markdown
Owner

Politur-Meilenstein M2.1. Orchestrierter 3-Slice-Build + adversariales 4-Perspektiven-Review (2 Blocker + 1 Major eingearbeitet). Verifiziert: tsc grün (api + web), Engine-Tests 12/12.

ℹ️ Gestapelt auf #3 (M2). Base feat/m2-editor-live → Diff M2.1-only.

Was drin ist

  • Saved Themes (apps/api/src/themes/*): user-scoped SavedTheme-CRUD (401 für Gäste, nur eigene löschbar).
  • Theme-Editor (ThemeEditor.tsx): Preset + Color-Picker (neuer lib/color.ts Hex↔HSL-Util + Round-Trip-Test) + Theme-Bibliothek (per useSession gated).
  • Link-Expiry + Revoke: expiresInHours beim Erstellen, DELETE /tournaments/:id/links/:linkId; SharePanel zeigt Ablauf + Revoke-Button.
  • Reseeding (SeedingEditor.tsx + PUT /tournaments/:id/seeding): Reihenfolge ändern → Bracket regenerieren. Reorder dependency-frei (Hoch/Runter), weil dnd-kit offline nicht installierbar war.

Der wichtige Review-Fund 🔴

Auto-advancte Byes sind COMPLETED, tragen aber keine Score. Das Zählen von COMPLETED-Matches hat dadurch (a) ein frisches Nicht-Zweierpotenz-Bracket sofort auf RUNNING gekippt und (b) Reseeding sofort gesperrt — genau dort, wo Seeding zählt. Fix: isScored() (beide Opponents haben numerische Score) steuert jetzt Reseed-Lock und Status-Recompute; das Frontend-Lock spiegelt es. Reseed-Guards laufen jetzt in einer Transaktion (TOCTOU) und emittieren ein SSE-Signal.

Verschoben (dokumentiert in docs/PLAN.md)

dnd-kit-Politur, Re-Scoring/Korrektur, SSE-Multi-Replica, In-App-Dialoge statt window.prompt/confirm.

⚠️ Laufzeit weiterhin offen

Wie zuvor: DB-gestützter Flow (Reseed-Regenerate, Themes-Persistenz, SSE durch BFF) ist offline nicht real gelaufen — nur typecheck + Engine-Unit-Tests. prisma migrate + ein echter Start stehen noch aus.

🤖 Generated with Claude Code

Polish milestone built via an orchestrated 3-slice pass + a 4-lens adversarial
review (2 blockers + 1 major folded in). Type-checked (api + web exit 0) and the
engine tests still pass (12/12).

Backend (apps/api):
- themes module: user-scoped SavedTheme CRUD (GET/POST/DELETE /themes, 401 for
  guests, owner-only delete).
- links: optional expiresInHours on create; DELETE /tournaments/:id/links/:linkId
  to revoke.
- reseed: PUT /tournaments/:id/seeding regenerates the bracket from a new seed
  order; the generation/persistence path is now a shared helper used by create()
  and reseed(); all guards + the destructive regenerate run in one transaction;
  emits an SSE change signal.

Frontend (apps/web):
- ThemeEditor (preset + color pickers via a new hex<->HSL util in lib/color.ts +
  round-trip test) with a saved-theme library gated by useSession.
- SeedingEditor: dependency-free up/down reorder (dnd-kit isn't installable
  offline) → reseed; locked once a real result exists.
- SharePanel: per-link TTL select + expiry display + revoke.

Review fix (the important one): auto-advanced byes are COMPLETED but carry no
score, so counting COMPLETED matches wrongly (a) flipped a fresh non-power-of-2
bracket to RUNNING and (b) locked reseeding immediately — exactly where seeding
matters. Introduced isScored() (both opponents carry a numeric score) and use it
for the reseed lock and status recompute; the frontend lock mirrors it. Also:
retry:false on auth-gated queries.

Deferred (see docs/PLAN.md): dnd-kit polish, re-score/correction, SSE
multi-replica, in-app dialogs instead of window.prompt/confirm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant