Review: Add jersey fields to AdminPlayerItem response
Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — Decomposed from westside-landing#183
- [x] Repo — forgejo_admin/basketball-api
- [x] User Story — As Marcus (admin), I want admin players API to return jersey fields
- [x] Context — Explains gap between Player model and AdminPlayerItem response model
- [x] File Targets — Modify list and do-not-touch list both present
- [x] Acceptance Criteria — 5 criteria, all testable
- [x] Test Expectations — Unit tests specified with run command
- [x] Constraints — Pattern matching and no-migration guard
- [x] Checklist — Present
- [x] Related — project-westside-basketball + parent issue linked
Traceability
- [x] story:WS-S9 — "As an admin, I want to track payment status per player so that I know who owes what" — found in project-westside-basketball user-stories section under Admin (Marcus)
- [x] arch:basketball-api — component identified on board item labels
- [ ] arch note MISSING — [SCOPE] No arch-basketball-api note found in pal-e-docs. Pre-existing gap, not a blocker for this ticket.
- [x] Forgejo issue — forgejo_admin/basketball-api#248, state: open
File Targets
- [x]
src/basketball_api/routes/admin.py— verified: AdminPlayerItem Pydantic model at line 289 has 13 fields, none are jersey fields. Query populates at lines 342-357. Adding 4 fields to BaseModel + 4 lines to constructor is accurate (~8 lines total). - [x]
src/basketball_api/models.py(do-not-touch) — verified: jersey_option (line 240), jersey_order_status (line 243), jersey_size (line 246), jersey_number (line 249) all exist on Player model as expected. - [x]
src/basketball_api/routes/jersey.py(do-not-touch) — correctly excluded - [x]
src/basketball_api/routes/checkout.py(do-not-touch) — correctly excluded
Repo Placement
Correct. Issue filed on forgejo_admin/basketball-api, all file targets are in basketball-api. Single-repo change. The downstream CRM frontend work is correctly filed as a separate issue on westside-landing (#183).
Dependencies
- [x] westside-landing#183 (CRM frontend) depends on this ticket — confirmed open, explicitly declares basketball-api#248 as a backend blocker. This ticket has no inbound blockers.
- [x] Board item #534 (Show contract status in admin CRM player list, story:WS-S9) — done. Same pattern (adding fields to AdminPlayerItem). Agent can reference as prior art.
Acceptance Criteria
All 5 criteria are testable via JSON response assertions. Each specifies a field name and expected type (string or null, or string enum). The jersey_order_status enum values (none/pending/paid/shipped) match JerseyOrderStatus in models.py (lines 97-101). The "existing behavior unchanged" criterion is covered by existing tests in test_admin_spa.py which will continue to pass since the change is purely additive.
Blast Radius
- Low. Additive-only change to one response model in one file.
- Existing test
test_admin_spa.py::TestAdminPlayersEndpoint::test_response_fields(line 226) checks a subset of fields, not an exact set — will still pass. test_contract.py(line 350) also calls GET /admin/players — additive, no breakage.- No other consumers of AdminPlayerItem outside admin.py.
- Agent must use
.valueserialization for enums (e.g.,player.jersey_option.value if player.jersey_option else None) matching the existing pattern at line 352 (player.division.value if player.division else None). - Rollback: revert one commit, no migration involved.
Decomposition Assessment
No decomposition needed. 1 file target, 5 acceptance criteria (all in same file), estimated <2 minutes agent time. Well within the three-thing limit and five-minute rule. No independent subtasks to parallelize.
Recommendation
- [BODY] Fix test run command:
pytest tests/test_admin.py -vshould bepytest tests/test_admin_spa.py -v. The test_admin.py file covers token generation and coach invitations, not the /admin/players endpoint. New jersey-field tests should be added to test_admin_spa.py. - [SCOPE] Create architecture note arch-basketball-api for component basketball-api (pre-existing gap across the board, not a blocker for this ticket).