feat(laeufe): Vier-Augen-Freigabe (#040)
Prüfung / pruefung (push) Waiting to run
Prüfung / e2e (push) Blocked by required conditions

Verlangt eine Vorlagen-Version eine Freigabe, laesst sich ein Lauf erst
abschliessen, wenn ein Zweiter ihn freigegeben hat. Das braucht zweierlei, und
beides zusammen: das neue Recht `freigeben` (ADMIN und REDAKTEUR, nicht
TECHNIKER) und dass man nicht an dem Lauf gearbeitet hat.

Als gearbeitet zaehlt: angelegt, einen Schritt gesetzt oder abgeschlossen. Eine
Zuweisung allein nicht — waere die Regel hier strenger, blockierte sie kleine
Teams ohne Gewinn.

Auch ein Administrator kann sich nicht selbst freigeben, und das ist der ganze
Sinn. Die Pruefung sitzt in `hatDaranGearbeitet` an einer Stelle, wie
`laufMussVeraenderbarSein`; die wichtigste Haelfte — der Ersteller — haelt
zusaetzlich ein CHECK in der Datenbank.

Zurueckweisen verlangt eine Begruendung, setzt den Lauf auf IN_ARBEIT und nimmt
eine erteilte Freigabe zurueck. Kein fuenfter LaufStatus: ein neuer Enum-Wert
haette jeden Codepfad betroffen, der heute vier Faelle kennt.

Sobald jemand abzuschliessen versucht und die Freigabe fehlt, bekommen die
Freigabeberechtigten eine Mail — ein anderer Empfaengerkreis als bei jeder
anderen Meldung, und ohne die, die gearbeitet haben. Die Aufforderung entsteht
ausserhalb der Transaktion: innerhalb wuerde sie mit dem Fehler zurueckgerollt,
und dann wartet ein Lauf auf etwas, von dem niemand weiss. Ein partieller
Unique-Index haelt sie bei mehreren Versuchen auf einmal.

Die Pflicht haengt an der Version, nicht an der Vorlage: eine veroeffentlichte
Version ist unveraenderlich, ein laufender Lauf behaelt also seine Regel. Beim
Bearbeiten und Duplizieren wandert sie mit — das war die unmittelbare Lehre aus
#039, wo die tiefe Kopie zwei Felder stillschweigend verworfen hatte.

1526 Vitest-Tests (vorher 1496), 115 E2E-Ablaeufe gruen. Klickprobe am gebauten
Stand mit elf Pruefungen; drei rote Punkte darin waren meine eigenen
Testfehler, einer davon lehrreich: ein reload() direkt nach einer Server Action
trifft den Router-Cache von Next und zeigt kurz den alten Stand.

Closes #40

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-10-24 01:14:04 +02:00
co-authored by Claude Opus 5
parent a2330ef682
commit d30bb6d235
27 changed files with 1373 additions and 44 deletions
+52
View File
@@ -242,6 +242,58 @@ Knopf gesperrt und darunter steht, was fehlt.
Wird danach eine Änderung nachgetragen, die einen Pflichtschritt wieder offen lässt, nimmt sich der
Abschluss selbst zurück. Damit lügt „abgeschlossen“ nie.
## Vier-Augen-Freigabe
Manche Arbeiten soll nicht derselbe abschließen, der sie gemacht hat: ein Firewall-Rollout, ein
Restore-Test, das Löschen eines Kontos. Verlangt die Vorlage eine Freigabe, steht das oben am Lauf —
und **Lauf abschließen** wartet, bis jemand sie erteilt hat.
### Wer freigeben darf
Es braucht zweierlei, und beides zusammen:
1. das Recht **freigeben** — das haben `ADMIN` und `REDAKTEUR`, **nicht** `TECHNIKER`;
2. und man darf **nicht an dem Lauf gearbeitet** haben.
Als „gearbeitet“ zählt: ihn angelegt, einen Schritt gesetzt oder ihn abgeschlossen zu haben. Nur
**zugewiesen** zu sein zählt nicht — wer zugewiesen wurde und nichts getan hat, darf freigeben.
**Auch ein Administrator kann sich nicht selbst freigeben.** Das ist der ganze Sinn, und es ist eine
bewusste Härte: wer allein im Haus ist, kommt damit nicht weiter und braucht einen Zweiten mit dem
Recht. Dieselbe Regel hält auch die Datenbank fest, nicht nur die Anwendung.
### Freigeben oder zurückweisen
Oben am Lauf steht eine Karte mit einem Feld für die **Begründung** und zwei Knöpfen:
- **Freigeben** — die Begründung ist freiwillig. Danach lässt sich der Lauf abschließen.
- **Zurückweisen** — die Begründung ist **Pflicht**. Der Lauf geht zurück auf *in Arbeit*, ein
bereits erteilter Abschluss wird aufgehoben, und der Bearbeiter sieht die Begründung an derselben
Stelle. Ohne Begründung steht er vor derselben Frage wie vorher.
Eine Zurückweisung nimmt auch eine **erteilte** Freigabe zurück. Damit lässt sich ein Lauf, der
schon abgeschlossen war, in die Arbeit zurückholen — ohne `archivVerwalten`, solange er nicht
archiviert ist.
### Wer erfährt davon
Sobald jemand den Lauf abzuschließen versucht und die Freigabe fehlt, bekommen die
**Freigabeberechtigten** eine Mail — nicht der Zuständige, wie bei allen anderen Meldungen. Wer an
dem Lauf gearbeitet hat, bekommt sie nicht: er dürfte ohnehin nicht freigeben.
Das geht **einmal** hinaus, auch wenn jemand es mehrmals versucht. Nach einer Zurückweisung wird
nicht erneut gemahnt — der Zurückweisende weiß, dass er wartet.
### Einschalten
Das Häkchen steht im Editor beim **Veröffentlichen**: „Läufe dieser Version brauchen eine Freigabe
durch einen Zweiten“. Es gehört zur **Version**, nicht zur Vorlage — ein laufender Lauf kann seine
Regel also nicht unter den Füßen verlieren, und in der Versionsliste steht an jeder Fassung, ob sie
eine Freigabe verlangt.
Beim Bearbeiten wandert das Häkchen in den neuen Entwurf mit. Eine Vorlage, die eine Freigabe
verlangt, verliert sie also nicht durch eine Textkorrektur.
## Archivieren — das ist endgültig
**archivieren** fragt nach: „Nach dem Archivieren ändert sich an diesem Lauf nichts mehr — kein