# Sprint 5 — 指令中心重設計：完整解決方案與細化實施步驟

> **建立**: 2026-04-08 (台北)
> **建立者**: Claude Code
> **狀態**: 📋 待統帥審核
> **技術選型**: ADR-060 React Flow + elkjs (已批准)

---

## 第一章：問題定義

### 1.1 現況問題

| 問題 | 具體描述 |
|------|---------|
| 首頁缺乏全局視角 | 目前首頁只有 Metrics Strip + Incident Feed + OpenClaw Panel，無法一眼看清服務依賴關係 |
| 拓撲圖不存在 | `/topology` 頁面只有簡單的 host list，沒有視覺化依賴圖 |
| 告警缺乏上下文 | 告警卡片不知道「這個服務影響了誰」 |
| AI 介入不透明 | 使用者不知道 OpenClaw 正在分析哪個服務 |
| 監控規模已達 67 實體 | 未來 120-150+，需要分層/聚焦能力 |

### 1.2 目標使用者

| 角色 | 使用場景 | 需要看到什麼 |
|------|---------|-------------|
| **統帥 (CIO)** | 每日巡檢、異常時指揮 | 全局健康度 → 異常在哪 → 該批准什麼 |
| **值班 SRE** | 告警響應、修復執行 | 哪個服務掛了 → 影響範圍 → 修復動作 |
| **管理層** | 週報/月報、ROI 評估 | 自動化率、MTTR 趨勢、處置分佈 |

### 1.3 成功標準

| 標準 | 量化目標 |
|------|---------|
| 發現異常 | 打開首頁 3 秒內能定位問題服務 |
| 理解影響 | 不用切換頁面就能看到依賴關係和爆炸半徑 |
| 執行修復 | 從發現到批准修復不超過 2 次點擊 |
| 資訊密度 | 一屏能呈現全局狀態，不需要捲動 |

---

## 第二章：解決方案概述

### 2.1 核心設計理念

**從「被動儀表板」到「主動指揮中心」**

```
傳統儀表板: 看數據 → 人腦判斷 → 手動操作
指令中心:   看全局 → AI 提供上下文 → 一鍵批准
```

### 2.2 頁面結構 (基於統帥截圖概念)

```
┌──────────────────────────────────────────────────────────┐
│ Header (68px): Logo + 頁面標題 + AI 狀態膠囊 + 語系    │
├──────────┬───────────────────────┬───────────────────────┤
│ Sidebar  │ KPI Strip (4-5 指標)  │                       │
│ (224px)  ├───────────────────────┤   右側面板 (300px)     │
│          │                       │   ┌─────────────────┐ │
│ · 儀表板 │  神經拓撲圖            │   │ 待核准任務       │ │
│ · 警報   │  (React Flow + elkjs) │   │ SSH URI + 按鈕   │ │
│ · 自動修復│  嵌套群組/展開/收合    │   ├─────────────────┤ │
│ · 神經指揮│                       │   │ 處置統計         │ │
│ · 腳本庫 │                       │   │ 四色計數+堆疊條  │ │
│ · 知識庫 ├───────────────────────┤   └─────────────────┘ │
│ · 報表   │ 系統活動串流 (Live)    │                       │
│ · 審計   │ AI 推理過程時間軸      │                       │
│ · 設定   ├───────────────────────┤                       │
│          │ 控制列 (頻率/數據流)   │                       │
└──────────┴───────────────────────┴───────────────────────┘
```

### 2.3 五大區塊定義

| 區塊 | 位置 | 功能 | 資料來源 (API) |
|------|------|------|---------------|
| **KPI Strip** | 頂部橫條 | 系統健康度/活動事件/自動修復率/總操作 | `/dashboard` + `/stats/disposition` |
| **神經拓撲圖** | 中央主區域 | 服務依賴 + AI 介入 + 嵌套群組 | `/dashboard` (hosts/services) |
| **活動串流** | 中央下方 | 即時事件時間軸 (告警/AI/修復) | SSE `/events` |
| **待核准面板** | 右上 | SSH URI + 風險等級 + 批准/拒絕 | `/approvals/pending` |
| **處置統計** | 右下 | 四色計數 + 堆疊條 + 自動化率 | `/stats/disposition` |

