Series-aware event badges on solving times, one public-visibility rule, API detail gate for editions - #206
Merged
Merged
Conversation
…e, API detail gate for editions
Solving times will soon be linkable to editions of recurring series (a
competition row with series_id set, no logo/shortcut, approved via its
series). Prepare every place a time's event is shown:
- IsCompetitionPubliclyVisible: the single rule (standalone: approved &
not rejected; edition: parent series approved & not rejected), with the
predicate exposed as SQL_CONDITION for list queries.
- 13 read-model SQL blocks select the series name/shortcut/slug next to
the competition columns (SolvedPuzzle, PuzzleSolver, PuzzleSolversGroup,
RecentActivityItem DTOs); GetLastSolvedPuzzle deleted (no consumers).
- One shared partial _competition_badge.html.twig replaces 5 copy-pasted
badge snippets (fixes the PuzzleTimes mixed-row label bug); editions
render "series · edition" and link straight to edition_detail — never
event_detail by bare slug, which is ambiguous across series.
_ladder.html.twig deleted (never included).
- GET /api/v1/competitions/{id} gates on the visibility rule (editions of
approved series become readable) and carries an additive series object.
Fixtures: SERIES_UNAPPROVED + EDITION_UNAPPROVED_1.
Refs #204
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUegPi2i9SjwkcrNWyENnL
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.
Part 2 of 4 for #204 (after #205). Visual no-op for every existing solving time — all of them link to standalone competitions. This PR prepares the rendering (and the API) for times linked to editions of recurring series, which the next PR makes selectable in the add-time picker.
What
IsCompetitionPubliclyVisible— the single visibility rule for a competition row: standalone → approved & not rejected; edition → its series approved & not rejected (editions are never individually approved,ConvertCompetitionToSerieseven clearsapproved_at). The predicate is exposed asSQL_CONDITIONso the picker's list query (next PR) embeds the exact same rule.competition.name/shortcut/slugnext to a solving time now also select the series name/shortcut/slug (SolvedPuzzle,PuzzleSolver,PuzzleSolversGroup,RecentActivityItemgot 3 nullable fields, appended with defaults).GetLastSolvedPuzzledeleted — no consumers.templates/_competition_badge.html.twigreplaces the 5 copy-pasted trophy-badge snippets (_player_solvings,LadderTable,PuzzleTimes×2,RecentActivity). Standalone output is unchanged (shortcut ?? name→event_detail); an edition rendersseries.shortcut ?? series.name · editionand links directly toedition_detail— neverevent_detailby bare slug, which is only unique per series. Also fixes thePuzzleTimes.html.twigrow that mixedsolving_time.competitionShortcut ?? aggregated_solver[0].competitionName._ladder.html.twigdeleted (never included).GET /api/v1/competitions/{id}gates on the visibility rule (editions of approved series are readable; editions of unapproved/rejected series, and unapproved/rejected standalone, still 404) and carries an additiveseries: {id, name, slug} | null. The list endpoint stays standalone-only (documented).SERIES_UNAPPROVED+EDITION_UNAPPROVED_1(documented in.claude/fixtures.md).Perf
EXPLAIN (ANALYZE, BUFFERS)forGetFastestPlayers(500 pcs, LIMIT 100) on the dev prod-like dump (339k solving times): before 177–188 ms warm, after 170–176 ms warm — the extra node is a hash join on a ≤200-row table applied after the CTE. Negligible everywhere else (PK lookup per row with acompetition_id).Tests
+25 tests:
IsCompetitionPubliclyVisibleTest(8), API detail endpoint (edition 200 withseries, rejected/unapproved series 404, standaloneseries: null), query tests for the new columns inGetPlayerSolvedPuzzles/GetPuzzleSolvers/GetFastestPlayers/GetRecentActivity(in-testUPDATEseeding under DAMA rollback — no permanent solving-time fixture rows, the picker/statistics tests pin exact counts),CompetitionBadgeTemplateTest(8 rendering cases incl. hrefs),PuzzleTimesCompetitionBadgeTest(live component). Full gates green locally (cs, phpstan max, 2209 tests, schema:validate, prod warmup).Refs #204
🤖 Generated with Claude Code
https://claude.ai/code/session_01QUegPi2i9SjwkcrNWyENnL