feat: implement audit trail alignment (soft delete & permission audit)
- Task Soft Delete:
- Add is_deleted, deleted_at, deleted_by fields to Task model
- Convert DELETE to soft delete with cascade to subtasks
- Add include_deleted query param (admin only)
- Add POST /api/tasks/{id}/restore endpoint
- Exclude deleted tasks from subtask_count
- Permission Change Audit:
- Add user.role_change event (high sensitivity)
- Add user.admin_change event (critical, triggers alert)
- Add PATCH /api/users/{id}/admin endpoint
- Add role.permission_change event type
- Append-Only Enforcement:
- Add DB triggers for audit_logs immutability (manual for production)
- Migration 008 with graceful trigger failure handling
- Tests: 11 new soft delete tests (153 total passing)
- OpenSpec: fix-audit-trail archived, fix-realtime-notifications & fix-weekly-report proposals added
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
107
openspec/changes/archive/2025-12-29-fix-audit-trail/design.md
Normal file
107
openspec/changes/archive/2025-12-29-fix-audit-trail/design.md
Normal file
@@ -0,0 +1,107 @@
|
||||
## Context
|
||||
|
||||
audit-trail spec 定義了軟刪除、權限變更記錄、append-only 日誌等需求,但現行實作未完全對齊。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 任務刪除改為軟刪除,保留資料可追溯
|
||||
- 所有權限變更記錄至 audit log
|
||||
- 確保 audit_logs 表不可被修改或刪除
|
||||
|
||||
**Non-Goals:**
|
||||
- 不實作任務還原 UI(僅提供 API)
|
||||
- 不變更現有 checksum 計算邏輯
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 軟刪除欄位設計
|
||||
|
||||
**Decision:** 使用 `is_deleted` + `deleted_at` + `deleted_by`
|
||||
|
||||
**Rationale:**
|
||||
- `is_deleted` 簡化查詢過濾
|
||||
- `deleted_at` 提供時間資訊
|
||||
- `deleted_by` 追蹤操作者
|
||||
|
||||
```python
|
||||
is_deleted = Column(Boolean, default=False, nullable=False)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(String(36), ForeignKey("pjctrl_users.id"), nullable=True)
|
||||
```
|
||||
|
||||
### 2. 查詢過濾策略
|
||||
|
||||
**Decision:** API 層過濾,非 ORM 層
|
||||
|
||||
**Rationale:**
|
||||
- 保持彈性,部分查詢需要包含已刪除項目
|
||||
- 避免 ORM 層複雜性
|
||||
|
||||
```python
|
||||
# 預設過濾
|
||||
query = query.filter(Task.is_deleted == False)
|
||||
|
||||
# 管理員可查看已刪除
|
||||
if include_deleted and current_user.is_system_admin:
|
||||
query = query.filter() # 不過濾
|
||||
```
|
||||
|
||||
### 3. Append-Only 實作
|
||||
|
||||
**Decision:** 使用 MySQL/PostgreSQL trigger
|
||||
|
||||
**MySQL:**
|
||||
```sql
|
||||
DELIMITER //
|
||||
CREATE TRIGGER prevent_audit_update BEFORE UPDATE ON pjctrl_audit_logs
|
||||
FOR EACH ROW BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Audit logs are immutable';
|
||||
END//
|
||||
|
||||
CREATE TRIGGER prevent_audit_delete BEFORE DELETE ON pjctrl_audit_logs
|
||||
FOR EACH ROW BEGIN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Audit logs are immutable';
|
||||
END//
|
||||
DELIMITER ;
|
||||
```
|
||||
|
||||
### 4. 權限變更事件
|
||||
|
||||
**Decision:** 記錄以下變更類型
|
||||
|
||||
| 事件 | event_type | sensitivity |
|
||||
|------|------------|-------------|
|
||||
| 角色指派 | user.role_change | high |
|
||||
| 角色權限更新 | role.permission_change | critical |
|
||||
| 系統管理員變更 | user.admin_change | critical |
|
||||
|
||||
## Data Model Changes
|
||||
|
||||
```sql
|
||||
-- Task 表新增欄位
|
||||
ALTER TABLE pjctrl_tasks ADD COLUMN is_deleted BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE pjctrl_tasks ADD COLUMN deleted_at DATETIME NULL;
|
||||
ALTER TABLE pjctrl_tasks ADD COLUMN deleted_by VARCHAR(36) NULL;
|
||||
ALTER TABLE pjctrl_tasks ADD INDEX idx_task_deleted (is_deleted);
|
||||
```
|
||||
|
||||
## API Changes
|
||||
|
||||
```
|
||||
# 現有 API 行為變更
|
||||
DELETE /api/tasks/{id} -> 軟刪除,回傳 200 而非 204
|
||||
GET /api/projects/{id}/tasks -> 預設排除 is_deleted=true
|
||||
|
||||
# 新增 API
|
||||
POST /api/tasks/{id}/restore -> 還原已刪除任務(需權限)
|
||||
GET /api/projects/{id}/tasks?include_deleted=true -> 管理員可查看全部
|
||||
```
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 軟刪除增加資料量 | 定期歸檔/清理策略 |
|
||||
| DB trigger 影響效能 | trigger 邏輯簡單,影響極小 |
|
||||
| 權限變更頻繁觸發 | 僅記錄實際變更 |
|
||||
Reference in New Issue
Block a user