feat: implement audit trail module
- Backend (FastAPI): - AuditLog and AuditAlert models with Alembic migration - AuditService with SHA-256 checksum for log integrity - AuditMiddleware for request metadata extraction (IP, user_agent) - Integrated audit logging into Task, Project, Blocker APIs - Query API with filtering, pagination, CSV export - Integrity verification endpoint - Sensitive operation alerts with acknowledgement - Frontend (React + Vite): - Admin AuditPage with filters and export - ResourceHistory component for change tracking - Audit service for API calls - Testing: - 15 tests covering service and API endpoints - OpenSpec: - add-audit-trail 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:
147
openspec/changes/archive/2025-12-29-add-audit-trail/design.md
Normal file
147
openspec/changes/archive/2025-12-29-add-audit-trail/design.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Design: add-audit-trail
|
||||
|
||||
## Architecture Decision
|
||||
|
||||
### Approach: Application-layer Middleware
|
||||
|
||||
選擇應用層中間件而非資料庫觸發器:
|
||||
|
||||
| 方案 | 優點 | 缺點 |
|
||||
|-----|------|-----|
|
||||
| **Middleware (選擇)** | 可取得完整 context (user, IP)、跨資料庫相容 | 需要在每個 API 加入 |
|
||||
| DB Trigger | 自動捕捉所有變更 | 無法取得 user context、MySQL 觸發器效能差 |
|
||||
|
||||
### Implementation Strategy
|
||||
|
||||
```
|
||||
Request → FastAPI Middleware → Extract metadata (user, IP, user_agent)
|
||||
↓
|
||||
API Handler → Execute operation
|
||||
↓
|
||||
AuditService.log() → Async write to pjctrl_audit_logs
|
||||
↓
|
||||
(if sensitive) → NotificationService → Alert admins
|
||||
```
|
||||
|
||||
## Data Model
|
||||
|
||||
### pjctrl_audit_logs
|
||||
|
||||
```sql
|
||||
CREATE TABLE pjctrl_audit_logs (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
event_type VARCHAR(50) NOT NULL,
|
||||
resource_type VARCHAR(50) NOT NULL,
|
||||
resource_id VARCHAR(36),
|
||||
user_id VARCHAR(36),
|
||||
action ENUM('create', 'update', 'delete', 'restore', 'login', 'logout') NOT NULL,
|
||||
changes JSON,
|
||||
metadata JSON,
|
||||
sensitivity_level ENUM('low', 'medium', 'high', 'critical') DEFAULT 'low',
|
||||
checksum VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_audit_user (user_id, created_at),
|
||||
INDEX idx_audit_resource (resource_type, resource_id, created_at),
|
||||
INDEX idx_audit_time (created_at),
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES pjctrl_users(id) ON DELETE SET NULL
|
||||
);
|
||||
```
|
||||
|
||||
### pjctrl_audit_alerts
|
||||
|
||||
```sql
|
||||
CREATE TABLE pjctrl_audit_alerts (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
audit_log_id VARCHAR(36) NOT NULL,
|
||||
alert_type VARCHAR(50) NOT NULL,
|
||||
recipients JSON NOT NULL,
|
||||
message TEXT,
|
||||
is_acknowledged BOOLEAN DEFAULT FALSE,
|
||||
acknowledged_by VARCHAR(36),
|
||||
acknowledged_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
FOREIGN KEY (audit_log_id) REFERENCES pjctrl_audit_logs(id),
|
||||
FOREIGN KEY (acknowledged_by) REFERENCES pjctrl_users(id)
|
||||
);
|
||||
```
|
||||
|
||||
## Checksum Calculation
|
||||
|
||||
確保日誌不可竄改:
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
def calculate_checksum(log: AuditLog) -> str:
|
||||
content = f"{log.event_type}|{log.resource_id}|{log.user_id}|{json.dumps(log.changes, sort_keys=True)}|{log.created_at.isoformat()}"
|
||||
return hashlib.sha256(content.encode()).hexdigest()
|
||||
```
|
||||
|
||||
## Sensitivity Levels & Event Types
|
||||
|
||||
| Event Type | Sensitivity | Alert |
|
||||
|-----------|-------------|-------|
|
||||
| task.create, task.update, task.assign | low | No |
|
||||
| task.delete, task.blocker | medium | No |
|
||||
| project.create, project.update | medium | No |
|
||||
| project.delete | high | Yes |
|
||||
| user.permission_change | critical | Yes |
|
||||
| user.login (異常) | high | Yes |
|
||||
|
||||
## API Design
|
||||
|
||||
### Query Audit Logs
|
||||
|
||||
```
|
||||
GET /api/audit-logs
|
||||
Query params:
|
||||
- start_date: datetime
|
||||
- end_date: datetime
|
||||
- user_id: UUID (optional)
|
||||
- resource_type: string (optional)
|
||||
- resource_id: UUID (optional)
|
||||
- sensitivity_level: string (optional)
|
||||
- limit: int (default 50, max 100)
|
||||
- offset: int
|
||||
```
|
||||
|
||||
### Resource History
|
||||
|
||||
```
|
||||
GET /api/audit-logs/resource/{resource_type}/{resource_id}
|
||||
Returns: Change history for specific resource
|
||||
```
|
||||
|
||||
### Export
|
||||
|
||||
```
|
||||
GET /api/audit-logs/export
|
||||
Query params: same as query + format=csv
|
||||
Returns: CSV file download
|
||||
```
|
||||
|
||||
### Integrity Check
|
||||
|
||||
```
|
||||
POST /api/audit-logs/verify-integrity
|
||||
Body: { start_date, end_date }
|
||||
Returns: { total_checked, valid_count, invalid_records: [] }
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
1. **Task API**: Log create/update/delete/assign
|
||||
2. **Project API**: Log create/update/delete
|
||||
3. **User API**: Log permission changes
|
||||
4. **Auth Middleware**: Log login/logout
|
||||
5. **Blocker API**: Log blocker events
|
||||
|
||||
## Alert Thresholds
|
||||
|
||||
- **Bulk delete**: > 5 deletes within 5 minutes
|
||||
- **Off-hours login**: Outside 06:00-22:00 local time
|
||||
- **Permission escalation**: Any admin role assignment
|
||||
@@ -0,0 +1,40 @@
|
||||
# Proposal: add-audit-trail
|
||||
|
||||
## Why
|
||||
|
||||
半導體產業對資料追溯有嚴格的合規需求。目前系統缺乏統一的稽核日誌機制,無法追蹤:
|
||||
- 誰在何時修改了什麼資料
|
||||
- 關鍵操作(如權限變更、資料刪除)的完整記錄
|
||||
- 異常行為的即時警示
|
||||
|
||||
此變更建立系統級稽核追蹤功能,為未來 document-management 模組提供基礎。
|
||||
|
||||
## What Changes
|
||||
|
||||
### Backend
|
||||
- 新增 AuditLog、AuditAlert models
|
||||
- 新增 AuditService (中間件自動記錄)
|
||||
- 新增 `/api/audit-logs` 查詢 API
|
||||
- 新增稽核報告匯出功能 (CSV)
|
||||
- 整合 NotificationService 發送敏感操作警示
|
||||
|
||||
### Frontend
|
||||
- 新增稽核日誌查詢頁面 (Admin only)
|
||||
- 新增資源變更歷史元件 (Task/Project 詳情頁)
|
||||
|
||||
### Database
|
||||
- 新增 `pjctrl_audit_logs` 表 (append-only)
|
||||
- 新增 `pjctrl_audit_alerts` 表
|
||||
|
||||
## Impact
|
||||
|
||||
- **依賴**: 使用現有 NotificationService 發送警示
|
||||
- **被依賴**: document-management 將使用此稽核功能
|
||||
- **權限**: 稽核查詢限 system_admin
|
||||
- **效能**: 使用非同步寫入避免影響主流程
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 時間序列資料庫(先用 MySQL,未來可擴展)
|
||||
- PDF 匯出(先實作 CSV)
|
||||
- 資料庫觸發器(使用應用層中間件)
|
||||
@@ -0,0 +1,94 @@
|
||||
## ADDED 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** 包含 SHA-256 校驗碼確保完整性
|
||||
|
||||
#### 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 格式
|
||||
- **THEN** 系統生成報告檔案供下載
|
||||
|
||||
### Requirement: Sensitive Operation Alerts
|
||||
系統 SHALL 對高敏感度操作發送即時警示。
|
||||
|
||||
#### Scenario: 權限提升警示
|
||||
- **GIVEN** 使用者被授予管理員權限
|
||||
- **WHEN** 權限變更生效
|
||||
- **THEN** 系統發送警示給安全管理員
|
||||
- **AND** 建立 AuditAlert 記錄
|
||||
|
||||
#### Scenario: 大量刪除警示
|
||||
- **GIVEN** 使用者在 5 分鐘內刪除超過 5 筆資料
|
||||
- **WHEN** 偵測到異常刪除模式
|
||||
- **THEN** 系統發送警示給安全管理員
|
||||
|
||||
#### Scenario: 警示確認
|
||||
- **GIVEN** 管理員收到敏感操作警示
|
||||
- **WHEN** 管理員確認警示
|
||||
- **THEN** 系統記錄確認者與確認時間
|
||||
84
openspec/changes/archive/2025-12-29-add-audit-trail/tasks.md
Normal file
84
openspec/changes/archive/2025-12-29-add-audit-trail/tasks.md
Normal file
@@ -0,0 +1,84 @@
|
||||
## 1. Database Schema
|
||||
|
||||
- [x] 1.1 建立 AuditLog model (`pjctrl_audit_logs`)
|
||||
- [x] 1.2 建立 AuditAlert model (`pjctrl_audit_alerts`)
|
||||
- [x] 1.3 建立 Alembic migration
|
||||
- [x] 1.4 建立 event types 和 sensitivity levels 常數
|
||||
|
||||
## 2. Core Audit Service
|
||||
|
||||
- [x] 2.1 建立 AuditService 核心類別
|
||||
- [x] 2.2 實作 checksum 計算邏輯
|
||||
- [x] 2.3 實作 log_event() 方法 (非同步)
|
||||
- [x] 2.4 實作 detect_changes() 方法 (比較 old/new values)
|
||||
- [x] 2.5 實作敏感度判定邏輯
|
||||
|
||||
## 3. Audit Middleware
|
||||
|
||||
- [x] 3.1 建立 AuditMiddleware 擷取 request metadata (IP, user_agent)
|
||||
- [x] 3.2 將 metadata 注入 request state
|
||||
|
||||
## 4. API Integration - Task
|
||||
|
||||
- [x] 4.1 整合 Task create 稽核
|
||||
- [x] 4.2 整合 Task update 稽核 (含 changes diff)
|
||||
- [x] 4.3 整合 Task delete 稽核
|
||||
- [x] 4.4 整合 Task assign 稽核
|
||||
|
||||
## 5. API Integration - Project
|
||||
|
||||
- [x] 5.1 整合 Project create 稽核
|
||||
- [x] 5.2 整合 Project update 稽核
|
||||
- [x] 5.3 整合 Project delete 稽核
|
||||
|
||||
## 6. API Integration - User & Auth
|
||||
|
||||
- [x] 6.1 整合 User permission change 稽核
|
||||
- [x] 6.2 整合 Login/Logout 稽核
|
||||
- [x] 6.3 整合 Blocker 事件稽核
|
||||
|
||||
## 7. Backend API - Query
|
||||
|
||||
- [x] 7.1 建立 AuditLog schemas (response)
|
||||
- [x] 7.2 實作 GET `/api/audit-logs` - 查詢稽核日誌
|
||||
- [x] 7.3 實作 GET `/api/audit-logs/resource/{type}/{id}` - 資源歷史
|
||||
- [x] 7.4 實作 query filters (時間、使用者、資源、敏感度)
|
||||
|
||||
## 8. Backend API - Export & Verify
|
||||
|
||||
- [x] 8.1 實作 GET `/api/audit-logs/export` - CSV 匯出
|
||||
- [x] 8.2 實作 POST `/api/audit-logs/verify-integrity` - 完整性驗證
|
||||
- [x] 8.3 實作分頁處理大量資料
|
||||
|
||||
## 9. Alert System
|
||||
|
||||
- [x] 9.1 建立 AuditAlert schemas
|
||||
- [x] 9.2 實作 create_alert() 方法
|
||||
- [x] 9.3 實作敏感操作警示觸發
|
||||
- [x] 9.4 實作大量刪除偵測
|
||||
- [x] 9.5 整合 NotificationService 發送警示
|
||||
- [x] 9.6 實作 PUT `/api/audit-alerts/{id}/acknowledge` - 確認警示
|
||||
|
||||
## 10. Frontend - Admin Audit Page
|
||||
|
||||
- [x] 10.1 建立 audit.ts service
|
||||
- [x] 10.2 建立 AuditLogList 元件
|
||||
- [x] 10.3 建立 AuditLogFilters 元件 (日期、使用者、資源)
|
||||
- [x] 10.4 建立 AuditLogDetail modal (顯示 changes diff)
|
||||
- [x] 10.5 建立 CSV 匯出按鈕
|
||||
- [x] 10.6 新增 Admin menu 連結
|
||||
|
||||
## 11. Frontend - Resource History
|
||||
|
||||
- [x] 11.1 建立 ResourceHistory 元件
|
||||
- [x] 11.2 整合至 Task 詳情頁
|
||||
- [x] 11.3 整合至 Project 詳情頁
|
||||
|
||||
## 12. Testing
|
||||
|
||||
- [x] 12.1 AuditService 單元測試
|
||||
- [x] 12.2 Checksum 計算測試
|
||||
- [x] 12.3 Audit API 端點測試
|
||||
- [x] 12.4 Alert 觸發測試
|
||||
- [x] 12.5 CSV 匯出測試
|
||||
- [x] 12.6 完整性驗證測試
|
||||
Reference in New Issue
Block a user