2 Commits
Author SHA1 Message Date
Moheeb Zara b477c38425 fix(billing): deep-audit P0/P1 fixes for the pinned Stripe API (2026-04-22.dahlia)
Independent audit (verified vs Stripe Basil 2025-03-31 changelog):
- P0: period end moved off the top-level Subscription -> read
  sub.items.data[0].current_period_end (grace/lapse now actually fires;
  was always null -> past_due members never went 'late').
- P0: invoice subscription metadata moved under invoice.parent.
  subscription_details -> read parent (metadata member-resolution was
  always failing, mislinking dues payments).
- P1: handle only invoice.paid (not also invoice.payment_succeeded) +
  pre-insert dedupe on (space_id,platform,external_id) -> no double
  payment-ledger rows.
- P2: idempotencyKey on customers.create -> no duplicate Stripe
  customers under concurrent checkout.
- 040: documented the 'do not wrap in manual BEGIN/COMMIT' caveat.
(P0 webhook-reprocess-on-failure was fixed in ca34e53.) Audit verdict:
isolation/secrets/RLS/status-bounds were already sound.
2026-05-17 03:46:08 -07:00
Moheeb Zara 521df696a2 feat(billing): P1a Stripe schema — payment_platform 'stripe' + member_billing + webhook ledger
Migration 040 (mirrored in schema.sql Section 25 + the CREATE TYPE
list): ALTER TYPE payment_platform ADD VALUE 'stripe' (only safe path;
not used as a literal in the same migration); member_billing (member<->
Stripe customer/subscription/status/period; RLS SELECT = admin/board/
treasurer, NO client write policy — webhook/service-client only);
stripe_webhook_events idempotency ledger (PK = Stripe event id, service-
only, no policy). Per-space OWN keys: secrets->vault, config->
integrations.config. types + DATABASE_SCHEMA + DB_SCHEMA_MAP.
2026-05-17 02:57:58 -07:00