Files
awoooi/docs/adr/ADR-050-telegram-interactive-incident-v2.md
OG T c9c60c3a61
Some checks failed
E2E Health Check / e2e-health (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
Type Sync Check / check-type-sync (push) Failing after 22s
feat(mcp-integrations): Phase S 架構修復 + MCP 整合基礎建設
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>
2026-04-01 16:20:57 +08:00

177 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 的處置結果
這增加了認知負擔,也拖慢了 MTTRMean 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 結構
```python
# 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/callback` endpoint`src/routers/telegram_callback.py`
- [ ] 建立 `TelegramCallbackService` 骨架(含 action dispatch
- [ ] 更新 `telegram_notification_service.py` 的 Inline Keyboard 結構
- [ ] Webhook 設定確認Bot API setWebhook 指向新 endpoint
**交付條件**:點擊新按鈕不報錯,回傳「功能開發中」佔位訊息
### P2詳情查詢 + 重診觸發Sprint 2
- [ ] `detail` action呼叫 `IncidentRepository.get_by_id()`,格式化後 `edit_message`
- [ ] `reanalyze` action呼叫 `IncidentService.trigger_reanalysis()`,回傳「重診已排程」
- [ ] 防止重複觸發:重診進行中時,按鈕顯示「⏳ 診斷中」並 disable
### P3歷史對比分析Sprint 3
- [ ] `history` action`IncidentRepository.find_similar(incident_id, top_k=5)`
- [ ] 相似度演算法:基於 type + host + time_window 的向量搜尋(若已啟用 pgvector
- [ ] 格式化歷史表格,含處置結果與信心分數
## 技術約束
1. **leWOOOgo 積木化**`TelegramCallbackService` 必須透過 `IncidentRepository` interface 存取資料,禁止 Router 層直接查 DB 或 Redis
2. **edit_message 限制**Telegram Bot API 限制 edit_message 只能在 48 小時內有效,超時需降級為發送新訊息
3. **Callback Query 答覆**:所有 callback_query 必須在 5 秒內呼叫 `answerCallbackQuery()`,否則 Telegram 顯示 loading 轉圈
4. **去重保護**:同一 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一次性操作 |
## 相關文件
- [ADR-035-telegram-alert-chain-enforcement.md](ADR-035-telegram-alert-chain-enforcement.md)
- [ADR-045-telegram-gateway-consolidation.md](ADR-045-telegram-gateway-consolidation.md)
- [feedback_telegram_dedup.md](~/.claude/projects/-Users-ogt-awoooi/memory/feedback_telegram_dedup.md)
- [feedback_telegram_alert_format.md](~/.claude/projects/-Users-ogt-awoooi/memory/feedback_telegram_alert_format.md)
- [feedback_lewooogo_modular_enforcement.md](~/.claude/projects/-Users-ogt-awoooi/memory/feedback_lewooogo_modular_enforcement.md)