# Implementation Plan: Spec 379 - Management Report PDF Runtime Validation & Generation Completion **Branch**: `379-management-report-pdf-runtime` | **Date**: 2026-06-14 | **Spec**: `specs/379-management-report-pdf-runtime/spec.md` **Input**: Feature specification from `specs/379-management-report-pdf-runtime/spec.md` ## Summary Validate the merged Spec 378 Gotenberg/PDF runtime in staging/Dokploy and complete the actual customer-safe Management Report PDF generation flow. The implementation must reuse `PdfRenderingGateway` / `PdfRendererClient`, existing Review Pack rendered-report truth, `ReportProfileRegistry`, `ReportDisclosurePolicy`, OperationRun, audit, and private storage patterns. It must not rebuild PDF infrastructure or expand into report delivery, auditor reports, billing PDFs, or a generic document engine. Spec 379 is the sole active implementation package for post-`G012` runtime validation and downstream Management Report PDF generation completion. Spec 378's unchecked downstream generation tasks are read-only historical baseline signals and must not be executed as a parallel work queue. ## 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 service from Spec 378 **Storage**: PostgreSQL plus private Laravel storage for generated PDF artifacts if file output is persisted **Testing**: Pest Unit, Feature, Filament/Livewire action tests, Browser/content smoke **Validation Lanes**: fast-feedback, confidence, browser, pgsql if schema/indexes are introduced **Target Platform**: Laravel Sail locally; Dokploy container deployment for staging/production **Project Type**: Laravel monolith under `apps/platform` **Performance Goals**: generation is queue-safe and observable; render/download avoids live provider calls; failed runtime/storage cases fail closed **Constraints**: no Graph calls during render/generation/download; only approved PDF gateway; private artifact storage; workspace/managed-environment isolation; confirmation-gated high-impact generation; customer-safe disclosure **Scale/Scope**: one on-demand `customer_executive` Management Report PDF path over one ready current review/report source ## Repo Truth Map Renderer/runtime baseline from Spec 378: - `docker-compose.yml` includes pinned internal `gotenberg/gotenberg:8.34.0-chromium`. - `apps/platform/config/tenantpilot.php` exposes PDF renderer config. - `apps/platform/app/Services/Pdf/PdfRenderRequest.php` - `apps/platform/app/Services/Pdf/PdfRenderResult.php` - `apps/platform/app/Services/Pdf/PdfRendererClient.php` - `apps/platform/app/Services/Pdf/PdfRenderingGateway.php` - `apps/platform/tests/Unit/Pdf/Spec378PdfRenderingGatewayTest.php` - `docs/package-governance.md` approves Gotenberg with controls. - `docs/deployment-checklist.md` records Dokploy/runtime controls. Report/profile foundations: - `apps/platform/app/Http/Controllers/ReviewPackRenderedReportController.php` - `apps/platform/resources/views/review-packs/rendered-report.blade.php` - `apps/platform/app/Support/ReviewPacks/ReportProfileRegistry.php` - `apps/platform/app/Support/ReviewPacks/ReportDisclosurePolicy.php` - `apps/platform/app/Support/ReviewPacks/ReportThemeResolver.php` - `apps/platform/app/Services/ReviewPackService.php` - `apps/platform/app/Jobs/GenerateReviewPackJob.php` - `apps/platform/app/Models/ReviewPack.php` - `apps/platform/app/Models/EnvironmentReview.php` - `apps/platform/app/Models/StoredReport.php` Execution/audit foundations: - `apps/platform/app/Services/OperationRunService.php` - `apps/platform/app/Support/OperationRunType.php` - `apps/platform/app/Support/OperationCatalog.php` - `apps/platform/app/Support/OperationRunLinks.php` - `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` - current audit logger/action ID paths used by Review Pack generation/download flows ## Repo-Truth Decisions To Resolve During Implementation 1. **Owner surface**: Prefer Review Pack detail or Environment Review detail. Do not add a new top-level page unless both existing surfaces are proven insufficient. 2. **Artifact substrate**: Prefer a narrow extension of existing report/artifact storage if needed. If a new table/entity is required, stop and update spec/plan before implementation continues. 3. **Operation type**: Reuse an existing canonical type only if it honestly represents management PDF generation. Otherwise add a narrow `report.management.generate` type/catalog mapping and tests. 4. **UI coverage**: Update route inventory/page reports/design matrix only for material surface changes, or record an explicit checked no-update rationale. 5. **Capabilities**: Generation uses `Capabilities::ENVIRONMENT_REVIEW_MANAGE` on an Environment Review owner surface or `Capabilities::REVIEW_PACK_MANAGE` on a Review Pack owner surface. Download uses `Capabilities::REVIEW_PACK_VIEW`. Any new capability requires spec/plan update and canonical registry tests. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed existing report/review artifact owner surface plus possible new signed/server-authorized PDF download route. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: - `ReviewPackResource` detail page and/or `EnvironmentReviewResource` detail page - existing rendered report source route - optional generated PDF download route/controller - `StoredReportResource` only if generated PDFs are listed/viewed there - **No-impact class, if applicable**: N/A. - **Native vs custom classification summary**: owner actions stay native Filament; PDF content inherits the bounded custom report artifact exception from Spec 366; artifact registry remains native if used. - **Shared-family relevance**: report viewer, artifact download, status/readiness messaging, OperationRun UX, audit. - **State layers in scope**: owner action state, modal confirmation, artifact state, OperationRun status/outcome, signed/download route, private storage. - **Audience modes in scope**: customer-read-only PDF content; operator-MSP generation/download; support-platform diagnostics only through existing OperationRun/log surfaces. - **Decision/diagnostic/raw hierarchy plan**: PDF is decision-first; OperationRun/logs carry diagnostics; raw/support evidence is absent from customer PDF. - **Raw/support gating plan**: raw JSON, provider payloads, signed URLs, secrets, stack traces, SQL errors, and internal MSP/support fields are forbidden in PDF and audit metadata. - **One-primary-action / duplicate-truth control**: owner surface shows one state-dependent action: generate, view operation, or download existing PDF. - **Handling modes by drift class or surface**: hard-stop for renderer duplication, public artifact storage, raw leakage, wrong-scope download, or unvalidated runtime enablement. - **Repository-signal treatment**: update UI coverage artifacts only when material; otherwise record no-update rationale in close-out. - **Special surface test profiles**: report-viewer plus high-impact artifact-generation action. - **Required tests or manual smoke**: Unit payload/readiness/disclosure; Feature authorization/storage/audit/run/download; Filament action state; Browser/content smoke. - **Exception path and spread control**: any custom report/PDF rendering view remains bounded to management report output and consumes existing profile/disclosure truth. - **Active feature PR close-out entry**: Guardrail + Smoke Coverage + Runtime Validation. - **UI/Productization coverage decision**: reachable UI surfaces change. - **Coverage artifacts to update**: route inventory for new route, UI-099 for report/PDF content change, UI-042 for Review Pack action/download changes, UI-048 for StoredReport exposure, design coverage matrix when action/artifact state materially changes. - **No-impact rationale**: N/A. - **Navigation / Filament provider-panel handling**: no navigation or panel-provider change planned. Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`. - **Screenshot or page-report need**: yes for bounded browser/content smoke if UI route/action/content changes are implemented. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: PDF gateway, Review Pack rendered report, report profile/disclosure policy, artifact storage, OperationRun, audit, localization, Filament owner actions. - **Shared abstractions reused**: `PdfRenderingGateway`, `ReportProfileRegistry`, `ReportDisclosurePolicy`, `ReportThemeResolver`, `ReviewPackService`, `OperationRunService`, `OperationRunLinks`, `OperationUxPresenter`, audit logger/action ID patterns. - **New abstraction introduced? why?**: one bounded generation service/payload builder/renderer adapter is allowed because PDF generation must be testable and must not live in Blade/controller code. - **Why the existing abstraction was sufficient or insufficient**: existing abstractions provide renderer and report truth; they do not own generated artifact identity, OperationRun generation lifecycle, or download audit. - **Bounded deviation / spread control**: implementation stays in existing report/review-pack/pdf namespaces; no generic document framework. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes. - **Central contract reused**: `OperationRunService`, `OperationRunLinks`, `OperationUxPresenter`, `OperationCatalog`, `OperationRunType` if needed. - **Delegated UX behaviors**: queued toast, `View operation`, artifact link, run-enqueued browser event, blocked/start-failure messaging, tenant/workspace-safe URL resolution. - **Surface-owned behavior kept local**: source readiness explanation, selected profile, and blocked reason. - **Queued DB-notification policy**: no running DB notifications; queued DB notification only if already supported and explicitly opted in. - **Terminal notification path**: central lifecycle mechanism. - **Exception path**: none. Synchronous no-run generation is out of scope for Spec 379 and requires a future spec before implementation. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes, only through existing stored report/evidence/review content. - **Provider-owned seams**: existing Microsoft/provider labels inside allowed report summaries. - **Platform-core seams**: artifact identity, profile, evidence basis, limitation, operation type, source review/pack provenance. - **Neutral platform terms / contracts preserved**: management report, profile, evidence basis, limitation, managed environment, generated artifact, operation. - **Retained provider-specific semantics and why**: existing profile-safe summaries only. - **Bounded extraction or follow-up path**: Technical/Auditor report if deeper provider appendix is needed. ## Constitution Check *GATE: Must pass before implementation. Re-check after runtime decisions and before code merge.* - Inventory-first: PASS. PDF consumes existing stored review/report truth, not live provider state. - Read/write separation: PASS with controls. Generation is explicit TenantPilot artifact creation with confirmation, audit, and tests. - Graph contract path: PASS. No Graph calls during render/generation/download. - Deterministic capabilities: REQUIRED. Reuse capability registry or add tested capability only if necessary. - RBAC-UX: REQUIRED. Non-member/wrong scope 404; scoped member missing capability 403; server-side authorization always. - Workspace isolation: REQUIRED. Artifact, source, run, and download resolve workspace/environment scope. - Destructive/high-impact actions: REQUIRED. Generate PDF is high-impact artifact creation and requires confirmation. - Global search: PASS. No global-search enablement planned; if StoredReport is touched, keep disabled unless updated by spec. - Run observability: REQUIRED. Queued/observable generation through OperationRun is mandatory. - OperationRun start UX: REQUIRED. Central start/link/notification paths only. - Ops-UX lifecycle: REQUIRED. Status/outcome transitions through `OperationRunService`. - Data minimization: REQUIRED. No secrets/raw payloads/signed URLs in PDF or audit metadata. - Test governance: REQUIRED. Unit/Feature/Filament/Browser lanes explicit. - Proportionality: PASS with controls. Durable PDF artifact truth solves current report handoff gap. - No premature abstraction: PASS with controls. Bounded generation components only. - Persisted truth: PASS if generated artifact metadata is durable and source-bound. - Behavioral state: PASS only for state/reason values that change generation/download behavior. - UI semantics: PASS. Directly map existing profile/readiness/disclosure truth. - Shared pattern first: PASS. Existing renderer/report/operation/audit paths first. - Provider boundary: PASS. Stored summaries only; no provider runtime calls. - UI-COV-001: REQUIRED. Coverage update or explicit no-update rationale required. ## Test Governance Check - **Test purpose / classification by changed surface**: - Unit: runtime validation decision mapping, payload/readiness/disclosure, renderer adapter failure mapping. - Feature: generation, private artifact storage, authorization, OperationRun, audit, download. - Filament/Livewire: owner-surface action visible/disabled/confirmed/queued state. - Browser/content smoke: generated/downloaded PDF content and leakage boundaries. - **Affected validation lanes**: fast-feedback, confidence, browser, pgsql if schema/indexes are introduced. - **Why this lane mix is the narrowest sufficient proof**: each lane proves one trust boundary and avoids broad surface discovery. - **Narrowest proving commands**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec379` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec379ManagementReportPdfSmokeTest.php --compact` - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec378` - `cd apps/platform && ./vendor/bin/sail pint --dirty` - `git diff --check` - **Fixture / helper / factory / seed / context cost risks**: add explicit Spec379 fixtures only; do not widen global report fixtures. - **Expensive defaults or shared helper growth introduced?**: no; browser smoke is explicit and feature-local. - **Heavy-family additions, promotions, or visibility changes**: one explicit browser/content smoke. - **Surface-class relief / special coverage rule**: high-impact artifact action and report-viewer. - **Closing validation and reviewer handoff**: verify no duplicate renderer, no public artifact storage, no raw leakage, no wrong-scope download, no unvalidated runtime enablement. - **Budget / baseline / trend follow-up**: record browser smoke runtime if materially slow. - **Review-stop questions**: lane fit, fixture cost, runtime validation proof, artifact substrate proportionality, OperationRun truth. - **Escalation path**: `document-in-feature` for local decisions; `follow-up-spec` for delivery center, retention/lifecycle framework, technical/auditor PDF, billing PDF. - **Active feature PR close-out entry**: Guardrail + Runtime Validation + Smoke Coverage. - **Why no dedicated follow-up spec is needed**: v1 generation is the direct follow-through over Spec 378; broader delivery/lifecycle/report families stay deferred. ## Project Structure ### Documentation (this feature) ```text specs/379-management-report-pdf-runtime/ ├── spec.md ├── plan.md ├── tasks.md ├── checklists/ │ └── requirements.md └── artifacts/ ├── runtime-validation.md # created during implementation ├── storage-operationrun-decision.md # created during implementation └── screenshots/ # created during browser/content smoke if captured ``` ### Source Code (likely affected, implementation only) ```text apps/platform/app/Services/Pdf/ apps/platform/app/Support/ReviewPacks/ apps/platform/app/Services/ReviewPackService.php apps/platform/app/Jobs/ apps/platform/app/Models/StoredReport.php apps/platform/app/Filament/Resources/ReviewPackResource/ apps/platform/app/Filament/Resources/EnvironmentReviewResource/ apps/platform/app/Http/Controllers/ apps/platform/routes/ apps/platform/database/migrations/ apps/platform/tests/Unit/ apps/platform/tests/Feature/ apps/platform/tests/Browser/ apps/platform/resources/lang/ ``` **Structure Decision**: Use the existing Laravel/Filament monolith. Add only feature-local report/PDF generation pieces under current report/PDF namespaces. Do not add new base folders or dependencies. ## Implementation Phases ### Phase 0 - Repo Verification And Runtime Gate Re-read Spec 378 artifacts and current PDF runtime files. Validate staging/Dokploy runtime controls and record results in `specs/379-management-report-pdf-runtime/artifacts/runtime-validation.md`. If validation fails, block report generation and implement only safe disabled/blocked behavior. ### Phase 1 - Tests First Add failing Unit, Feature, Filament/Livewire, and Browser/content smoke coverage for payload, readiness, authorization, generation, OperationRun, audit, download, and leakage boundaries. ### Phase 2 - Payload And Disclosure Build a deterministic customer-executive management report payload from existing Review Pack/rendered-report/profile/disclosure truth. No Graph calls, no Blade queries, no duplicated renderer infrastructure. ### Phase 3 - Artifact Storage And Idempotency Choose the smallest artifact substrate. Prefer narrow existing substrate extension if needed; stop for spec/plan update if a new entity/table is required. Store PDFs privately and protect against partial-ready artifacts. ### Phase 4 - OperationRun And Audit Queue and track generation through OperationRun, map success/blocked/failed outcomes safely, and record generation/download audit metadata without secrets or raw payloads. ### Phase 5 - Owner Action And Download Route Add one confirmed high-impact owner-surface action, disabled/blocked reasons, canonical operation link, existing-artifact download state, and a signed/server-authorized route if needed. ### Phase 6 - PDF Rendering And Localization Render through `PdfRenderingGateway`, include required management chapters and provenance, use private/local assets only, and add EN/DE labels for action, blocked reasons, chapters, limitations, and provenance where needed. ### Phase 7 - Coverage And Validation Run focused tests, browser/content smoke, Spec378 regression, Pint dirty, `git diff --check`, and record deployment impact, UI coverage decision, and final no-duplication scan. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |---|---|---| | Durable generated artifact metadata | The PDF must be downloadable, auditable, and source-bound after generation | Browser print cannot provide artifact truth, authorization, or audit | | Bounded generation service/payload builder | Generation needs tests, readiness, storage, audit, and OperationRun boundaries | Controller/Blade code would duplicate truth and hide failures | | Possible operation type mapping | Management PDF generation is an operator-visible queued artifact operation | Reusing an unrelated type would mislabel monitoring/audit truth | ## Proportionality Review - **Current operator problem**: no real customer-ready Management Report PDF despite approved renderer infrastructure. - **Existing structure is insufficient because**: Spec 378 gateway renders bytes but does not manage report payload, artifact identity, generation lifecycle, authorization, or audit. - **Narrowest correct implementation**: validate runtime and implement one customer-executive generation/download path over existing review/report truth. - **Ownership cost created**: tests, possible schema extension, operation/audit mapping, deployment validation artifact, one browser smoke. - **Alternative intentionally rejected**: second renderer, generic document/report engine, public links, delivery center, technical/auditor report, billing PDF. - **Release truth**: current-release follow-through over merged Spec 378. ## Rollout And Deployment Considerations - **Environment variables**: use existing Spec 378 PDF renderer env/config. Add only if implementation finds a missing bounded runtime switch. - **Migrations**: possible only for narrow artifact metadata/storage fields; PostgreSQL lane required if added. - **Queues/workers**: queued generation requires Dokploy workers and queue visibility. - **Storage**: private persistent disk/object storage required for PDF artifacts. - **Scheduler**: none expected. - **Filament assets**: no new Filament assets expected; `filament:assets` remains part of deploy only if assets are registered. - **Staging gate**: staging/Dokploy runtime validation is mandatory before production promotion. ## Filament v5 / Livewire v4 Output Contract - Livewire v4.0+ compliance: target app uses Livewire 4.1.4; no Livewire v3 APIs are planned. - Provider registration: no panel provider change planned; Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`. - Global search: no globally searchable resource is introduced; `StoredReportResource` remains non-globally-searchable unless a future spec updates it with safe View/Edit semantics. - Destructive/high-impact actions: `Generate management PDF` is high-impact artifact creation, must use `Action::make(...)->action(...)`, explicit confirmation, server authorization through `ENVIRONMENT_REVIEW_MANAGE` or `REVIEW_PACK_MANAGE` according to selected owner surface, readiness gate, audit, and tests. PDF download requires `REVIEW_PACK_VIEW`. - Asset strategy: no new panel/shared assets expected; deploy uses existing `filament:assets` requirement only if assets are registered. - Testing plan: Feature/Filament action tests cover owner action, authorization, OperationRun, audit, and download; Browser/content smoke covers customer-facing PDF.