SaaS Boilerplate mit Claude Code: Vollständiger Stack in einem Tag 2026
Die meisten SaaS-Ideen scheitern nicht am Produkt — sondern am Setup-Aufwand: Authentication, Billing, Multi-Tenancy, Onboarding-Flow. Claude Code reduziert diese Boilerplate-Arbeit von Wochen auf einen Tag.
Der SaaS-Stack den Claude Code in einem Tag aufbaut
- Next.js 15 App RouterServer Components, Server Actions, Streaming
- AuthenticationNextAuth v5 / Better Auth — Google, GitHub, Magic Link
- DatenbankPostgreSQL + Prisma ORM mit Migrations
- BillingStripe Subscriptions, Webhooks, Customer Portal
- EmailResend + React Email: Onboarding, Password Reset, Invoices
- Multi-TenancyOrganization/Workspace-Modell mit Role-Based Access
- DashboardAnalytics-Seite mit Usage-Tracking
- DeploymentVercel (Frontend) + Supabase/Neon (DB) + Upstash (Redis)
Der 1-Tag-Plan: Morgens Auth + DB-Schema. Mittags Stripe Billing + Webhooks. Nachmittags Dashboard + Email. Abends Deployment + Go-Live. Claude Code macht jeden Block in 30-60 Minuten statt 2-3 Tagen.
Schritt 1: Datenbank-Schema mit Multi-Tenancy
Multi-TenancyOrganization-basiertes Datenmodell
# Prompt: "Erstelle ein Prisma-Schema für eine Multi-Tenant SaaS-App:
# User kann mehreren Organizations gehören
# Organizations haben Plans (free/pro/enterprise)
# Row-Level-Security: User sieht nur eigene Org-Daten"
# schema.prisma — Claude Code generiert:
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
memberships OrgMembership[]
sessions Session[]
}
model Organization {
id String @id @default(cuid())
name String
slug String @unique // für URLs: /org/acme
plan Plan @default(FREE)
stripeId String? @unique
trialEndsAt DateTime?
members OrgMembership[]
projects Project[]
}
model OrgMembership {
id String @id @default(cuid())
role Role @default(MEMBER) // OWNER | ADMIN | MEMBER
userId String
orgId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
@@unique([userId, orgId])
}
enum Plan { FREE PRO ENTERPRISE }
enum Role { OWNER ADMIN MEMBER }
Schritt 2: Stripe Subscription Billing
StripeSubscription + Webhook-Handler
# Checkout Session erstellen
export async function createCheckoutSession(orgId, priceId) {
const org = await db.organization.findUnique({ where: { id: orgId } });
// Stripe Customer anlegen oder laden
let customerId = org.stripeId;
if (!customerId) {
const customer = await stripe.customers.create({
email: org.ownerEmail,
metadata: { orgId }
});
customerId = customer.id;
await db.organization.update({
where: { id: orgId },
data: { stripeId: customerId }
});
}
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: 'subscription',
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${APP_URL}/dashboard?upgraded=true`,
cancel_url: `${APP_URL}/pricing`,
metadata: { orgId }
});
return session.url;
}
# Webhook-Handler: Plan aktualisieren
export async function POST(req) {
const body = await req.text();
const sig = req.headers.get('stripe-signature');
const event = stripe.webhooks.constructEvent(
body, sig, process.env.STRIPE_WEBHOOK_SECRET
);
switch (event.type) {
case 'customer.subscription.updated':
case 'customer.subscription.created': {
const sub = event.data.object;
const orgId = sub.metadata.orgId;
const plan = getPlanFromPriceId(sub.items.data[0].price.id);
await db.organization.update({
where: { id: orgId },
data: { plan, stripeSubscriptionId: sub.id }
});
break;
}
case 'customer.subscription.deleted': {
const orgId = event.data.object.metadata.orgId;
await db.organization.update({
where: { id: orgId },
data: { plan: 'FREE' }
});
}
}
return Response.json({ received: true });
}
Schritt 3: Feature Gates für Plan-Limits
Feature GatesPlan-Limits durchsetzen
# lib/features.ts
const PLAN_LIMITS = {
FREE: { projects: 3, teamMembers: 1, apiCalls: 100 },
PRO: { projects: 20, teamMembers: 10, apiCalls: 10000 },
ENTERPRISE: { projects: Infinity, teamMembers: Infinity, apiCalls: Infinity }
};
export async function checkFeatureLimit(orgId, feature) {
const org = await db.organization.findUnique({
where: { id: orgId },
include: { _count: { select: { projects: true, members: true } } }
});
const limit = PLAN_LIMITS[org.plan][feature];
const current = org._count[feature];
if (current >= limit) {
throw new Error(`Plan limit reached: ${feature} (${current}/${limit}). Upgrade to PRO.`);
}
}
# In Server Action nutzen:
export async function createProject(formData) {
await checkFeatureLimit(session.orgId, 'projects'); // wirft wenn Limit erreicht
await db.project.create({ ... });
}
Deployment-Checkliste
- PostgreSQL-Verbindung mit Connection Pooling (Supabase/Neon)
- Stripe Webhooks in Production registriert + getestet
- Environment-Variablen in Vercel gesetzt (kein .env in Git!)
- CRON: Trial-Reminder-Emails 3 Tage vor Ablauf
- Error Monitoring: Sentry für kritische Pfade (Auth, Billing)
- Rate Limiting auf /api Routen (Upstash Redis)
- DSGVO: Privacy Policy, Imprint, Cookie-Consent
- Stripe Customer Portal aktiviert (Self-Service Upgrades/Downgrades)
Trial-to-Paid Rate: Das wichtigste Metric. Claude Code hilft dir Onboarding-Flows zu optimieren — beschreibe wo User abspringen und lass dir A/B-Test-Varianten generieren.
SaaS Boilerplate im Kurs
Im Claude Code Mastery Kurs bauen wir live eine vollständige SaaS-App: Authentication, Stripe Billing, Multi-Tenancy, Dashboard, Email-Onboarding — von 0 bis zum ersten zahlenden Kunden. Mit allem was du brauchst um schnell zu shippen.
14 Tage kostenlos testen →