TenantAtlas/specs/221-findings-operator-inbox/contracts/findings-operator-inbox.logical.openapi.yaml
Ahmed Darrazi 8cc73dff71
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 4m59s
feat: add findings operator inbox
2026-04-21 10:19:14 +02:00

399 lines
12 KiB
YAML

openapi: 3.1.0
info:
title: Findings Operator Inbox Surface Contract
version: 1.0.0
description: >-
Internal reference contract for the canonical My Findings inbox and the
workspace overview Assigned to me signal. The application continues to
return rendered HTML through Filament and Livewire. The vendor media types
below document the structured page models that must be derivable before
rendering. This is not a public API commitment.
paths:
/admin/findings/my-work:
get:
summary: Canonical personal findings inbox
description: >-
Returns the rendered admin-plane inbox for the current user's visible
assigned open findings. Personal assignment scope is fixed. Tenant
prefiltering may be derived from the active admin tenant context.
responses:
'302':
description: Redirects into the existing workspace or tenant chooser flow when membership exists but workspace context is not yet established
'200':
description: Rendered My Findings inbox page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.my-findings-inbox+json:
schema:
$ref: '#/components/schemas/MyFindingsInboxPage'
'404':
description: Workspace scope is not visible because membership is missing or out of scope
/admin:
get:
summary: Workspace overview with assigned-to-me signal
description: >-
Returns the rendered workspace overview. The vendor media type documents
the embedded personal findings signal used to decide whether assigned
findings work exists before opening the inbox.
responses:
'302':
description: Redirects into the existing workspace or tenant chooser flow when membership exists but workspace context is not yet established
'200':
description: Rendered workspace overview page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.workspace-overview-my-findings+json:
schema:
$ref: '#/components/schemas/WorkspaceOverviewMyFindingsSignalSurface'
'404':
description: Workspace scope is not visible because membership is missing or out of scope
/admin/t/{tenant}/findings/{finding}:
get:
summary: Tenant finding detail with inbox continuity support
description: >-
Returns the rendered tenant finding detail page. The logical contract
below documents only the continuity inputs required when the page is
opened from the My Findings inbox.
parameters:
- name: tenant
in: path
required: true
schema:
type: integer
- name: finding
in: path
required: true
schema:
type: integer
- name: nav
in: query
required: false
style: deepObject
explode: true
schema:
$ref: '#/components/schemas/CanonicalNavigationContext'
responses:
'200':
description: Rendered tenant finding detail page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.finding-detail-continuation+json:
schema:
$ref: '#/components/schemas/FindingDetailContinuation'
'403':
description: Viewer is in scope but lacks the existing findings capability for the tenant detail destination
'404':
description: Tenant or finding is not visible because workspace or tenant entitlement is missing
components:
schemas:
MyFindingsInboxPage:
type: object
required:
- header
- appliedScope
- availableFilters
- summaryCounts
- rows
- emptyState
properties:
header:
$ref: '#/components/schemas/InboxHeader'
appliedScope:
$ref: '#/components/schemas/InboxAppliedScope'
availableFilters:
description: Includes the fixed assignee-scope filter plus tenant, overdue, reopened, and high-severity filters. Tenant filter options are derived only from visible capability-eligible tenants.
type: array
items:
$ref: '#/components/schemas/InboxFilterDefinition'
summaryCounts:
$ref: '#/components/schemas/MyFindingsSummaryCounts'
rows:
description: Rows are ordered overdue first, reopened non-overdue second, then remaining findings. Within each bucket, rows with due dates sort by dueAt ascending, rows without due dates sort last, and remaining ties sort by findingId descending.
type: array
items:
$ref: '#/components/schemas/AssignedFindingInboxRow'
emptyState:
oneOf:
- $ref: '#/components/schemas/InboxEmptyState'
- type: 'null'
InboxHeader:
type: object
required:
- title
- description
properties:
title:
type: string
enum:
- My Findings
description:
type: string
clearTenantFilterAction:
oneOf:
- $ref: '#/components/schemas/ActionLink'
- type: 'null'
InboxAppliedScope:
type: object
required:
- workspaceScoped
- assigneeScope
- tenantPrefilterSource
properties:
workspaceScoped:
type: boolean
assigneeScope:
type: string
enum:
- current_user_only
tenantPrefilterSource:
type: string
enum:
- active_tenant_context
- explicit_filter
- none
tenantLabel:
type:
- string
- 'null'
InboxFilterDefinition:
type: object
required:
- key
- label
- fixed
properties:
key:
type: string
enum:
- assignee_scope
- tenant
- overdue
- reopened
- high_severity
label:
type: string
fixed:
type: boolean
options:
type: array
items:
$ref: '#/components/schemas/FilterOption'
FilterOption:
type: object
required:
- value
- label
properties:
value:
type: string
label:
type: string
MyFindingsSummaryCounts:
type: object
description: Counts derived from the currently visible inbox queue after the fixed assignee scope and any active tenant, overdue, reopened, or high-severity filters are applied.
required:
- openAssigned
- overdueAssigned
properties:
openAssigned:
type: integer
minimum: 0
overdueAssigned:
type: integer
minimum: 0
AssignedFindingInboxRow:
type: object
required:
- findingId
- tenantId
- tenantLabel
- summary
- severity
- status
- dueState
- detailUrl
properties:
findingId:
type: integer
tenantId:
type: integer
tenantLabel:
type: string
summary:
type: string
severity:
$ref: '#/components/schemas/Badge'
status:
$ref: '#/components/schemas/Badge'
dueAt:
type:
- string
- 'null'
format: date-time
dueState:
$ref: '#/components/schemas/DueState'
reopened:
type: boolean
ownerLabel:
type:
- string
- 'null'
detailUrl:
type: string
navigationContext:
oneOf:
- $ref: '#/components/schemas/CanonicalNavigationContext'
- type: 'null'
DueState:
type: object
required:
- label
- tone
properties:
label:
type: string
tone:
type: string
enum:
- calm
- warning
- danger
InboxEmptyState:
type: object
required:
- title
- body
- action
properties:
title:
type: string
body:
type: string
reason:
type: string
enum:
- no_visible_assigned_work
- active_tenant_prefilter_excludes_rows
action:
description: For `active_tenant_prefilter_excludes_rows`, clears the tenant prefilter and returns the queue to all visible tenants. For `no_visible_assigned_work`, opens the active tenant's findings list when tenant context exists; otherwise opens `/admin/choose-tenant` so the operator can establish tenant context before entering tenant findings.
$ref: '#/components/schemas/ActionLink'
WorkspaceOverviewMyFindingsSignalSurface:
type: object
required:
- workspaceId
- myFindingsSignal
properties:
workspaceId:
type: integer
myFindingsSignal:
$ref: '#/components/schemas/MyFindingsSignal'
MyFindingsSignal:
type: object
required:
- openAssignedCount
- overdueAssignedCount
- isCalm
- headline
- cta
properties:
openAssignedCount:
type: integer
minimum: 0
overdueAssignedCount:
type: integer
minimum: 0
isCalm:
type: boolean
headline:
type: string
enum:
- Assigned to me
description:
type:
- string
- 'null'
cta:
$ref: '#/components/schemas/OpenMyFindingsActionLink'
FindingDetailContinuation:
type: object
description: Continuity payload for tenant finding detail when it is opened from the My Findings inbox. The backLink is present whenever canonical inbox navigation context is provided and may be null only for direct entry without inbox continuity context.
required:
- findingId
- tenantId
properties:
findingId:
type: integer
tenantId:
type: integer
backLink:
description: Present when the detail page is reached from the My Findings inbox with canonical navigation context; null only for direct navigation that did not originate from the inbox.
oneOf:
- $ref: '#/components/schemas/BackToMyFindingsActionLink'
- type: 'null'
CanonicalNavigationContext:
type: object
required:
- source_surface
- canonical_route_name
properties:
source_surface:
type: string
canonical_route_name:
type: string
tenant_id:
type:
- integer
- 'null'
back_label:
type:
- string
- 'null'
back_url:
type:
- string
- 'null'
ActionLink:
type: object
required:
- label
- url
properties:
label:
type: string
url:
type: string
OpenMyFindingsActionLink:
allOf:
- $ref: '#/components/schemas/ActionLink'
- type: object
properties:
label:
type: string
enum:
- Open my findings
BackToMyFindingsActionLink:
allOf:
- $ref: '#/components/schemas/ActionLink'
- type: object
properties:
label:
type: string
enum:
- Back to my findings
Badge:
type: object
required:
- label
properties:
label:
type: string
color:
type:
- string
- 'null'