TenantAtlas/specs/094-assignment-ops-observability-hardening/contracts/assignment-ops.openapi.yaml
ahmido bda1d90fc4 Spec 094: Assignment ops observability hardening (#113)
Implements spec 094 (assignment fetch/restore observability hardening):

- Adds OperationRun tracking for assignment fetch (during backup) and assignment restore (during restore execution)
- Normalizes failure codes/reason_code and sanitizes failure messages
- Ensures exactly one audit log entry per assignment restore execution
- Enforces correct guard/membership vs capability semantics on affected admin surfaces
- Switches assignment Graph services to depend on GraphClientInterface

Also includes Postgres-only FK defense-in-depth check and a discoverable `composer test:pgsql` runner (scoped to the FK constraint test).

Tests:
- `vendor/bin/sail artisan test --compact` (passed)
- `vendor/bin/sail composer test:pgsql` (passed)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #113
2026-02-15 14:08:14 +00:00

128 lines
3.7 KiB
YAML

openapi: 3.0.3
info:
title: TenantPilot - Assignment Operations (Internal)
version: "1.0"
description: |
Internal contract describing the user-triggered operation start surfaces and Monitoring read surfaces
relevant to assignment fetch/restore observability.
servers:
- url: /
paths:
/admin/t/{tenant}/backup-items/{backupItem}/assignments/fetch:
post:
summary: Start assignment fetch/enrichment
parameters:
- in: path
name: tenant
required: true
schema: { type: string }
- in: path
name: backupItem
required: true
schema: { type: integer }
responses:
"202":
description: Accepted; operation run created/reused and job enqueued
content:
application/json:
schema:
$ref: "#/components/schemas/OperationRunStartResponse"
"403": { description: Forbidden (member missing capability) }
"404": { description: Not found (non-member / wrong plane) }
/admin/t/{tenant}/restore-runs/{restoreRun}/assignments/restore:
post:
summary: Start assignment restore
parameters:
- in: path
name: tenant
required: true
schema: { type: string }
- in: path
name: restoreRun
required: true
schema: { type: integer }
responses:
"202":
description: Accepted; operation run created/reused and job enqueued
content:
application/json:
schema:
$ref: "#/components/schemas/OperationRunStartResponse"
"403": { description: Forbidden (member missing capability) }
"404": { description: Not found (non-member / wrong plane) }
/admin/monitoring/operations:
get:
summary: List operation runs (Monitoring)
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/OperationRunSummary"
/admin/monitoring/operations/{operationRun}:
get:
summary: Get operation run detail (Monitoring)
parameters:
- in: path
name: operationRun
required: true
schema: { type: integer }
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/OperationRunDetail"
"404": { description: Not found (non-member / no entitlement) }
components:
schemas:
OperationRunStartResponse:
type: object
required: [operationRunId]
properties:
operationRunId:
type: integer
OperationRunSummary:
type: object
required: [id, type, status, outcome, createdAt]
properties:
id: { type: integer }
type: { type: string }
status: { type: string }
outcome: { type: string }
createdAt: { type: string, format: date-time }
OperationRunDetail:
allOf:
- $ref: "#/components/schemas/OperationRunSummary"
- type: object
properties:
startedAt: { type: string, format: date-time, nullable: true }
completedAt: { type: string, format: date-time, nullable: true }
context:
type: object
additionalProperties: true
failures:
type: array
items:
$ref: "#/components/schemas/FailureItem"
FailureItem:
type: object
required: [code, reasonCode, message]
properties:
code: { type: string }
reasonCode: { type: string }
message: { type: string }