TenantAtlas/specs/258-customer-review-productization/data-model.md
ahmido 966b7af472
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m0s
feat: productize customer review workspace (#310)
## Summary
- productize the customer review workspace and released-review drilldown into a calmer customer-safe governance flow
- make review-pack and evidence-proof access explicit, capability-aware, and auditable in the shared Filament resources
- add focused Pest coverage, browser smoke coverage, and the full Spec 258 artifact package

## Notes
- Filament stays on v5 with Livewire v4 surfaces; no provider registration changes were introduced
- no new global-search scope, destructive action surface, or asset registration was added
- bounded additive audit action IDs were added for workspace open and evidence proof open events

## Validation
- focused Pest feature suites for workspace, review detail, review-pack, and evidence flows
- bounded browser smoke: `tests/Browser/Reviews/CustomerReviewWorkspaceSmokeTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #310
2026-04-30 18:15:32 +00:00

12 KiB

Data Model — Customer Review Workspace Productization v1

Spec: 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:

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

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

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

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

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

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