Review: Tournament product creation + per-player Stripe checkout links

review-994-2026-04-12 Review

review needs-refinement

Verdict: NEEDS_REFINEMENT

Template Completeness

  • [x] Type
  • [x] Lineage
  • [x] Repo
  • [x] User Story
  • [x] Context
  • [x] File Targets
  • [x] Acceptance Criteria
  • [x] Test Expectations
  • [x] Constraints
  • [x] Checklist
  • [x] Related

Traceability

  • [x] story:WS-S33 label -- "As an admin, I want to bill players for tournament entry fees at team-specific rates via Stripe so that event costs are collected before registration deadlines"
  • [x] story note verified -- found in project-westside-basketball user-stories section (Admin stories list)
  • [ ] arch:email label -- MISLABEL. This ticket creates Tournament models, admin endpoints, and Stripe checkout links. The primary architecture component is checkout/commerce, not email. Email blast is explicitly scoped to the sibling ticket #456. [LABEL] Change arch:email to arch:basketball-api or arch:checkout
  • [ ] arch note MISSING -- no arch note exists for arch-email or any checkout-related arch component. [SCOPE] Create architecture note for the checkout/commerce component if one is needed, or use existing arch:basketball-api
  • [x] Forgejo issue -- #457, open

File Targets

  • [x] src/basketball_api/models.py -- verified: exists at /home/ldraney/basketball-api/src/basketball_api/models.py. ProductCategory.tournament at L126, ProductType.one_time at L117-120, Product class at L384. No Tournament model exists yet (correct, needs creation).
  • [ ] alembic/versions/032_add_tournament_tables.py -- ISSUE: Migration number 032 is almost certainly wrong. Local repo shows 030 as the latest numbered migration, but merged PRs reference migrations 040, 043, 044. The actual next migration slot must be determined from remote main. [BODY] Replace "032" with a note to use the next available migration slot (agent must check remote main HEAD).
  • [x] src/basketball_api/routes/admin.py -- verified: exists. Currently handles registration tokens, coach invitations, admin SPA dashboard.
  • [x] src/basketball_api/routes/checkout.py -- verified: exists. POST /create-session at L103, Stripe session creation at L221. Helper extraction target is clear.
  • [x] NOT-touch files correctly identified: services/email.py, services/email_queries.py, existing POST /create-session.

Repo Placement

OK -- issue filed on forgejo_admin/basketball-api, all file targets are in basketball-api. Single repo scope.

Dependencies

  • Sibling ticket: board item #993 (Forgejo issue #456, "Generic email blast system with pluggable audience queries", story:WS-S32) -- both in backlog. The sibling provides the tournament_committed query and {{checkout_url}} placeholder. This ticket can proceed independently since it only creates the checkout URLs; the blast system consumes them.
  • No blocking dependencies in in_progress or next_up columns.
  • Dependencies are documented in the Related section (good).

Acceptance Criteria

6 acceptance criteria. All are testable by an agent:
  • AC1-2: endpoint behavior, verifiable via test
  • AC3: Stripe session amount verification -- requires mock, achievable
  • AC4: Order record creation on payment -- verifiable via webhook mock test
  • AC5: Success/cancel URL behavior -- verifiable
  • AC6: Product category/type check -- simple assertion
Missing AC: No acceptance criterion for error cases (invalid tournament ID, player not on team, duplicate checkout link generation). Consider adding error-path criteria.

Blast Radius

Low. New models and endpoints don't modify existing checkout flow (POST /create-session stays untouched per scope). The helper extraction from checkout.py is the riskiest change -- if done incorrectly it could break existing self-service checkout. Test expectations cover this via integration test.

Decomposition Assessment

4 file targets in 1 repo, 6 acceptance criteria. Borderline but fits single agent pass: all changes are in basketball-api, logically cohesive (model + migration + 2 endpoints + 1 helper extraction). No decomposition needed.

Recommendation

  • [BODY] Fix migration number: replace "032_add_tournament_tables.py" with instruction to use next available migration slot from remote main HEAD. Current local shows 030 but remote has up to 044.
  • [LABEL] Change arch:email to arch:basketball-api on board item #994. This ticket is checkout/commerce architecture, not email.
  • [BODY] Add error-path acceptance criteria: invalid tournament ID returns 404, player not associated with team's product returns 400, duplicate link generation is idempotent or returns existing session.