# 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 = { 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; 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 觸發條件(須加入 HARD_RULES.md) ``` P0 Hotfix 判定標準(任一條件符合即觸發): □ 統帥無法使用核心功能(簽核按鈕、登入、Telegram 通知) □ Sentry P0 Error 每分鐘 > 10 次 □ 服務 availability < 99%(監控頁面顯示) □ OpenClaw 決策鏈完全中斷超過 5 分鐘 ```