import uuid from datetime import datetime from sqlalchemy import Column, String, Integer, BigInteger, Boolean, Text, ARRAY, Numeric from sqlalchemy import DateTime, ForeignKey, func from sqlalchemy.dialects.postgresql import UUID, JSONB, INET from sqlalchemy.orm import DeclarativeBase, relationship class Base(DeclarativeBase): pass class Workspace(Base): __tablename__ = "workspaces" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column(String(255), nullable=False) description = Column(Text) domain = Column(String(100)) created_by = Column(String(255)) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) files = relationship("File", back_populates="workspace") class File(Base): __tablename__ = "files" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) workspace_id = Column(UUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE")) filename = Column(String(500), nullable=False) original_name = Column(String(500), nullable=False) file_type = Column(String(50)) file_size = Column(BigInteger) storage_path = Column(Text) parsed_path = Column(Text) status = Column(String(50), default="uploaded") error_msg = Column(Text) metadata = Column(JSONB, default={}) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) workspace = relationship("Workspace", back_populates="files") tasks = relationship("Task", back_populates="file") class Task(Base): __tablename__ = "tasks" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) task_type = Column(String(100), nullable=False) status = Column(String(50), default="pending") payload = Column(JSONB, default={}) result = Column(JSONB) error_msg = Column(Text) progress = Column(Integer, default=0) file_id = Column(UUID(as_uuid=True), ForeignKey("files.id")) celery_task_id = Column(String(255)) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) completed_at = Column(DateTime(timezone=True)) file = relationship("File", back_populates="tasks") class ComplianceReport(Base): __tablename__ = "compliance_reports" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) file_id = Column(UUID(as_uuid=True), ForeignKey("files.id")) regulation_domains = Column(ARRAY(Text)) overall_risk_level = Column(String(20)) risk_score = Column(Numeric(5, 2)) findings = Column(JSONB, default=[]) recommendations = Column(JSONB, default=[]) report_markdown = Column(Text) llm_model = Column(String(100)) created_at = Column(DateTime(timezone=True), server_default=func.now()) class RegulationSource(Base): __tablename__ = "regulation_sources" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column(String(255), nullable=False) url = Column(Text, nullable=False) source_type = Column(String(50), default="webpage") domain = Column(String(100)) fetch_interval = Column(Integer, default=86400) is_active = Column(Boolean, default=True) last_fetched_at = Column(DateTime(timezone=True)) last_hash = Column(String(64)) fetch_config = Column(JSONB, default={}) created_at = Column(DateTime(timezone=True), server_default=func.now()) class RegulationUpdate(Base): __tablename__ = "regulation_updates" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) source_id = Column(UUID(as_uuid=True), ForeignKey("regulation_sources.id")) title = Column(String(500)) url = Column(Text) change_type = Column(String(50)) summary = Column(Text) raw_content = Column(Text) diff_content = Column(Text) is_notified = Column(Boolean, default=False) importance = Column(String(20), default="normal") fetched_at = Column(DateTime(timezone=True), server_default=func.now()) published_at = Column(DateTime(timezone=True))