Files
cve-dashboard/docs/guides/time-based-reporting-recommendations.md

334 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Time-Based Reporting Recommendations
**Date:** 2026-04-02
**Author:** Engineering (Claude Code)
**Status:** Draft — for director review
---
## Executive Summary
This document analyzes the current CVE Dashboard data model and recommends a set of time-based visualizations that can be added to the Reporting page. Recommendations are grouped by feasibility: **Tier 1** can be built with data already in the database, **Tier 2** requires a lightweight new tracking table, and **Tier 3** requires structural additions.
---
## Current Data Inventory
### What Already Has Time-Series History
| Source | Table | Date Fields | History? |
|--------|-------|-------------|----------|
| Compliance uploads | `compliance_uploads` | `report_date`, `uploaded_at` | **Yes** — one row per report cycle |
| Compliance items | `compliance_items` | `created_at`, `first_seen_upload_id`, `resolved_upload_id` | **Yes** — tracks lifecycle |
| Archer tickets | `archer_tickets` | `created_at`, `updated_at` | **Yes** — full history |
| Todo queue | `ivanti_todo_queue` | `created_at`, `updated_at` | **Yes** — by action |
| Finding notes | `ivanti_finding_notes` | `updated_at` | **Yes** — note activity |
### What Is Point-in-Time Only (no history yet)
| Source | Table | Problem |
|--------|-------|---------|
| Ivanti findings | `ivanti_findings_cache` | Single-row cache — overwritten on every sync |
| Ivanti counts | `ivanti_counts_cache` | Single-row cache — no snapshots stored |
| FP workflow states | Computed from `findings_json` | Ephemeral — not persisted historically |
---
## Tier 1 Recommendations — Build Now (No Schema Changes)
All of these use data that is already in the database.
---
### 1.1 Compliance Trend Line — Total Active Findings Over Time
**Description:** A line chart showing the total number of active (non-compliant) items per compliance upload date. This directly answers "are we improving over time?"
**Data Source:**
```sql
SELECT
cu.report_date,
COUNT(ci.id) AS active_count
FROM compliance_uploads cu
JOIN compliance_items ci ON ci.upload_id = cu.id AND ci.status = 'active'
GROUP BY cu.id
ORDER BY cu.report_date ASC;
```
**Chart Type:** Line chart with data points per upload
**Axes:** X = Report Date, Y = Number of Active Findings
**Value-add:** Overlay a trend line (linear regression) to show trajectory
---
### 1.2 New / Recurring / Resolved Bar Chart — Per Report Cycle
**Description:** A grouped or stacked bar chart showing the delta breakdown for each compliance upload: how many findings were newly introduced, how many recurred from a prior cycle, and how many were resolved.
**Data Source:** Already computed and stored in `compliance_uploads`:
```sql
SELECT report_date, new_count, recurring_count, resolved_count
FROM compliance_uploads
ORDER BY report_date ASC;
```
**Chart Type:** Stacked bar chart (one bar per upload date)
**Legend:** New (red/amber), Recurring (yellow), Resolved (green)
**Value-add:** Shows whether each reporting cycle is improving (more resolved than new) or degrading
---
### 1.3 Team Compliance Health Over Time — Multi-Line Chart
**Description:** A multi-line chart showing the active finding count per team per upload date. Answers "which team is trending better or worse?"
**Data Source:**
```sql
SELECT
cu.report_date,
ci.team,
COUNT(ci.id) AS active_count
FROM compliance_uploads cu
JOIN compliance_items ci ON ci.upload_id = cu.id AND ci.status = 'active'
GROUP BY cu.id, ci.team
ORDER BY cu.report_date ASC;
```
**Chart Type:** Multi-line chart (one line per team)
**Teams:** STEAM, ACCESS-ENG, ACCESS-OPS, INTELDEV
**Value-add:** Immediately visible which team is outlier or improving fastest
---
### 1.4 Mean Time to Resolution (MTTR) — Per Team
**Description:** A bar chart showing average number of upload cycles between when a finding first appeared and when it was resolved, broken out by team.
**Data Source:**
```sql
SELECT
ci.team,
AVG(ci.resolved_upload_id - ci.first_seen_upload_id) AS avg_cycles_to_resolve,
COUNT(*) AS resolved_count
FROM compliance_items ci
WHERE ci.resolved_upload_id IS NOT NULL
GROUP BY ci.team;
```
**Chart Type:** Horizontal bar chart
**Axes:** Y = Team, X = Average Cycles to Resolution
**Value-add:** Normalize to calendar days by joining with upload dates for true MTTR in days
---
### 1.5 Recurring Findings Heatmap — Seen Count Distribution
**Description:** A heatmap or bubble chart showing findings grouped by how many times they have recurred (`seen_count`). Identifies chronic, long-standing compliance gaps.
**Data Source:**
```sql
SELECT
team,
metric_id,
metric_desc,
seen_count,
COUNT(*) AS host_count
FROM compliance_items
WHERE status = 'active'
GROUP BY team, metric_id
ORDER BY seen_count DESC;
```
**Chart Type:** Horizontal bar chart sorted by `seen_count`, grouped by team
**Value-add:** Highlights the "chronic" findings that repeatedly appear — high priority for remediation
---
### 1.6 Archer Exception Ticket Status Over Time
**Description:** A line chart or cumulative area chart showing Archer ticket status transitions over time using `created_at` and `updated_at`.
**Data Source:**
```sql
SELECT
DATE(created_at) AS date,
status,
COUNT(*) AS count
FROM archer_tickets
GROUP BY DATE(created_at), status
ORDER BY date ASC;
```
**Chart Type:** Stacked area chart
**Statuses:** Draft, Open, Under Review, Accepted
**Value-add:** Tracks exception request pipeline velocity — are exceptions getting processed or stacking up?
---
### 1.7 Compliance Category Breakdown Over Time
**Description:** A stacked area chart showing what categories of compliance failures are driving the total over time (if the `category` field in `compliance_items` is populated).
**Data Source:**
```sql
SELECT
cu.report_date,
ci.category,
COUNT(ci.id) AS count
FROM compliance_uploads cu
JOIN compliance_items ci ON ci.upload_id = cu.id AND ci.status = 'active'
WHERE ci.category IS NOT NULL
GROUP BY cu.id, ci.category
ORDER BY cu.report_date ASC;
```
**Chart Type:** Stacked area chart
**Value-add:** Shows whether one category dominates or if failures are spread across areas
---
## Tier 2 Recommendations — Lightweight Schema Addition Required
These require adding one new table to persist snapshots of data that is currently overwritten on each sync.
---
### 2.1 Ivanti Findings Count Over Time — Open vs Closed Trend
**Description:** The single most-requested metric: "are we making progress on vulnerabilities?" A line chart showing open and closed Ivanti finding counts over time.
**Problem:** The current `ivanti_counts_cache` is a single-row table overwritten on each sync. No history is kept.
**Solution:** Add a `ivanti_counts_history` table and append a row on every successful sync:
```sql
CREATE TABLE ivanti_counts_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
open_count INTEGER NOT NULL,
closed_count INTEGER NOT NULL,
recorded_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
**Backend change:** In the sync route (`POST /api/ivanti/findings/sync`), after updating the cache, also `INSERT INTO ivanti_counts_history`.
**New API endpoint:** `GET /api/ivanti/findings/counts/history`
```sql
SELECT open_count, closed_count, recorded_at
FROM ivanti_counts_history
ORDER BY recorded_at ASC;
```
**Chart Type:** Dual-line chart
**Lines:** Open findings (red), Closed findings (green)
**Value-add:** Most direct measure of vulnerability remediation velocity
---
### 2.2 FP Workflow State Snapshots Over Time
**Description:** A stacked area or line chart showing how FP workflow states (Actionable, Requested, Approved, Rejected, Expired) trend over sync cycles.
**Solution:** Add a `ivanti_fp_workflow_history` table:
```sql
CREATE TABLE ivanti_fp_workflow_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
state TEXT NOT NULL,
finding_count INTEGER NOT NULL DEFAULT 0,
id_count INTEGER NOT NULL DEFAULT 0,
recorded_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
```
**Chart Type:** Stacked area chart
**Value-add:** Shows whether FP requests are being worked through or stacking up in "Requested" state
---
### 2.3 Todo Queue Velocity — Items Added vs Completed Per Week
**Description:** A bar chart showing weekly queue throughput (items added vs items marked complete).
**Data Source:** Already available in `ivanti_todo_queue.created_at` and `updated_at` + `status = 'complete'`:
```sql
SELECT
STRFTIME('%Y-W%W', created_at) AS week,
COUNT(*) AS items_added,
SUM(CASE WHEN status = 'complete' THEN 1 ELSE 0 END) AS items_completed
FROM ivanti_todo_queue
GROUP BY week
ORDER BY week ASC;
```
**Chart Type:** Grouped bar chart (weekly)
**Value-add:** Measures operational pace of the team's workflow action throughput
---
## Tier 3 Recommendations — Structural Additions (Future Consideration)
These require more significant changes but would provide powerful long-term reporting.
---
### 3.1 Finding Age / Dwell Time Distribution
**Description:** A histogram showing how long open findings have been open (age in days). The `lastFoundOn` field exists in the Ivanti findings JSON but is not persisted to a structured table.
**Requirement:** Parse and store `lastFoundOn` from findings JSON into a structured column during sync.
**Value-add:** Highlights findings that have been open for 90+ days — high-priority remediation targets.
---
### 3.2 SLA Breach Trends
**Description:** Track how many findings breach SLA (Due Date exceeded) over time. Currently SLA status is computed in the frontend on-the-fly.
**Requirement:** Add SLA breach tracking during sync — stamp findings that cross SLA date.
**Value-add:** Compliance and audit reporting for SLA adherence metrics.
---
## Recommended Implementation Order
| Priority | Chart | Effort | Impact |
|----------|-------|--------|--------|
| 1 | 1.2 — New/Recurring/Resolved bar chart | Low (data ready) | High |
| 2 | 1.1 — Compliance trend line | Low (data ready) | High |
| 3 | 1.3 — Team health multi-line | Low (data ready) | High |
| 4 | 2.1 — Ivanti open/closed history | Medium (new table) | Very High |
| 5 | 1.4 — MTTR per team | Low (data ready) | Medium |
| 6 | 1.6 — Archer ticket pipeline | Low (data ready) | Medium |
| 7 | 2.3 — Queue velocity | Low (data ready) | Medium |
| 8 | 1.5 — Recurring findings heatmap | Low (data ready) | Medium |
| 9 | 2.2 — FP workflow snapshots | Medium (new table) | Medium |
| 10 | 1.7 — Category breakdown | Low (data ready) | LowMedium |
---
## Charting Library Consideration
The current implementation uses **hand-rolled SVG donut charts** (no external library). For time-series line/bar/area charts, the team should decide:
| Option | Pros | Cons |
|--------|------|------|
| **Continue hand-rolled SVG** | Zero dependencies, full style control | Significant effort for axes, labels, tooltips |
| **Recharts** (React-native) | Well-matched to React 19, composable, responsive | ~500KB dependency |
| **Chart.js via react-chartjs-2** | Mature, widely documented | Less React-idiomatic |
| **Lightweight: uPlot or Chart.xkcd** | Very small bundle | Less community support |
**Recommendation:** Recharts aligns best with the React 19 stack and allows declaring charts as JSX components consistent with the existing code style. It supports all chart types listed above.
---
## Notes for Director Review
- All **Tier 1** recommendations can be implemented with zero database migrations — the data is already there.
- The **single highest-value addition** is `2.1 — Ivanti open/closed count history`, as it captures the most direct remediation progress metric. It only requires one new table and one line added to the sync handler.
- **Compliance charts (1.11.5)** will only be meaningful once multiple compliance uploads have been committed. If only 12 uploads exist currently, the trend will not show much until more data accumulates — but building the charts now means data will automatically populate them.
- All queries listed above have been validated against the actual database schema.
---
*Next step: Review with director, confirm priority order, then schedule sprint for implementation.*