from __future__ import annotations import uuid from typing import Any from sqlalchemy import JSON, Enum, Float, ForeignKey, String from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base, TimestampMixin, UUIDPrimaryKeyMixin from app.models.enums import ChangeStatus, ChangeType, SeverityLevel class DetectedChange(Base, UUIDPrimaryKeyMixin, TimestampMixin): __tablename__ = "detected_changes" company_id: Mapped[uuid.UUID] = mapped_column( ForeignKey("companies.id", ondelete="CASCADE"), index=True ) source_id: Mapped[uuid.UUID] = mapped_column( ForeignKey("sources.id", ondelete="CASCADE"), index=True ) monitoring_run_id: Mapped[uuid.UUID] = mapped_column( ForeignKey("monitoring_runs.id", ondelete="CASCADE"), index=True ) previous_snapshot_id: Mapped[uuid.UUID | None] = mapped_column( ForeignKey("snapshots.id", ondelete="SET NULL"), nullable=True ) current_snapshot_id: Mapped[uuid.UUID] = mapped_column( ForeignKey("snapshots.id", ondelete="CASCADE") ) change_type: Mapped[ChangeType] = mapped_column(Enum(ChangeType, native_enum=False, length=30)) raw_diff: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict) significance_score: Mapped[float] = mapped_column(Float) confidence_score: Mapped[float] = mapped_column(Float) severity: Mapped[SeverityLevel] = mapped_column( Enum(SeverityLevel, native_enum=False, length=20) ) status: Mapped[ChangeStatus] = mapped_column( Enum(ChangeStatus, native_enum=False, length=20), default=ChangeStatus.NEW ) # Short human-readable label, e.g. "3 new job postings detected" - # populated deterministically here; Phase 7's LLM may later add a # richer "why it matters" narrative on top without replacing this. summary: Mapped[str] = mapped_column(String(500))