This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a production MVP boilerplate for building SaaS applications with multiple frontend options (Flutter and Next.js) sharing a common Supabase backend. The architecture supports cross-platform development with integrated payments (Stripe), authentication (Supabase), analytics (PostHog), and transactional emails (Postmark).
nextjs/- Next.js web application (App Router, TypeScript, Tailwind)flutter/- Flutter cross-platform app (iOS, Android, Web, macOS, Linux, Windows)supabase/- Supabase backend configuration, migrations, and edge functionsdocs/- Comprehensive documentation for setup and configuration
cd nextjs
pnpm install # Install dependencies
pnpm dev # Start development server with Turbopack
pnpm build # Production build
pnpm lint # Run ESLint
pnpm prettier-fix # Format code with Prettiercd flutter
flutter run -d chrome --dart-define-from-file=env.json # Run web app
flutter run -d macos --dart-define-from-file=env.json # Run macOS app
flutter pub get # Install dependencies
flutter test # Run tests# From root directory
cd nextjs
pnpm supabase:start # Start local Supabase (runs Docker containers)
pnpm supabase:stop # Stop local Supabase
pnpm supabase:status # View connection info and URLs
pnpm supabase:restart # Stop and restart Supabase
pnpm supabase:reset # Reset database (destructive)
# Generate TypeScript types from database schema
pnpm supabase:generate-types # Generates types_db.ts in both nextjs/ and supabase/functions/
# Database migrations
pnpm supabase:generate-migration # Create migration from schema diff
pnpm supabase:push # Push migrations to remote
pnpm supabase:pull # Pull migrations from remotecd supabase
# Serve functions locally
supabase functions serve --env-file .env.local --import-map functions/deno.json
# Set secrets for production
supabase secrets set --env-file .env
# Deploy functions
supabase functions deploy --import-map functions/deno.json
# Sync Stripe products/prices to database
deno run -A functions/_scripts/sync-stripe.tsAvailable edge functions:
get_stripe_url- Returns Stripe checkout or billing portal URLsstripe_webhook- Handles Stripe webhook events (syncs subscriptions)on_user_modify- Triggered on user creation/deletion (PostHog events)
cd nextjs
pnpm stripe:login # Authenticate with Stripe CLI
pnpm stripe:listen # Forward webhooks to local Supabase function
pnpm stripe:fixtures # Load test products/prices from fixtures/stripe-fixtures.json- Supabase Auth handles all authentication (email/password, OAuth providers)
- Next.js uses Server Components with
@supabase/ssrfor server-side auth - Flutter uses
supabase_flutterwith session persistence - On user creation,
handle_new_user()trigger creates entry inuserstable - On user modify,
on_user_modifyedge function logs events to PostHog
- User initiates checkout from frontend (Flutter or Next.js)
- Frontend calls
get_stripe_urledge function with price ID - Edge function creates Stripe checkout session, returns URL
- User completes payment in Stripe
- Stripe sends webhook to
stripe_webhookedge function - Webhook handler syncs subscription data to
subscriptionstable - Frontend polls or refreshes to show updated subscription status
Database tables:
customers- Maps Supabase user IDs to Stripe customer IDsproducts- Synced from Stripe via webhooksprices- Synced from Stripe via webhookssubscriptions- User subscription status, synced from Stripe
- App Router with React Server Components
- Supabase client creation:
utils/supabase/server.ts- Server Component clientutils/supabase/client.ts- Client Component clientutils/supabase/middleware.ts- Middleware client for auth refreshutils/supabase/api.ts- Route handler client
- Components:
components/ui/- shadcn/ui components (Radix UI primitives)components/landing/- Landing page sectionscomponents/misc/- Miscellaneous shared components
- API Routes:
app/api/- Next.js route handlers for server-side operations
- PostHog:
app/PostHogPageView.tsxtracks pageviews,app/providers.tsxinitializes PostHog
- State Management: Riverpod with code generation (
riverpod_annotation) - Routing:
go_routerconfigured inlib/services/router_notifier.dart - Key Services:
lib/services/auth_notifier.dart- Authentication state managementlib/services/metadata_notifier.dart- User metadata managementlib/services/router_notifier.dart- Navigation with auth-based redirects
- Screens:
lib/screens/auth_screen.dart- Login/signup withsupabase_auth_uilib/screens/home_screen.dart- Main authenticated screenlib/screens/payments_screen.dart- Stripe checkout integration
- Configuration: Environment variables in
env.json(useenv.local.jsonfor local dev)
The schema is defined in nextjs/schema.sql and managed via Supabase migrations in supabase/migrations/.
Core tables:
users- User profiles with billing infocustomers- Stripe customer mapping (private table)products- Stripe products (synced via webhook)prices- Stripe prices (synced via webhook)subscriptions- User subscriptions (synced via webhook)
Row Level Security (RLS): All tables have RLS enabled. Users can only access their own data.
Both Next.js and Supabase edge functions share the same TypeScript types generated from the database schema:
nextjs/types_db.tssupabase/functions/types_db.ts
After modifying the database schema, run pnpm supabase:generate-types from the nextjs/ directory to update both files.
When running supabase start, the following services are available:
- API:
http://localhost:54321 - Database:
postgresql://postgres:postgres@localhost:54322/postgres - Studio:
http://localhost:54323 - Next.js:
http://localhost:3000(default)
- Next.js: Uses
.env(or.env.localfor local dev) - Flutter: Uses
env.json(orenv.local.jsonfor local dev) - Supabase Functions: Uses
.envinsupabase/directory (local:.env.local)
When working with environment variables, check the corresponding .env.example files for required variables.
Do not create Supabase clients directly with createClient() everywhere. Use the appropriate utility:
- Server Components:
import { createClient } from '@/utils/supabase/server' - Client Components:
import { createClient } from '@/utils/supabase/client' - Middleware:
import { updateSession } from '@/utils/supabase/middleware' - Route Handlers: Import from
@/utils/supabase/api
- Make schema changes in local Supabase Studio (
http://localhost:54323) - Generate migration:
pnpm supabase:generate-migration - Review generated SQL in
supabase/migrations/ - Apply migration locally:
pnpm supabase:reset(or restart) - Regenerate types:
pnpm supabase:generate-types - Push to production:
pnpm supabase:push
Flutter uses Riverpod code generation. After modifying files with @riverpod annotations, run:
flutter pub run build_runner build --delete-conflicting-outputs- Start Supabase:
cd nextjs && pnpm supabase:start - Start Stripe webhook listener:
pnpm stripe:listen(in separate terminal) - Load Stripe test data:
pnpm stripe:fixtures - Start Next.js:
pnpm devOR Start Flutter:cd ../flutter && flutter run -d chrome --dart-define-from-file=env.local.json
- Next.js: Uses
pnpm(not npm or yarn) - Flutter: Uses
flutter pub - Supabase Functions: Uses Deno with import maps (
functions/deno.json)
This repository uses GitHub Actions for CI/CD:
.github/workflows/flutter-web.yml- Deploys Flutter web to Netlify on PR/merge
For production deployment, refer to the documentation in docs/ for platform-specific setup (Stripe, PostHog, Postmark, etc.).