Files
Epicure/apps/web
Arnaud f871f4f588 feat: real Stripe billing -- Checkout, Customer Portal, admin billing dashboard (v0.73.0)
Implements plans/STRIPE_PLAN.md sections 1-9 for solo Pro/Family
billing (family multi-user sharing, section 1a, deliberately deferred
-- flagged in that plan as the most novel/error-prone piece).

Decisions locked in: cancel/downgrade at period end (Stripe Portal
default), no trial period.

- lib/stripe.ts: single client factory reading STRIPE_SECRET_KEY via
  site-settings (DB overrides env, same pattern as every other
  provider key in this codebase).
- Webhook route rewritten on the real `stripe` SDK
  (stripe.webhooks.constructEvent replaces the hand-rolled HMAC
  verifier) and now handles the full event set: checkout.session.completed,
  customer.subscription.{updated,deleted}, invoice.{payment_failed,paid}.
  past_due deliberately never downgrades tier on its own -- Stripe
  retries the card first, recovering via invoice.paid or eventually
  giving up via subscription.deleted. Every handler audit-logs under
  billing.<event>. Dedup via the existing processed_stripe_events
  table, unchanged.
- Schema: tierDefinitions gained stripe{ProductId,PriceIdMonthly,
  PriceIdYearly} (the lookup table mapping a Price back to a tier on
  checkout); users gained stripeSubscriptionId/subscriptionStatus/
  currentPeriodEnd.
- New POST /api/v1/billing/checkout (creates a subscription Checkout
  Session, allow_promotion_codes: true), POST /api/v1/billing/portal
  (Stripe's hosted self-serve cancel/upgrade/card-update), GET
  /api/v1/billing/status.
- /settings/billing: current plan + renewal date, past_due warning,
  usage-vs-limits (reuses the existing UsageQuotaSection), plan
  comparison cards with per-tier Checkout buttons, manage-billing
  button once a Stripe customer exists.
- /admin/billing: connection status (test/live mode detection),
  subscriber counts, past-due list, recent billing audit events, link
  to Stripe Dashboard. Tier Limits page extended with the three Stripe
  price fields per tier (own render branch, not the numeric+Unlimited-
  switch machinery the existing fields use).

Before going live: an admin needs to create real Products/Prices in
Stripe, enter the IDs on Tier Limits, and configure the Stripe-side
webhook endpoint -- all operational steps the plan always called for,
none of it code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 13:37:14 +02:00
..

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.