Files
PROJECT-CONTORL/openspec/specs/audit-trail/spec.md
beabigegg 35c90fe76b feat: implement 5 QA-driven security and quality proposals
Implemented proposals from comprehensive QA review:

1. extend-csrf-protection
   - Add POST to CSRF protected methods in frontend
   - Global CSRF middleware for all state-changing operations
   - Update tests with CSRF token fixtures

2. tighten-cors-websocket-security
   - Replace wildcard CORS with explicit method/header lists
   - Disable query parameter auth in production (code 4002)
   - Add per-user WebSocket connection limit (max 5, code 4005)

3. shorten-jwt-expiry
   - Reduce JWT expiry from 7 days to 60 minutes
   - Add refresh token support with 7-day expiry
   - Implement token rotation on refresh
   - Frontend auto-refresh when token near expiry (<5 min)

4. fix-frontend-quality
   - Add React.lazy() code splitting for all pages
   - Fix useCallback dependency arrays (Dashboard, Comments)
   - Add localStorage data validation in AuthContext
   - Complete i18n for AttachmentUpload component

5. enhance-backend-validation
   - Add SecurityAuditMiddleware for access denied logging
   - Add ErrorSanitizerMiddleware for production error messages
   - Protect /health/detailed with admin authentication
   - Add input length validation (comment 5000, desc 10000)

All 521 backend tests passing. Frontend builds successfully.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 23:19:05 +08:00

6.9 KiB
Raw Blame History

Audit Trail

Purpose

系統級稽核追蹤,記錄所有關鍵變更操作供合規與追溯需求。

Requirements

Requirement: Change Logging

系統 SHALL 記錄所有關鍵變更操作,包含誰在何時改了什麼。

Scenario: 任務欄位變更記錄

  • GIVEN 使用者修改任務的任何欄位(如截止日期、狀態、指派者)
  • WHEN 變更儲存成功
  • THEN 系統記錄變更前後的值
  • AND 記錄操作者、時間、IP 位址

Scenario: 專案設定變更記錄

  • GIVEN 管理者修改專案設定
  • WHEN 設定變更儲存
  • THEN 系統記錄所有變更的設定項目
  • AND 記錄操作者與時間

Scenario: 權限變更記錄

  • GIVEN 管理者修改使用者權限或角色
  • WHEN 權限變更生效
  • THEN 系統記錄權限變更詳情
  • AND 標記為高敏感度操作

Requirement: Delete Operations Tracking

系統 SHALL 追蹤所有刪除操作,支援軟刪除與追溯。

