# 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 連線管理確保訊息送達 - 離線使用者登入後補送未讀通知