WorkTime ProHandbuch
Zur Anwendung

PostgreSQL einrichten

WorkTime Pro setzt PostgreSQL 16 voraus. Alles Schützenswerte liegt darin: Zeitbuchungen, Zeitkonten, Abwesenheiten, Verrechnungssätze, Prüfprotokoll.

Erweiterungen

Angelegt werden citext, pg_trgm, pgcrypto und btree_gist. Die letzte ist keine Zier: Auf ihr beruht die Ausschlussbedingung, die überlappende Verrechnungssätze verhindert.

Zwei Zugänge, und das ist der Kern

ZugangWofür
DATABASE_URL_MIGRATIONSMigrationen, Seed, Richtlinien — braucht Rechte am Schema
DATABASE_URLdie laufende Anwendung — ohne Sonderrechte

Row-Level-Security gilt nicht für den Eigentümer der Tabellen. Verbindet sich die Anwendung als er, sind die Richtlinien zwar eingespielt, greifen aber nicht; die Mandantentrennung hängt dann allein an der Anwendungsschicht. Die API meldet das beim Start als Fehler und verweigert ihn im Produktivbetrieb.

Zwei Zeilen in der .env genügen:

openssl rand -hex 24
APP_DB_USER=worktime_app
APP_DB_PASSWORD=<das erzeugte>

DATABASE_URL nicht selbst setzen: Sie wird in der docker-compose.yml aus diesen beiden gebildet. Das Passwort steht damit nur an einer Stelle; zwei Stellen laufen leicht auseinander, und der Container startet dann nicht.

Warum Hex und nicht Base64

Base64 enthält /, + und =. Ein / im Passwort beendet den Adressteil der Verbindungszeichenkette; PostgreSQL meldet dann invalid integer value "…" for connection option "port" — auf das Passwort kommt man beim Suchen nicht so schnell. Ein # wiederum schneidet in der .env den Rest der Zeile ab.

Die drei Lagen

APP_DB_USERAPP_DB_PASSWORDVerhalten
gesetztgesetztRolle wird eingerichtet, Zugang geprüft
gesetztleerAbbruch — halb eingerichtet ist ein Versehen, keine Einstellung
leer—Hinweis im Protokoll: verbindet als Eigentümer, RLS greift nicht

Die Richtlinien

packages/database/prisma/policies.sql aktiviert die Mandantentrennung auf Datenbankebene und die Unveränderlichkeit des Prüfprotokolls. Es ist bewusst kein Teil der Migrationen, weil es die Funktion app_current_tenant() erst selbst anlegt.

Über Docker wird es bei jedem Start angewendet — das Skript ist wiederholbar. Beim manuellen Aufbau einmalig nachziehen:

psql "$DATABASE_URL" -f packages/database/prisma/policies.sql

Ohne diesen Schritt läuft die Anwendung normal, es fehlt aber die zweite Verteidigungslinie.

Vor dem Einspielen auf gewachsene Daten

Einige Migrationen legen Bedingungen an, die es vorher nicht gab: keine überlappenden Verrechnungssätze, keine zwei laufenden Einsatzzeiten je Mitarbeiter. Findet die Datenbank widersprechende Zeilen, bricht die Migration ab und der Container startet nicht. Das ist gewollt — lieber ein Start, der sagt warum, als eine Datenbank, die stillschweigend Daten verwirft.

Ein Prüfskript zeigt vorher, was im Weg steht, ohne etwas zu ändern. Siehe Aktualisieren.

Sicherung

Ein pg_dump mit dem Anwendungs- oder Eigentümerkonto bricht ab, weil die Trennung als FORCE ROW LEVEL SECURITY gesetzt ist. Was stattdessen zu tun ist, steht unter Sicherung — dort auch, warum --enable-row-security der falsche Ausweg wäre.