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
+67
View File
@@ -219,6 +219,73 @@ Import: ein Abteilungsname bedeutet in einer anderen Installation dasselbe.
**Lässt für eine Abteilung kein Abschnitt übrig, wird der Lauf abgewiesen** — es gäbe nichts
abzuarbeiten. Das passiert nur, wenn jeder Abschnitt einer Vorlage eingeschränkt ist.
## Bedingte Abschnitte und Schritte
Die Onboarding-Vorlage enthält **beide** Konto-Abschnitte — „Konto anlegen (Active Directory)“ mit
fünf Schritten und „Konto anlegen (Entra ID)“ mit vier. In jedem einzelnen Lauf gilt nur einer, und
die Variable **Kontotyp** sagt beim Start, welcher. Bis hierher klickte ein Techniker die anderen
neun Schritte weg.
Mit einer **Bedingung** erscheint ein Abschnitt oder ein einzelner Schritt nur dann, wenn er
zutrifft. Im Editor steht an jedem Abschnitt und an jedem Schritt **Bedingung (optional)**; ohne
eine gilt er immer.
### Zwei Arten, und die Wahl entscheidet, wann die Antwort entsteht
| Die Bedingung hängt an … | Beispiel | Wann sie entschieden wird |
|---|---|---|
| einer **Variable** | „gilt, wenn Kontotyp gleich Active Directory ist“ | beim Start, wenn die Variablen erfasst werden |
| einem **Schritt** | „gilt, wenn Prüfen fehlgeschlagen ist“ | während der Arbeit, sobald jemand den Schritt setzt |
Die zweite ist die interessantere: ein Abschnitt „Nacharbeit“, der erst erscheint, wenn der
Restore-Test fehlgeschlagen ist. Er ist zu Beginn nicht da und kommt in dem Moment dazu, in dem der
Schritt auf „fehlgeschlagen“ geht — bei einer offenen zweiten Sitzung sofort.
### Eine Bedingung, nicht mehr
Es gibt **kein** „und“ und kein „oder“. Wer zwei Bedingungen braucht, nimmt zwei Abschnitte oder
zwei Vorlagen. Das ist Absicht: ein Formular, in dem sich beliebige Ausdrücke bauen lassen, wäre
eine kleine Programmiersprache — und ein Abschnitt, der aus unerklärlichen Gründen fehlt, ist
schlimmer als einer zu viel.
Bei einer Schritt-Bedingung lassen sich dagegen **mehrere Zustände** ankreuzen: „erledigt oder nicht
zutreffend“ ist eine Frage, nicht zwei.
### Vier Dinge, die man dazu wissen muss
- **Lässt sich eine Bedingung nicht entscheiden, erscheint der Teil.** Hat niemand den Kontotyp
angegeben, stehen **beide** Konto-Abschnitte da — genau wie vorher. Auszublenden hieße, eine
Antwort zu erfinden, die niemand gegeben hat. Ein Abschnitt zu viel ist sichtbar und
korrigierbar; ein fehlender fällt niemandem auf.
- **Ein ausgeblendeter Pflichtschritt blockiert den Abschluss nicht** — dieselbe Regel wie bei den
Abteilungsabschnitten. Er steht nicht in der Abarbeitung, also lässt er sich nicht abhaken.
- **Ausgeblendet heißt nicht gelöscht.** Hat jemand in einem Schritt eine Notiz hinterlassen und
kippt dessen Bedingung danach, verschwindet der Schritt aus der Ansicht — die Notiz bleibt. Kippt
die Bedingung zurück, ist alles wieder da.
- **Die Nummerierung zählt, was man sieht.** Ein ausgeblendeter Abschnitt hinterlässt keine Lücke;
aus `01 · 02 · 03` wird nicht `01 · 03`.
### Die Warnung „dieser Schritt kommt später“
Zeigt eine Bedingung auf einen Schritt, der **nach** dem bedingten Teil steht, warnt der Editor.
Verboten ist es nicht, aber fast immer ein Versehen: der Abschnitt wäre beim Abarbeiten zunächst
unsichtbar und erschiene erst, nachdem jemand weiter unten etwas abgehakt hat — also rückwärts.
Gemeint ist meist ein Schritt davor.
### Export und Import
Eine Bedingung wandert mit. Im Austauschdokument steht sie über **Titel** statt über Kennungen
(`"abschnitt": "Prüfung", "schritt": "Prüfen"`), denn eine Kennung bedeutet in einer anderen
Installation nichts. Beim Import wird daraus wieder der richtige Schritt.
Findet sich der Titel-Pfad in der Datei nicht — etwa nach einem Tippfehler in einer von Hand
geschriebenen Vorlage —, wird die Bedingung **weggelassen**. Der Abschnitt gilt dann immer, und das
steht sichtbar im Editor. Die ganze Vorlage deswegen abzuweisen wäre die teurere Antwort.
**Ein Baustein-Schritt hat keine Bedingung.** Ein Baustein ist wiederverwendbar, und eine Bedingung
auf einer Variable, die es in der Zielvorlage nicht gibt, wäre dort nicht entscheidbar. Der
Abschnitt, in dem der Baustein eingesetzt wird, darf eine haben.
## Bausteine: ein Abschnitt für mehrere Vorlagen
„Datensicherung prüfen“ steht in vier der sieben mitgelieferten Vorlagen, wortgleich. Wer den Ablauf
+36
View File
@@ -387,6 +387,42 @@ Vom Mitarbeiter holt dieses Lesemodell **nur Name, UPN und Abteilung** — nicht
alles und dann gefiltert. Ein Ausdruck liegt herum, wird kopiert und weitergegeben;
was darauf steht, ist aus der Hand gegeben.
## 5f-2. Bedingte Teile: zwei Filter, eine Reihenfolge
Was ein Lauf zeigt, entsteht aus **zwei** Filtern uebereinander, und ihre
Reihenfolge ist der ganze Inhalt von `geltendeStruktur` in
`src/lib/bedingungen.ts`:
1. **Die Abteilungsauswahl (#031)** — beim Start festgeschrieben in
`Lauf.geltendeAbschnitte`. Festgeschrieben, weil ein archivierter Lauf genau
die Schritte zeigen muss, die damals abgearbeitet wurden, und ein spaeterer
Abteilungswechsel keinen Schritt entfernen darf, an dem eine Notiz haengt.
2. **Die Bedingungen (#039)** — **laufend** ausgewertet. Eine Bedingung auf einer
Variable liesse sich auch festschreiben; eine auf einem Schrittergebnis nicht,
denn ihre Antwort entsteht erst waehrend der Arbeit. Ein Abschnitt
„Nacharbeit“, der erscheint, wenn der Restore-Test fehlschlaegt, ist der Fall,
fuer den es gebaut ist.
Wer nur den ersten anwendet, bekommt Abschnitte, die nicht gelten; wer nur den
zweiten anwendet, umgeht die Abteilungsregel. Drei Schichten brauchen beide — die
Abschlussregel im Dienst, die Abarbeitung und die Druckansicht —, und
`tests/bedingte-laeufe.test.ts` prueft **strukturell**, dass keine davon die
zweite vergisst. Dieselbe Art Test wie „jede Seite prueft selbst“ (#038): die
Zusage steht in der Vollstaendigkeit einer Liste, und die muss jemand bewachen.
**Nicht entscheidbar heisst: gilt.** Hat niemand den Kontotyp angegeben, stehen
beide Konto-Abschnitte da — genau wie vor #039. Auszublenden hiesse, eine Antwort
zu erfinden, die niemand gegeben hat; und die Richtung, in die der Zweifel
faellt, soll die harmlose sein.
**Verwiesen wird ueber Titel-Pfade, nicht ueber Kennungen.** Vier Wege schreiben
eine Struktur neu und geben dabei neue Kennungen: Import, Export, Seed und
`entwurfSpeichern`. Eine Bedingung auf einer Kennung ueberlebte keinen davon —
ein Titel-Pfad ueberlebt alle vier, und `bedingungAufloesen` ist fuer alle
dieselbe Stelle. Dass eine Schritt-Bedingung auf **dieselbe Version** zeigt,
haelt ein Trigger: nach dem Veroeffentlichen waere ein fremder Verweis nicht mehr
entscheidbar, und der Abschnitt erschiene stillschweigend immer.
## 5g. Der Verzeichnis-Abgleich: vier Schichten und eine Notbremse
Eine Verzeichnisquelle hat seit #028 eine **Art** — `LDAP`, `GRAPH` oder `SCIM` —,
+77 -2
View File
@@ -40,12 +40,14 @@ als Unterpunkte mit Aufgabe und Dauer.
| #027 | Die Editor-Abläufe lassen ihre Vorlagen stehen | 2 h 10 min |
| #038 | Die E2E-Abläufe laufen in keinem Tor | 1 h 35 min |
| #037 | Zwei Nachzügler aus der Durchsicht von Phase 2 | 1 h 50 min |
| | **Summe** | **73 h 55 min** |
| #039 | M23 – Bedingte Schritte und Abschnitte | 5 h 20 min |
| | **Summe** | **79 h 15 min** |
| Meilenstein | Tatsächlich | Status |
|---|---|---|
| v0.1.0 | 35 h 20 min | veröffentlicht |
| v0.2.0 | 38 h 35 min | in Arbeit |
| v0.2.0 | 38 h 35 min | veröffentlicht |
| v0.3.0 | 5 h 20 min | in Arbeit |
---
@@ -1764,3 +1766,76 @@ Entra-Mandanten** und **gegen echte SCIM-Anbieter** ist nichts gelaufen. Die For
stammen aus der Dokumentation, nicht aus Mitschnitten. Stimmt eine Form nicht, stimmen Test und
Wirklichkeit nicht — die Prüflisten stehen in `docs/betrieb/entra-id.md` und
`docs/betrieb/scim.md`.
---
## 2026-10-23 · Sitzung 25 · 11:00–15:10
**Issue:** #039 (M23)
**Version:** 0.3.0 (unveröffentlicht)
### Erledigt
- **Bedingte Abschnitte und Schritte**, der erste Meilenstein von Phase 3. Eine Bedingung hängt an
einer Variable des Laufs oder am Zustand eines anderen Schritts; die Auswertung läuft bei jedem
Lesen und sitzt in `src/lib/bedingungen.ts`.
- **Der Seed nutzt es am echten Fall**: „Mitarbeiter-Onboarding“ hat die Bedingung auf `konto_typ`,
beide Konto-Abschnitte bleiben drin und schließen sich aus. Neun Schritte, die niemand mehr
wegklickt.
- Editor, Abarbeitung, Druck, Export, Import, Entwurf und Seed — sieben Wege, alle mit Tests.
- 1496 Vitest-Tests (vorher 1457), davon 29 neue. Klickprobe am gebauten Stand: Bildschirm, Druck
und 390 px zeigen dasselbe.
### Entscheidungen
- **Laufend auswerten, nicht beim Start festschreiben.** Für die Abteilungsabschnitte (#031) ist
Festschreiben richtig: die Abteilung steht beim Start fest. Für Bedingungen nicht — die Antwort auf
„ist Prüfen fehlgeschlagen?“ entsteht erst während der Arbeit. `geltendeStruktur` legt die
Reihenfolge der zwei Filter fest, und ein struktureller Test prüft, dass alle drei Schichten sie
rufen.
- **Nicht entscheidbar heißt: gilt.** Ein Lauf ohne `konto_typ` zeigt beide Konto-Abschnitte. Das ist
genau das Verhalten von vorher; eine erfundene Antwort wäre die Verschlechterung. Ein Abschnitt zu
viel ist sichtbar und korrigierbar, ein fehlender fällt niemandem auf.
- **`OFFEN` ist eine Antwort, keine Lücke** — der scharfe Gegensatz zur nicht gesetzten Variable.
Wäre `OFFEN` unentscheidbar, wäre ein bedingter Abschnitt von Anfang an sichtbar, also das
Gegenteil des Zwecks.
- **Eine Bedingung, kein Ausdrucksbaum.** Kein `und`, kein `oder`, keine Verschachtelung. Wer zwei
braucht, nimmt zwei Abschnitte. Ein Formular für beliebige Ausdrücke wäre eine kleine
Abfragesprache, und ein Abschnitt, der aus unerklärlichen Gründen fehlt, ist schlimmer als einer zu
viel.
- **Verwiesen wird über Titel-Pfade, nicht über Kennungen.** Vier Wege schreiben eine Struktur neu
und geben neue Kennungen: Import, Export, Seed, `entwurfSpeichern`. Eine Kennung überlebt keinen
davon.
### Probleme
- **Zwei stille Datenverluste, und der zweite war älter 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.
- Die **tiefe Kopie** verwarf es ebenfalls — damit verlor **jedes „Bearbeiten“** einer Vorlage alle
Abteilungseinschränkungen. Beide Kopierstellen hatten den Code einzeln ausgeschrieben und
vergaßen dieselben Felder.
**Die Ursache war ein von Hand getippter Zwischentyp.** `VersionMitInhalt` nannte weniger Felder,
als die Abfrage liefert; die Daten waren da, der Code konnte sie nicht sehen. Jetzt aus Prisma
abgeleitet — ein neues Feld ist dort automatisch vorhanden. Und bewacht von einem Test, der Kopie
und Original **Feld für Feld** vergleicht, nicht stichprobenweise.
- **Gefunden hat beides die Klickprobe am gebauten Stand**, nicht die Suite: im Editor stand
„Bedingung gesetzt“, und nach „Bearbeiten“ war sie weg. Genau dafür steht diese Probe in
`CLAUDE.md`. Dreizehn Gegenproben liefen in dieser Sitzung, alle wurden rot — und trotzdem lag der
teuerste Befund außerhalb von allen.
- **Zwei Schemas für dieselbe Form** liefen fast auseinander: Austauschformat und Editor-Struktur
brauchen die Pfad-Form, und TypeScript meldete die Abweichung erst, als die Typen aufeinandertrafen.
Jetzt eine Stelle.
- **Ein Mangel an der neuen Komponente**, beim Klicken aufgefallen: die Auswahlfelder standen in
einem umhüllenden `label`, und ihr zugänglicher Name schluckte den Text der gewählten Option mit.
Derselbe Fehler wie bei der Adresse im Verzeichnis-Formular (#016) — dort war es ein Reviewbefund.
- **Zwei eigene Testfehler**: dreimal versucht, eine Bedingung an einer **veröffentlichten** Version
zu setzen (die ist unveränderlich, dafür sorgen Trigger), und `vorlageBearbeiten` mit
`entwurfHolenOderErzeugen` verwechselt. Beide Male hat die Datenbank es gesagt.
### Nächster Schritt
- **M24 (#040)** Vier-Augen-Freigabe. Der Abschluss wird dort ohnehin angefasst, und M25 braucht den
Freigeber für das Blatt.
+95 -26
View File
@@ -1,10 +1,10 @@
# #039 M23 – Bedingte Schritte und Abschnitte
**Status:** offen
**Status:** erledigt
**Im Tracker:** –
**Meilenstein:** v0.3.0
**Labels:** phase-3, backend, frontend
**Geschätzt:** 12 h **Tatsächlich:** –
**Geschätzt:** 12 h **Tatsächlich:** 5 h 20 min
## Ziel
@@ -23,7 +23,7 @@ Stelle, an der das sitzt.
## Zu entscheiden
- [ ] **Wann wird ausgewertet?** Das ist die Entscheidung, an der alles hängt.
- [x] **Wann wird ausgewertet?** Das ist die Entscheidung, an der alles hängt.
Für Abteilungen (#031) wird beim **Start festgeschrieben** — die Abteilung des Laufs steht
dann fest, und ein archivierter Lauf muss genau die Schritte zeigen, die damals galten.
@@ -36,60 +36,129 @@ Stelle, an der das sitzt.
Änderung an einem Schrittergebnis; was dabei herauskommt, wird in den Lauf geschrieben (wie
`geltendeAbschnitte`). Damit gilt für das Archiv weiter „der Lauf weiß, was galt“, und der
Ereignisstrom aus #033 trägt die Änderung ohnehin schon zur zweiten Sitzung.
- [ ] **Woran darf eine Bedingung hängen?** Empfehlung: an einer **Variable** des Laufs und an
- [x] **Woran darf eine Bedingung hängen?** Empfehlung: an einer **Variable** des Laufs und an
einem **Schrittergebnis** derselben Version. Nicht an Gerätetyp, Abteilung oder Rolle — für
Abteilungen gibt es #031, und je mehr Quellen, desto schwerer zu erklären, warum ein Schritt
fehlt.
- [ ] **Wie wird sie gespeichert?** Empfehlung: ein Json-Feld `bedingung` an `VorlagenAbschnitt`
- [x] **Wie wird sie gespeichert?** Empfehlung: ein Json-Feld `bedingung` an `VorlagenAbschnitt`
und `VorlagenSchritt`, mit einem engen Schema — `{ art: "variable", schluessel, operator,
wert }` oder `{ art: "schritt", schrittId, zustand }`. Json, weil `konfig` es schon so macht
und ein neuer Operator dann keine Migration braucht.
**Eine Bedingung, kein Ausdrucksbaum.** Kein `und`/`oder`, keine Verschachtelung: das wäre
eine kleine Sprache, die niemand im Editor pflegen kann, und ein Abschnitt, der aus
unerklärlichen Gründen fehlt, ist schlimmer als einer zu viel.
- [ ] **Was passiert mit einem Schrittergebnis, das schon Daten trägt**, wenn die Bedingung
- [x] **Was passiert mit einem Schrittergebnis, das schon Daten trägt**, wenn die Bedingung
umschlägt? Empfehlung: die Zeile **bleibt** und wird nur ausgeblendet. Löschen hieße, eine
Notiz zu verlieren, die jemand geschrieben hat; und schlägt die Bedingung zurück, ist sie
wieder da.
## Aufgaben
- [ ] Migration: `bedingung Json?` an `VorlagenAbschnitt` und `VorlagenSchritt`, dazu ein CHECK, der
- [x] Migration: `bedingung Json?` an `VorlagenAbschnitt` und `VorlagenSchritt`, dazu ein CHECK, der
sicherstellt, dass eine Bedingung auf einen Schritt **derselben Version** zeigt (sonst zeigt
sie nach dem Veröffentlichen ins Leere)
- [ ] `src/lib/bedingungen.ts`, framework-frei: Schema, Auswertung, und die Liste der Schritte und
- [x] `src/lib/bedingungen.ts`, framework-frei: Schema, Auswertung, und die Liste der Schritte und
Abschnitte, die gelten. **Dieselbe Stelle für alle drei Schichten**, wie
`src/lib/geltende-abschnitte.ts`
- [ ] Auswertung bei jedem Schreiben an einem `Schrittergebnis`; das Ergebnis in den Lauf
- [ ] Abschlussregel: ein ausgeblendeter Pflichtschritt hält den Abschluss **nicht** auf (dieselbe
- [x] Auswertung bei jedem Schreiben an einem `Schrittergebnis`; das Ergebnis in den Lauf
- [x] Abschlussregel: ein ausgeblendeter Pflichtschritt hält den Abschluss **nicht** auf (dieselbe
Regel wie bei #031, dieselbe Funktion)
- [ ] Fortschrittsbalken und Zählwerte rechnen nur mit dem, was gilt
- [ ] Editor: Bedingung an Abschnitt und Schritt setzen, mit Auswahl der Variable bzw. des Schritts
- [x] Fortschrittsbalken und Zählwerte rechnen nur mit dem, was gilt
- [x] Editor: Bedingung an Abschnitt und Schritt setzen, mit Auswahl der Variable bzw. des Schritts
**aus derselben Version**; eine Vorschau, die sagt „gilt, wenn …“
- [ ] Warnung im Editor bei einer Bedingung auf einen Schritt, der **nach** dem bedingten steht —
- [x] Warnung im Editor bei einer Bedingung auf einen Schritt, der **nach** dem bedingten steht —
sie wäre beim Abarbeiten noch offen, und der Abschnitt erschiene erst rückwirkend
- [ ] Abarbeitung: ausgeblendete Abschnitte verschwinden, ohne die Nummerierung zu verschieben
- [x] Abarbeitung: ausgeblendete Abschnitte verschwinden, ohne die Nummerierung zu verschieben
(`01 · Vorbereitung` kommt aus der Position und wird nie gespeichert)
- [ ] Druckansicht und Archiv zeigen, was galt
- [ ] Export/Import: die Bedingung wandert mit, und ein Verweis auf einen Schritt wird dabei auf die
- [x] Druckansicht und Archiv zeigen, was galt
- [x] Export/Import: die Bedingung wandert mit, und ein Verweis auf einen Schritt wird dabei auf die
**neue** Kennung umgeschrieben — sonst zeigt sie in der zweiten Installation ins Leere
- [ ] Seed: „Mitarbeiter-Onboarding“ bekommt die Bedingung auf `konto_typ`, die beiden
- [x] Seed: „Mitarbeiter-Onboarding“ bekommt die Bedingung auf `konto_typ`, die beiden
Konto-Abschnitte bleiben drin und schließen sich gegenseitig aus. Das ist die Gegenprobe am
echten Fall.
- [ ] Anleitung Kapitel 04 (Vorlagen): wann eine Bedingung das richtige Mittel ist und wann eine
- [x] Anleitung Kapitel 04 (Vorlagen): wann eine Bedingung das richtige Mittel ist und wann eine
zweite Vorlage
## Akzeptanzkriterien
- [ ] Test: ein Lauf mit `konto_typ = AD` hat die 5 AD-Schritte und **keinen** der 4 Entra-Schritte
- [ ] Test: dasselbe umgekehrt, und bei nicht gesetzter Variable gelten **beide** — eine Bedingung,
- [x] Test: ein Lauf mit `konto_typ = AD` hat die 5 AD-Schritte und **keinen** der 4 Entra-Schritte
- [x] Test: dasselbe umgekehrt, und bei nicht gesetzter Variable gelten **beide** — eine Bedingung,
die nicht entschieden werden kann, blendet nichts aus
- [ ] Test: eine Bedingung auf einem Schrittergebnis schlägt um, **während** der Lauf läuft, und der
- [x] Test: eine Bedingung auf einem Schrittergebnis schlägt um, **während** der Lauf läuft, und der
Abschnitt erscheint
- [ ] Test: ein ausgeblendeter Pflichtschritt hält den Abschluss nicht auf
- [ ] Test: ein Schrittergebnis mit Notiz bleibt stehen, wenn seine Bedingung umschlägt, und ist
- [x] Test: ein ausgeblendeter Pflichtschritt hält den Abschluss nicht auf
- [x] Test: ein Schrittergebnis mit Notiz bleibt stehen, wenn seine Bedingung umschlägt, und ist
danach wieder da
- [ ] Test: Export und Import einer Vorlage mit Bedingungen ergeben dieselbe Struktur, und der
- [x] Test: Export und Import einer Vorlage mit Bedingungen ergeben dieselbe Struktur, und der
Schritt-Verweis zeigt auf den richtigen Schritt der **neuen** Version
- [ ] Test: ein archivierter Lauf zeigt genau die Schritte, die bei seinem Abschluss galten
- [ ] Am Handy kein horizontales Scrollen
- [x] Test: ein archivierter Lauf zeigt genau die Schritte, die bei seinem Abschluss galten
- [x] Am Handy kein horizontales Scrollen
## Beim Umsetzen dazugekommen
- **Die Entscheidungen aus dem Issue sind so gefallen wie empfohlen**, und zwei davon haben sich im
Code als richtig erwiesen:
- **Laufend auswerten, nicht beim Start festschreiben.** Eine Bedingung auf einer Variable ließe
sich wie #031 beim Start festhalten; eine auf einem Schrittergebnis nicht — und genau die ist der
interessante Fall (ein Abschnitt „Nacharbeit“, der erscheint, wenn der Restore-Test
fehlschlägt).
- **Nicht entscheidbar heißt: gilt.** Ein Lauf ohne `konto_typ` zeigt beide Konto-Abschnitte —
genau wie vor diesem Meilenstein. Eine erfundene Antwort wäre die Verschlechterung.
- **`OFFEN` ist eine Antwort, keine Lücke.** Der Unterschied zur Variable musste scharf gezogen
werden: eine nicht gesetzte Variable ist nicht entscheidbar, ein offener Schritt dagegen klar
„noch nicht erfüllt“. Wäre `OFFEN` unentscheidbar, wäre ein bedingter Abschnitt von Anfang an
sichtbar — das Gegenteil des Zwecks.
- **Verwiesen wird über Titel-Pfade, nicht über Kennungen**, und das war die größte Einzelerkenntnis.
**Vier** Wege schreiben eine Struktur neu und geben dabei neue Kennungen: Import, Export, Seed und
`entwurfSpeichern`. Eine Bedingung auf einer Kennung überlebt keinen davon. `bedingungAufloesen`
ist für alle vier dieselbe Stelle; dass eine Bedingung auf **dieselbe Version** zeigt, hält
zusätzlich ein Trigger.
- **Ein struktureller Test bewacht die drei Schichten.** Abschlussregel, Abarbeitung und Druck
müssen alle `geltendeStruktur` rufen; vergisst eine es, sieht der Techniker andere Schritte als
der Ausdruck. Der Test liest die drei Dateien — dieselbe Art Prüfung wie „jede Seite prüft selbst“
(#038).
- **Zwei Schemas für dieselbe Form liefen fast auseinander.** Austauschformat und Editor-Struktur
brauchen die Pfad-Form; ich hatte sie zweimal geschrieben, und TypeScript meldete es erst, als die
beiden Typen aufeinandertrafen. Jetzt steht `PfadBedingungSchema` in `src/lib/bedingungen.ts`, und
`vorlagen-format.ts` importiert es.
## Zwei stille Datenverluste, gefunden bei der Klickprobe
Beides hätte keine Suite gezeigt, und das zweite war **älter als dieser Meilenstein**:
- **Der Import verwarf `nurFuerAbteilungen`.** Der Export schreibt die Abteilungseinschränkung seit
[#031](031-abteilungsabschnitte.md), das Schema nimmt sie an — und der Import setzte sie nicht.
Eine Vorlage, die jemand in eine zweite Installation brachte, verlor ihre Abteilungsabschnitte:
sie galten dort für **alle**. Also mehr Schritte statt weniger, und niemand merkt es.
- **Die tiefe Kopie verwarf sie ebenfalls — und seit heute auch die Bedingung.** „Bearbeiten“ einer
Vorlage erzeugt eine tiefe Kopie als Entwurf (#009); `vorlageDuplizieren` dasselbe. Beide hatten
die Kopie einzeln ausgeschrieben, und beide vergaßen dieselben Felder. Damit verlor **jede
Bearbeitung** alle Abteilungseinschränkungen.
**Die Ursache war ein von Hand getippter Zwischentyp.** `VersionMitInhalt` nannte weniger Felder,
als die Abfrage liefert; die Felder waren da, der Code konnte sie nicht sehen. Jetzt ist der Typ
aus Prisma abgeleitet — ein neues Feld am Modell ist dort automatisch vorhanden.
Gefunden hat es die **Klickprobe am gebauten Stand**: der Editor zeigte „Bedingung gesetzt“ in der
veröffentlichten Version, und nach „Bearbeiten“ war sie weg. Das ist genau der Grund, warum diese
Probe in `CLAUDE.md` steht.
Bewacht wird es jetzt von einem Test, der Kopie und Original **Feld für Feld** vergleicht — nicht
stichprobenweise. So fällt auch das nächste Feld auf, das jemand ergänzt und beim Kopieren
vergisst.
- **Ein Mangel an der neuen Komponente**, aufgefallen beim Klicken: die Auswahlfelder standen in
einem umhüllenden `<label>`, und damit schluckte ihr zugänglicher Name den Text der gewählten
Option mit („VariableKontotyp“). Für einen Screenreader ist das eine Bezeichnung, die sich beim
Umschalten ändert. Jetzt `htmlFor`/`id` — derselbe Fehler wie bei der Adresse im Verzeichnis-Formular
(#016).
## Was offen bleibt
- **Kein `und`/`oder`**, bewusst. Wer zwei Bedingungen braucht, nimmt zwei Abschnitte.
- **Ein Baustein-Schritt hat keine Bedingung** (der Abschnitt, in dem er steht, darf eine haben): ein
Baustein ist wiederverwendbar, und eine Bedingung auf einer Variable der Zielvorlage wäre dort
nicht entscheidbar.
- **Zwei Schritte mit demselben Titel im selben Abschnitt** sind über den Titel-Pfad nicht
unterscheidbar; die Bedingung zeigt dann auf den ersten. Benannt in `src/lib/bedingungen.ts` —
zwei gleich benannte Schritte nebeneinander kann auch ein Mensch nicht unterscheiden.
+2 -2
View File
@@ -43,8 +43,8 @@ Diese Dateien sind die Quelle; `pnpm issues:sync` spiegelt sie in den Gitea-Trac
| #036 | [Reviewbefunde aus der Durchsicht von Phase 2](036-reviewbefunde-phase-2.md) | erledigt | v0.2.0 | 4 h | 3 h 40 min |
| #037 | [Zwei Nachzügler aus der Durchsicht von Phase 2](037-anhaenge-lesemodell.md) | erledigt | v0.2.0 | 2 h | 1 h 50 min |
| #038 | [Die E2E-Abläufe laufen in keinem Tor und waren monatelang rot](038-e2e-im-tor.md) | erledigt | v0.2.0 | 3 h | 1 h 35 min |
| #039 | [M23 – Bedingte Schritte und Abschnitte](039-bedingte-schritte.md) | offen | v0.3.0 | 12 h | – |
| #039 | [M23 – Bedingte Schritte und Abschnitte](039-bedingte-schritte.md) | erledigt | v0.3.0 | 12 h | 5 h 20 min |
| #040 | [M24 – Vier-Augen-Freigabe](040-vier-augen-freigabe.md) | offen | v0.3.0 | 8 h | – |
| #041 | [M25 – PDF-Übergabeprotokoll mit Unterschrift](041-pdf-uebergabeprotokoll.md) | offen | v0.3.0 | 8 h | – |
| #042 | [M26 – Weitere Schritt-Typen](042-weitere-schritt-typen.md) | offen | v0.3.0 | 6 h | – |
| | **Summe** | | | **272 h** | **73 h 55 min** |
| | **Summe** | | | **272 h** | **79 h 15 min** |