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
352 lines
21 KiB
Markdown
352 lines
21 KiB
Markdown
# 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.
|