thread-master/docs/product/demand-radar/tasks/T512-radar-watch-model-repo...

3.0 KiB
Raw Blame History

T512 — radar-watch-model-repository

Status: done2026-07-31
Milestone: M1
Kind: feat
Est. change: ~180 lines

Goal

完成後系統應RadarWatch domain 與 repository 就位,狀態機 active | paused | archived 只允許 spec §3.1 的轉移。

Depends on

  • T501

Inputs

  • Spec../spec.md §3.1、§4.2、§8
  • 既有 module 模式:apps/backend/internal/module/scout/**

Outputs

程式變更(預期路徑)

路徑 動作 說明
apps/backend/internal/module/radar/domain/watch.go add struct狀態轉移函式terms[]exclude_terms[]regions[] 正規化
apps/backend/internal/module/radar/repository/watch_mongo.go add CRUD、ListActiveCountActive(owner)TouchLastSweptAt
apps/backend/internal/module/radar/repository/watch_memory.go add 測試用
apps/backend/internal/module/radar/usecase/watch.go add CreateUpdatePauseResumeArchiveList

行為變更

  • archived 為終態:不得再 resume也不再被 ListActive 取到;既有商機與統計不刪。
  • regions[] 留空 = 沿用服務檔案地區(在判定時解析,不在此填值)。
  • terms[] 去空白、去重、大小寫正規化;空 terms[] 不得建立。

Out of scope

  • HTTP logic 與配額閘T513
  • 每日巡排程T527

Acceptance

  • unit testactive↔paused 可往返archived 後 resume 被拒;ListActive 不含 pausedarchived
  • 指令:
cd apps/backend && go test ./internal/module/radar/... -count=1

Notes2026-07-31

路徑 動作
internal/module/radar/domain/watch.go addstruct、CanTransitionWatchTransitionNormalize
internal/module/radar/repository/watch_{mongo,memory}.go add
internal/module/radar/usecase/watch.go addCreateGetListUpdatePauseResumeArchiveMarkSwept
internal/module/radar/usecase/watch_test.go add12 則,含狀態轉移矩陣)
  • term 一律轉小寫並收斂空白(含全形空白)。 Threads 搜尋不分大小寫不正規化的話「Wedding」與「wedding」會被當兩個 termM6 的關鍵字轉換率就會把同一個詞拆成兩列。
  • 同一個詞同時出現在 termsexclude_terms 直接拒絕,那種訂閱永遠不會命中任何東西,讓它建起來只會讓人以為系統壞了。
  • archived 不可逆。 封存後歷史商機與統計都還在,若允許復活,「這批統計是哪個訂閱在什麼期間跑的」就失去單一解釋。要再監控同一組詞請建新的。
  • UpdateWatch 用指標欄位表達「不動」。 nil = 不動、[] = 清空,這樣「只改地區」不會把關鍵字一起清掉。狀態不走 patch。
  • regions 留空不代入服務檔案的值。 判定時才解析,否則之後改服務檔案,舊訂閱會繼續用舊地區而使用者不會知道。