"""Analytics aggregates — Phase 12.8. Report definitions describe which local metric keys to compute; snapshots store a point-in-time metrics payload produced by simple local SQL counts (no external analytics engine, no cross-service imports). """ from __future__ import annotations import uuid from sqlalchemy import Index, String from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.types import JSON from app.core.database import Base from app.models.base import ( ActorAuditMixin, SoftDeleteMixin, TenantMixin, TimestampMixin, UUIDPrimaryKeyMixin, ) from app.models.types import GUID, LifecycleStatus class AnalyticsReportDefinition( Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, SoftDeleteMixin, ActorAuditMixin, ): """A tenant-scoped definition of which local metrics a report tracks.""" __tablename__ = "analytics_report_definitions" venue_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) code: Mapped[str] = mapped_column(String(50), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) metric_keys: Mapped[list] = mapped_column(JSON, nullable=False) filters: Mapped[dict | None] = mapped_column(JSON, nullable=True) status: Mapped[LifecycleStatus] = mapped_column( default=LifecycleStatus.ACTIVE, nullable=False ) __table_args__ = ( Index( "ix_analytics_report_definitions_tenant_code", "tenant_id", "code", unique=True, ), Index("ix_analytics_report_definitions_venue", "tenant_id", "venue_id"), Index( "ix_analytics_report_definitions_tenant_deleted", "tenant_id", "is_deleted", ), ) class AnalyticsSnapshot( Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, SoftDeleteMixin, ActorAuditMixin, ): """A point-in-time computed metrics payload for a report definition.""" __tablename__ = "analytics_snapshots" venue_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True) report_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False) period_start: Mapped[str] = mapped_column(String(32), nullable=False) period_end: Mapped[str] = mapped_column(String(32), nullable=False) metrics: Mapped[dict] = mapped_column(JSON, nullable=False) status: Mapped[LifecycleStatus] = mapped_column( default=LifecycleStatus.ACTIVE, nullable=False ) __table_args__ = ( Index("ix_analytics_snapshots_venue", "tenant_id", "venue_id"), Index("ix_analytics_snapshots_report", "tenant_id", "report_id"), Index( "ix_analytics_snapshots_tenant_deleted", "tenant_id", "is_deleted" ), )