Shuffle/supabase/README.md
cschlaefke 3135ed6381 docs(db): Meldungen (KAT-04) in Datenmodell, Katalogpflege, README und Umsetzungs-Nachtrag
Refs #13

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 19:16:31 +01:00

63 lines
7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Supabase – Datenbank für Shuffle
## Inhalt
| Pfad | Zweck |
|---|---|
| `migrations/` | Schema, Trigger und RLS-Policies für R1 (22 Tabellen, 3 Views). Nur additiv ändern, nie bestehende Dateien editieren. |
| `tests/database/` | pgTAP-Tests: Struktur-Regeln und Zugriffsrechte je Bereich. |
| `perf/` | Messskript für die Katalogsuche (kein Test, läuft nicht in `supabase test db`). |
| `templates/` | Auth-Mailvorlagen (HTML, Go-Template) für Bestätigung und Passwort-Reset. |
| `seed.sql` | Beispieldaten nur für die lokale Entwicklung. |
| `catalog/` | Katalog-Vokabular und Startbestand (CSV, Werkzeug `build_startbestand.ts`, erzeugte SQL-Dateien), siehe unten. |
## Lokal starten und testen
```bash
supabase start # lokales Backend
supabase db reset # Migrationen + Seed einspielen
supabase test db # alle pgTAP-Tests ausführen
```
## Registrierung (KTO-01)
- Der Trigger `handle_new_user` erzwingt Altersbestätigung, Zustimmung, `terms_version` und Anzeigename (1–30 Zeichen). Fehlertexte: siehe `docs/datenmodell-r1.md`. Clients senden diese Werte als `user_metadata` bei `signUp`.
- pgTAP-Fixtures, die `auth.users` direkt füllen, brauchen daher `age_confirmed`, `terms_accepted`, `terms_version` und `display_name` in `raw_user_meta_data`.
- Ergebnisse der GoTrue-Prüfung: `docs/specs/1-auth-spike-ergebnisse.md`.
- Auth-Einstellungen (`AUTH-CFG-nn` in `config.toml`), Env-Block für Staging/Produktion, Auth-Checkliste und bekannte Grenzen: [`docs/auth-konfiguration.md`](../docs/auth-konfiguration.md). Zentrale Release-Checkliste (Katalog, `checks.sql`, Zugang, Auth/SMTP, Runner): [`docs/release-checkliste.md`](../docs/release-checkliste.md).
- Mailvorlagen (Bestätigung, Passwort-Reset; de/en nach `user_metadata.locale`): `templates/`. Lokal landen Mails in Mailpit (`http://127.0.0.1:54324`).
## E2E-Tests (Playwright)
- `e2e/` testet GoTrue über Kong (`api`), die gebaute Web-App (`web`), die IP-Drosselung (`throttle`) und den SMTP-Ausfall (`spike`). Voraussetzung: `supabase start` mit Mailpit und Postgres (Ports 54321, 54322, 54324).
- `e2e/support/db.ts` verbindet sich direkt mit dem lokalen Postgres (Rolle `postgres`) und setzt `recovery_sent_at`/`confirmation_sent_at` für die Ablauftests; es bricht bei nicht-lokalem Host ab.
- Der Extra-Container für `throttle`/`spike` startet mit `e2e/support/start-throttle-gotrue.sh`. Details: [`e2e/README.md`](../e2e/README.md).
- CI: Job `e2e` in `.forgejo/workflows/ci.yml` (Runner `docker-host`, dind); Ablauf in [`docs/auth-konfiguration.md`](../docs/auth-konfiguration.md) Abschnitt 7.
## Katalog (KAT-05)
- Pflege in R1 nur über Studio bzw. `psql` (Rolle `postgres`), Ablauf und Regeln: [`docs/katalog-pflege.md`](../docs/katalog-pflege.md). Spec: `docs/specs/2-katalog-daten.md`.
- Suche und Entdecken lesen nur die View `catalog_games` (ohne ausgeblendete und zusammengeführte Spiele). Geänderte Fakten trägt ein Trigger in `games.manual_fields` ein.
- Zusammenführen von Duplikaten nur über die Funktion `public.admin_merge_games(quelle, ziel)` (nur Datenbankrolle `postgres`/`supabase_admin`, nicht über die API aufrufbar); Ablauf in `docs/katalog-pflege.md`, Abschnitt 5. Jede neue Tabelle mit Verweis auf `games` muss dort behandelt werden (Wächter in `tests/database/07_catalog_merge.test.sql` und `08_game_reports.test.sql`).
- Meldungen fehlender Spiele (`game_reports`) bearbeitet der Admin nur über `public.admin_resolve_report(meldung, status, ziel)` (nur Datenbankrolle `postgres`/`supabase_admin`); Ablauf in `docs/katalog-pflege.md`, Abschnitt 6. `visibility` und `owner_id` eines Spiels sind unveränderlich (Trigger `games_visibility_immutable`).
- `db reset` spielt `seed.sql`, `catalog/vocabulary.sql` und `catalog/startbestand.sql` ein (`[db.seed] sql_paths` in `config.toml`). Die SQL-Dateien in `catalog/` sind **erzeugt**; Quellen sind die CSV-Dateien. Neu erzeugen und testen (Deno, `brew install deno`):
```bash
deno run --allow-read=supabase --allow-write=supabase supabase/catalog/build_startbestand.ts
deno test --allow-read=supabase supabase/catalog/
```
- Ein Pfad in `sql_paths`, der nicht existiert, wird von der CLI nur mit Warnung übersprungen (kein Fehler). Genauere CLI-Ergebnisse: `docs/katalog-pflege.md`, Abschnitt 2.7.
- pgTAP-Tests, die Include-Dateien brauchen, nutzen `\ir ../support/…`; die Dateien in `tests/support/` sind erzeugt (gleiches Werkzeug) und keine Tests.
## Katalogsuche (KAT-01)
- `public.search_normalize(text)` (Normalisierung für Suche und Titelvergleich) und die RPC `public.search_catalog_games(…)` sind **für API-Rollen ausführbar** (`search_normalize`: `anon`, `authenticated`, `service_role`, weil generierte Spalten mit den Rechten des Schreibenden rechnen; `search_catalog_games`: `anon`, `authenticated`). Beides ist die Ausnahme von der Regel „Funktionen sind für niemanden aufrufbar“; die Rechte prüft `tests/database/09_catalog_search.test.sql`.
- **Fehlendes Spiel melden (KAT-04, `tests/database/10_game_reports_user.test.sql`):** `public.find_similar_catalog_games(titel, jahr)`, `public.report_missing_game(...)` und `public.adopt_report_target(meldung)` sind nur für `authenticated` ausführbar (`anon` und `service_role` nicht); ebenso die Hilfsfunktionen `strip_leading_article`, `normalize_game_title` und `report_day`. `adopt_report_target` ist die einzige `security definer`-Funktion dieser Gruppe (Eigentümer `postgres`, `search_path` leer, Aufrufer nur über `auth.uid()`, ruft keine `admin_*`-Funktion auf). `authenticated` darf in `game_reports` nur `owner_id, title, publisher_name, year, link, provisional_game_id` einfügen und nur `result_seen_at` ändern. Das Tageslimit (10 Nutzer-Meldungen je Berliner Tag) setzt ein Trigger durch, der unter READ COMMITTED (Standard bei PostgREST) wirkt; er gilt für jede Rolle, auch `postgres`. Vertrag und Fehlercodes: `docs/datenmodell-r1.md`, Abschnitt „Meldungen (KAT-04)“.
- Alternative Titel (`game_alt_titles`) sind für API-Rollen nur lesbar; Pflege über Studio (`docs/katalog-pflege.md`, Abschnitt 3.1) und die CSV-Spalte `alt_titles` (`de:Titel;en:Title`, `;` im Titel nicht erlaubt).
- Nach einem Image-Upgrade der Datenbank die Normalisierung prüfen (`docs/katalog-pflege.md`, Abschnitt 8).
- Messskript für das Zeitbudget der Suche (nur lokal, nie gegen Staging/Produktion, bewusst nicht unter `tests/`): `perf/catalog_search_perf.sql`, Aufruf im Kopfkommentar.
## Regeln
- Jede Tabelle hat `id` (uuid, PK), `created_at`, `updated_at` und Row Level Security.
- `updated_at` setzt ein Trigger; `id` und `created_at` sind nach dem Anlegen unveränderlich.
- Fremdschlüssel nur dort, wo Tabellen in Beziehung stehen, benannt `<Zieltabelle>_id`.
- Rechte werden explizit vergeben (erst alles entziehen, dann gezielt gewähren).
- Admin-Rolle kommt aus `app_metadata.role = 'admin'` im JWT, nie aus `user_metadata`; in R1 niemandem vergeben, Pflege über Studio (KAT-05 E10).
## Noch nicht enthalten
- Storage-Buckets und -Policies für Avatare und Spielbilder.
- Edge Functions (BGG-Import, Konto löschen).
- Selbst-Hosting-Setup auf Hetzner (ADR-0002, Aufgabe für `devops`).