feat(vorlagen): Abschnitte nur fuer bestimmte Abteilungen
Prüfung / pruefung (pull_request) Canceled after 0s
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (pull_request) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s

Beim Onboarding in der Buchhaltung gehoeren Schritte dazu, die sonst niemand
braucht: DATEV, Drucker fuer Formulare, Bankportal. Bisher hiess die Wahl: eine
Vorlage je Abteilung pflegen, oder Schritte, die fuer die meisten "nicht
zutreffend" sind.

Jeder Abschnitt kann jetzt nennen, fuer welche Abteilungen er gilt -- als
**Namen**, nicht als Kennungen. Der Abschnitt gehoert zur Version und muss ein
Umbenennen oder Archivieren einer Abteilung ueberleben; dieselbe Entscheidung
wie bei Mitarbeiter.abteilung. Deshalb wandert die Einschraenkung auch durch
Export und Import.

Welche Abschnitte ein Lauf hat, wird beim Start festgeschrieben. Ein spaeterer
Abteilungswechsel aendert ihn nicht -- sonst verschwaende ein Schritt, an dem
schon eine Notiz haengt, und ein archivierter Lauf muss genau das zeigen, was
damals abgearbeitet wurde.

Leer heisst alle: Laeufe von vor dieser Fassung verhalten sich unveraendert,
ohne dass eine Migration Daten nachfuehren muesste. Damit das eindeutig bleibt,
wird ein Lauf abgewiesen, fuer den kein Abschnitt uebrig bleibt -- es gaebe
ohnehin nichts abzuarbeiten.

Die Abschlussregel zaehlt nur geltende Pflichtschritte. Vorher waere der
Abschluss unerreichbar gewesen: abhaken laesst sich nur, was in der Abarbeitung
steht. Der Test hat das sofort gezeigt.

Die Regel liegt in src/lib, weil drei Schichten sie brauchen -- der Dienst beim
Start und beim Abschluss, die Lesemodelle der Abarbeitung und des Drucks. In
einem Lesemodell waere sie eine Abhaengigkeit in die falsche Richtung.

Im gebauten Stand durchgeklickt: einschraenken, speichern, veroeffentlichen,
zwei Laeufe mit verschiedenen Abteilungen starten -- 6 Abschnitte mit 23
Schritten fuer die Buchhaltung, 5 mit 20 fuer den Vertrieb. Dabei einen eigenen
Numerusfehler im Hinweistext gefunden und behoben.

