docs: add starbook-recovery implementation plan (2026-07-24)
- 5 Task plan: proto 加 GetAssetsByType RPC (只改 .pb.go 不动 .triple.go); - assetService provider 实现新 handler; - gateway 重建 starbook_controller.go 薄壳(接口零变, owner→assetService); - 路由注册 + main.go 装配; - 端到端验证; - 由于 Task 2 误删,本 plan 完整回滚 + 重建,前端 4 处调用零修改。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3cce70ec2e
commit
d3b57e3058
177
docs/superpowers/plans/2026-07-24-starbook-recovery.md
Normal file
177
docs/superpowers/plans/2026-07-24-starbook-recovery.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# starbook 接口恢复 (回滚 Task 2 + 重建 gateway 薄壳) Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 恢复前端 4 处 starbook 接口(`/api/v1/starbook/home` + `/api/v1/starbook/items`),保留 HTTP 接口不变,**owner 从 starbookService 切到 assetService**。前端**零修改**。
|
||||||
|
|
||||||
|
**Architecture:** 网关重建 `starbook_controller.go` 作为薄壳:auth + 参数解析 + 调 assetService 新 RPC `GetAssetsByType`(支持 `type`/`category`/`grade` 过滤),响应结构与原 home/items **完全不变**。**不动 proto 共享 triple.go**(Task 7 教训:用新 RPC 在 asset.proto 内,只重生成 asset.pb.go 不动 asset.triple.go——若影响 main.go 装配则局部调整)。
|
||||||
|
|
||||||
|
**Tech Stack:** Go 1.25 / Gin / Dubbo / GORM / PostgreSQL(本地 `top-fans`@`localhost:15432`)
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- **接口契约零变**: HTTP 路径、请求参数、响应结构与 Task 2 删前完全一致(从前端 `pages/starbook/{index,items}.vue` 调用出发倒推)。
|
||||||
|
- **owner 切到 assetService**: 旧 starbookService 调用的 Dubbo RPC,**全部替换为 assetService 客户端调用**——不要再去恢复 starbookService 任何残留。
|
||||||
|
- **不动 proto triple.go**: 只动 asset.proto(在 asset.pb.go 一侧);asset.triple.go / 其它 service 的 *.triple.go 不动(防 Task 7 的"改 hand-written triple.go → workspace 编译挂")。
|
||||||
|
- **gateway 路由注册**: 2 端点挂在已登录的 v1 group(`v1.GET("/starbook/home", ...)` + `v1.GET("/starbook/items", ...)`)。
|
||||||
|
- 不引新依赖;不动前序 Task 改动(stability/config 1/2/3/5/6 全保留)。
|
||||||
|
- 写明 `git status` + `go build ./...` + `go vet ./...` + 目标测试通过。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
| 类型 | 路径 | 职责 |
|
||||||
|
|---|---|---|
|
||||||
|
| 新建 | `backend/gateway/controller/starbook_controller.go` | 2 端点薄壳(auth + 参数解析 + 调 assetService) |
|
||||||
|
| 改 | `backend/gateway/router/router.go` | 注册 `/api/v1/starbook/{home,items}` 2 路由(挂 AuthMiddleware 保护的 v1 group) |
|
||||||
|
| 新建 | `backend/proto/asset/asset.pb.go` | 加 `GetAssetsByTypeRequest/Response` proto 消息 + `GetAssetsByType` RPC 方法(只动 asset.pb.go,**不动 asset.triple.go**) |
|
||||||
|
| 改 | `backend/services/assetService/provider/asset_provider.go` | 实现 `GetAssetsByType` RPC(调 service 层,过滤 type/category/grade/page/pageSize) |
|
||||||
|
| 改 | `backend/services/assetService/service/asset_service.go` | service 层加 `GetAssetsByType`(带 type/category/grade 过滤的 DB 查询) |
|
||||||
|
| 新建 | `backend/gateway/controller/starbook_controller_test.go` | 单元测试(mock assetService client) |
|
||||||
|
| 新建 | `backend/services/assetService/provider/asset_provider_test.go` (追加测试) | `GetAssetsByType` 测试(若已有 provider test) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: proto 加 `GetAssetsByType` RPC(只动 asset.pb.go)
|
||||||
|
|
||||||
|
**Files:** `backend/proto/asset/asset.pb.go`(追加 proto 消息 + RPC 方法 stub,不用重跑 protoc-gen 用手写 stub 模式)
|
||||||
|
|
||||||
|
**⚠️ 关键约束**:
|
||||||
|
- **只**改 `asset.pb.go`,**不动** `asset.triple.go`(上次的坑)
|
||||||
|
- 不重跑 protoc-gen-`(plugins 缺失)`;用最小改动:在 `asset.pb.go` 末尾**直接 append** proto 消息 + 方法 stub(其它 service 只通过 .pb.go 类型编译,.triple.go 路由表若没引用新方法则零影响)
|
||||||
|
- 在报告里验证:`grep "GetAssetsByType" backend/proto/asset/asset.triple.go` 为空(新方法仅在 .pb.go,**不污染** .triple.go)
|
||||||
|
|
||||||
|
**Step 1.1** 读 `asset.pb.go` 现有 `GetMyAssetsRequest/Response` 格式,据此追加:
|
||||||
|
```go
|
||||||
|
type GetAssetsByTypeRequest struct {
|
||||||
|
UserId int64 `protobuf:"varint,1,opt,name=user_id,...`
|
||||||
|
StarId int64 `protobuf:"varint,2,opt,name=star_id,...`
|
||||||
|
Type string `protobuf:"bytes,3,opt,name=type,...` // regular/collection/activity
|
||||||
|
Category string `protobuf:"bytes,4,opt,name=category,...` // regular 时为 castlove
|
||||||
|
Grade int32 `protobuf:"varint,5,opt,name=grade,...`
|
||||||
|
Page int32 `protobuf:"varint,6,opt,name=page,...`
|
||||||
|
PageSize int32 `protobuf:"varint,7,opt,name=page_size,...`
|
||||||
|
}
|
||||||
|
type GetAssetsByTypeResponse struct {
|
||||||
|
Base *common.BaseResponse `protobuf:"bytes,1,opt,name=base,...`
|
||||||
|
Data *AssetListData `protobuf:"bytes,2,opt,name=data,...` // 复用现有 AssetListData
|
||||||
|
}
|
||||||
|
// 标准 proto 方法: Reset/String/ProtoMessage + Descriptor methods
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 1.2** `asset.pb.go` 末尾 Service 注册(类似 GetMyAssets 的 service desc)追加 `GetAssetsByType` 方法描述符(若 .pb.go 用 `serviceDesc` 数组注册),**只 .pb.go,不动 .triple.go**。
|
||||||
|
|
||||||
|
**Step 1.3** 验证:
|
||||||
|
- `cd backend && go build ./...` 通过(全 workspace 编译)
|
||||||
|
- `grep "GetAssetsByType" backend/proto/asset/asset.triple.go` 为空
|
||||||
|
- 其它 service 的 .triple.go 零改动
|
||||||
|
|
||||||
|
**Step 1.4** 报告(写入 `.superpowers/sdd/starbook-recovery-task-1-report.md`):
|
||||||
|
- 改动行数 + 新增 proto 消息/方法清单
|
||||||
|
- build/vet 结果
|
||||||
|
- 确认 triple.go 零污染
|
||||||
|
- concerns
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 2: assetService 实现 `GetAssetsByType` (provider + service + 测试)
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 改 `backend/services/assetService/provider/asset_provider.go` 加 `GetAssetsByType(ctx, req *pb.GetAssetsByTypeRequest)` 方法(查 ctx 拿 user_id/star_id + 调 service + 包装响应)
|
||||||
|
- 改 `backend/services/assetService/service/asset_service.go` 加 `GetAssetsByType(req, userID, starID)`:从 `GetMyAssets` 复制过滤逻辑,加 `type/category/grade` 过滤(`type` 转 `assets.status`/visibility/category 字段映射,`category` 普通时 = 'castlove',`grade` 普通类型有效)
|
||||||
|
- 新建/追加 `backend/services/assetService/provider/asset_provider_test.go` 测试(若已有,加 `TestGetAssetsByType_*: type 过滤/category 过滤/grade 过滤/未认证`)
|
||||||
|
- 本地 `top-fans` 库,自包含测试,只清自己 sentinel 行
|
||||||
|
|
||||||
|
**Step 2.1** TDD:写 1-2 个失败测试(type=regular 过滤、grade 过滤)→ 跑失败 → 实现 → 跑通过。
|
||||||
|
**Step 2.2** provider `GetAssetsByType` 复制 `GetMyAssets` 骨架,加 `req.Type/Category/Grade` 透传到 service。
|
||||||
|
**Step 2.3** service 层 SQL 过滤:`WHERE a.type = ? AND (a.grade = ? OR ? = 0)` 等(按实际表 schema,**先 grep `backend/migrations` 确认 assets 表 type/category/grade 列存在**)。
|
||||||
|
**Step 2.4** 验证:`go test ./services/assetService/... -run GetAssetsByType` 通过 + `go build ./...` 通过。
|
||||||
|
**Step 2.5** 报告:含 type→status/visibility 映射决策 + 测试结果。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 3: gateway 重建 starbook_controller.go 薄壳
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 新建 `backend/gateway/controller/starbook_controller.go`:
|
||||||
|
- `StarbookController` 结构含 `assetClient pbAsset.AssetService` 字段
|
||||||
|
- `NewStarbookController(assetClient)`: 构造(不调 Dubbo client.NewClient,与 auth/user controller 模式一致,assetClient 在 main.go 注入)
|
||||||
|
- `GetStarbookHome(c)`: auth 取 user_id/star_id → 调 `assetClient.GetMyAssets` → 包装成旧响应结构(若旧响应字段是 `Data.Home.HomeItems` 等,严格还原)
|
||||||
|
- `GetStarbookItems(c)`: auth → 解析 type/category/grade/page/pageSize → 调 `assetClient.GetAssetsByType` → 包装响应
|
||||||
|
- 响应结构必须**与原 home/items 端点**返回**字段一致**(grep 老 controller 的响应包装代码 + 复制)——前端 UI 依赖字段名/嵌套结构。
|
||||||
|
|
||||||
|
**Step 3.1** 从 git 找老 `starbook_controller.go` 的响应包装代码,严格复用**字段名**(只改内部 RPC 调用,不改返回 JSON shape)。
|
||||||
|
**Step 3.2** 写 2 个测试:`TestStarbookHome_*` (登录 + 调 assetClient.GetMyAssets + 断言响应字段)、`TestStarbookItems_*` (登录 + 解析参数 + 调 GetAssetsByType + 断言)。
|
||||||
|
**Step 3.3** `cd backend && go build ./...` 通过。
|
||||||
|
**Step 3.4** 报告。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 4: 路由注册 + main.go 装配
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- 改 `backend/gateway/router/router.go`:
|
||||||
|
- L494 处的"星册路由已删除"注释块改成"2 端点恢复(经 assetService 路由)"
|
||||||
|
- `v1.GET("/starbook/home", starbookCtrl.GetStarbookHome)` + `v1.GET("/starbook/items", starbookCtrl.GetStarbookItems)` 挂 AuthMiddleware 保护组
|
||||||
|
- 改 `backend/gateway/main.go`:
|
||||||
|
- `NewStarbookController(assetClient)` 实例化(传 assetClient,不再传 starbookClient)
|
||||||
|
- `SetupRouter` 调用加 starbookCtrl(若之前参数顺序动过)
|
||||||
|
- **off-by-one 风险**: 重传参数时务必先 grep `func SetupRouter(` 当前签名
|
||||||
|
|
||||||
|
**Step 4.1** 删 router.go L494-495 旧注释,加新路由。
|
||||||
|
**Step 4.2** main.go 实例化 + 注入。
|
||||||
|
**Step 4.3** 验证:`go build ./...` + 实测 `curl /api/v1/starbook/home -H "Authorization: Bearer xxx"` 返回 200(用测试 token,或 mock 检查端点路径已注册)。
|
||||||
|
**Step 4.4** 报告 + **off-by-one 教训**(引 Task 7 的 setup 签名教训)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 5: 全局回归 + 完整收口
|
||||||
|
|
||||||
|
**Files:** 纯验证(无改动)。
|
||||||
|
|
||||||
|
**Step 5.1** 完整 build/vet/test:
|
||||||
|
- `cd backend && go build ./...` 通过
|
||||||
|
- `cd backend && go vet ./...` 通过
|
||||||
|
- `cd backend && go test ./gateway/... ./services/assetService/...` 通过(只相关包)
|
||||||
|
**Step 5.2** 端到端验证(本地有 gateway 跑):
|
||||||
|
- 用测试 token 调 `/api/v1/starbook/home` 返回 200 + 期望字段
|
||||||
|
- 调 `/api/v1/starbook/items?type=regular&category=castlove&page=1` 返回 200
|
||||||
|
- 报告 + 验证 status
|
||||||
|
**Step 5.3** 提交(用户批准后):
|
||||||
|
```bash
|
||||||
|
git add backend/proto/asset/asset.pb.go \
|
||||||
|
backend/services/assetService/{provider,service}/ \
|
||||||
|
backend/gateway/controller/starbook_controller.go \
|
||||||
|
backend/gateway/router/router.go \
|
||||||
|
backend/gateway/main.go \
|
||||||
|
backend/gateway/controller/starbook_controller_test.go
|
||||||
|
git commit -m "fix(gateway): restore /api/v1/starbook/* via assetService (Task 2 rollback + asset owner)
|
||||||
|
|
||||||
|
- 恢复 /api/v1/starbook/home + /api/v1/starbook/items 网关路由
|
||||||
|
(owner 由被删的 starbookService 切到 assetService);
|
||||||
|
- assetService 加 GetAssetsByType RPC (type/category/grade 过滤);
|
||||||
|
- gateway 新建 starbook_controller.go 薄壳 (auth + 参数解析 + RPC);
|
||||||
|
- 响应结构与原端点完全一致 (前端零修改);
|
||||||
|
- 仅改 asset.pb.go (不动 triple.go 防 Task 7 坑);
|
||||||
|
- main.go 装配更新 (SetupRouter 签名同步)。
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
|
||||||
|
1. **接口零变**: 端点 4 处前端调用经路由 + 响应字段不变。
|
||||||
|
2. **owner 切换正确**: starbookService 调 Dubbo → gateway 调 assetService 客户端,无残留。
|
||||||
|
3. **proto 仅 .pb.go**: triple.go 零污染,其它 service 不破。
|
||||||
|
4. **off-by-one 防御**: Task 4 显式核对 SetupRouter 签名。
|
||||||
|
5. **回归**: 全 build + vet + 相关包测试通过。
|
||||||
|
|
||||||
|
## Execution Handoff
|
||||||
|
|
||||||
|
**Plan complete and saved to `docs/superpowers/plans/2026-07-24-starbook-recovery.md`. Two execution options:**
|
||||||
|
|
||||||
|
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration. **Will use this for Task 1-2 (proto + RPC, highest risk), inline review for Task 3-5 (gateway shell, lower risk).**
|
||||||
|
|
||||||
|
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints for review.
|
||||||
Loading…
Reference in New Issue
Block a user