Files
PROJECT-CONTORL/openspec/changes/archive/2025-12-29-add-collaboration/design.md
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

3.9 KiB
Raw Blame History

Context

協作功能需要整合多個子系統:留言、@提及、阻礙管理、即時通知。這些功能與現有的 Task 模組緊密耦合,且需要引入 WebSocket 即時通訊機制。

Goals / Non-Goals

Goals:

  • 提供任務內留言討論功能
  • 實作 @提及與即時通知
  • 建立阻礙追蹤與主管通知機制
  • 使用 Redis Pub/Sub 處理即時推播

Non-Goals:

  • 不實作 Email 通知(未來功能)
  • 不實作離線訊息佇列
  • 不實作留言的 Markdown 編輯器(僅純文字)

Decisions

1. 留言儲存結構

  • 決策: 使用巢狀結構parent_comment_id支援回覆
  • 理由: 簡單且符合大多數專案管理工具的 UX 模式

2. @提及解析

  • 決策: 後端解析留言內容,提取 @username 模式並建立 Mention 記錄
  • 理由: 前端負責顯示建議,後端負責實際通知邏輯

3. 即時通知架構

  • 決策: Redis Pub/Sub + WebSocket (FastAPI WebSocket)
  • 替代方案:
    • Server-Sent Events (SSE) - 單向,不支援雙向互動
    • Polling - 延遲高,資源浪費
  • 理由: WebSocket 提供低延遲雙向通訊Redis 已在架構中使用

4. 阻礙管理

  • 決策: 新增獨立 pjctrl_blockers 表記錄阻礙詳情
  • 理由: Task 的 blocker_flag 只是布林值,需要追蹤原因、處理人、解除說明

Risks / Trade-offs

風險 緩解措施
WebSocket 連線管理複雜度 使用連線池,實作心跳機制
通知量過大導致效能問題 實作批次處理、設定通知合併策略
@提及被濫用 限制單則留言最多提及 10 人

Data Model

pjctrl_comments
├── id: UUID (PK)
├── task_id: UUID (FK -> tasks)
├── parent_comment_id: UUID (FK -> comments, nullable)
├── author_id: UUID (FK -> users)
├── content: TEXT
├── is_edited: BOOLEAN DEFAULT false
├── created_at: TIMESTAMP
└── updated_at: TIMESTAMP

pjctrl_mentions
├── id: UUID (PK)
├── comment_id: UUID (FK -> comments)
├── mentioned_user_id: UUID (FK -> users)
└── created_at: TIMESTAMP

pjctrl_notifications
├── id: UUID (PK)
├── user_id: UUID (FK -> users)
├── type: ENUM('mention', 'assignment', 'blocker', 'status_change', 'comment')
├── reference_type: VARCHAR(50)
├── reference_id: UUID
├── title: VARCHAR(200)
├── message: TEXT
├── is_read: BOOLEAN DEFAULT false
├── created_at: TIMESTAMP
└── read_at: TIMESTAMP

pjctrl_blockers
├── id: UUID (PK)
├── task_id: UUID (FK -> tasks)
├── reported_by: UUID (FK -> users)
├── reason: TEXT
├── resolved_by: UUID (FK -> users, nullable)
├── resolution_note: TEXT
├── created_at: TIMESTAMP
└── resolved_at: TIMESTAMP

API Design

# Comments
POST   /api/tasks/{task_id}/comments          # 新增留言
GET    /api/tasks/{task_id}/comments          # 取得任務留言列表
PUT    /api/comments/{comment_id}             # 編輯留言
DELETE /api/comments/{comment_id}             # 刪除留言

# Notifications
GET    /api/notifications                     # 取得通知列表
PUT    /api/notifications/{id}/read           # 標記已讀
PUT    /api/notifications/read-all            # 全部已讀
GET    /api/notifications/unread-count        # 取得未讀數量

# Blockers
POST   /api/tasks/{task_id}/blockers          # 標記阻礙
PUT    /api/blockers/{blocker_id}/resolve     # 解除阻礙
GET    /api/tasks/{task_id}/blockers          # 取得阻礙歷史

# WebSocket
WS     /ws/notifications                      # 即時通知連線

# User Search (for @mention autocomplete)
GET    /api/users/search?q={query}            # 搜尋使用者

Migration Plan

  1. 新增資料表(無 breaking changes
  2. Task model 新增 comments relationship
  3. User model 新增 notifications relationship
  4. 前端漸進式整合

Open Questions

無(已與現有架構對齊)