# 前端（apps/web）↔ Spec（haixun-backend）全量對照

> Status: **decisions locked（部分）** · 2026-07-10  
> 目的：在 **重切 task 之前** 確認「前端已有／在用的能力」是否被後端 spec **完整擁有**（可 live 交付），並標出雙向缺口。  
> 輸入：`apps/web` **現在 UI 實際呼叫**（**以 UI 為主**）；`repos.ts`；`spec.md` §4–§5–§9。  
> **範圍原則（2026-07-10 使用者）：以現在 UI 為準；舊靈感捨棄；死 API remove。**

## 0. 總結（先讀這）

| 結論 | 說明 |
|------|------|
| **頁面級大致有對** | Login／Admin／Crew／Studio／Outbox／Jobs／Settings／Scout／Brands／Invite／Usage 在 spec §5.3 都有域 |
| **方法級不夠完整** | Spec §5.2 是域摘要；§9 約 184 ID **未逐一對到** 前端每個在用 API。有一批 **UI 正在用** 的方法在 §9 **沒有獨立驗收** |
| **前端也還沒對齊已批 BYOK** | `UsageEvent` **無** `key_mode`；`UsageMonthSummary` **無** platform／byok 分欄 → 與 spec §4.7 衝突，live 前 FE 必須改契約型別 |
| **OAuth 前端契約缺** | Crew 用 `accounts.createMock`；repo **無** `oauthStart`／callback 消費路徑 |
| **live 未接線** | `createRepos('live')` 仍回 mock（僅 `dataSource: 'live'` 旗標） |
| **刻意不做（P2／mock 專用）** | Insights 真管線、simulate 當 live 完成、公開註冊頁、真金流 |

**因此：以「全部功能完整擁有」標準，目前 spec + 既有 57 tasks 仍不足以保證前端每一條主路徑都有後端＋驗收。**  
應先凍結本對照表 → 補 spec 能力清單／§9 → 再重切 task。

---

## 1. 畫面／導覽 → 後端域

| 前端路由／區塊 | 主要 Repos | Spec 域 | P0/P1/P2 | 對齊 |
|----------------|------------|---------|----------|------|
| `/login` | auth.login | Auth | P0 | ✅ |
| `/forgot-password` `/reset-password` | request/reset password | Auth | P0 | ✅ |
| `/verify-email` | send/verify email | Auth | P0 | ✅ |
| `/app/profile` | updateProfile | Auth | P0 | ✅ |
| `/app/users` | adminUsers.* + usage prefs | Admin + Usage | P0 | ✅ |
| `/app/crew` 帳號 | accounts.* | Threads Accounts | P0 | ⚠️ UI 仍 createMock，缺 OAuth 契約 |
| `/app/crew` 人設 | personas.* | Personas | P1 | ✅ |
| `/app/studio` 方案／Wizard | plays.* | Plays + Outbox | P1 | ⚠️ listByPost／listByExternalUrl 未入 §9 |
| `/app/studio` 單篇 Compose | compose.* + research + media | Compose + Research + Media | P1 | ⚠️ **mimic／analyzeViral** 未入 §9 |
| `/app/studio` 已發 | ownPosts.*（**無** generateFromFormula） | OwnPosts | P1 | ⚠️ **analyzePost** 未入 §9；formula **Remove** |
| `/app/studio` 提及 | mentions.* | Mentions | P1 | ⚠️ **generateReply** 未獨立驗收 |
| `/app/studio` 靈感 | **現 UI 版 only**（session/elements/trends/chat） | Inspiration | P1 | ✅ 範圍鎖定；舊 list/viral/spark **Remove** |
| `/app/outbox` | outbox.* | Outbox + Worker | P1 | ✅（simulate 僅 mock） |
| `/app/jobs` | jobs.* + notifications | Jobs + Notifications | P0 | ✅ |
| `/app/settings` | settings.* + 擴充 ZIP | Settings | P0 | ⚠️ platform_key_available／BYOK 顯示未全 |
| `/app/scout` `/app/brands` | scout.*（**無** topics UI） | Scout | P1 | topics **Remove**；activeBrand 可 CLIENT |
| `/app/invite` | invite.* | Invite | P1 | ✅ |
| `/app/usage` plans checkout | usage.* | Usage | P1 | ⚠️ **分計分顯未進 FE 型別** |
| `/app/today` | trends + ownPosts 摘要 | Inspiration + OwnPosts | P1 輕 | ⚠️ 聚合頁，依賴子域 |
| `/app/insights` | ownPosts + **local** accountInsights | — | **P2** | ⭕ 需求已列 P2；不進 Phase C 後端必做 |
| 公開註冊／三方頁 | — | Auth API 要、頁不做 | 決策 | ✅ 故意 |

