Production SaaS Starter

Production SaaS Starter

Production-orientierte B2B-SaaS-Basis mit workspace-basierter Multi-Tenancy, Stripe-Billing, Platform-Admin, RBAC und i18n. Diese Anleitung bringt Sie in unter einer Stunde vom Klon zum lokalen Betrieb.

Übersicht

Übersicht

Der Production SaaS Starter ist eine workspace-basierte Multi-Tenant-Plattform — keine Minimal-Demo. Er enthält echte Muster: PostgreSQL RLS, SECURITY DEFINER RPCs, Stripe-Webhook-Idempotenz, duale RBAC-Schichten und Service-Provider-Abstraktion.

  • Workspaces mit Mitgliedschaften, Einladungen und slug-basierten URLs
  • Stripe-Abonnements, Usage-Metering, Promo-Codes und Enterprise-Deals
  • Platform-Admin-Konsole mit Audit-Logs und User/Workspace-Moderation
  • E-Mail/Passwort + OAuth, 2FA, Passwort-Reset via Resend

Stack: Next.js 16, React 19, Supabase, Stripe, Resend, next-intl mit 4 Locales.

Setup~3 Min.

Abhängigkeiten installieren

Installieren Sie npm-Pakete im Projektroot, bevor Sie Umgebungsvariablen konfigurieren.

Einmal nach dem Klonen des Repositorys ausführen:

Terminal
npm install
Voraussetzung~5 Min.

Umgebungs-Setup

Konfigurieren Sie .env.local, bevor Sie die App starten. Legen Sie die Datei zuerst an und fügen Sie Werte Abschnitt für Abschnitt hinzu, während Sie das Setup unten abschließen.

Lokale Env-Datei erstellen

Kopieren Sie .env.example → .env.local im Projektroot, bevor Sie fortfahren. Fügen Sie Stripe- und Resend-Werte in den Abschnitten unten hinzu. Supabase-Variablen werden im Supabase-Setup-Abschnitt konfiguriert.

Terminal
cp .env.example .env.local

Windows: copy .env.example .env.local

App

Erforderlich

Ihre deployte App-URL — für Checkout-Weiterleitungen, E-Mail-Links und OAuth-Callbacks.

Schritte

  1. 1Für lokale Entwicklung NEXT_PUBLIC_APP_URL=http://localhost:3000 setzen
  2. 2Für Production Vercel-Deployment-URL oder Custom Domain verwenden
  3. 3Variable in Vercel → Projekt → Einstellungen → Umgebungsvariablen hinzufügen

Umgebungsvariablen

NEXT_PUBLIC_APP_URLErforderlich

Öffentliche URL Ihrer SaaS-App (ohne abschließenden Schrägstrich).

Wo zu finden

Lokal: http://localhost:3000 · Production: Vercel-Projektdomain oder Custom Domain

Beispiel: https://app.ihredomain.de

NEXT_PUBLIC_APP_NAME

Markenname in transaktionalen E-Mails.

Wo zu finden

Beliebigen Anzeigenamen wählen — kein externer Dienst nötig

Beispiel: Acme SaaS

Erlaubte Origins

Cross-Origin-Zugriff für CSRF-Validierung und Server Actions konfigurieren.

ALLOWED_ORIGINS

Kommagetrennte Liste der Frontend-Domains, die auf APIs zugreifen dürfen.

.env.local
ALLOWED_ORIGINS=
Einzelner Origin
ALLOWED_ORIGINS=http://localhost:3000
Mehrere Origins
ALLOWED_ORIGINS=http://localhost:3000,https://example.com
Setup~5 Min.

Supabase-Setup

Diese Supabase-Schritte der Reihe nach ausführen — Projekt erstellen, dann Umgebungsvariablen hinzufügen.

Diese Supabase-Schritte der Reihe nach ausführen — Projekt erstellen, dann Umgebungsvariablen hinzufügen.

2 Schritte — der Reihe nach ausführen

Supabase-Setup

~5 Min.

Projekt erstellen und Project ID kopieren

1

Supabase-Projekt erstellen

Bei supabase.com anmelden, New project klicken, Name und Region wählen, Datenbankpasswort setzen und auf die Bereitstellung warten.

