nextjs-supabase-saas-planner
π―Skillfrom sitechfromgeorgia/georgian-distribution-system
Transforms product ideas into comprehensive Next.js and Supabase SaaS technical roadmaps, covering architecture, schemas, features, and launch strategies.
Installation
npx skills add https://github.com/sitechfromgeorgia/georgian-distribution-system --skill nextjs-supabase-saas-plannerSkill Details
Comprehensive SaaS architecture planner for Next.js and Supabase applications. Converts ideas into production-ready technical plans with database schemas, file structures, feature breakdowns, and week-by-week development roadmaps. Use when planning subscription-based applications, multi-tenant SaaS products, or building from idea to launch with Next.js and Supabase stack.
Overview
# Next.js + Supabase SaaS Planner
Overview
Expert SaaS planning assistant that transforms product ideas into actionable technical roadmaps. Specializes in the Next.js 15 + Supabase stack, covering architecture design, database schemas, authentication patterns, multi-tenancy, billing integration, and launch strategies.
When to use this skill:
- Planning a new SaaS product from scratch
- Converting a product idea into technical specifications
- Designing database schemas for SaaS applications
- Setting up authentication and authorization
- Implementing multi-tenant architecture
- Integrating subscription billing (Stripe, Paddle)
- Planning feature rollout and MVP priorities
- Creating development roadmaps and timelines
---
Planning Workflow
Phase 1: Discovery and Requirements
Ask these questions first:
- Product Overview
- What problem does your SaaS solve?
- Who is your target user?
- What's your unique value proposition?
- Scale Expectations
- How many users in first year? (0-1K, 1K-10K, 10K-100K, 100K+)
- Expected growth rate?
- Geographic distribution?
- Team and Timeline
- Team size and skills?
- Launch timeline? (MVP date)
- Budget constraints?
- Business Model
- Pricing tiers?
- Free trial or freemium?
- What features differentiate paid tiers?
- Core Features
- Must-have features for MVP?
- Nice-to-have features for v1.1?
- Future roadmap ideas?
Phase 2: Technical Architecture Planning
Based on requirements, create:
- System Architecture Diagram
- Database Schema
- File/Folder Structure
- Authentication Flow
- Multi-Tenancy Strategy (if applicable)
- Billing Integration Plan
- Deployment Architecture
Phase 3: Development Roadmap
Create week-by-week plan:
- Week 1-2: Setup and infrastructure
- Week 3-4: Core features
- Week 5-6: Authentication and billing
- Week 7-8: Polish and testing
- Week 9: Launch preparation
---
Next.js 15 + Supabase Stack (2025)
Recommended Tech Stack
```
Frontend:
ββ Next.js 15 (App Router)
ββ React 19
ββ TypeScript
ββ Tailwind CSS
ββ shadcn/ui components
Backend:
ββ Next.js API Routes (Server Actions)
ββ Supabase Edge Functions (when needed)
ββ Stripe/Paddle webhooks
Database:
ββ PostgreSQL (Supabase)
ββ Row Level Security (RLS)
ββ Supabase Realtime (optional)
Authentication:
ββ Supabase Auth
ββ OAuth providers (Google, GitHub, etc.)
ββ Magic links
Storage:
ββ Supabase Storage (files, images)
Deployment:
ββ Vercel (frontend + API)
ββ Supabase (database, auth, storage)
ββ Cloudflare (CDN, DNS)
Payments:
ββ Stripe (recommended)
ββ Paddle (alternative)
Monitoring:
ββ Vercel Analytics
ββ Sentry (error tracking)
ββ PostHog (product analytics - optional)
```
Why This Stack?
Next.js 15:
- Server Components for performance
- Server Actions for mutations
- Built-in caching strategies
- Excellent DX and fast iteration
Supabase:
- Instant REST API
- Real-time subscriptions
- Built-in authentication
- Row-level security
- Open source (no vendor lock-in risk)
TypeScript:
- Type safety reduces bugs
- Better IDE support
- Self-documenting code
Stripe:
- Industry standard for payments
- Excellent documentation
- Subscription management
- Invoice handling
---
File Structure Template
```
my-saas/
ββ app/
β ββ (auth)/
β β ββ login/
β β β ββ page.tsx
β β ββ signup/
β β β ββ page.tsx
β β ββ forgot-password/
β β β ββ page.tsx
β β ββ layout.tsx
β β
β ββ (marketing)/
β β ββ page.tsx # Landing page
β β ββ pricing/
β β β ββ page.tsx
β β ββ about/
β β β ββ page.tsx
β β ββ layout.tsx
β β
β ββ (dashboard)/
β β ββ dashboard/
β β β ββ page.tsx
β β ββ settings/
β β β ββ profile/
β β β β ββ page.tsx
β β β ββ billing/
β β β β ββ page.tsx
β β β ββ team/
β β β ββ page.tsx
β β ββ layout.tsx
β β
β ββ api/
β β ββ webhooks/
β β β ββ stripe/
β β β ββ route.ts
β β ββ og/ # Open Graph images
β β ββ route.tsx
β β
β ββ layout.tsx # Root layout
β ββ globals.css
β
ββ components/
β ββ ui/ # shadcn components
β β ββ button.tsx
β β ββ card.tsx
β β ββ dialog.tsx
β β ββ ...
β ββ auth/
β β ββ login-form.tsx
β β ββ signup-form.tsx
β ββ dashboard/
β β ββ sidebar.tsx
β β ββ navbar.tsx
β ββ marketing/
β β ββ hero.tsx
β β ββ features.tsx
β β ββ pricing-cards.tsx
β ββ shared/
β ββ user-avatar.tsx
β ββ loading-spinner.tsx
β
ββ lib/
β ββ supabase/
β β ββ client.ts # Client-side Supabase
β β ββ server.ts # Server-side Supabase
β β ββ middleware.ts # Auth middleware
β ββ stripe/
β β ββ client.ts
β β ββ server.ts
β ββ db/
β β ββ queries.ts # Database queries
β ββ auth.ts # Auth helpers
β ββ utils.ts # General utilities
β
ββ hooks/
β ββ use-user.ts # User session hook
β ββ use-subscription.ts # Subscription status
β ββ use-toast.ts
β
ββ actions/ # Server Actions
β ββ auth/
β β ββ login.ts
β β ββ signup.ts
β β ββ logout.ts
β ββ billing/
β β ββ create-checkout.ts
β β ββ cancel-subscription.ts
β ββ profile/
β ββ update-profile.ts
β
ββ types/
β ββ database.ts # Generated from Supabase
β ββ supabase.ts
β ββ stripe.ts
β
ββ supabase/
β ββ migrations/ # Database migrations
β β ββ 20250101000000_initial.sql
β ββ functions/ # Edge Functions (optional)
β ββ config.toml
β
ββ public/
β ββ images/
β ββ icons/
β
ββ middleware.ts # Next.js middleware (auth)
ββ next.config.js
ββ tailwind.config.js
ββ tsconfig.json
ββ package.json
ββ .env.local
```
---
Database Schema Patterns
Core Tables for SaaS
```sql
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Users table (extended from Supabase auth.users)
CREATE TABLE profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT UNIQUE NOT NULL,
full_name TEXT,
avatar_url TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Organizations/Teams (multi-tenant)
CREATE TABLE organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
logo_url TEXT,
subscription_tier TEXT DEFAULT 'free',
subscription_status TEXT DEFAULT 'active',
stripe_customer_id TEXT UNIQUE,
stripe_subscription_id TEXT UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Organization memberships
CREATE TABLE organization_members (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
user_id UUID REFERENCES profiles(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member', -- 'owner', 'admin', 'member'
invited_by UUID REFERENCES profiles(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(organization_id, user_id)
);
-- Subscription plans
CREATE TABLE plans (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
description TEXT,
price_monthly DECIMAL(10,2),
price_yearly DECIMAL(10,2),
stripe_price_id_monthly TEXT,
stripe_price_id_yearly TEXT,
features JSONB,
limits JSONB, -- { "users": 5, "projects": 10 }
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Subscription usage tracking
CREATE TABLE usage_records (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
metric TEXT NOT NULL, -- 'api_calls', 'storage_mb', 'users'
value INTEGER NOT NULL,
period_start DATE NOT NULL,
period_end DATE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Invitations
CREATE TABLE invitations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
email TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'member',
token TEXT UNIQUE NOT NULL,
invited_by UUID REFERENCES profiles(id),
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
accepted_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Audit log (optional but recommended)
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
organization_id UUID REFERENCES organizations(id),
user_id UUID REFERENCES profiles(id),
action TEXT NOT NULL,
resource_type TEXT,
resource_id UUID,
metadata JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_org_members_org ON organization_members(organization_id);
CREATE INDEX idx_org_members_user ON organization_members(user_id);
CREATE INDEX idx_usage_org_period ON usage_records(organization_id, period_start, period_end);
CREATE INDEX idx_invitations_token ON invitations(token);
CREATE INDEX idx_audit_logs_org ON audit_logs(organization_id);
```
Row Level Security (RLS) Policies
```sql
-- Enable RLS
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE organization_members ENABLE ROW LEVEL SECURITY;
-- Profiles: Users can read and update their own profile
CREATE POLICY "Users can view own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
USING (auth.uid() = id);
-- Organizations: Members can read their organizations
CREATE POLICY "Members can view their organizations"
ON organizations FOR SELECT
USING (
id IN (
SELECT organization_id
FROM organization_members
WHERE user_id = auth.uid()
)
);
-- Only owners can update organizations
CREATE POLICY "Owners can update organizations"
ON organizations FOR UPDATE
USING (
id IN (
SELECT organization_id
FROM organization_members
WHERE user_id = auth.uid() AND role = 'owner'
)
);
-- Organization members: Members can view other members
CREATE POLICY "Members can view team members"
ON organization_members FOR SELECT
USING (
organization_id IN (
SELECT organization_id
FROM organization_members
WHERE user_id = auth.uid()
)
);
```
---
Authentication Setup
Supabase Auth Configuration
```typescript
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr';
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
// lib/supabase/server.ts
import { createServerClient, type CookieOptions } from '@supabase/ssr';
import { cookies } from 'next/headers';
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
cookieStore.set({ name, value, ...options });
},
remove(name: string, options: CookieOptions) {
cookieStore.set({ name, value: '', ...options });
},
},
}
);
}
```
Auth Middleware
```typescript
// middleware.ts
import { createServerClient, type CookieOptions } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
let response = NextResponse.next({
request: {
headers: request.headers,
},
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return request.cookies.get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
response.cookies.set({
name,
value,
...options,
});
},
remove(name: string, options: CookieOptions) {
response.cookies.set({
name,
value: '',
...options,
});
},
},
}
);
const { data: { user } } = await supabase.auth.getUser();
// Redirect to login if not authenticated
if (!user && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
// Redirect to dashboard if already authenticated
if (user && (
request.nextUrl.pathname === '/login' ||
request.nextUrl.pathname === '/signup'
)) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}
return response;
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.\\.(?:svg|png|jpg|jpeg|gif|webp)$).)',
],
};
```
---
Stripe Integration
Setup
```typescript
// lib/stripe/server.ts
import Stripe from 'stripe';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-11-20.acacia',
});
// Create checkout session
export async function createCheckoutSession(
organizationId: string,
priceId: string,
userId: string
) {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
line_items: [
{
price: priceId,
quantity: 1,
},
],
success_url: ${process.env.NEXT_PUBLIC_APP_URL}/dashboard/billing?success=true,
cancel_url: ${process.env.NEXT_PUBLIC_APP_URL}/pricing,
client_reference_id: organizationId,
metadata: {
organizationId,
userId,
},
});
return session;
}
```
Webhook Handler
```typescript
// app/api/webhooks/stripe/route.ts
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import Stripe from 'stripe';
import { stripe } from '@/lib/stripe/server';
import { createClient } from '@/lib/supabase/server';
export async function POST(req: Request) {
const body = await req.text();
const signature = (await headers()).get('stripe-signature')!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
}
const supabase = await createClient();
switch (event.type) {
case 'checkout.session.completed':
const session = event.data.object as Stripe.Checkout.Session;
await supabase
.from('organizations')
.update({
stripe_customer_id: session.customer as string,
stripe_subscription_id: session.subscription as string,
subscription_status: 'active',
})
.eq('id', session.metadata?.organizationId);
break;
case 'customer.subscription.updated':
const subscription = event.data.object as Stripe.Subscription;
await supabase
.from('organizations')
.update({
subscription_status: subscription.status,
})
.eq('stripe_subscription_id', subscription.id);
break;
case 'customer.subscription.deleted':
const deletedSub = event.data.object as Stripe.Subscription;
await supabase
.from('organizations')
.update({
subscription_status: 'canceled',
subscription_tier: 'free',
})
.eq('stripe_subscription_id', deletedSub.id);
break;
}
return NextResponse.json({ received: true });
}
```
---
Multi-Tenancy Patterns
Organization-Based (Recommended)
Pattern: Each organization has its own data space.
Benefits:
- Clear data isolation
- Easy to implement
- Scalable per organization
- Simple billing per organization
Implementation:
```typescript
// All queries include organization_id
const { data } = await supabase
.from('projects')
.select('*')
.eq('organization_id', currentOrgId);
```
Subdomain-Based (Advanced)
Pattern: Each organization has its own subdomain (e.g., acme.yourapp.com).
Benefits:
- Better branding
- Clear isolation
- Professional appearance
Challenges:
- DNS management
- SSL certificates
- More complex routing
Implementation:
```typescript
// middleware.ts
export function middleware(request: NextRequest) {
const hostname = request.headers.get('host')!;
const subdomain = hostname.split('.')[0];
// Fetch organization by subdomain
// Set in request context
}
```
---
MVP Feature Prioritization
Week 1-2: Foundation
- [ ] Project setup (Next.js + Supabase)
- [ ] Database schema creation
- [ ] Authentication (email + OAuth)
- [ ] Basic layouts and routing
- [ ] Landing page
Week 3-4: Core Features
- [ ] Dashboard layout
- [ ] First core feature (main value prop)
- [ ] User profile management
- [ ] Organization/team creation
- [ ] Team member invitations
Week 5-6: Monetization
- [ ] Pricing page
- [ ] Stripe integration
- [ ] Subscription management
- [ ] Usage limits enforcement
- [ ] Billing page
Week 7-8: Polish
- [ ] Email notifications
- [ ] Error handling
- [ ] Loading states
- [ ] Responsive design
- [ ] SEO optimization
Week 9: Launch Prep
- [ ] Testing (E2E, unit)
- [ ] Security audit
- [ ] Performance optimization
- [ ] Documentation
- [ ] Deployment scripts
---
Environment Variables
```bash
# .env.local
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-key
# Stripe
STRIPE_SECRET_KEY=sk_test_xxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Optional
SENTRY_DSN=your-sentry-dsn
POSTHOG_KEY=your-posthog-key
```
---
Deployment Checklist
Pre-Launch
- [ ] Environment variables configured
- [ ] Database migrations run
- [ ] RLS policies tested
- [ ] Stripe webhooks configured
- [ ] Domain configured
- [ ] SSL certificates active
- [ ] Analytics setup
- [ ] Error tracking (Sentry)
- [ ] Email service configured
- [ ] Terms of Service + Privacy Policy pages
Post-Launch
- [ ] Monitor error rates
- [ ] Check subscription flows
- [ ] Test webhook delivery
- [ ] Monitor database performance
- [ ] Set up backups
- [ ] Create status page
- [ ] Implement feature flags
---
Best Practices
Performance
- Use Server Components by default
- Implement proper caching strategies
- Optimize images with
next/image - Use React Server Actions for mutations
- Lazy load heavy components
Security
- Always use RLS policies
- Validate inputs on server
- Never expose service role key to client
- Use prepared statements (Supabase handles this)
- Implement rate limiting for sensitive endpoints
Development
- Use TypeScript strictly
- Write tests for critical paths
- Use database migrations (never manual changes)
- Version your API
- Document complex logic
User Experience
- Add loading states everywhere
- Implement optimistic updates
- Show clear error messages
- Make onboarding smooth
- Add helpful empty states
---
Common Patterns Reference
For detailed implementation patterns, see reference documents:
AUTHENTICATION_PATTERNS.md- OAuth, magic links, MFABILLING_PATTERNS.md- Stripe integration, webhooks, meteringMULTI_TENANT_PATTERNS.md- Organization structures, data isolationDEPLOYMENT_STRATEGIES.md- CI/CD, environments, monitoring
---
Example Output Format
When planning a SaaS, provide:
- Executive Summary
- Product overview
- Target users
- Key features
- Technical Architecture
- System diagram
- Tech stack rationale
- Database schema
- File Structure
- Complete folder organization
- Key file descriptions
- Development Roadmap
- Week-by-week breakdown
- Feature prioritization
- Estimated effort
- Deployment Plan
- Infrastructure setup
- Environment configuration
- Launch checklist
- Next Steps
- Immediate actions
- Setup commands
- Documentation links
---
Success Criteria
A well-planned SaaS should have:
- β Clear database schema with RLS
- β Secure authentication flow
- β Scalable architecture
- β Working billing integration
- β Organized file structure
- β Realistic timeline
- β Clear MVP scope
- β Deployment strategy
More from this repository10
Generates comprehensive SaaS architecture plans for Next.js and Supabase, transforming product ideas into detailed technical roadmaps with database schemas and development timelines.
Validates product ideas through comprehensive market research, competitive analysis, demand verification, and actionable recommendations to prevent wasted development efforts.
Designs mobile-first responsive interfaces by enforcing touch-friendly standards, optimizing performance, and ensuring cross-device accessibility.
Designs comprehensive product analytics systems by creating event tracking taxonomies, integrating SDKs, building dashboards, and generating actionable user behavior insights.
user-feedback-interpreter skill from sitechfromgeorgia/georgian-distribution-system
Performs comprehensive technical SEO audits, diagnosing website discoverability issues and providing actionable optimization strategies for improved search engine performance.
Prioritizes and scores product features using RICE/ICE frameworks, connecting ideas directly to business KPIs and revealing strategic investment opportunities.
saas-launch-planner skill from sitechfromgeorgia/georgian-distribution-system
system-architecture-advisor skill from sitechfromgeorgia/georgian-distribution-system
Designs and optimizes database schemas with expert guidance, ensuring scalable, secure, and compliant database architectures across SQL and NoSQL systems.