Review: Email: Queens practice — Friday → Wednesday Granger
Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, Queens schedule change
- [x] Repo — forgejo_admin/basketball-api
- [x] User Story — As admin, send email about schedule change
- [x] Context — Friday BWill → Wednesday Granger, 14 Queens parents, DB already updated
- [x] File Targets — 3 files to modify/create, 2 exclusions listed
- [x] Acceptance Criteria — 5 criteria
- [x] Test Expectations — test email + pytest
- [x] Constraints — references existing patterns, gmail-sdk, test_email param
- [x] Checklist — present
- [x] Related — project + seed issue #279
Traceability
- [x] story:WS-S7 label — "As an admin, I want to send branded email announcements so that parent comms are professional and consistent" — verified on project-westside-basketball user-stories section under Admin (Marcus)
- [x] story note verified — found in project-westside-basketball user-stories section
- [x] arch:basketball-api label — references the basketball-api service
- [ ] arch note MISSING — no arch-basketball-api note found in pal-e-docs. [SCOPE] Create architecture note arch-basketball-api for the basketball API service. (Non-blocking — shared gap across all basketball-api tickets.)
- [x] Forgejo issue — forgejo_admin/basketball-api#311, open
File Targets
- [x]
src/basketball_api/services/email.py— verified: exists, 1219+ lines, contains 7 existing send_*_email functions. Pattern clear: add new function following send_jersey_reminder_email pattern (line 1140). - [x]
src/basketball_api/templates/— directory does NOT exist. Ticket correctly says "if MJML dir exists, otherwise inline HTML." Existing templates load from external /data/email-templates via load_email_template(). Agent should use load_email_template() with fallback to inline HTML, matching jersey-reminder pattern. - [x]
src/basketball_api/routes/admin.py— verified: exists, has 4 existing POST /email/* endpoints (profile-reminder, roster-export, tryout-announcement, jersey-reminder). Pattern is clear: add POST /email/practice-schedule following jersey-reminder pattern (line 847). - [x] Exclusion:
models.py— correct, no model changes needed. Division enum (boys/girls) and Team.division already exist. - [x] Exclusion:
routes/schedule.py— correct, schedule routes not involved
Repo Placement
Correct. Issue filed on forgejo_admin/basketball-api, all file targets are in basketball-api. Single-repo change.
Dependencies
- No blockers. Ticket is standalone.
- Sibling tickets in backlog under same story:WS-S7: #763 (Welcome to first practice email), #764 (Local teams no Monday email). Independent — no ordering dependency.
- #758 (incomplete_profiles query) in needs_approval — unrelated, no conflict.
- References #279 (practice schedule data seeding) which is done — DB data already seeded.
Acceptance Criteria
- [x] Division filter (girls) — testable. Division enum exists in models (Division.girls). Query path: Team.division == girls → player_teams join → Parent. Clear implementation.
- [x] Email content (schedule details, Granger address) — testable via test_email param + visual inspection.
- [x] Exclude TEST players — testable. Player.name.contains("TEST") filter. No existing pattern but straightforward to add.
- [x] Log to email_log — testable. EmailLog model exists (line 363 of models.py), used by all existing send functions.
- [x] Test mode (single address) — testable. Existing pattern: test_email query param on jersey-reminder endpoint (line 849 of admin.py).
All 5 AC are verifiable by an agent. Test commands are real (pytest tests/ -k email).
Blast Radius
- Low. New endpoint + new function — no modifications to existing email functions.
- Queens-only filter means only 14 parents affected in production.
- test_email param provides safety gate before blast.
- No downstream consumers affected — this is a new endpoint.
- Rollback: delete endpoint + function. No migrations, no model changes.
Decomposition Assessment
Apply the three-thing limit and five-minute rule:
- File count: 2-3 files in 1 repo — under the 3-file threshold
- AC count: 5 acceptance criteria — at the boundary but all are closely related (same endpoint, same email)
- Estimated agent work: ~3 minutes (add email function + add route endpoint + write test)
- No independent subtasks that need parallelization — all changes are tightly coupled
No decomposition needed.
Recommendation
- [SCOPE] Create architecture note arch-basketball-api for the basketball API service. (Non-blocking — shared gap across all basketball-api tickets, not specific to this one.)
No other action needed. Ticket is well-scoped with clear file targets, verified patterns, and testable AC.