Supabase Dashboard öffnen
2

Project ID kopieren

Diese verwenden Sie beim Erstellen der API-URL und der App-Konfiguration.

Wo zu finden: Supabase Dashboard → Project → Project Settings → Project ID

Supabase-Umgebungsvariablen

Nach Erstellung des Supabase-Projekts in .env.local eintragen.

Beide Schlüssel befinden sich auf derselben Seite.

NEXT_PUBLIC_SUPABASE_URL

Ihre Projekt-API-URL.

Wenn Sie noch kein Projekt erstellt haben:

.env.local
NEXT_PUBLIC_SUPABASE_URL=https://YOURPROJECTID.supabase.co

Wo zu finden

Supabase Dashboard → Projekt öffnen → Settings → API → Project URL

NEXT_PUBLIC_SUPABASE_ANON_KEY

Öffentlicher anon key für clientseitige Supabase Auth und Abfragen.

Wo zu finden

Supabase Dashboard → Project Settings → API Keys → Legacy API Keys → anon public

SUPABASE_SERVICE_ROLE_KEY

Nur serverseitiger service_role key — niemals im Client preisgeben.

Wo zu finden

Supabase Dashboard → Project Settings → API Keys → Legacy API Keys → service_role

Super-Admin-E-Mail

Nach Konfiguration der Supabase-Zugangsdaten hinzufügen.

SUPER_ADMIN_EMAIL

E-Mail-Adresse, die Super-Admin-Berechtigungen erhalten soll.

.env.local
SUPER_ADMIN_EMAIL=
Beispiel
SUPER_ADMIN_EMAIL=admin@example.com
Konfiguration~15 Min.

Stripe-Setup

Stripe CLI

Stripe CLI für lokale Authentifizierung und Webhook-Weiterleitung während der Entwicklung.

  1. 1Stripe CLI gemäß der offiziellen Stripe-Dokumentation installieren
  2. 2Plattformspezifische Installationsschritte abschließen
  3. 3Stripe-Authentifizierung/Login ausführen
  4. 4Nach der Authentifizierung mit der lokalen Stripe-Entwicklung fortfahren
Stripe CLI Installationsanleitung

CLI authentifizieren

login ausführen — ein Browserfenster verbindet Ihr Stripe-Konto:

Terminal
stripe login

Webhooks lokal weiterleiten

Zuerst ausführen:

Terminal
stripe listen --forward-to localhost:3000/api/stripe/webhook

Dann das generierte Signing-Secret (whsec_...) aus der Terminalausgabe kopieren:

Terminal
whsec_xxxxx

In .env.local einfügen:

.env.local
STRIPE_WEBHOOK_SECRET=whsec_xxxxx

API-Schlüssel

Öffnen Sie das Stripe Dashboard und kopieren Sie Ihre Schlüssel in .env.local — niemals Schlüssel im Repository oder in der Dokumentation hardcoden.

Stripe Dashboard öffnen
  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY — Publishable key kopieren
  • STRIPE_SECRET_KEY — Secret key kopieren
Konfiguration~10 Min.

Resend-Setup

Resend

Erforderlich

Transaktions-E-Mail — Einladungen, 2FA-OTP, Passwort-Reset. Supabase-E-Mail wird nicht verwendet.

Schritte

  1. 1Auf resend.com registrieren
  2. 2Sende-Domain hinzufügen und verifizieren (DNS-Einträge)
  3. 3API-Key erstellen
  4. 4RESEND_FROM_DOMAIN auf Ihre verifizierte Sende-Domain setzen (siehe Resend-Setup unten)

Umgebungsvariablen

RESEND_API_KEYErforderlich

API-Key zum E-Mail-Versand.

Wo zu finden

Resend Dashboard → API Keys → Create API Key

RESEND_FROM_DOMAIN

Muss Ihre verifizierte Resend-Domain enthalten. Nur Root-/Origin-Domain verwenden — keine Subdomain.

.env.local
RESEND_FROM_DOMAIN=
Beispiel
RESEND_FROM_DOMAIN=shipy.live
Setup~2 Min.

