thread-master/docs/product/demand-radar/tasks/T500-api-shells-radar-crm-g...

76 lines
3.3 KiB
Markdown
Raw Normal View History

2026-08-03 05:52:02 +00:00
# T500 — api-shells-radar-crm-goctl
> Status: `done`2026-07-31
> Milestone: `M0`
> Kind: `feat`
> Est. change: `~180 lines`
## Goal
完成後系統應:`radar` 與 `crm` 兩個 group 的路由由 goctl 產出並可打通,所有尚未實作的能力回**明確未就緒錯誤**(禁止 `102000` 空成功)。
## Depends on
-
## Inputs
- Spec`../spec.md` §5.1、§5.2、§5.6
- 既有契約檔範例:`apps/backend/generate/api/growth.api`、`scout` 相關段落
- `AGENTS.md`:後端一律 goctl禁止手寫 handlerroutes
## Outputs
### 程式變更(預期路徑)
| 路徑 | 動作 | 說明 |
|------|------|------|
| `apps/backend/generate/api/radar.api` | add | service-profilewatchestodayopportunitiessweeps 全部 route 與 type |
| `apps/backend/generate/api/crm.api` | add | contactsfollowupsstats 全部 route 與 type |
| `apps/backend/generate/api/gateway.api` | edit | import 兩個新契約檔 |
| `apps/backend/internal/handler/**`、`routes.go` | generated | `make gen-api` 產出,**不手寫** |
| `apps/backend/internal/logic/radar/**` | add | logic 殼,一律回未就緒錯誤 |
| `apps/backend/internal/logic/crm/**` | add | logic 殼,一律回未就緒錯誤 |
### 行為變更
- 新路由存在且需 Bearer JWT`owner_uid` 取登入 uid。
- 未實作能力回明確 error codemessage`radar capability not ready`**不是** `102000` + 空 `data`
### API / 契約
- 依 spec §5.2 全表建立 route`P1` 的 `/api/v1/radar/import` 先不建。
- 列表型 request 一律 `page``pageSize``pageSize ≤ 50`response `pagination` + `list`
- 時間欄位一律 `int64` unix nanoseconds。
## Out of scope
- 任何業務邏輯與 Mongo 讀寫T510 起)
- Mongo 索引T501
- 前端接線T502
## Acceptance
- [x] `make gen-api``git status` 顯示 handlerroutes 為產生物,非手改
- [x] 每個新 route 回未就緒錯誤且**非** `102000`(以 34 個 capability 測試取代 curl斷言 HTTP 501`code≠102000``data=nil`
- [x] 指令:
```bash
cd apps/backend && make gen-api && make build && go test ./... -count=1
```
## Notes
route 命名避免與既有 `/api/v1/scout` 衝突;`promote` 掛在既有 scout groupT600
### 實作結果2026-07-31
- 新增 34 個 route`radar` 20、`crm` 14`internal/handler/{radar,crm}` 與 `routes.go` 全為 goctl 產出。
- 未就緒語意:`radarDomain.ErrNotReady``crmDomain.ErrNotReady` → `internal/response` 映射 **HTTP 501 / code 501010**;各 logic 以 `notReady("<capability>")` 標明是哪個能力。
- 一併定義兩個 module 的 `ErrNotFound``ErrForbidden``ErrValidation``400100`sentinel 與映射,供 M1 起直接使用,避免每則 task 重複改 `response.go`
- **超出 spec §5.2 表格的兩個 route**(刻意加入,非漏審):
- `GET /api/v1/radar/opportunities/:id/replies` — RP-01「查 replies 只有 public_comment」需要讀取端點。
- `POST /api/v1/crm/contacts/:id/unmerge` — spec §4.6.3 與 T571 都要求 unmerge。
- 送出回覆端點**未**建立,依原計畫留給 T550。
- `routes.go` 另有一處無害變動:兩個同前綴 `/api/v1/media` 區塊的輸出順序被 goctl 互換,`rest.WithJwt` 仍附在 `generate-image` 區塊,全檔 19 處計數不變。