# Design: add-task-management ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Frontend │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ Spaces │ │ Projects │ │ Tasks │ │ Task Detail │ │ │ │ List │ │ List │ │ ListView │ │ Form │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │ └───────┼─────────────┼─────────────┼────────────────┼────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ API Layer │ │ ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐ │ │ │ /api/spaces │ │ /api/projects │ │ /api/tasks │ │ │ │ router │ │ router │ │ router │ │ │ └──────┬───────┘ └───────┬────────┘ └────────┬────────┘ │ └─────────┼──────────────────┼────────────────────┼───────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Middleware Layer │ │ ┌─────────────────┐ ┌─────────────────────────────────┐ │ │ │ Auth Middleware│ │ Permission Middleware │ │ │ │ (JWT驗證) │ │ (RBAC + Security Level) │ │ │ └────────┬────────┘ └────────────────┬────────────────┘ │ └───────────┼────────────────────────────┼────────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Data Layer │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ pjctrl_ │ │ pjctrl_ │ │ pjctrl_ │ │ │ │ spaces │ │ projects │ │ tasks │ │ │ └────────────┘ └────────────┘ └────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Data Model Details ### pjctrl_spaces 空間是最上層的組織單位,用於將相關專案分組。 ```sql CREATE TABLE pjctrl_spaces ( id CHAR(36) PRIMARY KEY, name VARCHAR(200) NOT NULL, description TEXT, owner_id CHAR(36) NOT NULL, is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (owner_id) REFERENCES pjctrl_users(id) ); CREATE INDEX idx_spaces_owner ON pjctrl_spaces(owner_id); CREATE INDEX idx_spaces_active ON pjctrl_spaces(is_active); ``` ### pjctrl_projects 專案屬於某個空間,具有預算、時程和安全等級設定。 ```sql CREATE TABLE pjctrl_projects ( id CHAR(36) PRIMARY KEY, space_id CHAR(36) NOT NULL, title VARCHAR(200) NOT NULL, description TEXT, owner_id CHAR(36) NOT NULL, budget DECIMAL(15, 2), start_date DATE, end_date DATE, security_level ENUM('public', 'department', 'confidential') DEFAULT 'department', status VARCHAR(50) DEFAULT 'active', department_id CHAR(36), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (space_id) REFERENCES pjctrl_spaces(id) ON DELETE CASCADE, FOREIGN KEY (owner_id) REFERENCES pjctrl_users(id), FOREIGN KEY (department_id) REFERENCES pjctrl_departments(id) ); CREATE INDEX idx_projects_space ON pjctrl_projects(space_id); CREATE INDEX idx_projects_owner ON pjctrl_projects(owner_id); CREATE INDEX idx_projects_department ON pjctrl_projects(department_id); CREATE INDEX idx_projects_security ON pjctrl_projects(security_level); ``` ### pjctrl_task_statuses 定義專案內可用的任務狀態。 ```sql CREATE TABLE pjctrl_task_statuses ( id CHAR(36) PRIMARY KEY, project_id CHAR(36) NOT NULL, name VARCHAR(50) NOT NULL, color VARCHAR(7) DEFAULT '#808080', position INT DEFAULT 0, is_done BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (project_id) REFERENCES pjctrl_projects(id) ON DELETE CASCADE, UNIQUE KEY uk_status_name (project_id, name) ); CREATE INDEX idx_statuses_project ON pjctrl_task_statuses(project_id); ``` ### pjctrl_tasks 任務是核心實體,支援父子任務關係。 ```sql CREATE TABLE pjctrl_tasks ( id CHAR(36) PRIMARY KEY, project_id CHAR(36) NOT NULL, parent_task_id CHAR(36), title VARCHAR(500) NOT NULL, description TEXT, assignee_id CHAR(36), status_id CHAR(36), priority ENUM('low', 'medium', 'high', 'urgent') DEFAULT 'medium', original_estimate DECIMAL(8, 2), time_spent DECIMAL(8, 2) DEFAULT 0, blocker_flag BOOLEAN DEFAULT false, due_date DATETIME, position INT DEFAULT 0, created_by CHAR(36) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (project_id) REFERENCES pjctrl_projects(id) ON DELETE CASCADE, FOREIGN KEY (parent_task_id) REFERENCES pjctrl_tasks(id) ON DELETE CASCADE, FOREIGN KEY (assignee_id) REFERENCES pjctrl_users(id), FOREIGN KEY (status_id) REFERENCES pjctrl_task_statuses(id), FOREIGN KEY (created_by) REFERENCES pjctrl_users(id) ); CREATE INDEX idx_tasks_project ON pjctrl_tasks(project_id); CREATE INDEX idx_tasks_parent ON pjctrl_tasks(parent_task_id); CREATE INDEX idx_tasks_assignee ON pjctrl_tasks(assignee_id); CREATE INDEX idx_tasks_status ON pjctrl_tasks(status_id); CREATE INDEX idx_tasks_due ON pjctrl_tasks(due_date); CREATE INDEX idx_tasks_blocker ON pjctrl_tasks(blocker_flag); ``` ## Permission Model ### Security Level 行為 | Security Level | 可見範圍 | |----------------|----------| | public | 所有登入使用者 | | department | 同部門使用者 + 專案成員 | | confidential | 僅專案成員 | ### 權限檢查流程 ```python def check_project_access(user, project): # 系統管理員可存取所有 if user.is_system_admin: return True # 專案擁有者 if project.owner_id == user.id: return True # 依 security_level 判斷 if project.security_level == 'public': return True elif project.security_level == 'department': return user.department_id == project.department_id else: # confidential return is_project_member(user, project) ``` ## API Design ### Spaces API | Method | Endpoint | Description | |--------|----------|-------------| | GET | /api/spaces | 列出使用者可見的空間 | | POST | /api/spaces | 建立新空間 | | GET | /api/spaces/{id} | 取得空間詳情 | | PATCH | /api/spaces/{id} | 更新空間 | | DELETE | /api/spaces/{id} | 刪除空間 (軟刪除) | ### Projects API | Method | Endpoint | Description | |--------|----------|-------------| | GET | /api/spaces/{space_id}/projects | 列出空間內的專案 | | POST | /api/spaces/{space_id}/projects | 建立新專案 | | GET | /api/projects/{id} | 取得專案詳情 | | PATCH | /api/projects/{id} | 更新專案 | | DELETE | /api/projects/{id} | 刪除專案 | ### Tasks API | Method | Endpoint | Description | |--------|----------|-------------| | GET | /api/projects/{project_id}/tasks | 列出專案內的任務 | | POST | /api/projects/{project_id}/tasks | 建立新任務 | | GET | /api/tasks/{id} | 取得任務詳情 | | PATCH | /api/tasks/{id} | 更新任務 | | DELETE | /api/tasks/{id} | 刪除任務 | | PATCH | /api/tasks/{id}/status | 變更任務狀態 | | PATCH | /api/tasks/{id}/assign | 指派任務 | ## Default Task Statuses 每個新專案自動建立以下預設狀態: | Name | Color | is_done | |------|-------|---------| | To Do | #808080 | false | | In Progress | #0066cc | false | | Blocked | #cc0000 | false | | Done | #00cc66 | true | ## Trade-offs & Decisions 1. **子任務深度限制**: 限制為 2 層 (Task → Sub-task),避免過度巢狀造成的複雜度 2. **軟刪除 vs 硬刪除**: Space 使用軟刪除 (is_active),Tasks 使用級聯硬刪除 3. **狀態定義層級**: 狀態定義在 Project 層級,而非全域,提供專案彈性