fix(server): use configured PostgreSQL host in containers
Deploy / Test, build & deploy (push) Successful in 2m0s
Details
Deploy / Test, build & deploy (push) Successful in 2m0s
Details
This commit is contained in:
parent
7ba69494e1
commit
200a8ac381
|
|
@ -1349,6 +1349,7 @@ Aktualisierung nach dem Schritt-11-Orchestrierungsvertikalschnitt vom 2026-08-04
|
||||||
|
|
||||||
| Datum | Entscheidung | Begründung |
|
| Datum | Entscheidung | Begründung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-08-24 | Die PostgreSQL-Zieladresse der Serverlaufzeit wird bei Einzelvariablen-Konfiguration aus `ASSESSOR_POSTGRES_HOST` gelesen; ohne Wert bleibt `127.0.0.1` der lokale Standard. Eine explizite `ASSESSOR_DATABASE_URL` behaelt Vorrang. | Container teilen keinen Loopback-Namensraum. Der Compose-Dienstname `postgres` muss deshalb bis in die Backend-Verbindungszeichenfolge gelangen, ohne den bestehenden lokalen Entwicklungsbetrieb zu brechen. |
|
||||||
| 2026-08-23 | Im Pathfinder gerenderte Knoteninformationen sind das eigenstaendige Designelement `Pathfinder Micro Card` und keine allgemeine Matrix-/Finding-TileCard. Der Vertrag besitzt die Varianten `finding` und `relation`; Category bleibt eine groessere Relation-Auspragung. Bestaetigte Geometrie, Typografie und Radien sind eigene Tokens beziehungsweise Konstanten, und die gesamte Komposition skaliert unveraendert mit Faktor 0,4 im Graphkoordinatensystem. | Graphkarten beschriften Knoten und muessen Beziehungen sichtbar lassen. Eine Uebernahme allgemeiner Kartenmasse oder nachtraegliche kamerainverse Typografie wuerde die bestaetigte Darstellung verdecken beziehungsweise ihre inneren Proportionen veraendern. Ein eigener Vertrag erlaubt gezielte Regressionen, ohne regulaere TileCards ausserhalb des Pathfinders zu beeinflussen. |
|
| 2026-08-23 | Im Pathfinder gerenderte Knoteninformationen sind das eigenstaendige Designelement `Pathfinder Micro Card` und keine allgemeine Matrix-/Finding-TileCard. Der Vertrag besitzt die Varianten `finding` und `relation`; Category bleibt eine groessere Relation-Auspragung. Bestaetigte Geometrie, Typografie und Radien sind eigene Tokens beziehungsweise Konstanten, und die gesamte Komposition skaliert unveraendert mit Faktor 0,4 im Graphkoordinatensystem. | Graphkarten beschriften Knoten und muessen Beziehungen sichtbar lassen. Eine Uebernahme allgemeiner Kartenmasse oder nachtraegliche kamerainverse Typografie wuerde die bestaetigte Darstellung verdecken beziehungsweise ihre inneren Proportionen veraendern. Ein eigener Vertrag erlaubt gezielte Regressionen, ohne regulaere TileCards ausserhalb des Pathfinders zu beeinflussen. |
|
||||||
| 2026-08-23 | Scanner-Kontext wird zweistufig gespeichert: quellengetreue Reportabschnitte mit Prosa und Tabellen sowie typisierte EnvironmentObservations mit stabilen Schluesseln und explizitem Erfassungszustand. Findings bleiben ein getrennter Vertrag. | Nur die Rohstruktur verhindert Informationsverlust bei neuen PingCastle-Versionen; nur typisierte Fakten erlauben zugleich belastbare Dashboard-, Result-DB-, LLM- und Toolabfragen. Ein Zustandsfeld trennt echte Abwesenheit von leerer Ausgabe, fehlender Berechtigung, Lizenzgrenze und Parserluecke. |
|
| 2026-08-23 | Scanner-Kontext wird zweistufig gespeichert: quellengetreue Reportabschnitte mit Prosa und Tabellen sowie typisierte EnvironmentObservations mit stabilen Schluesseln und explizitem Erfassungszustand. Findings bleiben ein getrennter Vertrag. | Nur die Rohstruktur verhindert Informationsverlust bei neuen PingCastle-Versionen; nur typisierte Fakten erlauben zugleich belastbare Dashboard-, Result-DB-, LLM- und Toolabfragen. Ein Zustandsfeld trennt echte Abwesenheit von leerer Ausgabe, fehlender Berechtigung, Lizenzgrenze und Parserluecke. |
|
||||||
| 2026-08-23 | Typisierte Scanner-EnvironmentObservations werden als eigener Unified-Result-Quelltyp `environment-observation` projiziert und niemals als Finding umgedeutet. Die Projektion ist ein abgeleitetes Readmodell ueber die bestehende Environment-Persistenz; sie bewahrt Original-/Normalwert und vollstaendige Provenienz, bietet eigene Environment-Facetten und nimmt diese Zeilen aus Finding-spezifischen Facetten heraus. | Result DB, Exporte, LLMs und weitere Tools benoetigen einen gemeinsamen timeslotgebundenen Zugriff, ohne aus DFL, OS, PKI, Trusts oder Coverage kuenstliche Schweregrade, IOEs, Abweichungen oder Reviews abzuleiten. Ein Readmodell vermeidet Datenkopien und eine weitere Migration, waehrend der getrennte SourceKind den Vertrag eindeutig haelt. |
|
| 2026-08-23 | Typisierte Scanner-EnvironmentObservations werden als eigener Unified-Result-Quelltyp `environment-observation` projiziert und niemals als Finding umgedeutet. Die Projektion ist ein abgeleitetes Readmodell ueber die bestehende Environment-Persistenz; sie bewahrt Original-/Normalwert und vollstaendige Provenienz, bietet eigene Environment-Facetten und nimmt diese Zeilen aus Finding-spezifischen Facetten heraus. | Result DB, Exporte, LLMs und weitere Tools benoetigen einen gemeinsamen timeslotgebundenen Zugriff, ohne aus DFL, OS, PKI, Trusts oder Coverage kuenstliche Schweregrade, IOEs, Abweichungen oder Reviews abzuleiten. Ein Readmodell vermeidet Datenkopien und eine weitere Migration, waehrend der getrennte SourceKind den Vertrag eindeutig haelt. |
|
||||||
|
|
@ -1603,6 +1604,7 @@ Diese Entscheidungen werden erst getroffen, wenn die jeweilige Phase ansteht ode
|
||||||
|
|
||||||
| Risiko | Gegenmaßnahme |
|
| Risiko | Gegenmaßnahme |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| Die Compose-Konfiguration benennt den PostgreSQL-Dienst korrekt, waehrend das Backend den Host ignoriert und innerhalb des App-Containers gegen `127.0.0.1` verbindet; Build und Datenbank-Health bleiben dabei gruen, aber die App wird unhealthy. | `ASSESSOR_POSTGRES_HOST` in den Repository-Umgebungsvertrag und die Verbindungszeichenfolge aufnehmen, Loopback nur als lokalen Fallback verwenden und Docker-Hostname sowie lokalen Standard durch einen reinen Unit-Test absichern. |
|
||||||
| Eine Anzeige der technischen Paketversion koennte faelschlich als aktueller fachlicher Verarbeitungsstand verstanden werden; eine lokal im React-Code hartcodierte Zahl koennte ausserdem vom Processingvertrag abweichen. | Die zentrale Konstante `CURRENT_ASSESSOR_PROCESSING_VERSION` aus dem Processingvertrag im Markenblock rendern, weder `v` noch `Version` voranstellen und Quelle, Wert, Position sowie kompakte Metadaten-Typografie regressionspruefen. |
|
| Eine Anzeige der technischen Paketversion koennte faelschlich als aktueller fachlicher Verarbeitungsstand verstanden werden; eine lokal im React-Code hartcodierte Zahl koennte ausserdem vom Processingvertrag abweichen. | Die zentrale Konstante `CURRENT_ASSESSOR_PROCESSING_VERSION` aus dem Processingvertrag im Markenblock rendern, weder `v` noch `Version` voranstellen und Quelle, Wert, Position sowie kompakte Metadaten-Typografie regressionspruefen. |
|
||||||
| Ein Scanner-Reimport koennte den alten Lauf vor erfolgreicher Validierung loeschen, den falschen Timeslot beziehungsweise ein anderes Werkzeug ersetzen oder alte und neue Ergebnisse gleichzeitig in Work und Result DB anzeigen. | Vorschau und Abschluss kryptografisch an dasselbe Projekt-, Assessment- und ScanRun-Ziel binden, das erkannte Werkzeug gegen den aktiven Vorgaenger pruefen und Supersession samt neuem kanonischem Lauf in einer Repositorymutation committen. Den alten Lauf nicht loeschen; aktive Read-Modelle filtern `supersededByScanRunId`, waehrend der Projektexport beide Laeufe und ihre Beziehung erhaelt. |
|
| Ein Scanner-Reimport koennte den alten Lauf vor erfolgreicher Validierung loeschen, den falschen Timeslot beziehungsweise ein anderes Werkzeug ersetzen oder alte und neue Ergebnisse gleichzeitig in Work und Result DB anzeigen. | Vorschau und Abschluss kryptografisch an dasselbe Projekt-, Assessment- und ScanRun-Ziel binden, das erkannte Werkzeug gegen den aktiven Vorgaenger pruefen und Supersession samt neuem kanonischem Lauf in einer Repositorymutation committen. Den alten Lauf nicht loeschen; aktive Read-Modelle filtern `supersededByScanRunId`, waehrend der Projektexport beide Laeufe und ihre Beziehung erhaelt. |
|
||||||
| Ein Bericht desselben Werkzeugs mit gleichem Dateinamen oder Datum koennte faelschlich als Reimport akzeptiert werden; bei Mehrdatei-Reports koennte eine Teilmenge oder eine zusaetzliche Datei den falschen Bestand ersetzen. Ein Client koennte ausserdem eine reine Vorschaupruefung umgehen. | Anzahl und vollstaendiges SHA-256-Multiset der Originaldateien in Preview und Complete vergleichen und dieselbe Invariante in Local- und PostgreSQL-Repository sowie beim Uebernehmen bereits importierter Ersatzlaeufe erzwingen. Fehlende Originalhashes, Offline-Fallback und jede Abweichung fail closed ablehnen; der bestehende Scan bleibt aktiv. |
|
| Ein Bericht desselben Werkzeugs mit gleichem Dateinamen oder Datum koennte faelschlich als Reimport akzeptiert werden; bei Mehrdatei-Reports koennte eine Teilmenge oder eine zusaetzliche Datei den falschen Bestand ersetzen. Ein Client koennte ausserdem eine reine Vorschaupruefung umgehen. | Anzahl und vollstaendiges SHA-256-Multiset der Originaldateien in Preview und Complete vergleichen und dieselbe Invariante in Local- und PostgreSQL-Repository sowie beim Uebernehmen bereits importierter Ersatzlaeufe erzwingen. Fehlende Originalhashes, Offline-Fallback und jede Abweichung fail closed ablehnen; der bestehende Scan bleibt aktiv. |
|
||||||
|
|
@ -1780,6 +1782,7 @@ Diese Entscheidungen werden erst getroffen, wenn die jeweilige Phase ansteht ode
|
||||||
## 12. Änderungsprotokoll
|
## 12. Änderungsprotokoll
|
||||||
|
|
||||||
| Datum | Änderung |
|
| Datum | Änderung |
|
||||||
|
| 2026-08-24 | Phase-14-Containerverbindung korrigiert: Die Repository-Laufzeit uebernimmt `ASSESSOR_POSTGRES_HOST` in die PostgreSQL-Verbindungszeichenfolge, sodass der App-Container den Compose-Dienst `postgres` statt seines eigenen Loopbacks anspricht. `ASSESSOR_DATABASE_URL` behaelt Vorrang und `127.0.0.1` bleibt der lokale Standard. Docker-Hostname und lokaler Fallback sind synthetisch regressionsgeprueft; Gesamtlauf 735 bestanden, 8 optionale PostgreSQL-Tests uebersprungen, Local-only- und Designpruefung sowie Client-/Server-Produktionsbuild erfolgreich. Keine Schema- oder Datenmigration; Phase 14 bleibt offen. |
|
||||||
| 2026-08-24 | Phase-7-Dashboard-IOE-Kennzahl als Filtereinstieg umgesetzt: `IOEs found` ist bei vorhandenem Trefferbestand anklickbar, setzt bestehende Dashboardfilter zurueck, uebergibt exakt die als explizite `IOE Found`/`IOEs found` gezaehlten Datensatz-IDs an die vorhandene Work-Teilmenge und oeffnet Work. Bei null Treffern bleibt das Steuerelement deaktiviert, damit kein ungefilterter Bestand erscheint. Zehn fokussierte Dashboard- und Filtertests sowie vollstaendiger Client-/Server-Produktionsbuild erfolgreich; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
| 2026-08-24 | Phase-7-Dashboard-IOE-Kennzahl als Filtereinstieg umgesetzt: `IOEs found` ist bei vorhandenem Trefferbestand anklickbar, setzt bestehende Dashboardfilter zurueck, uebergibt exakt die als explizite `IOE Found`/`IOEs found` gezaehlten Datensatz-IDs an die vorhandene Work-Teilmenge und oeffnet Work. Bei null Treffern bleibt das Steuerelement deaktiviert, damit kein ungefilterter Bestand erscheint. Zehn fokussierte Dashboard- und Filtertests sowie vollstaendiger Client-/Server-Produktionsbuild erfolgreich; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
||||||
| 2026-08-24 | Phase-7-Dashboard-Ringspur nach Nutzerreferenz sichtbar gemacht: Der bislang mit dem Panel verschmelzende ungefuellte Anteil der oberen Statusringe verwendet nun den vorhandenen neutralgrauen Donut-Rahmentoken; Farbbogen, Geometrie, Werte und Interaktionen bleiben unveraendert. Sieben fokussierte Dashboardtests und vollstaendiger Client-/Server-Produktionsbuild erfolgreich; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
| 2026-08-24 | Phase-7-Dashboard-Ringspur nach Nutzerreferenz sichtbar gemacht: Der bislang mit dem Panel verschmelzende ungefuellte Anteil der oberen Statusringe verwendet nun den vorhandenen neutralgrauen Donut-Rahmentoken; Farbbogen, Geometrie, Werte und Interaktionen bleiben unveraendert. Sieben fokussierte Dashboardtests und vollstaendiger Client-/Server-Produktionsbuild erfolgreich; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
||||||
| 2026-08-24 | Phase-7-Dashboard-Statusleiste nach Nutzerreferenz korrigiert: Die sechs gleichartigen Donutkarten sind durch eine fuenfteilige Leiste ersetzt. Compliance Score erhaelt den grossen Ring mit Formelhinweis; Deviation, Passed und Not Run verwenden kompakte Ringe mit realer Anzahl und Prozentwert. Not Applicable und Error stehen gemeinsam in einer Zusammenfassung neben `IOEs found`. Der IOE-Wert zaehlt ausschliesslich explizite `IOE Found`-/`IOEs found`-Quellenfelder und wird nicht aus Deviations abgeleitet; Statuskarten bleiben direkte Filtereinstiege in Work. 14 fokussierte Dashboard-, Donut- und Inset-Tests sowie vollstaendiger Client-/Server-Produktionsbuild erfolgreich. Der bekannte Designcheck bleibt ausschliesslich an den unveraenderten Schattenregeln in `datahub-redesign.css` Zeilen 39/42 rot; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
| 2026-08-24 | Phase-7-Dashboard-Statusleiste nach Nutzerreferenz korrigiert: Die sechs gleichartigen Donutkarten sind durch eine fuenfteilige Leiste ersetzt. Compliance Score erhaelt den grossen Ring mit Formelhinweis; Deviation, Passed und Not Run verwenden kompakte Ringe mit realer Anzahl und Prozentwert. Not Applicable und Error stehen gemeinsam in einer Zusammenfassung neben `IOEs found`. Der IOE-Wert zaehlt ausschliesslich explizite `IOE Found`-/`IOEs found`-Quellenfelder und wird nicht aus Deviations abgeleitet; Statuskarten bleiben direkte Filtereinstiege in Work. 14 fokussierte Dashboard-, Donut- und Inset-Tests sowie vollstaendiger Client-/Server-Produktionsbuild erfolgreich. Der bekannte Designcheck bleibt ausschliesslich an den unveraenderten Schattenregeln in `datahub-redesign.css` Zeilen 39/42 rot; keine Import-, API-, Persistenz- oder Schemaaenderung. |
|
||||||
|
|
@ -2055,4 +2058,3 @@ Diese Entscheidungen werden erst getroffen, wenn die jeweilige Phase ansteht ode
|
||||||
| 2026-07-17 | Ersten versionierten Umsetzungsplan mit Zielarchitektur, Phasen, Abnahmekriterien, Entscheidungen und Risiken angelegt. |
|
| 2026-07-17 | Ersten versionierten Umsetzungsplan mit Zielarchitektur, Phasen, Abnahmekriterien, Entscheidungen und Risiken angelegt. |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ export interface RepositoryEnvironment {
|
||||||
ASSESSOR_DATABASE_SSL?: string;
|
ASSESSOR_DATABASE_SSL?: string;
|
||||||
ASSESSOR_DATABASE_POOL_SIZE?: string;
|
ASSESSOR_DATABASE_POOL_SIZE?: string;
|
||||||
ASSESSOR_POSTGRES_DB?: string;
|
ASSESSOR_POSTGRES_DB?: string;
|
||||||
|
ASSESSOR_POSTGRES_HOST?: string;
|
||||||
ASSESSOR_POSTGRES_USER?: string;
|
ASSESSOR_POSTGRES_USER?: string;
|
||||||
ASSESSOR_POSTGRES_PASSWORD?: string;
|
ASSESSOR_POSTGRES_PASSWORD?: string;
|
||||||
ASSESSOR_POSTGRES_PORT?: string;
|
ASSESSOR_POSTGRES_PORT?: string;
|
||||||
|
|
@ -38,20 +39,26 @@ function sslConfiguration(value: string | undefined): PoolConfig['ssl'] {
|
||||||
throw new Error('ASSESSOR_DATABASE_SSL muss disable oder require sein.');
|
throw new Error('ASSESSOR_DATABASE_SSL muss disable oder require sein.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function repositoryConnectionString(environment: RepositoryEnvironment): string | undefined {
|
||||||
|
const explicitConnectionString = environment.ASSESSOR_DATABASE_URL?.trim();
|
||||||
|
if (explicitConnectionString) return explicitConnectionString;
|
||||||
|
const password = environment.ASSESSOR_POSTGRES_PASSWORD?.trim();
|
||||||
|
if (!password) return undefined;
|
||||||
|
const host = environment.ASSESSOR_POSTGRES_HOST?.trim() || '127.0.0.1';
|
||||||
|
return `postgresql://${encodeURIComponent(environment.ASSESSOR_POSTGRES_USER?.trim() || 'assessor')}:${encodeURIComponent(password)}@${host}:${environment.ASSESSOR_POSTGRES_PORT?.trim() || '5432'}/${encodeURIComponent(environment.ASSESSOR_POSTGRES_DB?.trim() || 'assessor')}`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function createRepositoryRuntime(environment: RepositoryEnvironment = {
|
export async function createRepositoryRuntime(environment: RepositoryEnvironment = {
|
||||||
ASSESSOR_DATABASE_URL: process.env.ASSESSOR_DATABASE_URL,
|
ASSESSOR_DATABASE_URL: process.env.ASSESSOR_DATABASE_URL,
|
||||||
ASSESSOR_DATABASE_SSL: process.env.ASSESSOR_DATABASE_SSL,
|
ASSESSOR_DATABASE_SSL: process.env.ASSESSOR_DATABASE_SSL,
|
||||||
ASSESSOR_DATABASE_POOL_SIZE: process.env.ASSESSOR_DATABASE_POOL_SIZE,
|
ASSESSOR_DATABASE_POOL_SIZE: process.env.ASSESSOR_DATABASE_POOL_SIZE,
|
||||||
ASSESSOR_POSTGRES_DB: process.env.ASSESSOR_POSTGRES_DB,
|
ASSESSOR_POSTGRES_DB: process.env.ASSESSOR_POSTGRES_DB,
|
||||||
|
ASSESSOR_POSTGRES_HOST: process.env.ASSESSOR_POSTGRES_HOST,
|
||||||
ASSESSOR_POSTGRES_USER: process.env.ASSESSOR_POSTGRES_USER,
|
ASSESSOR_POSTGRES_USER: process.env.ASSESSOR_POSTGRES_USER,
|
||||||
ASSESSOR_POSTGRES_PASSWORD: process.env.ASSESSOR_POSTGRES_PASSWORD,
|
ASSESSOR_POSTGRES_PASSWORD: process.env.ASSESSOR_POSTGRES_PASSWORD,
|
||||||
ASSESSOR_POSTGRES_PORT: process.env.ASSESSOR_POSTGRES_PORT
|
ASSESSOR_POSTGRES_PORT: process.env.ASSESSOR_POSTGRES_PORT
|
||||||
}): Promise<RepositoryRuntime> {
|
}): Promise<RepositoryRuntime> {
|
||||||
const explicitConnectionString = environment.ASSESSOR_DATABASE_URL?.trim();
|
const connectionString = repositoryConnectionString(environment);
|
||||||
const localPassword = environment.ASSESSOR_POSTGRES_PASSWORD?.trim();
|
|
||||||
const connectionString = explicitConnectionString || (localPassword
|
|
||||||
? `postgresql://${encodeURIComponent(environment.ASSESSOR_POSTGRES_USER?.trim() || 'assessor')}:${encodeURIComponent(localPassword)}@127.0.0.1:${environment.ASSESSOR_POSTGRES_PORT?.trim() || '5432'}/${encodeURIComponent(environment.ASSESSOR_POSTGRES_DB?.trim() || 'assessor')}`
|
|
||||||
: undefined);
|
|
||||||
if (!connectionString) {
|
if (!connectionString) {
|
||||||
return {
|
return {
|
||||||
repository: new LocalAssessorRepository(),
|
repository: new LocalAssessorRepository(),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,19 @@
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { createRepositoryRuntime } from '../../server/repository-factory';
|
import { createRepositoryRuntime, repositoryConnectionString } from '../../server/repository-factory';
|
||||||
import { LocalAssessorRepository } from '../../src/persistence/local-assessor-repository';
|
import { LocalAssessorRepository } from '../../src/persistence/local-assessor-repository';
|
||||||
|
|
||||||
describe('repository runtime selection', () => {
|
describe('repository runtime selection', () => {
|
||||||
|
it('uses the configured PostgreSQL host and keeps loopback as the local default', () => {
|
||||||
|
expect(repositoryConnectionString({
|
||||||
|
ASSESSOR_POSTGRES_HOST: 'postgres',
|
||||||
|
ASSESSOR_POSTGRES_DB: 'assessor_experimental',
|
||||||
|
ASSESSOR_POSTGRES_USER: 'assessor_experimental',
|
||||||
|
ASSESSOR_POSTGRES_PASSWORD: 'synthetic password'
|
||||||
|
})).toBe('postgresql://assessor_experimental:synthetic%20password@postgres:5432/assessor_experimental');
|
||||||
|
expect(repositoryConnectionString({ ASSESSOR_POSTGRES_PASSWORD: 'synthetic' }))
|
||||||
|
.toBe('postgresql://assessor:synthetic@127.0.0.1:5432/assessor');
|
||||||
|
});
|
||||||
|
|
||||||
it('uses the explicit in-memory development mode when no database URL is configured', async () => {
|
it('uses the explicit in-memory development mode when no database URL is configured', async () => {
|
||||||
const runtime = await createRepositoryRuntime({});
|
const runtime = await createRepositoryRuntime({});
|
||||||
expect(runtime.persistence).toBe('memory');
|
expect(runtime.persistence).toBe('memory');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue