ADR 編號修正: - ADR-023 failure-auto-repair → ADR-028 - ADR-025 cicd-ai-integration → ADR-029 新增 ADR: - ADR-021: Playbook 更新驗證 - ADR-022: Sentry 整合架構 - ADR-027: Incident-Approval 同步 - ADR-028: 失敗自動修復閉環 - ADR-029: CI/CD AI 整合 (原 ADR-025) 更新: - ADR-018: LLM 測試策略狀態更新 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2.1 KiB
2.1 KiB
ADR-021: Playbook 更新驗證策略
| 屬性 | 值 |
|---|---|
| 狀態 | Accepted |
| 建立日期 | 2026-03-26 |
| 決策者 | 首席架構師 |
| 關聯 | Phase 8 P1 修復, leWOOOgo 積木化原則 |
背景
Router 層 (playbooks.py) 使用 setattr() 動態更新 Playbook 欄位,繞過 Pydantic 驗證:
# ❌ 問題代碼 (Router 層)
update_data = request.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(playbook, field, value) # 無驗證!
問題:
- 資料完整性 - 非法狀態值可直接寫入
- 違反分層 - Router 層執行業務邏輯
- 安全風險 - 可修改
playbook_id,success_count等欄位
決策
將更新邏輯移至 Service 層,實作 update_with_validation() 方法。
驗證規則
| 規則 | 說明 |
|---|---|
| 禁止修改欄位 | playbook_id, created_at, success_count, failure_count, last_used_at |
| 狀態轉換 | DRAFT → APPROVED (允許), APPROVED → DEPRECATED (允許), 反向 (禁止) |
| DEPRECATED 狀態 | 不可修改任何欄位 |
實作
# ✅ Service 層 (playbook_service.py)
async def update_with_validation(
self,
playbook_id: str,
update_data: dict,
) -> Playbook | None:
# 1. 過濾禁止修改的欄位
# 2. 驗證狀態轉換
# 3. 應用更新
# 4. 儲存
# ✅ Router 層 (playbooks.py)
updated = await service.update_with_validation(
playbook_id=playbook_id,
update_data=request.model_dump(exclude_unset=True),
)
影響
| 檔案 | 變更 |
|---|---|
src/services/playbook_service.py |
新增 update_with_validation() |
src/api/v1/playbooks.py |
改用 Service 方法 |
替代方案
| 方案 | 優點 | 缺點 | 決定 |
|---|---|---|---|
| 維持現狀 (setattr) | 無需改動 | 繞過驗證 | ❌ |
| Pydantic validator | 自動驗證 | 無法檢查狀態轉換 | ❌ |
| Service 層驗證 | 完整控制 | 需新增方法 | ✅ |
相關
- ADR-003: leWOOOgo 積木化架構
- Skill 02: leWOOOgo Backend Core