PDF export via Gotenberg #67
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#67
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
PDF export for reading/sharing, rendered server-side for consistent results (ADR 0009).
Scope
Add Gotenberg to the Compose stack (internal, pinned, healthcheck); PDF export job: render page via the public-HTML renderer (#56) in an export variant (no chrome, pond fonts inlined as base64 @font-face, print CSS: page margins, page numbers, title header), send to Gotenberg's Chromium route, store result for download; wire the page export menu's PDF entry with job progress.
Acceptance criteria
Technical notes
Dependencies
Depends on #56, #62, #66.
Size: ~1.5 days
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.Done in
8a68ef6. Pipeline fully green (all 7 contexts); the new Gotenberg sidecar is provisioned on both stages and PDF export is verified live.What shipped (ADR 0009/0016)
gotenberg/gotenberg:8in the Compose stack (internal, pinned, healthcheck); apiGOTENBERG_URL; arendererreadyz check at warning-level (mirrors the converter), so PDF export degrades gracefully when Gotenberg is down without failing readyz.buildPdfHtml): a self-contained document (no app chrome) — the page content with images inlined asdata:URIs, the pond's fonts inlined as base64@font-face(read from the catalog now baked into the api image) + applied via CSS variables, print CSS (A4, page-break rules, a title header), and page numbers from Gotenberg's footer.POST /pages/:id/export {format: pdf}(read-permission gated) builds the HTML and enqueues anexport_pdfjob on the #62 queue with the HTML as input; the worker branchesto === 'pdf'to theGotenbergRenderer(html → pdf) instead of pandoc, retrying an unreachable sidecar and failing a refused render (renderer_unavailable/render_failed, de+en). The client polls and downloadsGET /jobs/:id/result.Acceptance criteria
application/pdf(53 KB) with the pond font embedded (FontFile) and its image rendered.TODO(#79)inpdf-html.ts(placeholder acceptable now, per the AC).@RequiresPagePermission('read'); the resulting job is owner-scoped (a foreign/unknown id is 404, #62).render_failedjob failure (DB test with an injected failing renderer) + the warning-levelrendererreadyz check.Fonts in the api image: the api Dockerfile now bakes the font catalog in (
build-fonts.mjswithFONTS_OUT) so the exporter can inline a pond's WOFF2; a missing file falls back to the system stack.Tests:
export.service.dbPDF cases (HTML carries the title, the font CSS variable, and the inlined image; renderer-down →render_failed) + e2e PDF export (self-skips without a Gotenberg sidecar, like the.docxcase). Verified locally against real Gotenberg (valid PDF, font embedded) and live on Int.Stage provisioning (new sidecar, pattern from #62/#63): the repo Compose gained the
gotenbergservice; the byte-identical stage Composes on the VPS were replaced (backups*.bak-pre67) anddocker compose pull gotenberg && up -dran on both — Test + Int now reportrenderer: ok. The api degrades towarnwithout it, so the CD deploy was never blocked.Next: #68 (GDPR data export), #69 (QA fidelity gate).