Problem: if stripe listen is not running (dev) or the webhook secret is
misconfigured, a successful checkout leaves the user stuck on the free
plan in the DB even though Stripe knows they're subscribed.
Solution: 3 recovery mechanisms.
1. Backend: POST /stripe/sync (auth required)
Fetches the current user's subscriptions from Stripe by customer ID,
picks the most recent active/trialing/past_due one, and applies it to
the User row via the same applySubscriptionToUser helper used by the
webhook. If no active sub exists, downgrades to free. Returns the
current plan state.
2. Frontend: CheckoutSuccess now calls /stripe/sync first (instant,
reliable) before falling back to polling /stripe/subscription. This
fixes the 'just paid but still free' bug even with no webhook setup.
3. Frontend: 'Rafraîchir' button on the Profile free-plan upgrade banner
(ghost style with RefreshCw spinning icon). Tooltip hints at its
purpose. Users who paid but see the free state can click it to
self-heal in one click.
4. Backend script: scripts/sync-subscription.ts
- npm run stripe:sync -- user@example.com (sync one user by email)
- npm run stripe:sync -- --all (sync every user with a
stripeId, useful after
a prod webhook outage)
Colored output with ✓ / ✗ / ↷ status per user.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New script backend/scripts/setup-stripe.ts that:
- Reads STRIPE_SECRET_KEY from .env
- Detects test vs live mode and warns + 5s delay for live
- For each plan (Essentiel 3EUR/mo, Premium 5EUR/mo):
- Looks up existing price by lookup_key (freedge_essential_monthly,
freedge_premium_monthly) — idempotent, safe to re-run
- If missing, creates the product then the recurring price with the
lookup_key and nickname for clarity
- Prints the resulting price IDs with their env var names
- With --write-env flag, automatically upserts the values into
backend/.env preserving other lines
- Points to Customer Portal settings and stripe listen command as
next steps
npm scripts added:
- npm run stripe:setup # dry run, just print IDs
- npm run stripe:setup:write # update .env automatically
- npm run stripe:listen # shortcut for stripe CLI webhook forward
Updated README to show the script as the recommended path for step 1,
keeping the manual dashboard instructions as a fallback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>