# Design Document: VCL Compliance Reporting ## Overview This feature adds an executive-level VCL (Vulnerability Compliance Level) reporting page to the existing Compliance module, extends device records with remediation tracking fields (resolution date, remediation plan), and introduces a bulk upload mechanism for updating device metadata in batch. The VCL Report Page mirrors the layout of the leadership's existing spreadsheet deck — summary statistics bar, trend chart with forecast, non-compliant asset donut chart, heavy hitters table, and vertical breakdown table with burndown projections. The implementation builds on the existing `compliance.js` route module, `compliance_items` table, and `CompliancePage.js` frontend component. New backend endpoints compute VCL statistics from existing data plus the new `resolution_date` and `remediation_plan` columns. The frontend adds a new `VCLReportPage.js` component accessible from the Compliance module navigation. ## Architecture ```mermaid sequenceDiagram participant U as User participant FE as React Frontend participant BE as Express Backend participant DB as PostgreSQL Note over FE,DB: Device Metadata Update (single device) U->>FE: Edit resolution_date / remediation_plan in DetailPanel FE->>BE: PATCH /api/compliance/items/:hostname/metadata BE->>DB: UPDATE compliance_items SET resolution_date, remediation_plan WHERE hostname = $1 BE-->>FE: 200 OK { updated: count } Note over FE,DB: VCL Report Page Load FE->>BE: GET /api/compliance/vcl/stats BE->>DB: Aggregate compliance_items (counts, percentages, categorization) DB-->>BE: Raw counts BE->>BE: Compute stats, categorization, heavy hitters, vertical breakdown BE-->>FE: JSON { stats, donut, heavyHitters, verticalBreakdown } FE->>BE: GET /api/compliance/vcl/trend BE->>DB: Monthly aggregation from compliance_uploads + compliance_items history DB-->>BE: Monthly data points BE->>BE: Compute actuals + forecast BE-->>FE: JSON { months: [...] } Note over U,DB: Bulk Upload Flow U->>FE: Select xlsx file in bulk upload control FE->>FE: Parse xlsx with 'xlsx' library (client-side) FE->>FE: Map columns, validate fields, match hostnames FE->>BE: POST /api/compliance/vcl/bulk-preview { rows: [...] } BE->>DB: Match hostnames against compliance_items BE-->>FE: JSON { matched, unmatched, changes, invalid } FE->>FE: Display Diff_Preview U->>FE: Confirm changes FE->>BE: POST /api/compliance/vcl/bulk-commit { changes: [...] } BE->>DB: BEGIN; UPDATE compliance_items ...; COMMIT; BE-->>FE: 200 OK { committed: count } ``` ### Data Flow Summary 1. **Device metadata** — stored directly on `compliance_items` rows. Updated via PATCH endpoint (single) or bulk commit (batch). 2. **VCL statistics** — computed on-demand from current `compliance_items` state. No separate materialized table needed since the dataset is small (~1000 devices). 3. **Trend data** — derived from `compliance_uploads` history (existing) plus monthly snapshots of compliance percentages stored in a new `compliance_snapshots` table. 4. **Burndown projections** — computed from `resolution_date` values on active non-compliant items, bucketed by month. ## Components and Interfaces ### Backend #### New Endpoints (added to `backend/routes/compliance.js`) **`PATCH /api/compliance/items/:hostname/metadata`** Updates resolution_date and/or remediation_plan for all active items matching a hostname. - Auth: `requireAuth()`, `requireGroup('Admin', 'Standard_User')` - Body: `{ resolution_date?: string|null, remediation_plan?: string|null }` - Validation: resolution_date must be a valid ISO date or null; remediation_plan must be <= 2000 chars - Response: `{ updated: number }` **`GET /api/compliance/vcl/stats`** Returns computed VCL executive summary statistics. - Auth: `requireAuth()` - Response: ```json { "stats": { "total_devices": 1200, "in_scope": 1100, "compliant": 950, "non_compliant": 150, "remediations_required": 150, "compliance_pct": 86, "target_pct": 95 }, "donut": { "blocked": { "count": 45, "pct": 30 }, "in_progress": { "count": 105, "pct": 70 } }, "heavy_hitters": [ { "vertical": "Network Ops", "team": "STEAM", "non_compliant": 42, "compliance_date": "2026-06-30", "notes": "..." } ], "vertical_breakdown": [ { "vertical": "Network Ops", "compliance_pct": 82, "team": "STEAM", "non_compliant": 42, "actual_burndown": { "2026-01": 5, "2026-02": 8 }, "forecast_burndown": { "2026-03": 10, "2026-04": 12 }, "blockers": 8, "risk_acceptances": 3, "notes": "" } ] } ``` **`GET /api/compliance/vcl/trend`** Returns monthly compliance trend data for the overview chart. - Auth: `requireAuth()` - Query params: none - Response: ```json { "months": [ { "month": "2026-01", "compliant_count": 900, "compliance_pct": 82, "forecast_pct": null, "target_pct": 95 } ] } ``` Forecast is computed using linear regression on the last 3+ months of actual data, projected forward. **`POST /api/compliance/vcl/bulk-preview`** Accepts parsed bulk upload rows and returns a diff preview. - Auth: `requireAuth()`, `requireGroup('Admin', 'Standard_User')` - Body: `{ rows: [{ hostname, resolution_date?, remediation_plan?, notes? }] }` - Response: ```json { "matched": 850, "unmatched": 12, "changes": 200, "invalid": 5, "details": [ { "hostname": "srv-001", "status": "changed", "fields": { "resolution_date": { "old": null, "new": "2026-06-15" }, "remediation_plan": { "old": "", "new": "Patch in next window" } } } ], "unmatched_rows": ["unknown-host-1"], "invalid_rows": [{ "hostname": "srv-bad", "errors": ["resolution_date: invalid date format"] }] } ``` **`POST /api/compliance/vcl/bulk-commit`** Commits validated bulk changes in a single transaction. - Auth: `requireAuth()`, `requireGroup('Admin', 'Standard_User')` - Body: `{ changes: [{ hostname, resolution_date?, remediation_plan?, notes? }] }` - Response: `{ committed: number }` - Audit: logs `compliance_bulk_update` action #### Pure Helper Functions (exported for testing) ```javascript // Truncates text to maxLen chars with ellipsis function truncateText(text, maxLen = 80) { ... } // Validates remediation_plan length function validateRemediationPlan(text) { ... } // Validates a date string (ISO format) function isValidDateString(str) { ... } // Computes VCL summary stats from device rows function computeVCLStats(items, targetPct) { ... } // Categorizes non-compliant devices into blocked/in-progress function categorizeNonCompliant(items) { ... } // Ranks verticals by non-compliant count descending function rankHeavyHitters(verticalData) { ... } // Computes forecasted burndown from resolution_date values function computeForecastBurndown(items) { ... } // Matches uploaded rows to existing devices by hostname function matchByHostname(uploadedRows, existingHostnames) { ... } // Computes diff between uploaded values and current DB values function computeBulkDiff(matchedRows, currentData) { ... } // Maps column headers to known field names function mapColumnHeaders(headers) { ... } // Formats a decimal as a whole-number percentage string function formatPct(decimal) { ... } ``` ### Frontend #### New Component: `VCLReportPage.js` Located at `frontend/src/components/pages/VCLReportPage.js`. Accessible via a tab/button on the existing CompliancePage or as a separate nav entry. **Sub-components:** | Component | Purpose | |-----------|---------| | `VCLStatsBar` | Horizontal bar with 7 stat cards (Total, In-Scope, Compliant, Non-Compliant, Remediations, Current %, Target %) | | `ComplianceOverviewChart` | Recharts ComposedChart — bars for compliant count, solid line for actual %, dashed line for forecast %, ReferenceLine for target | | `NonCompliantDonutChart` | Recharts PieChart (donut) — Blocked vs In-Progress segments | | `HeavyHittersTable` | Sorted table of top verticals by non-compliant count | | `VerticalBreakdownTable` | Full breakdown table with burndown columns | | `BulkUploadModal` | Modal with file picker, column mapping preview, diff display, confirm/cancel | #### Modified Component: `ComplianceDetailPanel.js` Add two new fields to the device detail panel: - **Resolution Date** — `` with save on blur/enter - **Remediation Plan** — `