2.3 KiB
2.3 KiB
T525 — opportunity-model-repository
Status:
done
Milestone:M2
Kind:feat
Est. change:~190 lines
Goal
完成後系統應:Opportunity domain 與 repository 就位,狀態機依 spec §3.2,同 owner 同 external_id 去重且可記錄多個觸發 term。
Depends on
- T501
Inputs
- Spec:
../spec.md§3.2、§3.3、§8、§9.2(OP-06、SW-06) - 既有 module 模式:
apps/backend/internal/module/scout/**
Outputs
程式變更(預期路徑)
| 路徑 | 動作 | 說明 |
|---|---|---|
apps/backend/internal/module/radar/domain/opportunity.go |
add | struct+status 轉移+intent_band 由 score 推導(80/50)+reasons[] 五維度驗證 |
apps/backend/internal/module/radar/repository/opportunity_mongo.go |
add | UpsertByExternalID、ListByOwner(band/status/watch/日期 filter)、CountToday、Get、UpdateStatus、SetOverride |
apps/backend/internal/module/radar/repository/opportunity_memory.go |
add | 測試用 |
行為變更
reasons[]不足五維度時 repository 拒絕寫入(回明確錯誤)——OP-06。UpsertByExternalID:命中既有則只把新的觸發 term 併入matched_terms[],不重複建立、不重跑判定。region_match為三態match|mismatch|unknown;status含judging|qualified|rejected|accepted|dismissed。override記{from_band, to_band, from_status, to_status, actor_uid, at}。
Out of scope
- 判定演算法(T529)與寫入流程(T530)
- HTTP logic(T545/T546/T547)
Acceptance
- unit test:缺一條 reason 被拒;同
external_id兩次 upsert 只有一筆且matched_terms有兩個 - score 79→
mid、80→high、49→low - 指令:
cd apps/backend && go test ./internal/module/radar/... -count=1
Notes
band 門檻 80/50 為 spec 鎖定值,不可在此 task 調整。
實作落點
domain/opportunity.go:status 轉移、BandFromScore(80/50)、ValidateReasons五維度、UTCDayBoundsrepository/opportunity_{memory,mongo}.go:UpsertByExternalID命中只併matched_terms;CountToday/ListOpportunities/SetOpportunityOverride- 測試:
domain/opportunity_test.go、repository/opportunity_memory_test.go