---

## 2. Repository 方法全量分類

圖例：

- **MUST** = UI 有呼叫或 live 主路徑必需 → 後端 **必須**有等價 API + 驗收  
- **API-OK** = 後端要有、前端可不開 UI（register／三方）  
- **MOCK** = 僅 mock／除錯；live **不得**當完成定義  
- **CLIENT** = 可前端 state 或本機；後端可選  
- **P2** = 本階段不做後端  
- **DEPRECATED** = 註解已 deprecated，可相容可不做新驗收  

### 2.1 Auth（8 UI + 缺口）

| 方法 | 用途 | 分類 | Spec／§9 | 缺口 |
|------|------|------|----------|------|
| login / logout / me | 登入會話 | MUST | AU-01～09 | — |
| updateProfile | 個人資料／改密 | MUST | AP-04～07 | — |
| requestPasswordReset / resetPassword | 忘密 | MUST | AP-01～03 | — |
| sendEmailVerificationCode / verifyEmail | 驗證 | MUST | AR/AP | — |
| **refresh（token）** | 換 access | MUST | AU-07～08 | **FE AuthRepo 無此方法**；live client 必補 |
| register / 三方 OAuth | 完整會員 API | API-OK | AR / AO | 頁可不做 ✅ |

### 2.2 AdminUsers（8）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| listUsersPage / getUser / createMember / setSuspended / setEmailVerified / setRoles / resetPassword | MUST | AD-01～14 | — |
| listUsers（deprecated 全量） | CLIENT/compat | — | live 可只做 page |

### 2.3 Accounts（4 現有 + OAuth 缺）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list / refreshSession / remove(disconnect) | MUST | TH-05～10 | — |
| **createMock** | MOCK | TH-09 禁止旁路過關 | live **改** oauthStart |
| **oauthStart**（及 callback 由瀏覽器導向後端） | MUST | TH-01～04 | **FE repo／Crew UI 皆無** |

### 2.4 Plays（8）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list / get / save / remove / submit / resolveExternalLink | MUST | PL-01～05,08～09 | — |
| **listByPost** | MUST（PlaysPanel） | **無** | 須補 §5.2 + 驗收 PL-10 類 |
| **listByExternalUrl** | MUST（PlaysPanel） | **無** | 同上 PL-11 |

### 2.5 Outbox（6）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list / get / retryStep / remove | MUST | OB-* | — |
| simulateSuccess / simulateRootFail | MOCK | OB-12 | live 隱藏或 no-op 失敗 |

### 2.6 Jobs / Notifications（3+4）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| jobs.list/get/startDemo | MUST | JB-01～04,09～10 | startDemo = template demo |
| notifications.list/unread/markRead/markAllRead | MUST | JB-05～08 | — |

### 2.7 Settings（7）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| get/save Ai, get/save Placement, listModels | MUST | ST-01～04,14～15 | 應回 platform_key_available／member configured |
| get/set DataSource | CLIENT | — | 前端切 mock\|live，非後端 |
| 擴充 ZIP 下載 | MUST | ST-16 | T157 |

### 2.8 Personas（8）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list/get/getActiveId/setActiveId/save/remove/analyzeFromText/analyzeFromAccount | MUST | PE-01～06 | — |

### 2.9 OwnPosts（現 UI）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list / lastSyncedAt / sync / generateReply / sendReply | MUST | OP-01～05,07 | — |
| **analyzePost** | MUST（OwnPostsPanel 有按鈕） | **無獨立 ID** | 須補 OP-08 + AI 計費 |
| **generateFromFormula** | **REMOVE** | — | UI 未用；後端不做；FE repo 日後刪 |

### 2.10 Mentions（4）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| list / markReplied / skip | MUST | OP-06 偏狀態 | list 應明確 |
| **generateReply** | MUST（MentionsPanel） | **無** | 須補 OP-09 + 計費 |

### 2.11 Inspiration（**僅現 UI 版** · 舊流 Remove）

> 決策 2026-07-10：舊靈感完全捨棄，以 InspirePanel + Today 趨勢為準。

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| listTrends / refreshTrends | MUST（Today + Inspire） | IN-01～02 | — |
| listElements / saveElement / removeElement | MUST | IN-03 | — |
| getSession / saveSession / clearSession / chat(mode=chat\|generate) | MUST | IN-04～05 | — |
| list / saveIdea / generate / bookmarkTrend / listViral | **REMOVE** | — | 後端不做 |
| sparkAngles / sparkAnglesForTopic / sparkFromTrend | **REMOVE** | — | 後端不做 |
| searchTrends | **REMOVE**（UI 未呼叫） | — | 後端不做 |

