feat(billing): TD-13 webhook idempotency + Stripe Customer Portal + doc cleanup

- Table stripe_webhook_events + helpers isEventProcessed/markEventProcessed
- POST /stripe/customer-portal (auth + stripe_customer_id check)
- ARCHITECTURE-backend.md: suppression POST /plans/upgrade (duplication doc)
- TD-13 fermé dans TECH_DEBT-backend.md
- Tests: 261 → 278 verts (+17)
This commit is contained in:
Hermann_Kitio 2026-04-26 04:15:46 +03:00
parent ec0598d122
commit 6671bac347
10 changed files with 891 additions and 324 deletions

View file

@ -6,6 +6,34 @@ Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/).
---
## [Unreleased] — 2026-04-26 — Sprint 5a — Backend billing cleanup
### Added
- `supabase/migrations/007_sprint_5a_stripe_webhook_events.sql` — table `stripe_webhook_events(id TEXT PRIMARY KEY, processed_at TIMESTAMPTZ NOT NULL DEFAULT NOW())` + index sur `processed_at`. Idempotente (`CREATE TABLE IF NOT EXISTS`).
- `src/lib/stripeWebhookEvents.ts` — helpers `isEventProcessed` / `markEventProcessed` (insert idempotent, conflit unique `23505` avalé silencieusement).
- `src/lib/__tests__/stripeWebhookEvents.test.ts` — 8 tests (lecture, écriture, edge cases vide/erreur DB).
- `src/lib/__tests__/createBillingPortalSession.test.ts` — 4 tests (succès, customerId vide, returnUrl vide, URL Stripe vide).
- `POST /stripe/customer-portal` — endpoint authentifié qui crée une Stripe Billing Portal Session (gestion abonnement self-service) et redirige l'utilisateur. 400 `NO_ACTIVE_SUBSCRIPTION` si pas de `stripe_customer_id` ; return_url = `${APP_URL}/dashboard`.
### Changed
- `POST /stripe/webhook` — déduplication explicite des events Stripe (TD-13 résolu) : check `isEventProcessed(event.id)` avant traitement → early return `200 { received: true, replayed: true }` ; `markEventProcessed` après succès uniquement (pas si exception, pour permettre rejeu Stripe).
- `src/lib/stripe.ts` — nouvelle fonction `createBillingPortalSession({ customerId, returnUrl })` (mirror de `createCheckoutSession`).
- `src/routes/__tests__/stripe.test.ts` — 5 nouveaux tests (2 idempotency webhook + 3 customer-portal route).
- `docs/ARCHITECTURE-backend.md` — §3 commentaire `plans.ts` corrigé (`POST /plans/upgrade-prorata` au lieu de `POST /plans/upgrade` qui n'existait pas) ; §6 retrait de la ligne dupliquée `POST /plans/upgrade` (la création d'abonnement passe par `POST /stripe/checkout`) ; §6 ajout `POST /stripe/customer-portal`.
### Resolved
- **TD-13 🔴 → Résolu** : Webhook Stripe idempotent (table `stripe_webhook_events` + helpers + wiring route + 10 tests).
### Notes
- Tests : 261 → 278 verts (+17).
- Aucun changement frontend dans ce sprint — Sprint 5b (frontend billing) à venir.
---
## [Unreleased] — 2026-04-26 — Sprint 4.8 — Phonologie EO
### Added