feat(archiv): Uebersicht, Volltextsuche und Druckansicht
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

Der Einstieg am Schreibtisch und das Gedaechtnis der Anwendung. Die Uebersicht
sortiert nach Dringlichkeit — ueberfaellig zuerst, und das ist das Einzige in
Warnfarbe; alles andere auf der Seite ist Auskunft.

Das Archiv sucht ueber Titel, Notizen, erfasste Werte und Kommentare in einer
SQL-Anweisung: `Schrittergebnis.wert` ist ein Json, und nur `("wert")::text`
trifft den Trigramm-Index aus #006. Vor allem aber gehoert die Fundstelle zum
Treffer — ein Treffer ohne sichtbaren Grund ist fuer den Suchenden wertlos.

Die Druckansicht ist ein eigenes Lesemodell und kein Schalter an
`laufZumAbarbeiten`: dort entsteht beim Fuellen der Befehle ein Passwort, und auf
einem Blatt, das jemand abheftet, darf keines stehen. Vom Mitarbeiter holt sie
nur Name, UPN und Abteilung — nicht alles und dann gefiltert.

Der unabhaengige Review fand zwei Blocker, beide im Dashboard: „ueberfaellig“
verglich mit dem Augenblick statt mit dem Tagesbeginn, und der Schnellstart
zaehlte Laeufe fremder Kunden mit. Was „ueberfaellig“ heisst, steht seitdem in
`src/lib/fristen.ts` — eine Regel fuer Lesemodell und Anzeige.

