PDF-Export: Original-Antrag am Ende anhängen #9

Closed
opened 2026-04-07 22:50:56 +02:00 by tobias · 1 comment
Owner

Idee

Beim Export der GWÖ-Report-PDF soll das Original-Antrags-PDF am Ende angehängt werden, sodass Auswertung und Quelldokument in einer Datei zusammen vorliegen.

Skizze

  • webapp/app/report.py::generate_pdf_report() erweitern
  • pymupdf (fitz, schon Dependency) kann zwei PDFs mergen via doc.insert_pdf(other_doc)
  • Quelle für das Antrags-PDF:
    • Bei DB-Anträgen mit link-Feld (PDF-URL): per httpx herunterladen, aus den Bytes ein zweites fitz-Dokument bauen, anhängen
    • Bei manuell hochgeladenen Anträgen: optional eine Kopie des Uploads in data/ oder reports/ ablegen, sodass sie hier referenziert werden kann
  • Edge-Case: Antrag-PDF nicht erreichbar (404, Timeout) → Report trotzdem ausliefern, mit Hinweis-Seite „Original-PDF nicht verfügbar"
  • Optional: Trennseite mit Überschrift „Original-Antrag" zwischen Report und angehängtem PDF

Akzeptanzkriterien

  • PDF-Download eines NRW- oder LSA-Antrags enthält am Ende den vollständigen Originalantrag
  • Bei nicht erreichbarem Original-PDF: Report wird trotzdem ausgeliefert, mit Hinweis-Seite
  • Manuell hochgeladene Anträge funktionieren ebenfalls (Kopie wird gespeichert oder die Original-Datei aus Upload-Cache referenziert)
  • Smoke-Test live
## Idee Beim Export der GWÖ-Report-PDF soll das **Original-Antrags-PDF am Ende angehängt** werden, sodass Auswertung und Quelldokument in einer Datei zusammen vorliegen. ## Skizze - `webapp/app/report.py::generate_pdf_report()` erweitern - `pymupdf` (`fitz`, schon Dependency) kann zwei PDFs mergen via `doc.insert_pdf(other_doc)` - Quelle für das Antrags-PDF: - **Bei DB-Anträgen mit `link`-Feld** (PDF-URL): per `httpx` herunterladen, aus den Bytes ein zweites `fitz`-Dokument bauen, anhängen - **Bei manuell hochgeladenen Anträgen**: optional eine Kopie des Uploads in `data/` oder `reports/` ablegen, sodass sie hier referenziert werden kann - **Edge-Case**: Antrag-PDF nicht erreichbar (404, Timeout) → Report trotzdem ausliefern, mit Hinweis-Seite „Original-PDF nicht verfügbar" - **Optional**: Trennseite mit Überschrift „Original-Antrag" zwischen Report und angehängtem PDF ## Akzeptanzkriterien - [ ] PDF-Download eines NRW- oder LSA-Antrags enthält am Ende den vollständigen Originalantrag - [ ] Bei nicht erreichbarem Original-PDF: Report wird trotzdem ausgeliefert, mit Hinweis-Seite - [ ] Manuell hochgeladene Anträge funktionieren ebenfalls (Kopie wird gespeichert oder die Original-Datei aus Upload-Cache referenziert) - [ ] Smoke-Test live
Author
Owner

Erledigt

Commit 80e16df deployed auf https://gwoe.toppyr.de.

Live-Verifikation gegen Drucksache 8/6645 (Untrending Frauenhass, BÜNDNIS 90/DIE GRÜNEN LSA):

