- 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>
186 lines
4.7 KiB
Markdown
186 lines
4.7 KiB
Markdown
## 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 手動設定)
|