240 lines
8.0 KiB
Markdown
240 lines
8.0 KiB
Markdown
# 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
|
||
<Link href="/kunden/login">Mein Konto</Link>
|
||
<Link href="/kunden/dashboard">Meine Anfragen</Link>
|
||
```
|
||
|
||
---
|
||
|
||
## 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:
|
||
<Link href="/kunden/login">Mein Konto</Link>
|
||
Nach Login: <Link href="/kunden/dashboard">Meine Anfragen</Link>
|
||
|
||
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.
|
||
```
|