# EwoooC 後台 — Codex 開發交接規格 (HANDOFF.md)

> 這份文件是給 Codex（或任何工程團隊）將 prototype 重建為正式 production 專案的完整規格。  
> Prototype 是 React 18 + Babel Standalone（瀏覽器即時 transpile），**不是 production build**。  
> 請依下方規格，重建為正式專案。

---

## 0. 專案概覽

**產品名稱**：EwoooC（內部後台 / 比價爬蟲監控系統）  
**目標使用者**：採購、行銷、營運人員  
**核心功能**：商品價格監控、活動看板、廠商缺貨追蹤、AI 助手、雲端匯入  
**資料規模**：監控 7,000+ 商品，每日掃描多次，含歷史價格走勢

**設計語言（必須沿用）**：Nothing × Claude 混合風格  
- 米色基底（warm paper）+ 黑灰主體 + 焦糖橘 accent  
- JetBrains Mono 用於所有數字、ID、時間戳  
- Inter 用於介面文字、繁體中文用 Noto Sans TC  
- 安靜、結構化、靠留白和排版取勝；**避免**漸層厚重 hero、彩色表頭、五彩按鈕

---

## 1. 技術棧建議

| 類別 | 建議 | 備註 |
|------|------|------|
| Framework | **Next.js 14 + App Router** | SSR、RSC、檔案路由 |
| 語言 | **TypeScript** | 全面型別化 |
| 樣式 | **Tailwind CSS + CSS Variables** | tokens 走 CSS vars，元件用 Tailwind |
| 狀態 / 資料 | **TanStack Query (v5)** | 抓 API、cache、revalidate |
| 表單 | React Hook Form + Zod | 表單驗證 |
| 圖表 | **Recharts** 或 **Visx** | 價格走勢圖、KPI 趨勢 |
| 表格 | **TanStack Table v8** | 排序、篩選、虛擬化 |
| Icon | **Lucide React**（替代現有 SVG icons） | 與 prototype 風格相容 |
| 字型 | next/font 載入 JetBrains Mono + Inter + Noto Sans TC | self-host |
| 部署 | Vercel / 自架 Docker | — |

---

## 2. 路由表（Next.js App Router）

```
app/
├── layout.tsx              # 全域 layout（載字型、tokens、TanStack Provider）
├── (auth)/
│   └── login/page.tsx      # 登入頁
├── (admin)/
│   ├── layout.tsx          # Sidebar + Topbar shell
│   ├── dashboard/page.tsx  # 商品看板（首頁，重導 /）
│   ├── campaigns/
│   │   ├── page.tsx        # 活動看板（含 tab 切換）
│   │   └── [id]/page.tsx   # 單一活動詳情（可選）
│   ├── products/
│   │   ├── page.tsx        # 全商品列表
│   │   └── [id]/page.tsx   # 商品詳情 + 30 天走勢
│   ├── analytics/page.tsx  # 分析報表
│   ├── vendors/page.tsx    # 廠商缺貨
│   ├── ai-assistant/page.tsx # AI 助手
│   ├── cloud-import/page.tsx # 雲端匯入
│   └── settings/page.tsx   # 系統管理
└── api/                    # 若用 BFF，放這
```

**Sidebar 對應**：
- 監控：商品看板（dashboard）、活動看板（campaigns）、分析報表（analytics）
- 營運：廠商缺貨（vendors）、商品列表（products）、訂單（orders）
- 智能：AI 助手（ai-assistant）、雲端匯入（cloud-import）
- 系統：系統管理（settings）

---

## 3. Design Tokens（必讀，直接搬）

來源：`design-tokens.css`（已在交付包根目錄）

**核心變數**（節錄，完整見檔案）：

