feat(dashboard): Phase 13 — Executive Dashboard
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:
kitos
2026-05-20 16:20:21 +02:00
parent 41a0c536bb
commit ab591d30c4
8 changed files with 997 additions and 0 deletions

View 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"))