feat: implement document management module

- Backend (FastAPI):
  - Attachment and AttachmentVersion models with migration
  - FileStorageService with SHA-256 checksum validation
  - File type validation (whitelist/blacklist)
  - Full CRUD API with version control support
  - Audit trail integration for upload/download/delete
  - Configurable upload directory and file size limit

- Frontend (React + Vite):
  - AttachmentUpload component with drag & drop
  - AttachmentList component with download/delete
  - TaskAttachments combined component
  - Attachments service for API calls

- Testing:
  - 12 tests for storage service and API endpoints

- OpenSpec:
  - add-document-management change archived

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beabigegg
2025-12-29 22:03:05 +08:00
parent 0ef78e13ff
commit 3108fe1dff
21 changed files with 2027 additions and 1 deletions

View File

@@ -0,0 +1,159 @@
## Context
文件管理是專案系統的核心功能,需要考慮:
- 檔案存儲策略(本地 vs NAS
- 安全需求(加密、浮水印)
- 版本控制邏輯
- 大檔案處理
## Goals / Non-Goals
**Goals:**
- 提供任務層級的檔案附件功能
- 支援基本 CRUD 操作
- 整合現有 Audit Trail
- 為未來 NAS 整合預留擴展性
**Non-Goals:**
- 即時協作編輯(不在此範圍)
- 全文搜尋(未來功能)
- 檔案預覽(未來功能)
## Decisions
### 1. 檔案存儲策略
**Decision:** 使用本地檔案系統 + 環境變數配置路徑
**Rationale:**
- 開發階段使用本地存儲簡化設置
- 生產環境透過環境變數指向 NAS 掛載點
- 路徑結構:`{UPLOAD_DIR}/{project_id}/{task_id}/{attachment_id}/{version}/`
**Alternatives considered:**
- 直接 NAS 整合 - 開發環境設置複雜
- S3 相容存儲 - 增加外部依賴
### 2. 版本控制模型
**Decision:** 主表 + 版本歷史表分離
```
pjctrl_attachments (主表,存儲最新版本資訊)
├── id, task_id, filename, current_version, ...
pjctrl_attachment_versions (歷史表)
├── id, attachment_id, version, file_path, ...
```
**Rationale:**
- 主表快速查詢當前附件
- 歷史表保留所有版本
- 上傳同名檔案 → 建立新版本 → 更新主表 current_version
### 3. 加密策略
**Decision:** 使用 Fernet (基於 AES-128-CBC) 對稱加密
**Rationale:**
- Python cryptography 庫內建支援
- 自動處理 IV、padding、HMAC 驗證
- 比原生 AES-256 更安全(防止實作錯誤)
- 效能足夠(非大規模加密場景)
**實作方式:**
- 加密金鑰存儲於環境變數 `ENCRYPTION_KEY`
- 僅對機密專案的附件加密
- 加密狀態存於 `is_encrypted` 欄位
### 4. 浮水印策略
**Decision:** 下載時動態生成浮水印
**Rationale:**
- 不修改原始檔案
- 每次下載包含當下使用者資訊
- 使用 Pillow (圖片) 和 PyMuPDF (PDF) 處理
**浮水印內容:**
- 使用者姓名 + 工號
- 下載時間
- 機密等級(如適用)
### 5. 檔案大小限制
**Decision:** 預設 50MB可透過環境變數調整
```python
MAX_FILE_SIZE = int(os.getenv("MAX_FILE_SIZE_MB", 50)) * 1024 * 1024
```
**Rationale:**
- 避免記憶體溢出
- 大檔案使用串流處理
- 生產環境可依需求調整
## Data Model
```sql
-- 附件主表
pjctrl_attachments
├── id: UUID (PK)
├── task_id: UUID (FK -> tasks)
├── filename: VARCHAR(255) -- 顯示名稱
├── original_filename: VARCHAR(255) -- 原始上傳名稱
├── mime_type: VARCHAR(100)
├── file_size: BIGINT
├── current_version: INT DEFAULT 1
├── is_encrypted: BOOLEAN DEFAULT false
├── uploaded_by: UUID (FK -> users)
├── is_deleted: BOOLEAN DEFAULT false
├── created_at: TIMESTAMP
└── updated_at: TIMESTAMP
-- 版本歷史表
pjctrl_attachment_versions
├── id: UUID (PK)
├── attachment_id: UUID (FK -> attachments)
├── version: INT
├── file_path: VARCHAR(1000) -- 實際存儲路徑
├── file_size: BIGINT
├── checksum: VARCHAR(64) -- SHA-256
├── uploaded_by: UUID (FK -> users)
├── created_at: TIMESTAMP
└── INDEX (attachment_id, version)
```
## API Design
```
POST /api/tasks/{task_id}/attachments # 上傳附件
GET /api/tasks/{task_id}/attachments # 列出附件
GET /api/attachments/{id} # 取得附件資訊
GET /api/attachments/{id}/download # 下載附件
GET /api/attachments/{id}/download?version=2 # 下載特定版本
DELETE /api/attachments/{id} # 刪除附件(軟刪除)
GET /api/attachments/{id}/versions # 版本歷史
POST /api/attachments/{id}/restore/{version} # 回復特定版本
```
## Risks / Trade-offs
| Risk | Mitigation |
|------|------------|
| 大檔案記憶體溢出 | 使用串流上傳/下載 |
| 加密金鑰洩漏 | 僅存於環境變數,定期輪換 |
| 浮水印處理耗時 | 限制支援的檔案類型,非同步處理大檔案 |
| NAS 不可用 | 本地存儲 fallback監控告警 |
## Migration Plan
1. Phase 1: 建立模型、基本 CRUD、本地存儲
2. Phase 2: 版本控制
3. Phase 3: 加密與浮水印(可選)
## Open Questions
- [ ] NAS 掛載點路徑確認
- [ ] 生產環境加密金鑰管理方式KMS? Vault?
- [ ] 是否需要支援拖放上傳多檔案?

View File

@@ -0,0 +1,44 @@
# Change: Add Document Management
## Why
專案管理系統需要文件附件功能,讓使用者能在任務層級上傳、下載、管理檔案。半導體產業對機密文件有特殊安全需求(加密存儲、浮水印追溯)。
## What Changes
- **新增 Attachment 模型** - 支援任務層級的檔案附件
- **新增 AttachmentVersion 模型** - 檔案版本控制
- **新增 File Storage Service** - 本地檔案存儲(可擴展至 NAS
- **新增 Attachment API** - 上傳、下載、刪除、版本管理
- **新增加密功能** - AES-256 加密存儲(機密專案)
- **新增浮水印功能** - 下載時動態加入使用者資訊
- **整合 Audit Trail** - 記錄所有文件操作
## Impact
- Affected specs: `document-management`, `audit-trail` (已實作)
- Affected code:
- `backend/app/models/` - 新增 attachment 相關模型
- `backend/app/api/` - 新增 attachments router
- `backend/app/services/` - 新增 file_service, encryption_service
- `frontend/src/components/` - 新增附件元件
- `backend/migrations/` - 新增資料表
## Implementation Phases
### Phase 1: Basic Attachments (MVP)
- 檔案上傳/下載/刪除
- 本地檔案存儲
- 基本 API 與前端整合
- Audit 日誌整合
### Phase 2: Version Control
- 同名檔案版本控制
- 版本歷史查看
- 版本回復
### Phase 3: Security Features (Optional)
- AES-256 加密存儲
- 動態浮水印(圖片/PDF
- 加密金鑰管理
## Dependencies
- audit-trail (已完成) - 用於文件操作日誌
- collaboration (已完成) - 可在評論中引用附件

View File

@@ -0,0 +1,44 @@
## MODIFIED Requirements
### Requirement: Audit Trail
系統 SHALL 記錄所有文件操作供稽核追溯,整合現有 audit-trail 模組。
#### Scenario: 操作日誌記錄
- **GIVEN** 使用者對附件執行任何操作(上傳、下載、刪除)
- **WHEN** 操作完成
- **THEN** 系統透過 AuditService 記錄操作至 `pjctrl_audit_logs`
- **AND** 使用 event_type: `attachment.upload`, `attachment.download`, `attachment.delete`
#### Scenario: 稽核查詢
- **GIVEN** 稽核人員需要查詢文件操作歷史
- **WHEN** 稽核人員透過 Audit API 執行查詢
- **THEN** 可依 resource_type=attachment 篩選
- **AND** 顯示完整操作歷史
## ADDED Requirements
### Requirement: File Size Limits
系統 SHALL 限制上傳檔案大小以確保系統穩定性。
#### Scenario: 檔案大小驗證
- **GIVEN** 使用者上傳檔案
- **WHEN** 檔案大小超過限制(預設 50MB
- **THEN** 系統拒絕上傳並回傳錯誤訊息
#### Scenario: 大小限制配置
- **GIVEN** 管理者需要調整檔案大小限制
- **WHEN** 設定環境變數 MAX_FILE_SIZE_MB
- **THEN** 系統使用新的限制值
### Requirement: Mime Type Validation
系統 SHALL 驗證上傳檔案類型以確保安全性。
#### Scenario: 允許的檔案類型
- **GIVEN** 使用者上傳附件
- **WHEN** 檔案類型為常見文件格式pdf, doc, xls, jpg, png, zip 等)
- **THEN** 系統接受上傳
#### Scenario: 危險檔案類型拒絕
- **GIVEN** 使用者上傳附件
- **WHEN** 檔案類型為可執行檔exe, bat, sh, dll 等)
- **THEN** 系統拒絕上傳並回傳錯誤訊息

View File

@@ -0,0 +1,71 @@
## Phase 1: Basic Attachments
### 1.1 Database Schema
- [x] 1.1.1 建立 Attachment model (`pjctrl_attachments`)
- [x] 1.1.2 建立 AttachmentVersion model (`pjctrl_attachment_versions`)
- [x] 1.1.3 建立 Alembic migration
- [x] 1.1.4 新增 Task model 的 attachments relationship
### 1.2 File Storage Service
- [x] 1.2.1 建立 FileStorageService 類別
- [x] 1.2.2 實作 save_file() 方法(串流處理)
- [x] 1.2.3 實作 get_file() 方法
- [x] 1.2.4 實作 delete_file() 方法
- [x] 1.2.5 新增檔案存儲路徑配置 (UPLOAD_DIR)
- [x] 1.2.6 實作 checksum 計算 (SHA-256)
### 1.3 Attachment API
- [x] 1.3.1 建立 Attachment schemas (request/response)
- [x] 1.3.2 實作 POST `/api/tasks/{task_id}/attachments` - 上傳
- [x] 1.3.3 實作 GET `/api/tasks/{task_id}/attachments` - 列表
- [x] 1.3.4 實作 GET `/api/attachments/{id}` - 詳情
- [x] 1.3.5 實作 GET `/api/attachments/{id}/download` - 下載
- [x] 1.3.6 實作 DELETE `/api/attachments/{id}` - 軟刪除
- [x] 1.3.7 整合 Audit Trail - 記錄上傳/下載/刪除操作
### 1.4 Frontend - Basic
- [x] 1.4.1 建立 attachments.ts service
- [x] 1.4.2 建立 AttachmentList 元件
- [x] 1.4.3 建立 AttachmentUpload 元件(支援拖放)
- [x] 1.4.4 整合至 Task 詳情頁 (TaskAttachments 元件)
### 1.5 Testing - Phase 1
- [x] 1.5.1 FileStorageService 單元測試
- [x] 1.5.2 Attachment API 端點測試
- [x] 1.5.3 上傳/下載整合測試
## Phase 2: Version Control
### 2.1 Version Logic
- [x] 2.1.1 修改上傳邏輯支援版本控制
- [x] 2.1.2 實作 GET `/api/attachments/{id}/versions` - 版本歷史
- [x] 2.1.3 實作 POST `/api/attachments/{id}/restore/{version}` - 回復版本
- [x] 2.1.4 實作 GET `/api/attachments/{id}/download?version=N` - 下載特定版本
### 2.2 Frontend - Version
- [x] 2.2.1 建立 VersionHistory 元件 (integrated in AttachmentList)
- [x] 2.2.2 新增版本選擇下載功能 (in attachments service)
- [x] 2.2.3 新增版本回復功能 (in attachments service)
### 2.3 Testing - Phase 2
- [x] 2.3.1 版本控制邏輯測試
- [x] 2.3.2 版本 API 端點測試
## Phase 3: Security Features (Optional)
### 3.1 Encryption
- [ ] 3.1.1 建立 EncryptionService 類別
- [ ] 3.1.2 實作 encrypt_file() / decrypt_file() 方法
- [ ] 3.1.3 新增 Project security_level 欄位(如不存在)
- [ ] 3.1.4 修改上傳邏輯:機密專案自動加密
- [ ] 3.1.5 修改下載邏輯:自動解密
### 3.2 Watermarking
- [ ] 3.2.1 建立 WatermarkService 類別
- [ ] 3.2.2 實作圖片浮水印Pillow
- [ ] 3.2.3 實作 PDF 浮水印PyMuPDF
- [ ] 3.2.4 整合至下載流程
### 3.3 Testing - Phase 3
- [ ] 3.3.1 加密/解密測試
- [ ] 3.3.2 浮水印生成測試