Closes #51
This commit is contained in:
Florian Wilde
2026-10-04 20:04:14 +02:00
parent 80870133b8
commit b8166e10ea
24 changed files with 815 additions and 37 deletions
+5
View File
@@ -40,6 +40,11 @@ Es gibt drei Wege, und der schnellste ist meist nicht dieser:
entsteht und beginnt sofort, mit Gerät und Besitzer, ohne eine einzige Eingabe. Siehe
[Kapitel 03](03-qr-tags.md).
- **Aus der Übersicht**: der Block **Schnellstart** führt mit vorgewählter Vorlage in den Dialog.
Wählst du im Start-Dialog eine **Abteilung**, steht darunter, welche Abschnitte sie hinzunimmt — oder
dass Abschnitte nur für andere Abteilungen gelten und wegbleiben. Welche Abschnitte ein Lauf hat,
wird beim Start festgeschrieben und ändert sich danach nicht mehr, auch nicht, wenn jemand die
Abteilung des Laufs korrigiert.
- **Über den Knopf Lauf starten** in der Laufliste — der vollständige Weg, hier beschrieben.
![Der Start-Dialog mit Vorlage, Gerät, Person und den Angaben zum Lauf](bilder/lauf-starten-desktop.png)
+29
View File
@@ -190,6 +190,35 @@ und für `{{generiertes_passwort}}` entsteht **kein** Passwort — dort steht
Nutz sie vor dem Veröffentlichen, besonders bei Befehlen: erst hier sieht man, ob der fertige Befehl
so aussieht, wie er aussehen soll.
## Abschnitte nur für bestimmte Abteilungen
Beim Onboarding in der Buchhaltung gehören Schritte dazu, die sonst niemand braucht: DATEV
einrichten, Drucker für Formulare, Zugang zum Bankportal. Bisher hieß die Wahl: eine Vorlage je
Abteilung pflegen, oder Schritte, die für die meisten „nicht zutreffend“ sind.
In jedem Abschnitt steht dafür **Nur für diese Abteilungen**: ein Kästchen je gepflegter Abteilung,
darunter ein Feld für eine, die es noch nicht gibt. Bleibt alles leer, gilt der Abschnitt für jeden
Lauf — das ist der Normalfall.
Drei Dinge, die man dazu wissen muss:
- **Ein Lauf ohne Abteilung bekommt nur die uneingeschränkten Abschnitte.** Ein Firewall-Rollout hat
keine Abteilung, und das ist kein Mangel.
- **Die Auswahl wird beim Start festgeschrieben.** Wer später die Abteilung eines laufenden Laufs
ändert, ändert seine Abschnitte **nicht**. Sonst verschwände ein Schritt, an dem schon eine Notiz
hängt — und ein archivierter Lauf muss genau das zeigen, was damals abgearbeitet wurde.
- **Ein ausgefilterter Pflichtschritt blockiert den Abschluss nicht.** Er steht nicht in der
Abarbeitung, also lässt er sich auch nicht abhaken; würde er zählen, wäre der Abschluss
unerreichbar.
Gespeichert werden **Namen**, nicht Kennungen. Ein Abschnitt gehört zur Version und muss ein
Umbenennen oder Archivieren einer Abteilung überleben, ohne ins Leere zu zeigen — und beim Vergleich
ist Groß- und Kleinschreibung gleichgültig. Deshalb wandert die Einschränkung auch durch Export und
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.
## Bausteine: ein Abschnitt für mehrere Vorlagen
„Datensicherung prüfen“ steht in vier der sieben mitgelieferten Vorlagen, wortgleich. Wer den Ablauf
+38 -18
View File
@@ -1,10 +1,10 @@
# #031 M18 – Abteilungsspezifische Zusatzabschnitte
**Status:** offen
**Status:** erledigt
**Im Tracker:** [#51](https://git.wilde-server.de/florian.wilde/Laufzettel/issues/51)
**Meilenstein:** v0.2.0
**Labels:** phase-2, backend, frontend
**Geschätzt:** 8 h **Tatsächlich:** –
**Geschätzt:** 8 h **Tatsächlich:** 1 h 35 min
## Ziel
@@ -16,34 +16,54 @@ Ein Abschnitt soll sagen können: **nur für diese Abteilungen.**
## Zu entscheiden
- [ ] **Die Auswahl wird beim Start festgeschrieben** — Empfehlung. Der Lauf merkt sich, welche
- [x] **Die Auswahl wird beim Start festgeschrieben** — Empfehlung. Der Lauf merkt sich, welche
Abschnitte für ihn gelten, statt sie bei jedem Aufruf aus `Lauf.abteilungId` neu zu berechnen.
Grund: ein archivierter Lauf muss genau die Schritte zeigen, die damals abgearbeitet wurden.
Wechselt jemand später die Abteilung des Laufs, dürfen Schritte nicht verschwinden, an denen
schon eine Notiz hängt.
- [ ] **Was bei einem Lauf ohne Abteilung gilt:** nur die Abschnitte ohne Einschränkung. Ein
- [x] **Was bei einem Lauf ohne Abteilung gilt:** nur die Abschnitte ohne Einschränkung. Ein
Firewall-Rollout hat keine Abteilung, und das ist kein Mangel.
## Aufgaben
- [ ] `VorlagenAbschnitt.nurFuerAbteilungen` — Liste von Abteilungsnamen, nicht von Kennungen: der
- [x] `VorlagenAbschnitt.nurFuerAbteilungen` — Liste von Abteilungsnamen, nicht von Kennungen: der
Abschnitt gehört zur Version und muss ein Umbenennen oder Archivieren einer Abteilung
überleben, ohne ins Leere zu zeigen. Dieselbe Entscheidung wie bei `Mitarbeiter.abteilung`
- [ ] Beim Start: die geltenden Abschnitte ermitteln und am Lauf festhalten
- [ ] Die Abarbeitungsansicht zeigt nur geltende Abschnitte; die Nummerierung (`01 ·`) zählt nur sie
- [ ] **Die Abschlussregel zählt nur geltende Pflichtschritte.** Ein ausgefilterter Pflichtschritt
- [x] Beim Start: die geltenden Abschnitte ermitteln und am Lauf festhalten
- [x] Die Abarbeitungsansicht zeigt nur geltende Abschnitte; die Nummerierung (`01 ·`) zählt nur sie
- [x] **Die Abschlussregel zählt nur geltende Pflichtschritte.** Ein ausgefilterter Pflichtschritt
darf einen Lauf nicht blockieren — sonst ist der Abschluss unerreichbar
- [ ] Druckansicht und Archiv zeigen dieselbe Auswahl wie die Abarbeitung
- [ ] Editor: je Abschnitt eine Mehrfachauswahl über die gepflegten Abteilungen, mit Freitext für
- [x] Druckansicht und Archiv zeigen dieselbe Auswahl wie die Abarbeitung
- [x] Editor: je Abschnitt eine Mehrfachauswahl über die gepflegten Abteilungen, mit Freitext für
eine, die es noch nicht gibt
- [ ] Der Start-Dialog sagt vorher, wie viele Abschnitte die gewählte Abteilung hinzunimmt
- [ ] Anleitung Kapitel 04 und 02
- [x] Der Start-Dialog sagt vorher, wie viele Abschnitte die gewählte Abteilung hinzunimmt
- [x] Anleitung Kapitel 04 und 02
## Akzeptanzkriterien
- [ ] Test: ein Lauf für „Buchhaltung“ enthält den Buchhaltungs-Abschnitt, einer für „Vertrieb“ nicht
- [ ] Test: ein Lauf ohne Abteilung enthält nur die uneingeschränkten Abschnitte
- [ ] Test: die Abteilung eines laufenden Laufs ändern ändert **nicht** seine Abschnitte
- [ ] Test: ein ausgefilterter Pflichtschritt blockiert den Abschluss nicht
- [ ] Test: die Druckansicht zeigt genau die Abschnitte der Abarbeitung — nicht mehr und nicht weniger
- [ ] Am Handy kein horizontales Scrollen
- [x] Test: ein Lauf für „Buchhaltung“ enthält den Buchhaltungs-Abschnitt, einer für „Vertrieb“ nicht
- [x] Test: ein Lauf ohne Abteilung enthält nur die uneingeschränkten Abschnitte
- [x] Test: die Abteilung eines laufenden Laufs ändern ändert **nicht** seine Abschnitte
- [x] Test: ein ausgefilterter Pflichtschritt blockiert den Abschluss nicht
- [x] Test: die Druckansicht zeigt genau die Abschnitte der Abarbeitung — nicht mehr und nicht weniger
- [x] Am Handy kein horizontales Scrollen
## Beim Umsetzen dazugekommen
- **Festgeschrieben wird über `Lauf.geltendeAbschnitte`, und leer heißt „alle".** Damit verhalten
sich Läufe von vor dieser Fassung unverändert, ohne dass eine Migration Daten nachführen müsste.
Ein neuer Lauf trägt immer alle geltenden Kennungen — auch wenn nichts eingeschränkt ist, denn
sonst wäre „leer" zweideutig.
- **Ein Lauf, für den kein Abschnitt übrig bleibt, wird abgewiesen.** Das war nötig, damit „leer
heißt alle" eindeutig bleibt — und es ist ohnehin richtig: es gäbe nichts abzuarbeiten.
- **Die Abschlussregel musste nachziehen.** `offenePflichtschritte` zählte den ausgefilterten
Pflichtschritt weiter mit; der Abschluss wäre unerreichbar gewesen, weil sich nur abhaken lässt,
was in der Abarbeitung steht. Der Test hat das sofort gezeigt.
- **Die Regel liegt in `src/lib/geltende-abschnitte.ts`**, nicht in einem der Lesemodelle: drei
Schichten brauchen sie — der Dienst beim Start und beim Abschluss, und die Lesemodelle der
Abarbeitung und der Druckansicht. Lebte sie in einem Lesemodell, importierte ein Dienst daraus, und
das wäre eine Abhängigkeit in die falsche Richtung.
- **Ein Baustein-Abschnitt lässt sich genauso einschränken** wie jeder andere: die Einschränkung
gehört zur Vorlage, nicht zum Baustein.
- **Eigener Numerusfehler beim Durchklicken gefunden:** „Ein Abschnitt gilt … und *bleiben* weg."
Korrigiert — alles, was ein Mensch liest, schreibt sich richtig (CLAUDE.md).
+2 -2
View File
@@ -35,9 +35,9 @@ Diese Dateien sind die Quelle; `pnpm issues:sync` spiegelt sie in den Gitea-Trac
| #028 | [M15 – Quellenarten und Microsoft-Graph-Quelle](028-graph-quelle.md) | offen | v0.2.0 | 10 h | – |
| #029 | [M16 – SCIM-Endpunkt als Alternative zum Abgleich](029-scim-endpunkt.md) | offen | v0.2.0 | 12 h | – |
| #030 | [M17 – Wiederverwendbare Bausteine](030-bausteine.md) | erledigt | v0.2.0 | 12 h | 2 h 25 min |
| #031 | [M18 – Abteilungsspezifische Zusatzabschnitte](031-abteilungsabschnitte.md) | offen | v0.2.0 | 8 h | – |
| #031 | [M18 – Abteilungsspezifische Zusatzabschnitte](031-abteilungsabschnitte.md) | erledigt | v0.2.0 | 8 h | 1 h 35 min |
| #032 | [M19 – Anhänge und Fotos an Schritten](032-anhaenge.md) | offen | v0.2.0 | 10 h | – |
| #033 | [M20 – Live-Aktualisierung per SSE statt Polling](033-sse-live.md) | offen | v0.2.0 | 6 h | – |
| #034 | [M21 – Benachrichtigungen per Mail und Webhook](034-benachrichtigungen.md) | offen | v0.2.0 | 10 h | – |
| #035 | [M22 – Mitarbeiter-Selbstauskunft](035-selbstauskunft.md) | offen | v0.2.0 | 8 h | – |
| | **Summe** | | | **229 h** | **43 h 45 min** |
| | **Summe** | | | **229 h** | **45 h 20 min** |