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

32 KiB
Raw Permalink Blame History

Spec: 商機工作收件匣與產品需求搜尋

Status: approved Status note: 使用者 2026-08-11「批准」 Source: docs/product/opportunity-inbox/requirements.mdapproved 2026-08-11 Parent specs: docs/product/demand-radar/spec.mddocs/product/brand-product-radar/spec.md Last updated: 2026-08-12

1. 摘要

本規格把現有「今日商機」與「全部結果」合併成一個商機工作收件匣,以獨立的 review_state 管理待處理、已完成與已移除,不改變既有加入 CRM、判定合格或拒絕等業務狀態。移除是可復原的軟移除且保留來源 tombstone確保下一次巡邏不會把同一內容重新建立成新商機。

搜尋改為「產品真相 → 需求地圖 → 多組使用者語言 → 去重與前處理 → 輕量排序 → AI 深度判定」。預設推薦分數以產品痛點適配為主,另支援來源發布時間等排序。所有付費動作都沿用既有 meter、平台代付與 BYOK 規則,加入執行前預估、每次巡邏成本上限、階段用量明細,以及同候選同產品輸入版本不重複判定與扣點的契約。

2. 名詞與實體

名詞 定義
OpportunityStatus 既有業務/判定狀態:judging / qualified / rejected / accepted / dismissedaccepted 仍表示已加入 CRM
ReviewState 新增的工作收件匣狀態:pending / completed / removed,與 OpportunityStatus 分開
Soft removal 將 ReviewState 設為 removed 並保存原因、時間與操作者;資料與來源識別仍保留
Source tombstone 已移除商機保留的 owner來源唯一識別後續命中只合併來源不建立新卡、不自動恢復
DemandMap 一個產品可檢查的需求地圖:困擾語言、情境、期望結果、解法意圖與排除訊號
DemandInputVersion 由受眾、痛點、情境、能力、匹配與排除內容決定的產品搜尋輸入版本;純名稱或顯示欄位修改不改版
DemandMapVersion 需求地圖每次有效儲存的版本,供搜尋計畫與判定防重使用
QueryPlan 從目前 DemandMap 產生、符合來源短詞限制的多組搜尋語言與排除語言
CandidateDisposition 前處理結果:pass / review / rejectreject 不進 AI 深判review 可低順位保留或抽樣深判
DemandEvidence 候選原文中表達問題、求助、求推薦、比較或想達成結果的短片段
PriorityScore priority_score0100決定收件匣推薦順序與既有 intent_scoreproduct_fit_score 分開
Billable action 會使用平台代付搜尋或 AI provider 的動作;純 UI、規則前處理與已保存結果讀取不是付費動作
CostPreview 付費動作執行前的點數估計含固定最低值、可能最高值、BYOK 模式及估計依據
CreditCeiling 單次手動工作或每日自動巡邏最多可新增消耗的平台點數;不得超額後再通知

3. 狀態機與不變量

3.1 工作收件匣狀態

pending   --> completed : 使用者標示完成,或成功加入 CRM
completed --> pending   : 使用者恢復待處理
pending   --> removed   : 使用者移除並選原因
completed --> removed   : 使用者移除並選原因
removed   --> pending|completed : 復原到移除前狀態
  • 每筆 Opportunity 恰有一個 ReviewState。
  • completed 只代表使用者已處理,不代表適合/成交/加入 CRM不形成負向訓練訊號。
  • removed 必須保存 removal_reasonother 必須另有非空白說明。原因 enumpain_mismatch / provider_or_ad / stale / already_solved / duplicate / other / legacy_unknown
  • 進入 removed 時保存 previous_review_stateremoved_atremoved_by;復原回到 previous_review_state,缺值時回 pending,並保存最近一次移除紀錄供稽核。
  • 更新成目前相同狀態是 idempotent success不重複寫操作、不產生用量。
  • ReviewState 不得直接改寫 OpportunityStatus。既有 accept 成功後仍設 accepted、綁 Contact另外把 ReviewState 設為 completed
  • dismiss 行為保留相容,但改為設定 OpportunityStatus=dismissed 且 ReviewState=removedreason 空白的舊呼叫保存 legacy_unknown

