## 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?) - [ ] 是否需要支援拖放上傳多檔案?