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
9.1 KiB
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
-
1. Implement the computeMetricForecastBurndown helper function
-
1.1 Add computeMetricForecastBurndown to backend/helpers/vclHelpers.js
- Implement the pure function accepting
currentDevices,totalAssets, andhistoricalSnapshots - Return object with
historical,forecast, andcurrent_snapshotfields - Compute
current_snapshot.blockers(devices with no resolution_date) andcurrent_snapshot.with_dates(devices with a resolution_date) - Compute
compliance_pctasROUND((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
- Implement the pure function accepting
-
* 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
-
-
2. Checkpoint - Helper function verified
- Ensure all tests pass, ask the user if questions arise.
-
3. Implement backend API endpoints
-
3.1 Add GET /metrics-list endpoint to backend/routes/vclMultiVertical.js
- Add route handler at
/metrics-listwithrequireAuth()middleware - Query
compliance_itemsfor 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
- Add route handler at
-
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_snapshotsfor 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
computeMetricForecastBurndownhelper - Return response with
metric_id,historical,forecast, andcurrent_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
- Add route handler with
-
* 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
-
-
4. Checkpoint - Backend complete
- Ensure all tests pass, ask the user if questions arise.
-
5. Implement frontend MetricSelector and ForecastBurndownChart components
-
5.1 Add MetricSelector component to frontend/src/components/pages/CCPMetricsPage.js
- Fetch metrics list from
/api/compliance/vcl-multi/metrics-liston 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
onMetricSelectcallback - Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8
- Fetch metrics list from
-
5.2 Add ForecastBurndownChart component to frontend/src/components/pages/CCPMetricsPage.js
- Fetch forecast data from
/api/compliance/vcl-multi/metric/:metricId/forecast-burndownwhen 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
- Fetch forecast data from
-
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
-
-
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.jsandbackend/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_itemsandcompliance_snapshotstables
Task Dependency Graph
{
"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"] }
]
}