- 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>
4.7 KiB
4.7 KiB
Context
自動化系統需要處理兩種類型的自動化:
- 事件驅動 - 任務欄位變更時觸發
- 時間驅動 - 排程執行(如週報)
Goals / Non-Goals
Goals:
- 提供欄位變更觸發器(status, assignee, priority)
- 實作每週五 16:00 自動週報
- 整合現有通知系統
- 記錄所有觸發器執行日誌
Non-Goals:
- 複雜的工作流引擎
- 跨任務觸發器
- Email 發送(僅系統內通知)
Decisions
1. 排程方案
Decision: 使用 APScheduler 而非 Celery
Rationale:
- 無需額外 worker 進程,減少部署複雜度
- 嵌入 FastAPI 應用內運行
- 足夠處理週報等簡單定時任務
- 未來如需擴展可遷移至 Celery
Configuration:
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 結構定義條件
{
"field": "status_id",
"operator": "equals",
"value": "uuid-of-testing-status"
}
Supported Operators:
equals- 等於not_equals- 不等於changed_to- 變更為特定值changed_from- 從特定值變更
4. 動作定義格式
Decision: 使用 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
-- 觸發器表
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
-
Task Update Hook
- 在
tasks/router.py的 update_task 後調用 TriggerService.evaluate()
- 在
-
Notification Integration
- 使用現有 NotificationService.create_notification()
-
Audit Integration
- 觸發器執行記錄至 TriggerLog(非 AuditLog)
Open Questions
- 是否需要支援 Email 發送?(目前僅系統內通知)
- 週報收件者如何設定?(主管自動訂閱 or 手動設定)