3.2 舊資料讀取規則

review_state 的既有 Opportunity 依下列順序讀取:

status=accepted  -> completed
status=dismissed -> removed(removal_reason=legacy_unknown)
其他             -> pending
  • 第一次狀態寫入時持久化映射結果;列表讀取不可要求一次性全庫遷移才可用。
  • dismissed 舊資料復原時只恢復 ReviewState既有 OpportunityStatus 保持 dismissed,避免竄改歷史業務狀態。若需要重新成為 qualified仍走既有人工 override。

3.3 去重與 tombstone

  • 沿用「同 owner同來源內容識別只一筆 Opportunity」。來源識別優先用正規化 external ID其次正規化 permalink。
  • 查到既有 removed 商機時,只合併新的 watchterm產品匹配來源與最近命中時間不得建立新 Opportunity、不得自動改回 pending、不得重複深判。
  • duplicate 移除原因可保存 duplicate_of_opportunity_id;被指向的主卡不存在或不屬於同 owner 時拒絕操作。
  • tombstone 沿用既有資料保留政策P0 不提供不可逆硬刪除 API。

4. 搜尋、前處理與排名契約

4.1 DemandMap 結構

每個產品目前版本只有一份生效 DemandMap

DemandMap = {
  product_id, demand_input_version, map_version, state,
  pain_phrases[], scenario_phrases[], desired_outcomes[],
  solution_signals[], exclusion_signals[],
  source_basis[], custom_phrases[], ai_enriched_at?, updated_at
}
  • stateready / incomplete / stale
  • 每個 phrase 保存 textkindbasis_kindbasis_textorigin=product|user|aienabled;不得只保存無法追溯來源的模型輸出。
  • 系統從 BrandProduct 真相建立免費 baseline不得為了開頁或每日巡邏自動呼叫 AI。
  • 使用者手動編輯與啟停 phrase 不扣點,每次有效儲存增加 map_version。
  • AI enrichment 是明確的手動付費動作;成功後新增 AI phrases 並保存來源依據,不覆寫使用者自訂內容。
  • 產品受眾、痛點、情境、能力、匹配或排除內容實質變更時DemandInputVersion 改變;舊 AI enrichment 失效,免費 baseline 以新產品真相重建,使用者自訂內容保留但標示待確認。
  • 純品牌/產品名稱、圖片或顯示順序修改不改 DemandInputVersion也不允許重新扣同候選深判點數。
  • baseline 缺少痛點且缺少情境/期望結果時為 incomplete;可保存但不能啟動新的產品巡邏,畫面引導補產品資料。

4.2 QueryPlan

  1. 只從 enabled DemandMap phrases 產生符合 Threads 短詞契約的 16 組查詢;每組至少包含困擾/情境/期望結果之一,產品名不得單獨成組。
  2. solution signals 用於提升求助、求推薦、比較與購買意圖召回exclusion signals 傳給既有排除流程。
  3. 同義表達分散在不同查詢組,結果在 owner 層統一去重;增加 query 組數不得繞過單次 CostPreview 與 CreditCeiling。
  4. 每次 Sweep 保存實際使用的 demand_input_version、map_version 與 query plan 摘要,使結果可重現。
  5. 使用者手動修改 watch terms 時仍可使用,但 UI 顯示它們與 DemandMap 的關聯;純產品名 term 只能輔助召回,不能提供排名證據。

4.3 候選前處理

