feat(dashboard): Phase 13 — Executive Dashboard
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
PostureSnapshot model, Alembic migration (b039exec), schemas, service aggregating all phases (coverage/risk/operations/knowledge/MTTD), and router at /api/v1/dashboard with executive view, KPIs, coverage-by-tactic, posture-history, posture-snapshot, and activity-feed endpoints. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
77
backend/alembic/versions/b039_executive_dashboard.py
Normal file
77
backend/alembic/versions/b039_executive_dashboard.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""Phase 13: Executive Dashboard — posture_snapshots table.
|
||||
|
||||
Revision ID: b039exec
|
||||
Revises: b038risk
|
||||
Create Date: 2026-05-20
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "b039exec"
|
||||
down_revision = "b038risk"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
conn.execute(sa.text("""
|
||||
CREATE TABLE IF NOT EXISTS posture_snapshots (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
snapshot_date DATE NOT NULL,
|
||||
|
||||
-- Coverage
|
||||
total_techniques INTEGER NOT NULL DEFAULT 0,
|
||||
validated_count INTEGER NOT NULL DEFAULT 0,
|
||||
partial_count INTEGER NOT NULL DEFAULT 0,
|
||||
not_covered_count INTEGER NOT NULL DEFAULT 0,
|
||||
coverage_pct FLOAT NOT NULL DEFAULT 0.0,
|
||||
|
||||
-- Risk
|
||||
avg_risk_score FLOAT NOT NULL DEFAULT 0.0,
|
||||
critical_count INTEGER NOT NULL DEFAULT 0,
|
||||
high_count INTEGER NOT NULL DEFAULT 0,
|
||||
medium_count INTEGER NOT NULL DEFAULT 0,
|
||||
low_count INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- Operations
|
||||
open_queue_items INTEGER NOT NULL DEFAULT 0,
|
||||
orphan_techniques INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- Knowledge
|
||||
playbook_count INTEGER NOT NULL DEFAULT 0,
|
||||
lesson_count INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
-- MTTD
|
||||
mttd_avg_seconds FLOAT,
|
||||
executions_30d INTEGER NOT NULL DEFAULT 0,
|
||||
detection_rate_30d FLOAT,
|
||||
|
||||
-- Meta
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
|
||||
extra JSONB
|
||||
)
|
||||
"""))
|
||||
|
||||
# Unique constraint: one snapshot per calendar day
|
||||
conn.execute(sa.text("""
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE posture_snapshots
|
||||
ADD CONSTRAINT uq_posture_snapshot_date UNIQUE (snapshot_date);
|
||||
EXCEPTION WHEN duplicate_table THEN NULL;
|
||||
WHEN duplicate_object THEN NULL;
|
||||
END $$
|
||||
"""))
|
||||
|
||||
# Index for date-range trend queries
|
||||
conn.execute(sa.text("""
|
||||
CREATE INDEX IF NOT EXISTS ix_posture_snapshots_date
|
||||
ON posture_snapshots (snapshot_date)
|
||||
"""))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
conn.execute(sa.text("DROP TABLE IF EXISTS posture_snapshots CASCADE"))
|
||||
Reference in New Issue
Block a user