Create docs/monthly-billing-runbook.md (analog of tournament-billing-runbook) #504

Open
opened 2026-04-18 06:09:06 +00:00 by forgejo_admin · 0 comments

Type

Feature

Lineage

Standalone — discovered 2026-04-18 during QA review of PR #499. docs/tournament-billing-runbook.md exists and covers the Payment Link operational surface for tournaments; no equivalent exists for monthly-fee. QA flagged the gap.

Repo

forgejo_admin/basketball-api

User Story

As Marcus or a future dev responding to a monthly-fee billing issue, I can open docs/monthly-billing-runbook.md and find the operational surface: how links are minted, when they deactivate, what to do when a parent reports a broken URL, how to re-mint a fresh Payment Link for a pending order. Same reference material we now have for tournaments.

Context

With PR #499 merged, the monthly-fee flow uses Stripe Payment Links (no expiry) minted by services/monthly_checkout.py::create_monthly_order_payment_link from routes/checkout.py::first_payment_checkout. Emails embed {base_url}/checkout/first-payment?token=... which redirects to Order.stripe_checkout_url. Payment Links deactivate on successful payment via the webhook gate widened in PR #499.

All of that is now tribal knowledge in the PR description. It should be in a runbook so (a) Marcus can self-serve on "why isn't this parent paying?", (b) the next dev touching this area doesn't re-read #494 + #498 + #499 to reconstruct context, (c) the #497 recovery ticket can link to it as the mechanical-recovery reference.

File Targets

  • NEW: docs/monthly-billing-runbook.md
  • REFERENCE (read-only, mirror structure): docs/tournament-billing-runbook.md

Scope

