Postgres, PostGraphile, RLS und SQL
Überblick
Datenebenen-Mechanismus für diesen Stack. Implementiert Defense in Depth (RLS als letzte Mauer) und den einen legalen Datenpfad. Stackspezifisch – gilt nicht für Projekte ohne PostGraphile/Postgres.
Der Datenpfad
Browser → App-Server → PostGraphile → PostgreSQL. Genau ein legaler Pfad.
- Der Browser kommuniziert nie direkt mit GraphQL/DB; die App fragt die DB nie direkt nach Anwendungsdaten ab.
- Die App übergibt Sitzungskontext nur als Header (Benutzer-ID, Organisationshinweis) – keine Autorisierungslogik in der App; der Kontext wird nachgeschaltet validiert, nicht als vertrauenswürdig eingestuft.
- Ein einziger Pfad = ein einziger Ort, um Auth-Kontext, Validierung und RLS durchzusetzen. Seitenkanäle sind die Löcher, die die Durchsetzung umgehen.
Sicherheitsregeln
- RLS ist die letzte Durchsetzungsebene. Prüfungen auf App-Ebene sind UX; die Datenbank ist die Mauer. Selbst ein Fehler in den darüberliegenden Ebenen darf keine fremden Mandantenzeilen preisgeben.
- Rollen modellieren echte Sitzungszustände – nicht eingeloggt, eingeloggt ohne Organisation, eingeloggt mit Organisation, eine reine Verbindungsrolle, eine reine Migrationsrolle. Rollen haben Bedeutung.
- Die privilegierte Verbindungsrolle führt niemals Anwendungsabfragen aus. Anwendungsabfragen laufen unter einer eingeschränkten, RLS-unterworfenen Rolle.
SECURITY DEFINER-Funktionen setzensearch_pathinline in ihrer Definition – jedes Mal, ohne Ausnahmen.- Abwesenheit ist
NULL, niemals ein leerer String. Leerstring-Sentinels sind verboten; den Wert bei Abwesenheit weglassen. - GraphQL ist eine DoS-Angriffsfläche – begrenzen Sie sie. Erzwingen Sie Abfragetiefenlimits und Kosten-/Komplexitätsanalyse; lehnen Sie überdimensionierte Abfragen ab. Begrenzen Sie die Paginierungsgröße. Setzen Sie ein DB-
statement_timeoutfür App-Rollen. Deaktivieren Sie Introspection in der Produktion, sofern nicht bewusst benötigt.
SQL-Stil
- Ein Objekt pro Datei – jede Tabelle, Funktion, Richtlinie, Grant-Gruppe in ihrer eigenen Datei.
- Organisiert nach
schema/objekttyp/name– das Verzeichnis spiegelt die Datenbankstruktur wider. - Include-Reihenfolge ist Abhängigkeitsreihenfolge; das Include-Manifest ist das Inhaltsverzeichnis.
- Inline dokumentieren.
COMMENT ONlebt in derselben Datei wie das Objekt – was und warum. - Aussagekräftige Aliase (Singular des Tabellennamens, nicht einzelne Buchstaben); PostgreSQL-Idiome folgen (
current_*-Getter). - Typen und benutzerorientierte Rollen sind Daten, keine hartcodierten Einschränkungen – Nachschlagetabellen mit Schlüssel/Bezeichnung/Beschreibung, durch Fremdschlüssel validiert, erweiterbar ohne Schemaänderungen.
Kurzreferenz
| Regel | Prüfung |
|---|---|
Neue SECURITY DEFINER-Funktion | search_path inline gesetzt? |
| Neue Tabelle mit Mandantendaten | RLS-Richtlinie + Verweigerungstests (siehe graphql-contract-testing)? |
| Fehlender Wert | NULL, nicht ''? |
| Neue GraphQL-Oberfläche | Tiefen-/Kostenlimit und Paginierungsbegrenzung? |
| Neues Objekt | Eigene Datei, abhängigkeitsgeordneter Include, inline COMMENT ON? |
Vollständige Begründung: Artikel XIII, XIV, XVIII der Verfassung, gebündelt unter engineering-constitution/references/engineering-constitution.md. Migrationen: zero-downtime-migrations. Vertragstests: graphql-contract-testing.