TenantAtlas/specs/111-findings-workflow-sla/contracts/api-contracts.md
ahmido 7ac53f4cc4 feat(111): findings workflow + SLA settings (#135)
Implements spec 111 (Findings workflow + SLA) and fixes Workspace findings SLA settings UX/validation.

Key changes:
- Findings workflow service + SLA policy and alerting.
- Workspace settings: allow partial SLA overrides without auto-filling unset severities in the UI; effective values still resolve via defaults.
- New migrations, jobs, command, UI/resource updates, and comprehensive test coverage.

Tests:
- `vendor/bin/sail artisan test --compact` (1779 passed, 8 skipped).

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #135
2026-02-25 01:48:01 +00:00

5.3 KiB

API Contracts: 111 — Findings Workflow V2 + SLA

Date: 2026-02-24
Branch: 111-findings-workflow-sla


Overview

This feature does not introduce new external REST endpoints. User interaction is through Filament/Livewire actions on the Findings Resource and Alert Rules configuration. The only new cross-module “contract” is the sla_due alert event produced during scheduled alert evaluation and consumed by the Alerts dispatch pipeline.


1. Alert Event Contract: sla_due

Producer: App\Jobs\Alerts\EvaluateAlertsJob
Event Type: AlertRule::EVENT_SLA_DUE (sla_due)
Event Cardinality: At most 1 event per tenant per evaluation window (when newly-overdue findings exist)

Eligibility (Per Tenant)

An event is produced when a tenant has one or more newly-overdue open findings since the previous evaluation window:

  • status IN (new, triaged, in_progress, reopened)
  • due_at <= now()
  • due_at > windowStart

Terminal statuses (resolved, closed, risk_accepted) never contribute to overdue evaluation.

Event Payload Shape

{
  "event_type": "sla_due",
  "tenant_id": 123,
  "severity": "high",
  "fingerprint_key": "sla_due:tenant:123",
  "title": "SLA overdue findings detected",
  "body": "Tenant Contoso has 5 overdue open findings (critical: 1, high: 2, medium: 2, low: 0).",
  "metadata": {
    "overdue_total": 5,
    "overdue_by_severity": {
      "critical": 1,
      "high": 2,
      "medium": 2,
      "low": 0
    }
  }
}

Severity Semantics

severity is the maximum severity among overdue open findings for that tenant at evaluation time.

Rationale: alert rules can use minimum_severity; a critical-overdue case can bypass a “high-only” rule.


2. Filament Findings Resource: Workflow Actions Contract

All workflow actions:

  • enforce tenant membership as deny-as-not-found (404) for non-members
  • enforce capability checks (403 for members lacking capability)
  • write an audit log entry with before/after and any reason fields

List Defaults

Default list shows:

  • all finding types (no drift-only default)
  • open statuses only: new, triaged, in_progress, reopened

Quick filters:

  • Open
  • Overdue (due_at < now() and open statuses)
  • High severity (high + critical)
  • My assigned (assignee_user_id = current user)

Row Actions (More menu)

Action Allowed From Status To Status Capability Confirmation Notes
Triage new, reopened triaged TENANT_FINDINGS_TRIAGE (or legacy TENANT_FINDINGS_ACKNOWLEDGE alias) No Sets triaged_at
Start progress triaged in_progress TENANT_FINDINGS_TRIAGE (or legacy alias) No Sets in_progress_at
Assign open statuses unchanged TENANT_FINDINGS_ASSIGN No Sets assignee_user_id and optional owner_user_id (picker limited to tenant members)
Resolve open statuses resolved TENANT_FINDINGS_RESOLVE Yes Requires resolved_reason; sets resolved_at
Close any status closed TENANT_FINDINGS_CLOSE Yes Requires closed_reason; sets closed_at + closed_by_user_id
Risk accept any status risk_accepted TENANT_FINDINGS_RISK_ACCEPT Yes Requires reason (stored as closed_reason); sets closed_at + closed_by_user_id
Reopen resolved, closed, risk_accepted reopened TENANT_FINDINGS_TRIAGE (or legacy alias) Yes Manual reopen only. Automatic reopen is allowed only from resolved during detection.

Bulk Actions

Bulk actions are all-or-nothing (if any record is unauthorized for the current tenant context, the action is disabled):

Action Capability Confirmation Notes
Bulk triage TENANT_FINDINGS_TRIAGE (or legacy alias) Yes (typed confirm for large selections) Moves `new
Bulk assign TENANT_FINDINGS_ASSIGN Yes (typed confirm for large selections) Assignee/owner pickers limited to tenant members
Bulk resolve TENANT_FINDINGS_RESOLVE Yes Reason required
Bulk close TENANT_FINDINGS_CLOSE Yes Reason required
Bulk risk accept TENANT_FINDINGS_RISK_ACCEPT Yes Reason required

3. Backfill/Consolidation Operation Contract

Backfill is a tenant-context operation that upgrades legacy findings to v2 lifecycle fields and consolidates drift duplicates. It MUST be OperationRun-backed and use OPS-UX feedback surfaces (queued toast, progress surfaces, initiator-only completion notification).

OperationRun type: findings.lifecycle.backfill (label registered in OperationCatalog)
Idempotency: One active run per tenant (deduped by OperationRun identity)

Summary counts use canonical numeric keys only (e.g., total, processed, updated, failed, skipped).


4. Audit Contract (Tenant Scope)

Every workflow mutation writes a tenant audit record (via App\Services\Intune\AuditLogger) with:

  • action string (e.g., finding.triaged, finding.resolved, finding.closed, finding.risk_accepted, finding.reopened, findings.lifecycle.backfill.started)
  • metadata including: finding_id, before_status, after_status, and any reason fields or assignment deltas

Audit payloads must remain sanitized and must not include secrets/tokens.