候選依序經過下列不呼叫 AI provider 的階段;每階段保存計數與 machine reason

  1. 正規化與去重: 正規化 external IDpermalink同一來源只保留資訊最完整的一筆。
  2. 基本有效性: 必須有可用文字與來源;語言不支援、時間未知不直接 reject但留下風險。
  3. 硬排除: 命中產品排除訊號,或明確為同業供給、廣告、品牌公告、抽獎/互追雜訊時 disposition=reject
  4. 證據抽取: 從原文擷取 DemandEvidence找不到任何問題、求助、比較、求推薦或期望結果訊號時 disposition 至少降為 review
  5. 產品證據: 用 DemandMap 對困擾、情境、期望結果做輕量比對;產品名/品牌名命中不計分。
  6. 分流: 同時具備 DemandEvidence 與至少一項產品證據為 pass;只有其中一項為 review;兩者皆無為 reject
  • reject 候選不進 AI 深度判定也不建立高低商機Sweep 保留原因計數,不保存作者敏感資訊的額外副本。
  • review 候選可按輕量分數進入低順位結果或在 CreditCeiling 內抽樣深判;不得標為高順位。
  • 已存在且已有同 DemandInputVersionDemandMapVersion 有效判定的候選直接復用,不再呼叫 AI。

4.4 AI 深度判定

  • 只對 pass 的高價值候選及部分 review 不確定候選執行,順序以輕量產品證據、需求意圖與新鮮度排列。
  • 輸出必須包含結構化 DemandEvidence、產品適配證據、排除風險與各分數所有正向重要理由都須引用候選原文片段及 DemandMap產品依據。
  • AI 不得用品牌名、產品名或搜尋詞本身補成痛點證據;不得推測作者未公開的身分、預算或敏感屬性。
  • 結構不完整、證據無法在原文找到或產品依據不存在時,該判定失敗且不得保存為有效結果;工作可在剩餘 CreditCeiling 內繼續下一筆。
  • 判定結果為不適合但 provider 已成功完成有效結構化工作,仍正常計點並保存拒絕原因,避免日後重判重扣。

4.5 推薦分數與硬門檻

priority_score = pain_fit(0..45)
               + demand_intent(0..25)
               + evidence_quality(0..15)
               + freshness(0..15)
因子 行為定義
pain_fit 原文對 Product 痛點、情境或期望結果的適配;至少一項有可引用證據才可大於 0
demand_intent 是否正在求助、求推薦、比較方案、表達想改善或準備採取行動
evidence_quality 引文是否直接、完整且同時支持需求與產品適配;只有推測時為 0
freshness 沿用來源 posted_at 時效衰減;未知時間為 0不得視為最新
priority_band = high   if score >= 75 and hard gates pass
                review if score 45..74 and hard gates pass
                low    otherwise but has basic demand + product evidence

高順位 hard gates

  • 至少一段 DemandEvidence。
  • 至少一項痛點、情境或期望結果的產品證據。
  • 非 provider廣告公告雜訊且沒有產品硬排除。
  • 不能只靠品牌名、產品名或 matched term。
  • 來源與引文可回看;證據不足只能進 reviewlow。

排序 enum

sort 排序
recommended priority_score desc → product_fit_score desc → posted_at desc → id asc
newest 已知 posted_at desc → priority_score desc未知時間置底
oldest 已知 posted_at asc → priority_score desc未知時間置底
product_fit product_fit_score desc → priority_score desc → posted_at desc
demand_intent demand_intent desc → priority_score desc → posted_at desc
  • 所有分頁排序必須穩定,最後以 id tie-break禁止前端只對單頁資料重排。
  • sort=score 相容映射為 recommended,舊 sort=posted 相容映射為 newest

5. 扣點與配額契約

5.1 免費與付費邊界

動作 平台點數
開頁、列表、詳情、篩選、排序 0
完成、移除、復原、選移除原因 0
baseline DemandMap 建立、手動編輯、QueryPlan 規則產生 0
去重、硬排除、證據抽取、輕量排序 0
API path 搜尋 沿用既有 web_search 單次成本與 radar.* source
crawler path 搜尋 沿用既有 crawlerBYOK 計量行為,不臆造平台搜尋點數
DemandMap AI enrichment 沿用既有 AI meter以獨立 radar.demand_map source 歸因
AI 深度判定 沿用既有 AI research判定 meterradar.judge source 歸因
回覆生成 Retain 既有 meter 與按需生成規則
  • 不新增第五種 usage meterradar.* source 只用於歸因。
  • BYOK 的平台 credits 一律為 0但 count、source、工作統計仍增加。

