# RunBook: 前端 UI/UX 核心痛點徹底解決方案

> **類型**: 架構設計 + 實施 RunBook  
> **優先級**: 🔴 P0 (核心競爭力)  
> **建立**: 2026-03-29 12:38 (台北)  
> **建立者**: Antigravity  
> **核心命題**: 讓 AWOOOI 的前端「讓人看一眼就驚艷，用一次就上癮」

---

## 一、Claude Code 前端弱點診斷

### 1.1 五大結構性弱點

| 弱點 | 後果 | 解法 |
|------|------|------|
| **視覺感知盲區** | 代碼語法正確，但視覺效果差 | Playwright 截圖 + 統帥視覺主控 |
| **CSS 語境失憶** | 改 A 壞 B，不知道全局 CSS 影響 | Storybook 隔離組件 + TypeCheck |
| **動畫設計無感** | 150ms 快閃 vs 300ms 遲滯無法感知 | 在 Storybook Story 中定義動畫標準 |
| **設計意圖推斷不足** | Nothing.tech 審美需要視覺參照 | 每個組件附帶規格截圖 |
| **Safari 兼容性盲點** | `backdrop-blur` 在 Safari 有 bug | Playwright multi-browser E2E |

### 1.2 技術債現況（截至 2026-03-29）

```
i18n 違規：40+ 處（TECHNICAL_DEBT_PHASE2.md）
shadcn/ui 殘留：已部分廢除，但需全面確認
GenUI Registry：只有基礎 5 張卡片，缺少監控類
Knowledge Base：頁面空白，無後端
Omni-Terminal：外殼完整，SSE 事件類型未完全對接
```

---

## 二、九大行動詳細實施計畫

### 🔴 行動 1: i18n 閃電清零（工時：4h）

**策略：一次性掃描→批量修復，非逐一處理**

```bash
# Step 1.1: 自動掃描所有硬編碼字串
cd /Users/ogt/awoooi/apps/web

# 掃描 TSX 中的英文硬編碼（排除技術識別符）
grep -rn '"[A-Z][A-Z]' src/ --include="*.tsx" --include="*.ts" | \
  grep -v "//.*\"" | \
  grep -v "className=" | \
  grep -v "href=" | \
  grep -v "id=" | \
  grep -v "import " > /tmp/en_violations.txt

# 掃描中文硬編碼
grep -rn "\"[^\x00-\x7F]" src/ --include="*.tsx" | \
  grep -v "//.*\"" > /tmp/zh_violations.txt

echo "英文違規：$(wc -l < /tmp/en_violations.txt) 處"
echo "中文違規：$(wc -l < /tmp/zh_violations.txt) 處"
```

**已知 P0 違規快速修復清單**（根據 TECHNICAL_DEBT_PHASE2.md）：

```typescript
// ❌ agent/data-pincer.tsx:50-78（需修復）
// 現在：
const statuses = {
  standby: 'STANDBY',
  analyzing: 'ANALYZING',
  executing: 'EXECUTING',
  awaiting: 'AWAITING APPROVAL',
  error: 'ERROR'
}

// ✅ 修復後：
const statuses = {
  standby: t('status.standby'),
  analyzing: t('status.analyzing'),
  executing: t('status.executing'),
  awaiting: t('status.awaitingApproval'),
  error: t('status.error')
}
```

```typescript
// ❌ status-orb.tsx:16-31
// 現在：
const STATUS_TEXT = {
  idle: 'Idle',
  thinking: 'Thinking',
  executing: 'Executing',
  awaiting: 'Awaiting Approval'
}

// ✅ 修復後：
const STATUS_TEXT = {
  idle: t('status.idle'),
  thinking: t('status.thinking'),
  executing: t('status.executing'),
  awaiting: t('status.awaitingApproval')
}
```

**需要同步更新的字典檔**：

```json
// apps/web/messages/zh-TW.json（追加）
{
  "status": {
    "idle": "待機",
    "thinking": "分析中",
    "executing": "執行中",
    "awaitingApproval": "等待核准",
    "error": "錯誤",
    "standby": "待機",
    "analyzing": "分析中"
  }
}
```

```json
// apps/web/messages/en.json（追加）
{
  "status": {
    "idle": "Idle",
    "thinking": "Thinking",
    "executing": "Executing",
    "awaitingApproval": "Awaiting Approval",
    "error": "Error",
    "standby": "Standby",
    "analyzing": "Analyzing"
  }
}
```

**驗收指令（必須通過）**：

