4.0 KiB
4.0 KiB
Data Model: 111 — Findings Workflow V2 + SLA
Date: 2026-02-24
Branch: 111-findings-workflow-sla
Modified Entities
1. findings Table (Lifecycle + SLA + Recurrence)
This feature evolves findings from v1 (new|acknowledged|resolved) to a v2 workflow and adds lifecycle metadata and SLA fields.
New Columns
| Column | Type | Constraints | Notes |
|---|---|---|---|
first_seen_at |
timestampTz |
nullable initially; NOT NULL after backfill | Set on first observation; backfill from created_at where possible |
last_seen_at |
timestampTz |
nullable initially; NOT NULL after backfill | Updated on every observation (including terminal findings) |
times_seen |
integer |
default 0, NOT NULL (after backfill enforce) |
Incremented on every observation |
sla_days |
smallint |
nullable | SLA policy value applied when due_at was set/reset |
due_at |
timestampTz |
nullable | Only “open” findings participate in SLA due evaluation |
owner_user_id |
bigint |
FK → users, nullable | Retained even if user is no longer a tenant member |
assignee_user_id |
bigint |
FK → users, nullable | Retained even if user is no longer a tenant member |
triaged_at |
timestampTz |
nullable | Set on `new |
in_progress_at |
timestampTz |
nullable | Set on triaged → in_progress |
reopened_at |
timestampTz |
nullable | Set when transitioning into reopened (manual or automatic) |
closed_at |
timestampTz |
nullable | Used for both closed and risk_accepted terminal outcomes |
closed_by_user_id |
bigint |
FK → users, nullable | Actor for closed / risk_accepted |
closed_reason |
string |
nullable | Reason required for closed and risk_accepted |
recurrence_key |
string(64) |
nullable; indexed | Stable identity for drift recurrence (v2) |
Existing Columns Used/Extended
| Column | Notes |
|---|---|
status |
Extended v2 statuses (see below). Legacy acknowledged is mapped to v2 triaged in the UI and migrated during backfill. |
resolved_at / resolved_reason |
Remains the terminal “resolved” record with reason. |
acknowledged_at / acknowledged_by_user_id |
Retained for historical reference; acknowledged status is legacy. |
fingerprint |
Remains unique per tenant. For canonical drift rows going forward, the fingerprint is stable (aligned to recurrence identity). |
Status Values (Canonical)
Open statuses:
newtriagedin_progressreopened
Terminal statuses:
resolvedclosedrisk_accepted
Legacy status (migration window):
acknowledged(treated astriagedin v2 surfaces)
Indexes
New/updated indexes to support list filters and alert evaluation:
| Index | Type | Purpose |
|---|---|---|
(tenant_id, status, due_at) |
btree | Open/overdue filtering in tenant UI |
(tenant_id, assignee_user_id) |
btree | “My assigned” filter |
(tenant_id, recurrence_key) |
btree | Drift recurrence lookups and consolidation |
(workspace_id, status, due_at) |
btree | Workspace-scoped SLA due producer query |
Existing index (tenant_id, status) remains valid.
Configuration Keys (No Schema Change)
Settings: Findings SLA policy
Add a SettingsRegistry entry (workspace-resolvable):
findings.sla_days(JSON object): severity → days- Default:
- critical: 3
- high: 7
- medium: 14
- low: 30
Stored in existing workspace_settings / tenant_settings tables; no new tables required.
State Machine (High-Level)
new ──triage──> triaged ──start──> in_progress ──resolve──> resolved
└───────────────────────────────close/risk_accept──────────────> closed|risk_accepted
resolved ──(auto or manual)──> reopened ──triage──> triaged ...
closed|risk_accepted ──(manual only)──> reopened