# ADR-060: React Flow + elkjs 拓撲圖引擎技術選型

| 項目 | 內容 |
|------|------|
| **狀態** | ✅ 已批准 |
| **日期** | 2026-04-08 |
| **決策者** | 統帥 + 首席架構師 |
| **觸發** | Sprint 5 指令中心重設計 — 需呈現 67→150+ 個監控實體的服務拓撲 |

## 背景

AWOOOI 監控系統已涵蓋 67 個實體 (K8s Pods 15 + Docker 17 + 主機 5 + API 8 + AI 4 + 外部 6 + 其他)，未來預計擴展至 120-150+ 個。需要在前端呈現「神經拓撲圖」— 即時服務依賴 + AI 介入狀態 + 嵌套群組展開/收合。

## 候選方案評估

| 方案 | 組合 | 優點 | 缺點 | 評分 |
|------|------|------|------|------|
| A | React Flow + AntV X6 | 各取所長 | 維護兩套、設計語言分裂 | 60 |
| B | React Flow + dagre | 輕量統一 | dagre 不支援嵌套群組 | 70 |
| C | AntV X6 統一 | 內建佈局強 | React 整合非原生、Tailwind 穿透困難 | 55 |
| **D+** | **React Flow + elkjs** | **原生 React + 嵌套群組 + 正交路由** | elkjs API 較複雜 | **90** |

## 決策

**選擇方案 D+: React Flow (@xyflow/react) + elkjs**

### 核心理由

1. **DOM 渲染** — 節點是 HTML 元素，Tailwind/Lucide/自定義字型 100% 原生支援
2. **elkjs 嵌套群組** — 支援 Compound Graph，可實現 Macro→Drill-down 層級視圖
3. **單一技術棧** — 一套 API、一份節點元件、一個設計語言
4. **未來 150+ 節點** — elkjs 正交邊線路由 + 子群組摺疊，避免認知超載
5. **社群** — React Flow 155K/週下載、35K stars，問題好查

### 否決方案 A 的理由

- 同一專案維護兩套圖形引擎違反 SSOT (Single Source of Truth)
- 設計系統更新需同步兩處，增加漂移風險
- Bundle Size +330KB vs +270KB，無顯著優勢

## 安裝

```bash
npm install @xyflow/react elkjs
```

## 架構

```
apps/web/src/components/topology/
├── ServiceTopology.tsx     # React Flow 主元件
├── GroupNode.tsx            # 可展開/收合的群組節點
├── ServiceNode.tsx          # 服務節點 (memo + areEqual)
├── TopologyEdge.tsx         # 漸層邊線 + CSS 動畫
├── useTopologyData.ts       # API → nodes/edges
├── useElkLayout.ts          # elkjs 嵌套佈局
└── topology.css             # 邊線動畫
```

## 各頁面使用

| 頁面 | 模式 | 節點數 |
|------|------|--------|
| `/` 首頁 | 收合群組 (~4-6 節點) | 低 |
| `/topology` | 完整展開 (100+) + 篩選 | 高 |
| `/neural-command` | SSH 指揮鏈 (8-12) | 低 |

## 效能策略

- React.memo + 自定義 areEqual (只比 status/cpu/memory)
- 收合群組：預設 Macro View (~6 節點)
- 動態篩選：只顯示 Warning/Critical 節點
- elkjs Web Worker (避免阻塞主線程)

## 風險

| 風險 | 緩解 |
|------|------|
| elkjs API 複雜 | 封裝在 useElkLayout.ts，業務層不接觸 |
| elkjs 異步佈局 | 顯示 loading 骨架屏 |
| 節點數 500+ | 評估虛擬化 (viewport culling) |
