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>
8.1 KiB
#040 M24 – Vier-Augen-Freigabe
Status: erledigt Im Tracker: – Meilenstein: v0.3.0 Labels: phase-3, backend, frontend Geschätzt: 8 h Tatsächlich: 3 h 30 min
Ziel
Manche Arbeiten soll nicht derselbe abschließen, der sie gemacht hat: ein Firewall-Rollout, ein
Restore-Test, das Löschen eines Kontos. Heute kann jeder TECHNIKER jeden Lauf abschließen und
archivieren.
Gebraucht wird: eine Vorlage kann sagen „dieser Lauf braucht eine Freigabe“, und dann schließt ihn ein Zweiter ab — nachweisbar im Protokoll.
Zu entscheiden
- Freigabe am Lauf oder am Schritt? Empfehlung: am Lauf, gesetzt von der Vorlage.
Am Schritt wäre feiner und verführt zu Checklisten, in denen an fünf Stellen jemand warten
muss; am Lauf ist es eine Aussage über die Arbeit als Ganzes und erklärt sich von selbst.
Schritt-Freigaben bleiben möglich, wenn sich der Bedarf zeigt —
VorlagenSchritt.konfigist ein Json. - Wer darf freigeben? Empfehlung: ein eigenes Recht
freigeben, standardmäßig beiADMINundREDAKTEUR— nicht beiTECHNIKER. Begründung: die Vier-Augen-Regel soll nicht davon abhängen, dass zufällig ein zweiter Techniker greifbar ist; und wer sie umgehen will, braucht dann ein zweites Konto mit mehr Rechten, was im Protokoll steht. - Darf der Bearbeiter sich selbst freigeben? Nein, und das ist der ganze Sinn. Geprüft
wird gegen
Schrittergebnis.aktualisiertVonIdundLauf.erstelltVonId: wer irgendetwas daran getan hat, gibt nicht frei. EinADMIN, der allein im Haus ist, kommt damit nicht weiter — das ist eine bewusste Härte, und die Anleitung sagt es. - Was, wenn die Freigabe verweigert wird? Empfehlung: ein Zustand „zurückgewiesen“ mit
Pflichtnotiz. Der Lauf geht zurück auf
IN_ARBEIT, die Notiz steht im Protokoll und an der Abarbeitungsansicht. Kein eigenerLaufStatus— das wäre eine Änderung an einem Enum, das vier Jahre halten soll; es genügt ein Feld plus Protokolleintrag.
Aufgaben
- Migration:
freigabePflicht BooleananVorlagenVersion, dazufreigegebenVonId,freigegebenAmundfreigabeNotizamLauf; CHECK, dassfreigegebenVonIdundfreigegebenAmzusammen gesetzt sind (wie beiabgeschlossenAm) - CHECK:
freigegebenVonIdist nichterstelltVonId— die Regel gehört in die Datenbank, nicht nur in den Dienst (CLAUDE.md) - Recht
freigebeninRECHTE, Rollenmatrix-Test erweitern - Dienst:
laufFreigeben(laufId, benutzer, notiz?)undlaufZurueckweisen(laufId, benutzer, notiz); Abschluss verlangt die Freigabe, wenn die Version sie fordert - Die Prüfung „wer hat daran gearbeitet“ an einer Stelle, wie
laufMussVeraenderbarSein - Benachrichtigung: ein neuer
MeldeanlassLAUF_FREIGABE_OFFENan die Rollen mit dem Recht — sonst wartet ein Lauf, von dem niemand weiß - Oberfläche: Hinweis am Lauf („wartet auf Freigabe durch einen Zweiten“), Knöpfe für Freigeben und Zurückweisen, Notizfeld; die Übersicht bekommt einen Filter „wartet auf meine Freigabe“
- Editor: Häkchen „dieser Lauf braucht eine Freigabe“ an der Version
- Druckansicht und PDF nennen Freigeber und Zeitpunkt
- Anleitung: Kapitel 02 (Läufe abarbeiten) und 04 (Vorlagen), mit dem Hinweis, dass ein Einzelkämpfer sich nicht selbst freigeben kann
Akzeptanzkriterien
- Test: ein Lauf mit Freigabepflicht lässt sich nicht abschließen, solange keine Freigabe steht
- Test: der Bearbeiter kann nicht freigeben — auch nicht als
ADMIN - Test: die Datenbank weist es ebenfalls ab (CHECK), nicht nur der Dienst
- Test: eine Rolle ohne
freigebenwird abgewiesen, über jede Server Action - Test: Zurückweisen verlangt eine Notiz und setzt den Lauf auf
IN_ARBEIT - Test: die Meldung geht an die Rollen mit dem Recht und nicht an alle
- Test: ein Lauf ohne Freigabepflicht verhält sich unverändert — bestehende Läufe und Vorlagen merken nichts
- Am Handy kein horizontales Scrollen
Beim Umsetzen dazugekommen
- Die vier Entscheidungen sind so gefallen wie empfohlen. Zwei haben sich im Code als besonders
tragend erwiesen:
- Die Freigabe hängt an der Version, nicht an der Vorlage. Eine veröffentlichte Version ist unveränderlich — ein laufender Lauf kann seine Regel damit nicht unter den Füßen verlieren. In der Versionsliste steht an jeder Fassung, ob sie eine Freigabe verlangt.
- Kein fünfter
LaufStatusfür „zurückgewiesen“. Der Lauf geht aufIN_ARBEIT, die Begründung steht infreigabeNotizund im Protokoll. Ein neuer Enum-Wert hätte jeden Codepfad betroffen, der heute vier Fälle kennt.
- Als „gearbeitet“ zählt dreierlei — angelegt, ein Schrittergebnis gesetzt, abgeschlossen.
Der Zuständige gilt bewusst nicht als Bearbeiter: eine Zuweisung ist noch keine Arbeit, und
wäre die Regel hier strenger, blockierte sie kleine Teams ohne Gewinn. Die Prüfung sitzt in
hatDaranGearbeitet, an einer Stelle — wielaufMussVeraenderbarSein. - Die Aufforderung entsteht außerhalb der Transaktion, und das war die einzige knifflige Stelle:
der Abschlussversuch scheitert mit einem eigenen Fehlertyp
FreigabeFehlt, denlaufAbschliessenaußen fängt, um die Meldung einzureihen und dann weiterzuwerfen. Innerhalb würde sie mit dem Fehler zurückgerollt — und dann wartet ein Lauf auf etwas, von dem niemand weiß. Dafür musste die Transaktion in eine eigene Funktion (abschlussVersuchen). - Ein anderer Empfängerkreis als bei jeder anderen Meldung: nicht der Zuständige, sondern jeder
mit dem Recht
freigeben— ohne die, die gearbeitet haben. Eine Aufforderung zu etwas, das der Dienst abweist, ist schlimmer als keine. - Ein partieller Unique-Index (
Zustellung_freigabe_einmal) hält die Mahnung bei einem Lauf und Empfänger auf einmal. Ein Techniker versucht es mehrmals; ohne den Index wäre jede Mail für sich korrekt und in Summe eine Belästigung — derselbe Fall wie „überfällig“ in #034, nur schneller erreicht. - Die Freigabepflicht wandert bei „Bearbeiten“ und „Duplizieren“ mit. Das war kein Zufall,
sondern die unmittelbare Lehre aus #039: dort hatte die tiefe Kopie
nurFuerAbteilungenundbedingungstillschweigend verworfen. Eine Vorlage soll ihre Freigabepflicht nicht durch eine Textkorrektur verlieren.
Was die Klickprobe gezeigt hat
Elf Prüfungen am gebauten Stand, alle grün — von „Freigabe-Karte sichtbar“ über „Zurückweisen verlangt eine Begründung“ bis „Häkchen aus der Vorversion übernommen“ und 390 px.
Drei rote Punkte waren meine eigenen Testfehler, und der dritte ist festzuhalten:
-
Ein Selektor traf den versteckten Protokolltext „Lauf abgeschlossen“ statt der Erfolgsmeldung.
-
Ein Suchmuster
/freigeb/traf nichts: in „Freigabe“ und „freigegeben“ kommt diese Zeichenfolge gar nicht vor. Dreimal gesucht, bis es auffiel. -
Ein
reload()direkt nach einer Server Action zeigt kurz den alten Stand. Die Action revalidiert den Pfad, und der Benutzer sieht das Ergebnis ohne Neuladen — ein Reload im selben Kontext trifft dagegen den Router-Cache von Next. Das ist Next und kein Fehler dieser Anwendung, aber es ist auch nicht, was ein Mensch tut. Die Probe prüft jetzt das echte Verhalten.Nachgewiesen, bevor etwas geändert wurde: in einem frischen Browser-Kontext stand alles richtig da, und die Datenbank trug Freigeber, Zeitpunkt und Notiz.
Was offen bleibt
- Freigaben an einzelnen Schritten gibt es nicht, bewusst. Am Lauf ist es eine Aussage über die
Arbeit als Ganzes und erklärt sich von selbst; am Schritt verführte es zu Checklisten, in denen an
fünf Stellen jemand warten muss.
VorlagenSchritt.konfigist ein Json — wenn sich der Bedarf zeigt, ist der Platz da. - Ein Einzelkämpfer kommt nicht weiter: wer allein ist und an dem Lauf gearbeitet hat, kann ihn nicht freigeben, auch nicht als Administrator. Das ist die Härte, die die Regel ausmacht, und die Anleitung sagt es ausdrücklich.