@@ -11,27 +11,75 @@ Nachweis, dass die Abläufe wirklich durchlaufen, und eine Anleitung, mit der ei
## Aufgaben
- [] Playwright-Hauptablauf: anmelden → „PC Neuinstallation“ für `PC-001` starten → Schritte abhaken → Wert eintragen → einen Schritt „nicht zutreffend“ mit Notiz → abschließen → archivieren → im Archiv finden → Schreibschutz greift
- [] Derselbe Hauptablauf mit `SEED_MODE=SERVICE` gegen `MUS-PC-001`, mit Kundenwahl im Start-Dialog
- [] Playwright-QR-Ablauf: `/t/LZ-7K3F9Q` ohne Anmeldung → Login → Geräteseite → „Vorlage zuweisen“ → Lauf erscheint unter „Zugewiesen“ → „Starten“ setzt `IN_ARBEIT`; dazu unregistrierter Tag → Registrierformular → Geräteseite; unbekannter Tag → Hinweis
- [] Playwright-Onboarding-Ablauf: Vorlage starten → Vorname und Nachname eingeben → UPN, `sam` und Mail werden vorgeschlagen → Abteilung „Buchhaltung“ wählen → im Schritt „Konto anlegen“ steht der fertige `New-ADUser`-Befehl → Kopieren liefert exakt diesen Text (Clipboard auslesen)
- [] Playwright-Mobilprüfung: auf allen Hauptseiten bei 390 × 844 ist `scrollWidth <= clientWidth`
- [] Playwright-Rollenprüfung: `LESER` sieht keine Schreib-Knöpfe und wird serverseitig abgewiesen
- [] Die Abläufe suchen ihre Vorlage **am Namen**, nicht über `select ... { index: 1 }`. Aufgefallen in #017: gegen eine frisch geseedete Datenbank steht an erster Stelle „Mitarbeiter-Offboarding“ mit Pflichtvariablen, die der Helfer nicht füllt — sechs Abläufe liefen je 30 s in den Zeitablauf. Ein Ablauf, der von der Sortierung der Vorlagenliste abhängt, prüft nicht, was er zu prüfen vorgibt
- [] Die Voraussetzungen eines E2E-Laufs stehen an einer Stelle und werden geprüft, statt im Kopfkommentar zu stehen (`pnpm beispiel:vorlage`, `pnpm beispiel:stammdaten`, `pnpm beispiel:lauf`) — besser noch: die Abläufe legen an, was sie brauchen. Die drei Skripte tragen auch die Screenshots; was davon bleibt und was in die Abläufe wandert, wird hier entschieden. In den Seed gehört es **nicht**: eine frische Installation soll keine Demo-Läufe und keine offenen Entwürfe mitbringen (in #017 geprüft und so entschieden)
- [] Kein Ablauf setzt voraus, dass die Datenbank schon Läufe enthält. `uebersicht-druck.spec.ts` sucht sich mit `lauf.findFirstOrThrow()` irgendeinen Lauf und „Zuletzt bearbeitet" muss gefüllt sein — gegen eine frisch eingerichtete Installation scheitert beides mit „No record was found", und das sagt nichts über die Ursache (gesehen in #017)
- []Der E2E-Lauf prüft beim Start, dass er **dieselbe** Datenbank benutzt wie der Server unter Test. Die Abläufe legen ihre Daten über `prisma` aus `.env` an, die Adresse des Servers steht in `E2E_APP_URL` — zeigen beide auf verschiedene Datenbanken, schreibt der Test in die eine und sucht in der anderen. Die Meldung heißt dann „0 Treffer“ und sagt nichts über die Ursache (gesehen in #017)
- []`pnpm docs:screenshots`: Playwright-Skript, Desktop 1440 × 900 und Handy 390 × 844, Seed-Daten, dunkles Design, mit Markierungen (Rahmen, Nummern) für die beschriebenen Stellen; Ablage `docs/anleitung/bilder/`
- []`pnpm docs:pdf`: Anleitung als PDF über Chromium (`page.pdf`, A4, `printBackground`), Ablage `docs/anleitung/laufzettel-anleitung.pdf`
- []`docs/anleitung/` auf Deutsch, getrennt für Techniker und Admins: Erste Schritte · Vorlagen bauen · Läufe abarbeiten (Desktop und Handy) · QR-Tags drucken und registrieren · Mitarbeiter und Abteilungen · Betriebsmodus · Admin: Verzeichnis, Benutzer, Einstellungen · Fehlerbehebung
- []`README.md` vollständig: Setup, alle Umgebungsvariablen, Betrieb mit Docker Compose, authentik-Anbindung inkl. Gruppen für Rollen, Seed, Sicherungshinweis für die Datenbank
- [x] Playwright-Hauptablauf: anmelden → „PC Neuinstallation“ für `PC-001` starten → Schritte abhaken → Wert eintragen → einen Schritt „nicht zutreffend“ mit Notiz → abschließen → archivieren → im Archiv finden → Schreibschutz greift
- [x] Derselbe Hauptablauf mit `SEED_MODE=SERVICE` gegen `MUS-PC-001`, mit Kundenwahl im Start-Dialog
- [x] Playwright-QR-Ablauf: `/t/LZ-7K3F9Q` ohne Anmeldung → Login → Geräteseite → „Vorlage zuweisen“ → Lauf erscheint unter „Zugewiesen“ → „Starten“ setzt `IN_ARBEIT`; dazu unregistrierter Tag → Registrierformular → Geräteseite; unbekannter Tag → Hinweis
- [x] Playwright-Onboarding-Ablauf: Vorlage starten → Vorname und Nachname eingeben → UPN, `sam` und Mail werden vorgeschlagen → Abteilung „Buchhaltung“ wählen → im Schritt „Konto anlegen“ steht der fertige `New-ADUser`-Befehl → Kopieren liefert exakt diesen Text (Clipboard auslesen)
- [x] Playwright-Mobilprüfung: auf allen Hauptseiten bei 390 × 844 ist `scrollWidth <= clientWidth`
- [x] Playwright-Rollenprüfung: `LESER` sieht keine Schreib-Knöpfe und wird serverseitig abgewiesen
- [x] Die Abläufe suchen ihre Vorlage **am Namen**, nicht über `select ... { index: 1 }`. Aufgefallen in #017: gegen eine frisch geseedete Datenbank steht an erster Stelle „Mitarbeiter-Offboarding“ mit Pflichtvariablen, die der Helfer nicht füllt — sechs Abläufe liefen je 30 s in den Zeitablauf. Ein Ablauf, der von der Sortierung der Vorlagenliste abhängt, prüft nicht, was er zu prüfen vorgibt
- [x] Die Voraussetzungen eines E2E-Laufs stehen an einer Stelle und werden geprüft, statt im Kopfkommentar zu stehen (`pnpm beispiel:vorlage`, `pnpm beispiel:stammdaten`, `pnpm beispiel:lauf`) — besser noch: die Abläufe legen an, was sie brauchen. Die drei Skripte tragen auch die Screenshots; was davon bleibt und was in die Abläufe wandert, wird hier entschieden. In den Seed gehört es **nicht**: eine frische Installation soll keine Demo-Läufe und keine offenen Entwürfe mitbringen (in #017 geprüft und so entschieden)
- [x] Kein Ablauf setzt voraus, dass die Datenbank schon Läufe enthält. `uebersicht-druck.spec.ts` sucht sich mit `lauf.findFirstOrThrow()` irgendeinen Lauf und „Zuletzt bearbeitet" muss gefüllt sein — gegen eine frisch eingerichtete Installation scheitert beides mit „No record was found", und das sagt nichts über die Ursache (gesehen in #017)
- [x]`pnpm beispiel:stammdaten` und `pnpm beispiel:lauf` laufen nur im Modus `INTERN`: sie rufen die Dienste ohne Kunden und scheitern im Modus `DIENSTLEISTUNG` an `MandantFehler: Im Modus Dienstleistung muss ein Kunde gewählt werden`. Das ist richtiges Verhalten der App und eine Lücke der Skripte — wer den Hauptablauf in beiden Modi fahren will, braucht sie in beiden
- [x]Der E2E-Lauf prüft beim Start, dass er **dieselbe** Datenbank benutzt wie der Server unter Test. Die Abläufe legen ihre Daten über `prisma` aus `.env` an, die Adresse des Servers steht in `E2E_APP_URL` — zeigen beide auf verschiedene Datenbanken, schreibt der Test in die eine und sucht in der anderen. Die Meldung heißt dann „0 Treffer“ und sagt nichts über die Ursache (gesehen in #017)
- [x]`pnpm docs:screenshots`: Playwright-Skript, Desktop 1440 × 900 und Handy 390 × 844, Seed-Daten, dunkles Design, mit Markierungen (Rahmen, Nummern) für die beschriebenen Stellen; Ablage `docs/anleitung/bilder/`
- [x]`pnpm docs:pdf`: Anleitung als PDF über Chromium (`page.pdf`, A4, `printBackground`), Ablage `docs/anleitung/laufzettel-anleitung.pdf`
- [x]`docs/anleitung/` auf Deutsch, getrennt für Techniker und Admins: Erste Schritte · Vorlagen bauen · Läufe abarbeiten (Desktop und Handy) · QR-Tags drucken und registrieren · Mitarbeiter und Abteilungen · Betriebsmodus · Admin: Verzeichnis, Benutzer, Einstellungen · Fehlerbehebung
- [x]`README.md` vollständig: Setup, alle Umgebungsvariablen, Betrieb mit Docker Compose, authentik-Anbindung inkl. Gruppen für Rollen, Seed, Sicherungshinweis für die Datenbank
## Akzeptanzkriterien
- [] Alle Playwright-Abläufe grün, in `INTERN` und in `DIENSTLEISTUNG`
- [] Der Kopier-Knopf liefert exakt den erwarteten Befehlstext, zeichengenau geprüft
- [] Keine Hauptseite scrollt bei 390 px horizontal
- []`pnpm docs:screenshots` erzeugt alle in der Anleitung verlinkten Bilder reproduzierbar neu
- []`pnpm pruefe:doku` meldet kein fehlendes Bild
- [] Das PDF enthält alle Kapitel mit Bildern, Umlaute korrekt, keine abgeschnittenen Seiten
- [] Die README beschreibt authentik so, dass ein Dritter die Anbindung ohne Rückfrage hinbekommt
- [x] Alle Playwright-Abläufe grün, in `INTERN` und in `DIENSTLEISTUNG`
- [x] Der Kopier-Knopf liefert exakt den erwarteten Befehlstext, zeichengenau geprüft
- [x] Keine Hauptseite scrollt bei 390 px horizontal
- [x]`pnpm docs:screenshots` erzeugt alle in der Anleitung verlinkten Bilder reproduzierbar neu
- [x]`pnpm pruefe:doku` meldet kein fehlendes Bild
- [x] Das PDF enthält alle Kapitel mit Bildern, Umlaute korrekt, keine abgeschnittenen Seiten
- [x] Die README beschreibt authentik so, dass ein Dritter die Anbindung ohne Rückfrage hinbekommt
## Ergebnis
Erledigt am 2026-09-26. **101 Ende-zu-Ende-Abläufe** im Modus `INTERN` und **97** im Modus
`DIENSTLEISTUNG`, beide ohne Fehlschlag; Vitest unverändert bei 1130. Die Anleitung steht unter
`docs/anleitung/` mit 35 Bildern, das PDF hat 72 Seiten.
### Was die Abläufe jetzt anders machen
- **Die Voraussetzungen werden geprüft, nicht behauptet.** `tests/e2e/global-setup.ts` fragt vor dem
ersten Ablauf: antwortet ein gebauter Stand, steht der Seed-Bestand, und liest der Server
**dieselbe** Datenbank wie der Testprozess? Die dritte Frage hat in #017 einen halben Abend
gekostet, weil ihre Antwort „0 Treffer" hieß.
- **Jeder Ablauf legt an, was er braucht, und räumt es weg.** Keine Vorlage über `index: 1`, keine
Annahme „die Datenbank enthält schon Läufe", kein `test.skip` bei fehlenden Daten.
- **Zehn Kopien von `anmelden()`** sind zu einer geworden.
### Drei Fehler, die dabei herauskamen
1.**Das Projekt „handy" prüfte 412 px statt 390.**`devices["Pixel 7"]` ist 412 breit; CLAUDE.md und
das Abnahmekriterium nennen 390. Jeder „trägt am Handy ohne horizontales Scrollen"-Test lief
gegen eine Breite, die niemand verlangt hatte. Nach der Korrektur blieb alles grün — die Zusage
hielt, sie war nur nie geprüft.
2.**Eine Auskunft, die niemand je gesehen hat.** Ein angemeldeter Benutzer ohne Recht wurde auf
`/anmelden?fehler=keinrecht` geschickt, und die Anmeldeseite leitet einen Angemeldeten sofort
weiter. Die Meldung war unerreichbar, der Kommentar im Code versprach sie. Jetzt gibt es
`/kein-zugriff` mit der eigenen Rolle darin.
3.**Zwei Tests, die Schaden anrichteten:** der Verzeichnis-Ablauf schrieb die Attributzuordnung der
**ersten vorhandenen** Quelle um — in einer echten Installation die produktive; und ein Nachlauf
setzte die Namensregeln auf leer, statt den vorherigen Wert zurückzustellen.
### Der zweite Betriebsmodus
Der erste Durchgang im Modus `DIENSTLEISTUNG` hatte **28 rote Abläufe**, sechs Ursachen, alle
dieselbe blinde Stelle: die Kundenebene. Dort hat jedes Anlege-Formular ein Pflichtfeld mehr, und
dahinter steht eine Regel, die nicht verhandelbar ist — ein Lauf kann **strukturell** kein Gerät und
keine Abteilung eines fremden Kunden wählen, dafür sorgen zusammengesetzte Fremdschlüssel. „Irgendein
Kunde" ist dort nicht ungenau, sondern rot. Beim Onboarding war es sogar eine Reihenfolge: die
Kundenwahl stand hinter dem Namensvorschlag, und ohne Kunden greifen die Namensregeln nicht.
Ohne dieses Abnahmekriterium wäre der zweite Betriebsmodus ungeprüft ins Release gegangen.
### Beim Schreiben der Anleitung aufgefallen
Zwei Stellen, an denen die App etwas kann, das niemand bedienen kann — beide als Issue festgehalten,
nicht weggeschwiegen: [#022](022-schnellstart-pflegen.md) (Schnellstart je Gerätetyp setzt nur der
Seed) und [#023](023-protokoll-ansicht.md) (das Protokoll wird geschrieben, aber nie angezeigt).
@@ -26,6 +26,8 @@ Zwei erprobte Wege in den Betrieb und ein sauberes erstes Release.
- [ ] Devlog-Phasenzusammenfassung: Gesamtstunden, Stunden je Meilenstein, größte Zeitfresser, Abweichung vom Plan
- [ ]`CHANGELOG.md` für `v0.1.0` mit Datum, Version in `package.json`, Tag `v0.1.0`, Gitea-Release mit Changelog-Auszug, Anleitung als PDF beigelegt
- [ ] Die Anleitung als PDF (`pnpm docs:pdf`) dem Gitea-Release als Datei beilegen — im Repo liegt sie nicht, sie entsteht aus den Kapiteln und Bildern
## Akzeptanzkriterien
- [ ]`docker run --rm debian:13` mit `deploy/install.sh` installiert vollständig durch: Postgres läuft, Migration und Seed gelaufen, Dienst antwortet auf `/api/gesundheit`
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.