TenantAtlas/specs/179-provider-truth-cleanup/contracts/provider-truth-cleanup.openapi.yaml
ahmido dc46c4fa58 feat: complete provider truth cleanup (#207)
## Summary
- implement Spec 179 to make tenant lifecycle, provider consent, and provider verification the primary truth axes on the targeted Filament surfaces
- demote legacy tenant app status and legacy provider status and health to diagnostic-only roles, add centralized badge mappings for provider consent and verification, and keep provider connections excluded from global search
- add the full Spec 179 artifact set under `specs/179-provider-truth-cleanup/` plus focused Pest coverage for tenant truth cleanup, provider truth cleanup, RBAC, discovery safety, and badge semantics
- fix the numeric out-of-scope tenant route regression so inaccessible `/admin/tenants/{id}` paths return `404 Not Found` instead of `500`

## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionTruthCleanupSpec179Test.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/RequiredFiltersTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Tenants/TenantProviderConnectionsCtaTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Rbac/TenantResourceAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionListAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Rbac/AdminGlobalSearchContextSafetyTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantGlobalSearchLifecycleScopeTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantScopingTest.php`
- `vendor/bin/sail artisan test --compact tests/Unit/Badges/TenantBadgesTest.php`
- `vendor/bin/sail artisan test --compact tests/Unit/Badges/ProviderConnectionBadgesTest.php`

## Manual validation
- integrated-browser smoke on `/admin/tenants`, tenant detail, `/admin/provider-connections`, provider detail, and provider edit
- verified out-of-scope tenant and provider URLs return `404 Not Found` with the current session

## Notes
- branch: `179-provider-truth-cleanup`
- commit: `e54c6632`
- target: `dev`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #207
2026-04-05 00:48:31 +00:00

390 lines
12 KiB
YAML

openapi: 3.1.0
info:
title: Provider Truth Cleanup Internal Surface Contract
version: 0.1.0
summary: Internal planning contract for tenant and provider status-truth cleanup
description: |
This contract is an internal planning artifact for Spec 179. The affected
routes continue to render HTML. The schemas below describe the structured
truth that must be derivable before rendering so tenant and provider
surfaces stop elevating legacy status projections over lifecycle, consent,
and verification.
servers:
- url: /internal
x-surface-consumers:
- surface: tenant.list
summarySource:
- tenant.lifecycle
- optional_bounded_provider_signal
guardScope:
- app/Filament/Resources/TenantResource.php
expectedContract:
- lifecycle_is_primary_tenant_truth
- legacy_app_status_is_not_default_visible
- provider_signal_may_be_omitted_if_no_truthful_bounded_summary_exists
- surface: tenant.detail.provider_summary
summarySource:
- tenant.lifecycle
- tenant.provider_connection_state_helper
- provider_connection.consent_status
- provider_connection.verification_status
- latest_provider_connection_check_run
guardScope:
- app/Filament/Resources/TenantResource.php
- resources/views/filament/infolists/entries/provider-connection-state.blade.php
- app/Filament/Widgets/Tenant/TenantVerificationReport.php
expectedContract:
- lifecycle_is_separate_from_provider_truth
- provider_summary_leads_with_consent_and_verification
- legacy_status_and_health_are_diagnostic_only
- missing_default_connection_never_reads_as_ready
- surface: provider_connections.list
summarySource:
- provider_connection.consent_status
- provider_connection.verification_status
- provider_connection.connection_type
- provider_connection.is_default
- provider_connection.legacy_diagnostics
guardScope:
- app/Filament/Resources/ProviderConnectionResource.php
- app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php
expectedContract:
- consent_and_verification_are_default_visible_axes
- legacy_status_and_health_are_secondary
- core_filters_follow_leading_truth
- surface: provider_connections.detail
summarySource:
- provider_connection.consent_status
- provider_connection.verification_status
- provider_connection.legacy_diagnostics
guardScope:
- app/Filament/Resources/ProviderConnectionResource.php
- app/Filament/Resources/ProviderConnectionResource/Pages/ViewProviderConnection.php
- app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
expectedContract:
- current_state_and_diagnostics_are_visually_separate
- configured_or_consented_is_not_equated_with_verified
- legacy_diagnostics_do_not_dominate
paths:
/admin/tenants:
get:
summary: Render the tenant list with lifecycle-led truth and no legacy app-status prominence
operationId: viewTenantListTruthCleanup
responses:
'200':
description: Tenant list rendered with lifecycle as the primary tenant truth and no default-visible app-status truth
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.tenant-list-truth+json:
schema:
$ref: '#/components/schemas/TenantListTruthBundle'
'404':
description: Workspace or tenant scope is outside entitlement
/admin/tenants/{tenant}:
get:
summary: Render tenant detail with lifecycle and provider truth separated
operationId: viewTenantTruthDetail
parameters:
- name: tenant
in: path
required: true
schema:
type: string
responses:
'200':
description: Tenant detail rendered with lifecycle separate from provider consent and provider verification
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.tenant-detail-truth+json:
schema:
$ref: '#/components/schemas/TenantDetailTruthModel'
'404':
description: Tenant is outside entitlement scope
/admin/provider-connections:
get:
summary: Render the canonical provider-connections list with consent and verification as primary axes
operationId: viewProviderConnectionsTruthList
responses:
'200':
description: Provider-connection list rendered with current-state truth leading and legacy diagnostics secondary
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.provider-connections-list-truth+json:
schema:
$ref: '#/components/schemas/ProviderConnectionListTruthBundle'
'302':
description: Workspace members without an active tenant filter or equivalent context may be redirected according to existing canonical-admin rules
'404':
description: Workspace or tenant scope is outside entitlement
/admin/provider-connections/{record}:
get:
summary: Render provider connection detail with current state and diagnostics separated
operationId: viewProviderConnectionTruthDetail
parameters:
- name: record
in: path
required: true
schema:
type:
- integer
- string
responses:
'200':
description: Provider-connection detail rendered with consent and verification as the leading state contract
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.provider-connection-detail-truth+json:
schema:
$ref: '#/components/schemas/ProviderConnectionDetailTruthModel'
'403':
description: Actor is in scope but lacks the capability required for a protected action on the page
'404':
description: Provider connection is outside entitlement scope
/admin/provider-connections/{record}/edit:
get:
summary: Render provider connection edit with current state context before mutations
operationId: editProviderConnectionTruthDetail
parameters:
- name: record
in: path
required: true
schema:
type:
- integer
- string
responses:
'200':
description: Provider-connection edit page rendered with current consent and verification context and separate diagnostics
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.provider-connection-edit-truth+json:
schema:
$ref: '#/components/schemas/ProviderConnectionDetailTruthModel'
'403':
description: Actor is in scope but lacks manage capability
'404':
description: Provider connection is outside entitlement scope
components:
schemas:
VisibilityMode:
type: string
enum:
- hidden
- diagnostic
- primary
ProviderSignal:
type: object
required:
- mode
- explanation
properties:
mode:
type: string
enum:
- omitted
- missing_default_connection
- consent_verification_summary
consentStatus:
type:
- string
- 'null'
verificationStatus:
type:
- string
- 'null'
explanation:
type: string
TenantListRow:
type: object
required:
- tenantId
- tenantLabel
- lifecycle
- legacyAppStatusVisibility
- primaryInspectUrl
properties:
tenantId:
type: integer
tenantLabel:
type: string
lifecycle:
type: string
providerSignal:
oneOf:
- $ref: '#/components/schemas/ProviderSignal'
- type: 'null'
legacyAppStatusVisibility:
$ref: '#/components/schemas/VisibilityMode'
primaryInspectUrl:
type: string
TenantListTruthBundle:
type: object
required:
- rows
properties:
rows:
type: array
items:
$ref: '#/components/schemas/TenantListRow'
TenantProviderSummary:
type: object
required:
- connectionPresence
- ctaUrl
- legacyStatusVisibility
- legacyHealthVisibility
properties:
connectionPresence:
type: string
enum:
- missing
- configured
- default_configured
ctaUrl:
type: string
displayName:
type:
- string
- 'null'
provider:
type:
- string
- 'null'
consentStatus:
type:
- string
- 'null'
verificationStatus:
type:
- string
- 'null'
lastCheckedAt:
type:
- string
- 'null'
lastErrorReasonCode:
type:
- string
- 'null'
legacyStatusVisibility:
$ref: '#/components/schemas/VisibilityMode'
legacyHealthVisibility:
$ref: '#/components/schemas/VisibilityMode'
TenantDetailTruthModel:
type: object
required:
- tenantId
- lifecycle
- providerSummary
properties:
tenantId:
type: integer
lifecycle:
type: string
providerSummary:
$ref: '#/components/schemas/TenantProviderSummary'
verificationReportSurface:
type: string
description: Existing tenant verification widget remains the deep-dive verification surface
ProviderConnectionListItem:
type: object
required:
- connectionId
- displayName
- provider
- connectionType
- isDefault
- consentStatus
- verificationStatus
- legacyStatusVisibility
- legacyHealthVisibility
- primaryInspectUrl
properties:
connectionId:
type: integer
tenantLabel:
type:
- string
- 'null'
displayName:
type: string
provider:
type: string
connectionType:
type: string
isDefault:
type: boolean
consentStatus:
type: string
verificationStatus:
type: string
legacyStatusVisibility:
$ref: '#/components/schemas/VisibilityMode'
legacyHealthVisibility:
$ref: '#/components/schemas/VisibilityMode'
primaryInspectUrl:
type: string
ProviderConnectionListTruthBundle:
type: object
required:
- rows
properties:
rows:
type: array
items:
$ref: '#/components/schemas/ProviderConnectionListItem'
ProviderConnectionDetailTruthModel:
type: object
required:
- connectionId
- displayName
- provider
- connectionType
- isDefault
- consentStatus
- verificationStatus
- legacyStatusVisibility
- legacyHealthVisibility
properties:
connectionId:
type: integer
displayName:
type: string
provider:
type: string
connectionType:
type: string
isDefault:
type: boolean
consentStatus:
type: string
verificationStatus:
type: string
lastCheckedAt:
type:
- string
- 'null'
lastErrorReasonCode:
type:
- string
- 'null'
lastErrorMessage:
type:
- string
- 'null'
migrationReviewRequired:
type: boolean
legacyStatusVisibility:
$ref: '#/components/schemas/VisibilityMode'
legacyHealthVisibility:
$ref: '#/components/schemas/VisibilityMode'