3.9 KiB
3.9 KiB
T513 — radar-watch-api-crud-quota-gate
Status:
done(2026-07-31)
Milestone:M1
Kind:feat
Est. change:~200 lines
Goal
完成後系統應:watch CRUD/pause/resume/archive API 可用,且未建服務檔案不得建 active watch、超過方案 max_active_watches 明確拒絕。
Depends on
- T511、T512
Inputs
- Spec:
../spec.md§3.1、§4.9、§5.2、§5.6、§9.1(SP-01、RW-01、RW-02、RW-04) - 既有方案/配額讀取:
apps/backend/internal/module/usage/**、billingplan 定義
Outputs
程式變更(預期路徑)
| 路徑 | 動作 | 說明 |
|---|---|---|
apps/backend/generate/api/radar.api |
edit | watches req/resp type 定稿 |
apps/backend/internal/logic/radar/*Watch*Logic.go |
edit | list/create/get/update/delete(archive)/pause/resume |
apps/backend/internal/module/radar/usecase/watch_quota.go |
add | 方案上限查詢與判斷(Free 1/Starter 5/Pro 20) |
apps/backend/internal/module/billing/** 或方案常數檔 |
edit | 新增 max_active_watches、max_daily_opportunities 欄位(不改價格、不動 soft_caps) |
行為變更
- 建立或 resume 成
active前檢查兩道閘:服務檔案存在、active 數 < 上限。 - 兩種拒絕皆為明確錯誤:前者 message 指向服務檔案;後者 message 含「目前上限 N」與升級提示。
- 既有超額者不強制降級(只擋新增)。
DELETE語意為封存(軟刪),非實刪。
API / 契約
GET /watches支援page/pageSize、statusfilter,回pagination+list。
Out of scope
- 手動觸發 sweep(T533)
- 關鍵字建議(T514)
Acceptance
- SP-01:無服務檔案建 active watch → 明確錯誤且指向服務檔案
- RW-01:Free 已有 1 個 active,再建 → 明確錯誤含上限與升級提示
- RW-02/RW-04:pause 後不在 active 清單;archive 後不可 resume
- 指令:
cd apps/backend && make gen-api && go test ./internal/logic/radar/... ./internal/module/radar/... -count=1
Notes
配額欄位加在既有方案定義上,不要新增第五個 usage meter(RG-04)。
Notes(2026-07-31)
| 路徑 | 動作 |
|---|---|
internal/module/usage/domain/usage.go |
edit(PlanDef 加 MaxActiveWatches/MaxDailyOpportunities;Free 1/5、Starter 5/30、Pro 20/100) |
internal/module/usage/usecase/service.go |
edit(新增 PlanFor) |
internal/module/radar/usecase/watch_quota.go |
add(PlanQuota 介面、FixedQuota、assertCanActivate) |
internal/logic/radar/{list,create,get,update,archive,pause,resume}_*_logic.go |
edit |
internal/svc/service_context.go |
edit(radarQuotaBridge 橋接既有方案) |
internal/logic/radar/watch_logic_test.go |
add(8 則) |
- 價格與
soft_caps未動,也沒有新增第五個 meter:兩個新欄位只是方案的規模上限,AI 判定與回覆仍計既有四個 meter。 - 配額介面留在 radar module,實作橋接在
internal/svc。 radar 不反向依賴 usage module。 - 沒接上
PlanQuota時退回最低方案(1/5),不是無上限。 漏接線的後果應該是使用者看到上限提示來問,而不是所有人都拿到 Pro 的常駐監控量。 resume會重驗兩道閘。 暫停期間方案可能已降級,不重驗就等於「暫停再恢復」是繞過上限的後門。測試明確蓋住這條路。- 既有超額訂閱不強制降級(spec §3.1):降級後只擋新增,已經在跑的照跑。
DELETE是軟刪:archive 後列表仍看得到、active_count不含它,歷史商機與統計不動。GET /watches額外回active_count/max_active/profile_exists,讓雷達頁在使用者按下建立之前就能顯示引導或升級提示,而不是等 POST 被拒才說。