topfans/docs/superpowers/specs/2026-07-24-starbook-home-has-more-design.md
zerosaturation 383b5e042e docs(starbook): add has_more design spec and implementation plan
记录星册首页 More 按钮恢复的方案说明与 TDD 实施计划,作为本次特性 commit e079a6c 的设计依据。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 19:20:32 +08:00

8.7 KiB
Raw Blame History

星册首页“更多”按钮恢复设计

MVP 优先:本次仅恢复旧版星册首页“每组预览 3 张 + 超出显示更多”的既有行为,不引入新分页框架、不修改前端布局。

方案概述(必读)

要解决的问题

业务问题

  • 星册首页的原创、典藏和活动分组均不再显示“更多”按钮。
  • 用户无法从首页进入对应分类的完整藏品列表。

技术问题

  • assetService 迁移后,分组构建器返回全部藏品,并把 AssetGroup.HasMoreGradeSection.HasMore 固定为 false
  • protobuf 的 false 字段可能因 omitempty 不出现在 JSON 中,前端 v-if="group.has_more"v-if="gradeItem.has_more" 均不成立。
  • 当前分组构建器同时被首页 GetMyAssets 和查看更多 GetAssetsByType 复用,不能直接统一截断,否则查看更多页面也只能拿到前三张。

整体实现路径

  1. 为共享分组构建器增加预览上限参数,约 0.5 小时。
  2. 首页传入固定上限 3查看更多传入 0不限约 0.5 小时。
  3. 补充首页截断和查看更多完整返回测试,约 1 小时。
  4. 执行 assetService、gateway 相关测试和全服务预编译,约 0.5 小时。

预计总工作量:约 2.5 小时。

关键决策

  • 恢复旧版 HomePageSize = 3 行为:用户已确认每个分组或等级最多预览 3 张。
  • 统一按点赞数选取首页前三张:原创、典藏、活动均使用 models.Asset.LikeCount 按点赞数降序;点赞数相同时按 asset_id 升序,沿用项目排行榜的稳定排序口径。
  • 后端计算 has_more:保证 API 契约真实,避免前端下载全部数据后再截断。
  • 参数化复用现有构建器:首页限制 3查看更多限制 0避免复制三套分组逻辑。
  • 不修改前端模板:现有 v-if 在后端返回正确字段后即可工作。

核心架构图TL;DR

GET /api/v1/starbook/home
        │
        ▼
GetMyAssets ── previewLimit=3 ──► group builders
                                      │
                                      ├─ items[:3]
                                      ├─ total_count=真实数量
                                      └─ has_more=(真实数量 > 3)

GET /api/v1/starbook/items
        │
        ▼
GetAssetsByType ── previewLimit=0 ──► 同一组 builders
                                      │
                                      ├─ items=全部匹配项
                                      └─ 不因首页规则截断

文档说明

  • 适用范围:星册首页分组预览和“更多”入口。
  • 不包含:前端布局重做、数据库查询级分页重构、新增缓存。
  • 前置版本starbookService 已删除,相关能力已迁移到 assetService
  • 历史依据:旧版 starbookService 使用 HomePageSize = 3,原创按等级截断并计算 has_more
  • 目标读者:后端开发、前端联调和测试人员。

1. 当前行为与根因

StarbookContent.vue 已正确消费以下字段:

  • 原创:gradeItem.has_more
  • 典藏/活动:group.has_more

问题位于 assetService/service/asset_service.go:三个分组构建器返回所有项目,并把 HasMore 固定为 false。因此前端不需要增加兜底逻辑,修复应落在 API 数据生产端。

2. 分组构建器接口

三个构建器增加 previewLimit int 参数:

buildRegularGroupForAssets(..., previewLimit int) *pb.AssetGroup
buildCollectionGroupForAssets(..., previewLimit int) *pb.AssetGroup
buildActivityGroupForAssets(..., previewLimit int) *pb.AssetGroup

参数语义:

  • previewLimit > 0:先按 models.Asset.LikeCount DESC, Asset.ID ASC 排序,再最多保留指定数量;has_more 表示是否有项目被本次预览截断。
  • previewLimit <= 0:不截断,用于查看更多接口;分组和等级的 has_more 必须为 false,避免把“无限制模式”错误解释成仍有未返回项目。

定义首页常量:

const homePreviewLimit = 3

不增加配置文件或环境变量;该值是已确认的固定产品规则。

3. 首页数据规则

3.1 原创藏品

