internal/documentapi: neue Backend-Voraussetzung, die DOC-01/DOC-04 noch
nicht hatten - GET /documents/{id}/content liefert den entschluesselten
Originalinhalt der aktuellen Revision, Content-Type ausschliesslich ueber
Magic-Bytes, Content-Disposition: inline (kein Download-Zwang), volle
HTTP-Range-Unterstuetzung ueber http.ServeContent (Standardbibliothek) -
darueber laedt PDF.js grosse Dokumente automatisch seitenweise nach.
web/pdf-viewer: Next.js/React/TypeScript, PDF.js ausschliesslich auf
Canvas gerendert (kein iframe, siehe "Bekannte Fehler vermeiden"). Worker
laeuft aus public/pdf.worker.min.mjs (npm run copy-pdf-worker, Teil von
predev/prebuild) - bewusst NICHT ueber ein externes CDN, damit die
Anwendung vollstaendig offline/lokal lauffaehig bleibt. lib/viewerState.ts
kapselt Seiten-/Zoom-Navigation und Tastaturbedienung als reine,
DOM-unabhaengige Funktionen (Akzeptanzkriterium 2), Suche nutzt PDF.js'
eigene Textextraktion.
Pruefungen:
1. 300-seitiges PDF oeffnet im Zeitbudget - echter pdfjs-dist-Ladetest
gegen den echten Backend-Dienst: 247ms (Budget 5000ms)
2. Viewer per Tastatur bedienbar - 15 Vitest-Tests fuer Pfeiltasten/Zoom/
Suche-Fokus, inkl. Ignorieren waehrend im Suchfeld getippt wird
3. Speicherverbrauch im Browser - OFFEN, kein Headless-Browser in dieser
Umgebung verfuegbar (gleiche Einschraenkung wie bei ANA-02)
SHL-01 (Core-Board, eigener Branch-Strang mit gemeinsamer Basis) sauber
gemergt - kein Dateiueberschneidungs-Konflikt (web/shl vs. dms/).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.0 KiB
DOC-05 – Prüfprotokoll: PDF-Viewer-Komponente
Stand: 2026-09-17. Testhost 192.168.1.131.
Backend-Voraussetzung: internal/documentapi (neu für diese Kachel)
DOC-01/DOC-04 hatten noch keinen HTTP-Endpunkt, über den ein Viewer den Originalinhalt beziehen
kann. GET /documents/{id}/content liefert den entschlüsselten Inhalt der aktuellen Revision,
Content-Type ausschließlich über Magic-Bytes des entschlüsselten Inhalts (dieselbe Disziplin wie
DOC-04), Content-Disposition: inline (kein Download-Zwang), volle HTTP-Range-Unterstützung über
http.ServeContent (Standardbibliothek).
go test ./internal/documentapi/... -v — 3/3 PASS.
Grundsatzentscheidung: Canvas statt iframe, PDF.js im Web-Worker, Worker lokal ausgeliefert
Kein iframe/HTML-Rendering von Fremdinhalt — Rendering ausschließlich auf <canvas> (siehe
"Bekannte Fehler vermeiden"). PDF.js' eigener Worker läuft als eigenständiges Skript, geladen aus
public/pdf.worker.min.mjs (per npm run copy-pdf-worker, Teil von predev/prebuild) —
bewusst NICHT über ein externes CDN, damit die Anwendung vollständig offline/lokal
funktionsfähig bleibt. Direktes Bundling über Webpack scheiterte, weil der bereits minifizierte
ESM-Worker von Terser kein zweites Mal minifiziert werden kann (import/export außerhalb von
Modul-Code) — als statische, unverarbeitete Datei aus public/ umgangen.
Prüfung 1: 300-seitiges PDF öffnet im Zeitbudget
Echtes, synthetisch erzeugtes 300-Seiten-PDF über documentapi ausgeliefert, mit dem echten
pdfjs-dist-Paket (nicht simuliert) via getDocument() geladen: 247 ms bis numPages === 300
vorlag (Zeitbudget 5000 ms deutlich unterschritten). Test lief gegen den echten Backend-Dienst mit
echter Entschlüsselung, nicht gegen eine statische Datei.
Prüfung 2: Viewer per Tastatur bedienbar
lib/viewerState.ts (reine, DOM-unabhängige Zustandslogik) + npm test — 15/15 Vitest-Tests PASS:
Pfeiltasten (Seite vor/zurück, an den Rändern geklemmt), +/- (Zoom, an MIN_ZOOM/MAX_ZOOM
geklemmt), / (Suche fokussieren), Tastenkürzel werden ignoriert, während im Suchfeld getippt wird
(kein versehentliches Blättern beim Tippen eines Suchbegriffs mit +/-/Pfeiltasten im Text).
Prüfung 3: Speicherverbrauch im Browser bleibt stabil
Nicht automatisiert nachweisbar in dieser Umgebung — dafür fehlt ein echter Browser mit
Speicher-Profiling (kein Headless-Browser/keine Browser-Automatisierung hier verfügbar, gleiche
Einschränkung wie bereits bei ANA-02 dokumentiert). Strukturell durch den PDF.js-Standardpfad
adressiert: jede Seite wird einzeln gerendert (page.render), nicht das gesamte Dokument vorab
gerastert — PDF.js' eigene Page-Cache-/Cleanup-Mechanismen greifen unverändert. Diese Prüfung
bleibt offen, bis ein Zugriff auf eine echte Browser-Umgebung besteht.
Akzeptanzkriterien 1–3 (PDF ohne Download, Zoom/Blättern/Suche, seitenweises Nachladen)
- Ohne Download:
Content-Disposition: inlinereal imdocumentapi-Test verifiziert; PDF.js rendert direkt auf<canvas>, kein Browser-Download-Dialog. - Zoom/Blättern/Suche: UI-Bedienelemente in
PdfViewer.tsx, Logik inviewerState.tsgetestet; Suche nutzt PDF.js' eigene Textextraktion (getTextContent) über alle Seiten, springt zum ersten Treffer. - Seitenweises Nachladen:
documentapiunterstützt HTTP-Range (echter 206-Response im Test), PDF.js nutzt das für seinen eigenen inkrementellen Ladevorgang automatisch — kein eigener Chunking-Code nötig.
Build/Test-Ergebnis
npx tsc --noEmit— saubernpm test(Vitest) — 17/17 (2lib/api.test.ts+ 15lib/viewerState.test.ts)npm run build— erfolgreich (/viewer/[documentId]-Route, 2,01 kB / 89,4 kB First Load JS)- Go:
gofmt -l .,go build ./...,go vet ./...sauber;go test ./...— alle Pakete PASS (Alt-Tabellen-Kollision aus eigenem Smoketest-Seed bereinigt, keine echte Regression)
Offen
Prüfung 3 (Speicherverbrauch im Browser) bleibt mangels Browser-Zugriff unverifiziert.