Vollständiges Datenmodell in deutscher Benennung: 20 Tabellen, 9 Aufzählungen, eine Migration, dazu die framework-freien Helfer für tagCodes und Geheimnisse. Regeln stehen zusätzlich in der Datenbank, nicht nur im Service: 12 CHECKs, 2 partielle Eindeutigkeitsindizes, 4 zusammengesetzte Fremdschlüssel. Die Mandantengrenze ist damit strukturell erzwungen. Schrittergebnisse, Kommentare und Protokolleinträge kaskadieren bewusst nicht — das Archiv ist das Gedächtnis der Anwendung. 106 Tests, davon 42 gegen die echten Datenbankregeln. Closes #6 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
61 lines
2.3 KiB
TypeScript
61 lines
2.3 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { describe, expect, it } from "vitest";
|
|
import { parse } from "yaml";
|
|
|
|
/**
|
|
* Die Datenbank im Betriebsstand ist absichtlich von aussen nicht erreichbar.
|
|
* Diese Tests halten das fest, damit ein ports:-Mapping nicht versehentlich
|
|
* zurueckkommt. Siehe docs/betrieb/inbetriebnahme.md.
|
|
*/
|
|
function compose(datei: string): Record<string, never> {
|
|
return parse(readFileSync(datei, "utf8")) as Record<string, never>;
|
|
}
|
|
|
|
describe("Betriebsstand: docker-compose.yml", () => {
|
|
const stand = compose("docker-compose.yml") as unknown as {
|
|
services: Record<string, { ports?: unknown[]; networks?: string[] }>;
|
|
networks: Record<string, { internal?: boolean } | null>;
|
|
};
|
|
|
|
it("veroeffentlicht keinen Port der Datenbank", () => {
|
|
expect(stand.services["postgres"]?.ports).toBeUndefined();
|
|
});
|
|
|
|
it("haengt die Datenbank nur in das interne Netz", () => {
|
|
expect(stand.services["postgres"]?.networks).toEqual(["intern"]);
|
|
});
|
|
|
|
it("hat das interne Netz ohne Gateway", () => {
|
|
expect(stand.networks["intern"]?.internal).toBe(true);
|
|
});
|
|
|
|
it("laesst nur den Webdienst in das externe Netz", () => {
|
|
const aussen = Object.entries(stand.services)
|
|
.filter(([, dienst]) => dienst.networks?.includes("extern"))
|
|
.map(([name]) => name);
|
|
expect(aussen).toEqual(["web"]);
|
|
});
|
|
|
|
it("bindet den Webdienst standardmaessig nur auf localhost", () => {
|
|
expect(stand.services["web"]?.ports).toEqual(["${BIND_ADDR:-127.0.0.1}:${APP_PORT:-3000}:3000"]);
|
|
});
|
|
|
|
it("bricht ohne Geheimnisse ab, statt mit Standardwerten zu starten", () => {
|
|
const roh = readFileSync("docker-compose.yml", "utf8");
|
|
expect(roh).toContain("${APP_SECRET:?");
|
|
expect(roh).toContain("${POSTGRES_PASSWORD:?");
|
|
expect(roh).toContain("${APP_URL:?");
|
|
});
|
|
});
|
|
|
|
describe("Betriebsstand: Entwicklungsdatenbank", () => {
|
|
it("bindet nur auf localhost und auf einen eigenen, umstellbaren Port", () => {
|
|
const stand = compose("docker-compose.dev.yml") as unknown as {
|
|
services: Record<string, { ports?: string[] }>;
|
|
};
|
|
// Der Standard ist 5434, weil 5432 lokal und 5433 von einem anderen Projekt
|
|
// belegt sein koennen. Umstellbar ueber DEV_DB_PORT.
|
|
expect(stand.services["postgres"]?.ports).toEqual(["127.0.0.1:${DEV_DB_PORT:-5434}:5432"]);
|
|
});
|
|
});
|