feat: implement automation module
- Event-based triggers (Phase 1): - Trigger/TriggerLog models with field_change type - TriggerService for condition evaluation and action execution - Trigger CRUD API endpoints - Task integration (status, assignee, priority changes) - Frontend: TriggerList, TriggerForm components - Weekly reports (Phase 2): - ScheduledReport/ReportHistory models - ReportService for stats generation - APScheduler for Friday 16:00 job - Report preview/generate/history API - Frontend: WeeklyReportPreview, ReportHistory components - Tests: 23 new tests (14 triggers + 9 reports) - OpenSpec: add-automation 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:
185
openspec/changes/archive/2025-12-29-add-automation/design.md
Normal file
185
openspec/changes/archive/2025-12-29-add-automation/design.md
Normal file
@@ -0,0 +1,185 @@
|
||||
## Context
|
||||
|
||||
自動化系統需要處理兩種類型的自動化:
|
||||
1. 事件驅動 - 任務欄位變更時觸發
|
||||
2. 時間驅動 - 排程執行(如週報)
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 提供欄位變更觸發器(status, assignee, priority)
|
||||
- 實作每週五 16:00 自動週報
|
||||
- 整合現有通知系統
|
||||
- 記錄所有觸發器執行日誌
|
||||
|
||||
**Non-Goals:**
|
||||
- 複雜的工作流引擎
|
||||
- 跨任務觸發器
|
||||
- Email 發送(僅系統內通知)
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 排程方案
|
||||
|
||||
**Decision:** 使用 APScheduler 而非 Celery
|
||||
|
||||
**Rationale:**
|
||||
- 無需額外 worker 進程,減少部署複雜度
|
||||
- 嵌入 FastAPI 應用內運行
|
||||
- 足夠處理週報等簡單定時任務
|
||||
- 未來如需擴展可遷移至 Celery
|
||||
|
||||
**Configuration:**
|
||||
```python
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
scheduler = AsyncIOScheduler()
|
||||
scheduler.add_job(
|
||||
generate_weekly_reports,
|
||||
CronTrigger(day_of_week='fri', hour=16, minute=0),
|
||||
id='weekly_report'
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 觸發器評估策略
|
||||
|
||||
**Decision:** 同步評估,任務更新時直接執行
|
||||
|
||||
**Rationale:**
|
||||
- 簡化實作,無需消息隊列
|
||||
- 觸發器執行速度快(僅發送通知)
|
||||
- 失敗可即時回報
|
||||
|
||||
**Flow:**
|
||||
```
|
||||
Task Update → Detect Changes → Find Matching Triggers → Execute Actions → Log Results
|
||||
```
|
||||
|
||||
### 3. 條件定義格式
|
||||
|
||||
**Decision:** 使用 JSON 結構定義條件
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "status_id",
|
||||
"operator": "equals",
|
||||
"value": "uuid-of-testing-status"
|
||||
}
|
||||
```
|
||||
|
||||
**Supported Operators:**
|
||||
- `equals` - 等於
|
||||
- `not_equals` - 不等於
|
||||
- `changed_to` - 變更為特定值
|
||||
- `changed_from` - 從特定值變更
|
||||
|
||||
### 4. 動作定義格式
|
||||
|
||||
**Decision:** 使用 JSON 陣列定義動作
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "notify",
|
||||
"target": "assignee",
|
||||
"template": "任務 {task.title} 狀態已變更為 {new_value}"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Supported Actions (Phase 1):**
|
||||
- `notify` - 發送系統通知
|
||||
|
||||
**Target Types:**
|
||||
- `assignee` - 任務指派者
|
||||
- `creator` - 任務建立者
|
||||
- `project_owner` - 專案擁有者
|
||||
- `user:<user_id>` - 指定使用者
|
||||
|
||||
## Data Model
|
||||
|
||||
```sql
|
||||
-- 觸發器表
|
||||
pjctrl_triggers
|
||||
├── id: UUID (PK)
|
||||
├── project_id: UUID (FK -> projects)
|
||||
├── name: VARCHAR(200)
|
||||
├── description: TEXT
|
||||
├── trigger_type: ENUM('field_change', 'schedule')
|
||||
├── conditions: JSON
|
||||
├── actions: JSON
|
||||
├── is_active: BOOLEAN DEFAULT true
|
||||
├── created_by: UUID (FK -> users)
|
||||
├── created_at: TIMESTAMP
|
||||
└── updated_at: TIMESTAMP
|
||||
|
||||
-- 觸發器執行日誌
|
||||
pjctrl_trigger_logs
|
||||
├── id: UUID (PK)
|
||||
├── trigger_id: UUID (FK -> triggers)
|
||||
├── task_id: UUID (FK -> tasks, nullable)
|
||||
├── executed_at: TIMESTAMP
|
||||
├── status: ENUM('success', 'failed')
|
||||
├── details: JSON
|
||||
└── error_message: TEXT
|
||||
|
||||
-- 排程報告設定
|
||||
pjctrl_scheduled_reports
|
||||
├── id: UUID (PK)
|
||||
├── report_type: ENUM('weekly')
|
||||
├── recipient_id: UUID (FK -> users)
|
||||
├── is_active: BOOLEAN DEFAULT true
|
||||
├── last_sent_at: TIMESTAMP
|
||||
└── created_at: TIMESTAMP
|
||||
|
||||
-- 報告歷史
|
||||
pjctrl_report_history
|
||||
├── id: UUID (PK)
|
||||
├── report_id: UUID (FK -> scheduled_reports)
|
||||
├── generated_at: TIMESTAMP
|
||||
├── content: JSON
|
||||
├── status: ENUM('sent', 'failed')
|
||||
└── error_message: TEXT
|
||||
```
|
||||
|
||||
## API Design
|
||||
|
||||
```
|
||||
# Triggers
|
||||
POST /api/projects/{project_id}/triggers # 建立觸發器
|
||||
GET /api/projects/{project_id}/triggers # 列出專案觸發器
|
||||
GET /api/triggers/{id} # 觸發器詳情
|
||||
PUT /api/triggers/{id} # 更新觸發器
|
||||
DELETE /api/triggers/{id} # 刪除觸發器
|
||||
GET /api/triggers/{id}/logs # 觸發器執行日誌
|
||||
|
||||
# Reports
|
||||
GET /api/reports/weekly/preview # 預覽週報
|
||||
POST /api/reports/weekly/generate # 手動觸發週報
|
||||
GET /api/reports/history # 報告歷史
|
||||
```
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| 大量觸發器影響效能 | 限制每專案觸發器數量,建立索引 |
|
||||
| APScheduler 單點故障 | 記錄 last_sent_at 防止重複,考慮多實例鎖 |
|
||||
| 觸發器條件複雜度 | Phase 1 僅支援簡單條件,後續擴展 |
|
||||
|
||||
## Integration Points
|
||||
|
||||
1. **Task Update Hook**
|
||||
- 在 `tasks/router.py` 的 update_task 後調用 TriggerService.evaluate()
|
||||
|
||||
2. **Notification Integration**
|
||||
- 使用現有 NotificationService.create_notification()
|
||||
|
||||
3. **Audit Integration**
|
||||
- 觸發器執行記錄至 TriggerLog(非 AuditLog)
|
||||
|
||||
## Open Questions
|
||||
|
||||
- [ ] 是否需要支援 Email 發送?(目前僅系統內通知)
|
||||
- [ ] 週報收件者如何設定?(主管自動訂閱 or 手動設定)
|
||||
@@ -0,0 +1,52 @@
|
||||
# Change: Add Automation System
|
||||
|
||||
## Why
|
||||
專案管理需要自動化功能來減少重複性工作:
|
||||
- 當任務狀態變更時自動通知相關人員
|
||||
- 每週自動生成進度報告發送給主管
|
||||
- 減少人工追蹤與提醒的負擔
|
||||
|
||||
## What Changes
|
||||
- **新增 Trigger 模型** - 定義觸發條件與動作
|
||||
- **新增 TriggerService** - 觸發器評估與執行
|
||||
- **新增 ReportService** - 週報生成邏輯
|
||||
- **新增背景排程** - APScheduler 處理定時任務
|
||||
- **整合任務 API** - 任務變更時評估觸發器
|
||||
|
||||
## Impact
|
||||
- Affected specs: `automation`
|
||||
- Affected code:
|
||||
- `backend/app/models/` - 新增 trigger, scheduled_report 模型
|
||||
- `backend/app/api/` - 新增 triggers, reports router
|
||||
- `backend/app/services/` - 新增 trigger_service, report_service
|
||||
- `backend/app/api/tasks/router.py` - 整合觸發器評估
|
||||
- `frontend/src/` - 新增觸發器管理頁面
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Event-Based Triggers
|
||||
- Trigger 模型與 CRUD API
|
||||
- 欄位變更觸發器(status, assignee, priority)
|
||||
- 通知動作執行
|
||||
- 整合任務更新流程
|
||||
|
||||
### Phase 2: Weekly Reports
|
||||
- ScheduledReport 模型
|
||||
- 週報生成邏輯(彙整任務統計)
|
||||
- APScheduler 背景排程
|
||||
- 系統內通知發送
|
||||
|
||||
### Phase 3: Advanced Features (Optional)
|
||||
- 時間條件觸發器
|
||||
- 複合條件支援
|
||||
- 更新欄位動作
|
||||
- 自動指派動作
|
||||
|
||||
## Dependencies
|
||||
- notification (已完成) - 用於發送觸發通知
|
||||
- audit-trail (已完成) - 記錄觸發器執行日誌
|
||||
|
||||
## Technical Decisions
|
||||
- **使用 APScheduler** 而非 Celery - 輕量級,無需額外 worker 進程
|
||||
- **同步觸發器評估** - 任務更新時同步執行,避免複雜的異步處理
|
||||
- **JSON 欄位儲存條件** - 靈活的條件定義格式
|
||||
@@ -0,0 +1,105 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Trigger-Based Automation
|
||||
系統 SHALL 支援觸發器 (Triggers),當特定條件滿足時自動執行動作。
|
||||
|
||||
#### Scenario: 狀態變更觸發通知
|
||||
- **GIVEN** 專案設定了「當任務狀態變更為待測試時,通知指派者」的觸發器
|
||||
- **WHEN** 任務狀態變更為「待測試」
|
||||
- **THEN** 系統自動發送通知給任務指派者
|
||||
- **AND** 觸發器執行記錄至 TriggerLog
|
||||
|
||||
#### Scenario: 建立觸發器
|
||||
- **GIVEN** 專案管理者需要建立自動化規則
|
||||
- **WHEN** 管理者透過 API 設定觸發條件與動作
|
||||
- **THEN** 系統儲存觸發器規則
|
||||
- **AND** 規則立即生效
|
||||
|
||||
### Requirement: Trigger Conditions
|
||||
系統 SHALL 支援欄位變更觸發條件。
|
||||
|
||||
#### Scenario: 欄位變更條件
|
||||
- **GIVEN** 觸發器設定為「當 status_id 欄位變更為特定值」
|
||||
- **WHEN** 任務的 status_id 欄位變更為該值
|
||||
- **THEN** 觸發器被觸發
|
||||
- **AND** 支援運算子: equals, not_equals, changed_to, changed_from
|
||||
|
||||
### Requirement: Trigger Actions
|
||||
系統 SHALL 支援發送通知動作。
|
||||
|
||||
#### Scenario: 發送通知動作
|
||||
- **GIVEN** 觸發器動作設定為 notify
|
||||
- **WHEN** 觸發器被觸發
|
||||
- **THEN** 系統使用 NotificationService 發送通知
|
||||
- **AND** 通知目標支援: assignee, creator, project_owner, user:<id>
|
||||
- **AND** 通知內容可使用變數模板
|
||||
|
||||
### Requirement: Automated Weekly Report
|
||||
系統 SHALL 每週五下午 4:00 自動彙整本週任務狀態發送給主管。
|
||||
|
||||
#### Scenario: 週報自動生成
|
||||
- **GIVEN** APScheduler 排程設定為每週五 16:00
|
||||
- **WHEN** 到達排程時間
|
||||
- **THEN** ReportService 彙整使用者所屬專案的任務狀態
|
||||
- **AND** 生成週報並透過 NotificationService 發送
|
||||
|
||||
#### Scenario: 週報內容
|
||||
- **GIVEN** 週報生成中
|
||||
- **WHEN** 系統彙整資料
|
||||
- **THEN** 週報 JSON 包含:
|
||||
- completed_count: 本週已完成任務數
|
||||
- in_progress_count: 進行中任務數
|
||||
- overdue_count: 逾期任務數
|
||||
- tasks: 詳細任務清單
|
||||
|
||||
## MODIFIED Data Model
|
||||
|
||||
```
|
||||
pjctrl_triggers
|
||||
├── id: UUID (PK)
|
||||
├── project_id: UUID (FK -> projects)
|
||||
├── name: VARCHAR(200)
|
||||
├── description: TEXT
|
||||
├── trigger_type: ENUM('field_change', 'schedule')
|
||||
├── conditions: JSON
|
||||
│ └── { "field": "status_id", "operator": "changed_to", "value": "uuid" }
|
||||
├── actions: JSON
|
||||
│ └── [{ "type": "notify", "target": "assignee", "template": "..." }]
|
||||
├── is_active: BOOLEAN DEFAULT true
|
||||
├── created_by: UUID (FK -> users)
|
||||
├── created_at: TIMESTAMP
|
||||
└── updated_at: TIMESTAMP
|
||||
|
||||
pjctrl_trigger_logs
|
||||
├── id: UUID (PK)
|
||||
├── trigger_id: UUID (FK -> triggers)
|
||||
├── task_id: UUID (FK -> tasks, nullable)
|
||||
├── executed_at: TIMESTAMP
|
||||
├── status: ENUM('success', 'failed')
|
||||
├── details: JSON
|
||||
└── error_message: TEXT
|
||||
|
||||
pjctrl_scheduled_reports
|
||||
├── id: UUID (PK)
|
||||
├── report_type: ENUM('weekly')
|
||||
├── recipient_id: UUID (FK -> users)
|
||||
├── is_active: BOOLEAN DEFAULT true
|
||||
├── last_sent_at: TIMESTAMP
|
||||
└── created_at: TIMESTAMP
|
||||
|
||||
pjctrl_report_history
|
||||
├── id: UUID (PK)
|
||||
├── report_id: UUID (FK -> scheduled_reports)
|
||||
├── generated_at: TIMESTAMP
|
||||
├── content: JSON
|
||||
├── status: ENUM('sent', 'failed')
|
||||
└── error_message: TEXT
|
||||
```
|
||||
|
||||
## MODIFIED Technical Notes
|
||||
|
||||
- 使用 APScheduler (AsyncIOScheduler) 處理排程任務,嵌入 FastAPI 應用內運行
|
||||
- 觸發器評估採用同步處理,任務更新時直接執行,避免複雜的異步處理
|
||||
- 所有觸發器執行都記錄至 TriggerLog 供追蹤
|
||||
- Phase 1 僅支援 notify 動作
|
||||
- 條件運算子: equals, not_equals, changed_to, changed_from
|
||||
90
openspec/changes/archive/2025-12-29-add-automation/tasks.md
Normal file
90
openspec/changes/archive/2025-12-29-add-automation/tasks.md
Normal file
@@ -0,0 +1,90 @@
|
||||
## Phase 1: Event-Based Triggers
|
||||
|
||||
### 1.1 Database Schema
|
||||
- [x] 1.1.1 建立 Trigger model (`pjctrl_triggers`)
|
||||
- [x] 1.1.2 建立 TriggerLog model (`pjctrl_trigger_logs`)
|
||||
- [x] 1.1.3 建立 Alembic migration
|
||||
- [x] 1.1.4 定義 TriggerType enum (field_change, schedule)
|
||||
|
||||
### 1.2 Trigger Service
|
||||
- [x] 1.2.1 建立 TriggerService 類別
|
||||
- [x] 1.2.2 實作 evaluate_triggers(task, old_values, new_values) 方法
|
||||
- [x] 1.2.3 實作 check_condition(condition, old_value, new_value) 方法
|
||||
- [x] 1.2.4 實作 execute_action(action, task, user) 方法
|
||||
- [x] 1.2.5 實作 log_execution(trigger, task, status, error) 方法
|
||||
|
||||
### 1.3 Trigger API
|
||||
- [x] 1.3.1 建立 Trigger schemas (request/response)
|
||||
- [x] 1.3.2 實作 POST `/api/projects/{project_id}/triggers` - 建立
|
||||
- [x] 1.3.3 實作 GET `/api/projects/{project_id}/triggers` - 列表
|
||||
- [x] 1.3.4 實作 GET `/api/triggers/{id}` - 詳情
|
||||
- [x] 1.3.5 實作 PUT `/api/triggers/{id}` - 更新
|
||||
- [x] 1.3.6 實作 DELETE `/api/triggers/{id}` - 刪除
|
||||
- [x] 1.3.7 實作 GET `/api/triggers/{id}/logs` - 執行日誌
|
||||
|
||||
### 1.4 Task Integration
|
||||
- [x] 1.4.1 修改 update_task endpoint 整合觸發器評估
|
||||
- [x] 1.4.2 修改 update_task_status endpoint 整合觸發器評估
|
||||
- [x] 1.4.3 修改 assign_task endpoint 整合觸發器評估
|
||||
|
||||
### 1.5 Frontend - Triggers
|
||||
- [x] 1.5.1 建立 triggers.ts service
|
||||
- [x] 1.5.2 建立 TriggerList 元件
|
||||
- [x] 1.5.3 建立 TriggerForm 元件(條件/動作設定)
|
||||
- [x] 1.5.4 整合至 Project 設定頁面
|
||||
|
||||
### 1.6 Testing - Phase 1
|
||||
- [x] 1.6.1 TriggerService 單元測試
|
||||
- [x] 1.6.2 Trigger API 端點測試
|
||||
- [x] 1.6.3 觸發器執行整合測試
|
||||
|
||||
## Phase 2: Weekly Reports
|
||||
|
||||
### 2.1 Database Schema
|
||||
- [x] 2.1.1 建立 ScheduledReport model (`pjctrl_scheduled_reports`)
|
||||
- [x] 2.1.2 建立 ReportHistory model (`pjctrl_report_history`)
|
||||
- [x] 2.1.3 建立 Alembic migration
|
||||
|
||||
### 2.2 Report Service
|
||||
- [x] 2.2.1 建立 ReportService 類別
|
||||
- [x] 2.2.2 實作 generate_weekly_report(user_id) 方法
|
||||
- [x] 2.2.3 實作 get_weekly_stats(user_id, week_start) 方法
|
||||
- [x] 2.2.4 實作 send_report_notification(user_id, report) 方法
|
||||
- [x] 2.2.5 實作 save_report_history(report) 方法
|
||||
|
||||
### 2.3 Scheduler Setup
|
||||
- [x] 2.3.1 安裝 APScheduler
|
||||
- [x] 2.3.2 建立 scheduler.py 設定檔
|
||||
- [x] 2.3.3 設定週五 16:00 排程任務
|
||||
- [x] 2.3.4 整合至 main.py 啟動流程
|
||||
|
||||
### 2.4 Report API
|
||||
- [x] 2.4.1 建立 Report schemas
|
||||
- [x] 2.4.2 實作 GET `/api/reports/weekly/preview` - 預覽
|
||||
- [x] 2.4.3 實作 POST `/api/reports/weekly/generate` - 手動觸發
|
||||
- [x] 2.4.4 實作 GET `/api/reports/history` - 歷史紀錄
|
||||
|
||||
### 2.5 Frontend - Reports
|
||||
- [x] 2.5.1 建立 reports.ts service
|
||||
- [x] 2.5.2 建立 WeeklyReportPreview 元件
|
||||
- [x] 2.5.3 建立 ReportHistory 元件
|
||||
- [x] 2.5.4 新增管理員報告頁面
|
||||
|
||||
### 2.6 Testing - Phase 2
|
||||
- [x] 2.6.1 ReportService 單元測試
|
||||
- [x] 2.6.2 週報生成測試
|
||||
- [x] 2.6.3 排程執行測試
|
||||
|
||||
## Phase 3: Advanced Features (Optional)
|
||||
|
||||
### 3.1 Schedule Triggers
|
||||
- [ ] 3.1.1 支援 cron 表達式觸發器
|
||||
- [ ] 3.1.2 截止日期提醒觸發器
|
||||
|
||||
### 3.2 Additional Actions
|
||||
- [ ] 3.2.1 更新欄位動作
|
||||
- [ ] 3.2.2 自動指派動作
|
||||
|
||||
### 3.3 Complex Conditions
|
||||
- [ ] 3.3.1 AND/OR 複合條件
|
||||
- [ ] 3.3.2 多欄位條件
|
||||
Reference in New Issue
Block a user