### 2.12 Research / Media（1+2）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| research.search | MUST | IN-06 + ST/USG | — |
| media.generateImage | MUST | IN-07 | — |
| media.attachLocal | MUST（附圖） | IN-08～09 | **真上傳** → 持久 url；非法失敗；非 data URL 冒充 live |

### 2.13 Compose（3）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| publishSingle(+schedule) | MUST | PL-06～08 | — |
| **mimic** | MUST（ComposerPanel） | **無** | 須補 + AI 計費（ai_copy） |
| **analyzeViral** | MUST（ComposerPanel） | **無** | 須補 + AI 計費 |

### 2.14 Scout（31）

| 方法群 | 分類 | §9 | 缺口 |
|--------|------|-----|------|
| brands CRUD, products CRUD, importProductFromUrl | MUST | SC-01～02,14 | — |
| prepareBrief / runScanFromBrief / listPosts | MUST | SC-03～08 | — |
| draftOutreach / skip / markPublished / sendOutreach | MUST | SC-09～11 | — |
| removePost / removeTheme | MUST | SC-12 | — |
| homework list/save/get/remove | MUST | SC-13 | — |
| runScan / getScanContext | compat | 對齊 runScanFromBrief | 可映射 |
| getActiveBrandId / setActiveBrandId | CLIENT | — | 前端 local／session 即可 |
| **listTopics / saveTopic / removeTopic** | **REMOVE** | — | **無 UI 呼叫**；後端不做 |

### 2.15 Usage（10）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| getSummary / listEvents | MUST | USG-01～08 | **FE 型別缺 key_mode／byok 分欄** |
| getPlanId / purchasePlan / listMyPurchases | MUST | USG-11 | listMyPurchases 應補 §9 |
| getMemberPrefs / setMemberPrefs | MUST | USG-12～14 | — |
| getTenantSummary / getTenantAnalytics | MUST admin | USG-10 | analytics 序列分 platform/byok |
| setPlanId | admin／self 語意混 | 與 setMemberPrefs 重疊 | 契約要寫清 |

### 2.16 Invite（5）

| 方法 | 分類 | §9 | 缺口 |
|------|------|-----|------|
| getMyNetwork / applyInviteCode / getTree / moveMember / listParentCandidates | MUST | IV-01～13 | — |

### 2.17 非 Repo 但重要

| 能力 | 分類 | 說明 |
|------|------|------|
| Insights 頁 | P2 | localStorage 報表；requirements 已列 P2 |
| Job templates（persona_analyze、threads_sync、scout_scan、outbox_publish） | MUST | spec §5.4；worker |
| 數字 uid | MUST | FE 現 `uid: string`；live 可 number→string 顯示但 JSON number |
| BYOK 分顯 | MUST | FE Usage UI 需改；T155 有提但型別未改 |

---

## 3. Spec 有、前端尚未具備的 live 契約

| Spec | 前端現況 | 動作 |
|------|----------|------|
| oauthStart / OAuth 綁帳 | createMock | **改 AccountsRepo + Crew UI**（可 mock 保留 createMock） |
| Auth refresh | 無 repo 方法 | **補 AuthRepo.refresh** |
| Usage key_mode / platform vs byok summary | 無欄位 | **改 usageMeter 型別 + Usage 頁** |
| Settings platform_key_available | 僅 member configured | **擴 AiSettings／Placement 顯示** |
| 成功 envelope 102000 | live 未接 | live HTTP client |
| 未實作不回空成功 | live 未接 | 同上 |
| register／三方 API | 無頁 | 後端做即可（決策） |

---

## 4. 前端在用、Spec／§9 不足（必須補進「完整擁有」）

下列建議在 **重切 task 前** 寫入 `spec.md` §5.2 與 §9（新 ID）：

| # | 能力 | 建議驗收 ID | 優先 |
|---|------|-------------|------|
| 1 | plays.listByPost | PL-10 | P1 |
| 2 | plays.listByExternalUrl | PL-11 | P1 |
| 3 | compose.mimic | CP-01（或 PL-12）+ 計費 | P1 |
| 4 | compose.analyzeViral | CP-02 + 計費 | P1 |
| 5 | ownPosts.analyzePost | OP-08 + 計費 | P1 |
| 6 | mentions.list + generateReply | OP-09～10 + 計費 | P1 |
| 7 | usage.listMyPurchases | USG-15 | P1 |
| 8 | usage key_mode／byok 分欄 | FE 型別 + USG | P0 契約 |
| 9 | AuthRepo.refresh | 對齊 AU-07 | P0 前端 live |
| 10 | accounts.oauthStart | 對齊 TH-01；取代 createMock 主路徑 | P0 前端 live |
| — | 舊靈感／topics／generateFromFormula | — | **REMOVE · 不做** |

