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.2 KiB
Implementation Plan: CCP Metrics View Restructure
Overview
Restructure the CCP Metrics page from a vertical-first drill-down model to a metric-first model. Two new backend endpoints aggregate metrics across verticals. The frontend replaces VerticalTable/VerticalDetailView with MetricTable/MetricDetailView, removes the "By Vertical" table from AggregatedBurndownChart, and inverts the drill-down state hierarchy.
Tasks
-
1. Add backend endpoints for metric-centric aggregation
-
1.1 Implement GET /metrics endpoint in backend/routes/vclMultiVertical.js
- Add route handler that queries
vcl_multi_vertical_summaryusing onlyALL:rollup rows from the latest upload per vertical - Aggregate by
metric_id: SUM non_compliant, compliant, total; MAX metric_desc, category; AVG target - Compute
compliance_pctascompliant / total(0 when total is 0) - Sort by
non_compliantDESC - Return
{ metrics: [...] }with empty array when no data exists - Require
requireAuth()middleware - Return HTTP 500 with
{ "error": "Database error" }on query failure - Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9
- Add route handler that queries
-
1.2 Implement GET /metric/:id/verticals endpoint in backend/routes/vclMultiVertical.js
- Validate metric ID parameter (reject if > 50 chars with HTTP 400)
- Query all rows for the metric from latest uploads
- Separate
ALL:rollup rows from sub-team rows - Build per-vertical entries with nested
sub_teamsarrays - Sort verticals by
non_compliantDESC - Return
{ metric_id, metric_desc, category, verticals: [...] }with empty verticals array when metric not found - Require
requireAuth()middleware - Return HTTP 500 with
{ "error": "Database error" }on query failure - Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9
-
* 1.3 Write property test: Metrics aggregation uses only rollup rows from latest uploads
- Property 1: Metrics aggregation uses only rollup rows from latest uploads
- Generate random
vcl_multi_vertical_summaryrows with multiple verticals, metrics, uploads, and team configurations - Assert the endpoint returns exactly one entry per distinct
metric_idwith totals matching onlyALL:-prefixed rows from the latest upload per vertical - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 3.1, 3.3
-
* 1.4 Write property test: Metrics computed fields are mathematically correct
- Property 2: Metrics computed fields are mathematically correct
- Assert
compliance_pctequalscompliant / total(or 0 when total is 0) for each metric - Assert
targetequals the arithmetic mean of target values across verticals for each metric - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 3.4, 3.5
-
* 1.5 Write property test: Metrics response is sorted by non-compliant descending
- Property 3: Metrics response is sorted by non-compliant descending
- Assert each entry's
non_compliantis >= the next entry'snon_compliant - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 3.6
-
* 1.6 Write property test: Metric-verticals breakdown is complete and correct
- Property 4: Metric-verticals breakdown is complete and correct
- Assert one vertical entry per vertical that has the metric in its latest upload
- Assert each entry's
sub_teamscontains exactly the non-rollup team rows for that metric/vertical - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 4.1, 4.3
-
* 1.7 Write property test: Metric-verticals response is sorted by non-compliant descending
- Property 5: Metric-verticals response is sorted by non-compliant descending
- Assert each vertical entry's
non_compliantis >= the next entry'snon_compliant - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 4.4
-
-
2. Checkpoint - Backend endpoints verified
- Ensure all tests pass, ask the user if questions arise.
-
3. Remove "By Vertical" table from AggregatedBurndownChart
- 3.1 Remove the "By Vertical" contribution table JSX from AggregatedBurndownChart in frontend/src/components/pages/CCPMetricsPage.js
- Remove the entire
{data.by_vertical && data.by_vertical.length > 0 && (...)}block that renders the per-vertical table below the bar chart - Preserve the summary header (total non-compliant, blockers, in-progress, projected clear date) and bar chart
- Preserve all loading, error, empty-state, and all-blockers display behaviors
- Requirements: 1.1, 1.2, 1.3
- Remove the entire
- 3.1 Remove the "By Vertical" contribution table JSX from AggregatedBurndownChart in frontend/src/components/pages/CCPMetricsPage.js
-
4. Implement MetricTable component and replace VerticalTable
-
4.1 Create MetricTable component in frontend/src/components/pages/CCPMetricsPage.js
- Render one row per metric from the
/metricsendpoint response - Columns: Metric ID, Description, Category, Compliant, Non-Compliant, Total, Compliance %, Target %
- Sort rows by non-compliant descending (server-side, already sorted)
- Rows are clickable — clicking triggers
onSelectMetric(metricId) - Handle empty state (no metrics data)
- Requirements: 2.1, 2.2, 2.3, 2.4, 2.5
- Render one row per metric from the
-
4.2 Replace VerticalTable usage with MetricTable in the overview render logic
- Add fetch call to
GET /api/compliance/vcl-multi/metricsin the overview data loading - Pass fetched metrics data to MetricTable
- Wire
onSelectMetricto setselectedMetricstate - Requirements: 2.4, 2.5
- Add fetch call to
-
-
5. Implement MetricDetailView and update drill-down state
-
5.1 Create MetricDetailView component in frontend/src/components/pages/CCPMetricsPage.js
- Fetch data from
GET /metric/:id/verticalson mount - Display header with metric ID, description, category
- Display aggregated stats cards (total, compliant, non-compliant, compliance %)
- Display table of verticals with columns: vertical name, compliant, non-compliant, total, compliance %
- Clicking a vertical row calls
onSelectVertical(vertical, verticalData) - Include "Back to Overview" button that calls
onBack - Handle loading, error, and empty states
- Requirements: 5.1, 5.2, 5.3, 5.4, 6.2
- Fetch data from
-
5.2 Restructure drill-down state in CCPMetricsPage main component
- Change state model from
selectedVertical → selectedMetric → selectedTeamtoselectedMetric → selectedVertical → selectedTeam - Add state variables:
selectedMetric,selectedMetricData,selectedVertical,selectedVerticalData,selectedTeam - Update render logic: no metric = Overview (MetricTable), metric only = MetricDetailView, metric+vertical = MetricSubTeamView, all three = MetricDeviceList
- Wire back-navigation handlers at each level (clear appropriate state to go up one level)
- Pass
selectedVerticalData.sub_teamsto MetricSubTeamView asmetricData - Requirements: 5.4, 5.5, 5.6, 5.7, 5.8, 6.1, 6.2, 6.3, 6.4, 6.5
- Change state model from
-
* 5.3 Write property test: Drill-down state determines rendered view
- Property 6: Drill-down state determines rendered view
- Generate random combinations of
(selectedMetric, selectedVertical, selectedTeam)state values - Assert exactly one view is rendered for each combination following the state hierarchy rules
- Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Validates: Requirements 6.1, 6.5
-
-
6. Verify backward compatibility of existing endpoints
- * 6.1 Write integration tests verifying existing endpoints are unchanged
- Verify
GET /vertical/:code/metricsreturns same response shape - Verify
GET /vertical/:code/metric/:metricId/devicesreturns same response shape - Verify
GET /vertical/:code/burndownreturns same response shape - Verify
GET /statsstill returnsvertical_breakdownandmetric_breakdownfields - Test file:
backend/__tests__/ccp-metrics-view-restructure.property.test.js - Requirements: 7.1, 7.2, 7.3, 7.4
- Verify
- * 6.1 Write integration tests verifying existing endpoints are unchanged
-
7. 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 existing
MetricSubTeamViewandMetricDeviceListcomponents are reused with minor prop adjustments — no new component creation needed for those - All backend endpoints are added to the existing
backend/routes/vclMultiVertical.jsfile - All frontend changes are within
frontend/src/components/pages/CCPMetricsPage.js - Property-based tests use
fast-check(already in project dependencies)
Task Dependency Graph
{
"waves": [
{ "id": 0, "tasks": ["1.1", "1.2"] },
{ "id": 1, "tasks": ["1.3", "1.4", "1.5", "1.6", "1.7", "3.1"] },
{ "id": 2, "tasks": ["4.1"] },
{ "id": 3, "tasks": ["4.2", "5.1"] },
{ "id": 4, "tasks": ["5.2"] },
{ "id": 5, "tasks": ["5.3", "6.1"] }
]
}