fde9d7799c
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>
105 lines
5.1 KiB
Markdown
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>
|