Automated PR created by Copilot per user request. Branch pushed: 266-tenant-dashboard-productization-v1 Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #322
349 lines
12 KiB
Markdown
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. |