- 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>
11 KiB
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 格式,据此追加:
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 提交(用户批准后):
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
- 接口零变: 端点 4 处前端调用经路由 + 响应字段不变。
- owner 切换正确: starbookService 调 Dubbo → gateway 调 assetService 客户端,无残留。
- proto 仅 .pb.go: triple.go 零污染,其它 service 不破。
- off-by-one 防御: Task 4 显式核对 SetupRouter 签名。
- 回归: 全 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.