# app/models/syndarix/project.py """ Project model for Syndarix AI consulting platform. A Project represents a client engagement where AI agents collaborate to deliver software solutions. """ from sqlalchemy import Column, Enum, ForeignKey, Index, String, Text from sqlalchemy.dialects.postgresql import ( JSONB, UUID as PGUUID, ) from sqlalchemy.orm import relationship from app.models.base import Base, TimestampMixin, UUIDMixin from .enums import AutonomyLevel, ClientMode, ProjectComplexity, ProjectStatus class Project(Base, UUIDMixin, TimestampMixin): """ Project model representing a client engagement. A project contains: - Configuration for how autonomous agents should operate - Settings for MCP server integrations - Relationship to assigned agents, issues, and sprints """ __tablename__ = "projects" name = Column(String(255), nullable=False, index=True) slug = Column(String(255), unique=True, nullable=False, index=True) description = Column(Text, nullable=True) autonomy_level: Column[AutonomyLevel] = Column( Enum( AutonomyLevel, name="autonomy_level", values_callable=lambda x: [e.value for e in x], ), default=AutonomyLevel.MILESTONE, nullable=False, index=True, ) status: Column[ProjectStatus] = Column( Enum( ProjectStatus, name="project_status", values_callable=lambda x: [e.value for e in x], ), default=ProjectStatus.ACTIVE, nullable=False, index=True, ) complexity: Column[ProjectComplexity] = Column( Enum( ProjectComplexity, name="project_complexity", values_callable=lambda x: [e.value for e in x], ), default=ProjectComplexity.MEDIUM, nullable=False, index=True, ) client_mode: Column[ClientMode] = Column( Enum( ClientMode, name="client_mode", values_callable=lambda x: [e.value for e in x], ), default=ClientMode.AUTO, nullable=False, index=True, ) # JSON field for flexible project configuration # Can include: mcp_servers, webhook_urls, notification_settings, etc. settings = Column(JSONB, default=dict, nullable=False) # Foreign key to the User who owns this project owner_id = Column( PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True, ) # Relationships owner = relationship("User", foreign_keys=[owner_id]) agent_instances = relationship( "AgentInstance", back_populates="project", cascade="all, delete-orphan", ) issues = relationship( "Issue", back_populates="project", cascade="all, delete-orphan", ) sprints = relationship( "Sprint", back_populates="project", cascade="all, delete-orphan", ) __table_args__ = ( Index("ix_projects_slug_status", "slug", "status"), Index("ix_projects_owner_status", "owner_id", "status"), Index("ix_projects_autonomy_status", "autonomy_level", "status"), Index("ix_projects_complexity_status", "complexity", "status"), ) def __repr__(self) -> str: return f""