# PostgreSQL-Persistenz ## Architekturstand Phase 11 ergänzt `PostgresAssessorRepository` als produktiven Adapter hinter dem bestehenden `AssessorRepository`. React, API, Importengine und Vergleichslogik kennen weder SQL noch den PostgreSQL-Treiber. Relationale Spalten und Fremdschlüssel sichern Identitäten und Beziehungen. Das vollständige versionierte Fachobjekt bleibt zusätzlich als JSONB erhalten. Damit können neue Scannerfelder verlustfrei aufgenommen werden, ohne die Integritätsregeln für Projekt, Assessment, Scan-Lauf, Datei und Finding zu umgehen. ## Lokale Datenbank starten 1. `.env.postgres.example` nach `.env.postgres` kopieren. 2. Ein langes, nur lokal verwendetes Passwort eintragen. 3. `npm run db:up` ausführen. 4. pm run start:local oder pm run serve:local starten. Das Startskript lädt .env.postgres automatisch und bildet daraus die lokale Loopback-Verbindung. ```text ASSESSOR_DATABASE_URL=postgresql://assessor:@127.0.0.1:5432/assessor ASSESSOR_DATABASE_SSL=disable ASSESSOR_DATABASE_POOL_SIZE=10 ``` 5. `npm run serve:local` starten. Ohne `ASSESSOR_DATABASE_URL` startet ASSESSOR bewusst im flüchtigen In-Memory-Entwicklungsmodus. Ist eine URL gesetzt und PostgreSQL nicht erreichbar, bricht der Serverstart ab; er fällt nicht still auf Arbeitsspeicher zurück. Dadurch kann ein Konfigurationsfehler keine scheinbar erfolgreichen, aber nicht dauerhaften Importe erzeugen. `ASSESSOR_DATABASE_SSL=disable` ist ausschließlich für die Loopback-Verbindung auf dem Entwicklungsrechner vorgesehen. Für entfernte Datenbankziele ist TLS standardmäßig erforderlich. Die spätere Firmenkonfiguration benötigt eine vertrauenswürdige interne Zertifikatskette. ## Migrationen Migrationen liegen versioniert unter `server/postgres/migrations`. Beim Start mit PostgreSQL: 1. nimmt der Prozess einen PostgreSQL-Advisory-Lock, 2. prüft Version und SHA-256-Prüfsumme jeder bekannten Migration, 3. führt jede neue Migration in einer eigenen Transaktion aus, 4. dokumentiert sie in `assessor_schema_migrations`, 5. verweigert den Start, wenn eine bereits angewandte Migration verändert wurde. Angewandte Migrationen dürfen niemals nachträglich editiert werden. Änderungen erhalten stets eine neue, aufsteigend nummerierte SQL-Datei. ## Schema und Suche Das Schema besitzt unter anderem: - Primär- und Fremdschlüssel mit kontrollierten Löschregeln - eindeutige Scan-Reihenfolgen pro Assessment - optimistische Review-Revisionen - eine globale Repository-Revision für konkurrierende Importtransaktionen - B-Tree-Indizes auf Fremdschlüsseln und Filterspalten - gespeicherte `tsvector`-Dokumente und GIN-Indizes für Findings - einen GIN-JSONB-Index für spätere strukturierte Zusatzfeldabfragen Importdaten werden zunächst im Prozess gestagt. Der Commit öffnet genau eine Datenbanktransaktion auf genau einer Poolverbindung, sperrt die Repository-Revision, schreibt alle Entitäten, validiert das vollständige kanonische Assessment-Modell und führt danach den Commit aus. Fehler erzeugen ein Rollback ohne Teilimport. ## Import-Fingerprints Migration `002_import_fingerprints.sql` ergänzt `assessor_import_fingerprints`. Der SHA-256-Wert ist Primärschlüssel; gespeichert werden außerdem Dateiname, Größe, letzter Dateiänderungszeitpunkt, erster und letzter Importzeitpunkt sowie ein Wiederholungszähler. Der Abschluss eines bestätigten Batchimports verwendet `commitCanonicalImport`. Der PostgreSQL-Adapter schreibt neues Projekt, Assessment, Scan-Lauf, kanonische Importdaten und Fingerprints auf derselben Poolverbindung innerhalb derselben Transaktion. Die Repository-Revision wird dabei genau einmal erhöht. Ein Validierungs-, Auswahl- oder Datenbankfehler erzeugt ein vollständiges Rollback. ## Abgeleitete Result DB `assessor_result_db_rows` und `assessor_result_db_state` (Migration 024) sind abgeleitete Daten: Das Backend baut sie unter einer Advisory-Sperre aus den kanonischen Tabellen neu auf, sobald sich die Repository-Revision oder eine Policy-/Waechterversion aendert. Sie werden nie von Hand bearbeitet und zaehlen die Repository-Revision nicht hoch. ## Backup Vor Migrationen, Updates und größeren Löschvorgängen ist ein logisches Backup zu erstellen. Bei installiertem PostgreSQL-Client: ```text pg_dump --format=custom --no-owner --file=assessor-YYYYMMDD.backup "$ASSESSOR_DATABASE_URL" ``` Das Backup muss außerhalb des Datenbankcontainers, zugriffsgeschützt und gemäß der später festzulegenden Aufbewahrungsfrist abgelegt werden. Regelmäßig muss ein Restore in eine getrennte Testdatenbank durchgeführt werden; ein Backup ohne geprüften Restore gilt nicht als belastbar. ## Restore Ein Restore ersetzt Daten und darf nur nach exakter Prüfung der Zieldatenbank erfolgen. Empfohlen wird zunächst eine neue leere Datenbank: ```text createdb assessor_restore_test pg_restore --no-owner --exit-on-error --dbname=assessor_restore_test assessor-YYYYMMDD.backup ``` Danach werden Migrationstabelle, Projektanzahl, Assessments, Scan-Läufe, Findings, Reviews und Stichprobenexporte geprüft. Erst nach erfolgreicher Validierung darf ein betriebliches Umschalten geplant werden. ## Löschung Projektlöschung verlangt weiterhin die exakte Projekt-ID und `cascade: true`. PostgreSQL entfernt abhängige Assessments, Scan-Läufe, Dateien, Tabellen, Vorkommen, Evidenz, Diagnosen, Reviews, Regeln und Vergleiche innerhalb einer Transaktion. Nicht mehr verwendete Finding-Definitionen werden anschließend bereinigt. Datenbank-Backups bleiben davon unberührt und benötigen ein eigenes Aufbewahrungs- und Löschkonzept in Phase 14. ## Verifikation Neben Schema- und Migrationsläufertests existiert ein echter Integrationstest gegen PostgreSQL 16. Er prüft idempotente Migrationen, atomare Mehrlaufimporte, Volltextsuche, optimistische Reviewkonflikte, Vergleiche, Export, Parallelkonflikte, kanonische Batchimporte, dauerhafte Fingerprint-Zähler und kaskadierende Projektlöschung. Der Test verwendet `ASSESSOR_TEST_DATABASE_URL` und darf niemals auf eine produktive Datenbank zeigen. ## Technische Referenzen - PostgreSQL: https://www.postgresql.org/docs/current/ddl-constraints.html - PostgreSQL-GIN: https://www.postgresql.org/docs/current/gin.html - PostgreSQL-Volltextsuche: https://www.postgresql.org/docs/current/textsearch.html - node-postgres-Transaktionen: https://node-postgres.com/features/transactions - node-postgres-Parameter: https://node-postgres.com/features/queries