Skip to content

feature: events pages#484

Merged
lukepolo merged 10 commits into
mainfrom
feature/events
Jul 11, 2026
Merged

feature: events pages#484
lukepolo merged 10 commits into
mainfrom
feature/events

Conversation

@Flegma

@Flegma Flegma commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Web side of the Events feature (LAN mini-seasons). Design: docs/plans/2026-07-03-events-feature-design.md; implementation plan: docs/plans/2026-07-04-events-feature-implementation-plan.md.

Depends on the api PR (5stackgg/api#337). Merge the api PR first: the regenerated GraphQL types and every query here assume the events schema exists in Hasura.

What's included

  • generated/zeus regenerated with the events types.
  • graphql/simpleEventFields.ts, composables/useEventContext.ts, utilities/eventDisplay.ts.
  • pages/events/index.vue (list), create.vue, manage.vue, shared components/events/EventCard.vue, components/events/EventForm.vue.
  • pages/events/[eventId]/index.vue (detail) with tabs: Leaderboard, Standings, Tournaments, Teams, plus an organizer-only Settings tab (edit name/description/dates and move the event between Setup/Live/Finished).
  • components/events/EventLeaderboard.vue (get_event_leaderboard; categories rating/adr/kdr/kills/wins), EventStandings.vue (member-tournament trophies + medal table), EventMembershipPanel.vue (organizer-only attach/detach tournaments/teams/players + import-players-from-rosters).
  • Nav entries (Events + admin Manage Events), breadcrumb branch, full en.json i18n keys.
  • Old pages/events.vue "coming soon" stub removed.

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

  • f61cb96 create/manage gates aligned with the backend's create_events_role (new eventCreateRole store getter); Manage Events list broadened for privileged roles.
  • 685f54d tournaments-tab null guard; medal table keeps ad-hoc teams; Min. Rounds blank coerced to 0; removed a wasted fallback query at mount.
  • d8dba9e subscription error() handlers + malformed-uuid guard (no stuck skeleton); breadcrumb no longer shows a raw uuid or literal create/manage segment.

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, which itself caught and fixed one Minor regression):

  • 2918f87 + 487782c standings trophy shapes. Placement trophies are stored as one canonical team row plus one row per roster player, and MVP rows also carry the winning team's id. The standings component treated every row independently: placement slots stacked roster-size + 1 duplicate badges, the medal table credited one tournament win as roster-size + 1 golds, and the MVP slot showed the winning team's name/link instead of the player. Rows now collapse to one entry per team per placement, medal counts dedupe per (tournament, team, placement), MVP is player-scoped, and manually awarded player trophies keep their player link.
  • 0a8b956 organizer Settings tab (fixes unreachable edit mode). EventForm shipped with a complete edit mode that nothing mounted, so no UI could move an event out of Setup; newly created events stayed hidden from the public forever. The detail page now mounts the form in an organizer-gated Settings tab (mirroring the tournament detail page), and populateFromEvent correctly sets/clears dates.
  • a0b8c79 membership panel. The tournament attach search was scoped to tournaments the viewer personally organizes, locking out co-organizers and privileged roles (the server allows attaching any tournament); the roster-import mutation used on_conflict, which Hasura does not expose without an update permission, so it failed validation for every non-admin organizer.
  • 1f13265 isRoleAbove fail-closed. An unknown role gate (settings still loading) mapped to indexOf -1 and granted every logged-in user; the Create Event/Tournament buttons flashed for users the server would reject.
  • 8c495cc shared EventCard + eventDisplay helpers. The card markup and three display helpers were copy-pasted across the list page, manage page, and detail header; extracted to one component + one utility module. Also drops dead code (unused isOrganizer context field, unused imports).

Verification

Every task was built and reviewed against an ephemeral TimescaleDB + Hasura v2.49.2 stack loaded with the api events schema and dev fixtures (round-1 details in the commit history). The round-2 fixes were verified by a 4-agent adversarial regression pass: every trophy-row shape traced through both the placement cards and the medal table (7 scenarios), the settings-tab tab-state wiring (useRouteTab whitelist), the update mutation against the Hasura update permission columns, the attach-search/import mutations against the insert permissions, an audit of every isRoleAbove call site, and the EventCard extraction (i18n keys, no dangling references, simpleEventFields covers the card's fields). One regression was found and fixed (487782c). A live typecheck could not be re-run because the checked-in codegen targets the ephemeral schema (see below).

MUST DO before merge (needs the real production Hasura)

  • Re-run yarn codegen against production Hasura and recommit generated/. The committed regen was generated against the ephemeral verification Hasura, which had schema drift: it drops unrelated, unused columns (draft_games.scheduled_at, game_server_nodes.cs2_launch_options), adds players.faceit_synced_at, flips nullability on player_faceit_rank_history.elo/skill_level, and sets the zeus HOST constant to http://localhost:58080 (dead code, unused by the Apollo client). None affect the events code, and all are restored by the prod re-codegen. Run this AFTER the api PR merges, then merge this PR.
  • nuxi typecheck after the re-codegen (expect zero new errors over baseline).

Notes / follow-ups (not blockers)

  • pages/tournaments/manage.vue shows all tournaments to tournament_organizer/admin roles via its is_organizer filter (pre-existing); events/manage.vue handles the equivalent explicitly. Worth a ticket to make tournaments consistent.
  • The Manage Events nav entry stays gated on tournament_organizer/admin like Manage Tournaments (reviewed and kept: the whole Administration nav section is already role-gated above user, and those roles genuinely manage all events; the create gate inside the pages uses create_events_role).
  • No settings-page UI for public.create_events_role yet (DB-only; defaults to any logged-in user until set). Adding a control next to create_tournaments_role is a small follow-up.
  • EventMembershipPanel.vue/EventStandings.vue use raw gql / loosely-typed $apollo.query to sidestep a zeus ExtractVariables inference gap (documented workaround).
  • Accepted review observations: EventForm's date+time picker is a fork of the tournament form's (a shared DateTimePicker is a cross-domain refactor); the leaderboard fetch runs the rows query and the aggregate count together on every page change (LAN-sized cost); concurrent roster imports can race the PK and surface an error toast (retry self-heals).

@lukepolo lukepolo changed the title feature: events pages (LAN mini-seasons) feature: events pages Jul 11, 2026
@lukepolo lukepolo merged commit d5cdefb into main Jul 11, 2026
@lukepolo lukepolo deleted the feature/events branch July 11, 2026 18:37
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