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
210 lines
7.9 KiB
Markdown
210 lines
7.9 KiB
Markdown
# Data Model — Customer Review Workspace v1
|
|
|
|
**Spec**: [spec.md](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_id`
|
|
- `tenant_id`
|
|
- tenant membership role
|
|
- capability grants derived from [../../apps/platform/app/Support/Auth/Capabilities.php](../../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**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `status`
|
|
- `generated_at`
|
|
- `published_at`
|
|
- `summary`
|
|
- `evidence_snapshot_id`
|
|
- `current_export_review_pack_id`
|
|
- `tenant`
|
|
- `evidenceSnapshot`
|
|
- `currentExportReviewPack`
|
|
- `sections`
|
|
|
|
**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_id`
|
|
- `section_key`
|
|
- `title`
|
|
- `completeness_state`
|
|
- `summary_payload`
|
|
- `render_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**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `tenant_review_id`
|
|
- `status`
|
|
- `generated_at`
|
|
- `expires_at`
|
|
- `summary`
|
|
- `file_path`
|
|
- `file_disk`
|
|
- `sha256`
|
|
- `tenantReview`
|
|
- `evidenceSnapshot`
|
|
|
|
**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_VIEW` applies
|
|
- 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**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `status`
|
|
- `completeness_state`
|
|
- `generated_at`
|
|
- `expires_at`
|
|
- `summary`
|
|
- `items`
|
|
|
|
**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_id`
|
|
- `tenant_id`
|
|
- `tenant_name`
|
|
- `latest_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_url` is present only when a current pack exists and the actor can view it
|
|
- `evidence_detail_url` is 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. |