Schnellstart

Nach Abschluss von Umgebungs-, Supabase-, Stripe- und Resend-Setup oben ausführen:

Seed-Pläne mit Stripe synchronisieren — hauptsächlich zum Testen und zum Abgleich der Stripe-Pläne mit der Datenbank

Terminal
npm run sync:plans

🎉 Glückwunsch!

Alles ist konfiguriert. Starten Sie die Anwendung:

Terminal
npm run dev

Sie sind startklar!

Referenz~3 Min.

Entwicklung vs. Production

Unterschiedliche Befehle für den täglichen Entwicklungsbetrieb und die lokale Vorschau eines Production-Builds.

Entwicklung

Entwicklungsserver mit Hot Reload starten:

Terminal
npm run dev

Production-Vorschau

Production-Umgebung lokal prüfen — App bauen, dann Production-Server starten:

Terminal
npm run build
Terminal
npm run start
Referenz

Skript-Referenz

BefehlBeschreibung
npm run sync:plansSeed-Pläne mit Stripe-Produkten/Preisen synchronisieren
npm run devEntwicklungsserver starten
npm run buildProduction-Build
npm run startProduction-Server starten (nach Build)
npm run testJest-Unit-Tests ausführen (nur Services)
Referenz

Architektur

Vier Schichten mit strikter Aufrufreihenfolge — Agents und Entwickler folgen demselben Pfad:

UI → Server Actions / API → Services → Repositories → PostgreSQL (RLS/RPC)

Wichtige Orte:

1

Schicht 1

Präsentation — src/app/, src/components/

2

Schicht 2

Anwendung — Server Actions, createRequestContext(), RBAC-Guards

3

Schicht 3

Domain — src/modules/*/ *.service.ts (Geschäftslogik)

4

Schicht 4

Daten — Repositories + PostgreSQL RLS/RPCs via src/services/

Referenz

Multi-Tenancy

Ein Workspace ist der Mandant — es gibt keine separate Organisationstabelle.

  • Mandanten-Key: workspaces.id (UUID); URLs nutzen eindeutigen slug
  • Memberships verknüpfen User mit Workspaces in owner-, admin- oder member-Rollen
  • RLS-Policies erzwingen workspace_id IN (Mitgliedschaften des Users)

Platform-Admins greifen über platform_admins auf /admin zu — Rollen super_admin, platform_admin oder platform_viewer.

Referenz

Authentifizierung & Autorisierung

Auth-Flow: Login → optional 2FA → Onboarding (kein Workspace) oder Workspace-Dashboard. Platform-Admin-Einladungen führen zu platform-onboarding.

  • E-Mail/Passwort und OAuth via Supabase Auth
  • 2FA via E-Mail-OTP (Resend) — nicht Supabase-Built-in-E-Mail
  • Passwort-Reset mit tokenbasiertem Flow und Rate Limiting

Workspace-Rollen und Berechtigungen:

  • ownerBilling, Workspace löschen, volle Mitgliederverwaltung
  • adminMitglieder einladen/entfernen, Workspace-Einstellungen aktualisieren
  • memberLesen und teilnehmen — keine Admin-Aktionen
Referenz

Billing & Abonnements

Ein aktives Abonnement pro Workspace, verknüpft mit Stripe-Customer- und Subscription-IDs.

  • Checkout für neue Abos; Portal für Self-Service-Verwaltung
  • Upgrades mit Proration; Downgrades zum Periodenende geplant
  • Seed-Pläne: Starter ($29/Mo.), Pro ($39/Mo.), Enterprise (individuell)
  • Webhook unter /api/stripe/webhook synchronisiert Status mit idempotenter stripe_events-Tabelle
Deployment~15 Min.

Deployment

Empfohlener Stack: Vercel (Next.js) + Supabase Cloud + Stripe-Webhooks.

  1. 1Alle Env-Variablen in Vercel setzen — Abschnitt Umgebungs-Setup oben
  2. 2Next.js-App deployen
  3. 3Stripe-Webhook registrieren → https://YOUR_APP_URL/api/stripe/webhook
  4. 4Super-Admin bootstrappen und sync:plans in Production ausführen