# 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.