Closes #15

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-25 22:59:02 +02:00
co-authored by Claude Opus 5
parent e7a2e2d5c7
commit 8146e33f48
32 changed files with 4202 additions and 38 deletions
+47 -14
View File
@@ -1,9 +1,9 @@
# #015 M10 – Dashboard und Archiv
**Status:** offen
**Status:** erledigt
**Meilenstein:** v0.1.0
**Labels:** phase-1, frontend, backend
**Geschätzt:** 8 h **Tatsächlich:** –
**Geschätzt:** 8 h **Tatsächlich:** 2 h 20 min
## Ziel
@@ -11,18 +11,51 @@ Der Einstieg am Schreibtisch und das Gedächtnis der Anwendung.
## Aufgaben
- [ ] Dashboard: meine offenen Läufe, überfällige Läufe, zuletzt bearbeitet, Schnellstart der häufigsten Vorlagen
- [ ] Archiv-Volltextsuche über Titel, Notizen, Werte und Kommentare in einem gemeinsamen Query-Modul mit `pg_trgm` und `ILIKE`
- [ ] Filter nach Vorlage, Mitarbeiter, Abteilung, Gerät, Zeitraum und Bearbeiter; im Modus `DIENSTLEISTUNG` zusätzlich nach Kunde
- [ ] Druckansicht eines Laufs: Print-CSS, Kopfdaten, alle Abschnitte und Schritte, Werte, Notizen, Namen, Zeitstempel; ersetzt im MVP den PDF-Export
- [ ] In der Druckansicht erscheinen vom Mitarbeiter nur Name, UPN und Abteilung, sonst nichts
- [ ] Screenshots Übersicht, Archiv, Druckansicht in `docs/screenshots/m10/`
- [x] Dashboard: meine offenen Läufe, überfällige Läufe, zuletzt bearbeitet, Schnellstart der häufigsten Vorlagen
- [x] Archiv-Volltextsuche über Titel, Notizen, Werte und Kommentare in einem gemeinsamen Query-Modul mit `pg_trgm` und `ILIKE`
- [x] Filter nach Vorlage, Mitarbeiter, Abteilung, Gerät, Zeitraum und Bearbeiter; im Modus `DIENSTLEISTUNG` zusätzlich nach Kunde
- [x] Druckansicht eines Laufs: Print-CSS, Kopfdaten, alle Abschnitte und Schritte, Werte, Notizen, Namen, Zeitstempel; ersetzt im MVP den PDF-Export
- [x] In der Druckansicht erscheinen vom Mitarbeiter nur Name, UPN und Abteilung, sonst nichts
- [x] Screenshots Übersicht, Archiv, Druckansicht in `docs/screenshots/m10/`
## Akzeptanzkriterien
- [ ] Test: ein archivierter Lauf wird über ein Wort aus einer Schritt-Notiz gefunden
- [ ] Test: ein archivierter Lauf wird über ein Wort aus einem Kommentar gefunden
- [ ] Test: die Filter kombinieren sich (Vorlage und Zeitraum und Bearbeiter)
- [ ] Test: `{{generiertes_passwort}}` erscheint nicht in der Druckansicht
- [ ] Test: überfällige Läufe sind genau die mit `faelligAm < heute` und Status `OFFEN` oder `IN_ARBEIT`
- [ ] Die Druckansicht ist hell, ohne Navigation, und passt auf A4
- [x] Test: ein archivierter Lauf wird über ein Wort aus einer Schritt-Notiz gefunden
- [x] Test: ein archivierter Lauf wird über ein Wort aus einem Kommentar gefunden
- [x] Test: die Filter kombinieren sich (Vorlage und Zeitraum und Bearbeiter)
- [x] Test: `{{generiertes_passwort}}` erscheint nicht in der Druckansicht
- [x] Test: überfällige Läufe sind genau die mit `faelligAm < heute` und Status `OFFEN` oder `IN_ARBEIT`
- [x] Die Druckansicht ist hell, ohne Navigation, und passt auf A4
## Ergebnis
Erledigt am 2026-09-25. **980 Tests** (vorher 930) und **67 Ende-zu-Ende-Tests** grün, Screenshots in
`docs/screenshots/m10/`.
Drei Teile entstanden parallel: Archiv, Druckansicht und Übersicht. Eine Entscheidung des
Archiv-Teils ist nicht offensichtlich und darum hier festgehalten: **auch `ABGESCHLOSSEN` gehört
ins Archiv.** „Abgeschlossen ist nicht archiviert" (architektur.md §4) betrifft den Schreibschutz,
nicht das Suchen — wer die Seriennummer von letzter Woche sucht, weiß nicht, ob schon jemand
archiviert hat.
### Der unabhängige Review
Zwei Blocker, fünf Befunde, neun Anmerkungen — beide Blocker steckten im Dashboard, also in meinem
eigenen Teil:
- **„Überfällig" traf auch, was heute fällig ist.** Verglichen wurde mit dem Augenblick statt mit
dem Tagesbeginn; ein Datumsfeld speichert Mitternacht UTC, und damit stand ein heute fälliger
Lauf hierzulande ab zwei Uhr morgens in Warnfarbe — an genau dem Tag, an dem er erledigt werden
soll. Die Regel steht jetzt als `fristVerstrichen()` in `src/lib/fristen.ts`, Lesemodell und
Anzeige benutzen dieselbe, und ein Test prüft die Grenze selbst. Der alte Test kannte nur
„gestern" und „morgen".
- **Der Schnellstart zählte Läufe fremder Kunden mit.** Eine Vorlage ohne Kundenbezug gilt für alle
(#009); ihr Zähler sammelte die Läufe sämtlicher Kunden, und „4× gestartet" war damit eine
Auskunft über fremde Betriebe — dazu eine, die die Reihenfolge nach fremder Arbeit sortierte.
Dazu die Befunde: der E2E-Test „trägt kein Passwort" lief gegen eine Vorlage **ohne** Passwortschritt
und konnte gar nicht scheitern; der Trigramm-Index auf `Lauf.titel` war strukturell unerreichbar,
weil der Titeltreffer aus der materialisierten CTE las; `pflichtangaben` wurde berechnet,
dokumentiert und nie benutzt; „N weitere in der Liste" führte bei Überfälligen in die ungefilterte
Liste; und die Zusage „kein `{{generiertes_passwort}}` im Druck" galt nur für Vorlagentexte —
wörtlich in eine Notiz geschriebene Zeichenfolgen gibt der Beleg wieder, wie es ein Beleg tun muss.