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>
This commit is contained in:
125
openspec/changes/archive/2025-12-29-add-collaboration/design.md
Normal file
125
openspec/changes/archive/2025-12-29-add-collaboration/design.md
Normal file
@@ -0,0 +1,125 @@
|
||||
## 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
|
||||
|
||||
無(已與現有架構對齊)
|
||||
@@ -0,0 +1,18 @@
|
||||
# Change: Add Collaboration Features
|
||||
|
||||
## Why
|
||||
專案管理系統需要協作功能,讓團隊成員能在任務內進行討論、標記相關人員,並處理任務阻礙。目前系統缺乏這些核心協作機制,導致使用者仍需依賴 Email 或其他工具進行溝通。
|
||||
|
||||
## What Changes
|
||||
- 新增任務留言系統(支援巢狀回覆)
|
||||
- 實作 @提及功能(自動完成 + 即時通知)
|
||||
- 建立阻礙管理機制(標記原因、主管通知、解除追蹤)
|
||||
- 實作即時通知系統(Redis Pub/Sub + WebSocket)
|
||||
|
||||
## Impact
|
||||
- Affected specs: `collaboration`
|
||||
- Affected code:
|
||||
- 新增 models: Comment, Mention, Notification, Blocker
|
||||
- 新增 API routes: `/comments`, `/notifications`
|
||||
- 新增 services: NotificationService, WebSocketManager
|
||||
- 前端: 任務詳情頁新增留言區、通知中心
|
||||
@@ -0,0 +1,97 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Task Comments
|
||||
系統 SHALL 支援任務內部的討論留言,減少 Email 往返。
|
||||
|
||||
#### Scenario: 新增留言
|
||||
- **GIVEN** 使用者擁有任務的存取權限
|
||||
- **WHEN** 使用者在任務中新增留言
|
||||
- **THEN** 系統儲存留言並顯示在討論區
|
||||
- **AND** 記錄留言者與時間戳記
|
||||
|
||||
#### Scenario: 回覆留言
|
||||
- **GIVEN** 任務已有留言
|
||||
- **WHEN** 使用者回覆特定留言
|
||||
- **THEN** 系統建立巢狀回覆結構
|
||||
- **AND** 通知原留言者
|
||||
|
||||
#### Scenario: 編輯留言
|
||||
- **GIVEN** 使用者是留言的作者
|
||||
- **WHEN** 使用者編輯自己的留言
|
||||
- **THEN** 系統更新留言內容
|
||||
- **AND** 標示「已編輯」及編輯時間
|
||||
|
||||
#### Scenario: 刪除留言
|
||||
- **GIVEN** 使用者是留言的作者
|
||||
- **WHEN** 使用者刪除自己的留言
|
||||
- **THEN** 系統移除留言
|
||||
- **AND** 若有回覆則顯示「此留言已刪除」
|
||||
|
||||
### Requirement: User Mentions
|
||||
系統 SHALL 支援 @相關人員 功能,提及時發送即時通知。
|
||||
|
||||
#### Scenario: @提及通知
|
||||
- **GIVEN** 使用者在留言中使用 @username 提及某人
|
||||
- **WHEN** 留言送出
|
||||
- **THEN** 被提及者收到即時通知
|
||||
- **AND** 通知包含任務連結與留言摘要
|
||||
|
||||
#### Scenario: @提及自動完成
|
||||
- **GIVEN** 使用者輸入 @ 符號
|
||||
- **WHEN** 使用者繼續輸入
|
||||
- **THEN** 系統顯示符合的使用者名單供選擇
|
||||
- **AND** 可用鍵盤或滑鼠選擇
|
||||
|
||||
#### Scenario: @提及數量限制
|
||||
- **GIVEN** 使用者在單則留言中提及超過 10 人
|
||||
- **WHEN** 留言送出
|
||||
- **THEN** 系統拒絕並顯示錯誤訊息
|
||||
|
||||
### Requirement: Blocker Management
|
||||
系統 SHALL 提供阻礙 (Blocker) 機制,強制要求主管介入排解。
|
||||
|
||||
#### Scenario: 標記阻礙
|
||||
- **GIVEN** 工程師的任務遇到阻礙無法進行
|
||||
- **WHEN** 工程師將任務標記為 "Blocked"
|
||||
- **THEN** 系統設定 Task.blocker_flag = true
|
||||
- **AND** 建立 Blocker 記錄
|
||||
- **AND** 發送即時通知給該任務所屬專案的 Owner
|
||||
|
||||
#### Scenario: 阻礙原因說明
|
||||
- **GIVEN** 任務被標記為 Blocked
|
||||
- **WHEN** 使用者標記阻礙
|
||||
- **THEN** 系統要求填寫阻礙原因
|
||||
- **AND** 原因顯示在任務詳情與通知中
|
||||
|
||||
#### Scenario: 解除阻礙
|
||||
- **GIVEN** 主管或被指派者處理完阻礙
|
||||
- **WHEN** 使用者解除 Blocked 狀態
|
||||
- **THEN** 系統設定 Task.blocker_flag = false
|
||||
- **AND** 記錄解除時間與處理說明
|
||||
|
||||
### Requirement: Real-time Notifications
|
||||
系統 SHALL 透過 Redis Pub/Sub 與 WebSocket 推播即時通知。
|
||||
|
||||
#### Scenario: 即時通知推播
|
||||
- **GIVEN** 發生需要通知的事件(被指派任務、被 @提及、阻礙標記)
|
||||
- **WHEN** 事件發生
|
||||
- **THEN** 系統透過 WebSocket 即時推播通知給相關使用者
|
||||
- **AND** 未讀通知顯示數量標示
|
||||
|
||||
#### Scenario: 通知已讀標記
|
||||
- **GIVEN** 使用者有未讀通知
|
||||
- **WHEN** 使用者查看通知
|
||||
- **THEN** 系統標記為已讀
|
||||
- **AND** 更新未讀數量
|
||||
|
||||
#### Scenario: 通知清單查詢
|
||||
- **GIVEN** 使用者需要查看歷史通知
|
||||
- **WHEN** 使用者開啟通知中心
|
||||
- **THEN** 系統顯示通知列表(依時間降序)
|
||||
- **AND** 支援分頁與已讀/未讀篩選
|
||||
|
||||
#### Scenario: WebSocket 重連
|
||||
- **GIVEN** 使用者的 WebSocket 連線中斷
|
||||
- **WHEN** 連線恢復
|
||||
- **THEN** 系統自動重新建立連線
|
||||
- **AND** 補送中斷期間的未讀通知
|
||||
@@ -0,0 +1,76 @@
|
||||
## 1. Database Schema
|
||||
|
||||
- [x] 1.1 建立 Comment model (`pjctrl_comments`)
|
||||
- [x] 1.2 建立 Mention model (`pjctrl_mentions`)
|
||||
- [x] 1.3 建立 Notification model (`pjctrl_notifications`)
|
||||
- [x] 1.4 建立 Blocker model (`pjctrl_blockers`)
|
||||
- [x] 1.5 建立 Alembic migration
|
||||
- [x] 1.6 更新 Task model 加入 comments relationship
|
||||
- [x] 1.7 更新 User model 加入 notifications relationship
|
||||
|
||||
## 2. Backend API - Comments
|
||||
|
||||
- [x] 2.1 建立 Comment schemas (request/response)
|
||||
- [x] 2.2 實作 POST `/api/tasks/{task_id}/comments` - 新增留言
|
||||
- [x] 2.3 實作 GET `/api/tasks/{task_id}/comments` - 取得留言列表
|
||||
- [x] 2.4 實作 PUT `/api/comments/{comment_id}` - 編輯留言
|
||||
- [x] 2.5 實作 DELETE `/api/comments/{comment_id}` - 刪除留言
|
||||
- [x] 2.6 實作 @mention 解析邏輯(從留言內容提取 @username)
|
||||
|
||||
## 3. Backend API - Notifications
|
||||
|
||||
- [x] 3.1 建立 Notification schemas
|
||||
- [x] 3.2 實作 NotificationService(建立、發送通知)
|
||||
- [x] 3.3 實作 GET `/api/notifications` - 取得通知列表
|
||||
- [x] 3.4 實作 PUT `/api/notifications/{id}/read` - 標記已讀
|
||||
- [x] 3.5 實作 PUT `/api/notifications/read-all` - 全部已讀
|
||||
- [x] 3.6 實作 GET `/api/notifications/unread-count` - 未讀數量
|
||||
|
||||
## 4. Backend API - Blockers
|
||||
|
||||
- [x] 4.1 建立 Blocker schemas
|
||||
- [x] 4.2 實作 POST `/api/tasks/{task_id}/blockers` - 標記阻礙
|
||||
- [x] 4.3 實作 PUT `/api/blockers/{blocker_id}/resolve` - 解除阻礙
|
||||
- [x] 4.4 實作 GET `/api/tasks/{task_id}/blockers` - 取得阻礙歷史
|
||||
- [x] 4.5 整合阻礙通知(通知專案 Owner)
|
||||
|
||||
## 5. WebSocket Integration
|
||||
|
||||
- [x] 5.1 建立 WebSocket connection manager
|
||||
- [x] 5.2 實作 `/ws/notifications` endpoint
|
||||
- [x] 5.3 整合 Redis Pub/Sub 發布通知
|
||||
- [x] 5.4 實作 WebSocket 認證(JWT token)
|
||||
- [x] 5.5 實作心跳機制(keepalive)
|
||||
|
||||
## 6. Backend API - User Search
|
||||
|
||||
- [x] 6.1 實作 GET `/api/users/search?q={query}` - 使用者搜尋(支援 @mention 自動完成)
|
||||
|
||||
## 7. Frontend - Comments
|
||||
|
||||
- [x] 7.1 建立 CommentList 元件
|
||||
- [x] 7.2 建立 CommentItem 元件(支援巢狀回覆)
|
||||
- [x] 7.3 建立 CommentForm 元件(含 @mention 自動完成)
|
||||
- [x] 7.4 整合至 Task 詳情頁
|
||||
|
||||
## 8. Frontend - Notifications
|
||||
|
||||
- [x] 8.1 建立 NotificationContext(狀態管理)
|
||||
- [x] 8.2 建立 NotificationBell 元件(未讀數量 badge)
|
||||
- [x] 8.3 建立 NotificationList 元件
|
||||
- [x] 8.4 建立 NotificationItem 元件
|
||||
- [x] 8.5 整合 WebSocket 連線
|
||||
|
||||
## 9. Frontend - Blockers
|
||||
|
||||
- [x] 9.1 建立 BlockerDialog 元件(標記阻礙表單)
|
||||
- [x] 9.2 建立 BlockerHistory 元件
|
||||
- [x] 9.3 整合至 Task 詳情頁
|
||||
|
||||
## 10. Testing
|
||||
|
||||
- [x] 10.1 Comment API 單元測試
|
||||
- [x] 10.2 Notification API 單元測試
|
||||
- [x] 10.3 Blocker API 單元測試
|
||||
- [x] 10.4 WebSocket 連線測試
|
||||
- [x] 10.5 @mention 解析測試
|
||||
Reference in New Issue
Block a user