---

## 第三章：拓撲圖詳細設計

### 3.1 嵌套群組結構

```
Level 0 (Macro View) — 預設顯示，4-6 個群組節點
├── 基礎設施 (.110) [藍色邊框]
│   └── 收合時顯示: "5 服務 · 全部健康"
├── AI/數據中心 (.188) [紅色邊框 if 異常]
│   └── 收合時顯示: "10 服務 · 1 警告"
├── K3s 叢集 (120/121) [紫色邊框]
│   └── 收合時顯示: "15 Pods · 全部運行"
└── 外部網路 [橘色邊框]
    └── 收合時顯示: "6 目標 · 全部可達"

Level 1 (Drill-down) — 點擊群組展開
├── .110 展開後:
│   ├── Gitea (3001) ── 健康
│   ├── Harbor (5000) ── 健康
│   ├── Sentry (9000) ── 健康
│   ├── Prometheus (9090) ── 健康
│   ├── Alertmanager (9093) ── 健康
│   └── Grafana ── 健康
├── .188 展開後:
│   ├── PostgreSQL (5432) ── 健康
│   ├── Redis (6380) ── 健康
│   ├── OpenClaw (8089) ── [AI 診斷中 ⚡]
│   ├── Ollama (11434) ── 健康
│   ├── SignOz (3301) ── 健康
│   ├── ClickHouse (8123) ── 健康
│   ├── MinIO (9000) ── 健康
│   └── Langfuse (3100) ── 健康
...
```

### 3.2 節點設計 (React Flow Custom Node)

```
┌─────────────────────────┐
│ ● healthy               │  ← 狀態燈 + 文字
│ PostgreSQL              │  ← 服務名稱 (Inter 600)
│ .188:5432 · Docker      │  ← 位置 + 類型 (JetBrains Mono 9px)
└─────────────────────────┘
  圓角 8px · 0.5px 邊框 · card shadow

狀態顏色:
  ● 綠色 (#22C55E) = healthy
  ● 橘色 (#F59E0B) = warning (CPU/Memory 偏高)
  ● 紅色 (#cc2200) = critical (服務不可用)
  ● 藍色 (#4A90D9) = AI 正在診斷
  ● 灰色 (#A3A3A3) = unknown
```

### 3.3 邊線設計

| 類型 | 樣式 | 用途 |
|------|------|------|
| 正常依賴 | 綠色漸層 → 透明，實線 | 健康的服務間連線 |
| 異常依賴 | 橘色→紅色漸層，虛線 | 受影響的依賴鏈 |
| AI 介入 | 藍色→紫色漸層，流動粒子動畫 | OpenClaw 正在分析的路徑 |
| 收合群組間 | 灰色虛線 | 群組之間的連線 |

### 3.4 互動行為

| 操作 | 行為 |
|------|------|
| 點擊群組 | 展開/收合群組，顯示內部服務 |
| 點擊服務節點 | 右側面板顯示該服務詳情 (指標/日誌/告警) |
| Hover 節點 | 顯示 tooltip (CPU/Memory/連線數) |
| 滾輪 | 縮放 |
| 拖曳空白 | 平移畫布 |
| 「全部展開」按鈕 | 展開所有群組 |
| 「全部收合」按鈕 | 收合到 Macro View |
| 「只看異常」按鈕 | 隱藏所有健康節點，只顯示 warning/critical |

---

## 第四章：細化實施步驟

### Phase 1: 基礎建設 (Day 1)

#### Task 1.1: 安裝依賴

```bash
cd apps/web
npm install @xyflow/react elkjs
```

**驗證**: `import { ReactFlow } from '@xyflow/react'` 能成功 import

**檔案影響**: `package.json`, `package-lock.json`

---

#### Task 1.2: 建立 topology 元件目錄結構

