Phase S 技術債修復 (首席架構師審查 82→完整): - S-01: generate_alert_fingerprint 移至 AlertAnalyzer.generate_fingerprint() staticmethod - S-04: 移除 Pydantic v2 deprecated json_encoders (直接用原生 datetime 序列化) Sentry MCP 整合 (Phase 23): - ADR-048: Sentry→OpenClaw AI Triage 架構決策 - sentry_webhook_service.py: parse/analyze/create_incident/build_message Service 層 - config.py: SENTRY_WEBHOOK_SECRET (Fail-Closed HMAC-SHA256) Playwright MCP 整合 (短期): - smoke.spec.ts: 5 頁面 E2E smoke test (home/dashboard/incidents/approvals/terminal) - cd.yaml: E2E Smoke Test 步驟 + Telegram 🎭 Smoke 狀態通知 長期規劃 ADR: - ADR-049: Figma Code Connect 設計系統同步 - ADR-050: Telegram 互動式 Incident 2.0 (6鍵 Inline Keyboard) - ADR-051: Context7 依賴升級顧問 (Next.js 14→15, FastAPI 0.115→0.128) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.4 KiB
6.4 KiB
ADR-050: Telegram 互動式 Incident 管理 2.0
| 項目 | 內容 |
|---|---|
| 狀態 | 📋 已批准,待實作 |
| 日期 | 2026-04-01 |
| 決策者 | 首席架構師 + 統帥 |
| 觸發 | MCP 整合長期計畫 |
背景
目前 AWOOOI Telegram 告警訊息提供三個 Inline Keyboard 按鈕:
[✅ 批准 (Y)] [❌ 拒絕 (n)] [🔕 靜默]
統帥在 Telegram 收到告警時,除了批准/拒絕外,還需要切換到 Web UI 或 CLI 才能:
- 查看 Incident 的完整詳情(metrics、stack trace、診斷結果)
- 重新觸發 OpenClaw 分析(當第一次分析結果可疑時)
- 查詢歷史相似 Incident 的處置結果
這增加了認知負擔,也拖慢了 MTTR(Mean Time To Respond)。
問題
| 操作 | 現況 | 痛點 |
|---|---|---|
| 查看詳情 | 須切換至 Web UI | 手機操作不便,流程中斷 |
| 重新診斷 | 須 CLI 觸發 | 無法在 Telegram 中完成閉環 |
| 歷史對比 | 須查詢資料庫 | 完全手動,耗時 |
決策
擴充 Telegram Inline Keyboard,加入第二行按鈕:
[✅ 批准] [❌ 拒絕] [🔕 靜默]
[📋 詳情] [🔄 重診] [📊 歷史]
在後端新增 TelegramCallbackService,處理新按鈕的回調邏輯,並使用 edit_message 在原訊息中就地更新(不發送新訊息)。
架構
回調處理流程
Telegram Inline Button Click
→ Bot API callback_query
→ AWOOOI API POST /telegram/callback
→ TelegramCallbackRouter (apps/api/src/routers/telegram_callback.py)
→ TelegramCallbackService (apps/api/src/services/telegram_callback_service.py)
→ 根據 action 分派:
"detail" → IncidentRepository.get_by_id()
→ 格式化 Markdown 回傳
"reanalyze" → IncidentService.trigger_reanalysis()
→ OpenClaw 重分析排程
"history" → IncidentRepository.find_similar()
→ 格式化歷史對比表格
→ Telegram Bot API edit_message_text()
→ 原訊息就地更新(保留按鈕,附加展開內容)
Callback Data 格式
{action}:{incident_id}
範例:
detail:INC-2026-0401-001
reanalyze:INC-2026-0401-001
history:INC-2026-0401-001
新 Inline Keyboard 結構
# src/services/telegram_notification_service.py
InlineKeyboardMarkup(inline_keyboard=[
[
InlineKeyboardButton(text="✅ 批准", callback_data=f"approve:{incident_id}"),
InlineKeyboardButton(text="❌ 拒絕", callback_data=f"reject:{incident_id}"),
InlineKeyboardButton(text="🔕 靜默", callback_data=f"silence:{incident_id}"),
],
[
InlineKeyboardButton(text="📋 詳情", callback_data=f"detail:{incident_id}"),
InlineKeyboardButton(text="🔄 重診", callback_data=f"reanalyze:{incident_id}"),
InlineKeyboardButton(text="📊 歷史", callback_data=f"history:{incident_id}"),
],
])
詳情回覆格式
📋 Incident 詳情:INC-2026-0401-001
━━━━━━━━━━━━━━━━━━
🏷 類型:CPU_SPIKE
🖥 主機:k3s-node-1 (192.168.0.125)
⏱ 時間:2026-04-01 14:32 +08
📊 觸發值:CPU 94.3% (閾值 90%)
🤖 OpenClaw 信心:0.87
診斷摘要:
過去 30 分鐘 CPU 呈上升趨勢,
與 incident INC-2026-0318-007 模式相符。
建議:重啟 signal_worker pod。
歷史對比格式
📊 相似 Incident 歷史(近 30 天)
━━━━━━━━━━━━━━━━━━
| 日期 | 類型 | 處置 | 結果 |
|-------|-----------|-------|------|
| 03-18 | CPU_SPIKE | 批准 | ✅ |
| 03-10 | CPU_SPIKE | 批准 | ✅ |
| 02-28 | CPU_SPIKE | 靜默 | ⚠️ |
相似度最高:INC-2026-0318-007 (0.94)
實作計畫
P1:骨架建立(Sprint 1)
- 新增
/telegram/callbackendpoint(src/routers/telegram_callback.py) - 建立
TelegramCallbackService骨架(含 action dispatch) - 更新
telegram_notification_service.py的 Inline Keyboard 結構 - Webhook 設定確認(Bot API setWebhook 指向新 endpoint)
交付條件:點擊新按鈕不報錯,回傳「功能開發中」佔位訊息
P2:詳情查詢 + 重診觸發(Sprint 2)
detailaction:呼叫IncidentRepository.get_by_id(),格式化後edit_messagereanalyzeaction:呼叫IncidentService.trigger_reanalysis(),回傳「重診已排程」- 防止重複觸發:重診進行中時,按鈕顯示「⏳ 診斷中」並 disable
P3:歷史對比分析(Sprint 3)
historyaction:IncidentRepository.find_similar(incident_id, top_k=5)- 相似度演算法:基於 type + host + time_window 的向量搜尋(若已啟用 pgvector)
- 格式化歷史表格,含處置結果與信心分數
技術約束
- leWOOOgo 積木化:
TelegramCallbackService必須透過IncidentRepositoryinterface 存取資料,禁止 Router 層直接查 DB 或 Redis - edit_message 限制:Telegram Bot API 限制 edit_message 只能在 48 小時內有效,超時需降級為發送新訊息
- Callback Query 答覆:所有 callback_query 必須在 5 秒內呼叫
answerCallbackQuery(),否則 Telegram 顯示 loading 轉圈 - 去重保護:同一 Incident 的 reanalyze 在 10 分鐘 TTL 內只觸發一次(參考 feedback_telegram_dedup.md)
安全考量
- Callback data 中的
incident_id需驗證存在且屬於合法狀態 - Callback query 的
from.id需與 allowlist 核對(使用現有 Telegram access 控制) - 禁止在 callback 中執行不可逆操作(如刪除 Incident)
影響
| 面向 | 影響 |
|---|---|
| MTTR | 預計減少 40%(統帥不需切換視窗) |
| API | 新增 1 個 endpoint,無現有 endpoint 變更 |
| DB | 新增 find_similar query,需確認索引 |
| Telegram Bot | 需重新設定 Webhook(一次性操作) |