## Kanban Real-time Sync (NEW-002)
- Backend:
- WebSocket endpoint: /ws/projects/{project_id}
- Project room management in ConnectionManager
- Redis Pub/Sub: project:{project_id}:tasks channel
- Task CRUD event publishing (5 event types)
- Redis connection retry with exponential backoff
- Race condition fix in broadcast_to_project
- Frontend:
- ProjectSyncContext for WebSocket management
- Reconnection with exponential backoff (max 5 attempts)
- Multi-tab event deduplication via event_id
- Live/Offline connection indicator
- Optimistic updates with rollback
- Spec:
- collaboration spec: +1 requirement (Project Real-time Sync)
- 7 new scenarios for real-time sync
## Workload Cache Fix (NEW-001)
- Added cache invalidation to all task endpoints:
- create_task, update_task, update_task_status
- delete_task, restore_task, assign_task
- Extended to clear heatmap cache as well
## OpenSpec Archive
- 2026-01-05-add-kanban-realtime-sync
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
Collaboration
Purpose
協作功能系統,提供任務內討論、@提及通知與阻礙處理機制。
Requirements
Requirement: Task Comments
系統 SHALL 支援任務內部的討論線索,減少 Email 往返。
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 可用鍵盤或滑鼠選擇
Requirement: Blocker Management
系統 SHALL 提供阻礙 (Blocker) 機制,強制要求主管介入排解。
Scenario: 標記阻礙
- GIVEN 工程師的任務遇到阻礙無法進行
- WHEN 工程師將任務標記為 "Blocked"
- THEN 系統設定 Blocker_Flag = true
- AND 強制發送即時通知給該任務所屬專案的主管
Scenario: 阻礙原因說明
- GIVEN 任務被標記為 Blocked
- WHEN 使用者標記阻礙
- THEN 系統要求填寫阻礙原因
- AND 原因顯示在任務詳情與通知中
Scenario: 解除阻礙
- GIVEN 主管或被指派者處理完阻礙
- WHEN 使用者解除 Blocked 狀態
- THEN 系統清除 Blocker_Flag
- AND 記錄解除時間與處理說明
Requirement: Real-time Notifications
系統 SHALL 透過 Redis 推播即時通知。
Scenario: 即時通知推播
- GIVEN 發生需要通知的事件(如:被指派任務、被 @提及、阻礙標記)
- WHEN 事件發生
- THEN 系統透過 WebSocket 即時推播通知給相關使用者
- AND 未讀通知顯示數量標示
Scenario: 通知已讀標記
- GIVEN 使用者有未讀通知
- WHEN 使用者查看通知
- THEN 系統標記為已讀
- AND 更新未讀數量
Scenario: 專案事件頻道分離
- GIVEN 系統運作中
- WHEN 發生任務變更事件
- THEN 通知系統使用
notifications:{user_id}頻道推送個人通知 - AND 即時同步系統使用
project:{project_id}:tasks頻道推送專案事件 - AND 兩者互不干擾
Requirement: Project Real-time Sync
系統 SHALL 提供專案級即時同步機制,讓多位使用者同時協作時能即時看到任務變更。
Scenario: 訂閱專案即時更新
- GIVEN 使用者擁有專案的存取權限
- WHEN 使用者進入專案看板頁面
- THEN 系統自動建立 WebSocket 連線並訂閱該專案的即時更新
- AND 連線使用 JWT Token 進行身份驗證
Scenario: 接收任務狀態變更
- GIVEN 使用者已訂閱專案即時更新
- WHEN 其他使用者在同一專案中變更任務狀態
- THEN 系統透過 WebSocket 即時推送
task_status_changed事件 - AND 看板 UI 自動更新任務位置
Scenario: 接收任務建立事件
- GIVEN 使用者已訂閱專案即時更新
- WHEN 其他使用者在同一專案中建立新任務
- THEN 系統透過 WebSocket 即時推送
task_created事件 - AND 看板 UI 自動顯示新任務
Scenario: 接收任務刪除事件
- GIVEN 使用者已訂閱專案即時更新
- WHEN 其他使用者在同一專案中刪除任務
- THEN 系統透過 WebSocket 即時推送
task_deleted事件 - AND 看板 UI 自動移除該任務
Scenario: 取消訂閱專案
- GIVEN 使用者已訂閱專案即時更新
- WHEN 使用者離開專案看板頁面
- THEN 系統自動關閉 WebSocket 連線並取消訂閱
- AND 釋放相關資源
Scenario: 樂觀更新與衝突處理
- GIVEN 使用者拖曳任務改變狀態
- WHEN 本地先套用變更(樂觀更新)但 API 呼叫失敗
- THEN 系統回滾任務到原本位置
- AND 顯示錯誤訊息通知使用者
Scenario: 避免重複應用自己的事件
- GIVEN 使用者變更任務狀態並收到自己發起的事件
- WHEN WebSocket 收到該事件
- THEN 系統識別為本地發起的變更
- AND 不重複應用該變更
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
└── is_notified: BOOLEAN DEFAULT false
pjctrl_notifications
├── id: UUID (PK)
├── user_id: UUID (FK -> users)
├── type: ENUM('mention', 'assignment', 'blocker', 'status_change', 'comment')
├── reference_type: VARCHAR(50) (e.g., 'task', 'comment')
├── 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
Technical Notes
- 使用 Redis Pub/Sub 處理即時通知推播
- WebSocket 連線管理確保訊息送達
- 離線使用者登入後補送未讀通知