```
apps/web/src/components/topology/
├── index.ts                   # 匯出
├── ServiceTopology.tsx        # 主元件
├── nodes/
│   ├── GroupNode.tsx           # 群組節點 (可展開/收合)
│   ├── ServiceNode.tsx        # 服務節點 (memo)
│   └── node-types.ts          # nodeTypes 註冊
├── edges/
│   ├── TopologyEdge.tsx       # 自定義邊線 (漸層+動畫)
│   └── edge-types.ts          # edgeTypes 註冊
├── hooks/
│   ├── useTopologyData.ts     # API → nodes/edges 轉換
│   └── useElkLayout.ts        # elkjs 佈局引擎
├── utils/
│   ├── topology-colors.ts     # 狀態→顏色映射 (從 tailwind.config.ts)
│   └── topology-icons.ts      # 服務→Lucide icon 映射
└── topology.css               # 邊線動畫 keyframes
```

**驗證**: 目錄結構正確建立

---

### Phase 2: 核心元件 (Day 2-3)

#### Task 2.1: ServiceNode.tsx — 服務節點

```typescript
// 關鍵設計決策:
// 1. 用 React.memo + 自定義 areEqual
// 2. Tailwind className 直接套用
// 3. Lucide icon 根據服務類型選擇
// 4. 狀態色彩從 topology-colors.ts
```

**檔案**: `apps/web/src/components/topology/nodes/ServiceNode.tsx`
**測試**: 渲染 1 個節點，確認 Tailwind 樣式 + Lucide icon 正確
**i18n**: 節點標籤用 `useTranslations('topology')`

---

#### Task 2.2: GroupNode.tsx — 群組節點

```typescript
// 關鍵設計決策:
// 1. 收合時: 顯示群組名稱 + 服務數 + 健康摘要
// 2. 展開時: 變成透明容器，內部由 elkjs 排列子節點
// 3. 邊框顏色: 藍(.110) / 紅(.188異常) / 紫(K3s) / 橘(外部)
// 4. 點擊標題列 toggle 展開/收合
```

**檔案**: `apps/web/src/components/topology/nodes/GroupNode.tsx`
**測試**: 收合→展開→收合 循環測試

---

#### Task 2.3: TopologyEdge.tsx — 自定義邊線

```typescript
// 關鍵設計決策:
// 1. 用 React Flow 的 BaseEdge + getSmoothStepPath
// 2. SVG linearGradient 漸層色
// 3. CSS stroke-dasharray 流動動畫 (零 JS 開銷)
// 4. AI 介入路徑: 藍紫漸層 + 粒子動畫 (SVG animateMotion)
```

**檔案**: `apps/web/src/components/topology/edges/TopologyEdge.tsx`
**檔案**: `apps/web/src/components/topology/topology.css`
**測試**: 三種邊線 (正常/異常/AI) 渲染正確

---

#### Task 2.4: useElkLayout.ts — elkjs 佈局引擎

```typescript
// 關鍵設計決策:
// 1. elkjs 異步執行 — 需要 loading 狀態
// 2. 群組嵌套: elk options { 'elk.algorithm': 'layered' }
// 3. 節點間距: nodeSpacing=20, layerSpacing=50
// 4. 邊線路由: 'elk.edgeRouting': 'ORTHOGONAL' (正交)
// 5. 方向: 'elk.direction': 'RIGHT' (左到右)
```

**檔案**: `apps/web/src/components/topology/hooks/useElkLayout.ts`
**測試**: 輸入 20 個節點，輸出合理的 x/y 座標

---

#### Task 2.5: useTopologyData.ts — API 資料轉換

```typescript
// 關鍵設計決策:
// 1. 從 /api/v1/dashboard 取得 hosts + services
// 2. 轉換為 React Flow 的 Node[] + Edge[] 格式
// 3. 加入 parentId 實現嵌套 (elkjs compound graph)
// 4. 節點狀態即時更新 (透過 Zustand store 或定時 polling)
```

**檔案**: `apps/web/src/components/topology/hooks/useTopologyData.ts`
**測試**: API 回傳 → 正確的 nodes/edges 結構

---

### Phase 3: 主元件組裝 (Day 3-4)

#### Task 3.1: ServiceTopology.tsx — 主元件

```typescript
// 組裝所有子元件:
// 1. ReactFlow + nodeTypes + edgeTypes
// 2. useTopologyData (API 資料)
// 3. useElkLayout (佈局計算)
// 4. 控制列 (全部展開/收合/只看異常)
// 5. MiniMap + Controls
// 6. 骨架屏 (elkjs 計算中顯示)
```

