TenantAtlas/specs/266-tenant-dashboard-productization-v1/data-model.md
Ahmed Darrazi beebbaefbe
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 5m58s
chore: commit all local changes
2026-05-03 16:00:44 +02:00

349 lines
12 KiB
Markdown

# Data Model — Tenant Dashboard Productization v1
**Spec**: [spec.md](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_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 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_exceptions` rows via [../../apps/platform/app/Filament/Resources/FindingExceptionResource.php](../../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 risk` dashboard 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](../../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](../../apps/platform/app/Support/BackupHealth/BackupHealthDashboardSignal.php)
- current backup health resolvers
- [../../apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php](../../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](../../apps/platform/app/Models/OperationRun.php)
**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `type`
- `status`
- `outcome`
- `context`
- `failure_summary`
- `created_at`
- `started_at`
- `completed_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](../../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`
- 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](../../apps/platform/app/Models/ReviewPack.php)
**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `tenant_review_id`
- `status`
- `generated_at`
- `expires_at`
- `operation_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](../../apps/platform/app/Models/EvidenceSnapshot.php)
**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `status`
- `generated_at`
- `expires_at`
- `summary`
- `items`
**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](../../apps/platform/app/Services/Intune/TenantRequiredPermissionsViewModelBuilder.php)
**Relevant fields / contracts**:
- `overview.overall`
- `overview.counts.missing_application`
- `overview.counts.missing_delegated`
- `overview.freshness.last_refreshed_at`
- `overview.freshness.is_stale`
- `feature_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**:
- `workspace`
- `tenant`
- `context_chips`
- `header_actions`
- `kpis`
- `recommended_actions`
- `governance_status_rows`
- `recent_operations`
- `current_review`
- `risk_exception_summary`
- `provider_health_summary`
- `output_readiness_summary`
- `arrival_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**:
- `label`
- `url` or `action_key`
- `style` (`primary` or `secondary`)
- `availability_state`
- `helper_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**:
- `key`
- `label`
- `value`
- `supporting_text`
- `status_label`
- `badge_state`
- `trend_label` (nullable)
- `primary_link` (nullable)
**Validation rules**:
- at most 4 cards
- cards may use honest fallback labels such as `Unavailable`, `Not configured`, or `No 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**:
- `priority`
- `title`
- `reason`
- `impact`
- `category` (nullable)
- `cta_label`
- `cta_url`
- `availability_state`
- `helper_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**:
- `key`
- `label`
- `description`
- `status_label`
- `badge_state`
- `support_link` (nullable)
**Validation rules**:
- rows remain read-only summaries
- unknown or missing truth becomes `Unavailable` or equivalent fallback, never green by default
### RecentOperationSummary
**Purpose**: Derived compact recency row for the dashboard operations card.
**Persistence**: none
**Fields**:
- `operation_run_id`
- `label`
- `status_label`
- `outcome_label`
- `relative_time`
- `summary_text`
- `detail_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**:
- `title`
- `headline`
- `supporting_lines`
- `cta_label` (nullable)
- `cta_url` (nullable)
- `availability_state`
- `helper_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 now
- `absent`: the underlying artifact or condition does not exist yet
- `unavailable`: 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.