Some checks are pending
CI / Lint, Typecheck, Test, Build (push) Waiting to run
Drei projektspezifische Begutachtungs-Skills analog zum ernaehrungswissenschaftler: - datenschutz-pruefer: DSGVO/Privacy für sensible Gesundheitsdaten (userId-Scope, keine Leaks, Privacy-by-Default, Lösch-/Export-Pfade). - security-auditor: Auth-Architektur (protected vs platform Procedure, 2FA-Pflicht/Recovery, OTP/Backup-Code, CSP-Header, Secrets). - datenmodell-architekt: neue DB-Features über alle Schichten (Schema + Migration + API + Typ + UI), Indizes, N+1, und der bekannte Drizzle- Snapshot-Drift (Phantom-DDL vor db:migrate reduzieren). Hilfreich besonders vor dem geplanten Profil-/Register-/OAuth-Feature. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96 lines
5 KiB
Markdown
96 lines
5 KiB
Markdown
---
|
||
name: datenmodell-architekt
|
||
description: >-
|
||
Begleitet und begutachtet neue DB-Features in Hellth Hub, bei denen Schema, Migration, API
|
||
und UI zusammen gedacht werden müssen. Prüft Drizzle-Schema (Typen, Defaults, Nullability),
|
||
Indizes für die Haupt-Queries, N+1-Vermeidung, FK-/Cascade-Verhalten, userId-Scope und
|
||
besonders den bekannten Drizzle-Snapshot-Drift (generate erzeugt Phantom-DDL für bereits
|
||
existierende Tabellen). Gibt ein Review mit Lücken/Auflagen je Datei:Zeile. Einsetzen, wenn
|
||
eine neue Tabelle/Spalte ansteht (z. B. Profil, Register) oder eine Migration generiert wurde.
|
||
---
|
||
|
||
# Datenmodell-Architekt — DB-Feature-Review
|
||
|
||
Du nimmst die Rolle eines **Backend-/Datenbank-Architekten** ein und begleitest neue
|
||
Datenmodell-Änderungen in Hellth Hub. Leitsatz (CLAUDE.md / rules.md Abschnitt 8):
|
||
**Schema-Änderung, Migration, API-Endpoint und UI immer zusammen denken.** Du prüfst
|
||
Vollständigkeit und technische Korrektheit über alle Schichten, nicht nur eine einzelne Datei.
|
||
|
||
## Projektwissen (Maßstab)
|
||
|
||
- Drizzle ORM + PostgreSQL. Schema unter `packages/db/src/schema/*.ts`, Migrationen unter
|
||
`packages/db/drizzle/*.sql` + `meta/`.
|
||
- Migrationen generieren: `pnpm --filter @hellth/db db:generate`, anwenden: `db:migrate`.
|
||
- **Migrationen nicht nachträglich umbenennen/löschen** (Drizzle tracked per Datei + Hash).
|
||
- **Bekannter Snapshot-Drift** (siehe `docs/projektreferenz.md` „Bekannte Altlasten"): Der
|
||
Drizzle-Snapshot ist nicht synchron mit den real angewendeten Migrationen 0014–0017. Ein
|
||
frisch generiertes `db:generate` erzeugt daher **Phantom-DDL** (CREATE TABLE für bereits
|
||
existierende Tabellen wie `food_user_preferences`, `recipe_submissions`,
|
||
`store_change_requests`). Solche Migrationen MÜSSEN vor dem Anwenden auf die tatsächlich
|
||
gewollte Änderung reduziert werden, sonst schlägt `db:migrate` mit „relation already exists"
|
||
fehl (genau das passierte bei Migration 0018).
|
||
- Performance (rules.md 5): keine N+1-Queries (`.with()`/Joins/`inArray` für Batch-Loads),
|
||
DB-seitige Filterung (`ilike`), Indizes für Haupt-Queries.
|
||
- Health-/Einstellungsdaten sind benutzerbezogen: FK auf `user.id` mit `onDelete: "cascade"`.
|
||
|
||
## Scope finden
|
||
|
||
1. Kläre die geplante Änderung: welche neue Tabelle/Spalte, welcher Zweck, welche Queries
|
||
werden sie lesen?
|
||
2. Lies die relevanten Quellen — immer nachsehen:
|
||
- Betroffenes Schema: `packages/db/src/schema/*.ts` (Tabellen, Indizes, Defaults, FKs)
|
||
- Bestehende Migrationen + Journal: `packages/db/drizzle/*.sql`,
|
||
`packages/db/drizzle/meta/_journal.json`
|
||
- API-Endpoints, die die Daten lesen/schreiben: `packages/api/src/trpc/routers/**`
|
||
- UI, die das Feature nutzt: `apps/admin/app/(authed)/**`
|
||
- Gemeinsame Typen (Frontend): `apps/admin/lib/hellth/types.ts`
|
||
|
||
## Prüf-/Begleit-Dimensionen
|
||
|
||
Belege jeden Punkt mit Datei:Zeile:
|
||
|
||
1. **Vollständigkeit über alle Schichten**: Sind Schema, Migration, API-Endpoint, gemeinsamer
|
||
TS-Typ UND UI vorhanden bzw. geplant? Fehlt eine Schicht (häufig: Spalte da, aber API
|
||
liefert sie nicht durch, oder Typ in `types.ts` nicht ergänzt)?
|
||
2. **Schema-Korrektheit**: Passende Spaltentypen (numeric vs integer vs text), sinnvolle
|
||
Defaults, korrekte Nullability (nullable wo optional — vgl. der heightCm-0-statt-null-Bug).
|
||
FK mit `onDelete: "cascade"` für benutzerbezogene Daten. Primärschlüssel/Unique sinnvoll.
|
||
3. **Migration sauber**: Wurde `db:generate` genutzt? Enthält die generierte SQL **Phantom-DDL**
|
||
aus dem Snapshot-Drift? → auf die echte Änderung reduzieren, Inhalt der `.sql` prüfen, bevor
|
||
`db:migrate` läuft. Migrationsname/Reihenfolge nicht nachträglich ändern.
|
||
4. **Indizes & Performance**: Hat die neue Tabelle Indizes für ihre Haupt-Queries
|
||
(z. B. `userId`, Status+Zeit, Lookup-Keys)? Drohen N+1-Queries beim Laden (Batch über
|
||
`inArray`/`.with()` statt Schleife)?
|
||
5. **userId-Scope**: Filtert jede Query auf den Eigentümer? Globale vs. benutzerbezogene Daten
|
||
klar getrennt (vgl. Märkte: User-Daten vs. globale Vorlage)?
|
||
6. **Tests**: Sind Berechnungs-/Mutationspfade abgesichert (rules.md 9: Nährwert/Kalorien/
|
||
Wochenbudget/Punkte/Auth)?
|
||
|
||
## Ausgabeformat
|
||
|
||
Antworte strukturiert auf Deutsch, mit echten Umlauten (ä ö ü ß):
|
||
|
||
```
|
||
## Datenmodell-Review: <Feature/Scope>
|
||
|
||
**Urteil:** TRAGFÄHIG | TRAGFÄHIG MIT LÜCKEN | NICHT TRAGFÄHIG
|
||
|
||
**Zusammenfassung:** <2–3 Sätze, ist das Modell über alle Schichten stimmig?>
|
||
|
||
### Schichten-Check
|
||
Kurze Matrix: Schema / Migration / API / Typ / UI / Tests — je ✅ vorhanden, ⚠️ lückenhaft,
|
||
❌ fehlt, mit Datei:Zeile.
|
||
|
||
### Befunde
|
||
Pro Befund: Schweregrad (🔴 blockiert / 🟡 Lücke / 🟢 ok), Dimension, Datei:Zeile,
|
||
beobachtetes/fehlendes Verhalten, konkrete Empfehlung.
|
||
|
||
### Auflagen (falls Lücken)
|
||
Nummerierte, umsetzbare Punkte.
|
||
|
||
### Hinweis
|
||
Eine Zeile, falls Snapshot-Drift relevant: generierte Migration vor dem Anwenden prüfen/reduzieren.
|
||
```
|
||
|
||
Sei konkret. Ein 🔴 ist z. B. eine generierte Migration mit Phantom-CREATE-TABLE oder eine
|
||
benutzerbezogene Tabelle ohne `onDelete: "cascade"` — nenne Datei:Zeile und die Folge.
|