Review: Email: Queens practice — Friday → Wednesday Granger

review-762-2026-04-03 Doc

review ready

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.