feat: complete M7 cutover preparation

This commit is contained in:
2026-04-22 17:46:50 +08:00
parent 4c8ba535e4
commit 2fe0a9083d
19 changed files with 8258 additions and 7809 deletions

View File

@@ -0,0 +1,133 @@
# M7 联调、回归、部署与切流执行方案
日期:`2026-04-22`
## 1. 文档目标
这份文档把 `M7联调、回归、部署与切流任务清单` 从高层勾选项细化为可直接执行的工程方案。
M7 的目标不是新增玩法功能,而是在 `M0 ~ M6` 已迁移的 Rust 后端基础上完成切流前收口:
1. 固定本地、灰度、切流前的检查命令。
2. 固定 `Axum + SpacetimeDB + OSS` 的部署与回滚口径。
3. 固定观测字段、慢请求、上游失败日志与资产任务日志。
4. 固定旧 `server-node` 与新 `server-rs` 的双跑和 API 对比方式。
5. 等价拆分 `server-rs/crates/spacetime-module/src/lib.rs`,避免 SpacetimeDB 主工程继续退化为单大文件。
## 2. 执行约束
1. 不改变现有 HTTP contract、SSE contract、SpacetimeDB 表名、reducer 名、procedure 名和对象键前缀。
2. 不把 LLM、OSS、短信、微信等外部副作用移入 SpacetimeDB reducer。
3. `spacetime-module` 拆分只做物理结构收口,不做 schema 重命名、字段删除、字段重排或 reducer/procedure 改名。
4. 迁移期保留 `server-node` 作为回退锚点M7 不删除旧后端。
5. 前端切换默认仍指向 Node只有显式设置 `GENARRATIVE_BACKEND_STACK=rust``GENARRATIVE_RUNTIME_SERVER_TARGET` 时才切到 Rust。
## 3. 测试体系
M7 固定四层测试入口:
1. Rust crate 级别:`cargo check/test` 覆盖 `api-server``spacetime-module``shared-contracts` 与模块 crate。
2. Axum handler 级别:继续复用 `api-server` 内已有 `build_router + tower::ServiceExt` 测试,重点覆盖 `healthz/auth/runtime/assets/custom-world/story` 的兼容响应。
3. SpacetimeDB 模块级别:`cargo check -p spacetime-module` 作为 schema/reducer/procedure 的最低门禁;需要真实数据库行为时使用 `spacetime publish --server local --yes` 后再跑 smoke。
4. 端到端主流程:`server-rs/scripts/smoke.ps1``server-rs/scripts/oss-smoke.ps1` 分别覆盖基础 HTTP contract 与真实 OSS 链路。
推荐本地顺序:
```powershell
.\server-rs\scripts\m7-preflight.ps1
.\server-rs\scripts\smoke.ps1
node scripts\run-tsx.cjs scripts\m7-api-compare.ts
```
## 4. 部署准备
Axum 部署方式:
1. `cargo build -p api-server --release` 生成发布二进制。
2. 进程环境显式配置 `GENARRATIVE_API_HOST``GENARRATIVE_API_PORT``GENARRATIVE_API_LOG`
3. 反向代理继续保留 `Host``X-Forwarded-For``X-Forwarded-Proto``X-Request-Id`
4. SSE 路由必须禁用代理缓冲。
SpacetimeDB 发布方式:
1. 本地开发先执行 `server-rs/scripts/spacetime-dev.ps1` 启动 standalone。
2. 发布模块使用 `spacetime publish genarrative-dev --server local --yes --module-path server-rs/crates/spacetime-module`
3. 若需要重置开发库,必须显式加 `--clear-database --yes`,不得默认清库。
4. 生成绑定时使用仓库根目录 `spacetime.json` 中的 `typescript``rust` 输出目录。
OSS / CDN / 域名方案:
1. 正式对象真相仍为 `bucket + object_key`
2. bucket 默认私有读写,浏览器不直接匿名读取。
3. `/generated-*` 旧路径由 Axum 同源代理或 CDN 边缘回源到 Rust API。
4. CDN 只缓存可公开缓存的派生读结果,不把私有签名 URL 写入业务表。
环境变量最小清单:
1. `GENARRATIVE_API_HOST``GENARRATIVE_API_PORT``GENARRATIVE_API_LOG`
2. `GENARRATIVE_JWT_ISSUER``GENARRATIVE_JWT_SECRET`
3. `GENARRATIVE_SPACETIME_SERVER_URL``GENARRATIVE_SPACETIME_DATABASE``GENARRATIVE_SPACETIME_TOKEN`
4. `ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET`
5. `GENARRATIVE_LLM_PROVIDER``GENARRATIVE_LLM_BASE_URL``GENARRATIVE_LLM_API_KEY`
6. `DASHSCOPE_BASE_URL``DASHSCOPE_API_KEY`
7. `SMS_AUTH_ENABLED` 与短信供应商变量
8. `WECHAT_AUTH_ENABLED` 与微信 OAuth 变量
9. `GENARRATIVE_BACKEND_STACK``NODE_SERVER_TARGET``RUST_SERVER_TARGET``GENARRATIVE_RUNTIME_SERVER_TARGET`
## 5. 灰度与切流
灰度环境固定为三段:
1. `shadow`Node 继续承接用户流量Rust 只由脚本和内部账号请求。
2. `dual-run`:同一组 smoke/API compare 同时打 Node 与 Rust差异必须登记。
3. `rust-primary`:反向代理或 Vite dev proxy 指向 RustNode 进程保留但不作为主入口。
前端切换方式:
1. 默认 `GENARRATIVE_BACKEND_STACK=node`
2. 本地或灰度切 Rust 设置 `GENARRATIVE_BACKEND_STACK=rust`,并配置 `RUST_SERVER_TARGET`
3. 紧急回退设置 `GENARRATIVE_BACKEND_STACK=node` 或直接覆盖 `GENARRATIVE_RUNTIME_SERVER_TARGET` 指回 Node。
## 6. API 对比
`scripts/m7-api-compare.ts` 负责对比 Node 与 Rust 的基础 contract
1. 默认对比 `/healthz``/api/auth/login-options`
2. 可通过 `M7_COMPARE_PATHS` 扩展只读路径清单。
3. 对比时会固定传入 `x-request-id`,并归一化 `requestId / timestamp / latencyMs` 等波动字段。
4. 默认严格模式下发现差异直接返回非零退出码。
该脚本只承担“无状态 GET contract”对比带登录、写入、OSS 或 SSE 的主流程仍由专门 smoke 脚本负责。
## 7. 观测能力
M7 观测字段固定为:
1. HTTP 访问日志:`method``uri``status``latency_ms``slow_request``request_id`
2. 错误日志:`request_id``status``error_code`
3. 上游失败:`provider``operation``request_id``status/code``message`
4. 关键 reducer操作名、主实体 ID、结果状态
5. 资产任务:`task_id``character_id/entity_id``asset_kind``status`
慢请求阈值默认 `1000ms`,可通过 `GENARRATIVE_SLOW_REQUEST_THRESHOLD_MS` 覆盖。
## 8. 数据迁移与回滚
当前 M7 不做一次性“Node PostgreSQL 全量导入 SpacetimeDB”的危险迁移采用双跑验证与按主链确认的渐进策略
1. 已迁移主链以 SpacetimeDB 为真相源。
2. 未迁移或灰度失败主链继续回退到 Node。
3. 资产二进制以 OSS 为真相,不回滚到本地 `public/generated-*` 写盘。
4. 若 SpacetimeDB schema 需要清库重发,只允许在开发库或明确灰度库执行 `--clear-database`
5. 生产回滚优先切反向代理目标,不优先改代码。
## 9. 验收定义
M7 完成时必须满足:
1. M7 文档、脚本、任务清单均同步。
2. `api-server``spacetime-module` 至少通过 `cargo check`
3. 基础 smoke 脚本可执行,并覆盖 `healthz + envelope + request id`
4. Node/Rust API 对比脚本可执行。
5. Vite dev proxy 已具备 Node/Rust 切换与回退开关。
6. `spacetime-module` 已从单 `lib.rs` 拆为按 `runtime / gameplay / custom_world / asset_metadata / ai` 组织的文件结构。

