Skip to content

[BILLING-001] Add premium subscription management - #89

Open
chev0004 wants to merge 3 commits into
developfrom
feat/billing-001
Open

[BILLING-001] Add premium subscription management#89
chev0004 wants to merge 3 commits into
developfrom
feat/billing-001

Conversation

@chev0004

@chev0004 chev0004 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Outline

Summary

Wires the Manage Subscription flow to Stripe: subscription state lives in a new subscriptions table kept current by a signature-verified webhook, the settings button opens Stripe Checkout for free users or the billing portal for subscribers, and the premium tab shows real plan status with the renewal or end date.


Changes & Enhancements

  • Type of Change:
    • Feature
    • Bugfix
    • Refactor
    • Chore
  • Changes:
    • (Database):
      • Add subscriptions table storing Stripe customer id, subscription id, status, period end, and cancel-at-period-end per user.
      • Add src/db/billing.ts with lookup, upsert, and isSubscriptionActive helpers.
    • (Server):
      • Add src/lib/stripe.ts calling the Stripe REST API directly (checkout session, billing portal session, subscription lookup, webhook signature verification) with no SDK dependency.
      • Add POST /api/billing/portal returning a checkout URL for non-subscribers or a portal URL for active subscribers, 503 when Stripe env vars are unset, 502 when Stripe rejects the request.
      • Add POST /api/billing/webhook verifying the Stripe signature and syncing subscription state on checkout completion and subscription create, update, and delete events.
    • (Settings):
      • Manage Subscription and Upgrade buttons call the portal endpoint and redirect to the returned URL; failures surface an error in the save bar.
      • Premium status is computed server-side from the subscription (or the existing env allowlist) and the premium tab shows the renewal or end date.
    • (Config):
      • Document STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and STRIPE_PRICE_ID in .env.example.

Page / App Changes

Affected Next.js Routes (Local):

  • /[lang]/settings (premium status, renewal date, billing portal redirect, billing error state)
Before (Screenshot)
After (Screenshot)

Component / Storybook Changes

Affected Storybook Components (Local):

Before (Screenshot)
After (Screenshot)

Not Doing


Other (Remarks)

Verified locally without Stripe keys: the portal endpoint returns 503 and the settings UI shows the billing error; a seeded active subscription renders the premium tab with Manage billing and the renewal date; the webhook rejects unsigned payloads with 400. The full checkout round trip needs a Stripe test account. This PR adds a migration numbered 0012 in parallel with #86 and #87; whichever merges later needs drizzle/meta/_journal.json reconciled.


Checklists

  • Code is well-documented (comments, JSDoc, etc.).
  • Existing comments were updated as needed.
  • No out-of-scope changes are included.
  • Write TODO comments where future work is required.
  • Removed unnecessary debug code (e.g., console.log, debugger).
  • Self-reviewed and tested locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant