- CLAUDE.md: 紅區治理章節 - Skills 01/03: 版本更新 - ADR/Architecture: 標準化 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.9 KiB
4.9 KiB
Skill 01: AWOOOI Frontend Aesthetics
前端視覺主權守護者
管轄範圍:
apps/web/(Next.js, Zustand, Tailwind) 觸發條件: 任何.tsx,.ts,.css檔案修改
文件資訊
| 欄位 | 值 |
|---|---|
| 版本 | v1.2 |
| 建立日期 | 2026-03-20 (台北) |
| 建立者 | Claude Code |
| 最後修改 | 2026-03-25 23:58 (台北) |
| 修改者 | Claude Code |
變更紀錄
| 版本 | 日期 | 執行者 | 變更內容 |
|---|---|---|---|
| v1.0 | 2026-03-20 | Claude Code | 初始建立 |
| v1.1 | 2026-03-23 | Claude Code | Props Mapping 完整性檢查 |
| v1.2 | 2026-03-25 | Claude Code | 加入文件資訊區塊 |
核心約束 (Iron Laws)
1. Nothing.tech 純白工業風 (絕對標準)
| 元素 | 規範 | 違規處置 |
|---|---|---|
| 背景 | bg-white/70 backdrop-blur-[20px] |
立即修正 |
| 字體 | VT323 點陣風格 |
禁止其他字體 |
| 發光色 | #4A90D9 (Glacier Blue) |
唯一許可強調色 |
| 陰影 | shadow-lg/20 白玻璃效果 |
禁止深色陰影 |
2. i18n 零容忍硬編碼
// ❌ 絕對禁止
<span>確認執行</span>
<span>STATE: IDLE</span>
// ✅ 唯一許可
<span>{t('actions.confirm')}</span>
<span>{t('agent.state')}: {t('agent.idle')}</span>
語言選擇標準 (詳見 feedback_i18n_language_strategy.md):
| 元素 | 語言 | 範例 |
|---|---|---|
| UI 文字/狀態/按鈕 | 繁體中文 | 「系統穩定」「待命」 |
| 技術標識/版本 | 英文 | P0, v1.0.0 |
| 產品名稱 | 英文 | OpenClaw, AWOOOI |
- 所有 UI 文字必須透過
next-intl的useTranslations() - 字典檔案位置:
apps/web/messages/{locale}.json
3. Zustand SSE 狀態管理
// ✅ 正確模式
const buffer = useSSEStore((s) => s.buffer);
const appendChunk = useSSEStore((s) => s.appendChunk);
// ❌ 禁止模式
useState() // 管理 SSE 串流狀態
4. 禁止 Mock Data 掩蓋錯誤
- 所有 API 調用必須處理真實回應
- 無數據時顯示
"--"或空狀態組件 - 禁止使用假數據填充 UI
5. ADR-013 代碼註解規範
強制 JSDoc 場景:
/**
* 簽核待審批請求
* @param id - Approval UUID
* @param signerId - 簽核者 ID (需有對應 Tier 權限)
* @returns 簽核結果,包含是否觸發執行
* @throws {UnauthorizedError} 簽核者權限不足
*/
async function signApproval(id: string, signerId: string): Promise<ApprovalResult>
強制 data-testid:
// 命名: <component>-<element>[-<action>]
<button data-testid="approval-card-approve-btn">
<input data-testid="search-input-filter">
強制驗收程序 (Mandatory Validation)
修改任何 .tsx 後必須執行:
# Step 1: TypeScript 靜態檢查
cd apps/web && pnpm exec tsc --noEmit
# Step 2: 生產建置測試
pnpm run build
# Step 3: Hydration 錯誤檢測 (如有疑慮)
pnpm run dev & sleep 5 && curl -s http://localhost:3000 | grep -i "hydration"
驗收標準
| 檢查項目 | 通過條件 |
|---|---|
| tsc --noEmit | Exit code 0, 無錯誤 |
| pnpm build | 成功完成, 無警告 |
| Hydration | 無 "Hydration mismatch" 錯誤 |
常見陷阱 (Known Pitfalls)
- SSR vs Client State: 使用
useEffect包裝瀏覽器專屬 API - apiBaseUrl 空值: 確保
NEXT_PUBLIC_API_URL在 build-time 注入 - Tailwind Purge: 動態類名需完整拼寫,禁止字串拼接
🚨 Polling + 操作 Race Condition (2026-03-23 教訓)
事故: 簽核卡片按下後消失,所有卡片消失,又全部出現。原因是 Zustand Polling 與 signApproval API 競爭
症狀
- UI 元素閃爍、消失又出現
- 操作後狀態被覆蓋
- Console 無錯誤但行為異常
根因
// ❌ 問題模式: Polling 與操作同時進行
const signApproval = async () => {
await fetch('/api/sign') // 操作 API
// ⚠️ 此時 Polling (5秒一次) 可能已用舊數據覆蓋 state
}
✅ 正確模式: 操作期間暫停 Polling
// apps/web/src/stores/approval.store.ts
signApproval: async (id, signerId, signerName, comment) => {
// 🔧 暫停 Polling
const wasPolling = pollingTimer !== null
if (wasPolling) {
clearInterval(pollingTimer!)
pollingTimer = null
}
try {
const response = await fetch(`/api/v1/approvals/${id}/sign`, {...})
// ... 處理回應 ...
} finally {
// 🔧 延遲 1 秒後恢復 Polling (讓後端有時間更新)
if (wasPolling) {
setTimeout(() => {
get().startPolling(get().pollingInterval || 5000)
}, 1000)
}
}
}
適用場景
- 簽核/拒絕 (Approval)
- 任何會修改後端狀態的操作
- 樂觀更新 (Optimistic Update) 模式
參考文檔
- ADR-002: Nothing.tech 設計系統
apps/web/tailwind.config.ts: 顏色定義apps/web/src/components/ui/: 原子組件庫