Problem
/playtest 为了建立跨项目造型画廊,会先读取完整项目列表,再对每个项目分别调用一次 GET /characters?project_id=...。请求量随项目数量线性增长;开发环境的 React StrictMode 还会重放整段 Effect。
当前本地测试账号有 12 个项目,单次打开页面的服务日志记录到两次项目读取和 24 次角色读取,共 26 次请求。连续刷新会快速消耗全局每分钟 60 次请求额度,并连带影响登录、刷新令牌和其他正常接口。
项目中心只读取当前项目分页,不存在同等规模的请求扇出。
Root Cause
预览台在前端使用 Promise.all(projects.map(...)),为每个项目独立读取角色分页。该数据装配方式把请求复杂度绑定到项目数量;StrictMode 只是把问题放大,并非根因。
Goal
预览台完整读取当前用户可见资产时,请求数量只随项目页数和角色页数增长,不再随项目数量产生 N+1 扇出。
Scope
- 为角色列表提供当前用户范围内的跨项目分页读取,同时保留现有按项目读取能力。
- 预览台分别读取完整项目分页和角色分页,再通过
projectId 在前端组合画廊。
- 保留项目筛选、造型卡、空态、错误态和完整分页语义。
- 增加用户归属、分页和请求数量回归测试。
Out of Scope
- 不修改预览台视觉设计。
- 不调高或绕过全局限流。
- 不通过重试、延迟或串行化掩盖 N+1 请求。
- 不修改项目中心的预览读取策略。
- 不修改具体预览台工作台路由和操控逻辑。
Acceptance Criteria
Related
Problem
/playtest为了建立跨项目造型画廊,会先读取完整项目列表,再对每个项目分别调用一次GET /characters?project_id=...。请求量随项目数量线性增长;开发环境的 React StrictMode 还会重放整段 Effect。当前本地测试账号有 12 个项目,单次打开页面的服务日志记录到两次项目读取和 24 次角色读取,共 26 次请求。连续刷新会快速消耗全局每分钟 60 次请求额度,并连带影响登录、刷新令牌和其他正常接口。
项目中心只读取当前项目分页,不存在同等规模的请求扇出。
Root Cause
预览台在前端使用
Promise.all(projects.map(...)),为每个项目独立读取角色分页。该数据装配方式把请求复杂度绑定到项目数量;StrictMode 只是把问题放大,并非根因。Goal
预览台完整读取当前用户可见资产时,请求数量只随项目页数和角色页数增长,不再随项目数量产生 N+1 扇出。
Scope
projectId在前端组合画廊。Out of Scope
Acceptance Criteria
/playtest不再为每个项目分别调用角色列表接口。GET /characters?project_id=...的分页、状态过滤和归属校验不回归。Related