from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Index from sqlalchemy.sql import func from app.core.database import Base class AuditLog(Base): """审计日志:记录用户的关键操作""" __tablename__ = "audit_logs" id = Column(Integer, primary_key=True, index=True) # 操作人(nullable:登录失败、token 失效等场景可能没有 user_id) user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True) username = Column(String(50), index=True, comment="冗余存储用户名,便于 user 被删除后仍能查看") # 操作内容 action = Column(String(50), nullable=False, index=True, comment="操作类型,如:network.create") resource_type = Column(String(50), nullable=True, index=True, comment="资源类型:network / ip / snmp / user / scan") resource_id = Column(String(50), nullable=True, comment="资源 ID(字符串以便兼容多种类型)") resource_name = Column(String(200), nullable=True, comment="资源名称/标识,便于阅读") # 请求信息 method = Column(String(10), comment="HTTP 方法") path = Column(String(500), comment="请求路径") ip_address = Column(String(50), comment="客户端 IP") user_agent = Column(String(500), comment="User-Agent") # 状态 status = Column(String(20), default="success", index=True, comment="success / failed") detail = Column(Text, comment="变更详情 / 错误信息 / JSON diff") created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True) # 复合索引:按时间+用户查、按时间+资源查更高效 Index("idx_audit_logs_user_created", AuditLog.user_id, AuditLog.created_at.desc()) Index("idx_audit_logs_resource", AuditLog.resource_type, AuditLog.resource_id, AuditLog.created_at.desc())