```bash
cd apps/web

# 確認無中文硬編碼
if grep -rn '"[^\x00-\x7F]' src/ --include="*.tsx" | grep -v "//"; then
  echo "❌ 仍有中文硬編碼！"
  exit 1
else
  echo "✅ 中文硬編碼清零"
fi

# TypeScript 編譯驗證（workflow 硬規則）
pnpm exec tsc --noEmit
```

---

### 🔴 行動 2: Storybook 組件庫建立（工時：8h）

**這是解決 AI 視覺感知盲區的根本方案**。

```bash
# Step 2.1: 安裝 Storybook
cd apps/web
pnpm add -D storybook@latest @storybook/nextjs @storybook/addon-essentials \
           @storybook/addon-interactions @storybook/test
npx storybook@latest init --builder webpack5

# Step 2.2: 配置 Nothing.tech 主題
```

**必須上架的 10 個核心組件 Story**：

| 組件 | Nothing.tech 規格 | Story 狀態 |
|------|-----------------|-----------|
| `GlassCard` | `bg-white/70 backdrop-blur-[20px] border border-black/[0.06]` | Loading / Content / Error |
| `StatusOrb` | 燈號 + `animate-ping`（critical 時）| idle / thinking / executing / critical |
| `ApprovalCard` | 1.0 ConversationalView 風格 | LOW / MEDIUM / HIGH / CRITICAL |
| `OmniTerminal` | VT323 字體 + 綠色游標閃爍 | empty / thinking / streaming / error |
| `HostCard` | CPU/Memory 橫條 + 脈搏點 | healthy / warning / critical |
| `MetricsCard` | 數字大字 + 趨勢箭頭 | up / down / stable |
| `SystemHealthCard` | 燈號矩陣 5x5 | all-healthy / some-warning / critical |
| `FinOpsCard` | 成本分解 + 可省金額 | monthly / quarterly |
| `SLOCard` | 達成率 + 趨勢 | healthy / at-risk / breached |
| `AnomalyFrequencyCard` | 頻率統計 + 升級建議 | normal / repeat / escalate |

**Storybook Story 範例**（GlassCard）：

```typescript
// apps/web/src/components/ui/glass-card.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import { GlassCard } from './glass-card';

const meta: Meta<typeof GlassCard> = {
  title: 'AWOOOI/UI/GlassCard',
  component: GlassCard,
  parameters: {
    // Nothing.tech 白底背景
    backgrounds: {
      default: 'nothing-white',
      values: [{ name: 'nothing-white', value: '#F5F5F0' }],
    },
    // 規格文件截圖
    docs: {
      description: {
        component: `
          Nothing.tech 白玻璃卡片。固定規格：
          - bg: bg-white/70
          - blur: backdrop-blur-[20px]
          - border: border border-black/[0.06]
          - radius: rounded-xl
        `,
      },
    },
  },
  tags: ['autodocs'],
};
export default meta;

type Story = StoryObj<typeof GlassCard>;

export const Default: Story = {
  args: { children: '玻璃卡片內容' }
};

export const WithCriticalBorder: Story = {
  args: {
    children: '緊急狀態',
    className: 'border-status-critical border-2'
  }
};
```

---

### 🔴 行動 3: AI 視覺審查 SOP（工時：2h 建立，後續 0 工時）

**建立標準作業程序，讓 AI 自主截圖並等待統帥審核：**

```markdown
## AI 前端修改 SOP（強制執行）

### 修改前
1. 查閱 Storybook 對應組件的規格 Story
2. 確認 Nothing.tech 視覺 Token（詳見 tailwind.config.ts）

### 修改中
3. 修改代碼
4. 執行 `pnpm exec tsc --noEmit`（語法驗證）

### 修改後（🆕 新增強制步驟）
5. 啟動 Dev Server：`pnpm dev`
6. 執行截圖腳本：
   ```bash
   cd apps/web
   pnpm exec playwright screenshot \
     --browser chromium \
     http://localhost:3000 \
     docs/screenshots/$(date +%Y%m%d-%H%M)/homepage.png
   ```
7. 截圖存至 `docs/screenshots/{date}/{component}.png`
8. 在 LOGBOOK 記錄：「已截圖，視覺存檔 docs/screenshots/xxx/yyy.png」
9. 等待統帥視覺審批後方可 commit
```

---

### 🟠 行動 4: Omni-Terminal 後端全接通（工時：8h）

