Implements Spec392 customer output gating for review pack downloads, rendered reports, management PDFs, and customer workspace CTAs. Validation: - php vendor/bin/pest --filter=Spec392: 12 passed / 58 assertions - php vendor/bin/pest --filter='ReviewPack|CustomerReviewWorkspace|StoredReport': 283 passed / 1 skipped / 2053 assertions - affected browser matrix: 12 passed / 420 assertions - php vendor/bin/pint --dirty: pass - git diff --check: pass Notes: - Deprecated limited-download semantics remain removed. - Unsafe customer-facing output returns 403/no output. - Internal preview/report access is operator-only. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #463
21 KiB
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
- Inventory existing customer-output actions and routes.
- Define a single customer-output gate decision shape over existing readiness/disclosure/policy truth.
- Enforce the gate at direct routes before any file stream, rendered report, signed URL, or customer-facing page output.
- Replace misleading customer-facing labels with truthful destination-specific labels.
- Separate customer output from internal preview in UI, authorization, route behavior, and tests.
- Keep internal proof, OperationRun links, raw metadata, and diagnostics secondary or capability-gated by default.
The first implementation choice should be:
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.phpapps/platform/app/Support/ReviewPacks/ReviewPackOutputResolutionGuidance.phpapps/platform/app/Support/ReviewPacks/ReportDisclosurePolicy.phpapps/platform/app/Http/Controllers/ReviewPackDownloadController.phpapps/platform/app/Http/Controllers/ReviewPackRenderedReportController.phpapps/platform/app/Http/Controllers/ManagementReportPdfDownloadController.phpapps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.phpapps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.phpapps/platform/resources/views/review-packs/rendered-report.blade.phpapps/platform/app/Filament/Resources/ReviewPackResource.phpapps/platform/app/Filament/Resources/ReviewPackResource/Pages/ViewReviewPack.phpapps/platform/app/Filament/Resources/EnvironmentReviewResource.phpapps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ViewEnvironmentReview.phpapps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.phpapps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.phpapps/platform/lang/en/localization.phpapps/platform/lang/de/localization.php- Focused tests under
apps/platform/tests/Unit,apps/platform/tests/Feature, andapps/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, existingCustomerReviewWorkspace::environmentFilterUrl(), existingReviewPackResourceURLs, 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.mdbefore adding persisted truth.
Expected gate result shape can be represented as array/value object fields:
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:
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
ReviewPackDownloadedor 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
OperationRunis expected because this is access/gating, not long-running execution.
Test Strategy
Unit tests
- Gate returns
Readyfor published, safe, current output with artifact and permission. - Gate returns
Blockedfor PII/unredacted sensitive output. - Gate returns
Needs attentionorBlockedfor limitations/not-ready output according to severity. - Gate returns
Not configuredfor missing output/customer workspace. - Gate returns
Expiredfor expired/superseded/archived/revoked output where repo-backed. - Gate returns
Unknownwhen 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 workspaceonly appears when destination is actual Customer Review Workspace.Open review packis 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 workspaceopens actual workspace. - Review Pack detail action is labelled
Open review packwhen 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:assetsis 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=Spec392cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec392CustomerOutputGatingSmokeTest.php --compactgit 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
specs/392-customer-output-gating-review-pack-navigation/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
└── requirements.md
Likely runtime/test surfaces:
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.