refactor: replace issues backend with milestone tasks
This commit is contained in:
@@ -7,8 +7,8 @@ class ActivityLog(Base):
|
||||
__tablename__ = "activity_logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
action = Column(String(50), nullable=False) # e.g. "issue.created", "comment.added"
|
||||
entity_type = Column(String(50), nullable=False) # "issue", "project", "comment"
|
||||
action = Column(String(50), nullable=False) # e.g. "task.created", "comment.added"
|
||||
entity_type = Column(String(50), nullable=False) # "task", "project", "comment"
|
||||
entity_id = Column(Integer, nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
details = Column(Text, nullable=True) # JSON string
|
||||
|
||||
@@ -6,96 +6,42 @@ from app.models.role_permission import Role
|
||||
import enum
|
||||
|
||||
|
||||
class IssueType(str, enum.Enum):
|
||||
MEETING = "meeting"
|
||||
SUPPORT = "support"
|
||||
class TaskType(str, enum.Enum):
|
||||
"""Task type enum — 'issue' is a subtype of task, not the other way around."""
|
||||
ISSUE = "issue"
|
||||
MAINTENANCE = "maintenance"
|
||||
RESEARCH = "research"
|
||||
REVIEW = "review"
|
||||
STORY = "story"
|
||||
TEST = "test"
|
||||
RESOLUTION = "resolution" # 决议案 - 用于 Agent 僵局提交
|
||||
TASK = "task" # legacy generic type
|
||||
RESOLUTION = "resolution"
|
||||
TASK = "task"
|
||||
|
||||
|
||||
class IssueStatus(str, enum.Enum):
|
||||
class TaskStatus(str, enum.Enum):
|
||||
OPEN = "open"
|
||||
IN_PROGRESS = "in_progress"
|
||||
RESOLVED = "resolved"
|
||||
PENDING = "pending"
|
||||
PROGRESSING = "progressing"
|
||||
CLOSED = "closed"
|
||||
BLOCKED = "blocked"
|
||||
|
||||
|
||||
class IssuePriority(str, enum.Enum):
|
||||
class TaskPriority(str, enum.Enum):
|
||||
LOW = "low"
|
||||
MEDIUM = "medium"
|
||||
HIGH = "high"
|
||||
CRITICAL = "critical"
|
||||
|
||||
|
||||
class Issue(Base):
|
||||
__tablename__ = "issues"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
title = Column(String(255), nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
issue_type = Column(String(32), default=IssueType.ISSUE.value)
|
||||
issue_subtype = Column(String(64), nullable=True)
|
||||
status = Column(Enum(IssueStatus), default=IssueStatus.OPEN)
|
||||
priority = Column(Enum(IssuePriority), default=IssuePriority.MEDIUM)
|
||||
|
||||
# Relationships
|
||||
project_id = Column(Integer, ForeignKey("projects.id"), nullable=False)
|
||||
reporter_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
assignee_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# Resolution specific fields (for RESOLUTION type)
|
||||
resolution_summary = Column(Text, nullable=True) # 僵局摘要
|
||||
positions = Column(Text, nullable=True) # 各方立场 (JSON)
|
||||
pending_matters = Column(Text, nullable=True) # 待决事项
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
# Tags (comma-separated for simplicity)
|
||||
tags = Column(String(500), nullable=True)
|
||||
|
||||
# Dependencies
|
||||
depends_on_id = Column(Integer, ForeignKey("issues.id"), nullable=True)
|
||||
|
||||
# Due date and milestone
|
||||
due_date = Column(DateTime(timezone=True), nullable=True)
|
||||
milestone_id = Column(Integer, ForeignKey("milestones.id"), nullable=True)
|
||||
|
||||
# Task-specific fields
|
||||
task_code = Column(String(64), nullable=True, unique=True, index=True)
|
||||
depend_on = Column(Text, nullable=True) # JSON list of task codes
|
||||
estimated_effort = Column(Integer, nullable=True) # 1-10
|
||||
estimated_working_time = Column(Time(timezone=True), nullable=True)
|
||||
task_status = Column(String(32), default="open") # open, closed, pending, progressing
|
||||
started_on = Column(DateTime(timezone=True), nullable=True)
|
||||
finished_on = Column(DateTime(timezone=True), nullable=True)
|
||||
related_tasks = Column(Text, nullable=True) # JSON list of task codes
|
||||
created_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
project = relationship("Project", back_populates="issues")
|
||||
reporter = relationship("User", foreign_keys=[reporter_id], back_populates="reported_issues")
|
||||
assignee = relationship("User", foreign_keys=[assignee_id], back_populates="assigned_issues")
|
||||
comments = relationship("Comment", back_populates="issue", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class Comment(Base):
|
||||
__tablename__ = "comments"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
content = Column(Text, nullable=False)
|
||||
issue_id = Column(Integer, ForeignKey("issues.id"), nullable=False)
|
||||
task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False)
|
||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
issue = relationship("Issue", back_populates="comments")
|
||||
author = relationship("User", back_populates="comments")
|
||||
|
||||
|
||||
@@ -114,7 +60,6 @@ class Project(Base):
|
||||
|
||||
owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
|
||||
issues = relationship("Issue", back_populates="project", cascade="all, delete-orphan")
|
||||
members = relationship("ProjectMember", back_populates="project", cascade="all, delete-orphan")
|
||||
owner = relationship("User", back_populates="owned_projects")
|
||||
|
||||
@@ -125,15 +70,13 @@ class User(Base):
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
username = Column(String(50), unique=True, nullable=False)
|
||||
email = Column(String(100), unique=True, nullable=False)
|
||||
hashed_password = Column(String(255), nullable=True) # Nullable for OAuth users
|
||||
hashed_password = Column(String(255), nullable=True)
|
||||
full_name = Column(String(100), nullable=True)
|
||||
is_active = Column(Boolean, default=True)
|
||||
is_admin = Column(Boolean, default=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
owned_projects = relationship("Project", back_populates="owner")
|
||||
reported_issues = relationship("Issue", foreign_keys=[Issue.reporter_id], back_populates="reporter")
|
||||
assigned_issues = relationship("Issue", foreign_keys=[Issue.assignee_id], back_populates="assignee")
|
||||
comments = relationship("Comment", back_populates="author")
|
||||
project_memberships = relationship("ProjectMember", back_populates="user")
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ class Notification(Base):
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
type = Column(String(50), nullable=False) # issue.assigned, issue.mentioned, comment.added, milestone.due
|
||||
type = Column(String(50), nullable=False) # task.assigned, task.mentioned, comment.added, milestone.due
|
||||
title = Column(String(255), nullable=False)
|
||||
message = Column(Text, nullable=True)
|
||||
entity_type = Column(String(50), nullable=True) # issue, comment, milestone
|
||||
entity_type = Column(String(50), nullable=True) # task, comment, milestone
|
||||
entity_id = Column(Integer, nullable=True)
|
||||
is_read = Column(Boolean, default=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
@@ -26,18 +26,35 @@ class Task(Base):
|
||||
priority = Column(Enum(TaskPriority), default=TaskPriority.MEDIUM)
|
||||
task_code = Column(String(64), nullable=True, unique=True, index=True)
|
||||
|
||||
# Task type/subtype (replaces old issue_type/issue_subtype)
|
||||
task_type = Column(String(32), default="task")
|
||||
task_subtype = Column(String(64), nullable=True)
|
||||
|
||||
project_id = Column(Integer, ForeignKey("projects.id"), nullable=False)
|
||||
milestone_id = Column(Integer, ForeignKey("milestones.id"), nullable=False)
|
||||
reporter_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
assignee_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
created_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# Tags (comma-separated)
|
||||
tags = Column(String(500), nullable=True)
|
||||
|
||||
# Dependencies
|
||||
depend_on = Column(Text, nullable=True)
|
||||
related_tasks = Column(Text, nullable=True)
|
||||
|
||||
# Effort tracking
|
||||
estimated_effort = Column(Integer, nullable=True)
|
||||
estimated_working_time = Column(Time, nullable=True)
|
||||
started_on = Column(DateTime(timezone=True), nullable=True)
|
||||
finished_on = Column(DateTime(timezone=True), nullable=True)
|
||||
related_tasks = Column(Text, nullable=True)
|
||||
|
||||
# Resolution specific fields (for task_type="resolution")
|
||||
resolution_summary = Column(Text, nullable=True)
|
||||
positions = Column(Text, nullable=True)
|
||||
pending_matters = Column(Text, nullable=True)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
comments = relationship("Comment", foreign_keys="Comment.task_id", cascade="all, delete-orphan")
|
||||
|
||||
@@ -5,10 +5,10 @@ import enum
|
||||
|
||||
|
||||
class WebhookEvent(str, enum.Enum):
|
||||
ISSUE_CREATED = "issue.created"
|
||||
ISSUE_UPDATED = "issue.updated"
|
||||
ISSUE_CLOSED = "issue.closed"
|
||||
ISSUE_DELETED = "issue.deleted"
|
||||
TASK_CREATED = "task.created"
|
||||
TASK_UPDATED = "task.updated"
|
||||
TASK_CLOSED = "task.closed"
|
||||
TASK_DELETED = "task.deleted"
|
||||
COMMENT_CREATED = "comment.created"
|
||||
RESOLUTION_CREATED = "resolution.created"
|
||||
MEMBER_ADDED = "member.added"
|
||||
|
||||
@@ -7,9 +7,9 @@ class WorkLog(Base):
|
||||
__tablename__ = "work_logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
issue_id = Column(Integer, ForeignKey("issues.id"), nullable=False)
|
||||
task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
hours = Column(Float, nullable=False) # Hours spent
|
||||
hours = Column(Float, nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
logged_date = Column(DateTime(timezone=True), nullable=False) # When the work was done
|
||||
logged_date = Column(DateTime(timezone=True), nullable=False)
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
Reference in New Issue
Block a user