Gate tournament creation behind an operator-approved creator allowlist - #303
Merged
Conversation
amrtgaber
force-pushed
the
creator-allowlist
branch
from
July 25, 2026 21:17
92540f7 to
249577f
Compare
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.
Summary
Implements #296. Tournament creation becomes invite-gated while everything else about the auth model stays put:
tournament_creatorstable (expand-only migrationa96e9a05b112, validated against a throwaway Postgres 16):user_idString(36) PK — the tokensub— mirroringtournament_owners' FK-free shape. Identity stays in the auth service; app permissions stay modelled here.POST /v1/tournamentsnow 403s callers without an allowlist row, with a stable message and no contact address baked into the API (the management FE renders the request-access CTA).GET /v1/megainscan_create_tournaments: bool(additive) so the FE can gate create-form vs. CTA off the call it already makes — no probe POST. Consumers regenerate orval clients._MAX_OWNED_TOURNAMENTS_PER_CREATOR = 10— checked at create, counted against owner rows (creation records no separate authorship; ownership is the closest durable proxy)._MAX_ROSTER_ROWS_PER_TOURNAMENT = 100— checked at roster add; every linked row feeds the poller's per-profile upstream fan-out, so roster size is upstream quota for the whole platform.tournament_owners); approved creators still become first owner of what they create; PATCH/DELETE/roster/teams need ownership only, not creator status.Operational notes
INSERT INTO tournament_creators (user_id) VALUES ('<operator-uuid>');Idempotency-Key, which clients generate per logical attempt anyway.Tests
New: 403 for an authenticated non-allowlisted user;
can_create_tournamentstrue/false/per-user on/v1/me; ownership-ceiling 422; roster-ceiling 422 including slot-freed-after-delete. Existing create-path tests seed the allowlist via a newseed_tournament_creatorfixture. Full suite: 567 passed; migration chain validated on Postgres 16.Merge order: after #302 — this branch is stacked on it (shared create-handler/test context, and keeps the Alembic lineage linear).
Closes #296