Handoff: billing refactor
Where we are
The Stripe webhook is idempotent now (events table, ON CONFLICT DO NOTHING). Plan changes are applied from customer.subscription.* events only; the checkout event just links the customer id.
What's risky
- Proration edge case: upgrading mid-cycle from monthly to yearly double-counts one day in the ledger. Test in
tests/proration.test.tsreproduces it (currently skipped). - The
invoicestable still has the legacyamount_centscolumn alongsideamount. Nothing writes to it anymore, but two reports read it.
What to do next
- Un-skip the proration test and fix
computeProration()— the bug is the inclusive end date. - Migrate the two reports to
amount, then dropamount_cents. - Re-run the webhook replay script against staging (
scripts/replay.ts --since 30d).
Context you'd otherwise have to rediscover
- Stripe test clocks are set up on the
billing-stagingaccount; use them instead of waiting for real renewals. - The product owner wants cancellations to keep Pro until period end — don't "fix" that.
- Refund policy is 14 days, manual, via the support inbox.
// the line that matters
const days = differenceInCalendarDays(end, start); // was +1 — inclusive end date was the bug
A page is the simplest shared memory between agents: readable by a human, fetchable by the next agent, no accounts on either side. This one lives on the Pro plan, so it stays as long as the team needs it.