Scenario: 任務刪除記錄

  • GIVEN 使用者刪除任務
  • WHEN 刪除操作執行
  • THEN 系統執行軟刪除(標記 is_deleted = true
  • AND 記錄刪除操作與原因

Scenario: 附件刪除記錄

  • GIVEN 使用者刪除附件
  • WHEN 刪除操作執行
  • THEN 系統保留檔案於存檔區
  • AND 記錄刪除操作詳情

Requirement: Audit Log Immutability

系統 SHALL 確保稽核日誌不可竄改。

Scenario: 日誌寫入

  • GIVEN 需要記錄稽核事件
  • WHEN 日誌寫入
  • THEN 日誌記錄不可被修改或刪除
  • AND 包含校驗碼確保完整性

Scenario: 日誌完整性驗證

  • GIVEN 稽核人員需要驗證日誌完整性
  • WHEN 執行完整性檢查
  • THEN 系統驗證所有日誌記錄的校驗碼
  • AND 報告任何異常

Requirement: Audit Query Interface

系統 SHALL 提供稽核查詢介面供授權人員使用。

Scenario: 依時間範圍查詢

  • GIVEN 稽核人員需要查詢特定時間範圍的操作
  • WHEN 設定時間範圍並執行查詢
  • THEN 顯示該時間範圍內的所有稽核記錄

Scenario: 依操作者查詢

  • GIVEN 稽核人員需要查詢特定使用者的操作歷史
  • WHEN 選擇使用者並執行查詢
  • THEN 顯示該使用者的所有操作記錄

Scenario: 依資源查詢

  • GIVEN 稽核人員需要查詢特定任務或專案的變更歷史
  • WHEN 選擇資源並執行查詢
  • THEN 顯示該資源的完整變更歷程

Scenario: 稽核報告匯出

  • GIVEN 稽核人員需要匯出稽核報告
  • WHEN 選擇匯出格式CSV/PDF
  • THEN 系統生成報告檔案供下載

Requirement: Sensitive Operation Alerts

系統 SHALL 對高敏感度操作發送即時警示。

Scenario: 權限提升警示

  • GIVEN 使用者被授予管理員權限
  • WHEN 權限變更生效
  • THEN 系統發送警示給安全管理員

Scenario: 大量刪除警示

  • GIVEN 使用者在短時間內刪除大量資料
  • WHEN 偵測到異常刪除模式
  • THEN 系統發送警示並暫停操作

Scenario: 異常登入警示

  • GIVEN 偵測到異常登入行為(如異地登入、非工作時間登入)
  • WHEN 異常行為發生
  • THEN 系統記錄並發送警示

Requirement: Security Event Logging

The system SHALL record failed access attempts for security monitoring and intrusion detection.

Scenario: Permission denied logged

  • WHEN server returns 403 Forbidden for a resource access attempt
  • THEN audit log entry is created with event_type "security.access_denied"
  • AND entry includes user_id, resource_type, and attempted_action

Scenario: Repeated auth failures logged

  • WHEN same IP has 5+ failed authentication attempts in 10 minutes
  • THEN audit log entry is created with event_type "security.suspicious_auth_pattern"
  • AND entry includes IP address and failure count
  • AND alert is generated for security administrators

Requirement: Detailed Health Endpoint Security

The detailed system health endpoint SHALL require admin authentication to prevent information disclosure.

Scenario: Admin accesses detailed health

  • WHEN system administrator requests GET /health/detailed
  • THEN full system status including connection pools is returned

Scenario: Non-admin accesses detailed health

  • WHEN non-admin user or unauthenticated request to GET /health/detailed
  • THEN request is rejected with 401 Unauthorized or 403 Forbidden

Data Model

pjctrl_audit_logs
├── id: UUID (PK)
├── event_type: VARCHAR(50)
│   └── 'task.update', 'task.delete', 'project.update', 'user.permission_change', etc.
├── resource_type: VARCHAR(50)
│   └── 'task', 'project', 'user', 'attachment', 'trigger', etc.
├── resource_id: UUID
├── user_id: UUID (FK -> users)
├── action: ENUM('create', 'update', 'delete', 'restore', 'login', 'logout')
├── changes: JSON
│   └── { "field": "due_date", "old_value": "2024-01-15", "new_value": "2024-01-20" }
├── metadata: JSON
│   └── { "ip_address": "192.168.1.100", "user_agent": "...", "session_id": "..." }
├── sensitivity_level: ENUM('low', 'medium', 'high', 'critical')
├── checksum: VARCHAR(64) (SHA-256 of record content)
├── created_at: TIMESTAMP (immutable)
└── INDEX idx_audit_user (user_id, created_at)
└── INDEX idx_audit_resource (resource_type, resource_id, created_at)
└── INDEX idx_audit_time (created_at)

pjctrl_audit_alerts
├── id: UUID (PK)
├── audit_log_id: UUID (FK -> audit_logs)
├── alert_type: VARCHAR(50)
├── recipients: JSON (array of user IDs)
├── message: TEXT
├── is_acknowledged: BOOLEAN DEFAULT false
├── acknowledged_by: UUID (FK -> users)
├── acknowledged_at: TIMESTAMP
└── created_at: TIMESTAMP

Event Types Reference

事件類型 說明 敏感度
task.create 建立任務 low
task.update 更新任務 low
task.delete 刪除任務 medium
task.assign 指派任務 low
task.blocker 標記阻礙 medium
project.create 建立專案 medium
project.update 更新專案 medium
project.delete 刪除專案 high
user.login 使用者登入 low
user.logout 使用者登出 low
user.permission_change 權限變更 critical
attachment.upload 上傳附件 low
attachment.download 下載附件 low
attachment.delete 刪除附件 medium

Technical Notes

  • 稽核日誌表設計為 append-only不允許 UPDATE 或 DELETE
  • 使用資料庫觸發器或應用層中間件自動記錄變更
  • 日誌保留期限依法規要求設定(建議至少 7 年)
  • 考慮使用時間序列資料庫(如 TimescaleDB處理大量日誌
  • Checksum 計算包含event_type + resource_id + user_id + changes + created_at