Some checks failed
Main Confidence / confidence (push) Failing after 54s
Add `CustomerReviewWorkspace` page for tenant pre-filtered reviews Add customer workspace links to `EvidenceSnapshotResource`, `ReviewPackResource`, and `TenantReviewResource` Implement audit logging for `TenantReviewOpened` and `ReviewPackDownloaded` actions Update ReviewPack download controller to enforce tenant-scoped RBAC Add tests for ReviewPack download authorization and audit logging Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #289
311 lines
33 KiB
Markdown
311 lines
33 KiB
Markdown
# Implementation Plan: Customer Review Workspace v1
|
|
|
|
**Branch**: `249-customer-review-workspace` | **Date**: 2026-04-27 | **Spec**: [spec.md](spec.md)
|
|
**Input**: Feature specification from [spec.md](spec.md)
|
|
|
|
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
|
|
|
|
## Summary
|
|
|
|
Introduce one canonical customer-safe review workspace inside the existing `/admin` plane by adding a native Filament v5 read-only page that derives its content from existing tenant review, review-pack, evidence, findings, redaction, and audit truth. The page should answer the first customer question quickly, then reuse the existing tenant-scoped review, review-pack, and evidence detail routes for proof instead of creating a new truth layer.
|
|
|
|
This slice is explicitly consumption-only. It does not create or publish reviews, generate or regenerate review packs, remediate findings, widen the identity model, or add persistence. Livewire remains v4 under Filament v5, panel-provider registration stays in [../../apps/platform/bootstrap/providers.php](../../apps/platform/bootstrap/providers.php), no new globally searchable resource is introduced, and no new asset bundle is expected for v1.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4, Laravel 12
|
|
**Primary Dependencies**: Filament v5, Livewire v4, Pest v4, existing review/evidence/review-pack/audit/RBAC support services
|
|
**Storage**: PostgreSQL via existing `tenant_reviews`, `review_packs`, `evidence_snapshots`, findings / finding-exception truth, workspace memberships, and `audit_logs`; no new persistence planned
|
|
**Testing**: Pest v4 feature coverage plus one browser smoke slice, with optional narrow unit coverage only if a row-composition helper emerges during implementation
|
|
**Validation Lanes**: confidence, browser
|
|
**Target Platform**: Laravel monolith in `apps/platform` running via Sail, with existing `/admin` and tenant-scoped `/admin/t/{tenant}` surfaces
|
|
**Project Type**: Web application (Laravel monolith with Filament panels)
|
|
**Performance Goals**: page render remains DB-only and workspace-scoped; no Graph calls, no queue starts, and no remote work on render; latest review lookup should stay within one eager-loaded workspace read path
|
|
**Constraints**: preserve deny-as-not-found workspace and tenant isolation; keep the first slice in the existing admin plane; keep raw diagnostics and debug semantics out of the default path; avoid new persistence, new customer role families, and new presenter/taxonomy layers
|
|
**Scale/Scope**: 1 new admin page, 1 derived workspace summary per entitled tenant, reuse of 5 existing read surfaces and their services, 0 new runtime entities, and 1 explicit browser smoke slice
|
|
|
|
## Likely Affected Repo Surfaces
|
|
|
|
- [../../apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php](../../apps/platform/app/Filament/Pages/Reviews/ReviewRegister.php) for the existing workspace review register pattern, filter behavior, and action-surface expectations.
|
|
- [../../apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php](../../apps/platform/app/Filament/Pages/Monitoring/EvidenceOverview.php) for canonical workspace-page state persistence, tenant-prefilter handling, and clickable-row read-only reporting patterns.
|
|
- [../../apps/platform/app/Services/TenantReviews/TenantReviewRegisterService.php](../../apps/platform/app/Services/TenantReviews/TenantReviewRegisterService.php) as the preferred entitlement and workspace query seam to extend or reuse before adding any new helper.
|
|
- [../../apps/platform/app/Filament/Resources/TenantReviewResource.php](../../apps/platform/app/Filament/Resources/TenantReviewResource.php), [../../apps/platform/app/Filament/Resources/ReviewPackResource.php](../../apps/platform/app/Filament/Resources/ReviewPackResource.php), and [../../apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php](../../apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php) for existing tenant-scoped proof routes, action-surface rules, and capability gates.
|
|
- [../../apps/platform/app/Services/ReviewPackService.php](../../apps/platform/app/Services/ReviewPackService.php), [../../apps/platform/app/Http/Controllers/ReviewPackDownloadController.php](../../apps/platform/app/Http/Controllers/ReviewPackDownloadController.php), and [../../apps/platform/routes/web.php](../../apps/platform/routes/web.php) for signed download generation, current pack availability semantics, and the real download route.
|
|
- [../../apps/platform/app/Services/TenantReviews/TenantReviewService.php](../../apps/platform/app/Services/TenantReviews/TenantReviewService.php) plus the existing `TenantReview` summary/section payloads for published review truth, findings summaries, and accepted-risk source data.
|
|
- [../../apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php](../../apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php) and [../../apps/platform/app/Support/RedactionIntegrity.php](../../apps/platform/app/Support/RedactionIntegrity.php) for customer-safe outcome and redaction wording.
|
|
- [../../apps/platform/app/Services/Auth/RoleCapabilityMap.php](../../apps/platform/app/Services/Auth/RoleCapabilityMap.php), [../../apps/platform/app/Support/Auth/Capabilities.php](../../apps/platform/app/Support/Auth/Capabilities.php), and existing tenant review / evidence policies for capability-first RBAC.
|
|
- [../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php](../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php) and [../../apps/platform/app/Support/Audit/AuditActionId.php](../../apps/platform/app/Support/Audit/AuditActionId.php) for audit reuse.
|
|
- Likely new implementation files if code work later proceeds: `App\Filament\Pages\Reviews\CustomerReviewWorkspace`, a matching Blade view under `resources/views/filament/pages/reviews/`, and focused tests under `tests/Feature/Reviews/` and `tests/Browser/Reviews/`.
|
|
|
|
## UI / Filament & Livewire Fit
|
|
|
|
- Implement as a native Filament v5 `Page` using the same `HasTable` / `InteractsWithTable` style already used by the workspace review and evidence overview pages. Do not introduce a new Resource, portal shell, custom SPA, or second panel.
|
|
- Keep the page in the existing admin-plane reporting family with one primary inspect affordance and, at most, one inline safe download shortcut. The workspace page itself should not expose bulk actions, More-menu sprawl, or lifecycle controls.
|
|
- Livewire v4 hydration must preserve tenant prefilter and launch-context state through public, query-backed, or session-backed state. Do not rely on private page properties for any state that must survive a Livewire interaction.
|
|
- Tenant detail links should continue using the existing tenant-scoped route helpers from the resource layer so the workspace page stays a navigation surface, not a duplicate detail renderer.
|
|
- The new surface is a Page, not a globally searchable Resource. Existing tenant review, review-pack, and evidence resources already have global search disabled, and that remains unchanged for this slice.
|
|
|
|
## RBAC / Policy Fit
|
|
|
|
- Workspace membership remains the first gate. The preferred access check is the existing workspace-entitlement path already used by `TenantReviewRegisterService::canAccessWorkspace(...)` and the current workspace context.
|
|
- The safe v1 audience anchor remains the existing readonly-capable tenant role in [../../apps/platform/app/Services/Auth/RoleCapabilityMap.php](../../apps/platform/app/Services/Auth/RoleCapabilityMap.php). No new customer role family or external customer identity plane is planned.
|
|
- Page visibility and row composition should derive entitled tenants from the canonical capability registry: `TENANT_VIEW` plus `TENANT_REVIEW_VIEW` for page entry, with `REVIEW_PACK_VIEW`, `EVIDENCE_VIEW`, `TENANT_FINDINGS_VIEW`, `FINDING_EXCEPTION_VIEW`, and `AUDIT_VIEW` gating optional secondary proof.
|
|
- Non-members or explicit out-of-scope tenant targets must resolve as not found. Once workspace and tenant membership are established, missing secondary capabilities remain normal authorization failures for execution paths and should not leak hidden content through the UI.
|
|
- Policy and gate checks stay capability-first. No role-string checks or customer-only bypasses should appear in the implementation.
|
|
|
|
## Audit / Logging Fit
|
|
|
|
- Reuse the existing audit infrastructure through `WorkspaceAuditLogger` and `AuditActionId`. The feature should not create a separate audit store, mirror page-view ledger, or custom analytics table.
|
|
- Existing review export generation already logs `tenant_review.exported`, and review-pack download already has a real signed route. The plan assumes explicit customer-facing artifact open/download events can remain on the current audit pipeline.
|
|
- If the workspace page needs a distinct access event beyond what current review-pack or review actions already capture, add a stable `AuditActionId` case and log it through the shared audit path rather than page-local ad hoc logging.
|
|
- Default page render should not emit noisy audit events. The auditable boundary is explicit artifact access or download, not passive page paint.
|
|
|
|
## Data & Query Fit
|
|
|
|
- The preferred row source is a derived workspace read over entitled tenants and their latest published `TenantReview`, with eager-loaded `tenant`, `evidenceSnapshot`, and `currentExportReviewPack` relations.
|
|
- Accepted-risk and findings summaries should come from existing review summary / section payloads, not from a new customer-specific aggregation model. `TenantReviewSectionFactory` already shapes accepted-risk and finding outcome data into the review artifact.
|
|
- Absence handling must remain derived view logic. The page may surface `No published review available yet` or pack-unavailable messaging, but that language must not become a new persisted lifecycle or publication taxonomy.
|
|
- No new table, cache, or materialized view is planned. If the existing register service cannot express the exact latest-published-per-tenant query safely, extend that service or add a bounded page-local read helper rather than introducing a new projector or presenter family.
|
|
- Pack availability should remain tied to the current review/export relationship and existing signed download semantics. The page must not trigger generation or regeneration.
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
> **Fill for operator-facing or guardrail-relevant workflow changes. Docs-only or template-only work may use concise `N/A`. Copy the spec classification forward; do not rename or expand it here.**
|
|
|
|
- **Guardrail scope**: changed surfaces
|
|
- **Native vs custom classification summary**: native Filament
|
|
- **Shared-family relevance**: reporting, evidence/report viewers, navigation entry points, review/download actions, disclosure hierarchy
|
|
- **State layers in scope**: page, URL-query
|
|
- **Audience modes in scope**: customer/read-only, operator-MSP
|
|
- **Decision/diagnostic/raw hierarchy plan**: decision-first, diagnostics-second, support-raw-third
|
|
- **Raw/support gating plan**: capability-gated and hidden by default through reused detail routes only
|
|
- **One-primary-action / duplicate-truth control**: the dominant next action remains `Open latest review`; download is the only inline safe shortcut, and deeper proof stays on existing detail surfaces instead of being repeated on the workspace page
|
|
- **Handling modes by drift class or surface**: review-mandatory
|
|
- **Repository-signal treatment**: review-mandatory now, future hard-stop candidate if implementation introduces a second customer-review truth path
|
|
- **Special surface test profiles**: standard-native-filament, shared-detail-family
|
|
- **Required tests or manual smoke**: functional-core, bounded-browser-smoke
|
|
- **Exception path and spread control**: none expected; any need for a local presenter, custom disclosure taxonomy, or new detail shell should be treated as exception-required drift
|
|
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
> **Fill when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, navigation entry points, alerts, evidence/report viewers, or any other shared interaction family. Docs-only or template-only work may use concise `N/A`. Carry the same decision forward from the spec instead of renaming it here.**
|
|
|
|
- **Cross-cutting feature marker**: yes
|
|
- **Systems touched**: `ReviewRegister`, `EvidenceOverview`, `TenantReviewRegisterService`, `TenantReviewResource`, `ReviewPackResource`, `EvidenceSnapshotResource`, `ReviewPackService`, `TenantReviewService`, `ArtifactTruthPresenter`, `SurfaceCompressionContext`, `ActionSurfaceDeclaration`, `RedactionIntegrity`, `WorkspaceAuditLogger`, `AuditActionId`, and the existing capability / policy seams
|
|
- **Shared abstractions reused**: `TenantReviewRegisterService`, `ArtifactTruthPresenter`, `SurfaceCompressionContext`, Filament action-surface declarations, existing tenant-scoped resource URL helpers, `ReviewPackService`, `RedactionIntegrity`, and the existing audit pipeline
|
|
- **New abstraction introduced? why?**: none by default. If implementation discovers that the current register service cannot safely express latest-published-per-tenant rows, the smallest acceptable addition is a bounded read helper or service extension for this page only
|
|
- **Why the existing abstraction was sufficient or insufficient**: current review, evidence, and pack abstractions already hold the truth and disclosure language; they are insufficient only because there is no calm customer-safe workspace entry point today
|
|
- **Bounded deviation / spread control**: none planned. The new page must compose existing truth, not rename it or mirror it into a customer-specific presenter framework
|
|
|
|
## OperationRun UX Impact
|
|
|
|
> **Fill when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`. Docs-only or template-only work may use concise `N/A`.**
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: no
|
|
- **Central contract reused**: `N/A`
|
|
- **Delegated UX behaviors**: `N/A`
|
|
- **Surface-owned behavior kept local**: read-only inspection and signed artifact download only; any existing `OperationRun` links stay on reused detail surfaces and are not promoted into the default customer path
|
|
- **Queued DB-notification policy**: `N/A`
|
|
- **Terminal notification path**: `N/A`
|
|
- **Exception path**: none
|
|
|
|
## Provider Boundary & Portability Fit
|
|
|
|
> **Fill when the feature touches shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth. Docs-only or template-only work may use concise `N/A`.**
|
|
|
|
- **Shared provider/platform boundary touched?**: no
|
|
- **Provider-owned seams**: `N/A`
|
|
- **Platform-core seams**: existing workspace, tenant, review, evidence, findings, and audit vocabulary only
|
|
- **Neutral platform terms / contracts preserved**: `workspace`, `tenant`, `review`, `evidence`, `review pack`, `accepted risk`, and existing artifact-truth wording
|
|
- **Retained provider-specific semantics and why**: none; the feature consumes provider-shaped artifacts only through already-normalized platform surfaces
|
|
- **Bounded extraction or follow-up path**: `N/A`
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
|
|
|
- Inventory-first / snapshot truth: PASS. The slice consumes existing `TenantReview`, `ReviewPack`, and `EvidenceSnapshot` artifacts as read-only truth and does not redefine source-of-truth boundaries.
|
|
- Read/write separation: PASS. The workspace page is read-only and adds no create, publish, regenerate, expire, triage, or remediation action. Any destructive-like action that already exists on reused detail pages remains outside the default path and must continue using confirmation.
|
|
- Graph contract path: PASS. No new Graph calls or provider contract work are part of this slice.
|
|
- Deterministic capabilities: PASS. The plan reuses the canonical capability registry in [../../apps/platform/app/Support/Auth/Capabilities.php](../../apps/platform/app/Support/Auth/Capabilities.php) and the existing role map.
|
|
- Workspace isolation + tenant isolation: PASS. Workspace membership remains a 404 boundary, tenant entitlement remains a 404 boundary, and explicit out-of-scope tenant filters must not leak existence.
|
|
- RBAC-UX plane separation: PASS. Everything stays in the existing `/admin` plane and tenant-scoped detail routes; no `/system` surface or cross-plane flow is added.
|
|
- Destructive confirmation standard: PASS. No destructive action is planned on the workspace page. If implementation later discovers any destructive affordance on a reused surface must be exposed, it must remain confirmation-protected and out of the default customer-safe path.
|
|
- Global search safety: PASS. The new slice is a Page, not a Resource. Existing tenant review, review-pack, and evidence resources are already not globally searchable, and no new searchable resource is introduced.
|
|
- OperationRun and Ops-UX: PASS by non-use. The workspace page starts no run, emits no run UX, and performs no queue orchestration.
|
|
- Data minimization: PASS. Default-visible content stays decision-first; raw JSON, unrestricted audit metadata, fingerprints, debug semantics, and raw provider payloads stay hidden.
|
|
- Test governance (TEST-GOV-001): PASS. Planned proof stays in focused feature tests plus one bounded browser smoke slice, with optional unit coverage only if a local read helper appears.
|
|
- Proportionality / no premature abstraction: PASS. No new persistence, presenter family, enum family, or identity plane is planned; the narrowest shape is one page over existing truth seams.
|
|
- Persisted truth (PERSIST-001): PASS. No new table, cache, or stored customer-review projection is planned.
|
|
- Behavioral state (STATE-001): PASS. Any unavailable or no-published-review wording remains derived UI state, not a new persisted lifecycle.
|
|
- UI semantics / shared pattern first / Filament-native UI: PASS. The plan reuses Filament pages/resources, existing badge and artifact-truth presenters, existing download service, and the current disclosure language rather than inventing a new UI framework.
|
|
- Provider boundary (PROV-001): PASS. The slice stays within already-normalized review and evidence artifacts and does not deepen provider coupling.
|
|
- Filament / Laravel planning contract: PASS. Filament v5 remains on Livewire v4, provider registration stays in [../../apps/platform/bootstrap/providers.php](../../apps/platform/bootstrap/providers.php), no new panel registration is needed, and no new panel-only or shared asset registration is expected.
|
|
- Asset strategy: PASS. Default assumption is no new assets. If implementation later registers any Filament asset anyway, deployment continues to require `cd apps/platform && php artisan filament:assets`.
|
|
|
|
**Gate evaluation**: PASS.
|
|
|
|
- The slice stays inside the existing admin plane and current workspace/tenant membership model.
|
|
- The page remains a customer-safe consumption surface, not a new review-generation or remediation workflow.
|
|
- Existing review, evidence, pack, redaction, and audit seams are sufficient for v1 if the implementation resists adding a second presenter or persistence layer.
|
|
|
|
**Post-design re-check**: PASS (design artifacts: [research.md](research.md), [data-model.md](data-model.md), [quickstart.md](quickstart.md), [contracts/customer-review-workspace.openapi.yaml](contracts/customer-review-workspace.openapi.yaml)).
|
|
|
|
## Test Governance Check
|
|
|
|
> **Fill for any runtime-changing or test-affecting feature. Docs-only or template-only work may state concise `N/A` or `none`.**
|
|
|
|
- **Test purpose / classification by changed surface**: Feature for workspace-page behavior, authorization, and pack-access semantics; Browser for the calm customer-safe disclosure smoke path; optional Unit only if a bounded row-composition helper is extracted
|
|
- **Affected validation lanes**: confidence, browser
|
|
- **Why this lane mix is the narrowest sufficient proof**: feature coverage is the cheapest way to prove deny-as-not-found behavior, capability-gated secondary actions, empty states, and signed download wiring on a native Filament page; one browser smoke is justified because the product value of this slice is the disclosure experience itself
|
|
- **Narrowest proving command(s)**:
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Reviews/CustomerReviewWorkspaceAuthorizationTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Reviews/CustomerReviewWorkspaceSmokeTest.php`
|
|
- **Fixture / helper / factory / seed / context cost risks**: moderate but contained; reuse existing workspace membership, tenant membership, published review, ready pack, evidence snapshot, findings, and finding-exception fixtures rather than introducing heavy new helpers
|
|
- **Expensive defaults or shared helper growth introduced?**: no; any helper added for row composition or launch-context state should stay explicit and page-local
|
|
- **Heavy-family additions, promotions, or visibility changes**: exactly one browser smoke slice only; no broader browser family or heavy-governance lane expansion should be needed
|
|
- **Surface-class relief / special coverage rule**: standard-native-filament relief for route, auth, filters, and empty states; shared-detail-family checks only where navigation into existing review/pack/evidence surfaces needs proof
|
|
- **Closing validation and reviewer handoff**: rerun the four focused commands above, verify the page never shows admin or remediation controls by default, verify out-of-scope tenant targeting stays 404-safe, and verify download remains signed and capability-bound through the existing pack path
|
|
- **Budget / baseline / trend follow-up**: none expected beyond a small feature-local browser cost
|
|
- **Review-stop questions**: lane fit, hidden fixture cost, accidental browser family growth, duplicated detail rendering, audit proof adequacy
|
|
- **Escalation path**: `document-in-feature` for contained audit-test placement drift; `reject-or-split` if implementation grows into write workflows, new persistence, or a larger browser suite
|
|
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage
|
|
- **Why no dedicated follow-up spec is needed**: routine test and disclosure upkeep stays inside this feature unless implementation proves a structural need for a broader customer-access program
|
|
|
|
## Rollout & Risk Controls
|
|
|
|
- Keep the v1 audience anchored to the current readonly-capable tenant role plus existing review/evidence capabilities. No navigation or deep link should become visible without those gates.
|
|
- Treat the page as a new read-only entry point only. Do not move generation, publish, regenerate, refresh, expire, triage, or remediation controls onto it during implementation.
|
|
- Prefer extending the existing register and detail seams over introducing any persisted projection, local presenter family, or customer-only vocabulary.
|
|
- Keep signed pack download on the existing route and controller path. Do not replace it with a new download endpoint just for the workspace page.
|
|
- Validate the page with one browser smoke before considering any broader navigation prominence changes. The rollout risk is disclosure drift, not infrastructure change.
|
|
- No migration, queue worker change, or asset build sequence change is expected for this slice.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/249-customer-review-workspace/
|
|
├── plan.md
|
|
├── research.md
|
|
├── data-model.md
|
|
├── quickstart.md
|
|
├── contracts/
|
|
│ └── customer-review-workspace.openapi.yaml
|
|
└── tasks.md # Created later by /speckit.tasks, not by this plan step
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
```text
|
|
apps/platform/
|
|
├── app/
|
|
│ ├── Filament/
|
|
│ │ ├── Pages/Reviews/
|
|
│ │ │ ├── ReviewRegister.php
|
|
│ │ │ └── CustomerReviewWorkspace.php # likely new page if implementation proceeds
|
|
│ │ ├── Pages/Monitoring/EvidenceOverview.php
|
|
│ │ └── Resources/
|
|
│ │ ├── TenantReviewResource.php
|
|
│ │ ├── ReviewPackResource.php
|
|
│ │ └── EvidenceSnapshotResource.php
|
|
│ ├── Http/Controllers/ReviewPackDownloadController.php
|
|
│ ├── Models/TenantReview.php
|
|
│ ├── Services/
|
|
│ │ ├── Audit/WorkspaceAuditLogger.php
|
|
│ │ ├── ReviewPackService.php
|
|
│ │ └── TenantReviews/
|
|
│ │ ├── TenantReviewRegisterService.php
|
|
│ │ └── TenantReviewService.php
|
|
│ ├── Support/
|
|
│ │ ├── Audit/AuditActionId.php
|
|
│ │ ├── Auth/Capabilities.php
|
|
│ │ ├── RedactionIntegrity.php
|
|
│ │ └── Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php
|
|
│ └── Policies/
|
|
│ ├── TenantReviewPolicy.php
|
|
│ └── EvidenceSnapshotPolicy.php
|
|
├── bootstrap/providers.php
|
|
├── resources/views/filament/pages/reviews/ # likely new page view if implementation proceeds
|
|
├── routes/web.php
|
|
└── tests/
|
|
├── Browser/Reviews/
|
|
├── Feature/Reviews/
|
|
└── Feature/ReviewPack/
|
|
```
|
|
|
|
**Structure Decision**: Laravel monolith. Implementation should stay entirely inside `apps/platform`, add at most one new read-only page and matching Blade view, and reuse the existing review, pack, evidence, RBAC, and audit seams rather than creating a separate customer-facing subsystem.
|
|
|
|
## Complexity Tracking
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
|-----------|------------|-------------------------------------|
|
|
| None expected | The intended implementation is one native page plus derived queries over existing truth | A separate portal, persistence layer, or customer presenter framework would import unnecessary scope and ownership cost |
|
|
|
|
## Proportionality Review
|
|
|
|
- **Current operator problem**: review artifacts already exist, but readonly-capable tenant actors still lack one coherent customer-safe workspace surface to consume them.
|
|
- **Existing structure is insufficient because**: current review, pack, and evidence surfaces are truthful but fragmented and more operator-oriented than a calm customer-first entry point.
|
|
- **Narrowest correct implementation**: add one native Filament page over existing tenant review, review-pack, evidence, findings, redaction, and audit seams, with only derived row composition and no new persistence.
|
|
- **Ownership cost created**: one page, one view, one bounded query/composition seam if required, and focused feature/browser tests.
|
|
- **Alternative intentionally rejected**: a new customer portal, a new identity plane, and a new persisted customer-review projection were all rejected because existing admin-plane RBAC and review artifacts are sufficient for the first slice.
|
|
- **Release truth**: current-release customer-safe consumption slice, not future-release portal preparation.
|
|
|
|
## Phase 0 — Research (output: research.md)
|
|
|
|
Research resolves the remaining implementation-shaping decisions:
|
|
|
|
- place the new page in the existing admin-plane reviews family rather than extending `ReviewRegister` into a dual-persona page or creating a portal shell
|
|
- reuse `TenantReviewRegisterService` as the entitlement/query seam before adding any new helper
|
|
- keep tenant prefilter and launch context in Livewire-safe public/query/session-backed state
|
|
- reuse `ArtifactTruthPresenter`, existing review summary payloads, and `RedactionIntegrity` for disclosure instead of adding a customer presenter layer
|
|
- reuse the existing signed review-pack download route and audit pipeline rather than inventing a new consumption endpoint
|
|
|
|
**Output**: [research.md](research.md)
|
|
|
|
## Phase 1 — Design (outputs: data-model.md, contracts/, quickstart.md)
|
|
|
|
Design artifacts capture the narrow implementation shape:
|
|
|
|
- no new persistence; reused truth stays in tenant reviews, review packs, evidence snapshots, findings/exceptions, memberships, and audit logs
|
|
- one derived workspace entry model documents what the new page must compose without becoming a stored entity
|
|
- the conceptual contract documents the page route, tenant-detail handoff, and signed pack-download semantics
|
|
- quickstart records the intended implementation order, validation commands, Filament/Livewire assumptions, provider-registration location, and no-new-assets posture
|
|
|
|
**Artifacts**:
|
|
|
|
- [data-model.md](data-model.md)
|
|
- [contracts/customer-review-workspace.openapi.yaml](contracts/customer-review-workspace.openapi.yaml)
|
|
- [quickstart.md](quickstart.md)
|
|
|
|
## Phase 2 — Planning (for tasks.md)
|
|
|
|
Dependency-ordered implementation outline for the later `tasks.md` step:
|
|
|
|
1. Add a native `CustomerReviewWorkspace` admin page and Blade view in the reviews family, keeping the action surface read-only and customer-safe.
|
|
2. Reuse or minimally extend `TenantReviewRegisterService` to resolve workspace access, entitled tenants, and the latest published review per entitled tenant with the required eager loads.
|
|
3. Compose row content from existing review summary / section payloads, `ArtifactTruthPresenter`, current export review-pack relationships, and `RedactionIntegrity` notes, without creating a new presenter or persistence layer.
|
|
4. Preserve launch-context tenant prefiltering and Livewire-safe filter state using the same workspace-page state patterns already proven in `ReviewRegister` and `EvidenceOverview`.
|
|
5. Wire the dominant inspect action to the existing tenant-scoped review detail route and keep review-pack download on the current signed route; evidence drilldown remains explicit and capability-gated.
|
|
6. Reuse the audit pipeline for explicit artifact access or download events only if the current path does not already emit a truthful stable event; do not add a new audit store.
|
|
7. Add focused feature coverage for page behavior, authorization, and pack access, then one browser smoke test for calm disclosure and absence of admin controls. Run Pint after implementation.
|
|
|
|
## Guardrail / Exception / Smoke Coverage
|
|
|
|
- Guardrail result: PASS. Filament remains v5 on Livewire v4, panel provider registration stays unchanged in `apps/platform/bootstrap/providers.php`, the feature adds no new globally searchable Resource, no destructive action on the workspace page, and no new asset bundle. Deployment asset handling stays unchanged: `cd apps/platform && php artisan filament:assets` only matters if future registered assets are added.
|
|
- Shared seam outcome: `TenantReviewRegisterService` remained the entitlement and latest-published query seam. No local helper or second customer-review truth layer was introduced.
|
|
- Launch-path outcome: direct customer-workspace links landed on tenant review detail, review-pack detail, evidence related context, and the tenant review-pack widget. `ReviewRegister` and `EvidenceOverview` were satisfied through existing row/detail navigation reuse instead of duplicate workspace buttons.
|
|
- Read-only detail outcome: the workspace handoff now appends a dedicated customer-workspace context query flag, and `ViewTenantReview` suppresses management actions in that customer-safe flow while preserving the established operator detail route behavior outside that flow.
|
|
- Pack-download outcome: the existing signed route was retained, but it now also enforces tenant membership plus `REVIEW_PACK_VIEW` at request time. That touched download plumbing and required `ReviewPackDownloadTest.php` plus `ReviewPackRbacTest.php` updates.
|
|
- Audit outcome: the existing audit infrastructure was reused with additive `tenant_review.opened` and `review_pack.downloaded` action IDs logged through `WorkspaceAuditLogger`. No new audit store or parallel logging path was introduced.
|
|
- Validation lane result: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php tests/Feature/Reviews/CustomerReviewWorkspaceAuthorizationTest.php tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php tests/Feature/ReviewPack/ReviewPackWidgetTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/ReviewPack/ReviewPackRbacTest.php tests/Feature/TenantReview/TenantReviewUiContractTest.php tests/Browser/Reviews/CustomerReviewWorkspaceSmokeTest.php` passed with `83 passed (372 assertions)`.
|
|
- Smoke evidence: the executed smoke proof was the bounded Pest browser harness in `tests/Browser/Reviews/CustomerReviewWorkspaceSmokeTest.php`, which passed with `1 passed (19 assertions)`. No separate manual integrated-browser run was performed.
|
|
- Formatting result: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` passed.
|
|
- Review outcome class: `acceptable-special-case`.
|
|
- Workflow outcome: `keep`.
|
|
- Exception note: none. The implementation stayed within the planned admin-plane, read-only, shared-primitives-first shape.
|