```css
:root {
  /* 基底色 */
  --momo-bg-primary:  #f0eee9;   /* 米色頁底 */
  --momo-bg-surface:  #ffffff;   /* 卡片白 */
  --momo-bg-paper:    #f7f5f0;   /* 微暖灰白（hover/header） */
  --momo-bg-subtle:   #ebe8e0;
  --momo-bg-muted:    #e6e2d8;

  /* 主體色 */
  --momo-ink:           #1a1a1a;        /* Nothing 黑 */
  --momo-text-primary:  #1a1a1a;
  --momo-text-secondary:#4a4a4a;
  --momo-text-tertiary: #8a8a8a;

  /* Accent */
  --momo-accent:        #c96442;        /* Claude 焦糖橘 */
  --momo-accent-hover:  #b3553a;

  /* 語意色 */
  --momo-success: #16a34a;
  --momo-danger:  #dc2626;
  --momo-warning: #ea580c;
  --momo-info:    #3b5cb8;

  /* 邊線 */
  --momo-border:        #d6d2c8;
  --momo-border-light:  #e6e2d8;

  /* 字型 */
  --momo-font-family-base: 'Inter', 'Noto Sans TC', -apple-system, sans-serif;
  --momo-font-family-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;

  /* 字級 */
  --momo-font-size-xs:   11px;
  --momo-font-size-sm:   13px;
  --momo-font-size-base: 14px;
  --momo-font-size-lg:   16px;

  /* 圓角 */
  --momo-radius-sm:   3px;
  --momo-radius-md:   4px;
  --momo-radius-lg:   8px;
  --momo-radius-pill: 999px;

  /* 陰影 */
  --momo-shadow-sm:  0 1px 2px rgba(0,0,0,0.04);
  --momo-shadow-md:  0 2px 8px rgba(0,0,0,0.06);

  /* 過場 */
  --momo-transition-base: all 0.15s ease;
}
```

**Tailwind 對應建議**：在 `tailwind.config.ts` 用 `theme.extend.colors`、`fontFamily`、`borderRadius` 直接對應上述變數。

---

## 4. 元件清單（重建依據 `app/ui.jsx`）

| 元件 | Props (核心) | 行為 |
|------|--------------|------|
| `<Button>` | variant: gradient \| solid \| outline \| ghost \| secondary \| danger; size: sm/md/lg; icon; iconRight; loading | 主色為 accent，secondary 為米底+黑邊 |
| `<Badge>` | tone: primary/success/danger/warning/info/secondary; dot | 圓角 pill |
| `<Card>` | cardStyle: flat/elevated; padding | flat 為主（border-light + 白底） |
| `<Input>` | icon; size; error | 米底外框，focus 時黑邊 |
| `<Avatar>` | name; size; gradient | 圓形，預設取首字 |
| `<Icon>` | name; size | 統一用 Lucide 替代 |
| `<Modal>` | open; onClose; title; size | 中央 modal，漸出 |
| `<SectionLabel>` | num; children; sub | **重要** — Dashboard 大區塊用「01 / 02 / 03」編號標籤 |

**重要規範**：
- 所有「數字、ID、時間戳、價格」必須使用 Mono 字型（class `momo-mono` 或 Tailwind `font-mono`）
- 表頭 label 用 Mono + uppercase + letter-spacing 0.08em（看起來像終端機）
- 表格不要用紫色漸層 header（已棄用），改用米色 paper 底 + Mono 小字 label

---

## 5. 頁面規格

### 5.1 商品看板 / Dashboard（`/dashboard`）

**參考**：`app/page-dashboard.jsx`

**佈局**（從上到下）：

1. **區塊 01：監控總覽** — 一排 4 個 KPI（horizontal divider 分隔），第二顆「今日變動」用黑底反白
   - 監控總數 / 今日變動（accent）/ 漲價（danger）/ 降價（success）
   - 大字 44px Mono，下方 sub 11px

2. **區塊 02：焦點數據** — 三欄並排
   - 最活躍分類 / 最大變動（紅色 +金額）/ 爬蟲排程（綠點 ACTIVE + 上次執行時間）

3. **區塊 03：商品列表**
   - 篩選列：搜尋 + 分類 select + segmented tabs（全部/新上架/漲價/降價/下架）+ 更新/發送通知按鈕
   - 表格：分類 / 商品名稱（含 emoji 縮圖 + ID）/ 當天價格 / 昨日漲跌 / 週漲跌 / 更新時間 / 上架時間
   - 表頭：米色 paper 底，Mono uppercase 小字
   - 漲跌格子：紅色▲ / 綠色▼ + Mono 數字

**互動**：
- 點 row → 開 Modal 顯示 30 天價格走勢（用 Recharts LineChart）
- 篩選即時觸發（client-side 過濾或 query params）

---

### 5.2 活動看板（`/campaigns`）

**參考**：`app/page-campaigns.jsx`

**佈局**：

1. **活動切換 segmented tabs**（限時搶購 / 1.1狂歡 / 母親節 / 520 / 勞動節）
   - 每顆 tab 含 icon + 名稱 + 商品數 pill

