""" Backup Log model for tracking ClaudeTools database backups. This model logs all backup operations with verification status, ensuring the ClaudeTools database can be reliably restored if needed. """ from datetime import datetime from typing import Optional from sqlalchemy import ( BigInteger, CheckConstraint, Index, Integer, String, Text, ) from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.sql import func from .base import Base, UUIDMixin class BackupLog(Base, UUIDMixin): """ Backup tracking for ClaudeTools database. Logs all backup operations including timing, file details, and verification status. Ensures database can be restored with confidence. Attributes: id: Unique identifier backup_type: Type of backup (daily, weekly, monthly, manual, pre-migration) file_path: Path to the backup file file_size_bytes: Size of the backup file in bytes backup_started_at: When the backup started backup_completed_at: When the backup completed duration_seconds: Computed duration of backup operation verification_status: Status of backup verification (passed, failed, not_verified) verification_details: JSON with specific verification check results database_host: Host where database is located database_name: Name of the database backed up backup_method: Method used for backup (mysqldump, etc.) created_at: Timestamp when log entry was created """ __tablename__ = "backup_log" # Backup details backup_type: Mapped[str] = mapped_column( String(50), CheckConstraint( "backup_type IN ('daily', 'weekly', 'monthly', 'manual', 'pre-migration')" ), nullable=False, doc="Type of backup performed", ) file_path: Mapped[str] = mapped_column( String(500), nullable=False, doc="Path to the backup file", ) file_size_bytes: Mapped[int] = mapped_column( BigInteger, nullable=False, doc="Size of backup file in bytes", ) # Timing backup_started_at: Mapped[datetime] = mapped_column( nullable=False, doc="When the backup started", ) backup_completed_at: Mapped[datetime] = mapped_column( nullable=False, doc="When the backup completed", ) # Note: SQLAlchemy doesn't support TIMESTAMPDIFF directly, so we'll calculate in Python # The duration will be computed by the application layer rather than as a stored generated column duration_seconds: Mapped[Optional[int]] = mapped_column( Integer, nullable=True, doc="Duration of backup in seconds (computed in application)", ) # Verification verification_status: Mapped[Optional[str]] = mapped_column( String(50), CheckConstraint( "verification_status IN ('passed', 'failed', 'not_verified')" ), nullable=True, doc="Verification status of the backup", ) verification_details: Mapped[Optional[str]] = mapped_column( Text, nullable=True, doc="JSON with specific verification check results", ) # Metadata database_host: Mapped[Optional[str]] = mapped_column( String(255), nullable=True, doc="Host where database is located", ) database_name: Mapped[Optional[str]] = mapped_column( String(100), nullable=True, doc="Name of the database backed up", ) backup_method: Mapped[str] = mapped_column( String(50), default="mysqldump", nullable=False, doc="Method used for backup", ) created_at: Mapped[datetime] = mapped_column( nullable=False, server_default=func.now(), doc="When log entry was created", ) # Indexes __table_args__ = ( Index("idx_backup_type", "backup_type"), Index("idx_backup_date", "backup_completed_at"), Index("idx_verification_status", "verification_status"), ) def calculate_duration(self) -> None: """Calculate and set the duration_seconds field.""" if self.backup_started_at and self.backup_completed_at: delta = self.backup_completed_at - self.backup_started_at self.duration_seconds = int(delta.total_seconds()) def __repr__(self) -> str: """String representation of the backup log.""" return ( f"" )