d0176f48b7
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
按需求文档 revision 1554「发布设置页 → 二创信息区(必填项)」:衍生作品(有血缘行)发布新版本时**必须** 提供「本次核心改动说明」;母版(0 代)不需要——提供了也忽略、不校验、不落库。 - **存储**:`game_distribution_version` **表尾追加** `change_summary: Option<String>`(`#[default(None)]`); 列序属 wire format,`game_distribution_version_type` / `_version_snapshot_type` / `_create_version_input_type` 三个绑定同步重生成(仓外临时 out-dir,只回写受影响文件)。 - **请求**:`GameDistributionCreateVersionRequest.change_summary`(`#[serde(default, skip_serializing_if)]`: 缺省不序列化 `null`,保住旧客户端的幂等摘要)。 - **校验**:纯函数 `game_distribution_change_summary_violation(value, is_derivative)`,trim 后按**字符**计 **20..=500** —— 20 是「能写清改了什么」的下限,500 约 1 KiB 上限,兼顾详情页/族谱展示与存储; 超限或缺失**失败关闭**,错误码 `FORK_CHANGE_SUMMARY_REQUIRED` / `FORK_CHANGE_SUMMARY_INVALID`(均 **400**), 已登记进 api-server 的 `FORK_` 映射表并纳入「FORK 码由模块真实文案可达」的枚举测试(防上次那种不可达码)。 - **公开投影**:`currentVersion.changeSummary`(衍生为字符串、母版 `null`,发键不发值),版本负载键集合 逐字钉死为 id/version/entryUrl/sha256/publishedAt/controls/changeSummary,不带对象键/素材 id/审核字段。 - **契约与登记**:Rust DTO + TS 镜像 + parity(`version_summary_payload` 加 `mustEmit: ['changeSummary']`)。 - **文档**:技术方案 `§3.4`(请求增量 + 长度口径与理由 + 两个错误码 + 幂等摘要口径 + 公开投影)、数据契约 文档的版本表小节(表尾追加列)。 - **测试**:纯函数 5 条(衍生缺失/超短(ASCII 与汉字)/超长(ASCII 与汉字)/区间内 trim 边界/母版忽略)+ 事务 4 条 + 接口 3 条(含公开负载键集合与母版 null)。 门禁:`SPACETIME_SCHEMA_BASE_REF=9f4c7d76 npm run check:spacetime-schema` 0(98 表);`cargo check --all-targets` 0; `cargo test -p module-game-distribution` **119 passed**;`cargo test -p api-server game_distribution` **104 passed**; DTO parity 0(62 组 / 17 构建器 / 15 手拼类型);`check:encoding` 0(5535 files); `cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 0;`git diff --check` 0。 注:本块**未提交** `scripts/check-game-distribution-lineage-e2e.mjs` / `check-game-distribution-theme-e2e.mjs` / `capture-game-lineage-visual.mjs` 的配套改动(属别的 session 的文件,工作区里保留未提交,需其 owner 决定: 衍生作品发布若不传 `changeSummary` 现在会 400,那三个脚本需要同步补字段)。
api-server 主工程 crate 占位说明
日期:2026-04-20
1. crate 职责
api-server 是新后端的 Axum 主工程 crate,后续负责:
main.rs启动入口Router装配with_state共享状态注入- 中间件挂载
/healthz、/api/*、SSE 与静态资源兼容层装配- 由
../../scripts/dev.ps1与../../scripts/dev.sh驱动的本地开发启动链路 - 由
../../scripts/test.ps1与../../scripts/test.sh驱动的本地测试链路 - 由
../../scripts/check.ps1与../../scripts/check.sh驱动的本地统一检查链路 - 由
../../scripts/smoke.ps1与../../scripts/smoke.sh驱动的本地启动与协议冒烟链路
2. 当前阶段说明
当前目录已经完成以下基础骨架:
- 目录占位
Cargo.tomlsrc/main.rssrc/app.rssrc/state.rssrc/config.rs- 基础
TraceLayer挂载 - 接入
shared-logging完成tracing subscriber初始化 - 接入
POST /api/auth/entry首版密码登录链路 - 接入
POST /api/auth/password/change登录后修改密码链路 - 接入
POST /api/auth/password/reset手机验证码重置密码链路 - 接入
POST /api/assets/direct-upload-tickets直传票据接口 - 接入
GET /api/auth/me当前用户查询链路 - 接入
POST /api/auth/refreshrefresh token 轮换链路 - 接入
POST /api/auth/logout当前设备退出链路 - 接入
POST /api/assets/objects/confirm上传完成确认链路 - 接入
GET /api/auth/login-options登录方式探测链路 - 接入
POST /api/auth/phone/send-code手机验证码发送链路 - 接入
POST /api/auth/phone/login手机验证码登录链路 - 接入
GET /api/auth/wechat/start微信授权起跳链路 - 接入
GET /api/auth/wechat/callback微信回调换取系统登录态链路 - 接入
POST /api/auth/wechat/bind-phone微信待绑定账号补绑手机号链路 - 接入
POST /api/assets/objects/bind已确认对象绑定业务实体槽位链路 - 接入
POST /api/assets/sts-upload-credentials禁用式 STS 写权限 contract - 接入
POST /api/assets/character-visual/generate - 接入
GET /api/assets/character-visual/jobs/{task_id} - 接入
POST /api/assets/character-visual/publish - 接入
GET /api/assets/character-animation/templates - 接入
POST /api/assets/character-animation/import-video - 接入
GET /api/assets/character-workflow-cache/{character_id} - 接入
POST /api/assets/character-workflow-cache - 接入
POST /api/assets/character-animation/generate - 接入
GET /api/assets/character-animation/jobs/{task_id} - 接入
POST /api/assets/character-animation/publish - 生成资产读取统一走
/api/assets/read-url或 asset object projection
后续与本 crate 直接相关的任务包括:
- 接入统一日志与 tracing
- 接入
request_id - 接入统一错误处理中间件
- 接入 response envelope
- 接入
/healthz - 接入
/api/auth/entry - 接入
/api/assets/direct-upload-tickets - 接入
/api/auth/me - 接入
/api/auth/refresh - 接入
/api/auth/logout - 接入
/api/assets/objects/confirm - 接入
/api/auth/login-options - 接入
/api/auth/phone/send-code - 接入
/api/auth/phone/login - 接入
/api/auth/wechat/start - 接入
/api/auth/wechat/callback - 接入
/api/auth/wechat/bind-phone - 接入
/api/assets/objects/bind - 接入
/api/assets/sts-upload-credentials - 接入
character-visual generate / jobs / publish第一批 OSS 主链 - 接入
character-animation templates / import-video第一批 OSS 草稿链路 - 接入
character-workflow-cache get / save第一批 OSS JSON 草稿链路 - 接入
character-animation generate / jobs / publish第一批 OSS 主链 - 生成资产读取统一走
/api/assets/read-url或 asset object projection
当前 tracing 约定:
- 进程启动时通过
shared-logging统一初始化tracing subscriber。 - 默认日志过滤器来自
GENARRATIVE_API_LOG,未提供时回落到info,tower_http=info。 - HTTP 访问日志统一通过 Axum 路由层的
TraceLayer输出,后续request_id、响应头与错误中间件继续在同一层扩展。 - 本地启动器
npm run dev:api-server和完整联调入口npm run dev会在保留终端实时输出的同时,把同一份cargo/api-server输出持久化到logs/api-server/。如需固定文件或目录,可设置GENARRATIVE_API_SERVER_LOG_FILE或GENARRATIVE_API_SERVER_LOG_DIR。
当前 request context 约定:
- 中间件优先读取来访
x-request-id,未提供时生成新的 UUID。 request_id会统一写入请求extensions与请求头,供 tracing、错误处理中间件和响应头层复用。- 最终响应会回写同一个
x-request-id,保证调用方、日志链路和后续 envelopemeta.requestId可对齐。
当前错误处理中间件约定:
- 对 Axum 默认产生的空
4xx / 5xx响应,统一归一化为 legacy 兼容 JSON 错误体:{ error: { code, message, details? } }。 - 已经带
content-type的业务错误响应不会被覆盖,避免抢走后续 response envelope 的职责。 - 统一错误日志会复用当前请求的
request_id,便于后续和响应头、envelope 元信息串联。
当前 response envelope 约定:
RequestContext已记录request_id、请求开始时间、默认operation与 envelope 协商结果。json_success_body(...)/json_error_body(...)会根据x-genarrative-response-envelope自动在“裸数据 / 标准 envelope / legacy error + meta”之间切换。meta.apiVersion、meta.requestId、meta.routeVersion、meta.operation、meta.latencyMs、meta.timestamp已按当前前端契约生成,响应头回写仍留给后续独立任务。
当前基础响应头约定:
- 所有响应都会回写
x-request-id。 - 所有响应都会回写固定的
x-api-version,值来自shared_contracts::api::API_VERSION,当前为2026-06-16,并与 bodymeta.apiVersion保持一致。 - 所有响应都会回写
x-route-version,当前阶段默认与x-api-version保持一致,后续再按路由粒度细分。 - 所有响应都会回写
x-response-time-ms,值来源于RequestContext内记录的请求开始时间。
当前 /healthz 约定:
- 路径固定为
/healthz。 - 裸响应继续返回
{ ok: true, service: "genarrative-node-server" },保持与当前 Node 工程兼容。 - 当请求携带
x-genarrative-response-envelope时,/healthz会返回标准 success envelope。 x-request-id、x-api-version、x-route-version、x-response-time-ms会在/healthz响应中一并回写。
当前本地检查链路约定:
../../scripts/check.ps1与../../scripts/check.sh统一串联cargo fmt --all --check、cargo clippy、cargo check、cargo test。- 默认检查整个
server-rsworkspace,确保后续多 crate 扩容时仍然保持统一口径。 - 当只需聚焦单个 crate 时,可通过
-Package或SERVER_RS_CHECK_PACKAGE收窄clippy / check / test目标。 cargo fmt --all --check仍固定覆盖整个 workspace,避免多 crate 下格式基线漂移。
当前本地 smoke 链路约定:
../../scripts/smoke.ps1与../../scripts/smoke.sh会先构建api-server,再拉起临时本地进程完成冒烟验证。- smoke 当前固定校验
/healthz的 raw 响应、envelope 响应以及x-request-id、x-api-version、x-route-version、x-response-time-ms头。 - smoke 通过后,可作为“Axum 服务可独立启动且基础 contract 可联通”的本地自动化证据。
3. 边界约束
api-server负责 HTTP、SSE、Cookie、Header、路由与协议装配。- 业务逻辑优先通过独立模块 crate 暴露能力,再由主工程组合。
- 外部副作用通过
platform-auth、platform-oss、platform-llm与各模块 crate 的应用层完成。 - 不把领域规则直接堆在 handler 中。
- 当前密码登录由
module-auth负责用例编排,api-server只负责请求解析、JWT 签发与 refresh cookie 写回。 - 当前
/api/auth/me复用现有 Bearer JWT 中间件与module-auth用户快照查询,不直接绕过模块边界读取内部状态。 - 当前
/api/auth/refresh复用module-auth的 refresh session 轮换能力,api-server负责 refresh cookie 读取、失败清理与 access token 重签。 - 当前
/api/auth/logout复用module-auth的当前会话吊销与用户版本递增能力,api-server负责 Bearer JWT、refresh cookie 读取与清理 cookie 回写。 - 当前
/api/assets/objects/confirm先由platform-oss完成私有HEAD Object校验,再通过spacetime-client调用spacetime-module的对象确认持久化入口。 - 当前
/api/assets/objects/bind只绑定已确认对象到业务实体槽位,不访问 OSS,不创建悬空asset_object_id。 - 当前手机号登录与微信登录都复用
module-auth的进程内认证仓储,api-server负责请求解析、场景判定、系统 JWT 签发与 refresh cookie 写回。 - 当前微信回调不会把第三方 token 直接透传给前端或 SpacetimeDB,而是统一换成系统签发的 JWT。
- 当前
/api/assets/sts-upload-credentials按“服务器上传、Web 只下载”口径固定返回403,不向浏览器下发 OSS 写权限。 - 当前
/api/assets/character-visual/*第一批只保证现役接口 contract、OSS 草稿/正式对象、asset_object与asset_entity_binding主链可用;真实图片模型、workflow cache 与本地角色覆盖写回仍在后续阶段。 - 当前
/api/assets/character-animation/import-video第一批只接受data:video/*;base64,...并写入 OSS 草稿区,不读取旧本地public/路径,也不创建正式asset_object。 - 当前
/api/assets/character-workflow-cache/*第一批只把工作流 JSON 草稿写入 OSS,不迁移历史本地缓存,也不创建正式asset_object。 - 当前
/api/assets/character-animation/generate第一批只用 Rust 占位产物打通AiTaskService + OSS草稿链;image-sequence写 SVG 帧,视频类策略优先复用参考视频或仓库内可播放占位视频,不代表真实上游视频模型已完成迁移。 - 当前
/api/assets/character-animation/publish会把前端提交帧、动作级 manifest 与总 manifest 写入 OSS,并只把总 manifest 确认为asset_object后绑定到character / animation_set。 /generated-*只作为legacyPublicPath/ OSS object key 标识,读取必须通过/api/assets/read-url或业务投影中的签名读 URL。