2. **Hero 雙欄**
   - 左 2/3：活動主資訊卡（**漸層背景，色相依活動切換**）
     - flash: 紅橘漸層 / festival: 紫 / mothers: 玫紅 / valentine: 情人紅 / laborday: 藍
     - 點陣裝飾背景 + 大圖示 watermark
     - CAMPAIGN 標籤 + ID + 大標題 + meta（時段 / 最後更新 / 商品總數）+ 操作按鈕
   - 右 1/3：活動數據 KPI（上架/新品/漲價/降價 2x2）+ 底部排程 footer

3. **時段時間軸**（僅限時搶購顯示）
   - 24h 條狀圖，當前時段顯示 NOW 標籤
   - bar 高度依商品數，accent 色為當前

4. **分類 chips**（festival / mothers / valentine / laborday）
   - 橫向 wrap，每個 chip 有名稱 + count pill，可點選

5. **商品列表**
   - 同 Dashboard 表格樣式，但欄位：分類 / 商品資訊 / 價格 / 倒數組數 (限時) 或狀態

---

### 5.3 商品列表（`/products`）

**參考**：`app/page-products.jsx`  
全商品 CRUD + 篩選 + 編輯 modal。可重用 Dashboard 的 ProductTable 元件。

---

### 5.4 廠商缺貨（`/vendors`）

簡單表格：vendor / count / lastSeen，資料來源 `EWOOOC_DATA.outOfStock`。

---

### 5.5 其他頁面

- 分析報表：圖表為主（Recharts），尚未在 prototype 完整定義 → 可先做 placeholder
- AI 助手 / 雲端匯入 / 系統管理：prototype 為佔位 → 與 PM 確認需求

---

## 6. 資料模型 / API 規格

### 6.1 Mock 資料來源

`app/data.jsx` 中 `EWOOOC_DATA` 為所有假資料。**重建時請替換為 API 呼叫**。

### 6.2 建議的 OpenAPI Endpoints

```yaml
GET  /api/dashboard/summary         # 監控總覽 + 今日變動
GET  /api/dashboard/focus           # 最活躍分類 / 最大變動 / 排程狀態
GET  /api/products?category=&q=&tab=&page=  # 商品列表（含篩選）
GET  /api/products/{id}             # 商品詳情
GET  /api/products/{id}/price-history?days=30  # 30 天價格走勢
POST /api/products/{id}/notify      # 發送通知

GET  /api/campaigns                 # 所有活動清單
GET  /api/campaigns/{id}            # 單一活動詳情（含 timeSlots, categories, products, stats）
POST /api/campaigns/{id}/refresh    # 手動觸發爬蟲
POST /api/campaigns/{id}/notify

GET  /api/vendors/out-of-stock      # 廠商缺貨
GET  /api/schedule/status           # 爬蟲排程狀態
```

### 6.3 Schema 範例（TypeScript）

```ts
interface Product {
  id: string;
  category: string;
  name: string;
  emoji?: string;          // 暫時佔位，正式版改為 imageUrl
  imageUrl?: string;
  price: number;
  yesterdayChange: number | null;
  weekChange: number | null;
  updatedAt: string;       // ISO
  listedAt: string;        // ISO
  isNew?: boolean;
}

interface DashboardSummary {
  monitor: { total: number; todayAdded: number; weekGrowth: number; stableCount: number };
  dynamics: {
    priceUp: number; priceDown: number; delisted: number;
    avgUp: number; avgDown: number;
    activity: number; activeCount: number;
    hottestCategory: string; hottestCount: number;
    biggestChange: { product: string; amount: number };
  };
  schedule: { lastRun: string; scanned: number; added: number; status: 'success' | 'running' | 'failed' };
}

interface Campaign {
  id: 'flash' | 'festival' | 'mothers' | 'valentine' | 'laborday';
  name: string;
  icon: string;
  time: string;
  lastUpdate: string;
  total: number;
  schedule: { lastRun: string; anomalies: number; status: string };
  timeSlots?: { time: string; count: number; active?: boolean }[];
  categories?: { name: string; count: number; active?: boolean }[];
  stats: { listed: number; new: number; up: number; down: number; delisted: number };
  products: CampaignProduct[];
}
```

---

## 7. 互動行為清單

| 行為 | 描述 |
|------|------|
| Sidebar 折疊 | 寬度從 240 → 64，icon-only |
| Topbar 搜尋 | ⌘K / Ctrl+K 開啟全域搜尋 |
| 表格 row click | 開啟商品詳情 Modal（含 30 天走勢圖） |
| 漲跌欄排序 | 點欄頭 ↕ 切換 asc/desc |
| 篩選 tabs | 即時過濾，URL 同步 query string |
| 匯出報表 | 後端產 CSV 後 download |
| 發送通知 | trigger backend webhook，回應 toast |
| 活動切換 tab | URL `?tab=flash` 同步 |
| Tweaks 面板 | **正式版可移除**（prototype 用） |

