# #041 M25 – PDF-Übergabeprotokoll mit Unterschrift **Status:** erledigt **Im Tracker:** – **Meilenstein:** v0.3.0 **Labels:** phase-3, backend, frontend **Geschätzt:** 8 h **Tatsächlich:** 4 h 10 min ## Ziel Wer ein Notebook übergibt, braucht ein Blatt, das der Empfänger unterschreibt — und das danach auffindbar ist. Heute gibt es die Druckansicht eines Laufs (`/drucken/lauf/[id]`, #015): sie ist hell, vollständig und als Vorstufe genau dafür gebaut. Was fehlt, ist die Datei. Ein Browser-Ausdruck genügt nicht: er hängt am Drucker-Dialog des Betrachters, trägt dessen Kopfzeilen und lässt sich nicht an ein Ticket anhängen. ## Zu entscheiden - [x] **Wie entsteht das PDF?** Empfehlung: **Chromium aus `@playwright/test`**, wie `scripts/anleitung-pdf.ts` es für die Anleitung tut. Keine neue Abhängigkeit, keine zweite Auslegung des Layouts — gedruckt wird dieselbe Seite, die die Druckansicht zeigt. **Grenze, die genannt gehört:** damit braucht der Server einen Chromium. Im Compose-Stand ist das eine Ergänzung am Image, nativ ein Paket. Die Alternative (`pdf-lib` oder ein Dienst) wäre ein zweites Layout, das auseinanderläuft — der Preis ist höher. - [x] **Unterschrift auf Papier oder auf dem Gerät?** Empfehlung: **beides, in dieser Reihenfolge.** Zuerst ein Unterschriftsfeld im PDF (eine Linie, Name, Datum) — das löst den Fall heute und kostet fast nichts. Eine Unterschrift mit dem Finger auf dem Handy ist ein eigener Schritt-Typ und gehört zu [#042](042-weitere-schritt-typen.md); sie landet dann als Bild im PDF. Eine digitale **Signatur** im kryptografischen Sinn ist ausdrücklich **nicht** gemeint und wäre eine eigene Phase. - [x] **Wird das PDF gespeichert oder bei jedem Abruf erzeugt?** Empfehlung: **bei jedem Abruf erzeugt**, nicht gespeichert. Ein gespeichertes PDF ist eine zweite Wahrheit neben dem Lauf; wird eine Notiz später berichtigt, stimmt es nicht mehr. Für den Fall „wir brauchen das Blatt von damals“ gibt es das Archiv, das den Lauf unveränderlich hält. **`{{generiertes_passwort}}` erscheint auch hier nicht** — die Druckansicht zeigt `[Passwort – nicht gespeichert]`, und das PDF übernimmt das. ## Aufgaben - [x] `GET /api/laeufe/[id]/protokoll.pdf` — Route Handler, prüft sein Recht **selbst** (`tests/zugang.test.ts` erzwingt das seit #038) - [x] Erzeugung über Chromium, gegen die eigene Druckansicht; eine Seitenvorlage mit Kopf (Kunde, Lauf, Vorlage, Version), Inhalt und Fuß (Bearbeiter, Freigeber aus [#040](040-vier-augen-freigabe.md), Unterschriftsfeld) - [x] Ein **Chromium-Vorrat** im Prozess: ihn je Anfrage zu starten kostet Sekunden. Eine Instanz, die nach Leerlauf schließt — und eine Obergrenze gleichzeitiger Erzeugungen, wie `SSE_MAX_STROEME` in #033 - [x] Knopf „Protokoll als PDF“ an Lauf und Archiv - [x] `Dockerfile` und `deploy/install.sh` um Chromium ergänzen, **mit gemessener Bildgröße** im Changelog — eine Ergänzung am Image, die niemand bemerkt, ist eine böse Überraschung beim nächsten Rollout - [x] `docs/betrieb/` sagt, was die Erzeugung braucht und was passiert, wenn Chromium fehlt: **eine Meldung, kein stilles leeres PDF** - [x] Anleitung Kapitel 02 und 10 (Archiv) ## Wie entschieden wurde **Chromium gegen die eigene Druckansicht**, wie empfohlen — aber über `playwright-core` als echte Abhängigkeit, nicht über `@playwright/test`: das ist ein Entwicklungspaket und hat im Laufzeitbild nichts verloren. Gedruckt wird `/drucken/lauf/[id]` über `127.0.0.1`, mit dem Sitzungscookie des Anfragenden; damit gilt für das PDF dieselbe Rechte- und Mandantenprüfung wie für die Seite, und es gibt genau eine Vorlage für Papier und Datei. **Chromium ist optional und nicht im Standardbild.** Die gemessene Zahl war das Argument: das Laufzeitbild wächst von **370 MB auf 1,52 GB**, Alpines `chromium` kostet allein 1,13 GB. Das Bild baut mit `--build-arg MIT_PDF=1`, nativ installiert `deploy/install.sh --mit-pdf`. Ohne Chromium erscheint der Knopf gar nicht erst, und der Endpunkt antwortet `503` mit einer Meldung, die auf `docs/betrieb/pdf.md` verweist — kein stilles leeres PDF. Die Schätzung war damals auf „+328 MB“ hochgerechnet. Das war das `.apk`-Paket, nicht das Bild; gemessen ist es das Dreieinhalbfache. Deshalb steht die Zahl jetzt an drei Stellen gemessen da. **Nicht gespeichert, bei jedem Abruf erzeugt** — wie empfohlen. Das Unterschriftsfeld ist eine Linie auf Papier; die Unterschrift mit dem Finger bleibt [#042](042-weitere-schritt-typen.md). ## Akzeptanzkriterien - [x] Test: das PDF enthält Titel, Vorlage mit Version, alle geltenden Schritte mit Zustand, Notizen und Kommentare — geprüft am extrahierten Text, nicht am Vorhandensein der Datei - [x] Test: es enthält **kein** erzeugtes Passwort, über alle Schritt-Typen - [x] Test: ein Lauf eines fremden Kunden ist über die Adresse nicht abrufbar (wie #032 nach #036) - [x] Test: ohne Recht `401`, mit falschem Kunden `404` - [x] Test: fehlt Chromium, kommt eine Meldung mit Hinweis auf die Betriebsdoku — kein leeres PDF - [x] Test: zwei gleichzeitige Erzeugungen laufen, die dritte wartet oder wird abgewiesen (die Obergrenze gilt) - [x] Ein Blatt ist ausgedruckt und gegengesehen worden — das ist eine Abnahme von Hand und steht als solche im Devlog