feat: implement governed reporting vertical

This commit is contained in:
2026-08-01 17:48:39 +02:00
parent 720959536b
commit eba35edd3c
35 changed files with 8414 additions and 33 deletions
@@ -0,0 +1 @@
"""Reporting Alembic revisions."""
@@ -0,0 +1 @@
"""Reporting migration versions."""
@@ -0,0 +1,477 @@
"""v0.1.14 governed Reporting baseline.
Revision ID: e5b2c9d4f7a1
Revises: None
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
revision = "e5b2c9d4f7a1"
down_revision = None
branch_labels = None
depends_on = "4f2a9c8e7b6d"
def upgrade() -> None:
op.create_table(
"reporting_definition_identities",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("definition_kind", sa.String(length=40), nullable=False),
sa.Column("definition_id", sa.String(length=255), nullable=False),
sa.Column("definition_key", sa.String(length=120), nullable=False),
sa.Column("created_by", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_definition_identities")),
sa.UniqueConstraint(
"tenant_id",
"definition_kind",
"definition_id",
name="uq_reporting_definition_identity",
),
sa.UniqueConstraint(
"tenant_id",
"definition_kind",
"definition_key",
name="uq_reporting_definition_key",
),
)
_indexes(
"reporting_definition_identities",
"tenant_id",
"definition_kind",
"definition_id",
"definition_key",
"created_by",
)
op.create_index(
"ix_reporting_definition_catalog",
"reporting_definition_identities",
["tenant_id", "definition_kind", "definition_key"],
unique=False,
)
op.create_table(
"reporting_definition_revisions",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("identity_id", sa.String(length=36), nullable=False),
sa.Column("definition_kind", sa.String(length=40), nullable=False),
sa.Column("definition_id", sa.String(length=255), nullable=False),
sa.Column("definition_key", sa.String(length=120), nullable=False),
sa.Column("revision", sa.Integer(), nullable=False),
sa.Column("previous_revision_id", sa.String(length=36), nullable=True),
sa.Column("parent_kind", sa.String(length=40), nullable=True),
sa.Column("parent_id", sa.String(length=255), nullable=True),
sa.Column("parent_revision", sa.Integer(), nullable=True),
sa.Column("name", sa.String(length=500), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("status", sa.String(length=30), nullable=False),
sa.Column("visibility", sa.String(length=30), nullable=False),
sa.Column("content_hash", sa.String(length=64), nullable=False),
sa.Column("change_reason", sa.String(length=1000), nullable=False),
sa.Column("idempotency_key", sa.String(length=255), nullable=False),
sa.Column("request_sha256", sa.String(length=64), nullable=False),
sa.Column("event_id", sa.String(length=36), nullable=False),
sa.Column("recorded_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("superseded_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("payload", sa.JSON(), nullable=False),
sa.Column("changed_by", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["identity_id"],
["reporting_definition_identities.id"],
name=op.f(
"fk_reporting_definition_revisions_identity_id_reporting_definition_identities"
),
ondelete="RESTRICT",
),
sa.ForeignKeyConstraint(
["previous_revision_id"],
["reporting_definition_revisions.id"],
name=op.f(
"fk_reporting_definition_revisions_previous_revision_id_reporting_definition_revisions"
),
ondelete="RESTRICT",
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_definition_revisions")),
sa.UniqueConstraint(
"tenant_id",
"definition_kind",
"definition_id",
"revision",
name="uq_reporting_definition_revision",
),
sa.UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_reporting_definition_idempotency",
),
sa.UniqueConstraint(
"tenant_id",
"event_id",
name="uq_reporting_definition_event",
),
)
_indexes(
"reporting_definition_revisions",
"tenant_id",
"identity_id",
"definition_kind",
"definition_id",
"definition_key",
"previous_revision_id",
"parent_kind",
"parent_id",
"status",
"visibility",
"content_hash",
"event_id",
"recorded_at",
"superseded_at",
"changed_by",
)
op.create_index(
"ix_reporting_definition_current",
"reporting_definition_revisions",
["tenant_id", "definition_kind", "definition_id", "superseded_at"],
unique=False,
)
op.create_index(
"ix_reporting_definition_parent",
"reporting_definition_revisions",
["tenant_id", "parent_kind", "parent_id", "parent_revision"],
unique=False,
)
op.create_index(
"ix_reporting_definition_list",
"reporting_definition_revisions",
["tenant_id", "definition_kind", "status", "recorded_at"],
unique=False,
)
op.create_table(
"reporting_definition_grants",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("definition_kind", sa.String(length=40), nullable=False),
sa.Column("definition_id", sa.String(length=255), nullable=False),
sa.Column("subject_kind", sa.String(length=40), nullable=False),
sa.Column("subject_id", sa.String(length=255), nullable=False),
sa.Column("permissions", sa.JSON(), nullable=False),
sa.Column("active", sa.Boolean(), nullable=False),
sa.Column("source_revision", sa.Integer(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_definition_grants")),
sa.UniqueConstraint(
"tenant_id",
"definition_kind",
"definition_id",
"subject_kind",
"subject_id",
name="uq_reporting_definition_grant",
),
)
_indexes(
"reporting_definition_grants",
"tenant_id",
"definition_kind",
"definition_id",
"subject_kind",
"subject_id",
"active",
)
op.create_index(
"ix_reporting_definition_grant_subject",
"reporting_definition_grants",
["tenant_id", "subject_kind", "subject_id", "active"],
unique=False,
)
op.create_index(
"ix_reporting_definition_grant_object",
"reporting_definition_grants",
["tenant_id", "definition_kind", "definition_id", "active"],
unique=False,
)
op.create_table(
"reporting_executions",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("execution_id", sa.String(length=36), nullable=False),
sa.Column("report_id", sa.String(length=255), nullable=False),
sa.Column("report_revision", sa.Integer(), nullable=False),
sa.Column("semantic_model_id", sa.String(length=255), nullable=False),
sa.Column("semantic_model_revision", sa.Integer(), nullable=False),
sa.Column("dataset_id", sa.String(length=255), nullable=False),
sa.Column("dataset_revision", sa.Integer(), nullable=False),
sa.Column("status", sa.String(length=30), nullable=False),
sa.Column("idempotency_key", sa.String(length=255), nullable=False),
sa.Column("request_sha256", sa.String(length=64), nullable=False),
sa.Column("parameters", sa.JSON(), nullable=False),
sa.Column("query", sa.JSON(), nullable=False),
sa.Column("source_fingerprints", sa.JSON(), nullable=False),
sa.Column("definition_hashes", sa.JSON(), nullable=False),
sa.Column("output_hash", sa.String(length=64), nullable=True),
sa.Column("executor_version", sa.String(length=255), nullable=True),
sa.Column("result_schema", sa.JSON(), nullable=False),
sa.Column("result_rows", sa.JSON(), nullable=False),
sa.Column("total_rows", sa.Integer(), nullable=False),
sa.Column("truncated", sa.Boolean(), nullable=False),
sa.Column("diagnostics", sa.JSON(), nullable=False),
sa.Column("provenance", sa.JSON(), nullable=False),
sa.Column("started_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("actor_id", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_executions")),
sa.UniqueConstraint("tenant_id", "execution_id", name="uq_reporting_execution"),
sa.UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_reporting_execution_idempotency",
),
)
_indexes(
"reporting_executions",
"tenant_id",
"execution_id",
"report_id",
"semantic_model_id",
"dataset_id",
"status",
"output_hash",
"started_at",
"finished_at",
"actor_id",
)
op.create_index(
"ix_reporting_execution_history",
"reporting_executions",
["tenant_id", "report_id", "started_at"],
unique=False,
)
op.create_index(
"ix_reporting_execution_status",
"reporting_executions",
["tenant_id", "status", "started_at"],
unique=False,
)
op.create_table(
"reporting_saved_views",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("view_id", sa.String(length=36), nullable=False),
sa.Column("report_id", sa.String(length=255), nullable=False),
sa.Column("report_revision", sa.Integer(), nullable=False),
sa.Column("owner_kind", sa.String(length=40), nullable=False),
sa.Column("owner_id", sa.String(length=255), nullable=False),
sa.Column("name", sa.String(length=500), nullable=False),
sa.Column("revision", sa.Integer(), nullable=False),
sa.Column("state", sa.JSON(), nullable=False),
sa.Column("shared", sa.Boolean(), nullable=False),
sa.Column("access", sa.JSON(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_saved_views")),
sa.UniqueConstraint("tenant_id", "view_id", name="uq_reporting_saved_view"),
)
_indexes(
"reporting_saved_views",
"tenant_id",
"view_id",
"report_id",
"owner_kind",
"owner_id",
"shared",
)
op.create_index(
"ix_reporting_saved_view_catalog",
"reporting_saved_views",
["tenant_id", "report_id", "owner_id", "shared"],
unique=False,
)
op.create_table(
"reporting_schedules",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("schedule_id", sa.String(length=36), nullable=False),
sa.Column("report_id", sa.String(length=255), nullable=False),
sa.Column("report_revision", sa.Integer(), nullable=False),
sa.Column("name", sa.String(length=500), nullable=False),
sa.Column("revision", sa.Integer(), nullable=False),
sa.Column("trigger_kind", sa.String(length=30), nullable=False),
sa.Column("trigger_config", sa.JSON(), nullable=False),
sa.Column("parameters", sa.JSON(), nullable=False),
sa.Column("query", sa.JSON(), nullable=False),
sa.Column("publication_target", sa.JSON(), nullable=False),
sa.Column("enabled", sa.Boolean(), nullable=False),
sa.Column("next_run_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("last_run_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("last_execution_id", sa.String(length=36), nullable=True),
sa.Column("created_by", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_schedules")),
sa.UniqueConstraint("tenant_id", "schedule_id", name="uq_reporting_schedule"),
)
_indexes(
"reporting_schedules",
"tenant_id",
"schedule_id",
"report_id",
"enabled",
"next_run_at",
)
op.create_index(
"ix_reporting_schedule_due",
"reporting_schedules",
["enabled", "next_run_at", "tenant_id"],
unique=False,
)
op.create_table(
"reporting_publications",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("publication_id", sa.String(length=36), nullable=False),
sa.Column("execution_id", sa.String(length=36), nullable=False),
sa.Column("target_capability", sa.String(length=255), nullable=False),
sa.Column("target_ref", sa.String(length=1000), nullable=True),
sa.Column("format", sa.String(length=30), nullable=False),
sa.Column("status", sa.String(length=30), nullable=False),
sa.Column("idempotency_key", sa.String(length=255), nullable=False),
sa.Column("evidence", sa.JSON(), nullable=False),
sa.Column("error", sa.Text(), nullable=True),
sa.Column("completed_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_publications")),
sa.UniqueConstraint(
"tenant_id", "publication_id", name="uq_reporting_publication"
),
sa.UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_reporting_publication_idempotency",
),
)
_indexes(
"reporting_publications",
"tenant_id",
"publication_id",
"execution_id",
"status",
)
op.create_index(
"ix_reporting_publication_history",
"reporting_publications",
["tenant_id", "execution_id", "created_at"],
unique=False,
)
op.create_table(
"reporting_quality_results",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("result_id", sa.String(length=36), nullable=False),
sa.Column("quality_plan_id", sa.String(length=255), nullable=False),
sa.Column("quality_plan_revision", sa.Integer(), nullable=False),
sa.Column("dataset_id", sa.String(length=255), nullable=False),
sa.Column("dataset_revision", sa.Integer(), nullable=False),
sa.Column("status", sa.String(length=30), nullable=False),
sa.Column("output_hash", sa.String(length=64), nullable=False),
sa.Column("assertions", sa.JSON(), nullable=False),
sa.Column("source_fingerprints", sa.JSON(), nullable=False),
sa.Column("evaluated_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("actor_id", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_quality_results")),
sa.UniqueConstraint(
"tenant_id", "result_id", name="uq_reporting_quality_result"
),
)
_indexes(
"reporting_quality_results",
"tenant_id",
"result_id",
"quality_plan_id",
"dataset_id",
"status",
"output_hash",
"evaluated_at",
)
op.create_index(
"ix_reporting_quality_history",
"reporting_quality_results",
["tenant_id", "quality_plan_id", "evaluated_at"],
unique=False,
)
op.create_table(
"reporting_import_assessments",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("assessment_id", sa.String(length=36), nullable=False),
sa.Column("source_system", sa.String(length=255), nullable=False),
sa.Column("source_id", sa.String(length=500), nullable=False),
sa.Column("source_fingerprint", sa.String(length=64), nullable=False),
sa.Column("mapping_report", sa.JSON(), nullable=False),
sa.Column("status", sa.String(length=30), nullable=False),
sa.Column("accepted_approximations", sa.JSON(), nullable=False),
sa.Column("assessed_by", sa.String(length=255), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("pk_reporting_import_assessments")),
sa.UniqueConstraint(
"tenant_id",
"assessment_id",
name="uq_reporting_import_assessment",
),
)
_indexes(
"reporting_import_assessments",
"tenant_id",
"assessment_id",
"source_system",
"status",
)
op.create_index(
"ix_reporting_import_history",
"reporting_import_assessments",
["tenant_id", "source_system", "created_at"],
unique=False,
)
def downgrade() -> None:
op.drop_table("reporting_import_assessments")
op.drop_table("reporting_quality_results")
op.drop_table("reporting_publications")
op.drop_table("reporting_schedules")
op.drop_table("reporting_saved_views")
op.drop_table("reporting_definition_grants")
op.drop_table("reporting_executions")
op.drop_table("reporting_definition_revisions")
op.drop_table("reporting_definition_identities")
def _indexes(table: str, *columns: str) -> None:
for column in columns:
op.create_index(
op.f(f"ix_{table}_{column}"),
table,
[column],
unique=False,
)