This commit was merged in pull request #59.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- HANDGESCHRIEBEN. Prisma erzeugt hier zusaetzlich Loeschbefehle fuer die
|
||||
-- zusammengesetzten Fremdschluessel (Mandantengrenze), die Trigramm-Indizes
|
||||
-- (Archivsuche), die partiellen eindeutigen Indizes und die Trigger auf
|
||||
-- veroeffentlichten Versionen: es kennt sie nicht, weil sie sich im Schema nicht
|
||||
-- ausdruecken lassen. Diese Loeschbefehle sind bewusst gestrichen.
|
||||
--
|
||||
-- tests/datenbankregeln.test.ts prueft, dass alle diese Objekte vorhanden sind –
|
||||
-- ein versehentlich stehengelassener Loeschbefehl faellt dort sofort auf.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Anhaenge und Fotos an Schritten (#032).
|
||||
--
|
||||
-- Die Datei liegt im Dateisystem unter ANHAENGE_PFAD, hier stehen die
|
||||
-- Metadaten. Gegen bytea spricht die Sicherung: ein pg_dump mit Fotos ist nach
|
||||
-- einem Jahr keines, das jemand einspielt.
|
||||
|
||||
CREATE TABLE "Anhang" (
|
||||
"id" TEXT NOT NULL,
|
||||
"schrittergebnisId" TEXT NOT NULL,
|
||||
"laufId" TEXT NOT NULL,
|
||||
"kundeId" TEXT NOT NULL,
|
||||
"dateiname" TEXT NOT NULL,
|
||||
"medientyp" TEXT NOT NULL,
|
||||
"groesse" INTEGER NOT NULL,
|
||||
"pruefsumme" TEXT NOT NULL,
|
||||
"erstelltVonId" TEXT,
|
||||
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "Anhang_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "Anhang_schrittergebnisId_idx" ON "Anhang"("schrittergebnisId");
|
||||
CREATE INDEX "Anhang_laufId_idx" ON "Anhang"("laufId");
|
||||
CREATE INDEX "Anhang_kundeId_idx" ON "Anhang"("kundeId");
|
||||
|
||||
-- Schluesselkandidaten fuer die Mandantengrenze unten. Lauf hatte bisher keinen –
|
||||
-- die vier bestehenden zusammengesetzten Fremdschluessel zeigen auf Geraet,
|
||||
-- Mitarbeiter und Abteilung, nicht auf Lauf.
|
||||
CREATE UNIQUE INDEX "Schrittergebnis_id_laufId_key" ON "Schrittergebnis"("id", "laufId");
|
||||
CREATE UNIQUE INDEX "Lauf_id_kundeId_key" ON "Lauf"("id", "kundeId");
|
||||
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_schrittergebnisId_fkey"
|
||||
FOREIGN KEY ("schrittergebnisId") REFERENCES "Schrittergebnis"("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_laufId_fkey"
|
||||
FOREIGN KEY ("laufId") REFERENCES "Lauf"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_kundeId_fkey"
|
||||
FOREIGN KEY ("kundeId") REFERENCES "Kunde"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_erstelltVonId_fkey"
|
||||
FOREIGN KEY ("erstelltVonId") REFERENCES "Benutzer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- ---- Mandantengrenze und Zusammenhalt --------------------------------------
|
||||
--
|
||||
-- Dieselbe Bauart wie bei Lauf und Geraet: ein Anhang kann strukturell nicht zu
|
||||
-- einem Schrittergebnis eines anderen Laufs und nicht zu einem anderen Kunden
|
||||
-- als sein Lauf gehoeren.
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_ergebnis_gleicher_lauf"
|
||||
FOREIGN KEY ("schrittergebnisId", "laufId") REFERENCES "Schrittergebnis" ("id", "laufId")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_lauf_gleicher_kunde"
|
||||
FOREIGN KEY ("laufId", "kundeId") REFERENCES "Lauf" ("id", "kundeId")
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- Eine Groesse von 0 waere eine leere Datei, und eine negative gibt es nicht.
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_groesse_positiv" CHECK ("groesse" > 0);
|
||||
|
||||
-- SHA-256 als Hex: 64 Zeichen, nur Ziffern und a-f. Eine Pruefsumme, die keine
|
||||
-- ist, wuerde nach einer Ruecksicherung nichts beantworten.
|
||||
ALTER TABLE "Anhang"
|
||||
ADD CONSTRAINT "Anhang_pruefsumme_form" CHECK ("pruefsumme" ~ '^[0-9a-f]{64}$');
|
||||
@@ -134,6 +134,7 @@ model Kunde {
|
||||
benutzerbindungen BenutzerKunde[]
|
||||
geraete Geraet[]
|
||||
laeufe Lauf[]
|
||||
anhaenge Anhang[]
|
||||
mitarbeiter Mitarbeiter[]
|
||||
protokolle Protokoll[]
|
||||
verzeichnisquellen Verzeichnisquelle[]
|
||||
@@ -172,6 +173,7 @@ model Benutzer {
|
||||
protokolle Protokoll[]
|
||||
schrittergebnisse Schrittergebnis[]
|
||||
veroeffentlichteVersionen VorlagenVersion[] @relation("VersionVeroeffentlichtVon")
|
||||
anhaenge Anhang[]
|
||||
|
||||
@@index([aktiv])
|
||||
@@index([rolle])
|
||||
@@ -635,7 +637,10 @@ model Lauf {
|
||||
ergebnisse Schrittergebnis[]
|
||||
kommentare Kommentar[]
|
||||
protokolle Protokoll[]
|
||||
anhaenge Anhang[]
|
||||
|
||||
/// Schluesselkandidat fuer den zusammengesetzten Fremdschluessel von Anhang.
|
||||
@@unique([id, kundeId])
|
||||
@@index([kundeId, status])
|
||||
@@index([geraetId, status])
|
||||
@@index([mitarbeiterId])
|
||||
@@ -665,11 +670,52 @@ model Schrittergebnis {
|
||||
/// Codepfad darf annehmen, dass immer ein Mensch dahintersteht.
|
||||
aktualisiertVon Benutzer? @relation(fields: [aktualisiertVonId], references: [id], onDelete: Restrict)
|
||||
kommentare Kommentar[]
|
||||
anhaenge Anhang[]
|
||||
|
||||
@@unique([laufId, vorlagenSchrittId])
|
||||
/// Schluesselkandidat fuer den zusammengesetzten Fremdschluessel von Anhang.
|
||||
@@unique([id, laufId])
|
||||
@@index([laufId, zustand])
|
||||
}
|
||||
|
||||
/// Eine Datei oder ein Foto an einem Schritt (#032).
|
||||
///
|
||||
/// Die Datei selbst liegt im Dateisystem unter `ANHAENGE_PFAD`; hier stehen nur
|
||||
/// die Metadaten. Gegen `bytea` spricht die Sicherung: ein `pg_dump` mit Fotos
|
||||
/// ist nach einem Jahr kein `pg_dump` mehr, das jemand einspielt. **Folge:** die
|
||||
/// Sicherung muss Datenbank **und** Verzeichnis mitnehmen, siehe
|
||||
/// `docs/betrieb/sicherung.md`.
|
||||
model Anhang {
|
||||
id String @id @default(cuid())
|
||||
schrittergebnisId String
|
||||
laufId String
|
||||
/// Jede kundenbezogene Zeile traegt kundeId (CLAUDE.md). Die Mandantengrenze
|
||||
/// steht zusaetzlich als zusammengesetzter Fremdschluessel in der Migration.
|
||||
kundeId String
|
||||
/// Der Name, den der Browser mitgeschickt hat – nur zur Anzeige. Der Pfad auf
|
||||
/// der Platte entsteht aus `id`, damit kein Dateiname von aussen einen Pfad
|
||||
/// bestimmt.
|
||||
dateiname String
|
||||
medientyp String
|
||||
groesse Int
|
||||
/// SHA-256 der Datei. Beantwortet nach einer Ruecksicherung die Frage, ob die
|
||||
/// Datei noch die ist, die hier beschrieben steht.
|
||||
pruefsumme String
|
||||
erstelltVonId String?
|
||||
erstelltAm DateTime @default(now())
|
||||
|
||||
schrittergebnis Schrittergebnis @relation(fields: [schrittergebnisId], references: [id], onDelete: Cascade)
|
||||
lauf Lauf @relation(fields: [laufId], references: [id], onDelete: Restrict)
|
||||
kunde Kunde @relation(fields: [kundeId], references: [id], onDelete: Restrict)
|
||||
/// Leer bei einem Systemlauf – kein Codepfad nimmt an, dass ein Mensch
|
||||
/// dahintersteht.
|
||||
erstelltVon Benutzer? @relation(fields: [erstelltVonId], references: [id], onDelete: Restrict)
|
||||
|
||||
@@index([schrittergebnisId])
|
||||
@@index([laufId])
|
||||
@@index([kundeId])
|
||||
}
|
||||
|
||||
model Kommentar {
|
||||
id String @id @default(cuid())
|
||||
laufId String
|
||||
|
||||
Reference in New Issue
Block a user