Review: Admin blast endpoint /email/blast (re-review)

review-752-2026-04-03-r2 Review

review ready

Verdict: READY

Re-review of board item #752 (forgejo_admin/basketball-api#295). Previous review: review-752-2026-04-03 (NEEDS_REFINEMENT). Three items were raised; all three are now resolved.

Previous Findings Resolution

  • [x] [SCOPE] arch-email note created — arch-email exists in pal-e-docs with sections: Overview, Components, Layouts, Email Flow, Decisions. Traceability triangle complete.
  • [x] [BODY] Explicit ### Blockers section added to issue body — clearly states "This ticket CANNOT be built until both upstream tickets are merged and deployed" with references to #293 and #294.
  • [x] [LABEL] blocked-by:293 and blocked-by:294 labels added to board item #752. Uses Forgejo issue numbers (not board item IDs). Acceptable — issue numbers are the canonical reference.

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — depends on MJML system + send_templated_email() tickets; supersedes board item #724
  • [x] Repo — forgejo_admin/basketball-api
  • [x] User Story — clear admin-wants-blast-endpoint story
  • [x] Context — explains current hardcoded pattern, decision to genericize, query registry design
  • [x] Blockers — explicit hard blocker section referencing #293 and #294
  • [x] File Targets — specific create/modify/do-not-touch paths
  • [x] Acceptance Criteria — 7 testable conditions
  • [x] Test Expectations — 5 unit tests with run command
  • [x] Constraints — query return shape, placeholder format, auth dependency, pattern matching
  • [x] Checklist — PR opened, tests pass, no unrelated changes
  • [x] Related — project link, arch note, superseded ticket, dependency tickets

Traceability

  • [x] story:WS-S7 label — "As an admin, I want to send branded email announcements so that parent comms are professional and consistent"
  • [x] story:WS-S7 note verified — found in project-westside-basketball user-stories section (Admin stories)
  • [x] story:WS-S22 label — "As a parent, I want to receive clear email communications with action links so that I never miss a deadline"
  • [x] story:WS-S22 note verified — found in project-westside-basketball user-stories section (Parent stories)
  • [x] arch:email label — email architecture component
  • [x] arch note verified — arch-email note exists in pal-e-docs (project: westside-basketball). Sections: Overview, Components, Layouts, Email Flow, Decisions.
  • [x] Forgejo issue — forgejo_admin/basketball-api#295, open

File Targets

  • [x] src/basketball_api/services/email_queries.py — to create. Does not exist yet. Parent directory services/ exists with 10 existing modules. Correct.
  • [x] src/basketball_api/routes/admin.py — verified exists. Has require_admin dependency (line 48), existing email endpoints at /email/profile-reminder (line 438), /email/roster-export (line 487), /email/tryout-announcement (line 551), and /email/jersey-reminder (line 847). Good placement for new endpoint.
  • [x] src/basketball_api/services/email.py — listed as NOT to touch. Confirmed: has load_email_template() (line 1107). Correct boundary.
  • [x] contract_token column — verified on Player model (models.py line 232), unique constraint exists
  • [x] contract_signed_at column — verified on Player model (models.py line 229)
  • [x] EmailLog model — verified at models.py line 363

Repo Placement

Correct. Issue filed on forgejo_admin/basketball-api, all file targets are in that repo. Single-repo scope.

Dependencies

  • [x] Board item #750 (Issue #293: MJML email system) — in backlog. Hard blocker, documented in Blockers section and via blocked-by:293 label.
  • [x] Board item #751 (Issue #294: send_templated_email()) — in backlog. Hard blocker, documented in Blockers section and via blocked-by:294 label.
  • [x] Board item #724 (Contract reminder email endpoint) — superseded by this ticket per Lineage. No conflict.
Dependencies are now fully documented in three places: Lineage section, Blockers section, and board item labels. Execution order is clear: #293 first, then #294, then #295.

Acceptance Criteria

7 acceptance criteria — all specific and programmatically verifiable. Test run command is concrete: pytest tests/test_admin_email.py -v. No changes from previous review.

Blast Radius

Low. Single endpoint addition, no schema changes. Existing 4 email endpoints explicitly excluded. Query registry is a new self-contained pattern. load_email_template() is a pure function — safe to call. Rollback is straightforward.

Decomposition Assessment

2 file targets (1 create, 1 modify) across 1 repo. 7 AC tightly coupled to a single endpoint. Estimated agent time: 3-4 minutes. No decomposition needed.

Recommendation

No action needed. All three items from the previous review have been resolved. Ticket is ready for execution once blockers #293 and #294 are merged.