# 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 結構

```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)