**檔案**: `apps/web/src/components/topology/ServiceTopology.tsx`
**測試**: 完整拓撲圖渲染 + 互動

---

#### Task 3.2: i18n 翻譯

```json
// messages/zh-TW.json
{
  "topology": {
    "title": "神經拓撲",
    "expandAll": "全部展開",
    "collapseAll": "全部收合",
    "showAnomaliesOnly": "只看異常",
    "healthy": "健康",
    "warning": "警告",
    "critical": "異常",
    "aiDiagnosing": "AI 診斷中",
    "services": "服務",
    "pods": "Pods",
    "allHealthy": "全部健康",
    "infraGroup": "基礎設施",
    "aiGroup": "AI/數據中心",
    "k3sGroup": "K3s 叢集",
    "externalGroup": "外部網路"
  }
}
```

**檔案**: `messages/zh-TW.json`, `messages/en.json`

---

### Phase 4: 頁面整合 (Day 4-5)

#### Task 4.1: 首頁 `/` 整合

```
修改: apps/web/src/app/[locale]/page.tsx
新增: ServiceTopology 元件到中央區域
保留: 現有 Metrics Strip + Incident Feed + OpenClaw Panel
策略: 拓撲圖收合模式 (Macro View，4-6 群組節點)
```

---

#### Task 4.2: 拓撲頁 `/topology` 升級

```
修改: apps/web/src/app/[locale]/topology/page.tsx
替換: 現有 host list → 完整 ServiceTopology (可展開)
新增: 篩選器 (按群組/狀態/服務類型)
```

---

#### Task 4.3: 神經指揮 `/neural-command` 整合

```
修改: apps/web/src/components/neural-command/NeuralLiveCenter.tsx
新增: 迷你版 ServiceTopology (SSH 指揮鏈視圖)
```

---

### Phase 5: 設計稿與視覺調校 (Day 5-6)

#### Task 5.1: HTML Mockup 製作 (3+ 版本)

差異化在佈局比例和視覺重心：

| 版本 | 差異 | 拓撲佔比 | 右面板 |
|------|------|---------|--------|
| VA | 拓撲主角 + 右側固定面板 | 65% | 待核准 + 統計 |
| VB | 拓撲+串流並排 + 右側 tab 切換 | 55% | tab: 核准/串流/統計 |
| VC | 拓撲全幅 + 底部折疊面板 | 80% | 底部抽屜式 |

**部署**: scp → 192.168.0.188 → http://192.168.0.188:8765/

---

#### Task 5.2: 統帥選擇後視覺調校

根據統帥回饋修改：
- 佈局比例
- 配色微調
- 互動細節

---

### Phase 6: 後端 API 支援 (Day 6-7)

#### Task 6.1: `/api/v1/dashboard` 擴充

```python
# 現有回傳: hosts (name, status, cpu, ram, services)
# 需擴充:
# 1. 每個 host 加入 group 分類 (infra/ai/k3s/external)
# 2. 服務間的依賴關係 (edges)
# 3. AI 介入狀態 (openclaw_diagnosing: [service_name])
```

**檔案**: `apps/api/src/api/v1/dashboard.py`
**檔案**: `apps/api/src/services/dashboard_service.py` (如果有)

---

#### Task 6.2: 服務依賴關係定義

```yaml
# 可能需要新增 ConfigMap 或靜態配置
# 定義哪些服務依賴哪些服務
dependencies:
  awoooi-web → awoooi-api
  awoooi-api → postgresql, redis, openclaw
  awoooi-worker → postgresql, redis, ollama
  openclaw → ollama, langfuse
  ...
```

**方案選擇**:
- A: 靜態配置 (YAML/JSON) — 簡單可控
- B: 從 OTEL Trace 自動推導 — 動態但複雜
- C: 從 K8s NetworkPolicy 推導 — 部分覆蓋

**建議**: 先 A (靜態配置)，未來可加 B (OTEL 自動發現)

---

### Phase 7: 測試與驗收 (Day 7-8)

#### Task 7.1: TypeScript 驗證

```bash
cd apps/web && pnpm exec tsc --noEmit
```

#### Task 7.2: 生產建置

```bash
pnpm run build
```

#### Task 7.3: 視覺驗收

