TenantAtlas/specs/111-findings-workflow-sla/quickstart.md
2026-02-25 02:45:20 +01:00

3.9 KiB

Quickstart: 111 — Findings Workflow V2 + SLA

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


Prerequisites

  • Sail services running (vendor/bin/sail up -d)
  • Database migrated to latest
  • At least one workspace with at least one tenant
  • Queue worker running for queued jobs (e.g., vendor/bin/sail artisan queue:work)

Implementation Phases

Phase 1: Data Layer (Findings v2 Columns + Badges + Settings)

Goal: Extend findings to v2 lifecycle fields and add SLA policy setting.

  1. Migrations (add v2 columns + indexes; two-phase if enforcing NOT NULL after backfill)
  2. Update App\Models\Finding constants for v2 statuses and severities
  3. BADGE-001: extend Finding status badge mapping to include v2 statuses (and legacy acknowledged mapping)
  4. Settings:
    • Add findings.sla_days to SettingsRegistry
    • Expose in Workspace Settings UI (JSON textarea), validate via registry rules

Run: vendor/bin/sail artisan migrate && vendor/bin/sail artisan test --compact --filter=SettingsRegistry


Phase 2: Workflow + RBAC (Server-Side Enforcement + Filament Actions)

Goal: Enforce transition rules, write timestamps, and provide safe UI actions.

  1. Capabilities:
    • Add new TENANT_FINDINGS_* constants
    • Keep TENANT_FINDINGS_ACKNOWLEDGE as triage alias (migration window)
    • Update RoleCapabilityMap
  2. Policy/service layer:
    • Enforce allowed transitions server-side
    • Require reasons for resolve/close/risk accept
    • Audit log every mutation (before/after + reason fields)
  3. Filament FindingResource:
    • Remove drift-only default filters
    • Default to Open statuses across all finding types
    • Add quick filters (Open/Overdue/High severity/My assigned)
    • Add row actions + bulk actions per spec (grouped under “More”)

Run: vendor/bin/sail artisan test --compact --filter=FindingWorkflow


Phase 3: Generators (Lifecycle Fields + Drift Recurrence + Stale Resolve)

Goal: Ensure findings lifecycle fields and recurrence behavior are maintained automatically.

  1. Drift:
    • Compute recurrence_key and upsert by it
    • Auto-reopen only from resolved into reopened
    • Auto-resolve stale drift for a scope when no longer detected (resolved_reason=no_longer_detected)
  2. Permission posture + Entra roles:
    • Preserve existing reopen/auto-resolve behavior
    • Add lifecycle fields: first/last seen, times_seen, due_at/sla_days

Run: vendor/bin/sail artisan test --compact --filter=FindingRecurrence


Phase 4: Alerts (SLA Due Producer + UI Re-Enable)

Goal: Make sla_due alert rules functional.

  1. Add SLA due producer to EvaluateAlertsJob that emits one tenant-level event summarizing overdue counts.
  2. Re-enable sla_due in AlertRuleResource event type options (only after producer exists).

Manual verification:

  1. Create (or backfill) a finding with due_at in the past and open status.
  2. Run vendor/bin/sail artisan tenantpilot:alerts:dispatch --workspace={id}
  3. Confirm an alert_deliveries row is created for matching enabled rules.

Run: vendor/bin/sail artisan test --compact --filter=FindingSlaDue


Phase 5: Backfill/Consolidation (OperationRun-Backed)

Goal: Upgrade legacy findings and consolidate drift duplicates.

  1. Trigger backfill from tenant context (Filament action and/or an artisan command entrypoint).
  2. Verify OPS-UX:
    • queued toast intent-only
    • progress visible in active ops widget + OperationRun detail
    • exactly one terminal completion notification (initiator-only)
  3. Verify data outcomes:
    • acknowledged → triaged
    • lifecycle fields populated
    • due dates set from backfill time + SLA days for legacy open findings
    • drift duplicates consolidated (one canonical open row per recurrence identity)

Run: vendor/bin/sail artisan test --compact --filter=FindingBackfill


Formatting / Hygiene

  • Run vendor/bin/sail bin pint --dirty before finalizing.