feat(laeufe): Vier-Augen-Freigabe (#040)
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:
co-authored by
Claude Opus 5
parent
a2330ef682
commit
d30bb6d235
@@ -49,7 +49,7 @@ Enums: `Rolle {ADMIN REDAKTEUR TECHNIKER LESER MITARBEITER}` · `Betriebsmodus {
|
||||
`VersionStatus {ENTWURF VEROEFFENTLICHT}` · `Herkunft {ABGLEICH MANUELL}` ·
|
||||
`QuellenArt {LDAP GRAPH SCIM}` ·
|
||||
`Zustellweg {MAIL WEBHOOK}` · `Zustellzustand {OFFEN GESENDET FEHLGESCHLAGEN AUFGEGEBEN}` ·
|
||||
`Meldeanlass {LAUF_ZUGEWIESEN LAUF_UEBERFAELLIG LAUF_ABGESCHLOSSEN ABGLEICH_FEHLGESCHLAGEN}`.
|
||||
`Meldeanlass {LAUF_ZUGEWIESEN LAUF_UEBERFAELLIG LAUF_ABGESCHLOSSEN LAUF_FREIGABE_OFFEN ABGLEICH_FEHLGESCHLAGEN}`.
|
||||
|
||||
`SEED_MODE` akzeptiert `DIENSTLEISTUNG` und `SERVICE` als Alias.
|
||||
|
||||
@@ -77,6 +77,13 @@ Dreizeiler: Recht prüfen, Zod-Schema anwenden, Service rufen.
|
||||
Änderung an Kopfdaten, `Schrittergebnis` und `Kommentar` gerufen. Zurückholen nur `ADMIN`.
|
||||
- **Abschluss:** nur wenn alle Pflichtschritte `ERLEDIGT` oder `NICHT_ZUTREFFEND` sind.
|
||||
`NICHT_ZUTREFFEND` und `FEHLGESCHLAGEN` verlangen eine Notiz.
|
||||
- **Vier-Augen-Freigabe:** Verlangt eine `VorlagenVersion` sie (`freigabePflicht`), lässt sich ein
|
||||
Lauf erst nach der Freigabe abschließen (#040). **Wer daran gearbeitet hat, gibt nicht frei** —
|
||||
angelegt, einen Schritt gesetzt oder abgeschlossen; eine Zuweisung allein zählt nicht. Das prüft
|
||||
`hatDaranGearbeitet` an genau einer Stelle, wie `laufMussVeraenderbarSein`, und ein CHECK hält die
|
||||
wichtigste Hälfte (der Ersteller) auch gegen Schreiben an der Dienstschicht vorbei. Das Recht
|
||||
`freigeben` hat **nicht** `TECHNIKER`: sonst hängt die Regel daran, dass zufällig ein zweiter
|
||||
greifbar ist. Die Pflicht wandert bei „Bearbeiten“ und „Duplizieren“ in die Kopie mit.
|
||||
- **Mandant:** Jede kundenbezogene Zeile trägt `kundeId`. `kundeErmitteln()` liefert im Modus
|
||||
`INTERN` immer die eigene Organisation und **verwirft** eine mitgeschickte `kundeId`.
|
||||
- **Rechte:** nur serverseitig, aus der `RECHTE`-Tabelle über `darf()` / `rechtErforderlich()`.
|
||||
|
||||
Reference in New Issue
Block a user