-- --------------------------------------------------------------------------- -- HANDGESCHRIEBEN. Prisma erzeugt hier zusaetzlich Loeschbefehle fuer die -- zusammengesetzten Fremdschluessel (Mandantengrenze), die Trigramm-Indizes -- (Archivsuche), die partiellen eindeutigen Indizes und alle Trigger: 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. -- --------------------------------------------------------------------------- -- Vier-Augen-Freigabe (#040). /* * Ein neuer Meldeanlass. Ohne ihn wartet ein Lauf auf eine Freigabe, von der * niemand weiss — und das ist der Fall, der die ganze Regel wertlos macht: * sie haelt den Abschluss auf, und keiner merkt es. */ ALTER TYPE "Meldeanlass" ADD VALUE IF NOT EXISTS 'LAUF_FREIGABE_OFFEN' BEFORE 'ABGLEICH_FEHLGESCHLAGEN'; ALTER TABLE "VorlagenVersion" ADD COLUMN "freigabePflicht" BOOLEAN NOT NULL DEFAULT false; ALTER TABLE "Lauf" ADD COLUMN "freigegebenVonId" TEXT, ADD COLUMN "freigegebenAm" TIMESTAMP(3), ADD COLUMN "freigabeNotiz" TEXT; ALTER TABLE "Lauf" ADD CONSTRAINT "Lauf_freigegebenVonId_fkey" FOREIGN KEY ("freigegebenVonId") REFERENCES "Benutzer"("id") ON DELETE RESTRICT ON UPDATE CASCADE; CREATE INDEX "Lauf_freigegebenVonId_idx" ON "Lauf"("freigegebenVonId"); /* * Freigeber und Zeitpunkt gehoeren zusammen, in beide Richtungen — wie bei * `abgeschlossenAm`. Ohne den Zeitpunkt liesse sich nicht sagen, wann die * Freigabe erteilt wurde, und ein Zeitpunkt ohne Freigeber behauptete eine * Freigabe, die niemand gegeben hat. */ ALTER TABLE "Lauf" ADD CONSTRAINT "Lauf_freigabe_mit_zeitpunkt" CHECK (("freigegebenVonId" IS NULL) = ("freigegebenAm" IS NULL)); /* * **Der Kern der Vier-Augen-Regel, in der Datenbank.** * * Wer den Lauf angelegt hat, gibt ihn nicht frei. Das prueft auch der Dienst, * und zwar strenger: er sieht ausserdem nach, wer an den Schrittergebnissen * gearbeitet hat (`Schrittergebnis.aktualisiertVonId`). Dafuer braeuchte ein * CHECK eine Unterabfrage, und die gehoert nicht hinein. * * Diese Haelfte steht trotzdem hier, weil sie die wichtigere ist: der Ersteller * ist der naheliegende Fall, und die Regel muss auch dann gelten, wenn jemand an * der Service-Schicht vorbei schreibt (CLAUDE.md). Eine Freigabe, die in der * Datenbank steht, ist damit nachweislich nicht vom Ersteller. */ ALTER TABLE "Lauf" ADD CONSTRAINT "Lauf_freigabe_nicht_selbst" CHECK ("freigegebenVonId" IS NULL OR "freigegebenVonId" <> "erstelltVonId"); /* * **Die Freigabe-Aufforderung geht je Lauf und Empfaenger genau einmal hinaus.** * * Derselbe Grund wie bei „ueberfaellig“ (#034): sie entsteht bei einem * gescheiterten Abschlussversuch, und ein Techniker versucht es mehrmals — ohne * diesen Index bekaeme jeder Freigabeberechtigte bei jedem Versuch eine Mail, * und jede davon waere fuer sich korrekt. * * Partiell, weil es nur fuer diesen einen Anlass gilt: nach einer Zurueckweisung * und erneuter Fertigstellung soll **nicht** wieder gemahnt werden — der * Zurueckweisende weiss ja, dass er wartet. Dafuer traegt die Zurueckweisung * ihre eigene Notiz an der Abarbeitung. */ CREATE UNIQUE INDEX "Zustellung_freigabe_einmal" ON "Zustellung"("laufId", "empfaenger") WHERE "anlass" = 'LAUF_FREIGABE_OFFEN'; /* * Gegenprobe: die neuen Spalten sind ueberall leer, und keine bestehende Version * verlangt eine Freigabe. `ALTER TABLE ... ADD CONSTRAINT` prueft das von sich * aus — aber eine Migration, die ihre eigene Annahme nicht nachrechnet, ist * genau die Art Zusage, die dieses Projekt teuer bezahlt hat. */ DO $$ DECLARE anzahl INTEGER; BEGIN SELECT count(*) INTO anzahl FROM "Lauf" WHERE "freigegebenVonId" IS NOT NULL; IF anzahl > 0 THEN RAISE EXCEPTION 'Unerwartet % Laeufe mit Freigabe vor der Migration.', anzahl; END IF; SELECT count(*) INTO anzahl FROM "VorlagenVersion" WHERE "freigabePflicht"; IF anzahl > 0 THEN RAISE EXCEPTION 'Unerwartet % Versionen mit Freigabepflicht vor der Migration.', anzahl; END IF; END $$;