# 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 `` 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"] } ] } ```