Generic email blast system with pluggable audience queries #456
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api#456
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
Standalone — discovered during Utah Invitational tournament fee billing (2026-04-12). Every new email type currently requires a new hardcoded endpoint.
sop-email-senddescribes a generic blast system that doesn't exist yet.Repo
forgejo_admin/basketball-apiUser Story
As an admin
I want a generic email blast system with pluggable audience queries
So that new email types ship as config, not code changes
Context
basketball-api has 4 hardcoded email endpoints in
routes/admin.py(profile-reminder at L438, roster-export at L487, tryout-announcement at L551, jersey-reminder at L847). Each has audience logic baked in.sop-email-sendandarch-emaildescribe a horizontal system withemail_queries.pyregistry andPOST /email/blast— neither exists. The EmailType enum (models.py L63-70) has 7 values, none for tournament fees. Emails are inline HTML inservices/email.py(9 send functions).brand.pyhas Kings red/black CSS constants but NO Queens pink tokens — those must be added.File Targets
Files the agent should modify or create:
src/basketball_api/services/email_queries.py— NEW. Query registry: dict mapping names to functions returning(player, parent, team)tuples. Seed withtournament_committed(team_ids).src/basketball_api/services/email.py— Addbuild_action_email(headline, body, cta_text, cta_url, footer_note, team_gender)reusable builder using brand.py tokens. Kings=red, Queens=pink.src/basketball_api/brand.py— Add Queens pink design tokens (COLOR_PINK,COLOR_PINK_HOVER, etc.) alongside existing Kings red tokens. Check existing email functions in email.py for any inline pink values to extract.src/basketball_api/routes/admin.py— AddPOST /admin/email/blastaccepting: query_name, email_type, subject, data dict, optional test_email, optional query_params. Uses query registry, builds email, sends via Gmail SDK, logs to EmailLog.src/basketball_api/models.py— Extend EmailType enum (L63-70) withtournament_fee,payment_request.alembic/versions/NNN_add_email_types.py— NEW. Determine the next available migration number from remote main HEAD (do NOT hardcode — checkalembic/versions/for the latest slot).Files the agent should NOT touch:
routes/checkout.py— checkout link generation is separate ticket #457Acceptance Criteria
POST /admin/email/blastwithtest_email=draneylucas@gmail.comsends a single branded emailPOST /admin/email/blastwithouttest_emailsends to full query audiencetournament_committedquery returns players from specified team IDs{{player_name}},{{parent_name}},{{team_name}},{{checkout_url}}resolve correctlyTest Expectations
test_email_queries.py— tournament_committed returns correct players for given team_idstest_build_action_email— HTML contains headline, CTA, correct brand colors for both Kings (red) and Queens (pink)test_blast_endpoint— blast with test_email sends one email, creates EmailLogpytest tests/ -k "email_queries or build_action or blast"Constraints
build_action_emailmust produce table-based inline-style HTML (Gmail strips CSS)sop-email-sendapproval gate for actual blastsChecklist
Related
project-westside-basketball— parent projectstory:WS-S32— user storyarch-email(pal-e-docs slug:arch-email) — architecture doc (target state this implements)sop-email-send(pal-e-docs slug:sop-email-send) — SOP this makes real{{checkout_url}}placeholder support), #448 (player_ids filter — needs blast endpoint)Scope Review: NEEDS_REFINEMENT
Review note:
review-993-2026-04-12Well-structured feature ticket with thorough context and testable AC. Two file target errors and two missing backing notes block advancement.
Must fix before dispatch:
[BODY]Migration number031is wrong -- Forgejo main has migrations through 044. Next slot is 045+. Either correct the number or instruct agent to auto-detect.[BODY]Queens pink color tokens do not exist inbrand.pyoremail.py. Add to File Targets (modify brand.py or email.py constants).[BODY]Document downstream dependencies: #457 (tournament checkout) and #448 (player_ids filter) depend on this blast endpoint.[SCOPE]arch-emailarchitecture note does not exist in pal-e-docs. Create it.[SCOPE]sop-email-sendreferenced in body/Related does not exist in pal-e-docs. Create it or remove the reference.Scope refinement from review-993-2026-04-12 (NEEDS_REFINEMENT):
Five items flagged, three fixed, two disputed:
Fixed:
031toNNNwith instruction to determine next slot from remote main HEAD. Remote has migrations up to 044.brand.pyto File Targets with explicit instruction to add pink design tokens. Current brand.py only has Kings red/black.Disputed (false positives):
4.
arch-emailnote DOES exist in pal-e-docs — confirmed viaget_note_toc(slug="arch-email")returning sections: Overview, Components, Layouts, Email Flow, Preview & Approval Workflow, Decisions.5.
sop-email-sendnote DOES exist — confirmed viaget_note(slug="sop-email-send")returning full content (note id 1108, status: active, project: westside-basketball). QA agent likely had an MCP lookup issue.Scope Re-Review: NEEDS_REFINEMENT
Review note:
review-993-2026-04-12(updated)Disputed items resolved: Both
arch-emailandsop-email-sendexist in pal-e-docs. Previous review's search was spurious. These are no longer flagged.3 claimed fixes NOT present in the issue body:
031— should beNNNwith instruction to determine next slot from remote main (local=030, remote likely 044+)brand.pynot listed as a separate file target — needsCOLOR_PINKtoken for Queens branding (currently has onlyCOLOR_RED)All 3 are
[BODY]fixes — straightforward edits to the issue text.