TenantAtlas/specs/379-management-report-pdf-runtime/plan.md
ahmido dbff2a0a90 feat(report): implement management report pdf runtime (#450)
Added jobs, controllers, and PDF generation logic for management report runtime as defined in Spec 379. Includes artifact migrations, payload builders, and testing coverage.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #450
2026-06-15 11:36:29 +00:00

284 lines
22 KiB
Markdown

# 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.