12 KiB
Data Model — Tenant Dashboard Productization v1
Spec: spec.md
No new persisted tables, dashboard aggregates, or productized score artifacts are required. This slice reuses current tenant-owned governance, exception, operations, review, evidence, and output truth, then tightens the derived dashboard composition contract over those seams.
Persisted Truth Reused
Workspace / Tenant Entitlement Context
Purpose: Establish the active workspace boundary and tenant entitlement before any dashboard summary, link, or canonical follow-up route is composed.
Persisted carriers:
- existing workspace membership rows
- existing tenant membership pivot rows and role assignments
- current workspace context and selected tenant context
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 workspace member or the route resolves as not found
- current actor must be entitled to the tenant or the tenant dashboard and all tenant follow-up routes resolve as not found
- canonical admin follow-up routes launched from the dashboard may only reveal the originating tenant when that tenant is still entitled in the current workspace
Finding and Exception Truth
Purpose: Provide active findings pressure, high-priority follow-up, and accepted-risk or exception readiness truth.
Persisted carriers:
- existing findings rows via current findings resources and services
- existing
finding_exceptionsrows via ../../apps/platform/app/Filament/Resources/FindingExceptionResource.php
Relevant fields / relationships:
- finding severity, status, due or stale markers, and active workflow state
- exception
status - exception
current_validity_state - exception
review_due_at - exception
expires_at - exception owner, approver, and current decision relationships
Validation / usage rules:
- dashboard pressure and recommended-action logic stays tenant-scoped
- accepted-risk and exception summaries remain derived from current finding and exception truth
- no new
accepted riskdashboard entity or separate persistence layer is introduced
Tenant Governance Aggregate
Purpose: Existing derived posture truth for compare readiness, governance pressure, and next-action hints.
Carrier: ../../apps/platform/app/Support/Baselines/TenantGovernanceAggregateResolver.php and related derived-state seams
Relevant fields / contracts:
- aggregate summary assessment
- active findings counts
- governance warning counts
- compare or baseline posture states
- current next-action hints
Validation / usage rules:
- remains derived only
- stays the source for compare or baseline posture, not a new dashboard score
- dashboard composition may reorder or compress the truth but must not fork it into a second status family
Recovery / Restore Readiness Truth
Purpose: Existing restore-readiness and recovery evidence truth used to summarize whether the tenant can be recovered safely.
Persisted carriers:
- existing backup metadata and snapshot records
- existing restore run and recovery evidence records reached through current backup and restore services
Relevant seams:
- ../../apps/platform/app/Support/BackupHealth/BackupHealthDashboardSignal.php
- current backup health resolvers
- ../../apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php
Validation / usage rules:
- dashboard recovery and restore status remains derived from current safety evidence
- no new recovery status persistence or dashboard-only restore state is introduced
OperationRun
Purpose: Canonical truth for recent execution state and follow-up-worthy operations.
Persisted carrier: existing operation_runs rows via ../../apps/platform/app/Models/OperationRun.php
Relevant fields / relationships:
idworkspace_idtenant_idtypestatusoutcomecontextfailure_summarycreated_atstarted_atcompleted_at
Validation / usage rules:
- recent operation summaries remain tenant-scoped on the dashboard
- canonical operations collection and detail routes remain the only drill-through path
- dashboard composition may compress or reorder recent operations, but it does not own lifecycle state
TenantReview
Purpose: Canonical source for current review readiness and review drill-through.
Persisted carrier: existing tenant_reviews rows via ../../apps/platform/app/Models/TenantReview.php
Relevant fields / relationships:
idworkspace_idtenant_idstatusgenerated_atpublished_atsummaryevidence_snapshot_idcurrent_export_review_pack_id- related tenant, evidence snapshot, and current export review pack
Validation / usage rules:
- dashboard review readiness remains derived from existing review and publication truth
- dashboard must not invent a customer-safe output route when no published review or usable pack exists
ReviewPack
Purpose: Existing packaged output artifact for current downloadable review handoff.
Persisted carrier: existing review_packs rows via ../../apps/platform/app/Models/ReviewPack.php
Relevant fields / relationships:
idworkspace_idtenant_idtenant_review_idstatusgenerated_atexpires_atoperation_run_id- related tenant review and evidence snapshot
Validation / usage rules:
- dashboard output readiness must stay anchored to current pack state
- if a start-capable review-pack action is reused, it must keep its existing operation and audit behavior
EvidenceSnapshot
Purpose: Existing proof artifact for evidence availability and drill-through.
Persisted carrier: existing evidence_snapshots rows via ../../apps/platform/app/Models/EvidenceSnapshot.php
Relevant fields / relationships:
idworkspace_idtenant_idstatusgenerated_atexpires_atsummaryitems
Validation / usage rules:
- evidence readiness stays optional and lower-priority than the main governance decision
- raw evidence payloads remain off the default-visible dashboard
Required Permissions Comparison
Purpose: Current provider-blockage truth for missing permissions and freshness.
Carrier: ../../apps/platform/app/Services/Intune/TenantRequiredPermissionsViewModelBuilder.php
Relevant fields / contracts:
overview.overalloverview.counts.missing_applicationoverview.counts.missing_delegatedoverview.freshness.last_refreshed_atoverview.freshness.is_stalefeature_impacts
Validation / usage rules:
- remains derived only
- powers the provider-health summary card and required-permissions CTA
- no new tenant provider-health persistence is introduced
Derived Read Models
TenantDashboardSummary
Purpose: Derived page-level contract for the productized tenant landing surface.
Persistence: none; computed at request time
Fields:
workspacetenantcontext_chipsheader_actionskpisrecommended_actionsgovernance_status_rowsrecent_operationscurrent_reviewrisk_exception_summaryprovider_health_summaryoutput_readiness_summaryarrival_context(nullable)
Derivation rules:
- exactly one summary exists per current workspace + tenant pair
- top-level counts, badges, and actions derive only from existing repo-real truth and explicit fallback states
- hidden actions are omitted entirely; visible but blocked paths become explicit unavailable states only when the operator still needs the summary context
- the summary owns ordering, not a new truth family
DashboardHeaderAction
Purpose: Derived contract for the capped page-header CTA set.
Persistence: none
Fields:
labelurloraction_keystyle(primaryorsecondary)availability_statehelper_text(nullable)
Validation rules:
- at most 2 visible header actions
- any unavailable action must be explicit and must not appear as a clickable dead end
- no destructive action is introduced on the dashboard shell
DashboardKpiCard
Purpose: Derived posture card shown in the first KPI row.
Persistence: none
Fields:
keylabelvaluesupporting_textstatus_labelbadge_statetrend_label(nullable)primary_link(nullable)
Validation rules:
- at most 4 cards
- cards may use honest fallback labels such as
Unavailable,Not configured, orNo data yet - cards must not invent new score semantics or fake trend data
RecommendedDashboardAction
Purpose: Derived next-step record for the central decision card.
Persistence: none
Fields:
prioritytitlereasonimpactcategory(nullable)cta_labelcta_urlavailability_statehelper_text(nullable)
Derivation rules:
- ordered by bounded priority: governance pressure, provider blockage, pending risk or exception decisions, restore-readiness gaps, evidence or review readiness gaps, operation follow-up
- hidden actions are omitted from the list entirely
Validation rules:
- at most 3 actions
- each action owns exactly 1 dominant CTA
- if no action is needed, the list becomes a positive empty state rather than an empty shell
GovernanceStatusRow
Purpose: Derived compact status digest row for one readiness family.
Persistence: none
Fields:
keylabeldescriptionstatus_labelbadge_statesupport_link(nullable)
Validation rules:
- rows remain read-only summaries
- unknown or missing truth becomes
Unavailableor equivalent fallback, never green by default
RecentOperationSummary
Purpose: Derived compact recency row for the dashboard operations card.
Persistence: none
Fields:
operation_run_idlabelstatus_labeloutcome_labelrelative_timesummary_textdetail_url
Validation rules:
- at most 4 rows
- remains clearly diagnostic and secondary to the primary decision layer
SummaryCardState
Purpose: Shared derived state for current review, risk-exception, provider-health, and output-readiness cards.
Persistence: none
Fields:
titleheadlinesupporting_linescta_label(nullable)cta_url(nullable)availability_statehelper_text(nullable)
Validation rules:
- each card gets at most 1 dominant CTA
- cards without repo-real follow-up routes remain read-only readiness summaries
Derived Disclosure States
This feature introduces no new persisted lifecycle or enum family. It does require explicit derived action and disclosure states across the dashboard:
available: the actor can follow the link or perform the existing reused action nowabsent: the underlying artifact or condition does not exist yetunavailable: the condition exists conceptually, but the actor cannot act because of capability, readiness, or current state constraints
Hidden actions are omitted from the derived models entirely rather than stored as a visible state.