fix: coach Stripe retry + backfill scripts #40
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
forgejo_admin/basketball-api!40
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/coach-stripe-retry"
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
Changes
src/basketball_api/routes/coach.py: GET/coach/onboardnow detectsagreement_signed+ nostripe_connect_account_idand retries Stripe account creation instead of redirect-looping to statustests/test_coach.py: Updated existing test, added test for retry-creates-account pathscripts/backfill_stripe.py: New script — imports Stripe checkout sessions into DB (idempotent, dry-run by default)scripts/send_registration_emails.py: New script — sends branded registration emails to un-emailed paid parents (dry-run by default,--test-emailfor preview)Test Plan
agreement_signed+ no Stripe account visits/coach/onboard?token=...→ Stripe account created → redirected to Stripe onboardinghttps://basketball-api.tail5b443a.ts.net/coach/onboard?token=PZzOc6aDt5X5LqoUor0HhNkPI4XfxolkuTmY9qbRUtMReview Checklist
Related
plan-2026-03-08-tryout-prep— Phase 3b: Email blast (subphases 3b-iii + 3b-iv)PR #40 Review
BLOCKERS
None. The core fix is correct and the scripts are well-structured with safe defaults.
NITS
File handle leak in
scripts/backfill_stripe.pyline 168.args.stripe_key = open(key_file).read().strip()-- should use awithstatement orpathlib.Path(key_file).read_text().strip(). Not dangerous for a one-shot CLI script, but poor practice.Unused import in
scripts/backfill_stripe.pyline 34.Baseis imported frombasketball_api.modelsbut never used. Ruff would flag this.Fragile email mutation in
scripts/send_registration_emails.pylines 118-122.The
--test-emailpath temporarily overwritesparent.emailon a SQLAlchemy-tracked object, sends the email, then restores it. Ifsend_confirmation_email(or anything it calls) triggers a session flush, the test address could be persisted to the DB. Currently safe becausesend_confirmation_emaildoes not commit, but this is brittle. Safer approach: pass the email override directly or usedb.expunge(parent)/ work on a copy.No tests for the two new scripts.
scripts/backfill_stripe.pyandscripts/send_registration_emails.pyare non-trivial (221 and 148 lines respectively) with real business logic (backfill_session,get_unsent_parents). Thebackfill_sessionfunction andextract_custom_fieldswould benefit from unit tests -- they are pure-ish functions that could be tested without Stripe API access. Acceptable as operational scripts for a time-sensitive launch, but worth a follow-up.Potential duplicate players across sessions for the same parent.
In
backfill_stripe.py, if two Stripe sessions exist for the same parent email but with differentstripe_checkout_session_idvalues (e.g., a parent who paid for two kids), a new Player is always created. This is likely correct behavior for multi-child families, but if the same child appears in two sessions (e.g., a failed-then-retried checkout), a duplicate Player record will be created. The dedup is only onstripe_checkout_session_id, not on parent+player_name. Worth noting for the backfill operator.Code duplication in coach.py.
The Stripe account creation + redirect + error handling block (lines 158-172 in the new code) is nearly identical to the same block in
signup_submit(lines 130-143) andaccept_agreement(lines 220-233). Three copies of the same try/except pattern. A helper like_create_stripe_and_redirect(db, coach, token)would reduce this. Non-blocking.SOP COMPLIANCE
fix/coach-stripe-retry, not20-*orissue-20-*. This is a combined fix + feature PR so the descriptive name is understandable, but it does not follow the issue-number convention.plan-2026-03-08-tryout-prepreferenced.VERDICT: APPROVED
The core fix in
coach.pyis correct and well-tested. Whencontractor_agreement_signedis true butstripe_connect_account_idis null, the route now retries Stripe account creation instead of redirecting to a status page that would bounce back -- breaking the loop. The error path gracefully renders a status page with an error message rather than crashing.The backfill scripts are operationally sound with dry-run defaults, idempotent processing, and clear logging. The nits above are all non-blocking quality improvements that can be addressed in a follow-up.