diff --git a/.hermes/todos/【后端架构】api-server能力模块化与图片资产Adapter收口计划-2026-05-14.md b/.hermes/todos/【后端架构】api-server能力模块化与图片资产Adapter收口计划-2026-05-14.md index e076e786..1c695ead 100644 --- a/.hermes/todos/【后端架构】api-server能力模块化与图片资产Adapter收口计划-2026-05-14.md +++ b/.hermes/todos/【后端架构】api-server能力模块化与图片资产Adapter收口计划-2026-05-14.md @@ -1,54 +1,108 @@ -# api-server 能力模块化与图片资产 Adapter 收口计划 +# api-server 能力模块化与生成资产 Adapter 完整收口计划 状态:待执行 ## Summary -把两份计划合并成一个分阶段重构:先把 `api-server` 从扁平 `src/*.rs` 收成按能力组织的 Module + Router 结构;同时把散落在玩法 handler 里的“图片生成 -> 下载 -> OSS 写入/head -> asset_object 确认 -> entity binding”收成 `generated_image_assets` 深 Module。 +目标是把 `api-server` 从“超大 `app.rs` + 多个超大 handler 文件 + 多处生成资产重复链路”收成可长期维护的能力 Module 结构。 -本轮不改变 HTTP contract、DTO、前端行为、SpacetimeDB schema 或计费语义。 +本计划完整覆盖:路由能力模块化、生成图片资产 Adapter、复杂媒体链路扩展、大 handler 瘦身、文档与验收。全程不改变 HTTP contract、DTO、SpacetimeDB schema、前端行为和计费语义,除非某阶段文档先明确提出并单独批准。 -## Key Changes +## 文档交付 -- 新增 `server-rs/crates/api-server/src/modules/`,每个能力 Module 暴露 `router(state) -> Router`,`app.rs` 只负责全局 middleware 和 `.merge(...)`。 -- 能力分组建议:`admin`、`auth`、`assets`、`creation`、`runtime`、`platform`,核心基础设施继续保留在根层或 `core`。 -- 在 `modules/assets/generated_image_assets` 新增内部 Adapter Module,Interface 固定为“生成并入库”: - - 输入包含 provider、prompt、size、参考图、OSS 路径、asset kind、entity kind/id、slot、owner/profile/source_job_id。 - - 输出包含 `asset_object_id`、`legacy_public_path`、`object_key`、mime/extension、task_id/actual_prompt。 -- `asset_billing.rs` 不改语义;调用方继续在外层显式包 `execute_billable_asset_operation*`,图片 Adapter 不读写钱包。 -- 首批迁移稳定单图链路:Big Fish 正式图片、Square Hole 图片、Custom World 场景图/封面类图片入库路径。 -- 暂不迁移 Puzzle VectorEngine edits/multipart、Match3D 5x5 sheet/切图/绿幕后处理,以及音频、视频、GLB 转存链路。 +先新增一个总纲,再按阶段新增单独执行文档: -## Implementation Notes +- 总纲:`docs/technical/【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md` +- 阶段 1:`docs/technical/【后端架构】api-server路由能力模块化执行计划-2026-05-14.md` +- 阶段 2:`docs/technical/【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md` +- 阶段 3:`docs/technical/【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md` +- 阶段 4:`docs/technical/【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md` +- 同步更新 `server-rs/crates/api-server/README.md`、`docs/technical/README.md`、本 TODO 文档。 -- `generated_image_assets` 内部集中处理 OSS 缺配置、下载图片 mime/extension 归一、空内容/上游错误映射、`put_object -> head_object -> confirm_asset_object -> bind_asset_object_to_entity`。 -- 调用方玩法文件只保留领域上下文拼装、prompt 构造、计费包裹和响应映射。 -- `openai_image_generation.rs` 继续保留底层 VectorEngine 能力;本轮只让新 Adapter 封装“provider 结果 + OSS/asset_object 持久化”的更深 Interface。 -- 第一阶段不拆 `match3d.rs`、`puzzle.rs`、`custom_world.rs` 等超大 handler 内部实现;后续再单独切第二阶段。 +## 阶段 0:基线盘点与总纲冻结 -## Docs +- 盘点 `app.rs` 当前全部 route,按 `admin/auth/assets/profile/creation/runtime/story/platform/internal` 分类形成 route inventory。 +- 盘点 Big Fish、Square Hole、Custom World、Puzzle、Match3D、Visual Novel、音频、视频、GLB 的生成资产链路,标出 provider、下载方式、OSS prefix、asset kind、entity binding、计费位置、降级行为。 +- 在总纲文档中冻结边界:`api-server` 只做 HTTP/SSE/BFF、鉴权、DTO 映射、平台服务编排;领域规则仍归 `module-*`,SpacetimeDB 真相仍归 `spacetime-module`。 -- 新增或更新 `server-rs/crates/api-server/README.md`,说明能力 Module 目录规则、Router 暴露规则和 Adapter 边界。 -- 新增 `docs/technical` 说明,并挂到 `docs/technical/README.md`。 -- 文档明确:`api-server` 仍是 HTTP/SSE/BFF Adapter 与平台编排层,不承接领域规则主逻辑。 +退出条件:总纲和 inventory 能指导后续编码,不再只是一段方向描述。 -## Test Plan +## 阶段 1:路由能力模块化完整收口 -- 结构与路由回归: +- 新增 `server-rs/crates/api-server/src/modules/`,每个能力 Module 暴露 `router(state) -> Router`。 +- 第一批迁移低风险路由:`admin`、`auth`、`assets`、`profile`、`internal`、`health`。 +- 第二批迁移平台编排路由:`ai_tasks`、`llm`、`speech`、`wechat`、`creative_agent`、`visual_novel`、通用 audio。 +- 第三批迁移玩法路由:`big_fish`、`square_hole`、`puzzle`、`match3d`、`custom_world`、`story`、runtime save/settings/chat/inventory。 +- `app.rs` 最终只保留全局 middleware、TraceLayer、request context、tracking middleware、`.merge(modules::*::router(...))` 和少量顶层 glue。 +- handler 实现第一阶段可以继续留在原文件;本阶段只改变路由装配位置,不混入业务重构。 + +验收:route inventory 中所有原 route 仍存在;旧明确下线 route 继续 404;`cargo test -p api-server app --manifest-path server-rs/Cargo.toml` 或等价 route 回归通过。 + +## 阶段 2:稳定单图生成资产 Adapter 收口 + +- 新增 `modules/assets/generated_image_assets` 内部 Module,Interface 覆盖“provider 生成 -> 下载/base64 解码 -> MIME/extension 归一 -> OSS private upload -> HEAD -> asset_object confirm -> entity binding”。 +- Adapter 输入包含 provider、prompt、negative prompt、size、reference images、OSS prefix/path/file name、asset kind、entity kind/id、slot、owner/profile/source_job_id、metadata、可选透明背景后处理。 +- Adapter 输出包含 `legacy_public_path`、`object_key`、`asset_object_id`、`mime_type`、`extension`、`task_id`、`actual_prompt`。 +- 首批迁移: + - Big Fish 正式图片:主图、动作图、舞台背景。 + - Square Hole 图片:保留生成成功但入库失败时回退 Data URL。 + - Custom World 场景图、自动草稿场景图、生成封面图。 +- `asset_billing.rs` 仍由调用方显式包裹;Adapter 不扣费、不退款、不读钱包。 + +验收:三类调用方都经过同一 Adapter;删除旧重复 persist 函数后行为不变;Big Fish、Square Hole、Custom World 定向测试通过。 + +## 阶段 3:复杂媒体资产链路扩展 + +- 扩展 Adapter,但不把玩法图像处理规则塞进公共 Interface。 +- Puzzle: + - 收口普通 generations、edits/multipart 生成结果的下载、OSS、asset object、binding。 + - 拼图关卡 JSON 更新、参考图策略、UI 背景落位仍留在 Puzzle 编排层。 +- Match3D: + - APIMart material sheet、VectorEngine 背景/容器/封面生成接入统一入库能力。 + - 5x5 切图、绿幕透明化、格内校准、批量新增补齐规则仍留在 Match3D 专属处理器。 +- 音频: + - 评估是否抽 `generated_media_assets`,但背景音乐、点击音效的计费和落位语义不与图片 Adapter 混用。 +- GLB/视频: + - 仅历史转存链路复用“OSS + asset_object + binding”底层持久化能力,不恢复新草稿 GLB 生产。 + +验收:Puzzle 与 Match3D 的 generated 私有资产仍通过 `/api/assets/read-url` 换签读取;Match3D 不回退 Rodin/GLB;音频试听和运行态仍可播放。 + +## 阶段 4:超大 handler 能力内瘦身 + +- 在路由已模块化、资产 Adapter 已稳定后,再拆大文件,避免同时改 route 和业务实现。 +- 对 `match3d.rs`、`puzzle.rs`、`custom_world.rs`、`custom_world_ai.rs`、`big_fish.rs`、`square_hole.rs` 分别按能力拆: + - `router.rs` 只挂路由。 + - `handlers.rs` 只做 Axum extract、鉴权、request/response。 + - `application.rs` 做 api-server 层编排。 + - `assets.rs` 只放玩法专属生成资产策略。 + - `mapper.rs` 只做 DTO/record 映射。 + - `errors.rs` 只做该能力错误映射。 +- 不把领域规则留在 handler;发现领域规则时只登记迁出候选,不在本阶段直接扩大到 `module-*` 重构。 + +验收:每个原超大文件显著缩小;新文件按能力可读;定向玩法测试和全量 `api-server` 测试通过。 + +## 阶段 5:清理、文档和最终验收 + +- 删除旧重复 helper、过时注释和已迁移的私有函数。 +- 更新 `api-server` README:目录规则、Router 暴露规则、Adapter 边界、禁止事项。 +- 更新 `.hermes/shared-memory` 中长期有效的架构约定和排障经验。 +- 最终验收命令: - `cargo check -p api-server --manifest-path server-rs/Cargo.toml` - `cargo test -p api-server --manifest-path server-rs/Cargo.toml` - `npm run check:server-rs-ddd` - `npm run check:encoding` - `git diff --check` -- 图片 Adapter 单测覆盖 OSS 缺配置、asset object/binding 输入构造、URL/base64 结果归一、上游错误和空图片内容映射。 -- 迁移点回归: - - `cargo test -p api-server big_fish --manifest-path server-rs/Cargo.toml` - - `cargo test -p api-server square_hole --manifest-path server-rs/Cargo.toml` - - `cargo test -p api-server custom_world --manifest-path server-rs/Cargo.toml` -- API smoke 使用 `npm run api-server` 并检查 `/healthz`;不使用 `api-server:maincloud`。 + - `npm run api-server` 后检查 `/healthz` +- 禁止使用 `api-server:maincloud` 作为本轮 smoke。 + +## Public Interfaces + +- HTTP route、DTO、error envelope、SpacetimeDB schema、前端调用方式默认不变。 +- 新增的都是 `api-server` 内部 Rust Interface,不进入 `shared-contracts`。 +- 若后续任何阶段发现必须改 contract,先更新对应阶段文档和 G1 route/contract 矩阵,再单独实施。 ## Assumptions -- 本轮目标是提升 locality、降低重复和减少 `app.rs` 路由树压力。 -- `generated_image_assets` 先留在 `api-server` 内部,不新增 workspace crate。 -- Match3D、Puzzle 的复杂图片链路作为第二阶段迁移,不阻塞第一阶段收口。 +- 本计划目标是完整收口,不是只完成第一阶段。 +- 可以分阶段提交,但每个阶段都必须有文档、测试和明确退出条件。 +- `generated_image_assets` 首版必须至少被三个真实调用方使用,否则不算形成有效 Module。