- 首頁拓撲圖收合模式
- 點擊展開每個群組
- AI 介入動畫
- 異常節點高亮
- 響應式 (收合 Sidebar 後拓撲圖自動調整)

#### Task 7.4: 效能驗收

- 40+ 節點全展開時 FPS ≥ 30
- elkjs 佈局計算 ≤ 500ms
- 單一節點狀態更新不觸發其他節點 re-render

---

## 第五章：風險與緩解

| 風險 | 等級 | 緩解 |
|------|------|------|
| elkjs API 學習成本 | 中 | 封裝在 useElkLayout.ts，只暴露 layoutNodes() |
| elkjs 佈局計算阻塞 UI | 低 | Web Worker 或 setTimeout 分片 |
| 節點數 150+ DOM 效能 | 低 | 預設收合 (只 4-6 DOM)，展開時 memo |
| 服務依賴定義維護 | 中 | 先靜態 YAML，未來 OTEL 自動發現 |
| 設計與現有頁面衝突 | 低 | 拓撲圖是新增元件，不動現有佈局 |

---

## 第六章：時程預估

| Phase | 天數 | 內容 |
|-------|------|------|
| 1 | 1 | 安裝依賴 + 目錄結構 |
| 2 | 2 | 核心元件 (節點/邊線/佈局/資料) |
| 3 | 1 | 主元件組裝 + i18n |
| 4 | 1 | 頁面整合 (首頁/拓撲/神經指揮) |
| 5 | 2 | 設計稿 (3+版本) + 視覺調校 |
| 6 | 1 | 後端 API 擴充 |
| 7 | 1 | 測試 + 驗收 |
| **總計** | **~9 天** | |

---

## 第七章：需要統帥決策的事項

| # | 決策項 | 選項 | 建議 | 統帥決定 |
|---|--------|------|------|---------|
| 1 | 首頁拓撲圖佈局比例 | 65% / 55% / 80% | 待設計稿比較 | ⏳ |
| 2 | 右側面板模式 | 固定 / tab切換 / 底部抽屜 | 待設計稿比較 | ⏳ |
| 3 | 服務依賴定義方式 | 靜態YAML / OTEL自動 / 混合 | 先靜態 | ⏳ |
| 4 | 拓撲圖預設狀態 | 全部收合 / 展開異常群組 | 展開異常 | ⏳ |
| 5 | 是否先做 PoC 驗證 | 先 PoC 再做設計稿 / 並行 | 先 PoC | ⏳ |

---

## 第八章：需要的技術文檔 (輔助決策)

為了讓統帥能做出更完整的決策，以下文檔需要準備：

| # | 文檔 | 用途 | 狀態 |
|---|------|------|------|
| 1 | **React Flow + elkjs PoC Demo** | 在內網部署一個可互動的 PoC，讓統帥親手操作展開/收合/篩選 | ⏳ 待製作 |
| 2 | **競品 UI 截圖集** | Datadog Service Map / Dynatrace Smartscape / Grafana Node Graph 的真實產品截圖 | ⏳ 待收集 |
| 3 | **3+ 版本 HTML 設計稿** | 高品質 mockup 部署到內網 192.168.0.188:8765 | ⏳ 待製作 |
| 4 | **現有 API 回傳格式文件** | `/api/v1/dashboard` 目前回傳什麼、需要擴充什麼 | ⏳ 待整理 |
| 5 | **服務依賴關係圖** | 67 個實體的完整依賴關係 (手動整理) | ⏳ 待整理 |
| 6 | **Bundle Size 影響報告** | 安裝 @xyflow/react + elkjs 後的 bundle 增量 | ⏳ 待測量 |

---

## 第九章：建議下一步

**統帥，我建議按以下順序推進：**

```
Step 1: 先做 PoC (React Flow + elkjs 嵌套群組)
        → 部署到內網讓統帥實際操作
        → 確認技術可行性和互動體驗

Step 2: 收集競品截圖 + 整理服務依賴關係
        → 給統帥參考市場做法

Step 3: 基於 PoC + 競品 → 製作 3+ 版本設計稿
        → 統帥選擇方向

Step 4: 確認方向後 → 正式實作 (Phase 1-7)
```

**統帥，這份計畫是否足夠完整？還需要補充哪些內容？**
