This repository has been archived on 2026-05-06. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tippspiel/docs/SUPABASE_MIGRATION.md
Ronny fde9d7799c
Build & Deploy Tippspiel / build (push) Successful in 40s
docs: add Supabase credential migration guide
Documents the JWT-to-sb_secret key migration, deployment touchpoints
(local .env, Portainer Stack 115, Gitea workflow), and the fresh-clone
.env setup needed after machine migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-01 00:42:38 +02:00

105 lines
5.1 KiB
Markdown

# 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.<project-ref>`) verwenden — **nicht** Direct Connection (Port 5432, Host `db.<project-ref>.supabase.co`). Direct Connection läuft nur über IPv6 und scheitert in vielen Umgebungen mit `ENOTFOUND`.
Korrektes URL-Format (Pooler):
```text
postgresql://postgres.<project-ref>:<password>@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.<project-ref>:<password>@aws-0-eu-west-1.pooler.supabase.com:6543/postgres
SUPABASE_URL=https://<project-ref>.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://<host>:<port>/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: <https://supabase.com/docs/guides/getting-started/api-keys>
- Supabase Connection Pooler: <https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler>