Skip to content

feature: events (LAN mini-seasons)#337

Open
Flegma wants to merge 2 commits into
mainfrom
feature/events
Open

feature: events (LAN mini-seasons)#337
Flegma wants to merge 2 commits into
mainfrom
feature/events

Conversation

@Flegma

@Flegma Flegma commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Implements the approved Events feature: an event is a curated container grouping assigned tournaments; leaderboards and standings are computed on read over the derived match set. Design doc: docs/plans/2026-07-03-events-feature-design.md (workspace docs), implementation plan: docs/plans/2026-07-04-events-feature-implementation-plan.md.

What's included

  • Migration 1867000000300_events: tables events, event_organizers, event_tournaments, event_teams, event_players, enum e_event_status (Setup/Live/Finished). Event deletion cascades membership rows only; matches/tournaments/players are never touched.
  • is_event_organizer computed-field function (clone of is_tournament_organizer).
  • v_event_player_stats view: clone of v_tournament_player_stats keyed by event, membership derived via event_tournaments -> tournament_stages -> tournament_brackets.
  • get_event_leaderboard(_event_id, _category, _match_type, _min_rounds default 10) returning leaderboard_entries; categories rating/adr/kdr/kills/wins; non-empty event_players acts as a roster filter (empty = everyone). Low _min_rounds default because the global 50-round floor would blank a one-day LAN.
  • Hasura metadata: relationships, is_organizer computed field, player_stats manual relationship, settings-gated insert via public.create_events_role (same _exists mechanism as tournaments, full role fan-out), guest select hides Setup events (including all child tables, the stats view, and the leaderboard function), owner-only delete and owner-only co-organizer management, function tracking.
  • No NestJS changes; no changes to matches, player_elo, or ELO calculation.

Post-review fixes, round 1 (2026-07-04)

An 8-dimension find + adversarial-verify review produced:

  • Setup events fully hidden from the public (security). Child tables, stats view, and leaderboard function previously read wide open, letting anonymous clients enumerate a not-yet-public event's roster and standings by id. All event-derived read paths now apply the events table's status _neq Setup guest gate plus an organizer-aware user branch; get_event_leaderboard returns empty for a Setup or unknown event. Commit 5b7a3bf.
  • Rollback safety. down.sql clears the boot-phase SQL digests (guarded by to_regclass) so a forward deploy after a rollback recreates the view/functions. Commit cd8299a.

Post-review fixes, round 2 (2026-07-07)

A second full-PR review (8 finder angles, per-candidate adversarial verify, then an adversarial regression pass on the fixes) produced:

  • Leaderboard pagination fixed. get_event_leaderboard hard-capped output at LIMIT 100 while the web paginates via Hasura-level order_by/limit/offset (like the global get_leaderboard, which has no cap), silently truncating events with more than 100 players; the cap is removed. An explicit NULL _min_rounds also silently emptied the board (HAVING >= NULL); it now means "no minimum". Commit 1f006a0.
  • create_events_role='moderator' no longer bricks event creation. The insert-check role fan-out skipped the moderator tier entirely (no moderator permission, and the higher roles' _in lists jumped from streamer to match_organizer), so setting the role to moderator would have denied creation to everyone below administrator. Fixed with a moderator permission block and corrected lists. The tournaments clone source (create_tournaments_role checks) has the same pre-existing gap; flagged as a follow-up rather than widened into this PR. Commit eed53d6.

Verification

Run against an ephemeral TimescaleDB + Hasura v2.49.2 stack with the repo's full migration chain, SQL dirs, metadata, and dev fixtures applied (metadata ic list consistent):

  • v_event_player_stats verified row-identical to v_tournament_player_stats for a single-tournament event (EXCEPT check, both directions), and union growth verified with a second tournament.
  • All five leaderboard categories exercised with multi-map aggregation, plus _min_rounds threshold and _match_type filter behavior.
  • Role-based GraphQL audit: guest cannot see Setup events; organizer insert auto-sets organizer_steam_id; co-organizers can manage membership but cannot delete the event or manage the co-organizer list (two escalations found and fixed in c77cf4b).
  • Round-1 and round-2 fixes verified by adversarial re-review (permission-gate role matrix, plpgsql validity, YAML parse + role-list monotonicity, Hasura function pagination semantics). NOT yet re-applied against a live Hasura; the dev-stack steps below are the confirming pass.

Pre-merge checklist (needs the real dev stack)

  • yarn dev boot so HasuraService.setup() hash-applies the new/edited SQL files, then hasura metadata apply + hasura metadata ic list to confirm no inconsistencies.
  • Re-run the view equivalence check and leaderboard smoke test against real-scale data.
  • Guest query for a Setup event's event_tournaments/v_event_player_stats/get_event_leaderboard returns zero rows; the organizer still sees them.
  • Leaderboard pagination past row 100 works on a large event (or synthetic data).

Product notes for review

  • Setup-event visibility (resolved): guests can no longer enumerate Setup events' membership/stats/leaderboard. This intentionally diverges from the shipped tournaments family, which still reads its child tables wide open; the same tightening there is a suggested follow-up ticket.
  • Organizer preview during Setup: get_event_leaderboard takes no session argument, so it returns empty for a Setup event even to its organizer. This affects the web detail page's Leaderboard tab AND its Teams and Players tab (whose participant fallback uses the same function when no players are explicitly attached); explicitly attached players/teams still show. Raw per-player stats remain visible to the organizer via v_event_player_stats. If organizer preview during Setup is wanted, make the function session-aware (add hasura_session json + is_event_organizer check) as a follow-up.
  • tournament_organizer role can manage/delete any event (admin-tier semantics, same as is_event_organizer's role bypass).
  • events.organizer_steam_id FK has no ON DELETE action, so deleting a player who organizes an event is blocked (deliberate; no player-deletion flow exists today).
  • Accepted review observations (consistent with platform conventions, follow-up candidates): v_event_player_stats derives deaths from player_kills (like its tournament clone) while get_event_leaderboard uses player_match_map_stats, so KDR can differ slightly between the two read paths; the event match-set CTE is duplicated between the view and the function (kept separate to preserve the verified NOT MATERIALIZED inlining); the wins CTE is computed for all categories; no ORDER BY tiebreaker at page boundaries (same as the global leaderboard).

Web PR follows (page family + zeus codegen); merge this first.

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.

2 participants