Files
cve-dashboard/.kiro/specs/forecast-burndown-chart/tasks.md
Jordan Ramos a61d254ff9 Sync .kiro/ from master — v2.2.0 release batch
New specs: archer-template-library, ccp-metrics-view-restructure,
compliance-list-stale-after-sidebar-edit, compliance-metric-estimated-resolution-date,
compliance-remediation-display-fix, flexible-jira-ticket-creation,
forecast-burndown-chart, granite-loader-export, ivanti-queue-clear-completed-fix,
multi-item-jira-ticket, queue-collapsible-sections, vendor-issue-type-dropdown

New steering: archer-template-gen.md

Updated: migration-registration-check hook, remediation-plan-history spec,
gitlab-workflow, tech, versioning steering files
2026-06-04 11:27:31 -06:00

159 lines
9.1 KiB
Markdown

# Implementation Plan: Forecast Burndown Chart
## Overview
Add a per-metric forecast burndown chart to the CCP Metrics page. A pure helper function (`computeMetricForecastBurndown`) computes forecast projections from device records and historical snapshots. Two new API endpoints serve the metrics list and forecast data. A React frontend renders a metric selector and a ComposedChart (Bar + Line + ReferenceLine) using recharts. No database migrations are needed — the feature reads from existing `compliance_items` and `compliance_snapshots` tables.
## Tasks
- [x] 1. Implement the computeMetricForecastBurndown helper function
- [x] 1.1 Add computeMetricForecastBurndown to backend/helpers/vclHelpers.js
- Implement the pure function accepting `currentDevices`, `totalAssets`, and `historicalSnapshots`
- Return object with `historical`, `forecast`, and `current_snapshot` fields
- Compute `current_snapshot.blockers` (devices with no resolution_date) and `current_snapshot.with_dates` (devices with a resolution_date)
- Compute `compliance_pct` as `ROUND((total_assets - non_compliant) / total_assets * 100, 1)`, returning 0 when totalAssets is 0
- Generate forecast months by iterating forward from current month, decrementing non_compliant as devices reach their resolution_date month
- Treat past-due resolution dates as remediated in the current month
- Hold total_assets constant across all forecast data points
- Terminate forecast when all dated devices are remediated or at 12-month maximum
- Return empty forecast array when all devices are blockers (no resolution dates)
- Export the function for use in route handlers and tests
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 6.5_
- [ ]* 1.2 Write property test: Forecast structure invariant
- **Property 1: Forecast structure invariant**
- **Validates: Requirements 1.4, 3.1, 3.6**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.3 Write property test: Blocker and with_dates partition invariant
- **Property 2: Blocker and with_dates partition invariant**
- **Validates: Requirements 3.2**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.4 Write property test: Compliance percentage formula correctness
- **Property 3: Compliance percentage formula correctness**
- **Validates: Requirements 3.3, 3.10**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.5 Write property test: Forecast non_compliant monotonicity
- **Property 4: Forecast non_compliant monotonicity**
- **Validates: Requirements 3.4**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.6 Write property test: Per-month non_compliant computation correctness
- **Property 5: Per-month non_compliant computation correctness**
- **Validates: Requirements 3.8**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.7 Write property test: Forecast horizon bound
- **Property 6: Forecast horizon bound**
- **Validates: Requirements 1.9, 3.9**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [ ]* 1.8 Write property test: Past-due resolution dates treated as current month
- **Property 7: Past-due resolution dates treated as current month**
- **Validates: Requirements 6.5**
- Test file: `backend/__tests__/forecast-burndown-chart.property.test.js`
- [x] 2. Checkpoint - Helper function verified
- Ensure all tests pass, ask the user if questions arise.
- [x] 3. Implement backend API endpoints
- [x] 3.1 Add GET /metrics-list endpoint to backend/routes/vclMultiVertical.js
- Add route handler at `/metrics-list` with `requireAuth()` middleware
- Query `compliance_items` for distinct metric_ids with active non-compliant devices where vertical IS NOT NULL
- Return JSON array of `{ metric_id, device_count }` sorted by metric_id ascending
- Return empty array when no metrics have active devices
- Return HTTP 500 with `{ "error": "Failed to fetch metrics list" }` on database failure
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6_
- [x] 3.2 Add GET /metric/:metricId/forecast-burndown endpoint to backend/routes/vclMultiVertical.js
- Add route handler with `requireAuth()` middleware
- Query active devices for the metric from `compliance_items` (status = 'active', vertical IS NOT NULL)
- Determine the vertical from active devices and query `compliance_snapshots` for 3 months of historical data
- Compute per-metric historical non_compliant using the ratio method from Requirement 7.2
- Include current month as the most recent historical data point computed from live data
- Pass data to `computeMetricForecastBurndown` helper
- Return response with `metric_id`, `historical`, `forecast`, and `current_snapshot`
- Return 200 with empty arrays and zeroed snapshot when metricId has no active devices
- Return HTTP 500 with `{ "error": "Failed to compute forecast burndown" }` on database failure
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7_
- [ ]* 3.3 Write unit tests for API endpoints
- Test metrics-list returns correct shape with mocked database
- Test forecast-burndown returns correct shape with mocked database
- Test authentication middleware is applied to both endpoints
- Test empty/error states
- Test file: `backend/__tests__/forecast-burndown-chart.test.js`
- _Requirements: 1.7, 1.8, 1.10, 2.4, 2.5, 2.6_
- [x] 4. Checkpoint - Backend complete
- Ensure all tests pass, ask the user if questions arise.
- [x] 5. Implement frontend MetricSelector and ForecastBurndownChart components
- [x] 5.1 Add MetricSelector component to frontend/src/components/pages/CCPMetricsPage.js
- Fetch metrics list from `/api/compliance/vcl-multi/metrics-list` on mount
- Display dropdown showing each metric_id with active non-compliant device count
- Auto-select first metric and trigger forecast data fetch on load
- Handle loading state (non-interactive while fetching)
- Handle empty state ("No metrics with active non-compliant devices")
- Handle error state (inline error with AlertCircle icon, red border)
- On selection change, trigger `onMetricSelect` callback
- _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8_
- [x] 5.2 Add ForecastBurndownChart component to frontend/src/components/pages/CCPMetricsPage.js
- Fetch forecast data from `/api/compliance/vcl-multi/metric/:metricId/forecast-burndown` when metric changes
- Render recharts ComposedChart with:
- Blue Bar for total_assets (left Y-axis)
- Orange Bar for non_compliant (left Y-axis)
- Green Line for compliance_pct (right Y-axis, 0-100%)
- ReferenceLine as vertical divider between historical and forecast sections
- Render forecast data points at 50% opacity
- Display raw device count labels inside bars
- Display compliance percentage labels on the trend line
- X-axis labeled with months (YYYY-MM format)
- Left Y-axis scaled to max total_assets, right Y-axis 0-100%
- Handle loading state (loading indicator in chart area)
- Handle error state (inline error with AlertCircle icon and description)
- Handle empty data state ("No data available for this metric")
- Handle historical-only state (no divider line when forecast is empty)
- Discard stale responses on rapid metric switching (race condition handling)
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 4.12, 4.13, 4.14, 5.9_
- [x] 5.3 Wire MetricSelector and ForecastBurndownChart into CCPMetricsPage layout
- Add state for selected metric
- Place MetricSelector above ForecastBurndownChart in a dedicated section
- Connect selection change to chart data fetch
- Follow existing inline-style patterns from AggregatedBurndownChart and TrendChart
- _Requirements: 4.1, 5.1, 5.4_
- [x] 6. Final checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- The helper function is pure and stateless — all 7 property tests exercise it in isolation without database mocks
- All backend changes are in `backend/helpers/vclHelpers.js` and `backend/routes/vclMultiVertical.js`
- All frontend changes are within `frontend/src/components/pages/CCPMetricsPage.js`
- Property-based tests use `fast-check` (already in project dependencies)
- No database migrations needed — uses existing `compliance_items` and `compliance_snapshots` tables
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8"] },
{ "id": 2, "tasks": ["3.1", "3.2"] },
{ "id": 3, "tasks": ["3.3"] },
{ "id": 4, "tasks": ["5.1", "5.2"] },
{ "id": 5, "tasks": ["5.3"] }
]
}
```