---

## 5. 與現有 Tasks 的關係（為何先不重切）

| 現況 | 問題 |
|------|------|
| 57 tasks 依域粗切 | 未保證上表 MUST 方法都有 API task + 測試 case |
| T171「fe live studio」 | 一行無法覆蓋 PlaysPanel + Compose mimic/viral + OwnPosts analyze + Mentions generate |
| T155 usage byok display | FE 型別尚未定義分欄 → task 輸入不足 |
| T135 accounts live | 未強制改掉 createMock → OAuth |

**建議流程：**

```text
1) ~~開放題 1–6~~ ✅ 已鎖
2) ~~spec / requirements 回寫關鍵決策~~ ✅
3) 重切 tasks（UI MUST + 測試 + FE live + apps/backend）← 下一步
4) ready-to-implement
```

---

## 6. 已鎖定決策（2026-07-10）

| # | 議題 | 決策 |
|---|------|------|
| 1 | 舊靈感 API | **完全捨棄**。後端／驗收只做 **現 UI**：trends、elements、session、chat。list／saveIdea／generate／bookmark／listViral／spark*／searchTrends → **Remove** |
| 2 | generateFromFormula | **Remove**（UI 未用；後端不做） |
| 3 | 範圍原則 | **以現在 UI 為主**：有按鈕／主路徑呼叫 = MUST；僅 mock／死碼 = Remove 或 P2 |
| — | Scout topics | **Remove**（無 page 呼叫，跟 UI 原則） |
| 4 | attachLocal / 附圖 | **真上傳**（後端收檔 → 持久可取 URL；禁止只靠本機 data URL 當 live 完成） |
| 5 | Insights | **維持 P2**（頁面可 local 算；Phase C 後端不做真數據管線） |
| 6 | FE uid | **可以**：API JSON **number**；前端顯示／比對用 toString 即可 |

### 靈感：後端 MUST 清單（凍結）

```text
listTrends / refreshTrends
listElements / saveElement / removeElement
getSession / saveSession / clearSession
chat({ message, pinnedIds, mode: chat|generate })
```

### 明確 Remove（後端不實作、不進 §9）

```text
inspiration: list, saveIdea, generate, bookmarkTrend, listViral,
             sparkAngles, sparkAnglesForTopic, sparkFromTrend, searchTrends
ownPosts: generateFromFormula
scout: listTopics, saveTopic, removeTopic
outbox: simulate*（live 完成定義）
accounts: createMock（live 主路徑；mock 模式可留）
```

### 媒體上傳（凍結 · 決策 #4）

```text
media.attach / upload（對齊 FE attachLocal 語意）
  → 真 multipart（或等價）上傳
  → 回可跨裝置使用的 url（及 id）
  → 非法／過大失敗可讀
  → 不可 102000 + 空成功
```

儲存介面（本機 disk / S3 / 其他）實作可選，但驗收以「真上傳 + 可取 URL」為準。

### 實作清潔（不擋定義）

- FE 清掉 Remove 方法的 repo 型別（可併 live 接線 task）  
- Member.uid 型別：live 適配 number → 顯示 string  

---

## 7. 統計（粗）

| 項目 | 數 |
|------|-----|
| repos.ts 唯一方法名 | ~119 |
| UI 有呼叫（抽樣 grep）的主路徑 MUST | 估計 **75–90** |
| §9 現有 ID | 184（含權限／失敗／工程，非 1:1 方法） |
| 明確 MUST 但 §9 缺口 | **≥ 8**（§4 表）+ BYOK FE 契約 + OAuth FE |
| MOCK／P2／DEPRECATED 可排除 | simulate、createMock、Insights 真管線、spark*、公開註冊頁 |

---

## 8. 批准欄

- [x] 範圍原則：以現在 UI 為主  
- [x] 舊靈感捨棄；generateFromFormula／topics Remove  
- [x] #4 真上傳 · #5 Insights 維持 P2 · #6 uid number + toString 可以  
- [x] requirements #16–21、spec §5.2／§6／§9（含 IN-08～09）已回寫  
- [x] **tasks v3 approved**（「ok同意」）→ `ready-to-implement`；指定 T### 才寫碼
- [x] 已回寫 requirements 決策 #16–18、spec §5.2／§6／§9 補 PL-10～11、CP-01～02、OP-08～11  
- [ ] **授權補齊其餘 §9 細項後重切 tasks**（下一步）
