114 lines
6.8 KiB
Markdown
114 lines
6.8 KiB
Markdown
# 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"] }
|
|
]
|
|
}
|
|
```
|