# Implementation Plan: Spec 392 - Customer Output Gating & Review Pack Navigation v1 **Branch**: `392-customer-output-gating-review-pack-navigation` | **Date**: 2026-06-20 | **Spec**: `specs/392-customer-output-gating-review-pack-navigation/spec.md` **Input**: Feature specification from `specs/392-customer-output-gating-review-pack-navigation/spec.md` ## Summary Implement a route-enforced Customer Output Gate for existing customer-facing review output and correct misleading Review Pack / Customer Workspace navigation labels. The implementation should reuse existing review-pack readiness and disclosure truth first, then introduce one narrow gate/result adapter only if needed to make UI and direct routes consume the same decision. The primary safety requirement is simple: customer output may be opened or downloaded only when the same canonical decision says it is ready and customer-safe. Internal preview remains separate, secondary, and permission-protected. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12.52, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1 **Storage**: PostgreSQL; no new storage expected **Testing**: Pest 4, Laravel Feature/HTTP tests, Filament/Livewire tests, bounded Browser smoke **Validation Lanes**: fast-feedback, confidence, browser **Target Platform**: Laravel Sail local; Dokploy container deployment for staging/production **Project Type**: Laravel monolith under `apps/platform` **Performance Goals**: DB-only gate evaluation during render/download; no Graph or remote calls **Constraints**: no new persisted readiness truth; no broad Customer Review Workspace rebuild; no route bypass; no unsafe customer-facing download with limitations **Scale/Scope**: existing review, review-pack, stored-report, rendered-report, dashboard, evidence overview, and customer-workspace output surfaces only ## Technical Approach 1. Inventory existing customer-output actions and routes. 2. Define a single customer-output gate decision shape over existing readiness/disclosure/policy truth. 3. Enforce the gate at direct routes before any file stream, rendered report, signed URL, or customer-facing page output. 4. Replace misleading customer-facing labels with truthful destination-specific labels. 5. Separate customer output from internal preview in UI, authorization, route behavior, and tests. 6. Keep internal proof, OperationRun links, raw metadata, and diagnostics secondary or capability-gated by default. The first implementation choice should be: ```text Existing readiness/disclosure truth -> Customer output gate/result adapter -> UI action state and route enforcement ``` Do not create a new readiness engine. The gate may wrap current helpers such as `ReviewPackOutputReadiness`, `ReviewPackOutputResolutionGuidance`, and `ReportDisclosurePolicy` when they already express the needed truth. ## Likely Affected Repository Surfaces Implementation must re-verify exact current code before editing, but likely surfaces are: - `apps/platform/app/Support/ReviewPacks/ReviewPackOutputReadiness.php` - `apps/platform/app/Support/ReviewPacks/ReviewPackOutputResolutionGuidance.php` - `apps/platform/app/Support/ReviewPacks/ReportDisclosurePolicy.php` - `apps/platform/app/Http/Controllers/ReviewPackDownloadController.php` - `apps/platform/app/Http/Controllers/ReviewPackRenderedReportController.php` - `apps/platform/app/Http/Controllers/ManagementReportPdfDownloadController.php` - `apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php` - `apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php` - `apps/platform/resources/views/review-packs/rendered-report.blade.php` - `apps/platform/app/Filament/Resources/ReviewPackResource.php` - `apps/platform/app/Filament/Resources/ReviewPackResource/Pages/ViewReviewPack.php` - `apps/platform/app/Filament/Resources/EnvironmentReviewResource.php` - `apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ViewEnvironmentReview.php` - `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php` - `apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php` - `apps/platform/lang/en/localization.php` - `apps/platform/lang/de/localization.php` - Focused tests under `apps/platform/tests/Unit`, `apps/platform/tests/Feature`, and `apps/platform/tests/Browser` Implementation may remove a surface from the touched list if repo truth shows it is not customer-facing or already correct. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed existing customer-output actions, route access, labels, and customer/output states. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: Customer Review Workspace output actions, Review Pack download/report actions, management-report download if customer-facing, Review Pack/Environment Review labels, Environment Dashboard customer-workspace CTA, Evidence Overview customer-workspace links. - **No-impact class, if applicable**: N/A. - **Native vs custom classification summary**: mixed existing native Filament resources/pages plus existing Blade report/workspace composition. - **Shared-family relevance**: status messaging, action links, dashboard signal links, artifact/report viewers, customer-safe disclosure. - **State layers in scope**: page, detail, route, URL-query. - **Audience modes in scope**: customer/read-only, operator-MSP, support-platform where authorized. - **Decision/diagnostic/raw hierarchy plan**: customer-output safety decision first; diagnostics and raw/support proof second or gated. - **Raw/support gating plan**: collapsed or capability-gated; no raw metadata by default on customer-facing surfaces. - **One-primary-action / duplicate-truth control**: show one top-level customer output state and one state-appropriate primary action; demote internal preview and proof links. - **Handling modes by drift class or surface**: route bypass is hard-stop; misleading CTA labels are review-mandatory; internal-preview exceptions must be documented in feature. - **Repository-signal treatment**: BUG-007 is a hard input; broad completed specs are context only. - **Special surface test profiles**: global-context-shell + customer-safe strategic review surface + artifact download route. - **Required tests or manual smoke**: Unit gate tests, HTTP route tests, Filament/Livewire action state tests, Browser smoke. - **Exception path and spread control**: no exception expected; any retained limitations-bearing internal preview must be named and permission-protected. - **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage. - **UI/Productization coverage decision**: update existing page-report artifacts if implementation materially changes reachable page behavior; otherwise document no-count/no-archetype-change in active spec close-out. - **Coverage artifacts to update**: likely existing page reports under `docs/ui-ux-enterprise-audit/page-reports/...` for Customer Review Workspace / Review Pack / Environment Dashboard only if visible behavior materially changes. - **No-impact rationale**: N/A. - **Navigation / Filament provider-panel handling**: no provider registration or panel path change; verify provider registration remains `apps/platform/bootstrap/providers.php`. - **Screenshot or page-report need**: yes for browser proof of corrected CTA and safe/blocked output; page-report updates only if material page behavior changes. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: review-pack readiness/disclosure, output/download routes, Filament action labels, dashboard links, evidence/report viewers, localization, policy/capability checks. - **Shared abstractions reused**: `ReviewPackOutputReadiness`, `ReviewPackOutputResolutionGuidance`, `ReportDisclosurePolicy`, existing policies/capabilities, existing `CustomerReviewWorkspace::environmentFilterUrl()`, existing `ReviewPackResource` URLs, existing audit logger. - **New abstraction introduced? why?**: none by default; one narrow gate/result adapter only if needed to ensure route and UI consume the same customer-output decision. - **Why the existing abstraction was sufficient or insufficient**: current readiness helpers are sufficient for most derived safety signals, but they are not currently a route-enforced access boundary across every output path. - **Bounded deviation / spread control**: any new gate must stay scoped to customer-output open/download decisions and may not become a generic governance readiness framework. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no new start/completion; existing proof links may remain secondary. - **Central contract reused**: existing OperationRun link helpers/routes. - **Delegated UX behaviors**: N/A for new starts. - **Surface-owned behavior kept local**: output safety copy and customer/internal action labels only. - **Queued DB-notification policy**: N/A. - **Terminal notification path**: unchanged. - **Exception path**: none. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: no. - **Provider-owned seams**: N/A. - **Platform-core seams**: customer-output gating and artifact access labels. - **Neutral platform terms / contracts preserved**: customer output, customer workspace, review pack, internal preview, output state, blocking reason. - **Retained provider-specific semantics and why**: existing customer-safe review content may contain provider facts; gate labels should not. - **Bounded extraction or follow-up path**: none unless implementation finds provider-specific leakage requiring a separate follow-up. ## Domain And Data Implications - No migration is expected. - No new model is expected. - No new persisted enum/status family is expected. - Gate state should be derived from existing records, summaries, readiness/disclosure payloads, file metadata, lifecycle timestamps, and authorization. - If existing data cannot represent a blocker required by the spec, implementation must stop and update `spec.md` / `plan.md` before adding persisted truth. Expected gate result shape can be represented as array/value object fields: ```text state can_open_customer_workspace can_download_customer_output can_download_internal_preview primary_blocking_reason blocking_reasons[] is_customer_safe is_internal_preview_only customer_output_url internal_preview_url target_kind ``` Allowed visible states: ```text Ready Needs attention Blocked Not configured Expired Unknown ``` These are derived presentation states, not persisted lifecycle truth. ## Route And Authorization Plan Route enforcement must run before output content is returned: - `ReviewPackDownloadController`: verify membership, capability, output gate, artifact status, expiry, file existence, audit, stream. - `ReviewPackRenderedReportController`: verify membership, capability, output gate/report profile before rendering a customer-facing report or showing a customer-safe download action. - `ManagementReportPdfDownloadController`: if customer-facing, apply equivalent output/report gate before PDF stream. - Any signed/stale route: stale or blocked customer output returns 403/404/safe redirect without file content. Management-report PDF customer-facing criteria: - Customer-facing when labelled, linked, or positioned as customer/auditor review output from Customer Review Workspace, Review Pack, Environment Review, Environment Dashboard, Evidence Overview, or rendered-report flows. - Internal-only when reachable solely from operator/audit/technical surfaces and copy does not imply customer delivery. - Implementation must record the final include/exclude decision before editing or skipping this controller. Authorization semantics: - Non-member or wrong workspace/environment: 404 deny-as-not-found. - Entitled member without capability: 403. - Entitled member with capability but unsafe customer-output gate: 403 or safe admin redirect with block reason. - Internal preview access: capability plus internal-preview gate; never customer-output permission alone. ## Filament And Livewire Plan - Filament v5 / Livewire v4.0+ compliance is required; this app currently uses Livewire 4.1.4. - Panel provider registration remains `apps/platform/bootstrap/providers.php`; no provider changes are expected. - No global search behavior should be added or changed. - No destructive actions are introduced. Existing destructive/high-impact actions on related resources remain out of scope and must keep confirmation, authorization, audit, notifications, and tests. - UI labels must be route-truthful: - `Open customer workspace` -> actual Customer Review Workspace. - `Open review pack` -> internal Review Pack detail. - `Download customer output` -> customer-safe artifact only. - `Download internal preview` -> internal/operator artifact only. - `View audit trail` / `View technical details` -> internal detail only. - Hidden/disabled UI state is not a security boundary; route/controller checks are mandatory. ## Audit And Observability Plan - Successful customer-output download must keep existing `ReviewPackDownloaded` or equivalent audit events. - Internal preview download, if introduced or relabelled, must be auditable with safe metadata and must not log secrets/raw payloads. - Blocked attempts may be logged only if current audit conventions support it without noise or sensitive data. If added, use stable action IDs and safe metadata. - No new `OperationRun` is expected because this is access/gating, not long-running execution. ## Test Strategy ### Unit tests - Gate returns `Ready` for published, safe, current output with artifact and permission. - Gate returns `Blocked` for PII/unredacted sensitive output. - Gate returns `Needs attention` or `Blocked` for limitations/not-ready output according to severity. - Gate returns `Not configured` for missing output/customer workspace. - Gate returns `Expired` for expired/superseded/archived/revoked output where repo-backed. - Gate returns `Unknown` when current safety cannot be determined. - Permission denial blocks even when output is otherwise safe. - Permission grant does not override unsafe output. ### Feature / HTTP route tests - Safe customer-output download succeeds and audits. - PII/limited/not-ready output direct download is blocked. - Expired/superseded/missing output direct download is blocked. - Internal preview route/action requires internal/operator permission. - Customer/read-only user cannot access internal preview. - Rendered report does not expose customer download when gate blocks. - Management report PDF download, if customer-facing in implementation scope, respects the same gate. ### Filament / Livewire tests - Unsafe customer output action is hidden/disabled/replaced with blocked state. - Blocking reason appears once. - `Open customer workspace` only appears when destination is actual Customer Review Workspace. - `Open review pack` is used for Review Pack detail. - Deprecated limited-download copy is absent from customer-facing surfaces. - Internal preview is secondary and permission-gated. ### Browser smoke - Safe review pack: customer workspace opens and customer output downloads. - Unsafe review pack: customer output blocked and direct URL returns no file. - Internal preview, if present: labelled internal and secondary. - Dashboard CTA labelled `Open customer workspace` opens actual workspace. - Review Pack detail action is labelled `Open review pack` when destination is internal detail. ## Rollout And Deployment Considerations - No env var changes expected. - No migrations expected. - No queue/scheduler changes expected. - No storage topology changes expected. - No Graph scopes or external API changes expected. - No Filament asset registration expected; `filament:assets` is not required unless implementation unexpectedly registers assets. - Staging validation should include safe and unsafe seeded review-output cases before production promotion. ## Constitution Check - Inventory-first / snapshots-second: PASS. The gate reads existing observed/review/report/artifact truth and does not create new external truth. - Read/write separation: PASS. This is access/read/download gating; no Microsoft tenant mutation. - Graph contract path: PASS. No Graph calls are expected; render/download must remain DB/storage-only. - Deterministic capabilities: PASS. Existing capability registry remains authoritative. - RBAC-UX: PASS. Membership 404, capability 403, UI not a security boundary, route enforcement required. - Workspace/tenant isolation: PASS. All output records remain workspace/environment-scoped before access. - OperationRun UX: PASS. No new starts or lifecycle changes. - Test governance: PASS. Unit/Feature/Filament/Browser lanes are explicit and bounded. - Proportionality: PASS with condition. One narrow gate/result adapter is justified by security and route enforcement; no persistence/framework. - Persisted truth: PASS. No new tables/entities/artifacts expected. - State behavior: PASS. Derived visible states change route/action behavior, not persisted lifecycle. - UI semantics: PASS. One visible customer output state, no duplicated badges. - Shared pattern first: PASS. Reuse existing readiness/disclosure/action guidance before any new helper. - Provider boundary: PASS. No provider seam introduced. - Filament-native UI: PASS. Use native/action semantics and existing Blade composition; no new styling system. - UI/Productization coverage: PASS with condition. Update existing UI coverage/page-report artifacts only if runtime UI changes materially. ## Test Governance Check - **Test purpose / classification by changed surface**: Unit for gate derivation; Feature/HTTP for direct routes; Filament/Livewire for action state; Browser for rendered workflow/CTA proof. - **Affected validation lanes**: fast-feedback, confidence, browser. - **Why this lane mix is the narrowest sufficient proof**: route bypass and CTA destination cannot be proven by unit tests alone; browser is needed only for final trust path. - **Narrowest proving command(s)**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec392` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec392CustomerOutputGatingSmokeTest.php --compact` - `git diff --check` - **Fixture / helper / factory / seed / context cost risks**: use existing review-output fixtures; avoid new global seed defaults. - **Expensive defaults or shared helper growth introduced?**: no; any new fixture must be opt-in. - **Heavy-family additions, promotions, or visibility changes**: one explicit Browser smoke. - **Surface-class relief / special coverage rule**: no standard-native relief for the route gate; customer-output direct route proof is mandatory. - **Closing validation and reviewer handoff**: reviewers should verify safe/unsafe route behavior, CTA destinations, no limitations-bearing customer download, and no app-code scope expansion beyond listed surfaces. - **Budget / baseline / trend follow-up**: none. - **Review-stop questions**: Is the route gate shared? Is internal preview separate? Are completed specs untouched? Are broad report/workspace rewrites avoided? - **Escalation path**: document-in-feature for contained exceptions; follow-up-spec only for structural delivery gaps. - **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage. - **Why no dedicated follow-up spec is needed**: this is the dedicated narrow follow-up for fresh customer-output safety evidence; future artifact lifecycle/report runtime/customer portal work is separate. ## Implementation Phases ### Phase 1 - Repo Truth And Action Inventory Inventory all customer-output open/download actions and routes, classify each as customer-facing or internal, and record current label, destination, visibility condition, authorization, and direct-route behavior. ### Phase 2 - Gate Contract And Tests Add tests first for the gate states and route expectations. Choose the narrowest gate home after confirming current helper coverage. ### Phase 3 - Route Enforcement Apply the gate to customer-facing output routes before streaming/rendering output. Preserve membership/capability semantics and audit logging. ### Phase 4 - UI Label And Action Correction Update Customer Review Workspace, Review Pack, Environment Review, Environment Dashboard, Evidence Overview, and rendered report actions only where they are misleading or bypass the gate. ### Phase 5 - Internal Preview Separation If limited artifacts remain accessible, relabel as `Download internal preview`, demote to secondary, protect with internal permission, and remove from customer-facing/default surfaces. ### Phase 6 - Customer-Safe Disclosure And Proof Demotion Ensure internal proof links, OperationRun details, raw metadata, and diagnostics are secondary/capability-gated by default on customer-facing surfaces. ### Phase 7 - Validation And Browser Evidence Run targeted tests, browser smoke, `pint --dirty`, `git diff --check`, and update active spec/page-report artifacts as required by UI-COV. ## Project Structure ```text specs/392-customer-output-gating-review-pack-navigation/ ├── spec.md ├── plan.md ├── tasks.md └── checklists/ └── requirements.md ``` Likely runtime/test surfaces: ```text apps/platform/app/ ├── Http/Controllers/ ├── Filament/Pages/Reviews/ ├── Filament/Pages/Monitoring/ ├── Filament/Resources/ └── Support/ apps/platform/resources/views/ ├── filament/pages/reviews/ └── review-packs/ apps/platform/tests/ ├── Unit/ ├── Feature/ └── Browser/ ``` No new base folders are expected.