---

## 8. 字型與資源

**Self-host 字型**：
```ts
// app/layout.tsx
import { Inter, JetBrains_Mono, Noto_Sans_TC } from 'next/font/google';
// 對應 CSS variable
```

**Icon**：用 [Lucide](https://lucide.dev/) 替換現有 SVG，名稱對照：
- dashboard → `LayoutDashboard`
- megaphone → `Megaphone`
- chart → `BarChart3`
- box / package → `Package`
- robot / ai → `Bot`
- cloud → `Cloud`
- settings → `Settings`
- search → `Search`
- bell → `Bell`
- refresh → `RefreshCw`
- copy → `Copy`
- download → `Download`
- trendUp → `TrendingUp`
- arrowUp / arrowDown → `ArrowUp` / `ArrowDown`
- clock → `Clock`
- tag → `Tag`

---

## 9. 必須遵守的視覺紀律 ⚠️

❌ **不要**：
- 不要回到原本的紫色漸層 + emoji 圖示風格（舊 momo 後台）
- 不要在表頭用紫色漸層
- 不要用五彩繽紛的按鈕
- 不要在 KPI 卡用厚重藍色 hero 漸層
- 不要使用 Inter 以外的 sans-serif 主體（避開 Roboto, system-ui）
- 數字、ID、時間**不要**用 sans-serif

✅ **要**：
- 米色底 + 黑灰主體 + 焦糖橘 accent
- 區塊用「01 / 02 / 03」編號 + uppercase Mono label
- KPI 大數字 44px+ Mono，靠 horizontal divider 分隔，不要每顆都包卡片
- 活動 hero 才用漸層（且色相依活動主題）
- 表格安靜，靠 Mono 字體和留白做出層次
- 邊框細且淺（border-light），陰影克制

---

## 10. 開發里程碑建議

1. **Week 1**：架構 + tokens + 共用元件（Button/Card/Badge/Input/Modal/Icon/SectionLabel）
2. **Week 2**：Sidebar + Topbar shell + 路由 + Auth
3. **Week 3**：Dashboard（KPIRow / FocusRow / ProductTable）+ API 串接
4. **Week 4**：Campaigns（5 個 tab + Hero + Timeline + Products）
5. **Week 5**：Products 詳情 + 30 天走勢圖 modal
6. **Week 6**：Vendors / Analytics / 其他頁面 + 微調 + QA

---

## 11. 交付包檔案清單

```
ewoooc-handoff/
├── HANDOFF.md                      # ← 本文件
├── EwoooC 後台原型.html            # 入口（瀏覽器直開）
├── design-tokens.css               # 所有 CSS 變數
├── data.jsx                        # （根目錄舊版，可忽略）
├── design-canvas.jsx               # （prototype 工具，可忽略）
├── tweaks-panel.jsx                # （prototype 工具，可忽略）
└── app/
    ├── data.jsx                    # 假資料（轉為 API schema 參考）
    ├── icons.jsx                   # SVG icon 定義（轉為 Lucide）
    ├── ui.jsx                      # 共用元件（轉為 TS components）
    ├── shell.jsx                   # Sidebar + Topbar
    ├── main.jsx                    # 路由分派 + Tweaks
    ├── modals.jsx                  # 商品詳情 / 編輯 modal
    ├── page-dashboard.jsx          # 商品看板
    ├── page-campaigns.jsx          # 活動看板
    ├── page-products.jsx           # 商品列表
    └── page-orders.jsx             # 訂單（範例頁）
```

---

## 12. 與 PM / Designer 確認清單

開發前請與 PM / Designer 對齊：
- [ ] 真實 API endpoint 文件
- [ ] 認證 / 權限模型（RBAC？單一管理者？）
- [ ] 商品 emoji 是否替換為真實圖片（CDN？）
- [ ] Analytics 頁面圖表規格
- [ ] AI 助手 / 雲端匯入功能定義
- [ ] 多語系需求（目前只有繁中）
- [ ] 部署環境（Vercel / 自架 / on-prem）
- [ ] 監控與錯誤追蹤（Sentry？）

---

> 有任何視覺或行為不確定的地方，**以 prototype 的呈現為準**。  
> Prototype 路徑：開啟 `EwoooC 後台原型.html` 直接看 live demo，並用右下角 Tweaks 面板觀察可調整的設計變數。

---

## 13. 2026-05 增量更新（Codex 必讀）

本章記錄 HANDOFF.md 初稿後追加的所有設計決策。**以下優先於前面章節**。

### 13.1 商品看板 — KPI 列強化

KPI 從 4 格擴成 **5 格**，最後一格為「AI 挑品」入口：

| # | label | value | 互動 |
|---|---|---|---|
| 1 | 監控總數 | 7,234 | — |
| 2 | 今日變動 | 2,180（黑底反白）| — |
| 3 | 漲價（danger）| 458 | 點擊 → tab 切到 `up` |
| 4 | 降價（success）| 612 | 點擊 → tab 切到 `down` |
| 5 | **AI 挑品** | 50 ↗ | 點擊 → tab 切到 `ai` 並平滑滾到 §03 商品列表 |

實作：KPI cell 加 `cursor: pointer`，onClick 設 `setTab(...)` + `document.getElementById('product-table')?.scrollIntoView({behavior:'smooth'})`（或等效 ref 滾動）。

### 13.2 商品看板 — FilterBar tabs 順序

```
全部 | AI 揀品 | 新上架 | 漲價 | 降價 | 下架
```

`AI 揀品` tab 對應規則：目前用模擬條件（價格波動 > 8% 或標題含關鍵字）挑出約 1/3 商品，**正式版請改接 `GET /api/products/ai-picks`**（後端 ML 推薦），schema 同 `/api/products` response。

### 13.3 商品看板 — 表格分頁

Client-side 分頁，**50 筆/頁**。Footer 顯示 `1–50 · 共 N 筆` + 上下頁鈕（圖示按鈕，disabled 時 opacity 0.3）。正式版改 server-side：`GET /api/products?page=1&pageSize=50`。

### 13.4 商品看板 — Row hover & 警報欄位

- Row hover 時加左側 3px caramel accent 條（`box-shadow: inset 3px 0 0 var(--momo-warm-caramel)`）。
- 警報 chip 所在 `<td>` 設 `min-width: 140px; white-space: nowrap`，避免 chip 被擠到換行。

### 13.5 PriceHistoryModal（新元件）

點商品 row → 開全螢幕 modal 顯示價格走勢。

**Header**：
- 左：商品縮圖 + 名稱 + ID（mono）
- 右：3 顆 icon-only 操作鈕（加入監控 / 匯出 CSV / 分享連結）+ 關閉

**Body**：
- 區段切換 tabs：`7d` / `30d` / `90d` / `1y`
- LineChart：`days` 改變時呼叫 `buildSeries(days)` 重算資料點
  - 7d / 30d / 90d → 每日一點
  - 1y → 每週一點，共 52 點
- 下方資訊欄：當前價 / 區間最高 / 區間最低 / 變動幅度

**API**：`GET /api/products/{id}/price-history?range=7d|30d|90d|1y` → `{points: [{date, price}], stats: {...}}`

### 13.6 活動看板 — Hero 漸層與點陣

§03 三張活動卡（限時搶購 / 1.1 狂歡 / 母親節）背景：
- 加左上 3×36px caramel accent 條
- 疊一層 `opacity: 0.18` 的點陣紋理（`background-image: radial-gradient(circle, currentColor 1px, transparent 1px); background-size: 8px 8px`）
- §02 三張焦點卡 padding 16px（從 18 收緊）

### 13.7 設計紀律補充

- **絕不使用** emoji 當功能 icon（emoji 只能出現在商品縮圖位置）。
- **絕不**用漸層當大面積背景，僅活動 hero 卡可用，且需配點陣紋理壓低彩度。
- 所有數字、ID、時間戳一律 JetBrains Mono；中文標題用 Noto Sans TC。
- 表格 row 高度 56px、表頭 40px，padding 一律走 tokens。

### 13.8 尚未交付（Phase 2）

以下在 prototype 是 placeholder，正式版需設計 + 實作：
- 分析報表（`/analytics`）— 預期：類別趨勢、競品對比、季節性熱圖
- AI 助手對話流（`/ai-assistant`）— 串 LLM
- 雲端匯入精靈（`/cloud-import`）— S3 / GDrive 連接器
- 系統管理 RBAC（`/settings`）

> 若 prototype 與本章描述衝突，**以 prototype 的實際行為為準**。Codex 可直接讀 `app/page-dashboard.jsx`、`app/modals.jsx`、`app/page-campaigns.jsx` 取得真實實作。