根據 `ADR-031` 和 `AWOOOI_AGENTIC_WORKSPACE_ROADMAP.md` 的神經連接藍圖：

#### 4.1 三大 SSE 事件類型定義

```python
# apps/api/src/api/v1/terminal.py
# 擴充現有 SSE 端點

class SSEEventType(str, Enum):
    THOUGHT = "thought"          # Agent 思考流
    TOOL_CALL = "tool_call"      # 工具調用（含微動畫觸發信號）
    TOOL_RESULT = "tool_result"  # 工具結果
    RENDER_UI = "render_ui"      # 動態渲染 GenUI 組件
    STREAM_END = "stream_end"    # 思考流結束


# 範例事件：
async def stream_terminal_response(command: str):
    # 1. 思考流
    yield f"event: thought\ndata: {json.dumps({'text': '[Investigator] 分析指令...'})}\n\n"
    
    # 2. 工具調用（觸發前端 CSS 動畫）
    yield f"event: tool_call\ndata: {json.dumps({'tool': 'kubectl_get', 'args': {'resource': 'pod', 'namespace': 'awoooi-prod'}})}\n\n"
    
    # 3. 工具結果
    yield f"event: tool_result\ndata: {json.dumps({'pods': [...]})}\n\n"
    
    # 4. 渲染 GenUI 卡片（前端動態載入組件）
    yield f"event: render_ui\ndata: {json.dumps({'component': 'SystemHealthCard', 'props': {...}})}\n\n"
    
    # 5. 結束
    yield f"event: stream_end\ndata: {json.dumps({'success': True})}\n\n"
```

#### 4.2 前端 SSE 事件處理器（關鍵）

```typescript
// apps/web/src/hooks/useTerminalSSE.ts
// 修改現有 SSE hook，增加 tool_call 動畫觸發

const useTerminalSSE = (commandId: string) => {
  const [state, setState] = useTerminalStore();
  
  useEffect(() => {
    const es = new EventSource(`/api/v1/terminal/stream/${commandId}`);
    
    // 思考流
    es.addEventListener('thought', (e) => {
      const data = JSON.parse(e.data);
      setState(s => ({ ...s, thoughts: [...s.thoughts, data.text] }));
    });
    
    // 工具調用 → 觸發微動畫
    es.addEventListener('tool_call', (e) => {
      const data = JSON.parse(e.data);
      setState(s => ({
        ...s,
        activeToolCall: data.tool,  // UI 顯示「正在執行 kubectl_get...」
        isAnimating: true
      }));
    });
    
    // GenUI 動態渲染（核心功能！）
    es.addEventListener('render_ui', (e) => {
      const { component, props } = JSON.parse(e.data);
      setState(s => ({
        ...s,
        renderedCards: [...s.renderedCards, { component, props }]
      }));
    });
    
    es.addEventListener('stream_end', () => {
      setState(s => ({ ...s, isStreaming: false, isAnimating: false }));
      es.close();
    });
    
    return () => es.close();
  }, [commandId]);
};
```

---

### 🟠 行動 5: GenUI Registry 擴充（工時：8h）

新增 5 張監控類 GenUI 卡片（詳細規格見 `MONITORING_ARCHITECTURE_DEEP_DIVE.md`）：

```typescript
// apps/web/src/components/genui/registry.ts
export const GENUI_COMPONENTS = {
  // 現有：
  'MetricsCard': () => import('./cards/MetricsCard'),
  'K8sPodCard': () => import('./cards/K8sPodCard'),
  
  // 🆕 監控類（Wave M-3）：
  'SystemHealthCard': () => import('./monitoring/SystemHealthCard'),
  'ServiceDetailCard': () => import('./monitoring/ServiceDetailCard'),
  'FinOpsCard': () => import('./monitoring/FinOpsCard'),
  'SLODashboardCard': () => import('./monitoring/SLODashboardCard'),
  'AlertChainStatusCard': () => import('./monitoring/AlertChainStatusCard'),
  'AnomalyFrequencyCard': () => import('./monitoring/AnomalyFrequencyCard'),
  'MTTRCard': () => import('./monitoring/MTTRCard'),
}
```

---

## 三、前端改善路線圖時間表

