CD 修復: - 修復 buildx HTTP vs HTTPS 問題 (insecure registry 設定) - 移除 UAT 環境 (違反 Memory 鐵律) - 新增 Production 部署 Telegram 通知 - 修復 deploy-prod.yml 硬編碼 Token (改用 secrets) docs: - 新增 guidelines/ 結構化指引目錄 - ARCHITECTURE.md, FRONTEND.md, OPERATIONS.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
3.0 KiB
3.0 KiB
AWOOOI 前端指引
前端開發的核心原則與規範
快速索引
| 主題 | 核心原則 | 詳細章節 |
|---|---|---|
| i18n | 100% next-intl,零硬編碼 | → i18n |
| 視覺 | Nothing.tech 風格 | → 視覺規範 |
| 狀態 | Zustand (禁止 Redux) | → 狀態管理 |
| 數據 | 真實 API,禁止假數據 | → 數據規範 |
i18n 雙語
Memory 來源: feedback_i18n_zero_hardcode.md, feedback_naming_i18n.md
鐵律
// ❌ 禁止 - 任何硬編碼文字
<button>Submit</button>
<span>Loading...</span>
<p>System Status</p>
// ✅ 正確 - 100% next-intl
<button>{t('common.submit')}</button>
<span>{t('common.loading')}</span>
<p>{t('dashboard.systemStatus')}</p>
支援語言
zh-TW- 繁體中文 (預設)en- English
翻譯檔位置
apps/web/src/messages/
├── zh-TW.json
└── en.json
新增翻譯流程
- 在
zh-TW.json新增 key - 在
en.json新增對應翻譯 - 在組件使用
t('your.key')
視覺規範
Memory 來源: feedback_naming_i18n.md
Nothing.tech 風格
- 白玻璃毛玻璃效果 (awoooi-glass)
- 點陣紋理背景
- DataPincer 數據鉗容器
- 黑白紅極簡配色
顏色系統
/* 主色 */
--nothing-black: #000000
--nothing-white: #ffffff
--claw-red: #ff0000
/* 狀態色 */
--status-healthy: #00ff00
--status-warning: #ffaa00
--status-critical: #ff0000
組件規範
// DataPincerPanel - 標準容器
<DataPincerPanel title={t('dashboard.title')} status="healthy">
{children}
</DataPincerPanel>
// DataPincerCard - 卡片容器
<DataPincerCard>
{content}
</DataPincerCard>
狀態管理
Memory 來源: ADR-004
鐵律
// ❌ 禁止 - Redux
import { useSelector } from 'react-redux'
// ✅ 正確 - Zustand
import { useStore } from '@/stores/xxx.store'
Store 結構
apps/web/src/stores/
├── agent.store.ts - Agent 狀態
├── incident.store.ts - Incident 狀態
└── ui.store.ts - UI 狀態
數據規範
Memory 來源: feedback_no_fake_data.md
鐵律
// ❌ 禁止 - 假數據
const data = DEMO_DATA
const mockMetrics = generateMockData()
// ✅ 正確 - 真實 API
const { data } = useRealAPI()
const { metrics } = useGlobalPulseMetrics()
2026-03-23 教訓
GlobalPulseChartDemo 使用假數據,導致用戶無法看到真實系統狀態。已修正為 GlobalPulseChart 連接真實 API。
Loading/Error 處理
const { data, isLoading, error } = useAPI()
if (isLoading) return <Spinner />
if (error) return <ErrorState message={error} />
return <RealData data={data} />