View File

@@ -52,6 +52,7 @@
- [M6_CHARACTER_ANIMATION_IMPORT_AND_TEMPLATE_STAGE1_2026-04-22.md](./M6_CHARACTER_ANIMATION_IMPORT_AND_TEMPLATE_STAGE1_2026-04-22.md):冻结 `M6` 第一批角色动作模板查询与参考视频导入从旧 Node 本地草稿写盘切到 Rust `OSS` 草稿对象的接口 contract、对象键规划与暂不确认 `asset_object` 的边界。
- [M6_CHARACTER_WORKFLOW_CACHE_OSS_STAGE1_2026-04-22.md](./M6_CHARACTER_WORKFLOW_CACHE_OSS_STAGE1_2026-04-22.md):冻结 `M6` 第一批角色资产工作流缓存从旧 Node 本地 `workflow-cache.json` 切到 Rust `OSS` JSON 草稿对象的读写 contract、字段归一化与暂不落正式资产表的边界。
- [M6_CHARACTER_VISUAL_ASSET_OSS_INTEGRATION_STAGE1_2026-04-22.md](./M6_CHARACTER_VISUAL_ASSET_OSS_INTEGRATION_STAGE1_2026-04-22.md):冻结 `M6` 第一批角色主形象 `generate / jobs / publish` 接口从旧本地 `public/generated-*` 真相切到 `OSS + asset_object + asset_entity_binding + AI task` 的最小闭环与兼容 contract。
- [M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md](./M7_TEST_DEPLOY_CUTOVER_EXECUTION_PLAN_2026-04-22.md):冻结 `M7` 联调、回归、部署、观测、双跑对比、灰度切流、回滚和 `spacetime-module` 结构收口的可执行方案。
- [M3_BROWSE_HISTORY_AXUM_SPACETIMEDB_DESIGN_2026-04-21.md](./M3_BROWSE_HISTORY_AXUM_SPACETIMEDB_DESIGN_2026-04-21.md):冻结 `M3` 第二批 `browse history` 纵向切片的 `user_browse_history` 表、双路径 facade、宽松归一化、去重排序规则与测试策略。
- [ASSET_ENTITY_BINDING_REDUCER_DESIGN_2026-04-21.md](./ASSET_ENTITY_BINDING_REDUCER_DESIGN_2026-04-21.md):冻结已确认 `asset_object` 绑定到业务实体槽位的首版 reducer/procedure、通用 `asset_entity_binding` 表与 Axum facade。
- [FRONTEND_TO_BACKEND_MIGRATION_EXECUTION_PLAN_2026-04-21.md](./FRONTEND_TO_BACKEND_MIGRATION_EXECUTION_PLAN_2026-04-21.md)把鉴权、浏览历史、runtime story 快照、NPC 待接委托与正式生成编排继续后移到 Express 后端的实施方案与验收口径。