```
📅 本週（立即）：
  [4h] i18n 閃電清零（一次性全修）
  [2h] AI 視覺審查 SOP 建立（.awoooi-agent-rules.md 追加）

📅 Week 2-3：
  [8h] Storybook 10 個核心組件 Story
  [8h] Omni-Terminal 後端全接通（三種 SSE 事件）

📅 Week 4-5：
  [8h] 監控 GenUI 卡片擴充（7 張新卡片）
  [8h] Nexus 頁面 AI 自治率 UI 組件

📅 Month 2：
  [16h] Knowledge Base 後端 + 前端完整建設
  [8h]  Visual Regression Testing CI 整合

📅 Month 3（Phase 4 視覺靈魂注入）：
  [?h]  品牌 3D 資產 + Q 版 OpenClaw
  [?h]  全站微動畫升級（150ms 快閃標準）
  [?h]  Nothing.tech 認證級別的設計審計
```

---

## 四、強制驗收標準

每次前端 PR 合併前，必須通過以下全部驗收：

```bash
# 1. TypeScript 無錯誤（前端美學 Workflow 硬規則）
cd apps/web && pnpm exec tsc --noEmit

# 2. i18n 無硬編碼（CI 攔截）
[ -z "$(grep -rn '"[^\x00-\x7F]' src/ --include='*.tsx')" ] || exit 1

# 3. Storybook 可正常 build（確保組件獨立可用）
pnpm storybook build

# 4. E2E Smoke 測試通過
pnpm exec playwright test --grep @smoke

# 5. 截圖存檔（AI 執行，統帥視覺審批）
pnpm exec playwright screenshot http://localhost:3000 docs/screenshots/pr-{NUMBER}/homepage.png

# 6. Build 成功（生產環境兼容）
pnpm run build
```

---

## ⚠️ 架構安全補丁（2026-03-29 更新，行動 1 開始前必讀）

> 來源：`ARCHITECTURAL_RISK_WAR_GAME.md` 深度沙盤推演，代碼確認級別

### 補丁：Feature Freeze 前必須建立 release/v1.x 穩定分支

**問題**：行動 1（i18n 閃電清零）需要全域替換 `src/` 底下數千行代碼，`main` 分支會進入持續 3-5 天的「混沌狀態」。若此期間生產爆發 P0 Bug（如簽核按鈕失效），**無法切出乾淨的 Hotfix 分支**，導致修復與重構互相衝突。

> 🔴 **行動 1 開始前，必須先建立 `release/v1.x` 穩定分支！**

#### 必須在行動 1 之前執行

```bash
# Step 0（行動 1 前置）：建立穩定基準分支
git checkout main
git pull origin main
git checkout -b release/v1.x
git push origin release/v1.x

# 在 GitHub 設定 release/v1.x 為 Protected Branch
# Settings → Branches → Add branch protection rule → release/v1.x
# ✅ Require pull request reviews (1 approver)
# ✅ Do not allow bypassing the above settings
```

#### 正確的行動順序

```
Step 0：建立 release/v1.x（🆕 前置步驟，必須先做）

Step 1：宣佈 Frontend Feature Freeze（禁止非 i18n PR 合併前端代碼）

Step 2：i18n 閃電清零（在 fix/i18n-zero-violation 分支進行）

Step 3：PR 合併到 main → 解除 Frontend Freeze

Step 4：ESLint i18n Plugin 切換為 error 模式

Step 5：繼續行動 2-9（Storybook、Terminal 等）
```

#### Freeze 期間 P0 Hotfix 緊急流程

```bash
# 情境：簽核按鈕在生產失效，i18n 清零正在進行中

# 1. 從穩定基準切出 hotfix（不影響 i18n 重構）
git checkout release/v1.x
git checkout -b hotfix/fix-approval-button

# 2. 最小化修復（只改 Bug，不動其他代碼）
# ... 修復代碼 ...
git add . && git commit -m "fix: approval button not responding on mobile"

# 3. PR 到 release/v1.x → CD 直接部署 release 分支
git push origin hotfix/fix-approval-button
# → PR 合併到 release/v1.x
# → 觸發 CD 部署（CD 配置需支援 release/* 分支）

# 4. Cherry-pick 到 main（不中斷 i18n 重構）
git checkout main
git cherry-pick <hotfix-commit-hash>
# 若有衝突：手動解決後繼續
```

#### Hotfix 觸發條件（須加入 HARD_RULES.md）

```
P0 Hotfix 判定標準（任一條件符合即觸發）：
□ 統帥無法使用核心功能（簽核按鈕、登入、Telegram 通知）
□ Sentry P0 Error 每分鐘 > 10 次
□ 服務 availability < 99%（監控頁面顯示）
□ OpenClaw 決策鏈完全中斷超過 5 分鐘
```
