Wire up Supabase auth, Creem billing, and credits#1
Conversation
Implements all backend logic from PLAN.md across 7 phases: Phase 1 – Foundation: populate Supabase browser/server/admin clients, full Creem API wrapper (checkout, subscriptions, portal, webhook verification), Next.js middleware with auth-redirect guards, migration 004 adds creem_customer_id to profiles. Phase 2 – Auth: server actions for login/signup/OAuth/logout with Zod validation, OAuth callback route, useUser hook, auth-aware header. Phase 3 – Billing core: Zod webhook schemas, handleWebhookEvent dispatcher (checkout.completed, subscription lifecycle, refund.created), single /api/webhooks/creem route, createCheckoutSession/openCustomerPortal actions, CheckoutButton component, pricing section wired to real Creem product IDs. Phase 4 – Dashboard: layout moved to server component with auth check and real user passed to sidebar; dashboard page adds SubscriptionCard + CreditsCard above existing demo; settings/billing/credits sub-pages; AppSidebar accepts user prop with real nav links; NavUser wires logout. Phase 5 – Credits: migration 005 adds spend_credits RPC with row-level lock; credits types, actions (balance/purchase/spend/transactions), CreditsBalanceCard, TransactionHistory, useCredits hook. Phase 6 – Advanced billing: cancel (scheduled/immediate), resume, pause, upgrade server actions; ManageSubscription component with AlertDialog confirmation; useSubscription hook. Phase 7 – Polish: Toaster added to root layout; ActionResult shared type; vitest config + test setup; 12 passing tests covering webhook handlers, webhook signature verification, and spend_credits edge cases; CI extended with test and build jobs.
Expand README with quick start guide, table of contents, full setup instructions, and webhook integration docs. Add testing strategy section to ARCHITECTURE.md with colocated vs. cross-feature test conventions. Unignore TODO.md so it's tracked.
There was a problem hiding this comment.
Pull request overview
This PR turns the starter UI shell into a usable SaaS template by wiring Supabase auth/session handling, Creem billing (API + webhooks), and a credits ledger/RPC, plus adding unit tests and CI jobs.
Changes:
- Add Supabase SSR/browser/admin clients, middleware route protection, and auth server actions (email + OAuth) with UI wiring.
- Implement Creem client + webhook dispatcher to sync subscriptions and credit purchases/top-ups/refunds into Supabase.
- Add credits feature (RPC + server actions + UI) and introduce Vitest tests + CI test/build jobs.
Reviewed changes
Copilot reviewed 50 out of 52 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.ts | Adds Vitest config (jsdom, setup file, path alias). |
| supabase/migrations/004_profiles_creem_customer_id.sql | Adds creem_customer_id to profiles and indexes it for lookups. |
| supabase/migrations/005_spend_credits_rpc.sql | Introduces spend_credits RPC with row locking and ledger insert. |
| src/test/setup.ts | Adds Testing Library jest-dom matchers for Vitest. |
| src/middleware.ts | Adds Supabase SSR session refresh + route guards for auth/protected paths. |
| src/lib/supabase/server.ts | Implements server-side Supabase client using Next cookies. |
| src/lib/supabase/client.ts | Implements browser Supabase client. |
| src/lib/supabase/admin.ts | Implements admin Supabase client using service role key. |
| src/lib/creem/client.ts | Adds Creem API wrapper and webhook signature verification. |
| src/lib/creem/tests/client.test.ts | Unit tests for webhook signature verification and Creem fetch error handling. |
| src/lib/action-result.ts | Adds shared ActionResult type helper. |
| src/features/dashboard/components/nav-user.tsx | Adds settings/billing/credits links and logout form; dynamic avatar initials. |
| src/features/dashboard/components/nav-main.tsx | Converts nav items to real route links. |
| src/features/dashboard/components/app-sidebar.tsx | Replaces placeholder nav data with real dashboard routes and accepts user props. |
| src/features/credits/types.ts | Adds types for credit balance and credit transactions. |
| src/features/credits/hooks/use-credits.ts | Adds client hook to fetch/refresh credit balance. |
| src/features/credits/components/transaction-history.tsx | Adds UI for credit transaction history list. |
| src/features/credits/components/credits-balance-card.tsx | Adds UI card for credit balance + “Buy Credits” action. |
| src/features/credits/actions/index.ts | Adds server actions for balance, purchase checkout, spend RPC, and transaction history. |
| src/features/credits/actions/tests/spend-credits.test.ts | Unit tests for spend credits action behavior. |
| src/features/billing/webhooks/index.ts | Adds Creem webhook dispatcher and handlers for subscription + credits lifecycle. |
| src/features/billing/webhooks/tests/index.test.ts | Unit tests for webhook routing/validation/logging. |
| src/features/billing/types.ts | Adds webhook schemas/types and plan config constants. |
| src/features/billing/hooks/use-subscription.ts | Adds client hook to fetch/refresh user subscription. |
| src/features/billing/components/subscription-card.tsx | Adds dashboard billing summary UI (subscription + credits). |
| src/features/billing/components/pricing-section.tsx | Wires pricing CTAs to signup/checkout. |
| src/features/billing/components/manage-subscription.tsx | Adds UI/actions for cancel/resume/pause via Creem. |
| src/features/billing/components/checkout-button.tsx | Adds client checkout button triggering server action. |
| src/features/billing/actions/index.ts | Adds billing server actions for checkout, portal, cancel/resume/upgrade/pause, subscription query. |
| src/features/auth/types.ts | Adds auth-related shared types. |
| src/features/auth/hooks/use-user.ts | Adds client hook to track current Supabase user. |
| src/features/auth/components/signup-form.tsx | Wires signup form to server action w/ validation errors. |
| src/features/auth/components/settings-profile-card.tsx | Adds profile update form wired to server action. |
| src/features/auth/components/login-form.tsx | Wires login form and OAuth buttons to server actions w/ validation errors. |
| src/features/auth/actions/profile.ts | Adds server action for updating profile full name. |
| src/features/auth/actions/index.ts | Adds login/signup/OAuth/logout server actions with Zod validation. |
| src/components/header.tsx | Makes header auth-aware (Dashboard vs Login/Sign up). |
| src/app/layout.tsx | Adds global Sonner toaster. |
| src/app/auth/callback/route.ts | Adds OAuth callback route exchanging code for session. |
| src/app/api/webhooks/creem/route.ts | Adds Creem webhook endpoint with signature verification + dispatcher. |
| src/app/(dashboard)/layout.tsx | Adds server-side auth check and shared sidebar layout for dashboard routes. |
| src/app/(dashboard)/dashboard/page.tsx | Adds server-side data fetching for subscription + credits on dashboard home. |
| src/app/(dashboard)/dashboard/settings/page.tsx | Adds settings page showing profile card. |
| src/app/(dashboard)/dashboard/credits/page.tsx | Adds credits page (balance + transaction history). |
| src/app/(dashboard)/dashboard/billing/page.tsx | Adds billing page (subscription summary + management + plan CTAs). |
| package.json | Adds Supabase + Vitest/testing deps and test scripts. |
| package-lock.json | Locks added dependencies for Supabase SSR, Vitest, Testing Library, etc. |
| README.md | Expands docs (quick start, setup flow, demo info). |
| ARCHITECTURE.md | Documents testing strategy and folder layout additions. |
| .gitignore | Stops ignoring TODO.md (commented out ignore entry). |
| .github/workflows/ci.yml | Adds test and build jobs to CI. |
| .env.example | Adds Business product ID env var. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…vigation and performance
Greptile SummaryThis PR completes the backend wiring for the NextJS + Supabase + Creem starter: Supabase auth (login/signup/OAuth/middleware), the full Creem billing API wrapper, webhook event dispatch (subscriptions + one-time purchases + refunds), a credit system backed by safe Postgres RPCs, and dashboard/settings sub-pages — all tested with 12 unit tests and a CI pipeline. The overall implementation is solid and all five issues from the prior review round have been addressed. Two new issues were found that are worth resolving before shipping.
Confidence Score: 4/5Safe to merge after fixing the refund credit-unit mismatch and adding error handling to the three checkout/portal actions. All five prior review findings are resolved. Two new P1 issues remain: the refund handler silently deducts the wrong number of credits (monetary cents vs. credit units), and three server actions lack error handling for Creem API failures. src/features/billing/webhooks/index.ts (handleRefundCreated), src/features/billing/actions/index.ts (createCheckoutSession, openCustomerPortal), src/features/credits/actions/index.ts (purchaseCredits) Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Next as Next.js (Server Action)
participant Creem as Creem API
participant Webhook as /api/webhooks/creem
participant DB as Supabase (Admin RPC)
User->>Next: createCheckoutSession(productId)
Next->>Creem: POST /v1/checkouts
Creem-->>Next: { checkout_url }
Next-->>User: redirect(checkout_url)
User->>Creem: Complete payment
Creem->>Webhook: POST checkout.completed
Webhook->>Webhook: verifyWebhookSignature (HMAC)
Webhook->>DB: profiles.update(creem_customer_id)
alt Has subscription
Webhook->>DB: subscriptions.upsert(creem_subscription_id)
else One-time purchase
Webhook->>DB: rpc add_credits(user_id, amount)
end
Creem->>Webhook: POST subscription.paid (renewal)
Webhook->>DB: subscriptions.upsert
Webhook->>DB: rpc add_credits(user_id, plan_credits)
Creem->>Webhook: POST refund.created
Webhook->>DB: profiles.select(creem_customer_id)
Webhook->>DB: rpc deduct_credits(user_id, refund.amount ⚠️)
User->>Next: spendCredits(amount, desc)
Next->>DB: rpc spend_credits(user_id, amount) [FOR UPDATE lock]
DB-->>Next: true / false
Reviews (2): Last reviewed commit: "fix(faqs): clarify deployment instructio..." | Re-trigger Greptile |
…ith new fields and policies
…E_PUBLISHABLE_KEY Update all references in Supabase clients, middleware, CI, and env example to use the new publishable key env var name.
- Colocate loginSchema, signupSchema, profileSchema in auth/schema.ts - Handle email confirmation flow (no session after signUp) - Fix OAuth redirect URL to respect NEXT_PUBLIC_APP_URL and x-forwarded-* headers - Sanitise open-redirect in /auth/callback (reject non-relative or protocol-relative paths) - Show confirmation message in signup form
…dit RPCs - Move Creem webhook schemas + createCheckoutSchema to billing/schema.ts - billing/types.ts now contains TS-only types and PLANS - Fix cancel/resume/pause to filter by creem_subscription_id not user_id - Replace manual credit mutations with add_credits/deduct_credits RPCs - Guard unknown product IDs in creditsForProductId (warn + return 0) - Conditionally disable pricing buttons when product IDs are unconfigured
- Colocate spendCreditsSchema in credits/schema.ts - Replace manual Number.isInteger guard with Zod safeParse - Use z.int().min(1) per Zod v4 API
…tion Replace string equality check with crypto.timingSafeEqual to prevent timing-based signature oracle attacks on the webhook endpoint.
Middleware was accidentally deleted. Restored with NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY to match the renamed env var. Required for Supabase session cookie refresh and route protection on /dashboard.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 65 changed files in this pull request and generated 10 comments.
Comments suppressed due to low confidence (1)
README.md:168
- These commands reference scripts that don’t exist in package.json (
checkandtest:coverage). Either update the README to match the actual scripts (lint,typecheck,test,build) or add the missing scripts so the documented verification steps work.
cp .env.example .env.local
</details>
---
💡 <a href="/ubergonmx/nextjs-supabase-creem-starter/new/main?filename=.github/instructions/*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
- Add emailRedirectTo pointing to /auth/callback so Supabase sends the PKCE code to the callback route instead of the landing page - Redirect to /login?signup=pending after signup instead of returning an inline message; show a top-center Sonner toast on the login page - Add useRef guard in SignupPendingToast to prevent double-fire under React Strict Mode in development - Add useTransition to OAuth buttons so UI shows "Redirecting…" state - Clean up auth layout title template (remove redundant "Auth" segment)
- Replace manual HMAC verification with @creem_io/nextjs Webhook()
adapter; route is now 5 lines, all business logic lives in
src/features/billing/webhooks/index.ts per feature-based layout
- Add webhook_events table (migration 004) as idempotency log and
admin audit trail; duplicate webhookIds are skipped before any
DB write
- Remove verifyWebhookSignature from creem client (handled by SDK)
- Export creditsForProductId, mapStatus, isDuplicate as named exports
for testability; update tests to use typed event objects
- Add CheckoutSuccessToast for /dashboard?checkout=success feedback
- Add UpgradeButton component; billing page now uses UpgradeButton
for existing subscribers vs CheckoutButton for new ones
- Guard purchaseCredits against missing product env var
- Add nativeButton={false} to Link-rendered Buttons in subscription card
- Replace manual IconInnerShadowTop + text markup in AppSidebar header
with the shared <Logo> component; scale via [&>svg]:w-36 h-auto
- Remove stray sr-only spans from inside render={<Link/>} props in
AppSidebar and NavSecondary; these conflicted with base-ui useRender
children merging and caused logo/text to disappear
- Delete nav-documents.tsx (unused shadcn scaffold component)
- Add smooth scroll behaviour to root html element
- Add allowed ngrok dev origin to next.config.ts
Creem displays webhook secrets with a whsec_ prefix in the dashboard (visual indicator, like sk_test_ for API keys) but the actual HMAC key is the value after the prefix. The @creem_io/nextjs library uses the secret as-is, causing every signature verification to fail.
Debug confirmed Creem signs with the entire whsec_ string as the key — do not strip the prefix. Also move env var read inside the handler to avoid module-level evaluation before env is loaded.
…ns for feature navigation
- Implement security headers to enhance application security, including X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy. - Update next.config.ts to include an async headers function that returns the defined security headers for all routes.
…hema functions - Revoke EXECUTE permissions on trigger and utility functions from anon and authenticated roles to enhance security. - Grant EXECUTE permissions on credit RPCs exclusively to the service_role, ensuring continued access for admin clients through future permission resets.
…ler directly - Replace the existing POST function in the Creem webhook route with a direct export of the handleCreemWebhook function from the billing webhooks feature. - Update import statements in billing actions for consistency and clarity, including normalization of string quotes and minor adjustments to error handling and redirection logic.
- Remove unnecessary options from .oxfmtrc.json, including semi and trailingComma. - Simplify ignorePatterns in .oxlintrc.json by consolidating array elements into a single line for better readability.
- Introduce a new tsconfig.build.json file to exclude test files during production builds. - Update next.config.ts to conditionally set the TypeScript configuration path based on the environment. - Minor formatting adjustments in postcss.config.mjs for consistency.
…ion and resume actions - Add revalidation of the billing dashboard path after canceling or resuming a user subscription to ensure the UI reflects the latest subscription status. - Remove pause subscription functionality from the ManageSubscription component and update related UI elements for clarity.
- Change handleCancel and handleResume functions to remove async keyword, improving readability and consistency in the ManageSubscription component. - Ensure that the subscription management logic remains intact while enhancing code clarity.
…d dashboard layouts - Add ProgressProvider component to wrap children in both AuthLayout and DashboardLayout, enhancing user experience with loading indicators. - Introduce @bprogress/next dependency for improved progress management. - Remove unused action-result.ts file to clean up the codebase.
…features - Update import paths for billing and credits actions to improve clarity and maintainability. - Consolidate action imports in dashboard components to reflect new file structure. - Introduce new action files for handling credits and subscriptions, enhancing modularity.
Enable experimental viewTransition flag in next.config.ts, wrap page content in <ViewTransition> in the marketing layout, and pin the header nav with a named view-transition to prevent it from cross-fading.
Tag dashboard/login/signup links with transitionTypes=['cross-layout'] and suppress the root animation via active-view-transition-type CSS to avoid ugly transitions when leaving the marketing route group.
Suppress all root/header transitions by default so cross-layout navigations are instant. Re-enable cross-fade only for marketing↔marketing links via transitionTypes=['same-layout'] and active-view-transition-type CSS.
…ment - Added a new Starter subscription plan with specific pricing and credits. - Updated subscription management logic to handle the new plan, including UI adjustments in the billing page and subscription card components. - Refactored user subscription retrieval to improve clarity and maintainability. - Enhanced webhook handling for subscription events to accommodate the new plan. - Introduced tests for the new plan and related functionalities to ensure reliability.
…proxy support Use x-forwarded-host/proto in the callback route to build the correct redirect origin, fixing localhost redirects when accessed via ngrok. Also update getAuthRedirectBaseUrl to prefer incoming headers over NEXT_PUBLIC_APP_URL in non-production environments.
…ent with getUser - Replaced instances of createClient and its user retrieval logic with a new getUser function for improved clarity and maintainability. - Updated various components and actions to utilize the new getUser method, enhancing the overall authentication flow. - Removed unnecessary console logs in layout.tsx for cleaner code.
…ages - Introduced a new UrlToast component to display error messages based on URL parameters, enhancing user feedback during authentication and billing processes. - Updated LoginPage, BillingPage, and PricingPage to utilize UrlToast for displaying relevant error messages. - Added error handling logic in auth and billing features to improve user experience during sign-up and subscription management. - Refactored existing toast notifications to remove position settings for consistency.
… statuses; refactor proxy middleware for session management
…ing page layout; refactor subscription card and credits balance display
…d subscription details; refactor chart and section cards for improved credit activity display
…ption and credits components for better user experience
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 162 out of 164 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…rt for allowed dev origins and improve billing portal error messages
… and add developer tips
Problem / Intent
The starter had a complete UI shell but zero backend — Supabase clients were empty stubs, no auth or billing logic existed, no middleware protected routes, and no webhook handled Creem events. This PR wires everything up so the template is actually usable as a production SaaS starting point.
Approach
All business logic lives in server actions (no API routes except the single required webhook endpoint):
useUserhook, and an auth-aware headerhandleWebhookEventdispatcher covering the full subscription and checkout lifecycle,createCheckoutSession/openCustomerPortalactions, and checkout buttons wired to real product IDs on the pricing pagespend_creditsPostgres RPC with a row-level lock to prevent race conditions, balance/purchase/spend/transaction-history server actions, and associated UI components/billing,/credits, and/settingssub-pagesAlertDialogconfirmation UIspend_creditsedge cases; CI extended with test and build jobs