5.2 CostPreview 與執行確認

CostPreview 回傳:

{
  action, key_mode,
  fixed_credits, min_credits, max_credits,
  search_calls, max_ai_candidates,
  remaining_credits, estimate_basis, expires_at
}
  • 取得 preview 本身不扣點。
  • 手動搜尋巡邏、AI enrichment、批次深判與回覆生成在 UI 觸發前取得 preview固定成本顯示確值候選數未知時顯示範圍不假裝精準。
  • 使用者確認時送出 preview_idcredit_ceiling。preview 過期、產品query plan 改版或目前餘額不足時,執行前拒絕並要求重新確認。
  • 單筆既有固定成本的動作仍可由既有用量 metadata 顯示;若沒有變動成本,不必多一個確認步驟,但按鈕附近必須標示點數。

5.3 實際計點、防重與失敗

  1. provider 呼叫前通過會員額度、meter soft cap、preview 及 CreditCeiling gate。
  2. provider 未被呼叫,或呼叫未產生既有計量規則認定的有效工作,不 commit 點數。
  3. 搜尋 provider 成功返回(即使 0 hitcommit 搜尋點數。
  4. AI 成功返回可驗證的完整判定後commit 該候選判定點數;結果 rejected 仍計點。
  5. AI 輸出結構無效或不可驗證時,沿用既有失敗退點語意,不把失敗結果加入有效判定快取。
  6. 有效判定唯一鍵為 owner來源識別product_iddemand_input_versionmap_versionjudge_kind命中即復用重試、跨 watch 或跨 query 不再扣。
  7. Job 中斷重跑時,逐筆跳過已 commit 且已有有效結果的唯一鍵;不得只靠整批成功旗標防重。
  8. 達 CreditCeiling 或方案點數上限時停止新的 provider 呼叫,已完成結果保留,剩餘候選記 budget_deferred_count;不得把工作標成完整成功。

5.4 自動巡邏成本上限

  • P0 沿用方案既有雷達與 AI 配額作預設 CreditCeiling不新增每產品自訂額度自訂額度列 P1。
  • 每日排程不逐次詢問,但開始前仍建立系統 CostPreview 快照供對帳。
  • 多個 watch 共用 owner 當日剩餘額度;排程不得因先處理某個 watch 而突破會員方案上限。
  • 點數不足不刪除、不封存 watch該 Sweep 顯示 partial_budgetblocked_budget,並保留未判定數量。

6. 使用者流程(行為)

6.1 第一次進入商機收件匣

  1. 使用者進 /app/radar/opportunities,預設 review_state=pendingtime_scope=todaysort=recommended
  2. 頁首只顯示待決定/已處理/已移除、時間範圍與排序;品牌、產品、意向、匹配狀態收進「更多篩選」。
  3. 卡片首層顯示問題摘要、適合產品、單段最強證據、priority scoreband、posted_at 與三個明確決策:「加入名單並追蹤/只標示已處理/不適合」。
  4. 「加入名單並追蹤」成功後 OpportunityStatus=accepted 且 ReviewState=completed,顯示前往該 Contact 的入口;「只標示已處理」不建立 Contact。
  5. 使用者展開完整判定後仍可直接加入名單或只標示已處理,不必關閉詳情回卡片操作。
  6. 無結果時依 no watch、尚未巡邏、全部被前處理排除、點數不足、巡邏失敗、篩選後為空分別提示不回一個無解釋的空白頁。

6.2 完成、移除與復原

  1. 按「只標示已處理」立即將卡片移出 pending但不建立 Contact操作失敗則回復原畫面並顯示後端訊息。
  2. 按移除先選原因;other 需輸入說明。成功後顯示可復原提示,不觸發 AI。
  3. 已完成/已移除 tab 使用同一列表與排序契約;復原後依 previous_review_state 回到對應 tab。
  4. 加入 CRM 成功後 ReviewState 自動 completed並回傳 Contact 入口;只標示已處理不會自動建立 Contact。兩種整理動作皆不扣點。

6.3 檢查需求地圖與手動探索

  1. 使用者從雷達設定或收件匣次要入口選 BrandProduct查看免費 baseline DemandMap 與資料完整度。
  2. 可免費編輯、啟停 phrases儲存後 preview 顯示下一次探索使用的新 map version。
  3. 若選 AI enrichment先顯示 CostPreview確認後執行失敗不覆寫目前有效地圖。
  4. 手動探索前顯示 QueryPlan 摘要、預估搜尋次數、最多 AI 候選與點數範圍;使用者確認 ceiling 後才排程。
  5. 完成頁顯示 hit、dedupe、prefilter rejectreviewpass、AI judge、createdmerged、budget deferred 與實際點數。

6.4 每日巡邏

  1. worker 驗證 watch、產品與 DemandMapincomplete 時阻擋並通知補產品資料。
  2. 保存系統 preview 與版本,執行 QueryPlan 搜尋。
  3. 依 §4.3 前處理,先復用已有判定,再依輕量順位及剩餘 ceiling 選 AI 深判候選。
  4. 每完成一個可計點階段即記錄可續跑進度;中斷後從未完成候選繼續。
  5. 建立/合併 Opportunity 時保存 priority factors、證據、版本與 ReviewState=pending命中 removed tombstone 只合併來源。
  6. 完成時寫完整 funnel 與點數;部分完成必須標 partial 並顯示未處理數。

7. 介面契約

7.1 共通規則與 Auth

  • 所有 /api/v1/radar/** 只接受會員 Authorization: Bearer <member JWT>owner 隔離沿用既有安全語意。
  • AI provider tokenBYOK key 只供內部 provider 使用,不得出現在 CostPreview、Sweep 或 Opportunity response。
  • 成功 envelopecode=102000messagedataerror;失敗不得回成功空資料。
  • 列表 request page / pageSizeresponse pagination + list
  • 所有時間均為 UTC unix nanoseconds int64
  • 後端契約只由 generate/api/*.api 修改並以 goctl 生成 handlerroute業務行為落在 logicmodule。

7.2 HTTP / API

Method Path 用途 主要 requestresponse
GET /api/v1/radar/opportunities 單一收件匣列表 query 加 review_statetime_scopesortitem 加 review、priority、evidence
GET /api/v1/radar/opportunities/:id 商機詳情 回完整 review audit、priority factors、DemandEvidence 與產品依據
PUT /api/v1/radar/opportunities/:id/review-state 完成、移除、復原 req stateremoval_reason?removal_note?duplicate_of_opportunity_id?;回 Opportunity
POST /api/v1/radar/opportunities/:id/accept 加入 CRM Retain成功時另設 review_state=completed
POST /api/v1/radar/opportunities/:id/dismiss 舊客戶相容 Retain映射 review_state=removed保存 reason 或 legacy_unknown
GET /api/v1/radar/products/:productId/demand-map 讀目前需求地圖 回完整度、inputmap version、phrases 與 stale 資訊
PUT /api/v1/radar/products/:productId/demand-map 免費人工調整 req enabledcustom phrases 與基礎版本;衝突時要求重讀
POST /api/v1/radar/products/:productId/demand-map/enrich AI 擴充 req preview_idcredit_ceiling;回新 map 與 credits_used
GET /api/v1/radar/cost-preview 付費動作預估 query action、watchproductopportunity context回 CostPreview
POST /api/v1/radar/watches/:id/sweep 手動巡邏 req 加 preview_idcredit_ceiling;回 jobsweep 識別
POST /api/v1/radar/explore 手動探索 req 加 map version、preview、ceiling回 funnel 統計與實際耗點
GET /api/v1/radar/sweeps 巡邏紀錄 item 加版本、funnel counts、credit breakdown、budget state
GET /api/v1/radar/today 舊頁相容 Retain 暫時;只回 pendingtoday同新列表排序之後導覽移除

OpportunityPublic 增量:

{
  review_state, previous_review_state?, removal_reason?, removal_note?,
  removed_at?, removed_by?, last_matched_at?,
  priority_score, priority_band,
  priority_factors: { pain_fit, demand_intent, evidence_quality, freshness },
  demand_evidence[], demand_input_version?, demand_map_version?
}

RadarSweepPublic 增量:

{
  demand_input_version?, demand_map_version?,
  hit_count, deduped_count,
  prefilter_pass_count, prefilter_review_count, prefilter_rejected_count,
  cached_judgment_count, judged_count,
  created_count, merged_count, tombstone_matched_count,
  budget_deferred_count,
  status: complete|partial_budget|blocked_budget|failed,
  credits_used,
  credit_breakdown: { search, demand_map, judge, reply }
}

7.3 列表 query 行為

query 預設/說明
review_state pendingcompletedremoved pending
time_scope today7dall today與 fromto 不可同時使用
sort recommendednewestoldestproduct_fitdemand_intent recommended
brand_idproduct_id owner 可見識別 沿用既有 product match filter
priority_band highreviewlow 空表示全部
fromto unix ns UTC 以 posted_at 篩選;未知時間只在 all 且無 fromto 時出現
  • time_scope=today 以會員顯示時區的當地 00:00 換算成 UTC ns 範圍;資料儲存仍只用 UTC ns。
  • time scope、filter、sort、page 寫入 URL重新整理與返回頁面保持相同工作位置。

7.4 前端頁面 / 導覽

路由 目的 主要操作
/app/radar/opportunities 唯一商機工作收件匣 review tab、時間、排序、產品篩選、完成、移除、復原、詳情
/app/radar/today 舊連結相容 redirect 到 opportunities 的 pendingtoday不再顯示第二套頁面
/app/radar/watches 雷達與需求地圖入口 查看完整度、編輯 map、AI enrichment、預覽成本、觸發巡邏
/app/usage 用量追溯 沿用既有 meterradar.* source 查看消耗
  • 導覽只保留一個「商機」入口,不同頁面不得重複出現同一工作清單。
  • mocklive 實作同一 repository 介面、排序、狀態、錯誤與空結果。
  • 沿用 Harbor Desk 與既有 UI 元件;不新增 UI framework。

7.5 Job / 背景任務

Template type Worker 觸發 成功結果
radar_sweep 既有 radar worker 每日排程、首巡、手動巡 按新 funnel 執行guarded 更新完整或 partial 狀態與點數
radar_demand_map_enrich radar worker 使用者確認付費 enrichment 產生可驗證 phrases成功才切換 map version 與 commit 用量
  • Redis lock value 保持 workerID;只有持有者可續期/釋放。
  • Job status 必須 guarded 更新;被取消或已終態的 job 不得被晚到 worker 覆寫。
  • CostPreview 不是 Job不得占用工作佇列或扣點。

7.6 錯誤語意

情境 行為
非 owner 讀寫商機、產品或需求地圖 not foundforbidden 的既有安全語意,不洩漏存在性
review stateremoval reasonsort 不合法 validation error不做部分更新
removed 未帶原因或 other 未帶 note validation error保持原狀態
duplicate 指向不存在、自己或其他 owner validation errornot found保持原狀態
DemandMap 基礎版本過期 conflict回目前版本摘要要求重讀不覆寫
DemandMap incomplete 新巡邏 blocked回缺少哪些產品資訊不回成功空資料
preview 過期或 context 已改版 conflict要求重新預估與確認
ceiling 小於固定成本 執行前 validationquota errorprovider 不被呼叫、不扣點
點數於批次中耗盡 Sweep partial_budget回已完成與 deferred counts
全部候選被前處理排除 Sweep complete 且 created=0回各 reject reason counts非無說明空成功
provider 失敗 沿用 retry退點規則Sweep failed 或 partialwatch 不被刪除

8. 與現況對照

能力 Retain Replace Remove 備註
Opportunity 與 owner來源去重 加 tombstone 行為,不重建第二套實體
intent_scoreproduct_fit_score 保留顯示;新推薦排序用獨立 priority score
ProductMatch 與主推產品 DemandMap 提供更好的證據來源
accepted 加入 CRM 成功後同步 review completed
dismissed 終態 相容讀寫 新 UI 改用可復原 review removed
RadarTodayPage 獨立工作頁 舊 URL redirect 到單一收件匣
RadarOpportunitiesPage 改成唯一收件匣,不再只是封存查詢頁
watch 手工 includeexclude terms QueryPlan 與 DemandMap 提供可追溯建議
目前短詞建議 相容 升級為五類 DemandMap不只回平面 terms
基本 substring exclude分類 成為完整、可觀測的免費前處理 funnel
五問與產品適配 AI 只處理 shortlist輸出可驗證證據並防重扣
既有四 meter、BYOK、方案配額 只加 radar.* source 與預估/明細
今日/全部兩套導覽 時間改為同頁 scope
hard delete 商機 P0 明確不提供

9. 非功能

  • 安全/權限: Brand、Product、DemandMap、Opportunity、CostPreview、Sweep 全部以 owner 隔離;不得回傳 provider token、搜尋 session 或他人存在性。
  • 一致性: review state 更新、移除 audit 與 tombstone 必須同一成功邊界accept 的 CRM binding 與 review completed 不得出現成功訊息但狀態未更新。
  • 冪等性: review state、provider 判定與用量 commit 各自有穩定冪等鍵HTTP 重送及 Job 重跑不重複扣點。
  • 可觀測性: 每 Sweep 保存版本、funnel counts、各階段原因、點數 breakdown、partialblocked 原因;日誌不得含 token 或完整敏感設定。
  • 效能邊界: 列表必須 server-side filtersortpage前處理應在 provider 深判前完成。候選與 AI 最大數受現有搜尋 limit、方案配額與 CreditCeiling 三重上限。
  • 可解釋性: 正向高順位理由必須能回指公開原文與產品DemandMap 依據;找不到原文片段不得保存為高順位證據。
  • 相容性: 缺新欄位的舊資料可讀;舊 sort、today、accept、dismiss 呼叫有明確映射,不要求客戶端同日切換。

10. 資料保存(邏輯層)

實體 關鍵欄位 生命週期
Opportunity review state、previous state、removal fields、priority factors、demand evidence、版本、last matched 既有 owner來源唯一removed 保留 tombstone不硬刪
OpportunityReviewEvent opportunity、fromto、reasonnote、duplicate target、actor、at append-only完成、移除、復原皆留紀錄
DemandMap product、inputmap version、state、五類 phrases、basis、origin 一產品一個 current舊版本保留供既有判定解釋與防重
JudgmentResult owner、來源、product、inputmap version、kind、結果、usage event 唯一鍵防重;有效結果可復用;失敗不當有效快取
CostPreview owner、action、context version、估計、ceiling、expiry 短期保存;只可由同 owner 使用一次啟動工作,不扣點
RadarSweep query版本、funnel counts、status、credit breakdown、deferred 保留供成本、續跑與品質分析;時間 UTC ns
UsageEvent 既有 meter、radar.* source、key mode、credits、count Retain不新增 meter與 Sweep 可對帳

11. 驗收場景Given / When / Then

  1. Given 既有 qualified 商機沒有 review_stateWhen 開啟收件匣,Then 它出現在 pending且讀取不扣點。
  2. Given pending 商機,When 使用者標完成,Then 它移到 completed、未建立 Contact、可免費恢復 pending。
  3. Given pending 商機,When 以 pain_mismatch 移除,Then 它進 removed、保存原因下次同來源命中只更新來源資訊不新建、不重判、不扣判定點。
  4. Given removed 商機先前為 completedWhen 復原,Then 回 completed移除 audit 仍可查。
  5. Given 使用者按加入 CRMWhen Contact binding 成功,Then OpportunityStatus=accepted 且 ReviewState=completed只成功其中一半不得回成功。
  6. Given 產品只有名稱、沒有痛點與情境,When 建 DemandMapThen state=incomplete 且新巡邏被擋下,系統指出缺少資料。
  7. Given 產品痛點有多種使用者口語,When QueryPlan 產生,Then 查詢含困擾/情境/結果語言,產品名不單獨成組。
  8. Given 候選是同業廣告,When 前處理,Then disposition=reject、不呼叫 AI judgeSweep reject count 增加。
  9. Given 候選只有產品名命中,When 排名,Then pain fit 與 evidence quality 不因名稱得分,不能進 high。
  10. Given 候選用不同說法表達同一產品痛點且引用可驗證,When 深判,Then 保存原文 evidence 與產品 basis可依 priority 排到純關鍵字結果前。
  11. Given 三筆相同 priority scoreWhen 分頁查 recommendedThen 依 product fit、posted_at、id 穩定排序,跨頁無重複或跳筆。
  12. Given posted_at 未知,When sort newest 或 oldestThen 該筆都在已知時間之後,不冒充最新或最舊。
  13. Given 手動探索尚未確認,When 取得 CostPreviewThen credits 不變;確認 ceiling 後才可啟動 provider 呼叫。
  14. Given API 搜尋成功但 0 hitWhen Sweep 完成,Then 搜尋點數如實計入、AI judge 為 0畫面說明 no hit。
  15. Given 前處理排除全部候選,When Sweep 完成,Then AI judge 點數為 0並顯示各排除原因而非空白成功。
  16. Given AI 完成結構有效但判定不適合,When 結果保存,Then 該次正常計點並快取 rejected 結果,重跑不再扣。
  17. Given AI 回傳無法驗證的證據,When 判定失敗,Then 不建立有效 JudgmentResult、不 commit 該判定點Sweep 顯示失敗。
  18. Given Job 在第五筆後中斷,When 重跑,Then 前五筆從有效唯一鍵復用,僅未完成候選可能扣點。
  19. Given CreditCeiling 在批次中用完,When 尚有候選,Then 停止新 provider 呼叫、保存已完成結果、status=partial_budget 並回 deferred count。
  20. Given BYOK 會員執行相同流程,When 完成,Then 平台 credits_used=0count、source 與 funnel 統計仍可查。
  21. Given 產品只改名稱,When 同候選再命中,Then DemandInputVersion 不變,不允許重新扣點深判。
  22. Given 產品痛點實質修改,When DemandMap 更新,Then input version 改變、舊 AI phrases 失效、使用者 custom phrases 待確認,重新深判前需新的 CostPreview。
  23. Given 人工標註代表性資料,When 取 recommended 前十,Then 至少八筆同時具備需求與產品適配證據,且 provider公告純名稱命中不在 high。
  24. Given 使用者從舊 /app/radar/today 進入,When 頁面載入,Then redirect 到 opportunities pendingtoday沒有第二份狀態或列表邏輯。

12. 開放規格問題

  1. 無阻擋 P0 的開放問題。每產品自訂 CreditCeiling、批次操作與移除回饋調校均依 requirements 保持 P1不在 P0 偷渡。

13. 批准

  • Spec 已批准2026-08-11使用者
  • 批准後下一步:建立 plan.md,依 Phase B mock 收件匣 → 契約 → Phase C live → Phase D 搜尋與品質閘拆里程碑;本輪不建立 tasks、不修改產品程式。