原创按 grade 独立计算:

  1. 只统计能关联到真实 Asset 的有效注册记录。
  2. 每个等级使用关联到的 models.Asset.LikeCount 按点赞数降序排序;点赞数相同时按 Asset.ID 升序,不能使用可能漂移的 AssetRegistry.LikeCount
  3. 每个等级最多返回 3 张。
  4. GradeSection.TotalCount 为该等级有效项目总数。
  5. GradeSection.HasMore = previewLimit > 0 && TotalCount > previewLimit
  6. AssetGroup.HasMore 为任一等级 HasMore=true
  7. 保持现有 grade 降序输出。

3.2 典收藏品

  1. 构建有效项目列表。
  2. 使用关联到的 models.Asset.LikeCount 按点赞数降序排序;点赞数相同时按 Asset.ID 升序,不能使用 AssetRegistry.LikeCount
  3. 首页最多返回前三张。
  4. TotalCount 为有效项目总数。
  5. HasMore = previewLimit > 0 && TotalCount > previewLimit

3.3 活动藏品

规则与典藏一致:使用 models.Asset.LikeCount 按点赞数降序并以 Asset.ID ASC 稳定并列顺序,有效项目总数超过 3 时截断并返回 HasMore=true

4. 查看更多数据规则

GetAssetsByType 调用构建器时传 previewLimit=0

  • 不执行首页前三张截断。
  • 保留当前 type/category/grade 过滤逻辑。
  • 返回结果沿用首页的统一排序:models.Asset.LikeCount DESC, Asset.ID ASC
  • 返回所有匹配分组项目,确保首页点击“更多”后能看到完整数据。
  • 本次不扩展数据库级分页;现有接口的分页字段行为不在此次修复范围内。

5. 前端行为

frontend/pages/components/StarbookContent.vue 不需要修改:

  • 原创继续使用 v-if="gradeItem.has_more"
  • 典藏和活动继续使用 v-if="group.has_more"
  • processGroupsWithValidUrls 的深拷贝会保留值为 truehas_more 字段。

验收行为:

实际数量 首页显示数量 “更多”按钮
0 0 不显示
13 13 不显示
4+ 3 显示

6. 测试设计

6.1 Service 单元测试

至少覆盖:

  1. 原创某等级 3 张:返回 3 张,等级和外层 has_more=false
  2. 原创某等级 4 张:首页按 Asset.LikeCount DESC, Asset.ID ASC 返回前三张,total_count=4,等级和外层 has_more=true
  3. 典藏 4 张:首页按 Asset.LikeCount DESC, Asset.ID ASC 返回前三张,total_count=4has_more=true
  4. 活动 4 张:首页按 Asset.LikeCount DESC, Asset.ID ASC 返回前三张,total_count=4has_more=true
  5. 点赞来源口径:故意让 AssetRegistry.LikeCountAsset.LikeCount 相反,断言排序严格采用 Asset.LikeCount
  6. 查看更多模式 4 张:按同一规则返回全部 4 张,分组/等级 has_more=false,不受首页上限影响。
  7. 边界值 previewLimit=3:数量为 0、1、3、4 时分别验证返回数量和 has_more,防止 off-by-one。
  8. 注册记录找不到对应资产时:无效记录不应制造错误的 total_counthas_more
  9. 多个原创等级中仅一个等级超过 3 张:仅该等级 has_more=true,外层 AssetGroup.HasMore=true

6.2 回归验证

  • 运行 assetService 相关 service/provider 测试。
  • 运行 Starbook gateway controller 测试。
  • 编译 gateway 和 assetService。
  • dev.sh 服务列表预编译全部后端服务。
  • 检查 GetMyAssetsGetAssetsByType 的调用方,确认二者分别传入 3 和 0。

7. 错误处理与兼容性

  • 不改变 protobuf 字段或 REST 响应结构。
  • 不改变身份校验和 type/category/grade 过滤规则。
  • 空分组维持现有行为。
  • has_more=false 仍可能被 JSON 省略,前端将其视为假值,符合预期;只有需要按钮时必须返回 true

8. 实施文件

预计修改:

  • backend/services/assetService/service/asset_service.go
  • 对应的 assetService 测试文件(优先复用现有测试文件)

预计不修改:

  • frontend/pages/components/StarbookContent.vue
  • backend/proto/asset.proto
  • 生成的 protobuf 文件
  • 数据库与 migration

9. 非目标与后续项

本次明确不做:

  • 数据库查询层的真实分页与 limit/offset 下推。
  • 首页排序规则重构。
  • collection/activity 的分类结构重构。
  • 前端“更多”按钮样式调整。

如果单个用户藏品数量显著超过当前 GetByOwner(..., 1000, 0) 上限,应另立任务把首页预览下推到 repository 查询层;这不影响本次恢复既有按钮行为。