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
34 KiB
Implementation Plan: Spec 378 - Management Report PDF v1
Branch: 378-management-report-pdf-v1 | Date: 2026-06-14 | Spec: specs/378-management-report-pdf-v1/spec.md
Input: Feature specification from specs/378-management-report-pdf-v1/spec.md
Summary
Implement the first durable customer-executive management PDF artifact over the existing Review Pack rendered-report family. The PDF must reuse the current ReviewPackRenderedReportController content/profile/disclosure truth where possible, produce a stored or canonically referenced private artifact, expose an authorized download path, and record OperationRun plus audit evidence for generation and download.
This is not a new report engine. It is the smallest PDF artifact productization slice after Specs 356, 357, and 366.
Technical Context
Language/Version: PHP 8.4.15, Laravel 12.52.0
Primary Dependencies: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, PostgreSQL, approved Gotenberg 8 Chromium internal PDF rendering service (Sail/local service and Laravel gateway configured; staging/Dokploy controls pending), existing Playwright dev/browser tooling only
Storage: PostgreSQL plus private Laravel storage disk for generated PDF artifacts if stored file output is implemented
Testing: Pest Unit, Feature/Filament action, and Browser/content smoke
Validation Lanes: fast-feedback, confidence, browser; PostgreSQL lane if migrations/indexes are introduced
Target Platform: Laravel Sail locally, Dokploy container deployment for staging/production
Project Type: Laravel monolith under apps/platform
Performance Goals: PDF generation is queue-safe and idempotent; report render/download stays DB/storage-only with no live provider calls
Constraints: no Graph calls during render/generation/download; Gotenberg 8 Chromium only through a Laravel gateway/client; no direct browser runtime in Laravel app/queue containers; no new runtime package without package governance; workspace/managed-environment isolation; profile/disclosure fail-closed; private artifact storage; no raw technical leakage
Scale/Scope: one customer-executive PDF profile, one current ready Review Pack source, one artifact output path, focused report/audit/OperationRun tests
Repo Truth Map
Current runtime/report foundations:
apps/platform/app/Http/Controllers/ReviewPackRenderedReportController.phpbuilds the existing rendered report state.apps/platform/resources/views/review-packs/rendered-report.blade.phprenders the management-style HTML/print report.apps/platform/app/Support/ReviewPacks/ReportProfileRegistry.phpdefinescustomer_executive, technical, internal, auditor, and framework profiles.apps/platform/app/Support/ReviewPacks/ReportDisclosurePolicy.phpevaluates mandatory disclosures and appendix/technical visibility.apps/platform/app/Support/ReviewPacks/ReportThemeResolver.phpexists from Spec 366 for management layout/theme derivation.apps/platform/app/Services/ReviewPackService.phpgenerates Review Packs, signed ZIP/download URLs, and signed rendered-report URLs.apps/platform/app/Http/Controllers/ReviewPackDownloadController.phpowns current signed ZIP download access/audit.apps/platform/app/Models/StoredReport.phpandStoredReportResourceprovide a narrow report substrate for permission posture and Entra admin roles.apps/platform/app/Services/OperationRunService.php,OperationRunType,OperationCatalog, and Operations UI/actionability specs provide run truth.docs/ui-ux-enterprise-audit/page-reports/ui-099-rendered-review-report.md,ui-042-review-pack-detail.md, andui-048-stored-report-detail.mdare the relevant UI coverage references.
Repo-truth constraints:
- No native PDF runtime dependency is present in
apps/platform/composer.json. apps/platform/package.jsonincludes Playwright for dev/browser tooling, not an approved production PDF runtime.- Gotenberg 8 Chromium is approved with controls as an internal Docker PDF rendering service. Root
docker-compose.yml, Laravel app config, andPdfRenderingGateway/PdfRendererClientnow exist for Sail/local; no Dokploy config file exists in the repo, sodocs/deployment-checklist.mdrecords the required staging/production controls. - Existing
StoredReporthas no file path, format, generated-by, status, source review, source review pack, or operation-run columns today. - Existing Review Pack ZIP contract must remain unchanged.
Renderer Governance Gate Result
- Gate result: approved with controls.
- Selected renderer: Gotenberg 8 Chromium internal service.
- Decision matrix:
specs/378-management-report-pdf-v1/artifacts/spec378-pdf-renderer-decision-matrix.md. - Security controls:
specs/378-management-report-pdf-v1/artifacts/spec378-gotenberg-security-controls.md. - Constitution review:
specs/378-management-report-pdf-v1/artifacts/spec378-constitution-renderer-gate-review.md. - Package governance:
docs/package-governance.mdrecords the approved runtime service scope and controls. - Runtime status: Sail/local renderer service, Laravel config, health check, timeout/size controls, and gateway/client safe result mapping are implemented. Staging/Dokploy runtime validation remains pending before management report PDF generation is enabled.
- Approved service boundary: Laravel must call Gotenberg through
PdfRenderingGateway/PdfRendererClient; production PDF rendering must not install or execute Chromium, Chrome, Puppeteer, Playwright, Node, or browser binaries in Laravel app/queue containers. - Invoice / billing boundary: this approval is not approval for legal invoice generation, German B2B e-invoicing, XRechnung, ZUGFeRD/Factur-X, GoBD archival, tax calculation, invoice numbering, or billing compliance.
PDF Rendering Layer Responsibilities
PdfRendererClient: low-level HTTP transport to the internal Gotenberg service. It owns multipart request assembly, timeout handling, HTTP status mapping, response byte validation, configured body/output size limits, and correlation id headers.PdfRenderingGateway: shared application boundary for server-generated HTML-to-PDF rendering. It accepts sanitized HTML/assets/render options and returns typed success/failure results suitable for OperationRun and audit mapping. It does not know management-report domain rules.ManagementReportPdfRenderer: Spec 378 domain adapter. It converts a prepared management report payload into sanitized HTML/assets, callsPdfRenderingGateway, and maps returned renderer outcomes into management-report generation flow. It does not own HTTP transport, storage persistence, OperationRun lifecycle, or billing/invoice semantics.
SaaS Invoice / Billing Boundary
The shared renderer is infrastructure only. Domain truth remains separate:
- PDF Rendering Infrastructure: shared.
- Report Domain: separate.
- Billing / Invoice Domain: separate.
- E-Invoice XML Compliance: separate.
Target separation:
Shared PDF Rendering Infrastructure
-> Gotenberg / Chromium Renderer
-> PdfRenderingGateway
-> Storage
-> Audit
-> OperationRun
Domain-specific generators
-> ManagementReportGenerator
-> EvidenceReportGenerator
-> InvoiceDocumentGenerator
-> CreditNoteDocumentGenerator
Identity boundaries:
StoredReportis notBillingDocument.Report IDis notInvoice Number.OperationRun IDis notInvoice Number.StoredReport IDis notInvoice Number.
Future billing specs must separately define BillingDocument, InvoiceNumberAllocator, InvoiceTaxCalculator, EInvoiceXmlBuilder, ZugferdFacturXBuilder, XRechnungBuilder, InvoicePdfRenderer via PdfRenderingGateway, BillingDocumentArchive, and BillingAuditTrail.
Candidate Selection Gate
- Selected candidate: Spec 378 - Management Report PDF v1.
- Source: Direct user-provided Spec 378 draft.
- Why selected: It is the natural bounded follow-up after Specs 356/357/366 made the rendered report, profile/disclosure policy, and management layout repo-real.
- Deferred alternatives: Technical/Auditor Evidence Report, Delivery Center, scheduled delivery, Customer Review Workspace polish, compliance-framework reports, AI summaries.
- Completed-spec guardrail: Specs 356, 357, 365, 366, 367, 372, and 377 are context only. They contain completed task markers, validation, close-out, or browser evidence and must not be rewritten.
- Result: PASS.
UI / Surface Guardrail Plan
- Guardrail scope: changed existing report/review artifact surfaces plus one possible new signed/authorized PDF download route.
- Affected routes/pages/actions/states/navigation/panel/provider surfaces:
ReviewPackRenderedReportController- rendered-report Blade template only if PDF payload generation requires shared partial/content extraction
EnvironmentReviewResourceand/orReviewPackResourcedetail/header actionsStoredReportResourceonly if generated management PDF artifacts appear there- optional new management PDF download route
- No-impact class, if applicable: N/A.
- Native vs custom classification summary: owner surfaces remain native Filament actions; report canvas inherits Spec 366's legitimate custom report/print surface; stored report remains native Filament read-only registry.
- Shared-family relevance: report viewer, artifact download, status/readiness messaging, OperationRun start/link UX, audit.
- State layers in scope: detail header action state, source report payload, PDF artifact state, signed/download URL, OperationRun status/outcome, stored report/artifact lifecycle.
- Audience modes in scope: customer/read-only for PDF content; operator-MSP for generation/download/action state; support-platform only through existing OperationRun/log diagnostics.
- Decision/diagnostic/raw hierarchy plan: decision-first PDF; diagnostics only in OperationRun/logs; raw/support payload absent from PDF.
- Raw/support gating plan: no raw JSON/provider payload/support context in customer-executive PDF. Any failure detail remains safe summary in UI and deeper diagnostics in logs/OperationRun.
- One-primary-action / duplicate-truth control: source detail surfaces expose at most one dominant next step: generate if no current PDF and ready, download/open if generated, view operation if running/failed. The generate action must require explicit Filament confirmation before artifact creation starts.
- Handling modes by drift class or surface: hard-stop-candidate for raw leakage, unauthorized artifact access, unapproved PDF runtime package, second report engine, or historical/expired pack impersonation.
- Repository-signal treatment: update UI-099/UI-042/UI-048 only if action hierarchy or artifact presentation materially changes; otherwise record a no-update rationale in close-out.
- Special surface test profiles: report-viewer, high-impact artifact generation action, customer-facing artifact.
- Required tests or manual smoke: Unit payload/disclosure/readiness; Feature authorization/artifact/audit/run/download; Browser/content smoke for generate/download/PDF text.
- Exception path and spread control: custom PDF/report layout remains bounded to the existing rendered-report family. No generic report framework.
- Active feature PR close-out entry: Guardrail + Smoke Coverage.
- UI/Productization coverage decision: reachable report/action surfaces change; implementation must update or explicitly close out coverage docs.
- Coverage artifacts to update: update route inventory when a new signed/authorized PDF route is added; update
ui-099-rendered-review-report.mdwhen rendered-report/PDF source content or customer-facing report presentation materially changes; updateui-042-review-pack-detail.mdwhen Review Pack detail owns the action/download state; updateui-048-stored-report-detail.mdwhen StoredReport registry/detail exposes the artifact; update design coverage matrix when action hierarchy, artifact state, or customer-facing surface classification materially changes. - No-impact rationale: N/A.
- Navigation / Filament provider-panel handling: no navigation or panel provider change planned. Laravel 12 Filament provider registration remains in
apps/platform/bootstrap/providers.php. - Screenshot or page-report need: yes, one bounded browser/content smoke with artifact evidence where local tooling permits it.
Shared Pattern & System Fit
- Cross-cutting feature marker: yes.
- Systems touched: Review Pack rendered report, report profiles, disclosure policy, Review Pack service, stored report/artifact storage, OperationRun, audit, localization, Filament owner-surface actions.
- Shared abstractions reused:
ReportProfileRegistryReportDisclosurePolicyReportThemeResolverReviewPackOutputReadinessReviewPackOutputResolutionGuidanceReviewPackService- current signed route/download patterns
OperationRunService- current audit logger/action ID pattern
- New abstraction introduced? why?: likely one bounded generation service and one renderer adapter. This is justified because PDF generation must not live in Blade/controller code and must isolate rendering/storage failures.
- Why the existing abstraction was sufficient or insufficient: Existing abstractions are sufficient for HTML report content, profile/disclosure, source current-pack validation, and signed URL generation. They are insufficient for private PDF artifact storage, generation idempotency, OperationRun result metadata, and download audit.
- Bounded deviation / spread control: new code must live under existing report/review-pack/support namespaces and target only management PDF v1. No profile CRUD, delivery system, report engine, or artifact lifecycle framework.
OperationRun UX Impact
- Touches OperationRun start/completion/link UX?: yes.
- Central contract reused:
OperationRunService,OperationRunLinks,OperationUxPresenter,OperationCatalog,OperationRunTypeif a new type is needed. - Delegated UX behaviors: queued toast/run link/artifact link/run-enqueued browser event/dedupe-or-blocked/start-failure messaging should use the shared OperationRun start UX path.
- Surface-owned behavior kept local: generation readiness explanation and source review/pack selection only.
- Queued DB-notification policy: no queued/running DB notification unless explicitly approved through the existing shared start UX contract.
- Terminal notification path: central lifecycle mechanism.
- Exception path: none expected. If implementation proposes synchronous no-run PDF generation, update spec/plan first and prove why OperationRun is unnecessary.
Provider Boundary & Portability Fit
- Shared provider/platform boundary touched?: yes, indirectly through report/evidence content.
- Provider-owned seams: existing review/evidence summaries that may include Microsoft-specific evidence labels.
- Platform-core seams: report artifact identity, profile, disclosure, provenance, OperationRun type, StoredReport/source descriptor.
- Neutral platform terms / contracts preserved: management report, profile, evidence readiness, limitation, managed environment, workspace, generated artifact, source review, source pack, operation.
- Retained provider-specific semantics and why: only existing profile-safe evidence/finding summaries from stored review/pack truth. No new provider lookup or provider-specific renderer branch.
- Bounded extraction or follow-up path: Technical/Auditor Evidence Report follow-up if provider-specific detailed appendix becomes necessary.
Constitution Check
GATE: Must pass before implementation. Re-check after design and before code merge.
- Inventory-first: PASS. Report consumes existing released review/Review Pack/evidence truth, not live provider state.
- Read/write separation: PASS. PDF generation mutates TenantPilot artifact storage only and requires explicit operator action, audit, and tests.
- Graph contract path: PASS. No Graph calls are allowed during render, generation, or download.
- Deterministic capabilities: PASS with task. Reuse existing capability registry paths or add a tested capability only after repo verification.
- RBAC-UX: REQUIRED. Non-member/wrong scope 404; member missing capability 403; server-side authorization required.
- Workspace isolation: REQUIRED. Artifact, source review, source pack, operation, and download all resolve workspace/environment scope.
- Destructive-like/high-impact action: REQUIRED. Generate PDF is high-impact artifact creation; it needs readiness gate, authorization, audit, and safe feedback. It is not destructive.
- Global search: PASS. No global-search enablement planned;
StoredReportResourceremains non-globally-searchable unless spec/plan are updated. - Run observability: REQUIRED. Preferred path creates/reuses an OperationRun for generation.
- OperationRun start UX: REQUIRED if queued generation is used; central UX path only.
- Ops-UX lifecycle: REQUIRED. Status/outcome transitions through
OperationRunService; summary counts flat numeric-only if used. - Data minimization: REQUIRED. No secrets/raw provider payloads/signed URLs in PDF/audit metadata.
- Test governance: REQUIRED. Unit/Feature/Browser lanes and fixture costs explicit.
- Proportionality: PASS with constraint. Generated PDF artifact truth and renderer/generation service solve current customer artifact gap.
- No premature abstraction: PASS with constraint. Generation/renderer/payload components are bounded to one report family and must not become a generic framework.
- Persisted truth: PASS. Generated PDF is durable artifact truth with provenance.
- Behavioral state: PASS if new status/reason keys change artifact visibility, OperationRun outcome, or download behavior.
- UI semantics: PASS. Directly map existing profile/readiness/disclosure into the PDF; no new taxonomy.
- Shared pattern first: PASS. Reuse report/profile/disclosure/OperationRun/audit paths first.
- Provider boundary: PASS. Stored summaries only; no provider runtime calls.
- V1 explicitness / few layers: PASS. One profile, one artifact, one source family.
- BLOAT-001: REQUIRED and covered in
spec.md. - Badge/Filament-native UI: PASS. Owner surfaces stay native Filament. Custom report canvas remains bounded to report/print artifact.
- UI-COV-001: REQUIRED. Coverage update/no-update rationale required.
Test Governance Check
- Test purpose / classification by changed surface:
- Unit: payload/readiness/disclosure/profile filtering and renderer adapter failure mapping.
- Feature: generation action, authorization, artifact storage, OperationRun outcomes, audit metadata, signed download, cross-scope denial.
- Filament/Livewire: owner-surface action visibility/disabled state where generation action lands.
- Browser/content smoke: generate/download path and PDF/text content proof.
- Affected validation lanes: fast-feedback, confidence, browser; pgsql if schema/index changes.
- Why this lane mix is the narrowest sufficient proof: Unit tests prove deterministic content and safety decisions; Feature tests prove server-side trust; Browser/content smoke proves the customer-facing artifact is usable and leakage-free.
- Narrowest proving command(s):
cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec378cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec378ManagementReportPdfSmokeTest.php --compactcd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec357cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec366cd apps/platform && ./vendor/bin/sail pint --dirtygit diff --check
- Fixture / helper / factory / seed / context cost risks: Reuse Spec357/Spec366 report fixtures and review-output seed command. Any new PDF fixture helpers must remain local to Spec378 unless reused by at least three current specs.
- Expensive defaults or shared helper growth introduced?: no by default.
- Heavy-family additions, promotions, or visibility changes: one explicit browser/content smoke only.
- Surface-class relief / special coverage rule: customer-facing document artifact requires special content/leakage smoke.
- Closing validation and reviewer handoff: reviewers verify package governance gate, no raw leakage, artifact/operation/audit agreement, scope-safe download, and no report-center/auditor scope.
- Budget / baseline / trend follow-up: record follow-up if PDF rendering adds material runtime to browser/confidence lanes or production queue requirements.
- Review-stop questions: renderer approved? artifact storage private? no raw leakage? no second report engine? OperationRun/audit consistent? correct 404/403?
- Escalation path: document-in-feature for approved renderer choice; follow-up-spec for delivery center, technical/auditor PDF, scheduled delivery, artifact lifecycle.
- Active feature PR close-out entry: Guardrail + Smoke Coverage.
- Why no dedicated follow-up spec is needed: The renderer/artifact choice belongs inside Spec 378 if it stays bounded; any broader delivery/auditor lifecycle work is explicitly deferred.
Implementation Approach
Phase 0 - Pre-Implementation Verification
- Re-read current report/runtime files listed in the Repo Truth Map.
- Renderer/package governance decision is complete: use Gotenberg 8 Chromium as an internal service with the controls in
artifacts/spec378-gotenberg-security-controls.md. - Confirm the runtime config task has added the pinned Gotenberg service and app config before any report generation implementation starts.
- Verify whether
StoredReportcan be extended narrowly to reference PDF artifacts. - Verify whether generation should land on Environment Review, Review Pack, or Customer Review Workspace first. Preferred v1 placement: Environment Review or Review Pack detail, because both already know source review/pack readiness.
Phase 0.5 - PDF Rendering Infrastructure Runtime Config
This phase is the first allowed implementation phase after the governance gate. It must be completed before management report payload, storage, OperationRun, UI action, PDF templates, or report-generation work.
Required future implementation work:
- Identify exact runtime config targets before editing: root
docker-compose.ymlfor Sail/local service wiring, the repo's Dokploy/deployment config or documentation location if present, and an explicitnot presentnote if no Dokploy config file exists in the repo. - Add a pinned Gotenberg 8 Chromium internal service to Sail/Dokploy runtime config.
- Keep the renderer internal-network only with no public port.
- Add renderer configuration for base URL, timeout, request body limit, asset size limit, PDF output size limit, queue/concurrency expectations, and disabled/unavailable behavior.
- Add health check verification using Gotenberg
/health. - Add failing gateway/client tests for health check, renderer unavailable, timeout, invalid response, size-limit rejection, and safe error mapping before completing
PdfRendererClient/PdfRenderingGateway. - Add
PdfRenderingGateway/PdfRendererClientas the only Laravel integration boundary after the gateway/client tests are in place. - Add request correlation using the OperationRun id or generation correlation id.
- Render server-generated HTML payloads only; do not use user-provided URL rendering.
- Apply the Gotenberg security controls before enabling report generation.
- Map renderer unavailable, timeout, invalid request, and output-size failures into safe internal result types for later OperationRun handling.
- Do not add Composer/npm PDF/browser packages unless this spec/plan and
docs/package-governance.mdare updated again.
Phase 1 - Payload and Readiness
Create a deterministic management-report payload from existing report truth:
- Source: current ready non-expired Review Pack and linked Environment Review.
- Profile:
customer_executive. - Disclosure:
ReportDisclosurePolicy::evaluate(...). - Sections: cover, executive summary, governance posture, decisions, top risks/findings, accepted risks, evidence readiness, limitations, next actions, provenance, method summary.
- Readiness: block or disable generation when source is missing/not ready/expired/not current/profile-blocked/disclosure-blocked/unauthorized.
- No direct database queries in Blade/PDF template.
Likely implementation surfaces:
apps/platform/app/Support/ReviewPacks/ManagementReportPayloadBuilder.php
apps/platform/app/Support/ReviewPacks/ManagementReportReadiness.php
apps/platform/app/Support/ReviewPacks/ManagementReportPdfRenderer.php
Names may differ if existing repo conventions suggest a better home.
Phase 2 - Artifact Storage
Preferred path:
- Use
StoredReportif it can represent the generated PDF artifact with a narrow migration/addition. - Add a management report type constant only if resource capability/report type maps are updated safely.
- Store private PDF file path/disk or artifact reference in the canonical substrate.
- Keep PDF payload/provenance in JSONB metadata without raw provider payloads.
- Do not create a new artifact table unless the spec/plan are updated and proportionality is re-approved.
Migration impact if needed:
- Safe incremental migration under
apps/platform/database/migrations. - Reversible where feasible.
- PostgreSQL lane if constraints/indexes/JSONB behavior are relevant.
- Staging validation required before production.
Phase 3 - OperationRun and Audit
Preferred path:
- Add or map canonical operation type
report.management.generateonly if no existing type fits. - Register the operation type in
OperationCatalog/related guards as required. - Use
OperationRunServicefor queued/running/completed/failed/blocked transitions. - Use safe
context.resultssummary with artifact id, source review/pack ids, profile, format, and file metadata. - Do not write adapter reconciliation metadata unless a reconciliation adapter actually runs.
- Record audit for generation and download with safe metadata.
Phase 4 - UI Actions and Download
Owner surface behavior:
- Show or enable
Generate management PDFonly when source is ready and actor is authorized. - If a current generated PDF exists for the same source/profile/fingerprint, prefer
Download management PDForOpen management PDFrather than duplicate generation. - When generation is running, show one clear operation link.
- When blocked/failed, show safe reason and operation link.
- Keep one primary action per focused area.
Download behavior:
- Use a signed route or server-authorized route with short-lived URL if signing is used.
- Re-resolve artifact/source scope server-side.
- Audit every successful download.
- Do not embed signed URLs in the PDF body.
Phase 5 - PDF Rendering
Renderer requirements:
- Use the approved Gotenberg 8 Chromium renderer path through
PdfRenderingGatewayonly. - Render from prepared payload, not live controller/global request state.
- No remote fonts/assets.
- Header/footer, page metadata, generated timestamp, and page numbers when supported.
- Clean table/section breaks; no huge raw tables.
- No technical appendix in
customer_executivePDF. - EN/DE labels through localization.
Phase 6 - Validation and Close-Out
- Run targeted Spec378 tests.
- Run Spec357/Spec366 regressions.
- Run Review Pack and Customer Review Workspace focused regressions as needed.
- Run browser/content smoke.
- Run Pint and
git diff --check. - Record Livewire v4 compliance, provider registration, global-search posture, destructive/high-impact action safety, asset strategy, tests, and deployment impact.
Data Model / Persistence Impact
Expected possibilities:
- No schema change: if current artifact storage can reference a PDF through existing fields. Unlikely based on current
StoredReport. - Narrow
StoredReportextension: likely path if addingreport_type=management_report_pdf, artifact file metadata, tenant scope, source environment, source review/pack, operation run, generated by, generated at, status, and profile. This must stay tenant-owned withworkspace_id, NOT NULLtenant_idwhere the table represents tenant-owned artifact truth, and sourcemanaged_environment_id. - New artifact entity: not approved by this plan. Stop and update spec/plan before implementation if this becomes necessary.
- Tenant-scope stop condition: if the selected substrate cannot represent constitution-compliant tenant scope, stop before persistence changes and update spec/plan; do not rely on
managed_environment_idalone for newly persisted tenant-owned artifact truth.
Retention/lifecycle:
- V1 may use existing stored report retention defaults or record "retained" semantics consistent with current StoredReportResource.
- Do not implement artifact lifecycle/hold/delete framework in this spec.
RBAC / Policy Implications
- Generation requires workspace membership, tenant entitlement, managed-environment entitlement, and an existing review/export/manage capability unless a new capability is proven necessary.
- Download requires view/download permission for the generated artifact and same workspace/tenant/environment scope.
- Server handlers must call Gate/Policy/capability checks; UI disabled/hidden state is not security.
- Non-member/wrong workspace/wrong tenant/wrong environment gets 404.
- Member without capability gets 403 after scope is established.
- StoredReportResource capability map must include any new management report type or explicitly keep it out of the registry if a separate download route owns access.
UI / Filament / Livewire Implications
- Filament v5 on Livewire 4.1.4 remains compliant; no Livewire v3 APIs.
- Panel providers remain registered in
apps/platform/bootstrap/providers.php; no panel changes planned. StoredReportResourceremains globally non-searchable unless spec/plan are updated. It has a View page today.- Generate action is high-impact artifact creation and must use
Action::make(...)->action(...),->requiresConfirmation(), server-side authorization, readiness gate, explicit notification, and audit before artifact creation starts. - No destructive action is added.
- No new Filament assets planned.
Audit / Observability / Evidence Implications
- Generation audit must include actor, workspace, managed environment, source review id, source review pack id, stored report/artifact id, operation run id, profile, format, status, generated at, and safe metadata.
- Download audit must include actor, workspace, managed environment, artifact id, source review/pack ids, profile, format, downloaded at, and safe request metadata if existing audit captures it.
- OperationRun results should include artifact id/path hash/size/fingerprint only if safe; no signed URLs or secrets.
- Failed generation must be observable and safe.
Deployment / Ops Impact
- Env vars: renderer base URL, timeout, body/output size limits, disabled/unavailable behavior, and matching Gotenberg timeout/body/concurrency controls are added to
apps/platform/.env.example; no direct browser binary path is approved. - Migrations: possible narrow
stored_reportsextension; staging migration validation required. - Queues: likely uses queue worker for report generation. Dokploy worker command already includes
reportsqueue in deployment guidance; implementation must confirm actual queue selection. - Scheduler/cron: none.
- Storage: private PDF artifact storage required; production persistence/backup must include the disk/path.
- Filament assets: none planned; deployment already runs
php artisan filament:assetswhen assets are registered. - Package/runtime: Gotenberg 8 Chromium is approved with controls as an internal runtime service; no Composer/npm PDF/browser runtime package is approved. Any different renderer/runtime dependency requires package governance before code changes.
Filament v5 Output Contract For Implementation Close-Out
Implementation response must explicitly state:
- Livewire v4.0+ compliance.
- Provider registration remains in
apps/platform/bootstrap/providers.php. - Global search status:
StoredReportResourceis globally non-searchable today; any changed resource must keep View/Edit safety explicit. - Destructive/high-impact actions: no destructive action; generation is high-impact artifact creation with authorization, readiness, audit, and explicit confirmation implemented.
- Asset strategy: no new Filament assets unless implementation changes plan; deploy
filament:assetsonly if assets are registered. - Testing plan/results for payload, generation, access, audit, OperationRun, download, and browser/content smoke.
Risks and Mitigations
- Renderer config gap: Sail/local renderer service/config and gateway/client boundary exist, but staging/Dokploy controls are not yet validated. Mitigate by confirming internal-only staging runtime, health check, queue behavior, and persistence before enabling report generation.
- Storage mismatch: StoredReport may need schema changes. Mitigate with narrow extension or stop/split.
- Raw leakage: PDF may include hidden/internal content. Mitigate with prebuilt payload and negative content tests.
- Scope leakage: signed URL could bypass context. Mitigate by server-side re-resolution and 404/403 tests.
- Duplicate artifact churn: repeated generation could create clutter. Mitigate with source/profile/fingerprint idempotency where practical.
- Queue failures: renderer/storage can fail. Mitigate OperationRun failed/blocked outcomes and no ready artifact exposure.
Open Questions
Renderer governance decision is complete. Gotenberg 8 Chromium is approved with controls as the internal production PDF rendering service for report-style documents. Runtime/gateway implementation has started: Sail/local service, Laravel config, health check, timeout/size controls, and PdfRenderingGateway / PdfRendererClient now exist. Management report payload/storage/OperationRun/UI/PDF generation work must wait until staging/Dokploy controls are confirmed and the next implementation phase begins.
Implementation Phases
- Repo verification and renderer/package gate.
- Runtime config target discovery and Gotenberg service/config.
- Failing gateway/client tests, then
PdfRenderingGateway/PdfRendererClient. - Failing tests for payload, readiness, disclosure, authorization, audit, storage, OperationRun, download, renderer failure mapping, and content leakage.
- Payload/readiness/disclosure implementation.
- Artifact storage and idempotency.
- OperationRun and audit integration.
- UI action and download route integration.
- PDF rendering through the approved Gotenberg gateway.
- Localization.
- Browser/content smoke and UI coverage close-out.
- Final validation and close-out.