Files
cve-dashboard/.kiro/specs/vcl-aggregated-burndown/tasks.md

114 lines
6.8 KiB
Markdown
Raw Normal View History

# Implementation Plan: VCL Aggregated Burndown
## Overview
Implement an aggregated cross-vertical burndown forecast feature consisting of: two new pure helper functions (`deduplicateByHostname` and `computeAggregatedBurndown`) in `vclHelpers.js`, a new `GET /api/compliance/vcl-multi/burndown` endpoint in the existing `vclMultiVertical.js` route file, property-based tests validating 8 correctness properties, unit tests covering edge cases and API integration, and an `AggregatedBurndownChart` inline component in `CCPMetricsPage.js`.
## Tasks
- [x] 1. Implement backend helper functions
- [x] 1.1 Add `deduplicateByHostname` function to `backend/helpers/vclHelpers.js`
- Groups items by hostname
- For each hostname, selects the earliest non-null `resolution_date` across all entries
- If all entries for a hostname have null dates, the device is a blocker (null date preserved)
- Preserves the `vertical` from the first entry for that hostname
- Export the function from the module
- _Requirements: 1.6_
- [x] 1.2 Add `computeAggregatedBurndown` function to `backend/helpers/vclHelpers.js`
- Accepts an array of device objects with `hostname`, `resolution_date`, and `vertical` fields
- Counts total devices, blockers (null date), and with_dates (non-null date)
- Buckets with_dates devices by YYYY-MM of resolution_date into `monthly` object
- Sorts monthly keys chronologically
- Computes `projection` as cumulative remaining: starts at `total`, subtracts each month's count
- Sets `projected_clear_date` to the last month key if blockers = 0, otherwise null
- Groups devices by vertical for `by_vertical`, sorted descending by total, omitting verticals with zero devices
- Each `by_vertical` entry has `{ vertical, total, blockers, with_dates }`
- Returns `{ total, blockers, with_dates, monthly, projection, projected_clear_date, by_vertical }`
- Export the function from the module
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 5.1, 5.2, 5.4_
- [x]* 1.3 Write property tests for `deduplicateByHostname` and `computeAggregatedBurndown`
- **Property 1: Partition Invariant** — `blockers + with_dates = total` for any input
- **Validates: Requirements 2.2**
- **Property 2: Monthly Bucket Conservation** — sum of monthly values = with_dates
- **Validates: Requirements 2.3, 1.5**
- **Property 3: Chronological Monthly Ordering** — monthly keys in ascending YYYY-MM order
- **Validates: Requirements 2.4**
- **Property 4: Cumulative Projection Consistency** — projection[month].remaining = total - cumulative sum
- **Validates: Requirements 2.5**
- **Property 5: Projected Clear Date Logic** — null when blockers > 0, last month key when blockers = 0
- **Validates: Requirements 1.7**
- **Property 6: Hostname Deduplication with Earliest Date** — one entry per hostname, earliest non-null date
- **Validates: Requirements 1.6**
- **Property 7: Aggregation Consistency with Per-Vertical Computation** — aggregated totals = sum of per-vertical totals
- **Validates: Requirements 4.1, 4.2, 4.3, 4.4**
- **Property 8: By-Vertical Sorting and Filtering** — sorted descending by total, no zero-total entries, sum = overall total
- **Validates: Requirements 5.1, 5.2, 5.4**
- Test file: `backend/__tests__/vcl-aggregated-burndown.property.test.js`
- [x] 2. Implement backend API endpoint
- [x] 2.1 Add `GET /burndown` route to `backend/routes/vclMultiVertical.js`
- Query `compliance_items` for all active non-compliant devices across verticals
- Call `deduplicateByHostname` on the query results
- Call `computeAggregatedBurndown` on the deduplicated devices
- Map the result to the API response shape: `{ total_non_compliant, blockers, with_dates, monthly_forecast, projected_clear_date, by_vertical }`
- Handle database errors with 500 status and `{ error: "Database error" }`
- Route is protected by `requireAuth()` (already applied via `router.use`)
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9_
- [x]* 2.2 Write unit tests for the burndown endpoint
- Test empty DB returns zero/empty response (Requirement 1.8)
- Test all-blocker scenario returns with_dates=0, monthly={}, projected_clear_date=null (Requirement 2.7)
- Test single device single metric basic computation
- Test duplicate hostnames across metrics — verify deduplication picks earliest date
- Test duplicate hostnames where all dates are null — verify device is a blocker
- Test response shape matches API contract
- Test 401 without auth session (mock requireAuth to reject)
- Test file: `backend/__tests__/vcl-aggregated-burndown.test.js`
- _Requirements: 1.1, 1.8, 1.9, 2.6, 2.7_
- [x] 3. Checkpoint - Ensure all backend tests pass
- Ensure all tests pass, ask the user if questions arise.
- [x] 4. Implement frontend component
- [x] 4.1 Add `AggregatedBurndownChart` component to `frontend/src/components/pages/CCPMetricsPage.js`
- Add as an inline component following the existing pattern (StatsBar, DonutChart, TrendChart are all in the same file)
- Fetch `GET /api/compliance/vcl-multi/burndown` on page load alongside existing stats/trend calls
- Display summary header with total non-compliant, blockers, in-progress, and projected clear date
- Render a Recharts `BarChart` with one bar per monthly bucket (purple fill `#A78BFA`, fillOpacity 0.7)
- Below the chart, render a compact per-vertical contribution table sorted by total descending
- Show "No non-compliant devices" message when total = 0
- Show "All X non-compliant devices lack remediation dates" when monthly_forecast is empty but blockers > 0
- Show `<Loader />` spinner while fetching
- Show inline error message on API failure
- Place the component below the charts row (TrendChart + DonutChart), above the VerticalTable
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 5.3_
- [x] 5. 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
- Unit tests validate specific examples and edge cases
- The design uses JavaScript — all implementations use Node.js/Express (backend) and React 19 (frontend)
- The `vclMultiVertical.js` route file already exists with `router.use(requireAuth())` applied globally
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1"] },
{ "id": 1, "tasks": ["1.2"] },
{ "id": 2, "tasks": ["1.3", "2.1"] },
{ "id": 3, "tasks": ["2.2"] },
{ "id": 4, "tasks": ["4.1"] }
]
}
```