Add CCP Metrics page with multi-vertical VCL upload and cross-org reporting
New feature: multi-file per-vertical compliance xlsx upload with scoped resolution logic, executive-level aggregated reporting, and drill-down by vertical and metric. Supports daily upload cadence and batch commit. Backend: - Migration: add vertical column to compliance_items/uploads, create vcl_multi_vertical_summary table - New route module: routes/vclMultiVertical.js with preview, commit, stats, trend, metric drill-down, device list, and burndown endpoints - New helpers: parseVerticalFilename(), computeVerticalBurndown() - Vertical-scoped resolution: uploading one vertical never resolves items from other verticals Frontend: - CCPMetricsPage with stats bar, trend chart, donut, vertical table - Drill-down: vertical -> metrics by category -> device list - Per-vertical burndown forecast chart - MultiVerticalUploadModal: multi-file drag-drop, batch preview, commit - Nav entry: CCP Metrics (Building2 icon) Docs: - Design brief for stakeholder meeting (docs/vcl-multi-vertical-design-brief.md)
This commit is contained in:
65
backend/migrations/add_vcl_multi_vertical.js
Normal file
65
backend/migrations/add_vcl_multi_vertical.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Migration: Add multi-vertical support for VCL compliance reporting
|
||||
// Adds vertical column to compliance_items and compliance_uploads,
|
||||
// creates vcl_multi_vertical_summary table for per-vertical metric data.
|
||||
const pool = require('../db');
|
||||
|
||||
async function run() {
|
||||
console.log('Starting VCL multi-vertical migration...');
|
||||
try {
|
||||
// Add vertical column to compliance_items
|
||||
await pool.query(`ALTER TABLE compliance_items ADD COLUMN IF NOT EXISTS vertical TEXT DEFAULT NULL`);
|
||||
console.log('✓ vertical column added to compliance_items');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_compliance_items_vertical ON compliance_items(vertical)`);
|
||||
console.log('✓ idx_compliance_items_vertical index created');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_compliance_items_vertical_status ON compliance_items(vertical, status)`);
|
||||
console.log('✓ idx_compliance_items_vertical_status index created');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_compliance_items_vertical_metric ON compliance_items(vertical, metric_id, status)`);
|
||||
console.log('✓ idx_compliance_items_vertical_metric index created');
|
||||
|
||||
// Add vertical column to compliance_uploads
|
||||
await pool.query(`ALTER TABLE compliance_uploads ADD COLUMN IF NOT EXISTS vertical TEXT DEFAULT NULL`);
|
||||
console.log('✓ vertical column added to compliance_uploads');
|
||||
|
||||
// Create summary table for per-vertical metric data from Summary sheets
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS vcl_multi_vertical_summary (
|
||||
id SERIAL PRIMARY KEY,
|
||||
upload_id INTEGER NOT NULL REFERENCES compliance_uploads(id) ON DELETE CASCADE,
|
||||
vertical TEXT NOT NULL,
|
||||
metric_id TEXT NOT NULL,
|
||||
metric_desc TEXT DEFAULT '',
|
||||
category TEXT DEFAULT 'Other',
|
||||
team TEXT DEFAULT '',
|
||||
priority TEXT DEFAULT '',
|
||||
non_compliant INTEGER DEFAULT 0,
|
||||
compliant INTEGER DEFAULT 0,
|
||||
total INTEGER DEFAULT 0,
|
||||
compliance_pct NUMERIC(5,2) DEFAULT 0,
|
||||
target NUMERIC(5,2) DEFAULT 0,
|
||||
status TEXT DEFAULT '',
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
)
|
||||
`);
|
||||
console.log('✓ vcl_multi_vertical_summary table created');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_vcl_multi_summary_vertical ON vcl_multi_vertical_summary(vertical)`);
|
||||
console.log('✓ idx_vcl_multi_summary_vertical index created');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_vcl_multi_summary_upload ON vcl_multi_vertical_summary(upload_id)`);
|
||||
console.log('✓ idx_vcl_multi_summary_upload index created');
|
||||
|
||||
await pool.query(`CREATE INDEX IF NOT EXISTS idx_vcl_multi_summary_vertical_metric ON vcl_multi_vertical_summary(vertical, metric_id)`);
|
||||
console.log('✓ idx_vcl_multi_summary_vertical_metric index created');
|
||||
|
||||
} catch (err) {
|
||||
console.error('Migration error:', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('Migration complete.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run();
|
||||
Reference in New Issue
Block a user