feat: add division filter and exclude_ordered to jersey-reminder #247
No reviewers
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
ldraney/basketball-api!247
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "243-jersey-email-division-filter"
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?
Summary
Add optional
divisionandexclude_orderedquery params toPOST /admin/email/jersey-reminderso Marcus can target jersey reminder emails by division and skip parents who already ordered. Also updates the plain-text fallback with deadline messaging and commits the live ConfigMap template to the repo.Changes
src/basketball_api/routes/admin.py-- adddivision(str) andexclude_ordered(bool) query params with validation; filter parents by player division and skip already-ordered parentssrc/basketball_api/services/email.py-- update subject line to "Jersey Orders Open — Westside Kings & Queens"; replace "no rush" plain-text copy with rush (March 30) and final (April 10) deadline messagingemail-templates/jersey-reminder.html-- commit the live ConfigMap MJML-compiled template (912 lines) to the repo for CI/CDtests/test_jersey_reminder.py-- add 8 new tests: division filter (boys/girls), exclude_ordered, both combined, no-params backwards compat, invalid division 422, subject line, deadline copyTest Plan
pytest tests/test_jersey_reminder.py -v-- 16/16 pass (8 existing + 8 new)?division=boyssends only to boys-division parents?exclude_ordered=trueskips parents withjersey_option IS NOT NULLReview Checklist
Related
Related Notes
QA Review
Scope check
Code quality
divisionparam validated againstDivisionenum with 422 on invalid valuesexclude_orderedcorrectly filters at the application layer after query, scoped to relevant division when both params usedParent.players.any()for proper SQL-level filteringemail-templates/jersey-reminder.html(912 lines)Test coverage
Nits
None.
VERDICT: APPROVED
PR #247 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / pytest
admin.py -- Filtering logic (correct)
divisionparam validated against theDivisionenum with a clear 422 error message listing valid values. Good.Parent.players.any(Player.division == Division(division))-- correctany()semantics for the one-to-many relationship. This returns parents with at least one player in the target division.exclude_orderedlogic correctly scopesrelevant_playersto the target division when both params are combined. Theall()check onjersey_option is not Noneis the right predicate for "every relevant player already ordered."email.py -- Subject and plain-text (correct)
"Jersey Orders Open -- Westside Kings & Queens"as specified. Note: the old subject usedf"{tenant.name}"dynamically -- this is now hardcoded to the Westside brand. Acceptable for single-tenant use per the issue requirements.RUSH DEADLINE: March 30,FINAL DEADLINE: April 10) and removes the old "no rush" / "no pressure" / "take your time" copy. Matches acceptance criteria.Template (committed)
email-templates/jersey-reminder.htmlis 913 lines of MJML-compiled HTML. Uses{{jersey_url}}placeholder for the per-parent link -- correct pattern. No hardcoded tokens or credentials in the template. Contains expected branding (logo URL, color scheme, Westside Kings & Queens).Tests (comprehensive)
TestJerseyReminderDivisionFilterandTestJerseyReminderEmailContent:test_division_filter_boys_only-- verifies only boys-division parents receive emailtest_division_filter_girls_only-- verifies only girls-division parents receive emailtest_exclude_ordered_skips_ordered_parents-- verifies ordered parents are excludedtest_division_and_exclude_ordered_combined-- verifies both params work togethertest_no_params_sends_to_all-- backwards compatibilitytest_invalid_division_returns_422-- input validation error pathtest_subject_line_updated-- verifies exact subject stringtest_plain_text_has_deadline_copy-- verifies deadline messaging and absence of old copymixed_division_parentscreates three parents covering all filter combinations. Well-structured.get_gmail_clientandload_email_template-- no real email sends in tests.BLOCKERS
None.
NITS
Scope creep:
is_publicfield addition. TheAdminPlayerItemmodel gains anis_public: boolfield (and corresponding serialization inadmin_list_players). This is unrelated to the jersey-reminder division filter scope defined in issue #243. The issue explicitly lists file targets and this change is outside that scope. It shipped in a separate commit (feat: include is_public in admin players list response). Recommend splitting to its own ticket, but not blocking since the change is trivially correct and low-risk.Missing trailing newline in HTML template.
email-templates/jersey-reminder.htmlends without a newline (\ No newline at end of file). POSIX convention and most linters prefer a trailing newline.Hardcoded subject loses multi-tenant flexibility. The old
f"Jersey Options Available -- {tenant.name}"was tenant-aware. The new"Jersey Orders Open -- Westside Kings & Queens"hardcodes the brand. This is per the issue spec so it is intentional, but worth tracking if multi-tenant support ever matters.SOP COMPLIANCE
243-jersey-email-division-filterfollows{issue-number}-{kebab-case-purpose}conventionCloses #243presentis_publicfield addition is outside issue #243 scope (nit, not blocking)PROCESS OBSERVATIONS
is_publicaddition is the one exception).mixed_division_parentscreates exactly the right combination of states to verify all filter paths.chore: revert unrelated test_admin_spa.py change) shows the dev agent caught and reverted an unrelated change. Good discipline.exclude_orderedlogic correctly handles the edge case where division filtering narrows the "relevant players" before checking jersey order status. This is a subtle interaction and it's both implemented and tested correctly.VERDICT: APPROVED