Phase 0: Fundament der Feuerwehr-Verwaltungsplattform
Legt den kompletten Unterbau an, auf dem die Fachmodule aufsetzen. Betrieb: - docker-compose.yml mit Traefik, App, Worker, PostgreSQL 17 + PostGIS, Redis, MinIO und Gotenberg; Entwicklungs-Override ohne Traefik, dafuer mit Mailpit und Adminer - Mehrstufiges Dockerfile: eigener Benutzer, tini als PID 1, Healthcheck - .env.example mit einem Kommentar zu jeder Variable Mandantentrennung: - Row Level Security auf allen mandantenpflichtigen Tabellen - Zwei getrennte Datenbankverbindungen: florian_app mit aktiver RLS fuer die Anwendung, Eigentuemer-Zugang nur fuer Migration, Seed und Anmeldung - fuerOrganisation() als einziger Weg zu Fachdaten Nachvollziehbarkeit: - AuditLog append-only per Trigger; UPDATE ist dauerhaft gesperrt, DELETE nur im gekennzeichneten Aufbewahrungslauf - Geheimnisse werden vor dem Schreiben entfernt Anmeldung: - OIDC gegen ein extern betriebenes authentik, Rollen aus Gruppen nur als Vorbelegung beim ersten Login - Lokaler E-Mail/Passwort-Login als Rueckfallweg - Terminal per PIN und RFID mit zwei Schranken (Geraet, dann Person) Weiteres: - lib/authz.ts mit 9 Rollen und 38 Einzelrechten - lib/storage.ts (MinIO), lib/audit.ts, lib/warteschlange.ts (BullMQ) - Integrationen fuer Mail, Telegram und LLM hinter abschaltbaren Interfaces - tRPC v11, Basis-Layout mit Seitenleiste und dunkler Darstellung - Seed mit einer Beispielwehr: 16 Personen, 3 Fahrzeuge, 40 Geraete - 32 Vitest-Tests (davon 8 gegen eine echte Datenbank), 10 Playwright-Tests - README, Anleitung mit Screenshots, Roadmap, Aufwandsschaetzung, Devlog, Versionierungsregeln und Changelog Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
-- =============================================================================
|
||||
-- Kontrollierte Ausnahme vom Änderungsverbot des Audit-Logs.
|
||||
--
|
||||
-- Ausgangslage: Der Trigger aus 20260902000100_rls_policies verbietet UPDATE
|
||||
-- und DELETE auf audit_log. Das ist richtig — nachträglich verändern soll den
|
||||
-- Log niemand.
|
||||
--
|
||||
-- Es gibt aber genau einen Vorgang, der löschen können muss: der
|
||||
-- Aufbewahrungsjob des Workers. Nach AUDIT_AUFBEWAHRUNG_TAGE exportiert er die
|
||||
-- alten Einträge nach MinIO und räumt sie danach ab. Ohne diese Möglichkeit
|
||||
-- wächst die Tabelle unbegrenzt, und das Löschkonzept nach DSGVO ließe sich
|
||||
-- nicht umsetzen.
|
||||
--
|
||||
-- Der Ausweg ist ein ausdrücklicher Schalter, den nur der Eigentümer-Zugang
|
||||
-- setzen kann und der nur für die laufende Transaktion gilt:
|
||||
--
|
||||
-- BEGIN;
|
||||
-- SELECT set_config('app.audit_bereinigung', 'an', true);
|
||||
-- DELETE FROM audit_log WHERE zeitpunkt < now() - interval '10 years';
|
||||
-- COMMIT;
|
||||
--
|
||||
-- UPDATE bleibt unter allen Umständen verboten. Ein Eintrag kann verschwinden,
|
||||
-- nachdem er gesichert wurde — verfälscht werden kann er nie.
|
||||
-- =============================================================================
|
||||
|
||||
CREATE OR REPLACE FUNCTION audit_log_unveraenderlich()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
-- Änderungen sind ausnahmslos gesperrt.
|
||||
IF TG_OP = 'UPDATE' THEN
|
||||
RAISE EXCEPTION
|
||||
'Der Audit-Log ist unveraenderlich. UPDATE ist auf audit_log nicht zulaessig.'
|
||||
USING ERRCODE = 'insufficient_privilege';
|
||||
END IF;
|
||||
|
||||
-- Löschen nur im ausdrücklich gekennzeichneten Aufbewahrungslauf.
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
IF coalesce(current_setting('app.audit_bereinigung', true), '') = 'an' THEN
|
||||
RETURN OLD;
|
||||
END IF;
|
||||
|
||||
RAISE EXCEPTION
|
||||
'Der Audit-Log ist unveraenderlich. DELETE ist nur im Aufbewahrungslauf zulaessig '
|
||||
'(SET LOCAL app.audit_bereinigung = ''an'').'
|
||||
USING ERRCODE = 'insufficient_privilege';
|
||||
END IF;
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION audit_log_unveraenderlich() IS
|
||||
'Sperrt UPDATE auf audit_log dauerhaft und DELETE ausserhalb des Aufbewahrungslaufs.';
|
||||
|
||||
-- Die Anwendungsrolle darf den Schalter gar nicht erst setzen: sie hat kein
|
||||
-- DELETE-Recht auf audit_log (siehe vorherige Migration). Der Schalter wirkt
|
||||
-- also nur fuer den Eigentuemer-Zugang, den ausschliesslich Worker und
|
||||
-- Migrationen benutzen.
|
||||
Reference in New Issue
Block a user