TenantAtlas/specs/189-portfolio-triage-review-state/contracts/portfolio-triage-review-state.logical.openapi.yaml
ahmido 2f45ff5a84 feat: add portfolio triage review state tracking (#220)
## Summary
- add tenant triage review-state persistence, fingerprinting, resolver logic, service layer, and migration for current affected-set tracking
- surface review-state and affected-set progress across tenant registry, tenant dashboard arrival continuity, and workspace overview
- extend RBAC, audit/badge support, specs, and test coverage for portfolio triage review-state workflows
- suppress expected hidden-page background transport failures in the global unhandled rejection logger while keeping visible-page failures logged

## Validation
- targeted Pest coverage added for tenant registry, workspace overview, arrival context, RBAC authorization, badges, fingerprinting, resolver behavior, and logger asset behavior
- code formatted with `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes
- full suite was not re-run in this final step
- branch includes the spec artifacts under `specs/189-portfolio-triage-review-state/`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #220
2026-04-10 21:35:17 +00:00

436 lines
12 KiB
YAML

openapi: 3.1.0
info:
title: Portfolio Triage Review State Internal Surface Contract
version: 0.1.0
summary: Internal logical contract for persisted triage-review state, current-set progress, and operator mutations
description: |
This contract is an internal planning artifact for Spec 189. The affected routes still
render HTML through Filament and Livewire. The schemas below describe the bounded read
models and mutation payloads that must be derivable or writable before portfolio-triage
surfaces render review-state badges, progress summaries, or mutation actions.
servers:
- url: /internal
x-triage-review-consumers:
- surface: workspace.overview.progress
sourceFiles:
- apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
- apps/platform/app/Filament/Widgets/Workspace/WorkspaceSummaryStats.php
- apps/platform/app/Filament/Widgets/Workspace/WorkspaceNeedsAttention.php
mustRender:
- concern_family
- affected_total
- reviewed_count
- follow_up_needed_count
- changed_since_review_count
- surface: tenant.registry.triage
sourceFiles:
- apps/platform/app/Filament/Resources/TenantResource.php
- apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php
mustRender:
- concern_family
- derived_review_state
- reviewed_at
- reviewed_by_user_id
mustAccept:
- review_state
- backup_posture
- recovery_evidence
- triage_sort
- surface: tenant.dashboard.arrival
sourceFiles:
- apps/platform/app/Filament/Pages/TenantDashboard.php
- apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php
mustRender:
- concern_family
- derived_review_state
- mark_reviewed_action
- mark_follow_up_needed_action
paths:
/admin:
get:
summary: Workspace overview exposes current-set triage progress summaries
operationId: viewWorkspaceOverviewWithTriageReviewProgress
responses:
'200':
description: Rendered workspace overview with additive progress summary semantics
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.workspace-triage-progress+json:
schema:
$ref: '#/components/schemas/WorkspaceTriageProgressBundle'
'404':
description: Workspace scope is not available to the actor
/admin/tenants:
get:
summary: Tenant registry triage renders review-state badges and accepts review-state filters
operationId: viewTenantRegistryWithTriageReviewState
parameters:
- name: backup_posture
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/BackupConcernState'
- name: recovery_evidence
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/RecoveryConcernState'
- name: review_state
in: query
required: false
schema:
type: array
items:
$ref: '#/components/schemas/DerivedReviewState'
- name: triage_sort
in: query
required: false
schema:
type: string
enum:
- worst_first
responses:
'200':
description: Rendered tenant registry with concern truth plus review-state context
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.tenant-registry-triage-review+json:
schema:
$ref: '#/components/schemas/TenantRegistryTriageReviewBundle'
'404':
description: Workspace scope is not available to the actor
/admin/t/{tenant}:
get:
summary: Tenant dashboard arrival continuity shows the current review state for the focused concern family
operationId: viewTenantDashboardWithTriageReviewState
parameters:
- name: tenant
in: path
required: true
schema:
type: string
- name: arrival
in: query
required: false
schema:
type: string
description: Existing portfolio-arrival token carrying concern-family focus.
responses:
'200':
description: Rendered tenant dashboard with optional continuity review-state controls
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.tenant-dashboard-triage-review+json:
schema:
$ref: '#/components/schemas/TenantDashboardTriageReviewBundle'
'404':
description: Tenant is outside workspace or tenant entitlement scope
/internal/workspaces/{workspace}/tenants/{tenant}/triage-review-state:
put:
summary: Upsert the active triage-review record for one workspace, tenant, and concern family
operationId: upsertTenantTriageReviewState
parameters:
- name: workspace
in: path
required: true
schema:
type: integer
- name: tenant
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TriageReviewMutationRequest'
responses:
'200':
description: Active review record updated and current derived state returned
content:
application/vnd.tenantpilot.triage-review-state+json:
schema:
$ref: '#/components/schemas/TriageReviewMutationResult'
'403':
description: Actor is in scope but lacks the capability to mutate triage review state
'404':
description: Workspace or tenant is outside the actor's entitlement scope
components:
schemas:
ConcernFamily:
type: string
enum:
- backup_health
- recovery_evidence
BackupConcernState:
type: string
enum:
- absent
- stale
- degraded
RecoveryConcernState:
type: string
enum:
- unvalidated
- weakened
ConcernState:
type: string
enum:
- absent
- stale
- degraded
- unvalidated
- weakened
ManualReviewState:
type: string
enum:
- reviewed
- follow_up_needed
DerivedReviewState:
type: string
enum:
- not_reviewed
- reviewed
- follow_up_needed
- changed_since_review
TriageReviewSnapshot:
type: object
additionalProperties: false
required:
- concernFamily
- concernState
properties:
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
concernState:
$ref: '#/components/schemas/ConcernState'
reasonCode:
type:
- string
- 'null'
severityKey:
type:
- string
- 'null'
supportingKey:
type:
- string
- 'null'
ActiveTriageReviewRecord:
type: object
additionalProperties: false
required:
- workspaceId
- tenantId
- concernFamily
- currentState
- reviewedAt
- reviewFingerprint
properties:
workspaceId:
type: integer
tenantId:
type: integer
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
currentState:
$ref: '#/components/schemas/ManualReviewState'
reviewedAt:
type: string
format: date-time
reviewedByUserId:
type:
- integer
- 'null'
reviewFingerprint:
type: string
reviewSnapshot:
$ref: '#/components/schemas/TriageReviewSnapshot'
lastSeenMatchingAt:
type:
- string
- 'null'
format: date-time
resolvedAt:
type:
- string
- 'null'
format: date-time
ResolvedTriageReviewState:
type: object
additionalProperties: false
required:
- concernFamily
- derivedState
- currentConcernPresent
properties:
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
derivedState:
$ref: '#/components/schemas/DerivedReviewState'
currentConcernPresent:
type: boolean
currentFingerprint:
type:
- string
- 'null'
reviewedAt:
type:
- string
- 'null'
format: date-time
reviewedByUserId:
type:
- integer
- 'null'
snapshot:
anyOf:
- $ref: '#/components/schemas/TriageReviewSnapshot'
- type: 'null'
TriageProgressSummary:
type: object
additionalProperties: false
required:
- concernFamily
- affectedTotal
- reviewedCount
- followUpNeededCount
- changedSinceReviewCount
- notReviewedCount
properties:
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
affectedTotal:
type: integer
reviewedCount:
type: integer
followUpNeededCount:
type: integer
changedSinceReviewCount:
type: integer
notReviewedCount:
type: integer
TriageReviewMutationRequest:
type: object
additionalProperties: false
required:
- concernFamily
- state
- currentFingerprint
- snapshot
properties:
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
state:
$ref: '#/components/schemas/ManualReviewState'
currentFingerprint:
type: string
snapshot:
$ref: '#/components/schemas/TriageReviewSnapshot'
sourceSurface:
type:
- string
- 'null'
enum:
- tenant_registry
- tenant_dashboard_arrival
- null
TriageReviewMutationResult:
type: object
additionalProperties: false
required:
- activeRecord
- resolvedState
properties:
activeRecord:
$ref: '#/components/schemas/ActiveTriageReviewRecord'
resolvedState:
$ref: '#/components/schemas/ResolvedTriageReviewState'
WorkspaceTriageProgressBundle:
type: object
additionalProperties: false
required:
- summaries
properties:
summaries:
type: array
items:
$ref: '#/components/schemas/TriageProgressSummary'
TenantRegistryRowReviewState:
type: object
additionalProperties: false
required:
- tenantId
- concernFamily
- derivedState
properties:
tenantId:
type: integer
concernFamily:
$ref: '#/components/schemas/ConcernFamily'
derivedState:
$ref: '#/components/schemas/DerivedReviewState'
reviewedAt:
type:
- string
- 'null'
format: date-time
reviewedByUserId:
type:
- integer
- 'null'
TenantRegistryTriageReviewBundle:
type: object
additionalProperties: false
required:
- rows
properties:
concernFamilyFocus:
type:
- string
- 'null'
enum:
- backup_health
- recovery_evidence
- null
rows:
type: array
items:
$ref: '#/components/schemas/TenantRegistryRowReviewState'
activeFilters:
type:
- object
- 'null'
additionalProperties: true
TenantDashboardTriageReviewBundle:
type: object
additionalProperties: false
required:
- canRenderReviewControls
properties:
concernFamilyFocus:
anyOf:
- $ref: '#/components/schemas/ConcernFamily'
- type: 'null'
reviewState:
anyOf:
- $ref: '#/components/schemas/ResolvedTriageReviewState'
- type: 'null'
canRenderReviewControls:
type: boolean
markReviewedAllowed:
type: boolean
markFollowUpNeededAllowed:
type: boolean