thread-master/docs/product/opportunity-inbox/plan.md

283 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Plan: 商機工作收件匣與產品需求搜尋
> Status: `approved`
> Status note: 使用者 2026-08-11「請幫我做」視為批准 plan 並要求進入實作拆解
> Source: `docs/product/opportunity-inbox/spec.md`approved 2026-08-11
> Requirements: `docs/product/opportunity-inbox/requirements.md`approved 2026-08-11
> Baseline: `docs/product/brand-product-radar/` T700T762 done
> Last updated: `2026-08-11`
## 1. 交付策略
1. **保留已完成的產品雷達底座。** Opportunity、ProductMatch、主推產品、owner來源去重、每日巡邏、mocklive repository 均原地擴充,不另建一套商機或抓取系統。
2. **先簡化操作,再擴大後端。** Phase A 只固定新增資料語意、跨層契約與舊資料映射Phase B 先用 mock 驗證單一收件匣、完成移除復原、時間排序、DemandMap 與成本確認。使用者未確認這套操作前,不進入 Phase C 大量業務後端。
3. **先把免費流程做實,再接付費判定。** ReviewState、tombstone、DemandMap baseline、前處理與輕量排序先獨立可測搜尋與 AI 深判最後才接入 CostPreview、CreditCeiling、有效判定快取及既有 usage meter。
4. **分數不互相偷換。** 既有 `intent_score``product_fit_score` 保留,新 `priority_score` 專門服務推薦排序;所有分頁排序由後端穩定執行,前端不只重排當頁。
5. **用漏斗與點數對帳驗收。** 每次巡邏必須能對上 hit → dedupe → prefilter → cache → judge → createdmergedtombstonedeferred以及 searchjudge 實際點數;部分完成不能顯示完整成功。
6. **準確度與成本同時是上線閘門。** 前十至少八筆具有真實需求與產品適配證據,且同候選同版本重試不重扣;任一未達標,先修召回、前處理、排序或冪等,不擴 P1 自動學習。
正式 tasks 每題預估約 100200 行 production change測試或文件可較小但不得把 API、repository、worker、頁面與品質閘塞成單一大題。
## 2. 里程碑
### M0 — Phase A契約、相容與測試地基
- **目標:** 固定 ReviewState、DemandMap、CostPreview、PriorityScore、Sweep funnel 的跨層 shape 與舊資料讀法;尚未完成的能力明確回 not-ready不回成功空資料。
- **完成定義:**
- 盤點並鎖定現有 OpportunityStatus、acceptdismiss、todayopportunities、ProductMatch、Sweep 與 usage 行為,建立不可退化的 baseline tests。
- 只從 `generate/api/radar.api` 擴充 review state、需求地圖、cost preview、列表 query、priorityevidence 與 Sweep funnel 契約,再執行 `make gen-api`;不手寫 handlerroutes。
- goctl 產生的新 logic 在業務尚未完成前回明確 not-ready不得回 `102000` 空物件或空陣列。
- 前端 domain types 與 RadarRepo 加入同一契約mocklive 的方法簽名一致。
- 建立舊資料 fixtureaccepted→completed、dismissed→removed(legacy_unknown)、其他→pending`sort=score|posted` 映射新排序。
- 定義 ownersourceproductinput/map versionjudge kind 的判定冪等測試鍵,但此里程碑不實作深判業務。
- **建議 task 區間:** **T800T806**
- **驗證:** spec 驗收 #1、#11、#12、#24 的契約fixture 層generated code 無手改;前後端 compilebuild。
### M1 — Phase B單一商機收件匣frontend + mock
- **目標:** 先讓第一次使用者只在一個頁面完成「看證據 → 完成或移除 → 查看/復原」;不接真 API。
- **完成定義:**
- `/app/radar/opportunities` 成為唯一商機入口,預設 pendingtodayrecommended`/app/radar/today` redirect 並保留可理解的 query。
- 導覽移除第二個商機結果入口today7dall 只作為同頁時間範圍。
- 卡片首層只顯示問題、主推產品、一段最強證據、分數時間、原文、完成、移除回覆、CRM、其他產品與完整理由放詳情層。
- mock RadarRepo 支援 pendingcompletedremoved、移除原因、復原前狀態、legacy mapping、tombstone 再命中。
- 支援 recommendednewestoldestproduct_fitdemand_intent 與穩定分頁;未知 posted_at 在 newestoldest 均置底。
- filter、sort、time scope、page 寫 URLloading、error、各種 empty reason、操作失敗 rollback 均有明確狀態。
- 完成、移除、復原的 mock 用量保持 0加入 CRM 成功後自動 completed但單純完成不建 Contact。
- **建議 task 區間:** **T810T819**
- **驗證:** spec 驗收 #1#5、#11、#12、#24頁面 keyboardmobile 走查;前端 testbuildlinttoken check。
### M2 — Phase B需求地圖、探索成本與巡邏漏斗frontend + mock
- **目標:** 在任何付費後端開發前,驗證使用者能看懂「系統準備找什麼、可能花幾點、結果為何被排除或延後」。
- **完成定義:**
- `/app/radar/watches` 或其產品詳情提供 DemandMap 五類內容、來源 basis、完整度、AIuserproduct origin 與 stale待確認狀態。
- 免費 baseline、人工新增啟停 phrase 與版本衝突用 mock 完整走通;產品只有名稱時明確 incomplete 並阻擋新巡邏。
- QueryPlan 摘要顯示 16 組使用者語言;純品牌/產品名不能單獨成查詢組。
- AI enrichment、手動 sweepexplore 與回覆按鈕在需要的位置顯示固定點數或範圍;變動成本先開 CostPreview 確認。
- mock CostPreview 覆蓋 platformBYOK、過期、版本變動、餘額不足與 ceiling 小於固定成本。
- mock Sweep 結果顯示 hit、dedupe、prefilter passreviewreject、cache、judge、createdmergedtombstone、deferred 與 credit breakdown。
- `complete / partial_budget / blocked_budget / failed` 的文案與下一步可辨識,不用成功空畫面代替。
- **建議 task 區間:** **T820T829**
- **驗證:** spec 驗收 #6、#7、#13#15、#19、#20、#22人工走查能在執行前回答最多花幾點完成後回答點數花在哪裡。
- **硬閘門:** M1M2 未取得使用者 UX 批准前,不得開始 M3M6 的業務後端。
### M3 — Phase CReviewState、軟移除與穩定列表
- **目標:** 把 Phase B 已批准的收件匣工作狀態接到可信 domain、repository 與 live API保持既有業務狀態相容。
- **完成定義:**
- Opportunity domain 加 ReviewState、previous state、移除欄位與 review auditOpportunityStatus 保留原語意。
- memoryMongo repository 實作 idempotent 狀態更新、append-only audit、duplicate target owner 驗證與 tombstone merge。
- 缺 review 欄位的舊文件讀時映射,不要求全庫回填;首次更新才持久化。
- accept 在 Contact binding 與 completed 之間維持一致成功邊界;舊 dismiss 保存 reason 或 legacy_unknown。
- list 支援 review state、time scopefrom-to、新五種 sort、priority band 與 server-side 穩定 pagination未知時間置底。
- `/today` 使用新列表語意提供相容結果;新 UI 不再依賴 today 專屬商業邏輯。
- migration索引只加入必要查詢與 audit 支援,保留 owner來源唯一性。
- **建議 task 區間:** **T830T839**
- **驗證:** domainmemoryMongo parity、owner isolation、race 與 API integrationspec 驗收 #1#5、#11、#12、#24。
### M4 — Phase CDemandMap、版本與 CostPreview
- **目標:** 以產品真相建立可追溯需求地圖,並在 provider 執行前完成成本預估、版本確認與 ceiling gate。
- **完成定義:**
- DemandMap domain 定義五類 phrase、basis、origin、enabled、inputmap version、readyincompletestale 不變量。
- baseline 只讀 BrandProduct 受眾、痛點、情境、能力、匹配與排除內容,免費建立;不得因開頁或排程自動呼叫 AI。
- input version 只對實質搜尋內容變更名稱圖片等顯示修改不改版。產品內容變更後AI phrases 失效、user phrases 標待確認。
- memoryMongo repository 支援 current map、舊版本解釋、optimistic version conflict 與 owner 隔離。
- QueryPlan 產生 16 組合法短詞與排除訊號,保存使用版本與摘要。
- CostPreview 對 enrichment、manual sweepexplore、批次判定與回覆回固定範圍、key mode、餘額、期限及依據取得 preview 不扣點。
- preview 使用時驗證 owner、action、context version、expiry、remaining credits 與 ceiling不合格時 provider 不被呼叫。
- AI enrichment 走既有 meter 與新 `radar.demand_map` source結構basis 驗證成功才切 current map 並 commit失敗保留舊 map 且不重複扣。
- **建議 task 區間:** **T840T849**
- **驗證:** spec 驗收 #6、#7、#13、#17、#20#22usage event 可與 action 對帳BYOK credits=0。
### M5 — Phase C候選前處理、推薦排序與判定快取
- **目標:** 把昂貴 AI 判定縮到真正高價值或不確定候選,並讓推薦排序比產品名/關鍵字命中更貼近產品痛點。
- **完成定義:**
- 建立可純測試的 candidate preprocessing來源正規化去重、基本有效性、產品排除、provider廣告公告雜訊、DemandEvidence 抽取、產品證據與 passreviewreject。
- 每個 rejectreview 保存 machine reason 與 Sweep counterreject 不進 AI不建立高低商機。
- 輕量 ranking 在 provider 呼叫前排序review 只可低順位或在 ceiling 內抽樣深判,不能直接進 high。
- AI judge 輸出可驗證原文 excerpt、DemandMap產品 basis、風險與 priority factors缺欄位、找不到引文或 basis 不存在即失敗。
- `priority_score=45 pain fit + 25 demand intent + 15 evidence quality + 15 freshness`,並落實 high hard gates。
- JudgmentResult 以 ownersourceproductinput/map versionkind 唯一;有效 acceptedrejected 都可復用,失敗不進快取。
- 逐筆 usage commit 與結果保存具冪等關聯;同候選跨 watchquery、HTTP 重試或 worker 重跑不重扣。
- 建立口語改寫、純名稱、同業銷售、公告、泛討論、未知時間、重複來源與真正求助的固定 fixture。
- **建議 task 區間:** **T850T859**
- **驗證:** tablefixtureAI structured outputconcurrency testsspec 驗收 #8#12、#15#18、#21、#23。
### M6 — Phase C巡邏整合、續跑、live UI 與完整點數對帳
- **目標:** 把 DemandMap、前處理、快取、深判與新收件匣接回每日手動巡邏完成真實可操作的 P0。
- **完成定義:**
- `radar_sweep` 保存 system preview、DemandMapQueryPlan 版本按搜尋→前處理→cache→judge→persist 執行。
- API search 成功 0 hit 仍按既有規則計 search前處理 reject 不計 AI有效 rejected judge 正常計 AI無效 AI 結果走失敗退點語意。
- 每完成一筆保存 guarded checkpoint中斷後只續未完成唯一鍵。Redis lock value 保持 workerID晚到 worker 不覆寫終態。
- CreditCeiling方案額度用完後停止新 provider 呼叫,保留已完成結果並寫 deferredwatch 不刪除、不封存。
- removed tombstone 再命中只合併來源Sweep 增加 tombstone count不新建、不恢復、不重判。
- Sweep API 與 UI 可對帳所有 funnel counts、status、faileddeferred reason 與 searchdemand mapjudgereply credits。
- Phase B 頁面切 live repositorymocklive contract tests 使用同一組 fixturesloading、not-ready、conflict、quota、partial、empty reason 行為一致。
- 完成跨層流程:產品資料 → DemandMap → previewceiling → sweep → prefilterjudge → 收件匣排序 → 完成/移除/復原 → usage 對帳。
- **建議 task 區間:** **T860T869**
- **驗證:** spec 驗收 #1#22、#24 的 live pathintegration、race、restart tests前後端全套 buildtest。
### M7 — Phase D品質閘、成本回歸與安全上線
- **目標:** 以代表性資料證明搜尋更貼近產品且成本可控,再收斂相容路徑、文件與既有回歸。
- **完成定義:**
- 建立人工標註集與可重跑 evaluation有效需求、口語同義、產品不適合、provider、廣告、公告、泛討論、stale、unknown time、duplicate。
- recommended 前十至少八筆同時具備 DemandEvidence 與產品證據provider公告純名稱命中不得為 high。
- 比較 baseline 關鍵字排序與新 pipeline 的 precision@10、AI judged ratio、每筆有效商機平均 credits未達品質或成本閘不宣告完成。
- 多 worker、provider retry、HTTP retry、跨 watchquery、產品僅改名與產品實質改版的防重扣回歸全部通過。
- 回歸 generic radar、ProductMatch、主推產品、回覆、CRM、Scout、Outbox、usage soft caps、BYOK、通知與舊 Opportunity。
- `/today` redirect 與舊 API 相容性保留一個版本週期;文件記錄移除條件,不在本周期直接刪 API。
- 更新 testinggaps操作說明明列 P1批次操作、每產品 ceiling、移除原因調校、產品成本報表。
-`brand-product-radar` T773T775 共用 accuracyraceregression 驗收資產tasks 階段交叉引用一次實作,不複製兩套 fixture 與指令。
- **建議 task 區間:** **T870T879**
- **驗證:** spec 驗收 #16#23、requirements 成功標準全表;全 repo testbuildlinttoken check 綠。
## 3. 依賴與硬閘門
```text
brand-product-radar T700T762已完成底座
└─► M0 Phase A 契約/相容
└─► M1 Phase B 收件匣 mock
└─► M2 Phase B DemandMap成本 mock ──【使用者 UX 批准】
├─► M3 Phase C ReviewState列表
└─► M4 Phase C DemandMapCostPreview
M3 ─┐
M4 ─┴─► M5 Phase C 前處理/排名/快取
└─► M6 Phase C sweeplive ──【P0 live 驗收】
└─► M7 Phase D 品質/成本/回歸
```
| 關係 | 原因 |
|------|------|
| baseline → M0 | 新能力沿用現有 ProductMatch、主推產品、去重與 usage不重做底座 |
| M0 → M1M2 | mock 與 UI 必須使用批准後的共用 shape、legacy mapping 與錯誤語意 |
| M1M2 → M3M6 | **硬性:** 前端mock 操作未批准,不大寫業務後端 |
| M3 ↔ M4 | 可在 UX gate 後分開進行;兩者只透過已凍結契約相遇,不互相直接依賴 repository |
| M3M4 → M5 | 前處理結果需保存到商機/判定快取,且需要 DemandMap 版本與 basis |
| M5 → M6 | worker 不可自己重寫另一套前處理、排序或計費判斷 |
| M6 → M7 | accuracy 與成本只能用真 pipeline、真 funnel 語意驗證 |
| T773T775 ↔ M7 | 舊待辦與本計畫最後閘門範圍重疊;正式 tasks 只建立一次共用輸出並同步兩邊狀態 |
## 4. 風險與緩解
| 風險 | 緩解 |
|------|------|
| ReviewState 與既有 accepteddismissed 混義 | M0 鎖 legacy mappingM1 先驗證用語M3 保持兩個狀態機獨立accept 只做明確同步 |
| 合併頁面反而塞更多資訊 | M1 首層固定七項資訊,其餘進詳情;以第一次使用者走查作 Phase B 硬閘 |
| removed 後相同貼文再次出現 | M3 tombstone 沿用 owner來源唯一鍵M6 sweep 專測再命中只 merge |
| 移除一次就污染後續搜尋 | P0 只保存原因,不立即 AI 調校P1 批次建議仍需人工確認 |
| DemandMap 成為第二份產品真相 | phrase 必須有 basisbaseline 由 Product 建立AIuser 只作可辨識擴充;產品實質變更會改版 |
| 產品改名造成重判重扣 | DemandInputVersion 排除顯示欄位M4M7 專測名稱修改不改版 |
| 廣召回造成 AI 成本暴增 | M5 先免費前處理與 cache再在 ceiling 內 shortlistM7 比較 judged ratio 與每筆有效商機成本 |
| 前處理過嚴造成完全找不到 | reject 與 review 分開review 可低順位保留或抽樣深判Sweep 保存每階段原因供抽查 |
| CostPreview 顯示假精準 | 固定成本顯示確值,候選未知顯示 min/max 與依據;版本或餘額變動即失效重估 |
| provider 成功但後續中斷造成雙扣 | M5 有效判定唯一鍵usage 關聯M6 逐筆 checkpoint重跑只續未完成鍵 |
| ceiling 競態被多 watch 突破 | owner 當日額度在 provider 前 guarded 檢查M6M7 多 worker race 測試 |
| server 與前端排序不一致 | M0 共用 enumM3 server-side stable sortmocklive contract 使用相同 fixture |
| goctl 產生空 logic 被當成功 | M0 每個新 logic 先明確 not-ready只改 `.api` 後 gen業務只在 logicmodule |
| 舊工作樹已有相關修改 | tasks 實作前逐檔比對現況,保留使用者變更;禁止用 resetcheckout 覆蓋,重疊無法安全拆分時停下回報 |
## 5. 刻意不做(本 plan 週期內)
- 不實作 P1 的批次完成/移除、每產品 CreditCeiling、移除原因自動調校與產品成本儀表板。
- 不因每次完成或移除即時呼叫 AI也不自動修改 Product、Brand 或 DemandMap。
- 不提供 Opportunity 不可逆硬刪除,不封鎖作者,不刪除來源內容。
- 不新增 usage meter、不修改 FreeStarterPro 售價,不重做 StripeBYOKprovider 抽象。
- 不重做 Threads APIcrawler、排程器、CRM、Outbox、通知或成果歸因。
- 不用 priority score 取代既有 intentproduct fit 歷史欄位。
- 不保證公開發文者有預算、身分真實或一定購買;只判斷公開需求與產品證據。
- 不在本週期移除舊 `/api/v1/radar/today` 或 dismiss API只提供相容映射與 UI redirect。
## 6. 驗證策略與指令
### 6.1 前端里程碑
```bash
cd apps/web
npm run test
npm run build
npm run lint
npm run check:tokens
```
### 6.2 API 契約或 generated code 變更
```bash
cd apps/backend
make gen-api
go test ./internal/logic/radar/... ./internal/module/radar/... -count=1
make build
```
### 6.3 Phase C 整合與競態
```bash
cd apps/backend
make test-integration
go test ./internal/module/radar/... -race -count=1
go test ./... -count=1
```
### 6.4 Migration 驗證
只使用明確的獨立測試資料庫,不對預設開發資料庫執行:
```bash
cd apps/backend
RADAR_INBOX_TEST_MONGO_URL=mongodb://127.0.0.1:27017/thread_master_opportunity_inbox_test
MONGO_URL="$RADAR_INBOX_TEST_MONGO_URL" make migrate-up
MONGO_URL="$RADAR_INBOX_TEST_MONGO_URL" make init
```
### 6.5 品質與成本閘
正式 task 需提供固定 evaluation 指令,至少輸出:
```text
precision_at_10
high_without_required_evidence
provider_or_announcement_in_high
ai_judged_ratio
credits_per_valid_opportunity
duplicate_judgment_or_charge_count
```
通過條件:`precision_at_10 >= 0.8`、兩種 high 違規數皆為 0、重複判定扣點數為 0AI judged ratio 與每筆有效商機 credits 先記 baseline再由實際成本資料決定 P1 預算優化目標,不在 P0 捏造門檻。
### 6.6 里程碑驗收摘要
| M | 額外驗收 |
|---|----------|
| M0 | 舊 fixture 可讀;新 logic 未完成不回成功空資料goctl 產出乾淨 |
| M1 | 一個頁面完成處理流程today redirect五種排序與 URL 狀態正確;操作不扣點 |
| M2 | DemandMap 與 QueryPlan 看得懂執行前知道成本範圍partialblocked 不裝完整成功;取得 UX 批准 |
| M3 | reviewbusiness state 不混tombstone 不重建memoryMongoAPI 行為一致 |
| M4 | inputmap version 正確preview 免費且會過期provider 前 ceiling gateenrichment 失敗不覆蓋 |
| M5 | provider公告純名稱不進 highreject 不問 AI有效 acceptedrejected 都能防重復用 |
| M6 | 中斷可續、budget partial 可對帳mocklive 行為一致;完整 P0 流程可展示 |
| M7 | precision@10 過 0.8high 違規 0duplicate charge 0全 repo 回歸綠 |
## 7. Task 號段總表(供下一階段拆 task
| 區間 | Phase / Milestone | 內容 |
|------|-------------------|------|
| T800T806 | A / M0 | baseline tests、goctl 契約、not-ready、FE typesrepo、legacysort fixtures、冪等鍵契約 |
| T810T819 | B / M1 | 單一入口、收件匣 layout、review mock、完成移除復原、時間排序、URLemptymobile tests |
| T820T829 | B / M2 | DemandMap mock、phrase editor、QueryPlan、CostPreview、付費確認、Sweep funnel點數、UX gate tests |
| T830T839 | C / M3 | review domainaudit、memoryMongo、migration、tombstone、acceptdismiss 相容、列表 API排序 |
| T840T849 | C / M4 | DemandMap domainrepo、版本、baselineQueryPlan、CostPreview、enrichment、meterBYOK |
| T850T859 | C / M5 | preprocessor、evidence、disposition、priority scorer、AI judge、JudgmentResult cache、冪等計點、fixtures |
| T860T869 | C / M6 | sweep pipeline、checkpointresume、budget partial、counters、live repopages、跨層 P0 integration |
| T870T879 | D / M7 | 標註集、precision成本 evaluation、raceretry、相容與全回歸、文件rollout |
正式拆 tasks 時,每題必須包含 Goal、Depends on、Inputs、Outputs實際路徑行為、Out of scope、Acceptance commands、對應 spec 驗收編號。M1M2 tasks 只能做 frontendmockM3 之後才可寫業務後端。與 `brand-product-radar` T773T775 重疊的測試輸出只能建立一份並由兩邊索引交叉引用。
## 8. 批准
- [x] Plan 已批准2026-08-11使用者
- 批准後下一步:建立 `tasks/INDEX.md` 與各 T8xx task 文件;不在同一輪開始實作。