diff --git a/docs/SUPABASE_MIGRATION.md b/docs/SUPABASE_MIGRATION.md new file mode 100644 index 0000000..504e709 --- /dev/null +++ b/docs/SUPABASE_MIGRATION.md @@ -0,0 +1,104 @@ +# Supabase Credential Migration — Deployment Notes + +## Hintergrund + +Das Tippspiel-Repo hatte versehentlich Secrets im Git-History (alter `.gitea/workflows/build.yml`). Im Zuge der Bereinigung wurden: + +- **DB-Passwort** rotiert +- **Service Role Key** vom Legacy-JWT-Format auf das neue Supabase-Schlüsselformat migriert + +Die alten Werte sind ungültig — Deployments mit alter Konfiguration funktionieren nicht mehr. + +## Supabase Key-System: was sich geändert hat + +Supabase hat das API-Key-System umgestellt: + +| Alt (Legacy, JWT) | Neu | +|---|---| +| `anon` (Browser/Public) | `sb_publishable_...` | +| `service_role` (Backend) | `sb_secret_...` | + +**Wichtige Unterschiede:** + +- Legacy-Keys sind JWTs (lange Strings beginnend mit `eyJ...`), neue Keys sind Tokens beginnend mit `sb_secret_...` bzw. `sb_publishable_...` +- Legacy-Keys können nur als Gruppe rotiert werden (per JWT-Secret-Reset, invalidiert alle User-Sessions) +- Neue Keys sind **einzeln** rotierbar +- Das Supabase-SDK akzeptiert beide Formate — **kein Code-Change nötig**, nur die Env-Variable austauschen + +**Wir nutzen jetzt den neuen `sb_secret_...`-Key** unter dem Variablennamen `SUPABASE_SERVICE_ROLE_KEY`. + +## Betroffene Variablen + +| Variable | Wo zu finden | +|---|---| +| `DATABASE_URL` | Supabase Dashboard → Project Settings → Database → Connection string (**Transaction Pooler**, Port 6543) | +| `SUPABASE_URL` | Supabase Dashboard → Project Settings → API (unverändert) | +| `SUPABASE_SERVICE_ROLE_KEY` | Supabase Dashboard → Project Settings → API Keys → **Secret keys** Tab → `sb_secret_...` | + +> **Wichtig:** Bei `DATABASE_URL` den **Transaction Pooler** (Port 6543, Host `aws-0-eu-west-1.pooler.supabase.com`, User `postgres.`) verwenden — **nicht** Direct Connection (Port 5432, Host `db..supabase.co`). Direct Connection läuft nur über IPv6 und scheitert in vielen Umgebungen mit `ENOTFOUND`. + +Korrektes URL-Format (Pooler): + +```text +postgresql://postgres.:@aws-0-eu-west-1.pooler.supabase.com:6543/postgres +``` + +## Deployment-Stellen + +Die Variablen müssen an **drei Stellen** synchron gehalten werden: + +### 1. Lokales Dev-Environment + +Datei: `backend/.env` (gitignored, nicht im Repo). + +**Wichtig bei frischem Clone / Maschinenwechsel:** `backend/.env` ist **bewusst** nicht in Git — Secrets gehören niemals ins Repo. Stattdessen liegt `backend/.env.example` als Template mit Platzhaltern bei. Auf jeder neuen Maschine einmalig: + +```bash +cd backend +cp .env.example .env +# dann .env öffnen und Platzhalter durch echte Werte ersetzen +``` + +**Mindestens benötigte Werte für lauffähiges Dev-Setup:** + +```bash +DATABASE_URL=postgresql://postgres.:@aws-0-eu-west-1.pooler.supabase.com:6543/postgres +SUPABASE_URL=https://.supabase.co +SUPABASE_SERVICE_ROLE_KEY=sb_secret_... +FOOTBALL_API_KEY=... +``` + +`ANTHROPIC_API_KEY` und `ELEVENLABS_API_KEY` aus `.env.example` werden aktuell **nicht** benötigt (Features wurden entfernt). + +**Empfehlung:** Werte in einem Passwort-Manager (1Password, Bitwarden o.ä.) hinterlegen, damit sie beim nächsten Umzug sofort zur Hand sind. **Niemals** per E-Mail/Slack/Chat verschicken. + +### 2. Portainer Stack `wm2026-tippspiel` (Stack 115) + +Portainer UI → Stack → **Environment variables** → Werte ersetzen → **Update the stack** + +> **Häufiger Fehler:** Beim Pasten **nicht** den Variablennamen mitkopieren. Ins Value-Feld kommt nur der reine Wert, **nicht** `DATABASE_URL=postgresql://...`. Sonst entsteht eine doppelte Präfix-Verschachtelung und der Container kann keine DB-Verbindung aufbauen. + +### 3. CI/CD Workflow (`.gitea/workflows/build.yml`) + +Der Workflow holt die Env-Vars **dynamisch aus der Portainer Stack-Konfig** (Schritt 2). Im Repo selbst stehen **keine** Secrets, sondern nur Referenzen wie `${{ secrets.PORTAINER_TOKEN }}` und `${{ secrets.DEPLOY_TOKEN }}`. Diese beiden Gitea-Secrets bleiben unverändert. + +## Migration-Checklist für neue Umgebung + +- [ ] Aktuelles DB-Passwort aus Supabase abrufen (oder neu setzen unter Project Settings → Database) +- [ ] Aktuellen `sb_secret_...`-Key aus Supabase Dashboard kopieren (API Keys → Secret keys) +- [ ] Connection String aus Pooler-Tab kopieren, `[YOUR-PASSWORD]` ersetzen +- [ ] In Ziel-Stack die drei Variablen setzen: `DATABASE_URL`, `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY` +- [ ] Stack redeployen +- [ ] Smoke-Test: `curl http://:/api/matches` → soll JSON mit `matches`-Array liefern (kein 500) +- [ ] Falls 500: Container-Logs prüfen auf `ENOTFOUND` (→ Direct Connection statt Pooler) oder `28P01 invalid_password` (→ Passwort falsch oder Pooler-Cache braucht ~30s) + +## Code-relevante Stellen + +- DB-Pool wird konfiguriert in `backend/src/db/client.ts` — liest `DATABASE_URL` +- SSL ist nur in `NODE_ENV=production` aktiv, mit `rejectUnauthorized: false` +- Pool-Settings: max 10 Verbindungen, 5s Connection-Timeout, 30s Idle-Timeout + +## Referenzen + +- Supabase API Keys Doku: +- Supabase Connection Pooler: