feat(vorlagen): bedingte Abschnitte und Schritte (#039)
Prüfung / pruefung (push) Waiting to run
Prüfung / e2e (push) Blocked by required conditions

Ein Abschnitt oder ein einzelner Schritt erscheint nur, wenn seine Bedingung
zutrifft — abhaengig von einer Variable des Laufs oder vom Zustand eines
anderen Schritts. Der echte Fall steht im Seed: "Mitarbeiter-Onboarding" traegt
beide Konto-Abschnitte, fuenf AD-Schritte und vier fuer Entra ID, und
`konto_typ` sagt beim Start, welcher gilt. Bisher klickte ein Techniker die
anderen neun bei jedem Onboarding weg.

Entscheidungen, alle im Issue begruendet:

- Laufend ausgewertet, nicht beim Start festgeschrieben. Fuer die
  Abteilungsabschnitte (#031) ist Festschreiben richtig; fuer Bedingungen nicht
  — die Antwort auf "ist Pruefen fehlgeschlagen?" entsteht erst waehrend der
  Arbeit. Ein struktureller Test prueft, dass alle drei Schichten
  (Abschlussregel, Abarbeitung, Druck) die Auswertung rufen.
- Nicht entscheidbar heisst: gilt. Ein Lauf ohne konto_typ zeigt beide
  Abschnitte — genau wie vorher. Ein Abschnitt zu viel ist sichtbar und
  korrigierbar, ein fehlender faellt niemandem auf.
- OFFEN ist eine Antwort, keine Luecke: waere es unentscheidbar, waere ein
  bedingter Abschnitt von Anfang an sichtbar.
- Eine Bedingung, kein Ausdrucksbaum. Kein und, kein oder.
- Verwiesen wird ueber Titel-Pfade, nicht ueber Kennungen: vier Wege schreiben
  eine Struktur neu und geben neue Kennungen.

Zwei stille Datenverluste gefunden, der zweite aelter als dieser Meilenstein:

- Der Import verwarf `nurFuerAbteilungen`. Der Export schreibt es seit #031, das
  Schema nimmt es an, der Import setzte es nicht — eine exportierte Vorlage
  verlor ihre Abteilungsabschnitte und galt dort fuer alle.
- Die tiefe Kopie verwarf es ebenfalls, womit jedes "Bearbeiten" einer Vorlage
  alle Einschraenkungen verlor. Ursache war ein von Hand getippter Zwischentyp,
  der weniger Felder nannte als die Abfrage liefert; jetzt aus Prisma
  abgeleitet, beide Kopierwege teilen eine Stelle, und ein Test vergleicht Kopie
  und Original Feld fuer Feld.

Gefunden hat beides die Klickprobe am gebauten Stand, nicht die Suite: im Editor
stand "Bedingung gesetzt", nach "Bearbeiten" war sie weg. Dreizehn Gegenproben
liefen, alle wurden rot — und der teuerste Befund lag ausserhalb von allen.

1499 Vitest-Tests (vorher 1457), 115 E2E-Ablaeufe gruen.

Closes #39

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-10-23 14:54:10 +02:00
co-authored by Claude Opus 5
parent 2f247b3617
commit a2330ef682
29 changed files with 3051 additions and 146 deletions
+17
View File
@@ -70,7 +70,17 @@ describe.runIf(datenbankVerfuegbar)("Handgeschriebene Datenbankobjekte", () => {
*/
"Mitarbeiter_konto_mitziehen",
"VorlagenAbschnitt_baustein_veroeffentlicht",
/*
* Eine Schritt-Bedingung zeigt auf einen Schritt **derselben Version**
* (#039). Ein CHECK kann das nicht: es verlangt einen Blick in zwei andere
* Tabellen. Ohne diese Pruefung zeigt eine Bedingung nach dem
* Veroeffentlichen ins Leere — „Bearbeiten“ erzeugt eine tiefe Kopie mit
* neuen Kennungen —, und der Abschnitt erscheint dann stillschweigend
* immer.
*/
"VorlagenAbschnitt_bedingung_gleiche_version",
"VorlagenAbschnitt_unveraenderlich",
"VorlagenSchritt_bedingung_gleiche_version",
"VorlagenSchritt_unveraenderlich",
"VorlagenVariable_unveraenderlich",
"VorlagenVersion_status_einbahn",
@@ -159,6 +169,13 @@ describe.runIf(datenbankVerfuegbar)("Handgeschriebene Datenbankobjekte", () => {
"Verzeichnisquelle_scimtoken_gehasht",
// Und ein Token gehoert zu einem Zeitpunkt, in beide Richtungen.
"Verzeichnisquelle_scimtoken_mit_zeitpunkt",
/*
* Die Form einer Bedingung (#039). Eine mit unbekannter `art` wuerde beim
* Lesen als „keine Bedingung“ gelten — der Abschnitt waere sichtbar, und
* niemand koennte sagen, warum seine Bedingung nicht wirkt.
*/
"VorlagenAbschnitt_bedingung_form",
"VorlagenSchritt_bedingung_form",
"VorlagenVersion_veroeffentlicht_mit_zeitpunkt",
"Zustellung_bezug_passt_zum_anlass",
"Zustellung_empfaenger_nicht_leer",