topfans/docs/superpowers/plans/2026-07-24-starbook-recovery.md
zerosaturation d3b57e3058 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>
2026-07-24 14:05:01 +08:00

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.1asset.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.goGetAssetsByType(ctx, req *pb.GetAssetsByTypeRequest) 方法(查 ctx 拿 user_id/star_id + 调 service + 包装响应)
  • backend/services/assetService/service/asset_service.goGetAssetsByType(req, userID, starID):从 GetMyAssets 复制过滤逻辑,加 type/category/grade 过滤(typeassets.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

  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.