/api/assessment/pdf?drucksache=8/6645 → 160 KB (vorher ~33 KB)
Pages: 8
  page 0: GEMEINWOHL-ÖKONOMIE | ANTRAGSBEWERTUNG  Untrending Frauenhass…
  page 1: 1 2 3 4 5  D: Bürger:innen ++ ++ ++ ++  …  Legende
  page 2: feministische Bildung als systemische Demokratiebildung
  page 3: Vorschlag: Beratungsstrukturen mit festen, kommunal verankerten…
  page 4: Original-Antrag  Drucksache 8/6645  Untrending Frauenhass…  (Trennseite)
  page 5: (Ausgegeben am 24.02.2026) 24.02.2026 Drucksache 8/6645 öffentlich Antrag — Fraktion BÜNDNIS 90/DIE GRÜNEN…
  page 6: 2 Der Landtag fordert die Landesregierung auf, 1. in den Lehrplänen…
  page 7: 3 hältnisse als gesellschaftlich geprägt zu verstehen, Stereotype kritisch zu pr…

Also: 4 Report-Seiten + 1 Trennseite + 3 Seiten Originaldokument, alles in einer Datei.

Edge-Cases verifiziert:

  • Synthetischer 404-Link → 5 Seiten gesamt (4 Report + 1 Trennseite mit Original-PDF konnte nicht angehängt werden. Grund: HTTP 404 und Quell-URL), kein Crash
  • Kein link in der DB (z.B. manuell gepasteter Text): silent skip, Report wie gewohnt 4 Seiten

Implementierung: app/report.py::_append_original_antrag(). Best-effort: Download via httpx, PDF-Magic-Bytes-Check, Insert via PyMuPDF doc.insert_pdf(), atomic-replace via Sibling-.tmp-Datei (PyMuPDF kann nicht non-incremental in dieselbe Datei zurückschreiben). Trennseite via PyMuPDF-Text-API direkt — kein zweiter WeasyPrint-Roundtrip nötig.

## Erledigt Commit `80e16df` deployed auf https://gwoe.toppyr.de. **Live-Verifikation gegen Drucksache 8/6645** (Untrending Frauenhass, BÜNDNIS 90/DIE GRÜNEN LSA): ``` /api/assessment/pdf?drucksache=8/6645 → 160 KB (vorher ~33 KB) Pages: 8 page 0: GEMEINWOHL-ÖKONOMIE | ANTRAGSBEWERTUNG Untrending Frauenhass… page 1: 1 2 3 4 5 D: Bürger:innen ++ ++ ++ ++ … Legende page 2: feministische Bildung als systemische Demokratiebildung page 3: Vorschlag: Beratungsstrukturen mit festen, kommunal verankerten… page 4: Original-Antrag Drucksache 8/6645 Untrending Frauenhass… (Trennseite) page 5: (Ausgegeben am 24.02.2026) 24.02.2026 Drucksache 8/6645 öffentlich Antrag — Fraktion BÜNDNIS 90/DIE GRÜNEN… page 6: 2 Der Landtag fordert die Landesregierung auf, 1. in den Lehrplänen… page 7: 3 hältnisse als gesellschaftlich geprägt zu verstehen, Stereotype kritisch zu pr… ``` Also: 4 Report-Seiten + 1 Trennseite + 3 Seiten Originaldokument, alles in einer Datei. **Edge-Cases verifiziert:** - Synthetischer 404-Link → 5 Seiten gesamt (4 Report + 1 Trennseite mit `Original-PDF konnte nicht angehängt werden. Grund: HTTP 404` und Quell-URL), kein Crash - Kein `link` in der DB (z.B. manuell gepasteter Text): silent skip, Report wie gewohnt 4 Seiten **Implementierung:** `app/report.py::_append_original_antrag()`. Best-effort: Download via httpx, PDF-Magic-Bytes-Check, Insert via PyMuPDF `doc.insert_pdf()`, atomic-replace via Sibling-`.tmp`-Datei (PyMuPDF kann nicht non-incremental in dieselbe Datei zurückschreiben). Trennseite via PyMuPDF-Text-API direkt — kein zweiter WeasyPrint-Roundtrip nötig.
Sign in to join this conversation.
No description provided.