Author a monthly analog of the tournament runbook. Sections to mirror:

  1. Mint path: where links come from in code (first_payment_checkout, services/monthly_checkout.py).
  2. Email embed: what's in the parent's inbox (redirect URL, not Stripe URL); the contract-status re-check on click.
  3. Lifecycle: Payment Link stays active indefinitely until payment; webhook deactivates on success; Price + Product remain (per #503 cleanup ticket).
  4. Per-parent amounts: how Order.amount_cents drives the minted Price (scholarships, prorations, custom contracts).
  5. Recovery playbook: for any single parent whose link needs regeneration outside the blast recovery in #497. Step-by-step.
  6. Troubleshooting: common symptoms ("parent says link doesn't work," "payment didn't flip order to paid"), mapping each to the webhook log, stripe_customer_id back-fill, and the Stripe dashboard view.

Acceptance Criteria

  • docs/monthly-billing-runbook.md exists and is published alongside docs/tournament-billing-runbook.md
  • Same top-level section structure as the tournament runbook
  • Runbook links back to #494, #498, #499 for PR-level history
  • Recovery procedure verified by walking through it on a test-mode order (dry-run)

Test Expectations

  • Dry-run walkthrough: pick one pending monthly-fee order in test-mode Stripe, follow the runbook's Recovery playbook end-to-end, confirm each documented step produces the expected state (fresh Payment Link minted, Order.stripe_checkout_url updated, apology-or-manual-nudge path clear).
  • Doc-build/markdown lint passes (if the repo has a docs linter; if not, no-op).
  • Runbook reviewed for broken cross-references to code paths (filenames + line-range hints stay current).

Constraints

  • Do NOT copy the tournament runbook verbatim and do-a-find-replace — the monthly flow differs on setup_future_usage, amount_cents vs product.price_cents, and the redirect. Write for monthly's specifics.
  • Do NOT include any parent-identifiable info in the runbook.

Checklist

  • PR opened
  • Runbook reviewed by at least one dev who did NOT work on #499
  • Linked from docs/README.md (or whatever the docs index is)
  • forgejo_admin/basketball-api #494 — tournament migration
  • forgejo_admin/basketball-api #498 — monthly migration (PR #499)
  • forgejo_admin/basketball-api #497 — monthly recovery (will link this runbook for mechanical procedure)
  • docs/tournament-billing-runbook.md — structural reference
### Type Feature ### Lineage Standalone — discovered 2026-04-18 during QA review of PR #499. `docs/tournament-billing-runbook.md` exists and covers the Payment Link operational surface for tournaments; no equivalent exists for monthly-fee. QA flagged the gap. ### Repo `forgejo_admin/basketball-api` ### User Story As Marcus or a future dev responding to a monthly-fee billing issue, I can open `docs/monthly-billing-runbook.md` and find the operational surface: how links are minted, when they deactivate, what to do when a parent reports a broken URL, how to re-mint a fresh Payment Link for a pending order. Same reference material we now have for tournaments. ### Context With PR #499 merged, the monthly-fee flow uses Stripe Payment Links (no expiry) minted by `services/monthly_checkout.py::create_monthly_order_payment_link` from `routes/checkout.py::first_payment_checkout`. Emails embed `{base_url}/checkout/first-payment?token=...` which redirects to `Order.stripe_checkout_url`. Payment Links deactivate on successful payment via the webhook gate widened in PR #499. All of that is now tribal knowledge in the PR description. It should be in a runbook so (a) Marcus can self-serve on "why isn't this parent paying?", (b) the next dev touching this area doesn't re-read #494 + #498 + #499 to reconstruct context, (c) the #497 recovery ticket can link to it as the mechanical-recovery reference. ### File Targets - NEW: `docs/monthly-billing-runbook.md` - REFERENCE (read-only, mirror structure): `docs/tournament-billing-runbook.md` ### Scope Author a monthly analog of the tournament runbook. Sections to mirror: 1. **Mint path:** where links come from in code (`first_payment_checkout`, `services/monthly_checkout.py`). 2. **Email embed:** what's in the parent's inbox (redirect URL, not Stripe URL); the contract-status re-check on click. 3. **Lifecycle:** Payment Link stays active indefinitely until payment; webhook deactivates on success; Price + Product remain (per #503 cleanup ticket). 4. **Per-parent amounts:** how `Order.amount_cents` drives the minted Price (scholarships, prorations, custom contracts). 5. **Recovery playbook:** for any single parent whose link needs regeneration outside the blast recovery in #497. Step-by-step. 6. **Troubleshooting:** common symptoms ("parent says link doesn't work," "payment didn't flip order to paid"), mapping each to the webhook log, `stripe_customer_id` back-fill, and the Stripe dashboard view. ### Acceptance Criteria - [ ] `docs/monthly-billing-runbook.md` exists and is published alongside `docs/tournament-billing-runbook.md` - [ ] Same top-level section structure as the tournament runbook - [ ] Runbook links back to #494, #498, #499 for PR-level history - [ ] Recovery procedure verified by walking through it on a test-mode order (dry-run) ### Test Expectations - [ ] Dry-run walkthrough: pick one pending monthly-fee order in test-mode Stripe, follow the runbook's Recovery playbook end-to-end, confirm each documented step produces the expected state (fresh Payment Link minted, Order.stripe_checkout_url updated, apology-or-manual-nudge path clear). - [ ] Doc-build/markdown lint passes (if the repo has a docs linter; if not, no-op). - [ ] Runbook reviewed for broken cross-references to code paths (filenames + line-range hints stay current). ### Constraints - Do NOT copy the tournament runbook verbatim and do-a-find-replace — the monthly flow differs on `setup_future_usage`, `amount_cents` vs `product.price_cents`, and the redirect. Write for monthly's specifics. - Do NOT include any parent-identifiable info in the runbook. ### Checklist - [ ] PR opened - [ ] Runbook reviewed by at least one dev who did NOT work on #499 - [ ] Linked from `docs/README.md` (or whatever the docs index is) ### Related - `forgejo_admin/basketball-api #494` — tournament migration - `forgejo_admin/basketball-api #498` — monthly migration (PR #499) - `forgejo_admin/basketball-api #497` — monthly recovery (will link this runbook for mechanical procedure) - `docs/tournament-billing-runbook.md` — structural reference
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/basketball-api#504
No description provided.