docs: add Supabase credential migration guide
Build & Deploy Tippspiel / build (push) Successful in 40s
Build & Deploy Tippspiel / build (push) Successful in 40s
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>
This commit is contained in:
@@ -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.<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>
|
||||||
Reference in New Issue
Block a user