from datetime import datetime, timezone from sqlalchemy import BigInteger, Column, DateTime, Index, String, Text, UniqueConstraint from sqlalchemy.dialects.postgresql import JSONB from database.postgres import Base def _now(): return datetime.now(timezone.utc) class DeviceAlert(Base): """Current alert state per device+subsystem (upserted, not appended).""" __tablename__ = "device_alerts" __table_args__ = ( UniqueConstraint("device_serial", "subsystem"), Index("idx_device_alerts_serial", "device_serial"), ) id = Column(BigInteger, primary_key=True, autoincrement=True) device_serial = Column(String(128), nullable=False) subsystem = Column(String(128), nullable=False) state = Column(String(64), nullable=False) message = Column(Text) updated_at = Column(DateTime(timezone=True), nullable=False, default=_now, onupdate=_now) # NOTE: device_logs, commands, and heartbeats are NOT declared as ORM models here. # device_logs is a partitioned table — SQLAlchemy ORM does not support declarative # partitioned tables cleanly. All three tables are created via raw SQL in the # Alembic migration and accessed via raw queries in database/core.py (SQLite now) # and will be accessed via raw async SQL after Phase 5 cutover.