# app/modules/dev_tools/models/architecture_scan.py """ Architecture Scan Models Database models for tracking code quality scans and violations. This is the canonical location - models are re-exported from the legacy location for backward compatibility. """ from sqlalchemy import ( JSON, Boolean, Column, DateTime, Float, ForeignKey, Integer, String, Text, ) from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base class ArchitectureScan(Base): """Represents a single run of a code quality validator""" __tablename__ = "architecture_scans" id = Column(Integer, primary_key=True, index=True) timestamp = Column( DateTime(timezone=True), server_default=func.now(), nullable=False, index=True ) validator_type = Column( String(20), nullable=False, index=True, default="architecture" ) # 'architecture', 'security', 'performance' # Background task status fields (harmonized architecture) status = Column( String(30), nullable=False, default="pending", index=True ) # 'pending', 'running', 'completed', 'failed', 'completed_with_warnings' started_at = Column(DateTime(timezone=True), nullable=True) completed_at = Column(DateTime(timezone=True), nullable=True) error_message = Column(Text, nullable=True) progress_message = Column(String(255), nullable=True) # Current step description # Scan results total_files = Column(Integer, default=0) total_violations = Column(Integer, default=0) errors = Column(Integer, default=0) warnings = Column(Integer, default=0) duration_seconds = Column(Float, default=0.0) triggered_by = Column(String(100)) # 'manual:username', 'scheduled', 'ci/cd' git_commit_hash = Column(String(40)) # Celery task tracking (optional - for USE_CELERY=true) celery_task_id = Column(String(255), nullable=True, index=True) # Relationship to violations violations = relationship( "ArchitectureViolation", back_populates="scan", cascade="all, delete-orphan" ) def __repr__(self): return f"" class ArchitectureViolation(Base): """Represents a single code quality violation found during a scan""" __tablename__ = "architecture_violations" id = Column(Integer, primary_key=True, index=True) scan_id = Column( Integer, ForeignKey("architecture_scans.id"), nullable=False, index=True ) validator_type = Column( String(20), nullable=False, index=True, default="architecture" ) # 'architecture', 'security', 'performance' rule_id = Column(String(20), nullable=False, index=True) # e.g., 'API-001', 'SEC-001', 'PERF-001' rule_name = Column(String(200), nullable=False) severity = Column( String(10), nullable=False, index=True ) # 'error', 'warning', 'info' file_path = Column(String(500), nullable=False, index=True) line_number = Column(Integer, nullable=False) message = Column(Text, nullable=False) context = Column(Text) # Code snippet suggestion = Column(Text) status = Column( String(20), default="open", index=True ) # 'open', 'assigned', 'resolved', 'ignored', 'technical_debt' assigned_to = Column(Integer, ForeignKey("users.id")) resolved_at = Column(DateTime(timezone=True)) resolved_by = Column(Integer, ForeignKey("users.id")) resolution_note = Column(Text) created_at = Column( DateTime(timezone=True), server_default=func.now(), nullable=False ) # Relationships scan = relationship("ArchitectureScan", back_populates="violations") assigned_user = relationship( "User", foreign_keys=[assigned_to], backref="assigned_violations" ) resolver = relationship( "User", foreign_keys=[resolved_by], backref="resolved_violations" ) assignments = relationship( "ViolationAssignment", back_populates="violation", cascade="all, delete-orphan" ) comments = relationship( "ViolationComment", back_populates="violation", cascade="all, delete-orphan" ) def __repr__(self): return f"" class ArchitectureRule(Base): """Code quality rules configuration (from YAML with database overrides)""" __tablename__ = "architecture_rules" id = Column(Integer, primary_key=True, index=True) rule_id = Column( String(20), unique=True, nullable=False, index=True ) # e.g., 'API-001', 'SEC-001', 'PERF-001' validator_type = Column( String(20), nullable=False, index=True, default="architecture" ) # 'architecture', 'security', 'performance' category = Column( String(50), nullable=False ) # 'api_endpoint', 'service_layer', 'authentication', 'database', etc. name = Column(String(200), nullable=False) description = Column(Text) severity = Column(String(10), nullable=False) # Can override default from YAML enabled = Column(Boolean, default=True, nullable=False) custom_config = Column(JSON) # For rule-specific settings created_at = Column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at = Column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) def __repr__(self): return f"" class ViolationAssignment(Base): """Tracks assignment of violations to developers""" __tablename__ = "violation_assignments" id = Column(Integer, primary_key=True, index=True) violation_id = Column( Integer, ForeignKey("architecture_violations.id"), nullable=False, index=True ) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) assigned_at = Column( DateTime(timezone=True), server_default=func.now(), nullable=False ) assigned_by = Column(Integer, ForeignKey("users.id")) due_date = Column(DateTime(timezone=True)) priority = Column( String(10), default="medium" ) # 'low', 'medium', 'high', 'critical' # Relationships violation = relationship("ArchitectureViolation", back_populates="assignments") user = relationship("User", foreign_keys=[user_id], backref="violation_assignments") assigner = relationship( "User", foreign_keys=[assigned_by], backref="assigned_by_me" ) def __repr__(self): return f"" class ViolationComment(Base): """Comments on violations for collaboration""" __tablename__ = "violation_comments" id = Column(Integer, primary_key=True, index=True) violation_id = Column( Integer, ForeignKey("architecture_violations.id"), nullable=False, index=True ) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) comment = Column(Text, nullable=False) created_at = Column( DateTime(timezone=True), server_default=func.now(), nullable=False ) # Relationships violation = relationship("ArchitectureViolation", back_populates="comments") user = relationship("User", backref="violation_comments") def __repr__(self): return f""