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
7.9 KiB
Data Model — Customer Review Workspace v1
Spec: spec.md
No new persisted tables or customer-review entities are required for v1. The feature reuses existing tenant-owned review, review-pack, evidence, findings, and audit truth, then derives one workspace-scoped read model for page presentation.
Persisted Truth Reused
Workspace / Tenant Entitlement Context
Purpose: Establish the current workspace boundary and the entitled tenant set before any review rows are composed.
Persisted carriers:
- existing workspace membership records
- existing tenant membership pivot records and tenant role assignments
- existing capability registry and role-capability map
Relevant fields / contracts:
workspace_idtenant_id- tenant membership role
- capability grants derived from ../../apps/platform/app/Support/Auth/Capabilities.php
Validation rules:
- current actor must be a member of the current workspace or the page resolves as not found
- tenant rows may only be composed for tenants in the current workspace where the actor is entitled through the canonical role-capability map
- no cross-workspace or cross-tenant fallback lookups are allowed
TenantReview
Purpose: Canonical source for the latest customer-safe review posture, summary text, findings summary, accepted-risk summary, and primary inspect target.
Persisted carrier: existing tenant_reviews rows via TenantReview
Relevant fields / relationships:
idworkspace_idtenant_idstatusgenerated_atpublished_atsummaryevidence_snapshot_idcurrent_export_review_pack_idtenantevidenceSnapshotcurrentExportReviewPacksections
Validation / usage rules:
- the default customer-safe path uses the latest published review per entitled tenant
- draft, ready, failed, archived, and superseded reviews stay off the default-visible page summary unless explicitly reused as internal proof elsewhere
- summary data already shaped into the review artifact remains the preferred source for findings and review-level posture messaging
TenantReviewSection
Purpose: Supporting persisted proof for accepted-risk and section-level disclosure without introducing a new workspace summary store.
Persisted carrier: existing tenant_review_sections rows
Relevant fields / relationships:
tenant_review_idsection_keytitlecompleteness_statesummary_payloadrender_payload
Validation / usage rules:
- accepted-risk summaries should come from the existing review section payloads that were already composed for the review artifact
- section payload reuse must remain read-only and redaction-safe
ReviewPack
Purpose: Canonical packaged artifact for customer-safe review consumption and download.
Persisted carrier: existing review_packs rows via ReviewPack
Relevant fields / relationships:
idworkspace_idtenant_idtenant_review_idstatusgenerated_atexpires_atsummaryfile_pathfile_disksha256tenantReviewevidenceSnapshot
Validation / usage rules:
- download is available only when the current pack is ready and not expired
- the workspace page may surface availability and a signed download path only when
REVIEW_PACK_VIEWapplies - the workspace page must not start generation, regeneration, or recovery flows
EvidenceSnapshot
Purpose: Existing proof artifact for freshness and evidence completeness when the actor explicitly asks for supporting detail.
Persisted carrier: existing evidence_snapshots rows via EvidenceSnapshot
Relevant fields / relationships:
idworkspace_idtenant_idstatuscompleteness_stategenerated_atexpires_atsummaryitems
Validation / usage rules:
- evidence detail is not part of the default-visible customer path
- drilldown remains explicit and capability-gated by
EVIDENCE_VIEW - evidence truth remains tenant-owned and derived from the existing snapshot lifecycle
Audit Log Event Family
Purpose: Existing audit truth for explicit review-artifact access and download actions.
Persisted carrier: existing audit_logs rows via WorkspaceAuditLogger
Relevant fields / contracts:
- stable
AuditActionId workspace_id- optional
tenant_id - actor metadata
- target resource type / id / label
- action context metadata
Validation / usage rules:
- no new audit store is introduced
- explicit artifact open/download events should reuse the current audit pipeline
- page render itself should not become a noisy new audit family
Derived Read Model
CustomerReviewWorkspaceEntry
Purpose: Derived page row or card summarizing the latest customer-safe review state for one entitled tenant.
Persistence: none; computed at request time
Fields:
workspace_idtenant_idtenant_namelatest_published_review_id(nullable)latest_review_generated_at(nullable)latest_review_published_at(nullable)review_outcome_label(nullable, derived from existing artifact truth)review_outcome_explanation(nullable)key_findings_summary(nullable, derived from existing review summary)accepted_risk_summary(nullable, derived from existing review section payloads)review_pack_id(nullable)review_pack_available(boolean)review_pack_status_note(nullable derived string)evidence_snapshot_id(nullable)primary_review_url(nullable)review_pack_download_url(nullable)evidence_detail_url(nullable)redaction_note(nullable)absence_note(nullable derived string)
Derivation rules:
- exactly one entry exists per entitled tenant visible in the current workspace scope
- when a published review exists, the entry derives customer-safe posture from that latest published review only
- when no published review exists for an entitled tenant, the entry may carry a derived absence note such as
No published review available yet; this remains view logic, not domain state - raw JSON, raw provider payloads, unrestricted audit metadata, fingerprints, and debug-only context are never part of the entry
Validation rules:
- entries may only be built for tenants in the current workspace and current entitlement scope
review_pack_download_urlis present only when a current pack exists and the actor can view itevidence_detail_urlis present only when the actor can view evidence detail- absence or unavailable wording must not hint at hidden drafts or hidden operator-only artifacts
Request-Scoped Page State
CustomerReviewWorkspaceState
Purpose: Livewire-safe page state carrying tenant launch context and remembered filters.
Persistence: request, query, and session-backed page state only
Fields:
tenant_id(nullable requested prefilter)highlight_tenant_id(nullable)launch_source(nullable string such as review, review_pack, evidence, or dashboard)search(nullable)tableFilters(session-backed when the implementation uses table filters)
Validation rules:
- requested tenant filters must resolve to an entitled tenant or the page should respond as not found for explicit tenant targeting
- state that needs to survive Livewire interactions must remain hydrated public or query/session-backed state
- if implementation adds a secondary status filter, it must operate on customer-safe derived labels only, not raw internal lifecycle states
State Transition Summary
This slice introduces no new persisted lifecycle or status family. Only derived page-state transitions are expected:
- default workspace view -> tenant-prefiltered view
- tenant-prefiltered view -> cleared workspace view
- published review available -> inspect or download action available subject to capability checks
- no published review available -> truthful absence message only
No queue, publish, generate, regenerate, remediate, or archive transition belongs to this page.