feat: implement custom fields, gantt view, calendar view, and file encryption
- Custom Fields (FEAT-001): - CustomField and TaskCustomValue models with formula support - CRUD API for custom field management - Formula engine for calculated fields - Frontend: CustomFieldEditor, CustomFieldInput, ProjectSettings page - Task list API now includes custom_values - KanbanBoard displays custom field values - Gantt View (FEAT-003): - TaskDependency model with FS/SS/FF/SF dependency types - Dependency CRUD API with cycle detection - start_date field added to tasks - GanttChart component with Frappe Gantt integration - Dependency type selector in UI - Calendar View (FEAT-004): - CalendarView component with FullCalendar integration - Date range filtering API for tasks - Drag-and-drop date updates - View mode switching in Tasks page - File Encryption (FEAT-010): - AES-256-GCM encryption service - EncryptionKey model with key rotation support - Admin API for key management - Encrypted upload/download for confidential projects - Migrations: 011 (custom fields), 012 (encryption keys), 013 (task dependencies) - Updated issues.md with completion status 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# Proposal: Add Calendar View
|
||||
|
||||
**Change ID:** `add-calendar-view`
|
||||
**Issue Reference:** `FEAT-004` (issues.md)
|
||||
**Status:** Draft
|
||||
**Author:** Claude
|
||||
**Date:** 2026-01-05
|
||||
|
||||
## Summary
|
||||
|
||||
實作行事曆視角,以月/週/日視圖呈現任務截止日期,方便使用者規劃工作時程。
|
||||
|
||||
## Motivation
|
||||
|
||||
行事曆視角提供直覺的日期導向任務規劃:
|
||||
- 快速掌握本週/本月截止的任務
|
||||
- 識別特定日期的工作量
|
||||
- 避免任務截止日期過度集中
|
||||
- 與個人行事曆習慣一致
|
||||
|
||||
目前系統需要在列表或看板中逐一檢視任務日期,無法一覽全局。
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Frontend: Calendar 元件(月視圖、週視圖、日視圖)
|
||||
- Frontend: 任務依截止日期顯示在行事曆上
|
||||
- Frontend: 點擊任務開啟詳情 Modal
|
||||
- Frontend: 拖拉任務更改截止日期
|
||||
- Frontend: 篩選器(依指派者、狀態、優先級)
|
||||
|
||||
### Out of Scope
|
||||
- 與外部行事曆(Google Calendar、Outlook)同步
|
||||
- 重複任務功能
|
||||
- 行事曆分享
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 前端函式庫選擇
|
||||
建議使用 **FullCalendar**:
|
||||
|
||||
| 函式庫 | 優點 | 缺點 |
|
||||
|--------|------|------|
|
||||
| FullCalendar | 功能完整、React 支援好、拖拉支援 | 需要 premium 功能要付費 |
|
||||
| react-big-calendar | 開源、輕量 | 功能較少 |
|
||||
| @schedule-x/react | 現代設計 | 社群較小 |
|
||||
|
||||
**建議**: 使用 FullCalendar(MIT 授權核心功能足夠)
|
||||
|
||||
### 視圖模式
|
||||
| 視圖 | 說明 |
|
||||
|------|------|
|
||||
| Month | 月曆格式,每格顯示當日任務(最多 3 個,其餘 "+N more")|
|
||||
| Week | 週視圖,每格顯示當日所有任務 |
|
||||
| Day | 日視圖,當天任務完整列表 |
|
||||
|
||||
### 任務顯示規則
|
||||
- 依 due_date 顯示在對應日期
|
||||
- 任務卡片顯示:標題、狀態顏色標記、優先級圖示
|
||||
- 已完成任務可選顯示/隱藏
|
||||
- 已過期未完成任務特殊標記(紅色邊框)
|
||||
|
||||
### 拖拉更新日期
|
||||
- 拖拉任務至其他日期更新 due_date
|
||||
- 使用現有 PUT /api/tasks/{id} API
|
||||
- 樂觀更新,失敗時回滾
|
||||
|
||||
### API 使用
|
||||
```
|
||||
# 使用現有 API,加入日期範圍篩選
|
||||
GET /api/projects/{project_id}/tasks?due_after=2026-01-01&due_before=2026-01-31
|
||||
```
|
||||
|
||||
## Affected Specs
|
||||
|
||||
| Spec | Change Type |
|
||||
|------|-------------|
|
||||
| task-management | MODIFIED (Multiple Views requirement 行事曆細節) |
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 單日任務過多影響顯示 | 月視圖最多顯示 3 個,其餘收合 |
|
||||
| 效能問題 | 只載入當前視圖月份的任務 |
|
||||
| 與甘特圖日期衝突 | 行事曆編輯 due_date,甘特圖可編輯 start_date + due_date |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- FullCalendar(或其他行事曆函式庫)
|
||||
- 現有 Task API 的 due_date 篩選支援
|
||||
@@ -0,0 +1,51 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Multiple Views
|
||||
系統 SHALL 支援多維視角:看板 (Kanban)、甘特圖 (Gantt)、列表 (List)、行事曆 (Calendar)。
|
||||
|
||||
#### Scenario: 行事曆視角
|
||||
- **GIVEN** 使用者選擇行事曆視角
|
||||
- **WHEN** 系統載入專案任務
|
||||
- **THEN** 任務依截止日期顯示在行事曆上
|
||||
|
||||
#### Scenario: 行事曆視圖切換
|
||||
- **GIVEN** 使用者正在查看行事曆
|
||||
- **WHEN** 使用者切換視圖模式(月、週、日)
|
||||
- **THEN** 行事曆相應調整顯示格式
|
||||
- **AND** 任務正確顯示在對應日期
|
||||
|
||||
#### Scenario: 月視圖任務顯示
|
||||
- **GIVEN** 使用者選擇月視圖
|
||||
- **WHEN** 某日有超過 3 個任務
|
||||
- **THEN** 顯示前 3 個任務
|
||||
- **AND** 顯示 "+N more" 連結可展開查看全部
|
||||
|
||||
#### Scenario: 點擊任務查看詳情
|
||||
- **GIVEN** 使用者正在查看行事曆
|
||||
- **WHEN** 使用者點擊任務
|
||||
- **THEN** 系統開啟任務詳情 Modal
|
||||
- **AND** 可在 Modal 中編輯任務
|
||||
|
||||
#### Scenario: 拖拉調整截止日期
|
||||
- **GIVEN** 使用者正在查看行事曆
|
||||
- **WHEN** 使用者拖拉任務至其他日期
|
||||
- **THEN** 系統更新任務的 due_date
|
||||
- **AND** 任務顯示在新日期
|
||||
|
||||
#### Scenario: 已過期任務標示
|
||||
- **GIVEN** 任務的 due_date 已過期
|
||||
- **WHEN** 任務狀態不是「已完成」
|
||||
- **THEN** 任務顯示特殊標記(紅色邊框或背景)
|
||||
- **AND** 提醒使用者注意
|
||||
|
||||
#### Scenario: 日期範圍載入
|
||||
- **GIVEN** 使用者查看行事曆
|
||||
- **WHEN** 系統載入任務
|
||||
- **THEN** 只載入當前視圖日期範圍內的任務
|
||||
- **AND** 切換月份時動態載入對應任務
|
||||
|
||||
#### Scenario: 行事曆篩選
|
||||
- **GIVEN** 使用者正在查看行事曆
|
||||
- **WHEN** 使用者設定篩選條件(指派者、狀態、優先級)
|
||||
- **THEN** 行事曆只顯示符合條件的任務
|
||||
- **AND** 篩選條件在視圖切換時保留
|
||||
@@ -0,0 +1,80 @@
|
||||
# Tasks: Add Calendar View
|
||||
|
||||
## Backend Tasks
|
||||
|
||||
### 1. Add date range filter to Tasks API
|
||||
- [x] Modify GET /api/projects/{project_id}/tasks to accept `due_after` and `due_before` query params
|
||||
- [x] Add filter logic to query
|
||||
- [x] Add API tests
|
||||
- **驗證**: 可依日期範圍篩選任務 ✅
|
||||
|
||||
## Frontend Tasks
|
||||
|
||||
### 2. Install and configure FullCalendar
|
||||
- [x] Install @fullcalendar/react and related packages
|
||||
- [x] Install @fullcalendar/daygrid (month view)
|
||||
- [x] Install @fullcalendar/timegrid (week/day view)
|
||||
- [x] Install @fullcalendar/interaction (drag & drop)
|
||||
- **驗證**: 套件安裝成功 ✅
|
||||
|
||||
### 3. Create CalendarView component
|
||||
- [x] Create `frontend/src/components/CalendarView.tsx`
|
||||
- [x] Configure calendar with month/week/day views
|
||||
- [x] Style calendar to match application theme
|
||||
- [x] Add view toggle buttons
|
||||
- **驗證**: 行事曆正確渲染 ✅
|
||||
|
||||
### 4. Load and display tasks on calendar
|
||||
- [x] Fetch tasks from API with date range
|
||||
- [x] Transform tasks to FullCalendar event format
|
||||
- [x] Display task title, status color, priority icon
|
||||
- [x] Handle overdue tasks (special styling)
|
||||
- **驗證**: 任務正確顯示在對應日期 ✅
|
||||
|
||||
### 5. Implement task click to open detail modal
|
||||
- [x] Handle event click in calendar
|
||||
- [x] Open TaskDetailModal with selected task
|
||||
- [x] Refresh calendar on task update
|
||||
- **驗證**: 點擊任務開啟詳情 ✅
|
||||
|
||||
### 6. Implement drag-to-change date
|
||||
- [x] Enable drag & drop in FullCalendar
|
||||
- [x] Handle event drop to get new date
|
||||
- [x] Call PUT /api/tasks/{id} with new due_date
|
||||
- [x] Show optimistic update, rollback on error
|
||||
- **驗證**: 拖拉更新日期可正常運作 ✅
|
||||
|
||||
### 7. Add filter controls
|
||||
- [x] Add assignee filter dropdown
|
||||
- [x] Add status filter (show/hide completed)
|
||||
- [x] Add priority filter
|
||||
- [x] Persist filter in URL or localStorage
|
||||
- **驗證**: 篩選器正確過濾任務 ✅
|
||||
|
||||
### 8. Integrate Calendar view into Tasks page
|
||||
- [x] Add "Calendar" option to view toggle
|
||||
- [x] Store view preference in localStorage
|
||||
- [x] Handle view switching
|
||||
- **驗證**: 可在 List/Kanban/Gantt/Calendar 之間切換 ✅
|
||||
|
||||
## Task Dependencies
|
||||
|
||||
```
|
||||
[1] Date Range Filter API
|
||||
↓
|
||||
[2] FullCalendar Setup → [3] CalendarView Component
|
||||
↓
|
||||
[4] Task Display
|
||||
↓
|
||||
[5] Click → Modal
|
||||
↓
|
||||
[6] Drag to Change Date
|
||||
↓
|
||||
[7] Filters
|
||||
↓
|
||||
[8] View Integration
|
||||
```
|
||||
|
||||
- Task 1 (Backend) 可平行於 Tasks 2-3 (Frontend) 開發
|
||||
- Task 4 需要 Task 1 完成(需要日期範圍 API)
|
||||
- Tasks 5-8 為循序開發
|
||||
@@ -0,0 +1,83 @@
|
||||
# Proposal: Add Custom Fields
|
||||
|
||||
**Change ID:** `add-custom-fields`
|
||||
**Issue Reference:** `FEAT-001` (issues.md)
|
||||
**Status:** Draft
|
||||
**Author:** Claude
|
||||
**Date:** 2026-01-05
|
||||
|
||||
## Summary
|
||||
|
||||
實作自定義欄位功能,允許專案管理者為任務新增自定義欄位,包含文字、數字、下拉選單、日期、人員標籤和公式等類型。
|
||||
|
||||
## Motivation
|
||||
|
||||
目前系統僅支援固定的任務欄位(標題、描述、狀態、優先級等)。不同專案可能需要追蹤特定資料,例如:
|
||||
- 半導體製程:封裝類型、機台編號、預計良率
|
||||
- 軟體開發:Sprint 編號、Story Points、影響版本
|
||||
- 行銷活動:活動代碼、預算類別、目標受眾
|
||||
|
||||
自定義欄位讓專案管理者可以根據需求彈性擴展任務資料結構。
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Backend: CustomField 和 TaskCustomValue models
|
||||
- Backend: Custom fields CRUD API endpoints
|
||||
- Backend: Formula field 計算引擎
|
||||
- Frontend: Custom fields 管理 UI(專案設定頁面)
|
||||
- Frontend: Task form 動態渲染自定義欄位
|
||||
- Frontend: Task list/kanban 顯示自定義欄位值
|
||||
|
||||
### Out of Scope
|
||||
- 跨專案共用欄位定義
|
||||
- 自定義欄位匯入/匯出
|
||||
- 複雜公式函數(僅支援基本數學運算)
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 欄位類型
|
||||
| Type | 說明 | 儲存格式 |
|
||||
|------|------|----------|
|
||||
| text | 單行文字 | VARCHAR |
|
||||
| number | 數字 | DECIMAL |
|
||||
| dropdown | 下拉選單 | VARCHAR (選項儲存於 options JSON) |
|
||||
| date | 日期 | DATE |
|
||||
| person | 人員標籤 | UUID (FK -> users) |
|
||||
| formula | 公式計算 | DECIMAL (計算結果) |
|
||||
|
||||
### 公式欄位
|
||||
- 支援基本數學運算:`+`, `-`, `*`, `/`
|
||||
- 可引用其他數字欄位:`{field_name}`
|
||||
- 可引用任務內建欄位:`{original_estimate}`, `{time_spent}`
|
||||
- 範例公式:`{time_spent} / {original_estimate} * 100`
|
||||
|
||||
### API 設計
|
||||
```
|
||||
POST /api/projects/{project_id}/custom-fields # 新增欄位定義
|
||||
GET /api/projects/{project_id}/custom-fields # 列出所有欄位
|
||||
PUT /api/custom-fields/{field_id} # 更新欄位定義
|
||||
DELETE /api/custom-fields/{field_id} # 刪除欄位(含所有值)
|
||||
|
||||
# 欄位值透過現有 task API 操作
|
||||
PUT /api/tasks/{task_id} # body 包含 custom_values
|
||||
```
|
||||
|
||||
## Affected Specs
|
||||
|
||||
| Spec | Change Type |
|
||||
|------|-------------|
|
||||
| task-management | MODIFIED (Custom Fields requirement 實作細節) |
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 公式欄位循環引用 | 建立欄位時驗證公式不引用自己或形成循環 |
|
||||
| 大量自定義欄位影響效能 | 限制每專案最多 20 個自定義欄位 |
|
||||
| 刪除欄位遺失資料 | 刪除前顯示確認對話框,說明將刪除所有相關值 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- 無外部依賴
|
||||
- 需要現有 tasks API 支援
|
||||
@@ -0,0 +1,54 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Custom Fields
|
||||
系統 SHALL 支援自定義欄位,包含下拉選單、公式、人員標籤等類型。
|
||||
|
||||
#### Scenario: 新增自定義欄位
|
||||
- **GIVEN** 專案管理者需要追蹤特定資料(如:封裝類型、機台編號、預計良率)
|
||||
- **WHEN** 管理者在專案中新增自定義欄位
|
||||
- **THEN** 系統建立欄位定義並套用至該專案所有任務
|
||||
|
||||
#### Scenario: 編輯自定義欄位
|
||||
- **GIVEN** 專案已有自定義欄位
|
||||
- **WHEN** 管理者修改欄位名稱或選項
|
||||
- **THEN** 系統更新欄位定義
|
||||
- **AND** 現有任務的欄位值保持不變
|
||||
|
||||
#### Scenario: 刪除自定義欄位
|
||||
- **GIVEN** 專案已有自定義欄位且有任務包含該欄位的值
|
||||
- **WHEN** 管理者刪除該欄位
|
||||
- **THEN** 系統顯示確認對話框說明將刪除所有相關值
|
||||
- **AND** 確認後刪除欄位定義及所有任務的該欄位值
|
||||
|
||||
#### Scenario: 公式欄位計算
|
||||
- **GIVEN** 任務包含公式類型的自定義欄位
|
||||
- **WHEN** 相依欄位的值發生變更
|
||||
- **THEN** 系統自動重新計算公式欄位的值
|
||||
|
||||
#### Scenario: 公式欄位循環引用檢查
|
||||
- **GIVEN** 管理者建立公式欄位
|
||||
- **WHEN** 公式引用自己或形成循環引用
|
||||
- **THEN** 系統拒絕建立並顯示錯誤訊息
|
||||
|
||||
#### Scenario: 人員標籤欄位
|
||||
- **GIVEN** 任務包含人員標籤類型的自定義欄位
|
||||
- **WHEN** 使用者選擇人員
|
||||
- **THEN** 系統驗證人員存在並建立關聯
|
||||
- **AND** 被標籤的人員可收到相關通知
|
||||
|
||||
#### Scenario: 下拉選單欄位
|
||||
- **GIVEN** 任務包含下拉選單類型的自定義欄位
|
||||
- **WHEN** 使用者選擇選項
|
||||
- **THEN** 系統儲存選擇的值
|
||||
- **AND** 選項列表由欄位定義提供
|
||||
|
||||
#### Scenario: 自定義欄位值顯示
|
||||
- **GIVEN** 任務有自定義欄位值
|
||||
- **WHEN** 使用者在列表或看板視角查看任務
|
||||
- **THEN** 自定義欄位值顯示在任務資訊中
|
||||
- **AND** 公式欄位顯示計算結果(唯讀)
|
||||
|
||||
#### Scenario: 欄位數量限制
|
||||
- **GIVEN** 專案已有 20 個自定義欄位
|
||||
- **WHEN** 管理者嘗試新增第 21 個欄位
|
||||
- **THEN** 系統拒絕新增並顯示數量已達上限的訊息
|
||||
@@ -0,0 +1,82 @@
|
||||
# Tasks: Add Custom Fields
|
||||
|
||||
## Backend Tasks
|
||||
|
||||
### 1. Create CustomField and TaskCustomValue models
|
||||
- [x] Create `backend/app/models/custom_field.py` with CustomField model
|
||||
- [x] Create `backend/app/models/task_custom_value.py` with TaskCustomValue model
|
||||
- [x] Update `backend/app/models/__init__.py` to export new models
|
||||
- [x] Create Alembic migration for new tables
|
||||
- **驗證**: Migration 成功執行,tables 建立正確
|
||||
|
||||
### 2. Create Custom Fields API endpoints
|
||||
- [x] Create `backend/app/api/custom_fields/router.py`
|
||||
- [x] Implement `POST /api/projects/{project_id}/custom-fields` - 新增欄位
|
||||
- [x] Implement `GET /api/projects/{project_id}/custom-fields` - 列出欄位
|
||||
- [x] Implement `PUT /api/custom-fields/{field_id}` - 更新欄位
|
||||
- [x] Implement `DELETE /api/custom-fields/{field_id}` - 刪除欄位
|
||||
- [x] Add permission checks (only project owner/manager can manage fields)
|
||||
- [x] Register router in main.py
|
||||
- **驗證**: API endpoints 可正常呼叫,權限檢查正確
|
||||
|
||||
### 3. Implement formula calculation engine
|
||||
- [x] Create `backend/app/services/formula_service.py`
|
||||
- [x] Implement formula parsing (extract field references)
|
||||
- [x] Implement formula validation (detect circular references)
|
||||
- [x] Implement formula calculation
|
||||
- [x] Add unit tests for formula service
|
||||
- **驗證**: 公式計算正確,循環引用被拒絕
|
||||
|
||||
### 4. Integrate custom values with Tasks API
|
||||
- [x] Modify `TaskCreate` schema to accept `custom_values`
|
||||
- [x] Modify `TaskUpdate` schema to accept `custom_values`
|
||||
- [x] Modify `TaskResponse` schema to include `custom_values`
|
||||
- [x] Update `create_task` endpoint to save custom values
|
||||
- [x] Update `update_task` endpoint to save custom values
|
||||
- [x] Update `get_task` endpoint to return custom values
|
||||
- [x] Trigger formula recalculation on value change
|
||||
- **驗證**: 任務 CRUD 包含自定義欄位值
|
||||
|
||||
### 5. Add backend tests
|
||||
- [x] Test custom field CRUD operations
|
||||
- [x] Test permission checks
|
||||
- [x] Test formula calculation
|
||||
- [x] Test task integration with custom values
|
||||
- **驗證**: 所有測試通過 (20/20 tests passed)
|
||||
|
||||
## Frontend Tasks
|
||||
|
||||
### 6. Create Custom Fields management UI
|
||||
- [x] Create `frontend/src/pages/ProjectSettings.tsx` or extend existing
|
||||
- [x] Create `frontend/src/components/CustomFieldEditor.tsx` - 欄位編輯表單
|
||||
- [x] Create `frontend/src/components/CustomFieldList.tsx` - 欄位列表
|
||||
- [x] Add custom fields API service in `frontend/src/services/customFields.ts`
|
||||
- **驗證**: 可在專案設定中管理自定義欄位
|
||||
|
||||
### 7. Dynamic field rendering in Task forms
|
||||
- [x] Create `frontend/src/components/CustomFieldInput.tsx` - 動態欄位輸入
|
||||
- [x] Integrate into TaskDetailModal.tsx
|
||||
- [x] Integrate into task creation form
|
||||
- [x] Handle different field types (text, number, dropdown, date, person)
|
||||
- [x] Display formula fields as read-only
|
||||
- **驗證**: 任務表單正確顯示和儲存自定義欄位
|
||||
|
||||
### 8. Display custom fields in task views
|
||||
- [x] Add custom field columns to List view
|
||||
- [x] Display custom field values in Kanban cards (optional, configurable)
|
||||
- [x] Add column visibility toggle for custom fields
|
||||
- **驗證**: 自定義欄位值在各視角中正確顯示
|
||||
|
||||
## Task Dependencies
|
||||
|
||||
```
|
||||
[1] Models -> [2] API -> [4] Task Integration -> [5] Tests
|
||||
\
|
||||
[3] Formula Engine /
|
||||
|
||||
[6] Management UI -> [7] Task Forms -> [8] View Display
|
||||
```
|
||||
|
||||
- Tasks 1-5 (Backend) 可平行於 Tasks 6-8 (Frontend) 開發
|
||||
- Task 2 完成後 Task 6 可開始(需要 API)
|
||||
- Task 4 完成後 Task 7 可開始(需要 Task API 支援 custom values)
|
||||
@@ -0,0 +1,110 @@
|
||||
# Proposal: Add File Encryption
|
||||
|
||||
**Change ID:** `add-file-encryption`
|
||||
**Issue Reference:** `FEAT-010` (issues.md)
|
||||
**Status:** Draft
|
||||
**Author:** Claude
|
||||
**Date:** 2026-01-05
|
||||
|
||||
## Summary
|
||||
|
||||
實作 AES-256 加密存儲功能,對機密等級專案的附件進行加密保護,並提供金鑰管理與輪換機制。
|
||||
|
||||
## Motivation
|
||||
|
||||
半導體產業的設計文件、製程參數和良率報告屬於高度機密資料。目前系統的附件以明文形式儲存於 NAS,若發生以下情況可能導致資料外洩:
|
||||
- NAS 遭未授權存取
|
||||
- 備份媒體遺失
|
||||
- 儲存設備報廢未妥善處理
|
||||
|
||||
透過 AES-256 加密,即使檔案被取得也無法解讀內容,提供額外的安全層。
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Backend: EncryptionKey model 和 key 管理 API
|
||||
- Backend: 加密服務(encrypt/decrypt)
|
||||
- Backend: 附件上傳時自動加密(依專案機密等級)
|
||||
- Backend: 附件下載時自動解密
|
||||
- Backend: 金鑰輪換功能
|
||||
- 稽核日誌:加密相關操作記錄
|
||||
|
||||
### Out of Scope
|
||||
- 客戶端加密(End-to-End Encryption)
|
||||
- Hardware Security Module (HSM) 整合
|
||||
- 現有檔案的批次加密遷移(需另案處理)
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 加密策略
|
||||
| 專案機密等級 | 加密行為 |
|
||||
|-------------|---------|
|
||||
| public | 不加密 |
|
||||
| department | 不加密 |
|
||||
| confidential | 強制加密 |
|
||||
|
||||
### 金鑰管理
|
||||
- 採用對稱金鑰加密(AES-256-GCM)
|
||||
- 每個金鑰有唯一 ID,儲存於資料庫
|
||||
- 金鑰本身使用 Master Key 加密後存儲
|
||||
- Master Key 從環境變數讀取,不存於資料庫
|
||||
|
||||
### 加密流程
|
||||
```
|
||||
1. 上傳檔案
|
||||
2. 檢查專案機密等級
|
||||
3. 若為 confidential:
|
||||
a. 取得當前有效金鑰
|
||||
b. 使用 AES-256-GCM 加密檔案
|
||||
c. 儲存加密後的檔案
|
||||
d. 記錄 encryption_key_id
|
||||
4. 儲存 Attachment 記錄
|
||||
```
|
||||
|
||||
### 解密流程
|
||||
```
|
||||
1. 請求下載檔案
|
||||
2. 驗證存取權限
|
||||
3. 若 is_encrypted = true:
|
||||
a. 取得 encryption_key_id 對應的金鑰
|
||||
b. 解密檔案
|
||||
c. 返回解密後的內容
|
||||
4. 若 is_encrypted = false:
|
||||
a. 直接返回檔案
|
||||
```
|
||||
|
||||
### 金鑰輪換
|
||||
- 建立新金鑰並標記為 active
|
||||
- 舊金鑰標記為 inactive(但保留用於解密舊檔案)
|
||||
- 新上傳檔案使用新金鑰
|
||||
- 可選:批次重新加密舊檔案(背景任務)
|
||||
|
||||
### API 設計
|
||||
```
|
||||
# 金鑰管理 (Admin only)
|
||||
GET /api/admin/encryption-keys # 列出所有金鑰
|
||||
POST /api/admin/encryption-keys # 建立新金鑰
|
||||
POST /api/admin/encryption-keys/rotate # 金鑰輪換
|
||||
DELETE /api/admin/encryption-keys/{id} # 停用金鑰(不刪除)
|
||||
|
||||
# 附件加密狀態由系統自動處理,無需額外 API
|
||||
```
|
||||
|
||||
## Affected Specs
|
||||
|
||||
| Spec | Change Type |
|
||||
|------|-------------|
|
||||
| document-management | MODIFIED (File Encryption requirement 實作細節) |
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Master Key 遺失導致資料無法解密 | 提供 Master Key 備份指引,建議異地保存 |
|
||||
| 加密效能影響 | 使用串流加密避免大檔案記憶體問題 |
|
||||
| 金鑰輪換中斷 | 使用資料庫交易確保原子性 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Python cryptography 套件
|
||||
- Master Key 環境變數配置
|
||||
@@ -0,0 +1,52 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: File Encryption
|
||||
系統 SHALL 對半導體敏感圖檔進行 AES-256 加密存儲。
|
||||
|
||||
#### Scenario: 自動加密判斷
|
||||
- **GIVEN** 使用者上傳檔案至任務
|
||||
- **WHEN** 該任務所屬專案的 security_level 為 "confidential"
|
||||
- **THEN** 系統自動使用 AES-256-GCM 加密檔案
|
||||
- **AND** 設定 is_encrypted = true 及 encryption_key_id
|
||||
|
||||
#### Scenario: 加密存儲
|
||||
- **GIVEN** 專案設定為機密等級
|
||||
- **WHEN** 使用者上傳檔案
|
||||
- **THEN** 系統使用 AES-256 加密後存儲
|
||||
- **AND** 加密金鑰安全管理
|
||||
|
||||
#### Scenario: 解密讀取
|
||||
- **GIVEN** 使用者請求下載加密檔案
|
||||
- **WHEN** 系統驗證權限通過
|
||||
- **THEN** 系統解密檔案後提供下載
|
||||
- **AND** 解密過程透明,使用者無感
|
||||
|
||||
#### Scenario: 串流處理大檔案
|
||||
- **GIVEN** 使用者上傳或下載大型加密檔案
|
||||
- **WHEN** 系統處理加密或解密
|
||||
- **THEN** 使用串流方式處理避免記憶體溢出
|
||||
- **AND** 效能損耗在可接受範圍內
|
||||
|
||||
#### Scenario: 金鑰輪換
|
||||
- **GIVEN** 安全政策要求金鑰輪換
|
||||
- **WHEN** 管理員執行金鑰輪換
|
||||
- **THEN** 系統建立新金鑰並標記為 active
|
||||
- **AND** 舊金鑰保留用於解密既有檔案
|
||||
- **AND** 新上傳檔案使用新金鑰加密
|
||||
|
||||
#### Scenario: Master Key 管理
|
||||
- **GIVEN** 系統需要加解密檔案
|
||||
- **WHEN** 系統取得加密金鑰
|
||||
- **THEN** 使用 Master Key 解密金鑰後使用
|
||||
- **AND** Master Key 從環境變數讀取,不存於資料庫
|
||||
|
||||
#### Scenario: 加密操作稽核
|
||||
- **GIVEN** 發生加密相關操作
|
||||
- **WHEN** 操作完成
|
||||
- **THEN** 系統記錄操作類型、金鑰 ID、檔案 ID、操作者、時間
|
||||
- **AND** 日誌不可竄改
|
||||
|
||||
#### Scenario: 金鑰管理權限
|
||||
- **GIVEN** 使用者嘗試管理加密金鑰
|
||||
- **WHEN** 使用者不是系統管理員
|
||||
- **THEN** 系統拒絕操作並返回 403 錯誤
|
||||
@@ -0,0 +1,89 @@
|
||||
# Tasks: Add File Encryption
|
||||
|
||||
## Backend Tasks
|
||||
|
||||
### 1. Create EncryptionKey model
|
||||
- [x] Create `backend/app/models/encryption_key.py`
|
||||
- [x] Update `backend/app/models/__init__.py`
|
||||
- [x] Add `encryption_key_id` FK to Attachment model
|
||||
- [x] Create Alembic migration
|
||||
- **驗證**: Migration 成功執行
|
||||
|
||||
### 2. Implement encryption service
|
||||
- [x] Create `backend/app/services/encryption_service.py`
|
||||
- [x] Add `MASTER_KEY` to config.py (from env var)
|
||||
- [x] Implement `generate_key()` - 產生新的 AES-256 金鑰
|
||||
- [x] Implement `encrypt_key()` - 使用 Master Key 加密金鑰
|
||||
- [x] Implement `decrypt_key()` - 使用 Master Key 解密金鑰
|
||||
- [x] Implement `encrypt_file()` - 串流式檔案加密 (AES-256-GCM)
|
||||
- [x] Implement `decrypt_file()` - 串流式檔案解密
|
||||
- [x] Add unit tests for encryption service
|
||||
- **驗證**: 加密解密測試通過
|
||||
|
||||
### 3. Create encryption key management API
|
||||
- [x] Create `backend/app/api/admin/encryption_keys.py`
|
||||
- [x] Implement `GET /api/admin/encryption-keys` - 列出金鑰(不含實際金鑰值)
|
||||
- [x] Implement `POST /api/admin/encryption-keys` - 建立新金鑰
|
||||
- [x] Implement `POST /api/admin/encryption-keys/rotate` - 金鑰輪換
|
||||
- [x] Add system admin only permission check
|
||||
- [x] Register router in main.py
|
||||
- **驗證**: API 可正常呼叫
|
||||
|
||||
### 4. Integrate encryption with attachment upload
|
||||
- [x] Modify `backend/app/api/attachments/router.py` upload endpoint
|
||||
- [x] Check project security_level before upload
|
||||
- [x] If confidential: encrypt file using encryption service
|
||||
- [x] Set is_encrypted = True and encryption_key_id
|
||||
- [x] Store encrypted file to NAS
|
||||
- **驗證**: 機密專案上傳的檔案為加密狀態
|
||||
|
||||
### 5. Integrate decryption with attachment download
|
||||
- [x] Modify `backend/app/api/attachments/router.py` download endpoint
|
||||
- [x] Check is_encrypted flag
|
||||
- [x] If encrypted: decrypt using encryption service before returning
|
||||
- [x] Maintain streaming for large files
|
||||
- **驗證**: 下載加密檔案可正確解密
|
||||
|
||||
### 6. Add encryption audit logging
|
||||
- [x] Log encryption operations (encrypt, decrypt, key_create, key_rotate)
|
||||
- [x] Include key_id, file_id, user_id, timestamp
|
||||
- **驗證**: 稽核日誌正確記錄加密操作
|
||||
|
||||
### 7. Add backend tests
|
||||
- [x] Test encryption service (encrypt/decrypt)
|
||||
- [x] Test key management API
|
||||
- [x] Test attachment upload with encryption
|
||||
- [x] Test attachment download with decryption
|
||||
- [x] Test key rotation
|
||||
- **驗證**: 所有測試通過
|
||||
|
||||
## Configuration Tasks
|
||||
|
||||
### 8. Environment configuration
|
||||
- [x] Add `MASTER_KEY` to .env.example
|
||||
- [x] Document key generation procedure
|
||||
- [x] Document key backup recommendations
|
||||
- **驗證**: 文件完整
|
||||
|
||||
## Task Dependencies
|
||||
|
||||
```
|
||||
[1] EncryptionKey Model
|
||||
↓
|
||||
[2] Encryption Service
|
||||
↓
|
||||
[3] Key Management API ─────┐
|
||||
↓ │
|
||||
[4] Upload Integration │
|
||||
↓ │
|
||||
[5] Download Integration │
|
||||
↓ │
|
||||
[6] Audit Logging │
|
||||
↓ │
|
||||
[7] Tests ←─────────────────┘
|
||||
↓
|
||||
[8] Configuration
|
||||
```
|
||||
|
||||
- Tasks 1-7 為循序依賴
|
||||
- Task 8 可平行進行
|
||||
111
openspec/changes/archive/2026-01-05-add-gantt-view/proposal.md
Normal file
111
openspec/changes/archive/2026-01-05-add-gantt-view/proposal.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Proposal: Add Gantt View
|
||||
|
||||
**Change ID:** `add-gantt-view`
|
||||
**Issue Reference:** `FEAT-003` (issues.md)
|
||||
**Status:** Draft
|
||||
**Author:** Claude
|
||||
**Date:** 2026-01-05
|
||||
|
||||
## Summary
|
||||
|
||||
實作甘特圖視角,以時間軸方式呈現專案任務,顯示任務期間、依賴關係和里程碑。
|
||||
|
||||
## Motivation
|
||||
|
||||
甘特圖是專案管理的核心視覺化工具,可幫助團隊:
|
||||
- 了解任務時程與排程
|
||||
- 識別關鍵路徑
|
||||
- 發現資源衝突和瓶頸
|
||||
- 追蹤進度與延遲
|
||||
|
||||
目前系統僅有看板和列表視角,缺少時間軸視圖,無法直觀地規劃和追蹤專案進度。
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Backend: Task model 新增 start_date 欄位
|
||||
- Backend: TaskDependency model(前置任務關係)
|
||||
- Backend: 依賴關係 CRUD API
|
||||
- Frontend: Gantt chart 元件(使用第三方函式庫)
|
||||
- Frontend: 任務時程編輯(拖拉調整日期)
|
||||
- Frontend: 依賴關係視覺化(箭頭連線)
|
||||
|
||||
### Out of Scope
|
||||
- 關鍵路徑計算
|
||||
- 資源分配視圖
|
||||
- 基線對比功能
|
||||
- 匯出為圖片/PDF
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 任務依賴類型
|
||||
| Type | 說明 | 範例 |
|
||||
|------|------|------|
|
||||
| finish_to_start (FS) | 前置任務完成後才能開始 | 設計完成 → 開發開始 |
|
||||
| start_to_start (SS) | 前置任務開始後才能開始 | 設計開始 → 文件開始 |
|
||||
| finish_to_finish (FF) | 前置任務完成後才能完成 | 開發完成 → 測試完成 |
|
||||
| start_to_finish (SF) | 前置任務開始後才能完成 | 較少使用 |
|
||||
|
||||
**預設**: finish_to_start (FS) 為最常見類型
|
||||
|
||||
### Data Model 變更
|
||||
```sql
|
||||
-- Task 新增欄位
|
||||
ALTER TABLE pjctrl_tasks ADD COLUMN start_date DATETIME;
|
||||
|
||||
-- 新增依賴關係表
|
||||
CREATE TABLE pjctrl_task_dependencies (
|
||||
id UUID PRIMARY KEY,
|
||||
predecessor_id UUID REFERENCES pjctrl_tasks(id),
|
||||
successor_id UUID REFERENCES pjctrl_tasks(id),
|
||||
dependency_type ENUM('FS', 'SS', 'FF', 'SF') DEFAULT 'FS',
|
||||
lag_days INT DEFAULT 0,
|
||||
created_at TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 前端函式庫選擇
|
||||
建議使用 **DHTMLX Gantt** 或 **Frappe Gantt**:
|
||||
|
||||
| 函式庫 | 優點 | 缺點 |
|
||||
|--------|------|------|
|
||||
| DHTMLX Gantt | 功能完整、效能好 | 商業授權 |
|
||||
| Frappe Gantt | 開源、輕量 | 功能較少 |
|
||||
| React-Gantt-Chart | React 原生 | 社群較小 |
|
||||
|
||||
**建議**: 使用 Frappe Gantt(MIT 授權),足夠基本需求
|
||||
|
||||
### API 設計
|
||||
```
|
||||
# 依賴關係 API
|
||||
POST /api/tasks/{task_id}/dependencies # 新增依賴
|
||||
GET /api/tasks/{task_id}/dependencies # 取得依賴
|
||||
DELETE /api/task-dependencies/{dependency_id} # 刪除依賴
|
||||
|
||||
# 任務日期更新(使用現有 API)
|
||||
PUT /api/tasks/{task_id} # body 包含 start_date, due_date
|
||||
```
|
||||
|
||||
### 日期驗證規則
|
||||
- start_date 不可晚於 due_date
|
||||
- 有依賴關係時,根據 dependency_type 驗證日期合理性
|
||||
- 循環依賴檢測
|
||||
|
||||
## Affected Specs
|
||||
|
||||
| Spec | Change Type |
|
||||
|------|-------------|
|
||||
| task-management | MODIFIED (Multiple Views requirement 甘特圖細節) |
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 複雜依賴關係影響效能 | 限制單任務最多 10 個直接依賴 |
|
||||
| 循環依賴 | 新增/修改依賴時進行循環檢測 |
|
||||
| 大型專案載入慢 | 分頁載入或虛擬滾動 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Frappe Gantt(或其他甘特圖函式庫)
|
||||
- 需要 Task model 已有 due_date 欄位(✓ 已存在)
|
||||
@@ -0,0 +1,67 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Multiple Views
|
||||
系統 SHALL 支援多維視角:看板 (Kanban)、甘特圖 (Gantt)、列表 (List)、行事曆 (Calendar)。
|
||||
|
||||
#### Scenario: 甘特圖視角
|
||||
- **GIVEN** 使用者選擇甘特圖視角
|
||||
- **WHEN** 系統載入專案任務
|
||||
- **THEN** 任務依時間軸顯示為水平條狀
|
||||
- **AND** 顯示任務相依關係與里程碑
|
||||
|
||||
#### Scenario: 甘特圖時間軸縮放
|
||||
- **GIVEN** 使用者正在查看甘特圖
|
||||
- **WHEN** 使用者切換縮放層級(日、週、月)
|
||||
- **THEN** 時間軸相應調整顯示密度
|
||||
- **AND** 任務條保持正確的相對位置
|
||||
|
||||
#### Scenario: 拖拉調整任務日期
|
||||
- **GIVEN** 使用者正在查看甘特圖
|
||||
- **WHEN** 使用者拖拉任務條改變位置或長度
|
||||
- **THEN** 系統更新任務的 start_date 和 due_date
|
||||
- **AND** 驗證日期合理性(start_date <= due_date)
|
||||
|
||||
#### Scenario: 顯示任務依賴關係
|
||||
- **GIVEN** 任務之間存在依賴關係
|
||||
- **WHEN** 使用者查看甘特圖
|
||||
- **THEN** 系統顯示連接任務的箭頭
|
||||
- **AND** 箭頭方向表示依賴方向(前置任務 → 後續任務)
|
||||
|
||||
#### Scenario: 新增任務依賴
|
||||
- **GIVEN** 使用者在甘特圖上選擇兩個任務
|
||||
- **WHEN** 使用者建立依賴關係
|
||||
- **THEN** 系統儲存依賴關係
|
||||
- **AND** 顯示連接箭頭
|
||||
|
||||
#### Scenario: 刪除任務依賴
|
||||
- **GIVEN** 任務之間存在依賴關係
|
||||
- **WHEN** 使用者刪除該依賴
|
||||
- **THEN** 系統移除依賴記錄
|
||||
- **AND** 連接箭頭消失
|
||||
|
||||
#### Scenario: 循環依賴檢測
|
||||
- **GIVEN** 使用者嘗試建立依賴關係
|
||||
- **WHEN** 該依賴會形成循環(A → B → C → A)
|
||||
- **THEN** 系統拒絕建立並顯示錯誤訊息
|
||||
- **AND** 現有依賴關係保持不變
|
||||
|
||||
#### Scenario: 依賴類型支援
|
||||
- **GIVEN** 使用者建立任務依賴
|
||||
- **WHEN** 使用者選擇依賴類型
|
||||
- **THEN** 系統支援以下類型:
|
||||
- Finish-to-Start (FS): 前置完成後開始
|
||||
- Start-to-Start (SS): 前置開始後開始
|
||||
- Finish-to-Finish (FF): 前置完成後完成
|
||||
- Start-to-Finish (SF): 前置開始後完成
|
||||
|
||||
## ADDED Data Model
|
||||
|
||||
```
|
||||
pjctrl_task_dependencies
|
||||
├── id: UUID (PK)
|
||||
├── predecessor_id: UUID (FK -> tasks)
|
||||
├── successor_id: UUID (FK -> tasks)
|
||||
├── dependency_type: ENUM('FS', 'SS', 'FF', 'SF') DEFAULT 'FS'
|
||||
├── lag_days: INT DEFAULT 0
|
||||
└── created_at: TIMESTAMP
|
||||
```
|
||||
92
openspec/changes/archive/2026-01-05-add-gantt-view/tasks.md
Normal file
92
openspec/changes/archive/2026-01-05-add-gantt-view/tasks.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Tasks: Add Gantt View
|
||||
|
||||
## Backend Tasks
|
||||
|
||||
### 1. Add start_date to Task model
|
||||
- [x] Add `start_date` column to Task model
|
||||
- [x] Create Alembic migration
|
||||
- [x] Update TaskCreate/TaskUpdate schemas to include start_date
|
||||
- [x] Update TaskResponse schema
|
||||
- **驗證**: Migration 成功,API 可設定 start_date
|
||||
|
||||
### 2. Create TaskDependency model
|
||||
- [x] Create `backend/app/models/task_dependency.py`
|
||||
- [x] Define predecessor_id, successor_id, dependency_type, lag_days
|
||||
- [x] Update `backend/app/models/__init__.py`
|
||||
- [x] Create Alembic migration
|
||||
- **驗證**: Migration 成功
|
||||
|
||||
### 3. Implement dependency CRUD API
|
||||
- [x] Create `backend/app/api/task_dependencies/router.py`
|
||||
- [x] Implement `POST /api/tasks/{task_id}/dependencies` - 新增依賴
|
||||
- [x] Implement `GET /api/tasks/{task_id}/dependencies` - 取得依賴
|
||||
- [x] Implement `DELETE /api/task-dependencies/{dependency_id}` - 刪除依賴
|
||||
- [x] Add circular dependency detection
|
||||
- [x] Register router in main.py
|
||||
- **驗證**: 依賴關係 CRUD 可正常操作,循環依賴被拒絕
|
||||
|
||||
### 4. Add date validation
|
||||
- [x] Validate start_date <= due_date
|
||||
- [x] Validate dependency constraints on date change
|
||||
- [x] Add validation tests
|
||||
- **驗證**: 不合理日期被拒絕
|
||||
|
||||
### 5. Add backend tests
|
||||
- [x] Test TaskDependency CRUD
|
||||
- [x] Test circular dependency detection
|
||||
- [x] Test date validation
|
||||
- **驗證**: 所有測試通過
|
||||
|
||||
## Frontend Tasks
|
||||
|
||||
### 6. Install and configure Gantt library
|
||||
- [x] Install Frappe Gantt (or chosen library)
|
||||
- [x] Create wrapper component for React integration
|
||||
- [x] Configure styling to match application theme
|
||||
- **驗證**: Gantt 元件可正常渲染
|
||||
|
||||
### 7. Create GanttChart component
|
||||
- [x] Create `frontend/src/components/GanttChart.tsx`
|
||||
- [x] Load tasks with start_date and due_date
|
||||
- [x] Display tasks as horizontal bars on timeline
|
||||
- [x] Show task title, assignee, progress
|
||||
- [x] Support zoom levels (day, week, month)
|
||||
- **驗證**: 任務正確顯示在時間軸上
|
||||
|
||||
### 8. Implement drag-to-edit dates
|
||||
- [x] Handle bar drag to move task dates
|
||||
- [x] Handle bar resize to change duration
|
||||
- [x] Call API to update task dates
|
||||
- [x] Show optimistic update, rollback on error
|
||||
- **驗證**: 拖拉調整日期可正確更新
|
||||
|
||||
### 9. Implement dependency visualization
|
||||
- [x] Add dependency arrows between tasks
|
||||
- [x] Create dependency API service
|
||||
- [x] Implement add/remove dependency UI (right-click or toolbar)
|
||||
- [x] Validate and show error for circular dependencies
|
||||
- **驗證**: 依賴關係正確顯示和編輯
|
||||
|
||||
### 10. Integrate Gantt view into Tasks page
|
||||
- [x] Add "Gantt" option to view toggle
|
||||
- [x] Store view preference in localStorage
|
||||
- [x] Handle view switching
|
||||
- **驗證**: 可在 List/Kanban/Gantt 之間切換
|
||||
|
||||
## Task Dependencies
|
||||
|
||||
```
|
||||
[1] start_date 欄位
|
||||
↓
|
||||
[2] TaskDependency Model → [3] Dependency API → [4] Date Validation → [5] Tests
|
||||
↓
|
||||
[6] Gantt Library Setup → [7] GanttChart Component
|
||||
↓
|
||||
[8] Drag Edit → [9] Dependency UI
|
||||
↓
|
||||
[10] View Integration
|
||||
```
|
||||
|
||||
- Tasks 1-5 (Backend) 可平行於 Tasks 6-10 (Frontend) 開發
|
||||
- Task 7 需要 Task 1 完成(需要 start_date 欄位)
|
||||
- Task 9 需要 Task 3 完成(需要依賴 API)
|
||||
Reference in New Issue
Block a user