6.7 KiB
6.7 KiB
Data Model: Portfolio Triage Arrival Context
Overview
This feature introduces no new persisted tables or stored entities. The model impact is a small set of request-scoped, derived runtime contracts that connect existing workspace triage truth to tenant-dashboard arrival rendering.
Existing Source Truths
Workspace overview attention item
Type: Existing derived workspace summary payload
Source: WorkspaceOverviewBuilder
| Field | Type | Notes |
|---|---|---|
tenant_route_key |
string | Tenant route identifier already used in workspace attention items |
family |
string | Existing concern family, such as backup_health or recovery_evidence |
title |
string | Operator-facing concern headline |
body |
string | Operator-facing bounded summary |
supporting_message |
string or null | Existing claim-boundary or next-step phrasing |
reason_context.family |
enum | backup_health or recovery_evidence |
reason_context.state |
enum | Existing posture state emitted from workspace triage |
reason_context.reason |
string or null | Existing bounded reason code |
destination.kind |
string | Existing destination type |
destination.url |
string or null | Existing destination URL |
destination.disabled |
bool | Existing capability-aware destination availability |
destination.helper_text |
string or null | Existing degraded-access explanation |
Tenant-registry triage state
Type: Existing query-driven list state
Source: ListTenants::applyRequestedTriageIntent()
| Field | Type | Validation |
|---|---|---|
backup_posture |
array | Sanitized through TenantResource::sanitizeBackupPostures() |
recovery_evidence |
array | Sanitized through TenantResource::sanitizeRecoveryEvidenceStates() |
triage_sort |
string or null | Sanitized through TenantResource::sanitizeTriageSort() |
Existing destination continuity inputs
Type: Existing route-level continuity params
| Surface | Param | Purpose |
|---|---|---|
| Backup-set list | backup_health_reason |
Explains why backup detail or backup list was opened |
| Restore-run list | recovery_posture_reason |
Explains why restore history was opened |
| Restore-run detail | recovery_posture_reason |
Explains why a specific restore run was opened |
New Derived Runtime Contracts
PortfolioArrivalContext
Type: Request-scoped value object
Lifecycle: Decoded from a tenant-dashboard query token, validated against current scope, discarded after the request completes
| Field | Type | Validation |
|---|---|---|
version |
integer | Must match the current token version |
sourceSurface |
enum | workspace_overview or tenant_registry |
tenantRouteKey |
string | Must match the current tenant route or resolve to the same tenant |
workspaceId |
integer or null | Optional scope binding; when present, must match current workspace context |
concernFamily |
enum | backup_health or recovery_evidence |
concernState |
enum | absent, stale, degraded, unvalidated, or weakened |
concernReason |
string or null | Allowlisted per concern family |
arrivalSummary |
string | Derived bounded explanation of why the operator arrived |
claimBoundary |
string or null | Derived reminder that arrival reason is not a stronger truth than current evidence supports |
nextStep |
NextStepTarget |
Capability-aware navigation target |
returnTarget |
ReturnTarget |
Portfolio return link with bounded route and query state |
currentTruthDelta |
string or null | Optional note when current tenant truth differs from the arrival reason |
NextStepTarget
Type: Request-scoped navigation descriptor
| Field | Type | Notes |
|---|---|---|
kind |
enum | tenant_dashboard, backup_sets, restore_runs, restore_run_detail |
label |
string | Operator-facing next-step verb + object label |
url |
string or null | Null when unavailable under current RBAC |
disabled |
bool | True when the user can see the arrival block but cannot access the target |
helperText |
string or null | Truthful reason the next step cannot be opened |
reasonParam |
array<string, scalar> | Existing backup_health_reason or recovery_posture_reason continuation payload when needed |
ReturnTarget
Type: Request-scoped navigation descriptor
| Field | Type | Notes |
|---|---|---|
kind |
enum | workspace_overview or tenant_registry |
label |
string | Operator-facing return label |
url |
string | Canonical return URL |
filters |
array<string, mixed> | Allowlisted triage filters and sort state for registry returns |
Validation Rules
Concern family and state compatibility
| Concern Family | Allowed States | Allowed Reasons |
|---|---|---|
backup_health |
absent, stale, degraded |
Existing TenantBackupHealthAssessment reason constants that justify tenant-opening triage |
recovery_evidence |
unvalidated, weakened |
Existing restore-safety or recovery-triage reason codes such as no_history, failed, partial, or completed_with_follow_up |
Token decode rules
- Empty, malformed, or unsupported-version tokens decode to
null. - Unknown families, states, reasons, or return kinds decode to
null. - Tokens bound to a different tenant route or incompatible workspace context decode to
null. - Successful decode does not replace current tenant truth; it only authorizes rendering of the continuity block.
Return filter rules
- Registry return filters may include only the existing triage keys:
backup_posture,recovery_evidence, andtriage_sort. - Filter values must pass the same sanitizers used by
ListTenantson mount. - Unknown or empty filters are dropped from the return target.
Relationships
- One workspace attention item may generate one
PortfolioArrivalContextwhen its destination is a tenant-level surface. - One filtered tenant-registry session may generate one
PortfolioArrivalContextper tenant-open action. - One
PortfolioArrivalContextowns exactly oneNextStepTargetand oneReturnTarget. - One tenant dashboard request may resolve zero or one valid
PortfolioArrivalContext.
Rendering Rules
- No valid
PortfolioArrivalContextmeans the tenant dashboard renders normally with no continuity block. - A valid
PortfolioArrivalContextmay render even if current tenant truth has changed, but the block must differentiate arrival reason from current truth. NextStepTarget.disabled = truestill allows the block to render, but the CTA must be absent or disabled with helper text.ReturnTargetrenders only when the origin surface can be reconstituted safely.