Files
Genarrative/server-rs/crates/api-server
高物 bb60ca91ef Match3D & Puzzle: runtime UI, assets, drag fix
Backend: stop treating background music as a required draft asset and remove auto-submit/plan for background music; load persisted generated UI/assets into Match3D agent session responses (added helpers to resolve profile id and fetch existing generated assets). Frontend: make Match3D result preview reuse runtime UI styles, unify runtime settings entry, update PuzzleRuntime to apply immediate pointermove transforms (disable drag transition), use SVG clipPath for merged piece rounding, ensure PuzzleRuntimeShell supplies platform theme classes, and adjust related tests. Docs & logs: update decision log, pitfalls and product docs to reflect these changes.
2026-05-15 08:49:59 +08:00
..

api-server 主工程 crate 占位说明

日期:2026-04-20

1. crate 职责

api-server 是新后端的 Axum 主工程 crate后续负责

  1. main.rs 启动入口
  2. Router 装配
  3. with_state 共享状态注入
  4. 中间件挂载
  5. /healthz/api/*、SSE 与静态资源兼容层装配
  6. ../../scripts/dev.ps1../../scripts/dev.sh 驱动的本地开发启动链路
  7. ../../scripts/test.ps1../../scripts/test.sh 驱动的本地测试链路
  8. ../../scripts/check.ps1../../scripts/check.sh 驱动的本地统一检查链路
  9. ../../scripts/smoke.ps1../../scripts/smoke.sh 驱动的本地启动与协议冒烟链路

2. 当前阶段说明

当前目录已经完成以下基础骨架:

  1. 目录占位
  2. Cargo.toml
  3. src/main.rs
  4. src/app.rs
  5. src/state.rs
  6. src/config.rs
  7. 基础 TraceLayer 挂载
  8. 接入 shared-logging 完成 tracing subscriber 初始化
  9. 接入 POST /api/auth/entry 首版密码登录链路
  10. 接入 POST /api/auth/password/change 登录后修改密码链路
  11. 接入 POST /api/auth/password/reset 手机验证码重置密码链路
  12. 接入 POST /api/assets/direct-upload-tickets 直传票据接口
  13. 接入 GET /api/auth/me 当前用户查询链路
  14. 接入 POST /api/auth/refresh refresh token 轮换链路
  15. 接入 POST /api/auth/logout 当前设备退出链路
  16. 接入 POST /api/assets/objects/confirm 上传完成确认链路
  17. 接入 GET /api/auth/login-options 登录方式探测链路
  18. 接入 POST /api/auth/phone/send-code 手机验证码发送链路
  19. 接入 POST /api/auth/phone/login 手机验证码登录链路
  20. 接入 GET /api/auth/wechat/start 微信授权起跳链路
  21. 接入 GET /api/auth/wechat/callback 微信回调换取系统登录态链路
  22. 接入 POST /api/auth/wechat/bind-phone 微信待绑定账号补绑手机号链路
  23. 接入 POST /api/assets/objects/bind 已确认对象绑定业务实体槽位链路
  24. 接入 POST /api/assets/sts-upload-credentials 禁用式 STS 写权限 contract
  25. 接入 custom-world-librarycustom-world-gallery 与 agent publish_world 首批 Axum facade
  26. 接入 custom world agent session create / session snapshot Axum facade
  27. runtime story 兼容接口已下线并保持未挂载;运行时故事写链路改为:
    • POST /api/story/sessions/runtime
    • GET /api/story/sessions/{story_session_id}/runtime-projection
    • POST /api/story/sessions/{story_session_id}/actions/resolve
  28. 接入 POST /api/assets/character-visual/generate
  29. 接入 GET /api/assets/character-visual/jobs/{task_id}
  30. 接入 POST /api/assets/character-visual/publish
  31. 接入 GET /api/assets/character-animation/templates
  32. 接入 POST /api/assets/character-animation/import-video
  33. 接入 GET /api/assets/character-workflow-cache/{character_id}
  34. 接入 POST /api/assets/character-workflow-cache
  35. 接入 POST /api/assets/character-animation/generate
  36. 接入 GET /api/assets/character-animation/jobs/{task_id}
  37. 接入 POST /api/assets/character-animation/publish
  38. 下线旧 /generated-* 资产直读代理;生成资产读取统一走 /api/assets/read-url 或 asset object projection
  39. 下线旧 /api/custom-world/* 非 runtime 前缀和 /api/runtime/puzzle/runs/local-next-level,并用路由回归测试确认这些旧入口保持 404

后续与本 crate 直接相关的任务包括:

  1. 接入统一日志与 tracing
  2. 接入 request_id
  3. 接入统一错误处理中间件
  4. 接入 response envelope
  5. 接入 /healthz
  6. 接入 /api/auth/entry
  7. 接入 /api/assets/direct-upload-tickets
  8. 接入 /api/auth/me
  9. 接入 /api/auth/refresh
  10. 接入 /api/auth/logout
  11. 接入 /api/assets/objects/confirm
  12. 接入 /api/auth/login-options
  13. 接入 /api/auth/phone/send-code
  14. 接入 /api/auth/phone/login
  15. 接入 /api/auth/wechat/start
  16. 接入 /api/auth/wechat/callback
  17. 接入 /api/auth/wechat/bind-phone
  18. 接入 /api/assets/objects/bind
  19. 接入 /api/assets/sts-upload-credentials
  20. 接入 custom world library / gallery / publish_world 首批 facade
  21. 接入 custom world agent session create / snapshot facade
  22. 下线旧 runtime story compat facade并接入 story session scoped runtime story 写读入口
  23. 接入 character-visual generate / jobs / publish 第一批 OSS 主链兼容 facade
  24. 接入 character-animation templates / import-video 第一批 OSS 草稿兼容 facade
  25. 接入 character-workflow-cache get / save 第一批 OSS JSON 草稿兼容 facade
  26. 接入 character-animation generate / jobs / publish 第一批 OSS 主链兼容 facade
  27. 下线旧 /generated-* 路径 OSS 私有读同源代理
  28. 下线旧 /api/custom-world/* 非 runtime 前缀和 Puzzle local-next-level 兼容入口

当前 tracing 约定:

  1. 进程启动时通过 shared-logging 统一初始化 tracing subscriber
  2. 默认日志过滤器来自 GENARRATIVE_API_LOG,未提供时回落到 info,tower_http=info
  3. HTTP 访问日志统一通过 Axum 路由层的 TraceLayer 输出,后续 request_id、响应头与错误中间件继续在同一层扩展。
  4. 本地启动器 npm run api-server 和完整联调入口 npm run dev / npm run dev:rust 会在保留终端实时输出的同时,把同一份 cargo / api-server 输出持久化到 logs/api-server/。如需固定文件或目录,可设置 GENARRATIVE_API_SERVER_LOG_FILEGENARRATIVE_API_SERVER_LOG_DIR

当前 request context 约定:

  1. 中间件优先读取来访 x-request-id,未提供时生成新的 UUID。
  2. request_id 会统一写入请求 extensions 与请求头,供 tracing、错误处理中间件和响应头层复用。
  3. 最终响应会回写同一个 x-request-id,保证调用方、日志链路和后续 envelope meta.requestId 可对齐。

当前错误处理中间件约定:

  1. 对 Axum 默认产生的空 4xx / 5xx 响应,统一归一化为 legacy 兼容 JSON 错误体:{ error: { code, message, details? } }
  2. 已经带 content-type 的业务错误响应不会被覆盖,避免抢走后续 response envelope 的职责。
  3. 统一错误日志会复用当前请求的 request_id便于后续和响应头、envelope 元信息串联。

当前 response envelope 约定:

  1. RequestContext 已记录 request_id、请求开始时间、默认 operation 与 envelope 协商结果。
  2. json_success_body(...) / json_error_body(...) 会根据 x-genarrative-response-envelope 自动在“裸数据 / 标准 envelope / legacy error + meta”之间切换。
  3. meta.apiVersionmeta.requestIdmeta.routeVersionmeta.operationmeta.latencyMsmeta.timestamp 已按当前前端契约生成,响应头回写仍留给后续独立任务。

当前基础响应头约定:

  1. 所有响应都会回写 x-request-id
  2. 所有响应都会回写固定的 x-api-version,当前值与 body meta.apiVersion 保持一致。
  3. 所有响应都会回写 x-route-version,当前阶段默认与 x-api-version 保持一致,后续再按路由粒度细分。
  4. 所有响应都会回写 x-response-time-ms,值来源于 RequestContext 内记录的请求开始时间。

当前 /healthz 约定:

  1. 路径固定为 /healthz
  2. 裸响应继续返回 { ok: true, service: "genarrative-node-server" },保持与当前 Node 工程兼容。
  3. 当请求携带 x-genarrative-response-envelope 时,/healthz 会返回标准 success envelope。
  4. x-request-idx-api-versionx-route-versionx-response-time-ms 会在 /healthz 响应中一并回写。

当前本地检查链路约定:

  1. ../../scripts/check.ps1../../scripts/check.sh 统一串联 cargo fmt --all --checkcargo clippycargo checkcargo test
  2. 默认检查整个 server-rs workspace确保后续多 crate 扩容时仍然保持统一口径。
  3. 当只需聚焦单个 crate 时,可通过 -PackageSERVER_RS_CHECK_PACKAGE 收窄 clippy / check / test 目标。
  4. cargo fmt --all --check 仍固定覆盖整个 workspace避免多 crate 下格式基线漂移。

当前本地 smoke 链路约定:

  1. ../../scripts/smoke.ps1../../scripts/smoke.sh 会先构建 api-server,再拉起临时本地进程完成冒烟验证。
  2. smoke 当前固定校验 /healthz 的 raw 响应、envelope 响应以及 x-request-idx-api-versionx-route-versionx-response-time-ms 头。
  3. smoke 通过后可作为“Axum 服务可独立启动且基础 contract 可联通”的本地自动化证据。

3. 边界约束

  1. api-server 负责 HTTP、SSE、Cookie、Header、路由与协议装配。
  2. 业务逻辑优先通过独立模块 crate 暴露能力,再由主工程组合。
  3. 外部副作用通过 platform-authplatform-ossplatform-llm 与各模块 crate 的应用层完成。
  4. 不把领域规则直接堆在 handler 中。
  5. 当前密码登录由 module-auth 负责用例编排,api-server 只负责请求解析、JWT 签发与 refresh cookie 写回。
  6. 当前 /api/auth/me 复用现有 Bearer JWT 中间件与 module-auth 用户快照查询,不直接绕过模块边界读取内部状态。
  7. 当前 /api/auth/refresh 复用 module-auth 的 refresh session 轮换能力,api-server 负责 refresh cookie 读取、失败清理与 access token 重签。
  8. 当前 /api/auth/logout 复用 module-auth 的当前会话吊销与用户版本递增能力,api-server 负责 Bearer JWT、refresh cookie 读取与清理 cookie 回写。
  9. 当前 /api/assets/objects/confirm 先由 platform-oss 完成私有 HEAD Object 校验,再通过 spacetime-client 调用 spacetime-module 的对象确认持久化入口。
  10. 当前 /api/assets/objects/bind 只绑定已确认对象到业务实体槽位,不访问 OSS不创建悬空 asset_object_id
  11. 当前手机号登录与微信登录都复用 module-auth 的进程内认证仓储,api-server 负责请求解析、场景判定、系统 JWT 签发与 refresh cookie 写回。
  12. 当前微信回调不会把第三方 token 直接透传给前端或 SpacetimeDB而是统一换成系统签发的 JWT。
  13. 当前 /api/assets/sts-upload-credentials 按“服务器上传、Web 只下载”口径固定返回 403,不向浏览器下发 OSS 写权限。
  14. 当前 /api/runtime/custom-world/agent/sessions/api/runtime/custom-world/agent/sessions/{session_id} 只提供 deterministic session 骨架与 snapshot 读取,不承诺 message submit、operation query、card detail 的完整能力。
  15. 当前 /api/runtime/story/* 不再挂载runtime story 开局、读取和动作结算通过 /api/story/sessions/runtime/api/story/sessions/{story_session_id}/runtime-projection/api/story/sessions/{story_session_id}/actions/resolve 进入 BFF并由 module-runtime-story、story session 和 runtime snapshot 投影共同闭合。
  16. 当前 /api/assets/character-visual/* 第一批只保证旧接口 contract、OSS 草稿/正式对象、asset_objectasset_entity_binding 主链可用真实图片模型、workflow cache 与本地角色覆盖写回仍在后续阶段。
  17. 当前 /api/assets/character-animation/import-video 第一批只接受 data:video/*;base64,... 并写入 OSS 草稿区,不读取旧本地 public/ 路径,也不创建正式 asset_object
  18. 当前 /api/assets/character-workflow-cache/* 第一批只把工作流 JSON 草稿写入 OSS不迁移历史本地缓存也不创建正式 asset_object
  19. 当前 /api/assets/character-animation/generate 第一批只用 Rust 占位产物打通 AiTaskService + OSS 草稿链;image-sequence 写 SVG 帧,视频类策略优先复用参考视频或仓库内可播放占位视频,不代表真实上游视频模型已完成迁移。
  20. 当前 /api/assets/character-animation/publish 会把前端提交帧、动作级 manifest 与总 manifest 写入 OSS并只把总 manifest 确认为 asset_object 后绑定到 character / animation_set
  21. 当前旧 /generated-* 直读兼容层已下线;/generated-* 只作为 legacyPublicPath / OSS object key 标识,读取必须通过 /api/assets/read-url 或业务投影中的签名读 URL。
  22. 当前旧 /api/custom-world/entity/api/custom-world/scene-npc/api/custom-world/scene-image/api/custom-world/cover-image/api/custom-world/cover-upload 不再挂载RPG 创作资产入口统一使用 /api/runtime/custom-world/*
  23. 当前旧 /api/runtime/puzzle/runs/local-next-level 不再挂载,正式 Puzzle 运行态只通过 /api/runtime/puzzle/runs/{run_id}/next-level 进入后端真相源。