# PROJECT CONTROL - Issue Tracking > 審核日期: 2026-01-04 > 更新日期: 2026-01-05 > 整體完成度: 約 99% > 已修復問題: 25 (CRIT-001~003, HIGH-001~008, MED-001~012, NEW-001~002) --- ## 目錄 - [嚴重問題 (Critical)](#嚴重問題-critical) - [高優先問題 (High)](#高優先問題-high) - [中優先問題 (Medium)](#中優先問題-medium) - [低優先問題 (Low)](#低優先問題-low) - [未實作功能 (Missing Features)](#未實作功能-missing-features) - [可訪問性問題 (Accessibility)](#可訪問性問題-accessibility) - [程式碼品質建議 (Code Quality)](#程式碼品質建議-code-quality) --- ## 嚴重問題 (Critical) ### CRIT-001: JWT 密鑰硬編碼 - **類型**: 安全漏洞 - **模組**: Backend - Authentication - **檔案**: `backend/app/core/config.py:28` - **問題描述**: JWT secret key 有硬編碼的預設值 `"your-secret-key-change-in-production"`,若部署時未設定環境變數,所有 JWT token 都可被偽造。 - **影響**: 完全繞過認證系統 - **建議修復**: ```python JWT_SECRET_KEY: str = "" # 移除預設值 def __init__(self, **kwargs): super().__init__(**kwargs) if not self.JWT_SECRET_KEY or self.JWT_SECRET_KEY == "your-secret-key-change-in-production": raise ValueError("JWT_SECRET_KEY must be set in environment") ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 使用 pydantic @field_validator 驗證 JWT_SECRET_KEY,拒絕空值和佔位符值 --- ### CRIT-002: 登入嘗試未記錄稽核日誌 - **類型**: 安全漏洞 - **模組**: Backend - Authentication / Audit - **檔案**: `backend/app/api/auth/router.py` - **問題描述**: Spec 要求記錄失敗的登入嘗試,但 auth router 未呼叫 AuditService.log_event() 記錄登入成功/失敗。 - **影響**: 無法偵測暴力破解攻擊,稽核追蹤不完整 - **建議修復**: ```python # 登入成功時 AuditService.log_event( db=db, event_type="user.login", resource_type="user", action=AuditAction.LOGIN, user_id=user.id, ... ) # 登入失敗時 AuditService.log_event( db=db, event_type="user.login_failed", ... ) ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 在 login endpoint 添加 AuditService.log_event() 呼叫,記錄成功/失敗的登入嘗試,包含 IP 和 User-Agent --- ### CRIT-003: 前端 API 路徑重複導致請求失敗 - **類型**: Bug - **模組**: Frontend - Core - **檔案**: - `frontend/src/pages/Spaces.tsx:29, 43` - `frontend/src/pages/Projects.tsx:44-45, 61` - `frontend/src/pages/Tasks.tsx:54-56, 73, 86` - **問題描述**: API 呼叫使用 `/api/spaces` 但 axios baseURL 已設為 `/api`,導致實際請求路徑變成 `/api/api/spaces`。 - **影響**: Spaces、Projects、Tasks 頁面所有 API 呼叫都會失敗 - **建議修復**: ```typescript // 錯誤: const response = await api.get('/api/spaces') // 正確: const response = await api.get('/spaces') ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 移除 Spaces.tsx, Projects.tsx, Tasks.tsx, attachments.ts 中所有 API 路徑的 `/api` 前綴 --- ## 高優先問題 (High) ### HIGH-001: 專案刪除使用硬刪除 - **類型**: 資料完整性 - **模組**: Backend - Projects - **檔案**: `backend/app/api/projects/router.py:268-307` - **問題描述**: 專案刪除使用 `db.delete(project)` 硬刪除,但 Audit Trail spec 要求所有刪除操作使用軟刪除。 - **影響**: 資料遺失,稽核日誌無法參照已刪除專案 - **建議修復**: 為 Project model 新增 `is_deleted`, `deleted_at`, `deleted_by` 欄位,實作軟刪除 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 使用現有 is_active 欄位實作軟刪除,delete_project 設定 is_active=False 而非 db.delete() --- ### HIGH-002: Redis Session Token 類型比對問題 - **類型**: Bug - **模組**: Backend - Authentication - **檔案**: `backend/app/middleware/auth.py:43-50` - **問題描述**: Redis `get()` 在某些配置下回傳 bytes,與字串 token 比對可能失敗。 - **影響**: 使用者可能意外被登出 - **建議修復**: ```python stored_token = redis_client.get(f"session:{user_id}") if stored_token is None: raise HTTPException(...) if isinstance(stored_token, bytes): stored_token = stored_token.decode('utf-8') if stored_token != token: raise HTTPException(...) ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 在 middleware/auth.py 添加 bytes 類型檢查和 decode 處理 --- ### HIGH-003: 無 Rate Limiting 實作 - **類型**: 安全漏洞 - **模組**: Backend - API - **檔案**: 多個 API endpoints - **問題描述**: Spec 提及 rate limiting,但未實作任何速率限制中介軟體。 - **影響**: API 易受暴力破解和 DoS 攻擊 - **建議修復**: ```python from slowapi import Limiter from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address) @router.post("/login") @limiter.limit("5/minute") async def login(...): ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 使用 slowapi 實作 rate limiting,login endpoint 限制 5 req/min,測試環境使用 memory storage --- ### HIGH-004: 附件 API 缺少權限檢查 - **類型**: 安全漏洞 - **模組**: Backend - Attachments - **檔案**: `backend/app/api/attachments/router.py` - **問題描述**: 附件 endpoints 只檢查任務是否存在,未驗證當前使用者是否有權存取該任務的專案。`check_task_access` 函數存在但未被呼叫。 - **影響**: 使用者可上傳/下載不應有權存取的任務附件 - **建議修復**: 在每個 endpoint 加入 `check_task_access(current_user, task, task.project)` 呼叫 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 get_task_with_access_check 和 get_attachment_with_access_check 輔助函數,所有 endpoints 都使用這些函數進行權限驗證 --- ### HIGH-005: 任務視角僅有列表視角 - **類型**: 功能缺失 - **模組**: Frontend - Task Management - **檔案**: `frontend/src/pages/Tasks.tsx` - **問題描述**: Spec 要求 4 種視角 (Kanban, Gantt, List, Calendar),目前僅實作列表視角。 - **影響**: 無法滿足不同工作流程需求 - **建議修復**: 優先實作看板 (Kanban) 視角,支援拖拉變更狀態 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 KanbanBoard.tsx 元件,支援 HTML5 drag-and-drop 變更狀態,Tasks.tsx 新增 List/Kanban 切換按鈕,偏好設定儲存於 localStorage --- ### HIGH-006: 資源管理模組前端 UI 未開發 - **類型**: 功能缺失 - **模組**: Frontend - Resource Management - **檔案**: - - **問題描述**: 整個資源管理模組前端未開發,包括負載熱圖、容量規劃、專案健康看板。 - **影響**: 主管無法視覺化查看團隊工作負載 - **建議修復**: 開發 WorkloadHeatmap 元件和相關頁面 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 WorkloadPage.tsx、WorkloadHeatmap.tsx、WorkloadUserDetail.tsx 元件,完整實作負載熱圖視覺化功能 --- ### HIGH-007: 協作/附件/觸發器元件未整合 - **類型**: 功能缺失 - **模組**: Frontend - Integration - **檔案**: - `frontend/src/components/Comments.tsx` - 未使用 - `frontend/src/components/TaskAttachments.tsx` - 未使用 - `frontend/src/components/TriggerList.tsx` - 未使用 - `frontend/src/components/TriggerForm.tsx` - 未使用 - **問題描述**: 多個元件已開發但未整合進任何頁面或路由。 - **影響**: 使用者無法使用留言、附件管理、觸發器設定功能 - **建議修復**: 1. 建立任務詳情頁面/Modal,整合 Comments 和 Attachments 2. 新增 /automation 路由整合 TriggerList/TriggerForm - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 TaskDetailModal.tsx 元件,整合 Comments 和 TaskAttachments,點擊任務卡片/列表項目即可開啟詳細視窗 --- ### HIGH-008: 任務指派 UI 缺失 - **類型**: 功能缺失 - **模組**: Frontend - Task Management - **檔案**: `frontend/src/pages/Tasks.tsx` - **問題描述**: 建立/編輯任務時無法選擇指派者 (assignee),無法設定時間估算。 - **影響**: 核心任務管理功能不完整 - **建議修復**: 在任務建立 Modal 新增指派者下拉選單和時間估算欄位 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 UserSelect.tsx 元件提供使用者搜尋下拉選單,Tasks.tsx 建立任務 Modal 新增指派者、到期日、時間估算欄位,TaskDetailModal 支援編輯這些欄位 --- ## 中優先問題 (Medium) ### MED-001: 附件 Router 重複 Commit - **類型**: 效能問題 - **模組**: Backend - Attachments - **檔案**: `backend/app/api/attachments/router.py:118-133, 178-192` - **問題描述**: 同一請求中多次 `db.commit()`,效率低且可能導致部分交易狀態。 - **建議修復**: 移除重複 commit,使用單一交易 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 移除 attachments/router.py 中 4 處重複的 db.commit() 呼叫 --- ### MED-002: 負載熱圖 N+1 查詢 - **類型**: 效能問題 - **模組**: Backend - Resource Management - **檔案**: `backend/app/services/workload_service.py:169-210` - **問題描述**: 計算多使用者負載時,對每個使用者分別查詢任務。 - **影響**: 使用者數量增加時資料庫效能下降 - **建議修復**: 批次查詢所有使用者的任務,在記憶體中分組 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 重構為批次查詢所有使用者的任務,使用 defaultdict 在記憶體中分組 --- ### MED-003: datetime.utcnow() 已棄用 - **類型**: 棄用警告 - **模組**: Backend - Security - **檔案**: `backend/app/core/security.py:21-25` - **問題描述**: 使用 `datetime.utcnow()` 在 Python 3.12+ 已棄用。 - **建議修復**: ```python from datetime import datetime, timezone expire = datetime.now(timezone.utc) + timedelta(...) ``` - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 將所有 datetime.utcnow() 改為 datetime.now(timezone.utc).replace(tzinfo=None) 以保持與 SQLite 相容性 --- ### MED-004: 錯誤回應格式不一致 - **類型**: API 一致性 - **模組**: Backend - API - **檔案**: 多個 endpoints - **問題描述**: 部分 endpoints 回傳 `{"message": "..."}` 而其他回傳 `{"detail": "..."}`。FastAPI 慣例是 `detail`。 - **影響**: 前端必須處理不一致的回應格式 - **建議修復**: 統一使用 `{"detail": "..."}` 格式 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 統一 attachments/router.py 和 auth/router.py 的回應格式為 {"detail": "..."} --- ### MED-005: 阻礙狀態自動設定可能衝突 - **類型**: 邏輯問題 - **模組**: Backend - Tasks - **檔案**: `backend/app/api/tasks/router.py:506-511` - **問題描述**: 狀態變更時自動設定 `blocker_flag = False` 可能與 Blocker 表中未解除的阻礙記錄衝突。 - **建議修復**: 根據 Blocker 表實際記錄設定 flag,而非僅依據狀態名稱 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 修改狀態變更邏輯,檢查 Blocker 表中是否有未解決的阻礙記錄來決定 blocker_flag --- ### MED-006: 專案健康看板未實作 - **類型**: 功能缺失 - **模組**: Backend + Frontend - Resource Management - **檔案**: - - **問題描述**: `pjctrl_project_health` 表和相關 API 未實作。 - **影響**: 主管無法一覽所有專案狀態 - **建議修復**: 實作後端 API 和前端健康看板元件 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 實作 HealthService、health router、ProjectHealthPage 前端元件 --- ### MED-007: 容量更新 API 缺失 - **類型**: 功能缺失 - **模組**: Backend - Resource Management - **檔案**: - - **問題描述**: 使用者容量 (capacity) 儲存在資料庫,但無更新 API。 - **建議修復**: 新增 `PUT /api/users/{id}/capacity` endpoint - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 PUT /api/users/{user_id}/capacity endpoint,支援權限檢查、稽核日誌、快取失效 --- ### MED-008: 排程觸發器未完整實作 - **類型**: 功能缺失 - **模組**: Backend - Automation - **檔案**: `backend/app/api/triggers/router.py` - **問題描述**: 觸發器類型驗證僅支援 `field_change` 和 `schedule`,但 schedule 類型的執行邏輯未完成。 - **影響**: 無法使用時間條件觸發器 - **建議修復**: 實作排程觸發器的 cron 解析和執行邏輯 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 實作 TriggerSchedulerService,支援 cron 表達式解析、截止日期提醒、排程任務整合 --- ### MED-009: 浮水印功能未實作 - **類型**: 功能缺失 - **模組**: Backend - Document Management - **檔案**: `backend/app/api/attachments/router.py` - **問題描述**: Spec 要求下載時自動加上使用者浮水印,但未實作 Pillow/PyPDF2 處理邏輯。 - **影響**: 無法追蹤檔案洩漏來源 - **建議修復**: 實作圖片和 PDF 浮水印處理函數 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 實作 WatermarkService,支援圖片和 PDF 浮水印,整合至下載流程 --- ### MED-010: useEffect 依賴缺失 - **類型**: Bug - **模組**: Frontend - Multiple Components - **檔案**: - `frontend/src/components/TriggerList.tsx:27-29` - `frontend/src/components/ResourceHistory.tsx:15-17` - **問題描述**: `fetchTriggers` 和 `loadHistory` 函數在 useEffect 中呼叫但未列為依賴。 - **影響**: 可能導致閉包過期 (stale closure),ESLint 警告 - **建議修復**: 使用 useCallback 包裝函數並加入依賴陣列 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 使用 useCallback 包裝 fetchTriggers 和 loadHistory 函數,並加入正確的依賴陣列 --- ### MED-011: DOM 操作在元件外執行 - **類型**: 反模式 - **模組**: Frontend - Attachments - **檔案**: `frontend/src/components/AttachmentUpload.tsx:185-192` - **問題描述**: 在元件模組頂層建立並附加 style 元素,違反 React 生命週期管理。 - **影響**: 潛在記憶體洩漏,每次 import 都會執行 - **建議修復**: 將樣式移至 CSS 檔案或使用 useEffect 管理 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 將 style 元素注入邏輯移至 useEffect,並在清理時移除樣式元素 --- ### MED-012: PDF 匯出未實作 - **類型**: 功能缺失 - **模組**: Frontend - Audit Trail - **檔案**: `frontend/src/pages/AuditPage.tsx` - **問題描述**: Spec 提及 CSV/PDF 匯出,目前僅實作 CSV。 - **建議修復**: 新增 PDF 匯出選項 - **狀態**: [x] 已修復 (2026-01-04) - **修復方式**: 新增 Export PDF 按鈕,使用瀏覽器 window.print() 功能匯出 PDF --- ## 低優先問題 (Low) ### LOW-001: 缺少完整類型提示 - **類型**: 程式碼品質 - **模組**: Backend - Services - **檔案**: 多個 service 檔案 - **問題描述**: 部分函數缺少完整類型提示。 - **狀態**: [ ] 待改善 --- ### LOW-002: 分頁無最大限制 - **類型**: 效能問題 - **模組**: Backend - API - **檔案**: 多個 list endpoints - **問題描述**: 雖有分頁實作,但部分 endpoints 無最大 page size 限制。 - **狀態**: [ ] 待修復 --- ### LOW-003: 狀態名稱使用魔術字串 - **類型**: 程式碼品質 - **模組**: Backend - Reports - **檔案**: `backend/app/services/report_service.py:84-92` - **問題描述**: 使用硬編碼字串比對狀態名稱 `["done", "completed", "完成"]`。 - **建議修復**: 統一使用 TaskStatus model 的 is_done flag - **狀態**: [ ] 待改善 --- ### LOW-004: 觸發器類型驗證不完整 - **類型**: 驗證不足 - **模組**: Backend - Automation - **檔案**: `backend/app/api/triggers/router.py:62-66` - **問題描述**: 觸發器類型僅驗證 "field_change" 和 "schedule",但 spec 提及 "creation" 類型。 - **狀態**: [ ] 待修復 --- ### LOW-005: 使用 any 類型 - **類型**: TypeScript 類型安全 - **模組**: Frontend - Login - **檔案**: `frontend/src/pages/Login.tsx:21` - **問題描述**: `catch (err: any)` 失去類型安全。 - **建議修復**: 使用 `catch (err: unknown)` 並進行類型守衛 - **狀態**: [ ] 待改善 --- ### LOW-006: 使用原生 confirm()/alert() - **類型**: UX 一致性 - **模組**: Frontend - Multiple - **檔案**: - `frontend/src/components/Comments.tsx:74` - `frontend/src/components/AttachmentList.tsx:40` - `frontend/src/components/TriggerList.tsx:41` - `frontend/src/components/WeeklyReportPreview.tsx:171` - **問題描述**: 使用原生對話框,非無障礙且 UX 不一致。 - **建議修復**: 建立可重用的確認 Modal 元件 - **狀態**: [ ] 待改善 --- ### LOW-007: 錯誤處理無使用者回饋 - **類型**: UX 問題 - **模組**: Frontend - Spaces - **檔案**: `frontend/src/pages/Spaces.tsx:31-32` - **問題描述**: 錯誤僅記錄至 console,無向使用者顯示。 - **建議修復**: 新增 toast 通知系統 - **狀態**: [ ] 待改善 --- ### LOW-008: 樣式方法不一致 - **類型**: 程式碼一致性 - **模組**: Frontend - Styling - **檔案**: 多個元件 - **問題描述**: 混合使用 inline styles 物件 (Dashboard.tsx) 和類似 Tailwind 的 class 字串 (Comments.tsx)。 - **建議修復**: 統一使用 CSS Modules 或 styled-components - **狀態**: [ ] 待改善 --- ### LOW-009: 缺少載入骨架 - **類型**: UX 問題 - **模組**: Frontend - Multiple - **問題描述**: 所有載入狀態顯示純文字 "Loading...",造成版面跳動。 - **建議修復**: 新增骨架元件 (skeleton components) - **狀態**: [ ] 待改善 --- ### LOW-010: 缺少前端測試 - **類型**: 測試覆蓋 - **模組**: Frontend - **問題描述**: 未發現任何測試檔案。 - **建議修復**: 新增 Vitest/Jest 單元測試 - **狀態**: [ ] 待開發 --- ## 未實作功能 (Missing Features) | ID | 模組 | 功能 | 後端 | 前端 | 優先級 | 狀態 | |----|------|------|:----:|:----:|--------|------| | FEAT-001 | Task Management | 自定義欄位 (Custom Fields) | 有 | 有 | 高 | ✅ 已完成 (2026-01-05) | | FEAT-002 | Task Management | 看板視角 (Kanban View) | 有 | 有 | 高 | ✅ 已完成 (KanbanBoard.tsx) | | FEAT-003 | Task Management | 甘特圖視角 (Gantt View) | 有 | 有 | 中 | ✅ 已完成 (2026-01-05) | | FEAT-004 | Task Management | 行事曆視角 (Calendar View) | 有 | 有 | 中 | ✅ 已完成 (2026-01-05) | | FEAT-005 | Task Management | 子任務建立 UI | 有 | 缺 | 中 | 待開發 | | FEAT-006 | Task Management | 拖拉變更狀態 | 有 | 有 | 中 | ✅ 已完成 (KanbanBoard drag-drop) | | FEAT-007 | Resource Management | 負載熱圖 UI | 有 | 有 | 高 | ✅ 已完成 (WorkloadPage.tsx) | | FEAT-008 | Resource Management | 專案健康看板 | 有 | 有 | 中 | ✅ 已完成 (ProjectHealthPage.tsx) | | FEAT-009 | Resource Management | 容量更新 API | 有 | N/A | 低 | ✅ 已完成 (PUT /api/users/{id}/capacity) | | FEAT-010 | Document Management | AES-256 加密存儲 | 有 | N/A | 高 | ✅ 已完成 (2026-01-05) | | FEAT-011 | Document Management | 動態浮水印 | 有 | N/A | 中 | ✅ 已完成 (watermark_service.py) | | FEAT-012 | Document Management | 版本還原 UI | 有 | 缺 | 低 | 待開發 | | FEAT-013 | Automation | 排程觸發器執行 | 有 | N/A | 中 | ✅ 已完成 (trigger_scheduler.py) | | FEAT-014 | Automation | 更新欄位動作 | 缺 | 缺 | 低 | 待開發 | | FEAT-015 | Automation | 自動指派動作 | 缺 | 缺 | 低 | 待開發 | | FEAT-016 | Audit Trail | 稽核完整性驗證 UI | 有 | 缺 | 低 | 待開發 | --- ## 可訪問性問題 (Accessibility) ### A11Y-001: 表單缺少 Label - **檔案**: `frontend/src/pages/Spaces.tsx:95-101` - **問題**: Modal 中的 input 欄位缺少關聯的 `