from enum import Enum as PyEnum from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String, Text from sqlalchemy.orm import relationship from app.models.base import BaseModel class TaskStatus(str, PyEnum): TODO = "todo" IN_PROGRESS = "in_progress" DONE = "done" CANCELLED = "cancelled" class TaskPriority(str, PyEnum): LOW = "low" MEDIUM = "medium" HIGH = "high" URGENT = "urgent" class TaskSource(str, PyEnum): MANUAL = "manual" CHAT = "chat" SCHEDULE_CENTER = "schedule_center" TODAY_STATUS = "today_status" COMMANDER = "commander" class TaskQuadrant(str, PyEnum): URGENT_IMPORTANT = "urgent-important" NOT_URGENT_IMPORTANT = "not-urgent-important" URGENT_NOT_IMPORTANT = "urgent-not-important" NOT_URGENT_NOT_IMPORTANT = "not-urgent-not-important" class TaskAssigneeType(str, PyEnum): USER = "user" COMMANDER = "commander" AGENT = "agent" PLANNER = "planner" EXECUTOR = "executor" KNOWLEDGE = "knowledge" ANALYST = "analyst" CODER = "coder" RESEARCHER = "researcher" class TaskDispatchStatus(str, PyEnum): IDLE = "idle" QUEUED = "queued" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" DispatchStatus = TaskDispatchStatus DispatchStatus = TaskDispatchStatus class TaskHistoryAction(str, PyEnum): CREATED = "created" CREATED_FROM_CHAT = "created_from_chat" UPDATED = "updated" STATUS_CHANGED = "status_changed" ASSIGNED = "assigned" DELETED = "deleted" SUBTASK_CREATED = "subtask_created" SUBTASK_UPDATED = "subtask_updated" SUBTASK_DELETED = "subtask_deleted" SUBTASK_REORDERED = "subtask_reordered" DISPATCHED_TO_COMMANDER = "dispatched_to_commander" DISPATCH_STATUS_CHANGED = "dispatch_status_changed" def enum_values(enum_cls: type[PyEnum]) -> list[str]: return [item.value for item in enum_cls] TASK_STATUS_ENUM = Enum(TaskStatus, values_callable=enum_values) TASK_PRIORITY_ENUM = Enum(TaskPriority, values_callable=enum_values) TASK_SOURCE_ENUM = Enum(TaskSource, values_callable=enum_values) TASK_QUADRANT_ENUM = Enum(TaskQuadrant, values_callable=enum_values) TASK_ASSIGNEE_TYPE_ENUM = Enum(TaskAssigneeType, values_callable=enum_values) TASK_DISPATCH_STATUS_ENUM = Enum(TaskDispatchStatus, values_callable=enum_values) class Task(BaseModel): __tablename__ = "tasks" user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True) title = Column(String(500), nullable=False) description = Column(Text, nullable=True) status = Column(TASK_STATUS_ENUM, default=TaskStatus.TODO, nullable=False, index=True) priority = Column(TASK_PRIORITY_ENUM, default=TaskPriority.MEDIUM, nullable=False) due_date = Column(DateTime, nullable=True, index=True) completed_at = Column(DateTime, nullable=True) tags = Column(String(1000), nullable=True) # JSON array source = Column(TASK_SOURCE_ENUM, default=TaskSource.MANUAL, nullable=False, index=True) conversation_id = Column(String(36), nullable=True, index=True) quadrant = Column(TASK_QUADRANT_ENUM, nullable=True, index=True) assignee_type = Column(TASK_ASSIGNEE_TYPE_ENUM, nullable=True, index=True) assignee_id = Column(String(255), nullable=True, index=True) dispatch_status = Column( TASK_DISPATCH_STATUS_ENUM, default=TaskDispatchStatus.IDLE, nullable=False, index=True, ) dispatch_run_id = Column(String(64), nullable=True, index=True) result_summary = Column(Text, nullable=True) started_at = Column(DateTime, nullable=True) last_synced_at = Column(DateTime, nullable=True) subtasks = relationship( "TaskSubTask", back_populates="task", cascade="all, delete-orphan", order_by="TaskSubTask.order_index.asc()", ) history = relationship( "TaskHistory", back_populates="task", cascade="all, delete-orphan", order_by="TaskHistory.created_at.desc()", ) class TaskSubTask(BaseModel): __tablename__ = "task_subtasks" task_id = Column(String(36), ForeignKey("tasks.id"), nullable=False, index=True) title = Column(String(500), nullable=False) description = Column(Text, nullable=True) status = Column(TASK_STATUS_ENUM, default=TaskStatus.TODO, nullable=False, index=True) order_index = Column(Integer, default=0, nullable=False, index=True) assignee_type = Column(TASK_ASSIGNEE_TYPE_ENUM, nullable=True, index=True) assignee_id = Column(String(255), nullable=True, index=True) dispatch_status = Column( TASK_DISPATCH_STATUS_ENUM, default=TaskDispatchStatus.IDLE, nullable=False, index=True, ) dispatch_run_id = Column(String(64), nullable=True, index=True) result_summary = Column(Text, nullable=True) completed_at = Column(DateTime, nullable=True) task = relationship("Task", back_populates="subtasks") class TaskHistory(BaseModel): __tablename__ = "task_histories" task_id = Column(String(36), ForeignKey("tasks.id"), nullable=False, index=True) subtask_id = Column(String(36), ForeignKey("task_subtasks.id"), nullable=True, index=True) action = Column(String(100), nullable=False) old_value = Column(Text, nullable=True) new_value = Column(Text, nullable=True) task = relationship("Task", back_populates="history")