Added PDF generation service for management reports as per Spec 378, including Gotenberg integration in docker-compose and configuration updates. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #449
84 lines
8.5 KiB
Markdown
84 lines
8.5 KiB
Markdown
# Spec 378 PDF Renderer Decision Matrix
|
|
|
|
Date: 2026-06-14
|
|
Scope: Management Report PDF v1 renderer/runtime governance only.
|
|
Outcome: approved with controls for Gotenberg 8 Chromium as an internal Docker service.
|
|
|
|
## Repo Safety Baseline
|
|
|
|
- Branch: `378-management-report-pdf-v1`
|
|
- HEAD: `f1eadadf docs: add spec 377 post-productization browser reaudit closeout gate (#448)`
|
|
- `git status --short --branch`: branch `378-management-report-pdf-v1`; untracked `specs/378-management-report-pdf-v1/`
|
|
- `git diff --name-only`: no tracked-file diff before this governance update
|
|
- Staged files before this governance update: none observed
|
|
- Dirty/untracked files before this governance update: `specs/378-management-report-pdf-v1/`
|
|
- Spec 378 files already changed before this governance update: present as an untracked active spec directory
|
|
- Other specs affected before this governance update: none observed
|
|
- Existing runtime PDF renderer in `apps/platform/composer.json`: none
|
|
- Existing PDF runtime in `apps/platform/package.json`: none; `playwright` is listed only under `devDependencies`
|
|
- Docker infrastructure: root `docker-compose.yml` exists with `laravel.test`, `queue`, `pgsql`, and `redis`; `apps/platform/docker-compose.yml`, `apps/platform/Dockerfile`, and `apps/platform/docker/` are not present
|
|
|
|
## Gate Verification
|
|
|
|
Result: gate can be updated with approved renderer.
|
|
|
|
- Spec 378 was correctly blocked at the renderer/package gate.
|
|
- The missing approved production-safe PDF renderer was documented in `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md`.
|
|
- Downstream implementation tasks remain open.
|
|
- No runtime implementation was started in tracked app/runtime files.
|
|
- Playwright is dev/browser tooling only in `apps/platform/package.json`.
|
|
- No Composer PDF renderer is present in `apps/platform/composer.json`.
|
|
- Root Docker Compose already has an internal service network, so an internal renderer service can fit the deployment model, but no Gotenberg service exists yet.
|
|
|
|
## Decision Matrix
|
|
|
|
| Candidate | Runtime model | Deployment impact | Security posture | Maintenance posture | Layout quality | Laravel integration complexity | Docker/Dokploy fit | License/commercial concern | Enterprise suitability | Decision | Rationale |
|
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Gotenberg 8 Chromium internal service | Separate Docker HTTP service using Chromium HTML-to-PDF route; Laravel calls it through a narrow `PdfRenderingGateway` / `PdfRendererClient` | Requires adding a pinned internal service, health check, env config, timeouts, request/output limits, and Dokploy service wiring | Strongest option when kept internal-only with no public port, no user-provided URL rendering, outbound restrictions, server-generated HTML, and structured failure mapping | Operationally patchable as a service image; avoids embedding Chrome/Node in the app container; image must be pinned to an explicit 8.x Chromium tag or digest | High for modern HTML/CSS report layouts, page breaks, headers/footers, and branded management reports | Moderate; HTTP client and gateway contract are needed, but no Composer PDF package or browser binary in Laravel | Strong; repo is Sail/Docker/Dokploy-oriented and already uses a compose network | Open-source service; no per-document commercial licensing identified for report rendering; production image/version governance still required | Best fit for enterprise SaaS report PDFs under controls | approved with controls | Matches Docker-first deployment, isolates browser runtime from Laravel, supports Chromium-quality rendering, and can be governed with network, timeout, egress, and artifact controls. |
|
|
| Spatie Browsershot / Spatie Laravel PDF with Browsershot | Laravel package invokes Puppeteer/Chrome through Node | Adds Composer package plus Node/Puppeteer/Chrome runtime or custom image changes near the app container | Larger app-container attack/ops surface; browser process ownership, temp files, sandboxing, and binary path management move into Laravel runtime | Actively used but coupled to Node/Puppeteer/Chrome versions and host dependencies | High Chromium quality | Low at code level but high at runtime; needs Node 22+, Puppeteer, Chrome, binary paths | Weaker for this repo because it pulls browser runtime into app/queue containers | MIT-style package ecosystem, but operational dependency surface is larger | Good for smaller apps; not preferred here | rejected | It solves layout quality but violates the preferred isolation boundary: no direct Chromium/Node/browser runtime in Laravel app or queue containers for v1. |
|
|
| dompdf / barryvdh/laravel-dompdf | Pure PHP package inside Laravel | Simple Composer install and no external service | Smaller infrastructure surface, but renderer runs in app process and remote resource/file options require careful hardening | Mature PHP package, but HTML/CSS engine is intentionally limited | Not sufficient for modern enterprise report layouts; limited CSS, no JavaScript, weak repeating header/footer support | Low | Good deployment simplicity | LGPL/transitive license review required; no commercial blocker | Suitable for simple PDFs only | rejected | Simplicity is outweighed by CSS/layout limitations for branded management reports with reliable page breaks, tables, and headers/footers. |
|
|
| wkhtmltopdf / Snappy | Native binary or PHP wrapper around wkhtmltopdf using Qt WebKit | Requires binary installation, container image changes, and runtime process management | Higher maintenance and security risk due to old browser engine lineage | Poor; upstream wkhtmltopdf repository is archived/read-only and organization is marked unmaintained | Historically useful but outdated rendering engine | Moderate; wrappers exist but depend on external binary | Weak for new platform work | LGPL-style tooling; main issue is maintenance, not license | Not acceptable for new enterprise SaaS renderer | rejected | The upstream status and Qt WebKit legacy make it a poor default for a new security-sensitive SaaS runtime. |
|
|
| PrinceXML | Commercial print/Paged Media engine | Requires licensed binary/service integration and procurement | Strong if licensed and isolated correctly | Strong commercial vendor posture | Highest print/Paged Media quality | Moderate; custom client/integration required | Good if packaged as service or sidecar | Commercial/OEM license and cost review required | Excellent for premium publishing/compliance documents | premium future option | Overkill for v1 management reports, but worth revisiting for premium print workflows or legally constrained document classes if licensing is approved. |
|
|
|
|
## Selected Renderer
|
|
|
|
Decision: approved with controls.
|
|
|
|
Approved renderer family: Gotenberg 8 Chromium internal PDF rendering service.
|
|
|
|
Production pinning rule: use an explicit Gotenberg 8 Chromium image tag or immutable digest during the runtime config task. Do not use `latest`. Do not treat the unpinned major tag as sufficient for production promotion unless the deployment governance explicitly accepts that risk.
|
|
|
|
Approved scope:
|
|
|
|
- Internal PDF rendering infrastructure for TenantPilot report-style documents.
|
|
- Server-generated HTML-to-PDF using the Chromium conversion route.
|
|
- Use by Spec 378 Management Report PDF v1 through a Laravel gateway/client abstraction.
|
|
|
|
Not approved:
|
|
|
|
- Legal invoice generation.
|
|
- German B2B e-invoicing.
|
|
- XRechnung, ZUGFeRD, or Factur-X compliance.
|
|
- GoBD archival.
|
|
- Tax calculation.
|
|
- Invoice numbering.
|
|
- Billing compliance.
|
|
- Public renderer exposure.
|
|
- User-supplied URL-to-PDF rendering in v1.
|
|
- Direct Node/Chromium/browser runtime inside the Laravel app or queue containers.
|
|
|
|
## Consulted Primary Sources
|
|
|
|
- Gotenberg installation and image variants: https://gotenberg.dev/docs/getting-started/installation
|
|
- Gotenberg Chromium HTML-to-PDF route: https://gotenberg.dev/docs/convert-with-chromium/convert-html-to-pdf
|
|
- Gotenberg configuration flags: https://gotenberg.dev/docs/configuration
|
|
- Gotenberg outbound URL filtering: https://gotenberg.dev/docs/outbound-url-filtering
|
|
- Gotenberg health check: https://gotenberg.dev/docs/system/get-health-check
|
|
- Spatie Browsershot requirements: https://spatie.be/docs/browsershot/v4/requirements
|
|
- Dompdf README: https://github.com/dompdf/dompdf
|
|
- Spatie Laravel PDF DOMPDF driver limitations: https://spatie.be/docs/laravel-pdf/v2/drivers/using-the-dompdf-driver
|
|
- wkhtmltopdf status: https://wkhtmltopdf.org/status.html
|
|
- wkhtmltopdf archived repository evidence: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/5160
|
|
- Snappy wrapper dependency: https://github.com/KnpLabs/snappy/
|
|
- PrinceXML product and licensing: https://www.princexml.com/ and https://www.princexml.com/purchase/
|