Files

173 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 当前设备退出链路
14. 接入 `POST /api/assets/objects/confirm` 上传完成确认链路
15. 接入 `GET /api/auth/login-options` 登录方式探测链路
16. 接入 `POST /api/auth/phone/send-code` 手机验证码发送链路
17. 接入 `POST /api/auth/phone/login` 手机验证码登录链路
18. 接入 `GET /api/auth/wechat/start` 微信授权起跳链路
19. 接入 `GET /api/auth/wechat/callback` 微信回调换取系统登录态链路
20. 接入 `POST /api/auth/wechat/bind-phone` 微信待绑定账号补绑手机号链路
21. 接入 `POST /api/assets/objects/bind` 已确认对象绑定业务实体槽位链路
22. 接入 `POST /api/assets/sts-upload-credentials` 禁用式 STS 写权限 contract
23. 接入 `custom-world-library``custom-world-gallery` 与 agent `publish_world` 首批 Axum facade
24. 接入 custom world agent `session create / session snapshot` Axum facade
25.`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`
26. 接入 `POST /api/assets/character-visual/generate`
27. 接入 `GET /api/assets/character-visual/jobs/{task_id}`
28. 接入 `POST /api/assets/character-visual/publish`
29. 接入 `GET /api/assets/character-animation/templates`
30. 接入 `POST /api/assets/character-animation/import-video`
31. 接入 `GET /api/assets/character-workflow-cache/{character_id}`
32. 接入 `POST /api/assets/character-workflow-cache`
33. 接入 `POST /api/assets/character-animation/generate`
34. 接入 `GET /api/assets/character-animation/jobs/{task_id}`
35. 接入 `POST /api/assets/character-animation/publish`
36. 下线旧 `/generated-*` 资产直读代理;生成资产读取统一走 `/api/assets/read-url` 或 asset object projection
37. 下线旧 `/api/custom-world/*` 非 runtime 前缀和 `/api/runtime/puzzle/runs/local-next-level`,并用路由回归测试确认这些旧入口保持 `404`
后续与本 crate 直接相关的任务包括:
1. [x] 接入统一日志与 tracing
2. [x] 接入 `request_id`
3. [x] 接入统一错误处理中间件
4. [x] 接入 response envelope
5. [x] 接入 `/healthz`
6. [x] 接入 `/api/auth/entry`
7. [x] 接入 `/api/assets/direct-upload-tickets`
8. [x] 接入 `/api/auth/me`
9. [x] 接入 `/api/auth/refresh`
10. [x] 接入 `/api/auth/logout`
11. [x] 接入 `/api/assets/objects/confirm`
12. [x] 接入 `/api/auth/login-options`
13. [x] 接入 `/api/auth/phone/send-code`
14. [x] 接入 `/api/auth/phone/login`
15. [x] 接入 `/api/auth/wechat/start`
16. [x] 接入 `/api/auth/wechat/callback`
17. [x] 接入 `/api/auth/wechat/bind-phone`
18. [x] 接入 `/api/assets/objects/bind`
19. [x] 接入 `/api/assets/sts-upload-credentials`
20. [x] 接入 `custom world library / gallery / publish_world` 首批 facade
21. [x] 接入 `custom world agent session create / snapshot` facade
22. [x] 下线旧 `runtime story` compat facade并接入 story session scoped runtime story 写读入口
23. [x] 接入 `character-visual generate / jobs / publish` 第一批 OSS 主链兼容 facade
24. [x] 接入 `character-animation templates / import-video` 第一批 OSS 草稿兼容 facade
25. [x] 接入 `character-workflow-cache get / save` 第一批 OSS JSON 草稿兼容 facade
26. [x] 接入 `character-animation generate / jobs / publish` 第一批 OSS 主链兼容 facade
27. [x] 下线旧 `/generated-*` 路径 OSS 私有读同源代理
28. [x] 下线旧 `/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`、响应头与错误中间件继续在同一层扩展。
当前 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.apiVersion``meta.requestId``meta.routeVersion``meta.operation``meta.latencyMs``meta.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-id``x-api-version``x-route-version``x-response-time-ms` 会在 `/healthz` 响应中一并回写。
当前本地检查链路约定:
1. `../../scripts/check.ps1``../../scripts/check.sh` 统一串联 `cargo fmt --all --check``cargo clippy``cargo check``cargo test`
2. 默认检查整个 `server-rs` workspace确保后续多 crate 扩容时仍然保持统一口径。
3. 当只需聚焦单个 crate 时,可通过 `-Package``SERVER_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-id``x-api-version``x-route-version``x-response-time-ms` 头。
3. smoke 通过后可作为“Axum 服务可独立启动且基础 contract 可联通”的本地自动化证据。
## 3. 边界约束
1. `api-server` 负责 HTTP、SSE、Cookie、Header、路由与协议装配。
2. 业务逻辑优先通过独立模块 crate 暴露能力,再由主工程组合。
3. 外部副作用通过 `platform-auth``platform-oss``platform-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_object``asset_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` 进入后端真相源。