# Data Model — Customer Review Workspace Productization v1

**Spec**: [spec.md](spec.md)

No new persisted tables, projections, or customer-review entities are required for this follow-up. The feature reuses current tenant-owned review, finding-exception, evidence, review-pack, membership, and audit truth, then tightens the derived workspace and detail presentation contracts.

## Persisted Truth Reused

### Workspace / Tenant Entitlement Context

**Purpose**: Establish the active workspace boundary and the entitled tenant set before any workspace rows, proof links, or review detail routes are composed.

**Persisted carriers**:
- existing workspace membership records
- existing tenant membership pivot rows and 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)
- current workspace and remembered tenant context from the existing workspace context/session model

**Validation rules**:
- current actor must be a member of the current workspace or the route resolves as not found
- workspace rows and explicit tenant filters may only resolve for entitled tenants in that current workspace
- out-of-scope tenant targets remain `404` and must not leak draft/review existence

### TenantReview

**Purpose**: Canonical source for the released governance record, current outcome summary, findings summary, accepted-risk summary, proof pointers, and review-detail inspect target.

**Persisted carrier**: existing `tenant_reviews` rows via [../../apps/platform/app/Models/TenantReview.php](../../apps/platform/app/Models/TenantReview.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `status`
- `generated_at`
- `published_at`
- `summary`
- `evidence_snapshot_id`
- `current_export_review_pack_id`
- `published_by_user_id`
- `tenant`
- `evidenceSnapshot`
- `currentExportReviewPack`
- `sections`

**Embedded summary payload currently reused**:
- `finding_count`
- `finding_outcomes`
- `risk_acceptance.status_marked_count`
- `risk_acceptance.valid_governed_count`
- `risk_acceptance.warning_count`
- `publish_blockers`

**Validation / usage rules**:
- the workspace default path continues to use the latest published review per entitled tenant only
- internal-only review states remain off the customer-safe default path
- the customer-workspace drilldown stays on the existing review detail route under the existing query-context flag
- productization may refine how summary data is explained, but it must not move that truth into a new stored model

### FindingException

**Purpose**: Existing accepted-risk and accountability truth used to explain who accepted risk, why it is on record, and whether it needs follow-up.

**Persisted carrier**: existing `finding_exceptions` rows via [../../apps/platform/app/Models/FindingException.php](../../apps/platform/app/Models/FindingException.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `finding_id`
- `status`
- `current_validity_state`
- `requested_at`
- `approved_at`
- `effective_from`
- `expires_at`
- `review_due_at`
- `owner_user_id`
- `approved_by_user_id`
- `current_decision_id`
- `evidence_summary`
- `owner`
- `approver`
- `currentDecision`
- `evidenceReferences`

**Validation / usage rules**:
- accountability summaries should derive from existing owner/approver/current-decision truth where present
- missing accountable-person or accountable-role truth must surface as partial/unavailable disclosure, not fabricated customer-safe copy
- accepted-risk visibility remains read-only in this slice; no edit, renew, revoke, or approval behavior moves into the customer-safe path

### EvidenceSnapshot

**Purpose**: Existing proof artifact for evidence freshness, completeness, and optional supporting detail reached only after explicit user intent.

**Persisted carrier**: existing `evidence_snapshots` rows via [../../apps/platform/app/Models/EvidenceSnapshot.php](../../apps/platform/app/Models/EvidenceSnapshot.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `status`
- `completeness_state`
- `generated_at`
- `expires_at`
- `summary`
- `items`

**Validation / usage rules**:
- evidence proof remains optional, lower-priority, and capability-gated by the current evidence-view path
- raw payloads and unrestricted diagnostics remain out of the default-visible workspace and review detail path
- if implementation adds explicit proof-access auditing, it should stay on the shared audit pipeline

### ReviewPack

**Purpose**: Existing packaged governance artifact for current downloadable review output.

**Persisted carrier**: existing `review_packs` rows via [../../apps/platform/app/Models/ReviewPack.php](../../apps/platform/app/Models/ReviewPack.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `tenant_review_id`
- `status`
- `generated_at`
- `expires_at`
- `summary`
- `file_path`
- `file_disk`
- `sha256`
- `operation_run_id`
- `tenantReview`
- `evidenceSnapshot`

**Validation / usage rules**:
- only current ready, unexpired packs remain available in the customer-safe flow
- review-pack access continues to use the existing signed download route and current capability check
- the feature must not surface generate/regenerate flows, even when a pack is unavailable

### Audit Log Event Family

**Purpose**: Existing auditable truth for explicit customer-review consumption moments.

**Persisted carrier**: existing `audit_logs` rows via [../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php](../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php)

**Relevant current action IDs**:
- `tenant_review.opened`
- `review_pack.downloaded`

**Potential bounded extensions only if implementation confirms a gap**:
- workspace access open event for the customer review workspace route
- evidence proof access open event for proof routes launched from the customer review flow

**Validation / usage rules**:
- auditable access remains on the shared audit path only
- no new audit store or mirror analytics stream is justified
- workspace, tenant, source-surface, and artifact identifiers stay in stable audit metadata when a new access moment is added

## Derived Read Models

### CustomerReviewWorkspaceEntry

**Purpose**: Derived row-level presentation contract for one entitled tenant on the existing workspace page.

**Persistence**: none; computed at request time

**Fields**:
- `workspace_id`
- `tenant_id`
- `tenant_name`
- `latest_published_review_id` (nullable)
- `latest_review_published_at` (nullable)
- `outcome_summary`
- `findings_summary`
- `accepted_risk_accountability_summary`
- `evidence_proof_state`
- `review_pack_state`
- `primary_review_url` (nullable)
- `review_pack_download_url` (nullable)
- `proof_detail_url` (nullable)
- `absence_note` (nullable)
- `unavailable_note` (nullable)
- `redaction_note` (nullable)

**Derivation rules**:
- exactly one derived entry exists per entitled tenant visible in the current workspace scope
- if a published review exists, the entry derives its customer-safe summary from that released record only
- if no published review exists, the entry surfaces an explicit absence note and omits deep links that depend on a released review
- if optional proof or pack access is blocked by capability or artifact state, the review remains readable while the secondary path becomes explicitly unavailable

**Validation rules**:
- entries may only be built for entitled tenants in the active workspace
- `review_pack_download_url` is present only when a current pack exists and the actor can consume it
- `proof_detail_url` is present only when the actor can open the proof route
- raw payloads, unrestricted diagnostics, provider IDs, and copied support context are never part of the default entry model

### CustomerReviewDetailPresentation

**Purpose**: Derived section contract for the existing released-review detail page when it is launched from the customer review workspace.

**Persistence**: none; computed from the existing review record and current query-context flag

**Fields**:
- `review_id`
- `tenant_id`
- `launched_from_customer_workspace` (boolean)
- `narrative_outcome_summary`
- `findings_summary`
- `accepted_risk_accountability_summary`
- `evidence_summary`
- `proof_pointer_state`
- `review_pack_state`
- `operator_actions_hidden` (boolean)
- `secondary_diagnostics_collapsed` (boolean)

**Derivation rules**:
- only the existing `customer_workspace` query context activates this productized secondary presentation mode
- the detail remains readable even when optional pack/evidence capabilities are absent
- management actions remain suppressed in this context

**Validation rules**:
- this derived model must not create a second review detail route or a second stored summary object
- secondary proof and support detail remain lower-priority than the narrative governance record
- duplicate equal-priority summary blocks between workspace and detail should be removed or reduced

### CustomerReviewPageState

**Purpose**: Request/query/session-backed page state already required for tenant-prefilter, remembered scope, and launch context continuity.

**Persistence**: request, URL query, and existing session-backed table state only

**Fields**:
- `tenant` prefilter (nullable)
- remembered tenant id in workspace context (nullable)
- `customer_workspace` detail context flag (boolean on the detail route)
- navigation context metadata when launched from other canonical pages (nullable)

**Validation rules**:
- explicit tenant prefilters must resolve to an entitled tenant or the request fails as not found
- any state required after Livewire interaction must remain hydrated via public/query/session-backed state
- no private property may own the control path for disclosure or filter restore

## Derived Disclosure States

This feature introduces no new persisted lifecycle or enum family. It does require explicit derived disclosure outcomes on existing surfaces:

- `available`: the actor can open the review/proof/pack path now
- `absent`: the underlying released artifact does not exist for this tenant yet
- `unavailable`: the artifact exists conceptually but is not currently consumable because of capability, readiness, or redaction limits
- `expired`: the artifact exists and was previously consumable, but time-based or release-lifecycle rules now block access while the surface still needs to explain why
- `redacted`: the route or surface remains visible, but protected details stay hidden behind existing redaction rules
- `partial`: the governance record is readable, but accountability/proof detail is incomplete in current source truth

These remain derived page semantics only and must not become stored status families.

## State Transition Summary

No new persisted lifecycle is added. Only derived surface transitions are expected:

- workspace open -> entitled tenant rows or truthful empty/absence state
- remembered tenant or explicit tenant query -> tenant-prefiltered workspace view
- workspace row with released review -> existing review detail route available
- workspace row without released review -> explicit absence state and no review-open action
- released review detail with optional proof/pack capability missing -> review remains readable and secondary path becomes unavailable
- released review detail with an expired pack/proof artifact -> review remains readable and secondary path becomes explicitly expired
- explicit workspace/review/proof/pack consumption -> shared audit event when covered by the current audit registry or a bounded additive action ID