Review: Bug: parent phone missing from /admin/players list endpoint

review-736-2026-04-03 Doc

review ready

Verdict: READY

Template Completeness

  • [x] Type — Bug
  • [x] Lineage — Standalone, discovered during admin CRM audit
  • [x] Repo — forgejo_admin/basketball-api
  • [x] What Broke — clear description of missing parent_phone field
  • [x] Repro Steps — concrete steps with specific player/parent IDs
  • [x] Expected Behavior — clearly stated
  • [x] Environment — prod / basketball-api namespace
  • [x] Acceptance Criteria — 4 criteria, all testable
  • [x] Related — project reference and companion frontend ticket mentioned

Traceability

  • [x] story:WS-S12 — "As an admin, I want to manage user accounts (reset passwords, view profiles) so that I can support parents directly"
  • [x] story note verified — found in project-westside-basketball user-stories section (Admin stories list)
  • [x] arch:basketball-api — references the basketball-api service
  • [ ] arch note MISSING — [SCOPE] No arch-basketball-api note found in pal-e-docs. Platform-wide gap, not blocking this ticket.
  • [x] Forgejo issue — forgejo_admin/basketball-api#276, open

File Targets

Issue does not specify exact file paths. Reviewer verified the bug location:
  • [x] src/basketball_api/routes/admin.py:290-297AdminPlayerItem Pydantic model has parent_name and parent_email but no parent_phone field. Confirmed.
  • [x] src/basketball_api/routes/admin.py:342-358 — Constructor call builds AdminPlayerItem without parent_phone. Confirmed.
  • [x] src/basketball_api/routes/admin.py:526 — CSV export endpoint DOES include parent_phone: p.parent.phone or "", proving the parent join already loads the phone. Fix pattern exists.
  • [x] tests/test_admin_spa.py:236-249test_response_fields checks expected fields but does not include parent_phone. Test must be updated.

Repo Placement

OK. Issue is filed on forgejo_admin/basketball-api, and the fix is entirely within that repo. The companion frontend ticket (westside-app) is correctly scoped as a separate issue.

Dependencies

  • [x] Parent join already loaded — joinedload(Player.parent) at line 318. No additional query needed.
  • [x] Parent.phone column exists in database — no migration required.
  • [x] No blocking items on the board.
The westside-app companion ticket depends on THIS ticket, not the other way around. No blockers.

Acceptance Criteria

All 4 criteria are agent-verifiable:
  • [x] AC1: "GET /admin/players response includes parent_phone field" — testable via existing test pattern in test_admin_spa.py
  • [x] AC2: "parent_phone value matches parents.phone from database" — testable with populated_db fixture
  • [x] AC3: "parent_phone is null for players with no parent phone set" — testable with fixture data (set phone=None)
  • [x] AC4: "Existing admin list functionality unchanged" — existing tests cover filters, sorting, pagination

Blast Radius

  • Same pattern exists: IncompletePlayerItem (admin.py:403-409) also omits parent_phone. Separate follow-up scope.
  • SubscriptionListItem (subscriptions.py:57-64) also omits parent_phone. Different endpoint, different concern.
  • Roster endpoint (roster.py:24) already includes parent_phone. No issue.
  • Tryouts endpoint (tryouts.py:456) already includes parent_phone. No issue.
  • Rollback is trivial — revert the field addition. No data changes.

Decomposition Assessment

Apply the three-thing limit and five-minute rule:
  • Discrete changes: 2 (add field to Pydantic model + pass in constructor). Well under 3.
  • Test changes: 1 file (test_admin_spa.py field list update). Total: 2 files touched.
  • Estimated agent time: under 2 minutes.
  • No independent subtasks to parallelize.
No decomposition needed.

Recommendation

  • [SCOPE] Create architecture note arch-basketball-api for the basketball-api service (platform-wide gap, not blocking this ticket).
  • [BODY] Consider adding explicit file targets to the issue body for agent consumption: src/basketball_api/routes/admin.py (AdminPlayerItem model + constructor) and tests/test_admin_spa.py (test_response_fields).
Neither recommendation blocks dispatch. Ticket is READY.