Files
PROJECT-CONTORL/backend/app/models/task.py
beabigegg 3470428411 feat: implement collaboration module
- Backend (FastAPI):
  - Task comments with nested replies and soft delete
  - @mention parsing with 10-mention limit per comment
  - Notification system with read/unread tracking
  - Blocker management with project owner notification
  - WebSocket endpoint with JWT auth and keepalive
  - User search API for @mention autocomplete
  - Alembic migration for 4 new tables

- Frontend (React + Vite):
  - Comments component with @mention autocomplete
  - NotificationBell with real-time WebSocket updates
  - BlockerDialog for task blocking workflow
  - NotificationContext for state management

- OpenSpec:
  - 4 requirements with scenarios defined
  - add-collaboration change archived

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 20:45:07 +08:00

50 lines
2.3 KiB
Python

from sqlalchemy import Column, String, Text, Integer, Boolean, DateTime, Numeric, Enum, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.core.database import Base
import enum
class Priority(str, enum.Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
URGENT = "urgent"
class Task(Base):
__tablename__ = "pjctrl_tasks"
id = Column(String(36), primary_key=True)
project_id = Column(String(36), ForeignKey("pjctrl_projects.id", ondelete="CASCADE"), nullable=False)
parent_task_id = Column(String(36), ForeignKey("pjctrl_tasks.id", ondelete="CASCADE"), nullable=True)
title = Column(String(500), nullable=False)
description = Column(Text, nullable=True)
assignee_id = Column(String(36), ForeignKey("pjctrl_users.id"), nullable=True)
status_id = Column(String(36), ForeignKey("pjctrl_task_statuses.id"), nullable=True)
priority = Column(
Enum("low", "medium", "high", "urgent", name="priority_enum"),
default="medium",
nullable=False
)
original_estimate = Column(Numeric(8, 2), nullable=True)
time_spent = Column(Numeric(8, 2), default=0, nullable=False)
blocker_flag = Column(Boolean, default=False, nullable=False)
due_date = Column(DateTime, nullable=True)
position = Column(Integer, default=0, nullable=False)
created_by = Column(String(36), ForeignKey("pjctrl_users.id"), nullable=False)
created_at = Column(DateTime, server_default=func.now(), nullable=False)
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
# Relationships
project = relationship("Project", back_populates="tasks")
parent_task = relationship("Task", remote_side=[id], back_populates="subtasks")
subtasks = relationship("Task", back_populates="parent_task", cascade="all, delete-orphan")
assignee = relationship("User", foreign_keys=[assignee_id], back_populates="assigned_tasks")
creator = relationship("User", foreign_keys=[created_by], back_populates="created_tasks")
status = relationship("TaskStatus", back_populates="tasks")
# Collaboration relationships
comments = relationship("Comment", back_populates="task", cascade="all, delete-orphan")
blockers = relationship("Blocker", back_populates="task", cascade="all, delete-orphan")