Loading...
+ }
+
+ return (
+
+
+ navigate('/spaces')} style={styles.breadcrumbLink}>
+ Spaces
+
+ /
+ navigate(`/spaces/${project?.space_id}`)}
+ style={styles.breadcrumbLink}
+ >
+ Projects
+
+ /
+ {project?.title}
+
+
+
+
Tasks
+
+
+
+
+ {tasks.map((task) => (
+
+
+
+
{task.title}
+
+ {task.assignee_name && (
+ {task.assignee_name}
+ )}
+ {task.due_date && (
+
+ Due: {new Date(task.due_date).toLocaleDateString()}
+
+ )}
+ {task.subtask_count > 0 && (
+
+ {task.subtask_count} subtasks
+
+ )}
+
+
+
+
+ ))}
+
+ {tasks.length === 0 && (
+
+
No tasks yet. Create your first task!
+
+ )}
+
+
+ {showCreateModal && (
+
+
+
Create New Task
+
setNewTask({ ...newTask, title: e.target.value })}
+ style={styles.input}
+ />
+
+
+ )}
+
+ )
+}
+
+const styles: { [key: string]: React.CSSProperties } = {
+ container: {
+ padding: '24px',
+ maxWidth: '1200px',
+ margin: '0 auto',
+ },
+ breadcrumb: {
+ marginBottom: '16px',
+ fontSize: '14px',
+ color: '#666',
+ },
+ breadcrumbLink: {
+ color: '#0066cc',
+ cursor: 'pointer',
+ },
+ breadcrumbSeparator: {
+ margin: '0 8px',
+ },
+ header: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginBottom: '24px',
+ },
+ title: {
+ fontSize: '24px',
+ fontWeight: 600,
+ margin: 0,
+ },
+ createButton: {
+ padding: '10px 20px',
+ backgroundColor: '#0066cc',
+ color: 'white',
+ border: 'none',
+ borderRadius: '6px',
+ cursor: 'pointer',
+ fontSize: '14px',
+ fontWeight: 500,
+ },
+ taskList: {
+ backgroundColor: 'white',
+ borderRadius: '8px',
+ boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)',
+ overflow: 'hidden',
+ },
+ taskRow: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: '16px',
+ borderBottom: '1px solid #eee',
+ gap: '12px',
+ },
+ taskContent: {
+ flex: 1,
+ },
+ taskTitle: {
+ fontSize: '14px',
+ fontWeight: 500,
+ marginBottom: '4px',
+ },
+ taskMeta: {
+ display: 'flex',
+ gap: '12px',
+ fontSize: '12px',
+ color: '#666',
+ },
+ assignee: {
+ backgroundColor: '#f0f0f0',
+ padding: '2px 6px',
+ borderRadius: '4px',
+ },
+ dueDate: {},
+ subtaskCount: {
+ color: '#999',
+ },
+ statusSelect: {
+ padding: '6px 12px',
+ border: 'none',
+ borderRadius: '4px',
+ fontSize: '12px',
+ cursor: 'pointer',
+ color: 'white',
+ },
+ empty: {
+ textAlign: 'center',
+ padding: '48px',
+ color: '#666',
+ },
+ loading: {
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '200px',
+ },
+ modalOverlay: {
+ position: 'fixed',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ modal: {
+ backgroundColor: 'white',
+ padding: '24px',
+ borderRadius: '8px',
+ width: '400px',
+ maxWidth: '90%',
+ },
+ modalTitle: {
+ marginBottom: '16px',
+ },
+ input: {
+ width: '100%',
+ padding: '10px',
+ marginBottom: '12px',
+ border: '1px solid #ddd',
+ borderRadius: '4px',
+ fontSize: '14px',
+ boxSizing: 'border-box',
+ },
+ textarea: {
+ width: '100%',
+ padding: '10px',
+ marginBottom: '12px',
+ border: '1px solid #ddd',
+ borderRadius: '4px',
+ fontSize: '14px',
+ minHeight: '80px',
+ resize: 'vertical',
+ boxSizing: 'border-box',
+ },
+ label: {
+ display: 'block',
+ marginBottom: '4px',
+ fontSize: '14px',
+ fontWeight: 500,
+ },
+ select: {
+ width: '100%',
+ padding: '10px',
+ marginBottom: '16px',
+ border: '1px solid #ddd',
+ borderRadius: '4px',
+ fontSize: '14px',
+ boxSizing: 'border-box',
+ },
+ modalActions: {
+ display: 'flex',
+ justifyContent: 'flex-end',
+ gap: '12px',
+ },
+ cancelButton: {
+ padding: '10px 20px',
+ backgroundColor: '#f5f5f5',
+ border: '1px solid #ddd',
+ borderRadius: '4px',
+ cursor: 'pointer',
+ },
+ submitButton: {
+ padding: '10px 20px',
+ backgroundColor: '#0066cc',
+ color: 'white',
+ border: 'none',
+ borderRadius: '4px',
+ cursor: 'pointer',
+ },
+}
diff --git a/openspec/changes/archive/2025-12-28-add-task-management/design.md b/openspec/changes/archive/2025-12-28-add-task-management/design.md
new file mode 100644
index 0000000..6971d82
--- /dev/null
+++ b/openspec/changes/archive/2025-12-28-add-task-management/design.md
@@ -0,0 +1,231 @@
+# 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 層級,而非全域,提供專案彈性
diff --git a/openspec/changes/archive/2025-12-28-add-task-management/proposal.md b/openspec/changes/archive/2025-12-28-add-task-management/proposal.md
new file mode 100644
index 0000000..06457b8
--- /dev/null
+++ b/openspec/changes/archive/2025-12-28-add-task-management/proposal.md
@@ -0,0 +1,60 @@
+# Proposal: add-task-management
+
+## Summary
+
+實作任務管理核心系統,包含 Space > Project > Task > Sub-task 多層級架構、基本 CRUD 操作、狀態管理與任務指派功能。
+
+## Motivation
+
+任務管理是專案控制系統的核心功能,其他模組(資源管理、協作、自動化)都依賴於任務資料。需優先建立穩固的任務管理基礎。
+
+## Scope
+
+### 包含 (In Scope)
+
+1. **資料模型**
+ - pjctrl_spaces: 空間管理
+ - pjctrl_projects: 專案管理
+ - pjctrl_tasks: 任務與子任務管理
+ - pjctrl_task_statuses: 任務狀態定義
+
+2. **API 端點**
+ - Spaces CRUD: GET/POST/PATCH/DELETE /api/spaces
+ - Projects CRUD: GET/POST/PATCH/DELETE /api/projects
+ - Tasks CRUD: GET/POST/PATCH/DELETE /api/tasks
+ - Task 狀態管理與指派
+
+3. **權限控制**
+ - Space/Project 層級的存取權限
+ - Security Level 隔離 (public, department, confidential)
+ - 任務指派權限驗證
+
+4. **前端基礎**
+ - Space/Project 列表與詳情頁
+ - Task 列表視角 (List View)
+ - 任務建立/編輯表單
+
+### 不包含 (Out of Scope)
+
+- 自定義欄位 (Custom Fields) - 下一階段
+- 看板視角 (Kanban View) - 下一階段
+- 甘特圖視角 (Gantt View) - 下一階段
+- 行事曆視角 (Calendar View) - 下一階段
+- WebSocket 即時同步 - 下一階段
+- 公式欄位計算 - 下一階段
+
+## Affected Specs
+
+- `task-management`: 新增 Purpose 區塊,補充 ADDED Requirements
+
+## Dependencies
+
+- `user-auth`: 需使用認證中間件與使用者資料
+
+## Risks
+
+1. **資料模型複雜度**: 多層級結構可能導致查詢效能問題
+ - 緩解: 適當建立索引,限制子任務深度
+
+2. **權限檢查效能**: 每次 API 請求都需驗證權限
+ - 緩解: Redis 快取使用者權限資料
diff --git a/openspec/changes/archive/2025-12-28-add-task-management/specs/task-management/spec.md b/openspec/changes/archive/2025-12-28-add-task-management/specs/task-management/spec.md
new file mode 100644
index 0000000..30198e5
--- /dev/null
+++ b/openspec/changes/archive/2025-12-28-add-task-management/specs/task-management/spec.md
@@ -0,0 +1,80 @@
+# Task Management
+
+## Purpose
+
+任務管理核心系統,支援多層級架構 (Space > Project > Task > Sub-task)、狀態管理與任務指派功能。
+
+## ADDED Requirements
+
+### Requirement: Hierarchical Task Structure
+系統 SHALL 支援多層級任務架構:空間 (Space) > 專案 (Project) > 任務 (Task) > 子任務 (Sub-task)。
+
+#### Scenario: 建立空間
+- **GIVEN** 使用者擁有建立空間的權限
+- **WHEN** 使用者建立新空間
+- **THEN** 系統建立空間並設定擁有者
+- **AND** 空間可包含多個專案
+
+#### Scenario: 建立專案
+- **GIVEN** 使用者在某空間內擁有建立專案的權限
+- **WHEN** 使用者建立新專案
+- **THEN** 系統建立專案並關聯至該空間
+- **AND** 設定專案的 Owner、Budget、Timeline、Security_Level
+- **AND** 自動建立預設任務狀態 (To Do, In Progress, Blocked, Done)
+
+#### Scenario: 建立任務與子任務
+- **GIVEN** 使用者在專案內擁有建立任務的權限
+- **WHEN** 使用者建立任務或子任務
+- **THEN** 系統建立任務並維護父子關係
+- **AND** 子任務深度限制為 2 層
+
+### Requirement: Project Security Level
+系統 SHALL 根據專案的安全等級 (Security Level) 控制存取權限。
+
+#### Scenario: Public 專案存取
+- **GIVEN** 專案設定為 security_level = 'public'
+- **WHEN** 任何已登入使用者嘗試存取
+- **THEN** 系統允許存取
+
+#### Scenario: Department 專案存取
+- **GIVEN** 專案設定為 security_level = 'department'
+- **WHEN** 使用者嘗試存取
+- **THEN** 系統僅允許同部門使用者或專案成員存取
+
+#### Scenario: Confidential 專案存取
+- **GIVEN** 專案設定為 security_level = 'confidential'
+- **WHEN** 使用者嘗試存取
+- **THEN** 系統僅允許專案成員存取
+- **AND** 系統管理員不受此限制
+
+### Requirement: Task Status Management
+系統 SHALL 管理任務狀態,支援專案層級的狀態定義。
+
+#### Scenario: 預設狀態建立
+- **GIVEN** 使用者建立新專案
+- **WHEN** 專案建立完成
+- **THEN** 系統自動建立預設狀態: To Do, In Progress, Blocked, Done
+
+#### Scenario: 狀態變更
+- **GIVEN** 使用者擁有更新任務的權限
+- **WHEN** 使用者變更任務狀態
+- **THEN** 系統更新狀態並記錄變更時間
+
+#### Scenario: 阻礙標記
+- **GIVEN** 任務遇到阻礙無法進行
+- **WHEN** 使用者將任務狀態變更為 "Blocked"
+- **THEN** 系統設定 blocker_flag = true
+
+### Requirement: Task Assignment
+系統 SHALL 支援任務指派與時間估算。
+
+#### Scenario: 指派任務
+- **GIVEN** 使用者擁有指派任務的權限
+- **WHEN** 使用者將任務指派給某人
+- **THEN** 系統更新 assignee_id
+- **AND** 任務計入被指派者的工作負載
+
+#### Scenario: 時間估算與追蹤
+- **GIVEN** 任務已被指派
+- **WHEN** 使用者設定 original_estimate 與回報 time_spent
+- **THEN** 系統記錄並可計算剩餘時間
diff --git a/openspec/changes/archive/2025-12-28-add-task-management/tasks.md b/openspec/changes/archive/2025-12-28-add-task-management/tasks.md
new file mode 100644
index 0000000..f5783d7
--- /dev/null
+++ b/openspec/changes/archive/2025-12-28-add-task-management/tasks.md
@@ -0,0 +1,163 @@
+# Tasks: add-task-management
+
+## 1. 資料庫模型
+
+- [x] 1.1 建立 `pjctrl_spaces` migration
+- [x] 1.2 建立 `pjctrl_projects` migration
+- [x] 1.3 建立 `pjctrl_task_statuses` migration
+- [x] 1.4 建立 `pjctrl_tasks` migration
+- [x] 1.5 建立 SQLAlchemy models (Space, Project, TaskStatus, Task)
+- [x] 1.6 驗證 migration 可正確執行與回滾
+
+## 2. Pydantic Schemas
+
+- [x] 2.1 建立 Space schemas (Create, Update, Response)
+- [x] 2.2 建立 Project schemas (Create, Update, Response)
+- [x] 2.3 建立 TaskStatus schemas (Create, Update, Response)
+- [x] 2.4 建立 Task schemas (Create, Update, Response)
+
+## 3. 權限中間件
+
+- [x] 3.1 實作 Space 權限檢查 (`check_space_access`)
+- [x] 3.2 實作 Project 權限檢查 (`check_project_access`)
+- [x] 3.3 實作 Security Level 過濾邏輯
+- [x] 3.4 整合至現有 auth middleware
+
+## 4. Spaces API
+
+- [x] 4.1 實作 `GET /api/spaces` (列出可見空間)
+- [x] 4.2 實作 `POST /api/spaces` (建立空間)
+- [x] 4.3 實作 `GET /api/spaces/{id}` (取得詳情)
+- [x] 4.4 實作 `PATCH /api/spaces/{id}` (更新空間)
+- [x] 4.5 實作 `DELETE /api/spaces/{id}` (軟刪除)
+
+## 5. Projects API
+
+- [x] 5.1 實作 `GET /api/spaces/{space_id}/projects` (列出專案)
+- [x] 5.2 實作 `POST /api/spaces/{space_id}/projects` (建立專案)
+- [x] 5.3 實作 `GET /api/projects/{id}` (取得詳情)
+- [x] 5.4 實作 `PATCH /api/projects/{id}` (更新專案)
+- [x] 5.5 實作 `DELETE /api/projects/{id}` (刪除專案)
+- [x] 5.6 建立專案時自動建立預設狀態
+
+## 6. Tasks API
+
+- [x] 6.1 實作 `GET /api/projects/{project_id}/tasks` (列出任務)
+- [x] 6.2 實作 `POST /api/projects/{project_id}/tasks` (建立任務)
+- [x] 6.3 實作 `GET /api/tasks/{id}` (取得詳情)
+- [x] 6.4 實作 `PATCH /api/tasks/{id}` (更新任務)
+- [x] 6.5 實作 `DELETE /api/tasks/{id}` (刪除任務)
+- [x] 6.6 實作 `PATCH /api/tasks/{id}/status` (變更狀態)
+- [x] 6.7 實作 `PATCH /api/tasks/{id}/assign` (指派任務)
+- [x] 6.8 實作子任務建立 (parent_task_id)
+
+## 7. 測試
+
+- [x] 7.1 撰寫 Space API 單元測試
+- [x] 7.2 撰寫 Project API 單元測試
+- [x] 7.3 撰寫 Task API 單元測試
+- [x] 7.4 撰寫權限檢查測試 (Security Level)
+- [x] 7.5 撰寫子任務層級限制測試
+- [x] 7.6 整合測試
+
+## 8. 前端 (基礎)
+
+- [x] 8.1 建立 Spaces 列表頁面
+- [x] 8.2 建立 Projects 列表頁面
+- [x] 8.3 建立 Tasks 列表視角 (ListView)
+- [x] 8.4 建立任務建立/編輯表單
+- [x] 8.5 實作任務狀態變更
+- [x] 8.6 實作任務指派功能
+
+## Dependencies
+
+```
+1.x (資料庫) → 2.x (Schemas) → 3.x (權限)
+ ↓
+ 4.x (Spaces API)
+ ↓
+ 5.x (Projects API)
+ ↓
+ 6.x (Tasks API)
+ ↓
+ 7.x (測試)
+
+8.x (前端) 可與 4.x-6.x 並行開發
+```
+
+## Notes
+
+- 所有資料表使用 `pjctrl_` 前綴
+- 子任務深度限制為 2 層
+- 每個新專案自動建立 4 個預設狀態
+- Security Level 為 'confidential' 時需檢查專案成員資格
+
+## Implementation Summary
+
+完成日期: 2024-12-28
+E2E 測試完成日期: 2024-12-29
+
+### 已建立的檔案
+
+**Backend:**
+- `migrations/versions/002_task_management_tables.py` - 資料庫 migration
+- `app/models/space.py` - Space model
+- `app/models/project.py` - Project model
+- `app/models/task_status.py` - TaskStatus model
+- `app/models/task.py` - Task model
+- `app/schemas/space.py` - Space schemas
+- `app/schemas/project.py` - Project schemas
+- `app/schemas/task_status.py` - TaskStatus schemas
+- `app/schemas/task.py` - Task schemas
+- `app/api/spaces/router.py` - Spaces API
+- `app/api/projects/router.py` - Projects API
+- `app/api/tasks/router.py` - Tasks API
+- `tests/test_spaces.py` - Space 測試
+- `tests/test_projects.py` - Project 測試
+- `tests/test_tasks.py` - Task 測試
+
+**Frontend:**
+- `src/pages/Spaces.tsx` - Spaces 列表頁面
+- `src/pages/Projects.tsx` - Projects 列表頁面
+- `src/pages/Tasks.tsx` - Tasks 列表頁面
+- `src/components/Layout.tsx` - 共用 Layout 元件
+
+### 測試結果
+
+36 tests passed (包含 user-auth 的 13 個測試)
+
+### E2E 測試結果 (2024-12-29)
+
+使用真實帳號 (ymirliu@panjit.com.tw) 進行端對端測試:
+
+**Spaces API:**
+- [x] POST /api/spaces - 建立空間
+- [x] GET /api/spaces - 列出空間
+- [x] GET /api/spaces/{id} - 取得空間詳情
+- [x] PATCH /api/spaces/{id} - 更新空間
+- [x] DELETE /api/spaces/{id} - 軟刪除空間
+
+**Projects API:**
+- [x] POST /api/spaces/{space_id}/projects - 建立專案
+- [x] GET /api/spaces/{space_id}/projects - 列出專案
+- [x] GET /api/projects/{id} - 取得專案詳情
+- [x] PATCH /api/projects/{id} - 更新專案
+- [x] DELETE /api/projects/{id} - 刪除專案
+- [x] GET /api/projects/{id}/statuses - 驗證 4 個預設狀態自動建立
+
+**Tasks API:**
+- [x] POST /api/projects/{project_id}/tasks - 建立任務
+- [x] GET /api/projects/{project_id}/tasks - 列出任務
+- [x] GET /api/tasks/{id} - 取得任務詳情
+- [x] PATCH /api/tasks/{id} - 更新任務
+- [x] PATCH /api/tasks/{id}/status - 變更狀態
+- [x] PATCH /api/tasks/{id}/assign - 指派任務
+- [x] DELETE /api/tasks/{id} - 刪除任務
+- [x] 子任務建立 (Level 1) - 成功
+- [x] 子任務深度限制 (Level 2) - 正確拒絕
+- [x] subtask_count 自動計算 - 正確
+
+**權限控制:**
+- [x] Admin 可存取 department 級別專案
+- [x] Admin 可存取 confidential 級別專案
+- [x] Security Level 過濾邏輯運作正常