thread-master/docs/product/demand-radar/tasks/T510-service-profile-model-...

3.0 KiB
Raw Blame History

T510 — service-profile-model-repository

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

Goal

完成後系統應:radar module 有 ServiceProfile domain 與 repositorymongomemory每會員一份可讀寫。

Depends on

  • T501

Inputs

  • Spec../spec.md §2、§4.1、§8
  • 既有 module 模式:apps/backend/internal/module/scout/{domain,repository,usecase}

Outputs

程式變更(預期路徑)

路徑 動作 說明
apps/backend/internal/module/radar/domain/service_profile.go add struct驗證services[](項目+價格區間)、cases[]forbidden[]faq[]service_areas[]remote_okavailabilitytone_note
apps/backend/internal/module/radar/repository/service_profile_mongo.go add radar_service_profiles_id = owner_uid upsert
apps/backend/internal/module/radar/repository/service_profile_memory.go add 測試用
apps/backend/internal/module/radar/usecase/service_profile.go add GetUpsert usecase

行為變更

  • Upsert 為整份覆寫(每會員一份),updated_at 為 ns UTC。
  • Get 未建立時回「不存在」語意,供上層判斷 SP-01 前置條件。
  • 驗證:價格區間下限 ≤ 上限;service_areas[] 為縣市代碼白名單;forbidden[] 去空白去重。

Out of scope

  • HTTP logicT511
  • 判定與回覆如何使用本檔T529T549

Acceptance

  • unit testupsert → get 欄位完整、forbidden[] 可讀、價格區間反向被拒
  • 指令:
cd apps/backend && go test ./internal/module/radar/... -count=1

Notes

縣市代碼白名單放 domain 常數不猜測、不做模糊比對OP-04 行為靠這個約束)。

實作結果2026-07-31

路徑 動作
internal/module/radar/domain/service_profile.go add含 22 個縣市代碼白名單、NormalizeMatchesRegion
internal/module/radar/domain/repository.go addRepository 介面)
internal/module/radar/repository/service_profile_{mongo,memory}.go add
internal/module/radar/usecase/service_profile.go addGetHasUpsert
internal/module/radar/usecase/service_profile_test.go add9 則)

幾個刻意的決定

  • Get 未建檔回 ErrNotFound,不回零值檔案。 「沒建檔」與「建了一份空的」必須分得出來SP-01 的訂閱閘門就是靠這個差別HTTP 層才把它翻成 exists=false 的 200。
  • 價格只在兩端都填時比大小。 只填 price_min 是「起價」、只填 price_max 是「上限」,都是真實的報價方式,硬要成對會逼使用者亂填。填了價格但沒填幣別時補 TWD
  • service_areas 空且 remote_ok=false 直接拒絕。 兩者皆空時,五問判定的地區這一問沒有任何依據可用。
  • Upsert 是整份覆寫,但保留 created_at 不做欄位合併,否則使用者永遠刪不掉一個服務項目或禁語。