# Spec 378 Constitution Renderer Gate Review Date: 2026-06-14 Review type: renderer/package/runtime governance gate. Decision: renderer gate approved with controls; implementation may proceed after a scoped runtime config task. ## Repo Safety - Branch: `378-management-report-pdf-v1` - HEAD: `f1eadadf docs: add spec 377 post-productization browser reaudit closeout gate (#448)` - Dirty files before governance update: untracked `specs/378-management-report-pdf-v1/` - Staged files before governance update: none observed - Untracked files before governance update: `specs/378-management-report-pdf-v1/` - `git diff --name-only` before governance update: no tracked-file diff - Spec 378 files already changed before governance update: yes, active Spec 378 directory existed as untracked content - Other specs affected before governance update: none observed ## Runtime Surface Read - `docker-compose.yml`: present at repo root; contains `laravel.test`, `queue`, `pgsql`, `redis`, and a `sail` bridge network. - `apps/platform/docker-compose.yml`: not present. - `apps/platform/Dockerfile`: not present. - `apps/platform/docker/`: not present. - `apps/platform/composer.json`: no runtime PDF renderer package. - `apps/platform/package.json`: `playwright` appears under `devDependencies`; no production PDF runtime is declared. ## Gate State Result: gate can be updated with approved renderer. - Previous gate stop was valid. - Missing renderer evidence was documented in Spec 378. - Downstream implementation tasks remain open. - No tracked app-code, runtime compose, Composer, npm, StoredReport, OperationRun, UI, or template implementation was started. - Gotenberg is not currently deployed or configured in the repo. - This review approves the renderer architecture only; runtime config remains pending. ## Constitution Alignment | Area | Result | Review | |---|---|---| | Package Governance | PASS with controls | Gotenberg is a runtime service, not a Composer/npm package. The decision is documented in Spec 378 artifacts and `docs/package-governance.md`, with pinning, security, maintenance, and review-date controls. | | Security | PASS with controls | The approved model keeps the browser runtime out of Laravel containers, internal-only, no public port, server-generated HTML only, no signed URLs/secrets in HTML, outbound access restricted, and safe error mapping required. | | RBAC / Isolation | PASS | Renderer selection does not weaken RBAC. Generation/download still require workspace, tenant, managed-environment, and capability checks before renderer invocation or artifact return. | | Auditability | PASS | The renderer gateway must pass correlation/OperationRun metadata and map success/failure into OperationRun and audit records without raw renderer errors. | | Proportionality / BLOAT | PASS | A separate internal renderer service plus narrow Laravel gateway is justified by customer-facing PDF artifact quality, queue failure isolation, and avoiding browser binaries in the app container. It is narrower than a generic report engine. | | No Premature Abstraction | PASS with controls | Only `PdfRenderingGateway` / `PdfRendererClient` is approved as shared infrastructure. Domain generators remain separate; no report center, billing framework, or generic document engine is approved. | | UI-COV | PASS | Renderer governance changes no reachable UI by itself. Spec 378 still records that implementation will change report/action/download surfaces and must update or close out UI coverage then. | | Test Governance | PASS | This docs-only gate requires no PHP tests. Future runtime implementation must cover gateway, failure mapping, authorization-before-render, artifact storage, OperationRun, audit, and content smoke. | | Operational Readiness | PASS with controls | Docker/Dokploy fit is strong, but runtime service config, health check, env/config, timeouts, request limits, logs, and image pinning remain required implementation tasks. | | Billing / Invoice Boundary | PASS | Approval is explicitly limited to report-style PDF rendering. BillingDocument, invoice numbering, tax/e-invoice XML, and invoice archival remain separate future domains. | ## SaaS Invoice Future Boundary PDF Rendering Infrastructure is shared. Report Domain is separate. Billing / Invoice Domain is separate. E-Invoice XML Compliance is separate. Target architecture: ```text Shared PDF Rendering Infrastructure -> Gotenberg / Chromium Renderer -> PdfRenderingGateway -> Storage -> Audit -> OperationRun Domain-specific generators -> ManagementReportGenerator -> EvidenceReportGenerator -> InvoiceDocumentGenerator -> CreditNoteDocumentGenerator ``` Identity boundaries: - `StoredReport` is not `BillingDocument`. - `Report ID` is not `Invoice Number`. - `OperationRun ID` is not `Invoice Number`. - `StoredReport ID` is not `Invoice Number`. Future billing specs must define these separately before implementation: - `BillingDocument` - `InvoiceNumberAllocator` - `InvoiceTaxCalculator` - `EInvoiceXmlBuilder` - `ZugferdFacturXBuilder` - `XRechnungBuilder` - `InvoicePdfRenderer via PdfRenderingGateway` - `BillingDocumentArchive` - `BillingAuditTrail` ## Final Gate Result renderer gate approved - implementation may proceed after runtime config task. Required next scoped task before report runtime implementation: - Add and validate Gotenberg runtime service configuration for Sail/Dokploy with the controls from `spec378-gotenberg-security-controls.md`. - Add config keys for renderer base URL, timeout, body/output size limits, and disabled/unavailable behavior. - Implement `PdfRenderingGateway` / `PdfRendererClient` only after the runtime config task is scoped. - Do not implement management report payload, StoredReport integration, OperationRun integration, UI action, PDF templates, or report generation before that runtime path exists.