# Modul: Kunden-Portal (Supabase Auth + Dashboard)
> Vollständiges Kundenkonto-System auf Basis von Supabase Auth: Registrierung mit Email-Bestätigung (signierter Confirmation-Link), Login mit Magic Link oder Passwort, Kundendashboard mit Anfragen-Übersicht (Status, Positionen, Admin-Notizen), Profilverwaltung, Logout.
---
## Enthaltene Dateien
| Ziel im neuen Projekt | Inhalt |
|---|---|
| `app/kunden/login/page.tsx` | Login-Seite (Supabase Auth, Redirect nach Login) |
| `app/kunden/registrieren/page.tsx` | Registrierungs-Seite (mit API-Aufruf) |
| `app/kunden/dashboard/page.tsx` | Kundendashboard (Anfragen, Status-Badges, Positionen) |
| `app/auth/callback/page.tsx` | OAuth/Magic-Link Callback Handler |
| `app/api/kunden/anfragen/route.ts` | GET: Anfragen des eingeloggten Kunden |
| `app/api/kunden/registrieren/route.ts` | POST: Registrierung via Supabase Admin API + Email |
---
## Voraussetzungen
```bash
npm install @supabase/supabase-js @supabase/ssr
```
Benötigt außerdem:
- `lib/supabase.ts` mit Browser-Client und Service-Client
- `lib/mailer.ts` (Modul 01) – für Registrierungs-Bestätigungs-Email (optional, Supabase sendet selbst)
- Modul 04 (Reservation System) – wenn Kunden ihre Anfragen sehen sollen
---
## Umgebungsvariablen (`.env.local`)
```env
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ... # Für Registrierung via Admin API
APP_URL=https://example.com # Basis-URL für Confirmation-Links
```
---
## Datenbank-Setup (Supabase)
### 1. Supabase Auth aktivieren
Supabase Dashboard → Authentication → Settings:
- Email-Bestätigung aktivieren
- Redirect URL eintragen: `https://example.com/auth/callback`
### 2. Optional: Kunden-Profil-Tabelle
```sql
-- Verknüpft auth.users mit zusätzlichen Kundendaten
CREATE TABLE kunden_profile (
id uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
firma text,
telefon text,
erstellt_am timestamptz DEFAULT now()
);
-- Trigger: Profil automatisch beim User-Create anlegen
CREATE OR REPLACE FUNCTION handle_new_user()
RETURNS trigger AS $$
BEGIN
INSERT INTO public.kunden_profile (id)
VALUES (NEW.id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE PROCEDURE handle_new_user();
```
### 3. Row Level Security für Anfragen
```sql
-- Kunden sehen nur ihre eigenen Anfragen
ALTER TABLE anfragen ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Kunden sehen eigene Anfragen"
ON anfragen FOR SELECT
USING (auth.uid() = kunde_id);
```
---
## Einbindung Schritt für Schritt
### 1. Dateien kopieren
### 2. Supabase Middleware einrichten (`middleware.ts` im Projekt-Root)
```ts
import { createServerClient } from "@supabase/ssr";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export async function middleware(request: NextRequest) {
let response = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ cookies: { /* ... */ } }
);
await supabase.auth.getUser(); // Session refreshen
return response;
}
export const config = { matcher: ["/kunden/:path*"] };
```
### 3. Supabase Browser-Client in `lib/supabase.ts`
```ts
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
```
### 4. Dashboard an eigene Datenstruktur anpassen
`app/kunden/dashboard/page.tsx` erwartet:
- `anfragen` Tabelle mit `status`, `firma`, `erstellt_am`
- `anfragen_positionen` mit `maschine_name`, `mietbeginn`, `mietende`, `gesamt_preis`
- RLS-Policy: Kunden sehen nur `anfragen WHERE kunde_id = auth.uid()`
### 5. Navigation ergänzen
```tsx
Mein Konto
Meine Anfragen
```
---
## Anpassungspunkte
| Was | Wo |
|---|---|
| Registrierungs-Email | `lib/mailer.ts` → `sendeRegistrierungsBestaetigung()` |
| Passwort-Mindestlänge (8 Zeichen) | `app/api/kunden/registrieren/route.ts` → Zod-Schema |
| Dashboard-Felder | `app/kunden/dashboard/page.tsx` |
| Auth-Provider (Magic Link, OAuth) | Supabase Dashboard → Auth → Providers |
| Session-Cookie-Dauer | Supabase Dashboard → Auth → Settings → JWT Expiry |
| Kunden-Profil-Felder | `kunden_profile` Tabelle + Profilseite |
---
## Integrations-Prompt
Kopiere diesen Prompt in eine neue KI-Konversation, nachdem du die `files/` in dein Projekt kopiert hast. Ersetze alle `[PLATZHALTER]`.
```
Ich integriere das Kunden-Portal (Supabase Auth, Registrierung, Kundendashboard) in mein Next.js/Supabase-Projekt.
PROJEKT-KONTEXT:
- Modul 01 (Email) ist bereits integriert (mailer.ts verfügbar)
- Modul 04 (Reservierungssystem) ist bereits integriert (anfragen-Tabelle existiert)
- Kundenbereich URL-Prefix: /kunden
- App-URL: [https://beispiel.de]
BEREITS KOPIERTE DATEIEN (aus modules/06-kunden-portal/files/):
- app/kunden/login/page.tsx
- app/kunden/registrieren/page.tsx
- app/kunden/dashboard/page.tsx
- app/auth/callback/page.tsx
- app/api/kunden/anfragen/route.ts
- app/api/kunden/registrieren/route.ts
AUFGABEN – führe sie der Reihe nach aus:
1. SUPABASE AUTH KONFIGURIEREN:
Gehe zu Supabase Dashboard → Authentication → URL Configuration.
Trage ein:
- Site URL: [https://beispiel.de]
- Redirect URLs: [https://beispiel.de]/auth/callback
2. SUPABASE-PAKETE installieren (falls noch nicht vorhanden):
npm install @supabase/supabase-js @supabase/ssr
3. SUPABASE CLIENTS in lib/supabase.ts ergänzen:
Lies lib/supabase.ts. Füge hinzu (falls Browser-Client fehlt):
import { createBrowserClient } from "@supabase/ssr";
export function createBrowserSupabaseClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
4. MIDDLEWARE erstellen: Erstelle middleware.ts im Projekt-Root:
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function middleware(request: NextRequest) {
let response = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ cookies: {
getAll() { return request.cookies.getAll(); },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options));
},
}}
);
await supabase.auth.getUser();
return response;
}
export const config = { matcher: ["/kunden/:path*", "/auth/:path*"] };
5. RLS-POLICY für Anfragen: Führe im Supabase SQL-Editor aus:
ALTER TABLE anfragen ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Kunden sehen eigene Anfragen"
ON anfragen FOR SELECT USING (auth.uid() = kunde_id);
6. REGISTRIERUNGS-EMAIL anpassen: Lies lib/mailer.ts.
Passe die Funktion sendeRegistrierungsBestaetigung() an (oder erstelle sie falls nicht vorhanden):
- Ersetze "Mietpark Hahn" durch "[PROJEKTNAME]"
- Passe den Betreff an: "Bitte bestätigen Sie Ihre E-Mail – [PROJEKTNAME]"
7. DASHBOARD anpassen: Lies app/kunden/dashboard/page.tsx.
- Ersetze "Mietanfrage/Maschine" durch die eigene Bezeichnung
- Passe angezeigte Felder aus anfragen_positionen an
8. NAVIGATION ergänzen: Füge in den öffentlichen Header hinzu:
Mein Konto
Nach Login: Meine Anfragen
9. TEST:
a) /kunden/registrieren → Registrierung abschließen
b) Bestätigungs-Email öffnen, Link klicken → /auth/callback → /kunden/dashboard
c) /kunden/dashboard → Anfragen des Kunden erscheinen
d) /kunden/login → Logout → Redirect zu /kunden/login
Lies jede Datei vor dem Bearbeiten. Melde wenn alle Schritte abgeschlossen sind.
```