# #018 M13 – E2E-Tests, Anleitung, PDF **Status:** erledigt **Meilenstein:** v0.1.0 **Labels:** phase-1, test, docs **Geschätzt:** 14 h **Tatsächlich:** 2 h 15 min ## Ziel Nachweis, dass die Abläufe wirklich durchlaufen, und eine Anleitung, mit der ein Techniker ohne Einweisung arbeiten kann. ## Aufgaben - [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 - [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).