Instruction file imported from newtimes2003-prog/Bibelgenealogie (
.github/instructions/dev-workflow.instructions.md). Copyright stays with the author.
Entwicklungs-Workflow — Bibelgenealogie
Beachte dazu auch main.instructions.md.
Schema-Änderungen = neue Migration
Jede DB-Änderung kommt als neue Datei unter supabase/migrations/ mit
Timestamp-Präfix. Die Baseline (00000000000001_baseline_schema.sql)
bleibt unverändert.
Konvention: YYYYMMDDHHmmss_<snake_case_beschreibung>.sql (UTC).
Beispiel:
supabase/migrations/20260601090000_add_task_priority.sql
KI-Assistenten schreiben die Migration als Datei, spielen sie aber
nicht ein. Der Maintainer wendet sie an (Dashboard SQL Editor oder
supabase db push). Vollständige Regeln:
docs/migrations.md.
Was als SQL-Änderung zählt
- Neue Tabellen (
create table) - Schema-Änderungen (
alter table) - Neue/geänderte RLS-Policies
- Neue Indizes (
create index) - Neue Funktionen oder Trigger
- Initiale Seed-Daten (nur in
supabase/seed.sqlfür Dev-Reset, nicht in Migrationen) - Neue Enums oder Typen
Was keine SQL-Änderung ist
- Neue API-Routen oder React-Komponenten
- TypeScript-Änderungen ohne Schemaeingriff
- CSS/Styling-Änderungen
- Env-/Config-Dateien
Nach jeder Migration: Typen neu generieren
pnpm gen:types
Das Root-predev-Script tut das automatisch beim nächsten pnpm dev
(falls online, sonst skippt es und lässt die bestehende Datei intakt).
Pflicht-Checkliste für neue Tabellen
Jede neue Tabelle erhält bewusst eine RLS-Entscheidung. Default-Muster ist „service-role-only" — neue Tabellen erben dieses Muster:
create table if not exists public.<name> (
id bigint generated by default as identity primary key,
owner_id bigint references public.tenant_users(id) on delete cascade,
-- weitere Spalten
created_at timestamptz default now()
);
create index if not exists idx_<name>_owner on public.<name>(owner_id);
alter table public.<name> enable row level security;
-- Service-role only: keine permissiven Policies. App liest/schreibt via
-- createAdminClient() in lib/supabase/server.ts.
Wenn eine Tabelle öffentlich lesbar sein soll, explizit eine Read-Policy ergänzen — Beispiel:
create policy <name>_public_read
on public.<name> for select
using (<bedingung, z. B. is_active = true>);
Prüfabfrage: Tabellen mit RLS aber ohne Policy
select relname as tabelle
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
and c.relkind = 'r'
and c.relrowsecurity = true
and not exists (select 1 from pg_policy p where p.polrelid = c.oid)
order by relname;
Erwartet (im Default-Muster): alle App-Tabellen erscheinen — service-role-only ist das Design. Erst wenn owner-basierte Policies eingeführt werden, schrumpft die Liste auf wirklich admin-only Tabellen.
Pflicht: Seitentest nach Implementierung
Nach jeder Code-Änderung muss jede betroffene Route per Browser-Aufruf getestet werden.
| Änderung | Test |
|---|---|
| Neue Seite / Route | Happy-Path im Browser aufrufen |
| Geänderte Server Action | Formular absenden + Fehlerfälle |
| Geänderte API-Route | Aufruf mit gültigem + ungültigem Input |
| Auth-Flow (Login/Register/Reset) | Kompletter Durchlauf inkl. Mail-Bestätigung |
| Redirect-Logik (proxy.ts) | Sowohl erlaubten als auch blockierten Zugriff testen |
Bestanden, wenn
- Keine JS-Fehler in der Browser-Konsole.
- Keine 500/404 im Terminal.
- Redirects landen auf den erwarteten Routen.
- Formulare geben verständliche Fehlermeldungen.