171 lines
12 KiB
Markdown
171 lines
12 KiB
Markdown
# 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/runtime/story/state/resolve`
|
||
- `GET /api/runtime/story/state/{session_id}`
|
||
- `POST /api/runtime/story/actions/resolve`
|
||
- `POST /api/runtime/story/initial`
|
||
- `POST /api/runtime/story/continue`
|
||
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-character-drafts/*`、`/generated-characters/*`、`/generated-animations/*`、`/generated-custom-world-scenes/*`、`/generated-custom-world-covers/*`、`/generated-qwen-sprites/*` 到 OSS 私有读代理
|
||
|
||
后续与本 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
|
||
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 私有读同源代理
|
||
|
||
当前 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/*` 已在 Rust 侧补齐 compat handler,但内部仍是 `runtime_snapshot` 驱动的兼容桥与确定性动作编排,不应误判为真正的 SpacetimeDB `resolve_story_action` 真相链已完成。
|
||
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 前缀到 OSS 私有读签名,不回退仓库 `public/`,Stage 1 不支持视频 Range 分片。
|