from datetime import datetime from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, JSON, String, Text, func from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class Asset(Base): __tablename__ = "assets" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(160)) asset_type: Mapped[str] = mapped_column(String(64)) address: Mapped[str | None] = mapped_column(String(255), nullable=True) status: Mapped[str] = mapped_column(String(32), default="unknown") class Monitor(Base): __tablename__ = "monitors" id: Mapped[int] = mapped_column(Integer, primary_key=True) asset_id: Mapped[int | None] = mapped_column(ForeignKey("assets.id", ondelete="CASCADE"), nullable=True) name: Mapped[str] = mapped_column(String(160)) monitor_type: Mapped[str] = mapped_column(String(64)) target: Mapped[str] = mapped_column(String(512)) config: Mapped[dict] = mapped_column(JSON, default=dict) interval_seconds: Mapped[int] = mapped_column(Integer, default=60) status: Mapped[str] = mapped_column(String(32), default="unknown") last_checked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) class CheckResult(Base): __tablename__ = "check_results" id: Mapped[int] = mapped_column(Integer, primary_key=True) monitor_id: Mapped[int] = mapped_column(ForeignKey("monitors.id", ondelete="CASCADE")) status: Mapped[str] = mapped_column(String(32)) response_time_ms: Mapped[int | None] = mapped_column(Integer, nullable=True) message: Mapped[str | None] = mapped_column(Text, nullable=True) observed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Metric(Base): __tablename__ = "metrics" id: Mapped[int] = mapped_column(Integer, primary_key=True) monitor_id: Mapped[int] = mapped_column(ForeignKey("monitors.id", ondelete="CASCADE")) name: Mapped[str] = mapped_column(String(120)) value: Mapped[float] = mapped_column(Float) unit: Mapped[str | None] = mapped_column(String(32), nullable=True) observed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Credential(Base): __tablename__ = "credentials" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(160)) credential_type: Mapped[str] = mapped_column(String(64)) encrypted_secret: Mapped[str | None] = mapped_column(Text, nullable=True) extra: Mapped[dict] = mapped_column("metadata", JSON, default=dict) class AlertRule(Base): __tablename__ = "alert_rules" id: Mapped[int] = mapped_column(Integer, primary_key=True) monitor_id: Mapped[int] = mapped_column(ForeignKey("monitors.id", ondelete="CASCADE")) name: Mapped[str] = mapped_column(String(160)) severity: Mapped[str] = mapped_column(String(32), default="warning") condition: Mapped[dict] = mapped_column(JSON, default=dict) failure_threshold: Mapped[int] = mapped_column(Integer, default=3) cooldown_seconds: Mapped[int] = mapped_column(Integer, default=300) is_enabled: Mapped[bool] = mapped_column(Boolean, default=True) class NotificationChannel(Base): __tablename__ = "notification_channels" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(160)) channel_type: Mapped[str] = mapped_column(String(64)) settings: Mapped[dict] = mapped_column(JSON, default=dict) encrypted_secret: Mapped[str | None] = mapped_column(Text, nullable=True) is_enabled: Mapped[bool] = mapped_column(Boolean, default=True) class Incident(Base): __tablename__ = "incidents" id: Mapped[int] = mapped_column(Integer, primary_key=True) asset_id: Mapped[int | None] = mapped_column(ForeignKey("assets.id", ondelete="SET NULL"), nullable=True) monitor_id: Mapped[int | None] = mapped_column(ForeignKey("monitors.id", ondelete="SET NULL"), nullable=True) alert_rule_id: Mapped[int | None] = mapped_column(ForeignKey("alert_rules.id", ondelete="SET NULL"), nullable=True) title: Mapped[str] = mapped_column(String(240)) severity: Mapped[str] = mapped_column(String(32)) status: Mapped[str] = mapped_column(String(32), default="open") opened_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) acknowledged_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) silenced_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) details: Mapped[dict] = mapped_column(JSON, default=dict)