Merge branch 'master' into codex/ddd
This commit is contained in:
@@ -259,7 +259,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
`tableStats` 中单表失败必须展示 `errorMessage`,不能让整页变成空白。SpacetimeDB private 表或当前身份不可见的表在 `/sql` 下可能返回 `no such table` / `marked private`,后台服务必须将这类错误归一为“不可统计(private 或当前身份不可见)”,避免把预期的访问边界展示成原始 HTTP 400 故障。
|
||||
|
||||
线上如果大量表都显示“不可统计(private 或当前身份不可见)”,优先检查 `api-server` 启动环境中的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN` 是否存在且属于目标库 owner。Jenkins 覆盖发布包时必须保留部署目录已有运行 token;只带迁移 token 不能让后台概览读取 private 表。
|
||||
线上如果大量表都显示“不可统计(private 或当前身份不可见)”,优先检查 `api-server` 启动环境中的 `GENARRATIVE_SPACETIME_TOKEN` 是否存在且属于目标库 owner。Jenkins 覆盖发布包时必须保留部署目录已有运行 token;只带迁移 token 不能让后台概览读取 private 表。
|
||||
|
||||
### 4.6 API 调试 contract
|
||||
|
||||
@@ -380,7 +380,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
|
||||
### 7.1 本地联调
|
||||
|
||||
1. 启动后端:`npm run api-server:maincloud`。
|
||||
1. 启动后端:`npm run api-server`。
|
||||
2. 启动后台前端:在 `apps/admin-web` 执行 `npm run dev`。
|
||||
3. 后台 dev server 通过 Vite proxy 转发 `/admin/api` 到 `ADMIN_API_TARGET`;未配置时默认 `http://127.0.0.1:3100`。
|
||||
4. 若使用非 3100 端口,在仓库根目录 `.env.local` 设置 `ADMIN_API_TARGET=http://127.0.0.1:<api-server-port>`,并重启后台前端 dev server。
|
||||
@@ -437,7 +437,7 @@ export interface ProfileInviteCodeAdminResponse {
|
||||
- 后续接入根 workspace 后,补充后台工程 build/typecheck 脚本。
|
||||
3. 后端:
|
||||
- 继续保留 `cargo test -p api-server --manifest-path server-rs/Cargo.toml admin`。
|
||||
- 修改后端管理 API 后必须运行 `npm run api-server:maincloud` 并手动验证 `/admin` 为 404、`/admin/api/login` 可用。
|
||||
- 修改后端管理 API 后必须运行 `npm run api-server` 并手动验证 `/admin` 为 404、`/admin/api/login` 可用。
|
||||
|
||||
## 9. 后续扩展边界
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
## 2. 根因
|
||||
|
||||
### 2.1 Maincloud 目标库挂起
|
||||
### 2.1 远端目标库挂起
|
||||
|
||||
CLI 直接查询 `xushi-p4wfr` 返回:
|
||||
|
||||
@@ -20,7 +20,7 @@ Error: database is suspended
|
||||
HTTP status server error (503 Service Unavailable)
|
||||
```
|
||||
|
||||
这说明 `maincloud.spacetimedb.com` 入口在线,但具体数据库 `xushi-p4wfr` 当前不可订阅、不可查 schema、不可执行 SQL。所有依赖该库的 procedure 都会失败。
|
||||
这说明远端 SpacetimeDB 入口在线,但具体数据库 `xushi-p4wfr` 当前不可订阅、不可查 schema、不可执行 SQL。所有依赖该库的 procedure 都会失败。
|
||||
|
||||
### 2.2 认证快照同步被当成硬失败
|
||||
|
||||
@@ -64,7 +64,7 @@ HTTP status server error (503 Service Unavailable)
|
||||
|
||||
## 4. 本地可跑链路
|
||||
|
||||
Maincloud `xushi-p4wfr` 挂起期间,抓大鹅本地体验应使用本地 SpacetimeDB:
|
||||
远端 `xushi-p4wfr` 挂起期间,抓大鹅本地体验应使用本地 SpacetimeDB:
|
||||
|
||||
```powershell
|
||||
spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101
|
||||
@@ -75,10 +75,10 @@ spacetime --root-dir=server-rs/.spacetimedb/local publish xushi-p4wfr --server h
|
||||
再让 Rust API 指向本地库:
|
||||
|
||||
```powershell
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL="http://127.0.0.1:3101"
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE="xushi-p4wfr"
|
||||
$env:GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN=""
|
||||
npm run api-server:maincloud
|
||||
$env:GENARRATIVE_SPACETIME_SERVER_URL="http://127.0.0.1:3101"
|
||||
$env:GENARRATIVE_SPACETIME_DATABASE="xushi-p4wfr"
|
||||
$env:GENARRATIVE_SPACETIME_TOKEN=""
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
最后重启前端:
|
||||
@@ -96,10 +96,10 @@ npm run dev:web
|
||||
1. `GET http://127.0.0.1:3000/api/auth/login-options` 返回 `["phone","password"]`。
|
||||
2. `GET http://127.0.0.1:3000/api/runtime/match3d/gallery` 返回 `{"items":[]}`,不再返回 SpacetimeDB 503。
|
||||
3. 未登录请求 `POST http://127.0.0.1:3000/api/creation/match3d/sessions` 返回 `401`,说明同源请求已进入 Rust 鉴权层,不再被 Vite `404`。
|
||||
4. 隔离端口指向挂起的 Maincloud 并使用 mock 短信时,手机号验证码登录返回 `200` 和 token;日志只记录“认证快照写入 SpacetimeDB 失败,当前认证流程继续”。
|
||||
4. 隔离端口指向挂起的远端库并使用 mock 短信时,手机号验证码登录返回 `200` 和 token;日志只记录“认证快照写入 SpacetimeDB 失败,当前认证流程继续”。
|
||||
|
||||
## 6. 后续
|
||||
|
||||
1. Maincloud `xushi-p4wfr` 仍需恢复数据库挂起状态,否则正式云端玩法 procedure 仍不可用。
|
||||
1. 远端 `xushi-p4wfr` 仍需恢复数据库挂起状态,否则对应玩法 procedure 仍不可用。
|
||||
2. 本地开发如只为体验抓大鹅,可继续使用本地 SpacetimeDB 链路。
|
||||
3. 认证快照同步失败会影响进程重启后的云端恢复完整性,需要在 Maincloud 恢复后重新完成一次成功同步。
|
||||
3. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
但当前链路仍暴露出两个直接体验问题:
|
||||
|
||||
1. 前端草稿进度页仍把大鱼吃小鱼展示成单个 `compile` 步骤,用户会感觉“整个生成过程只有一步,而且一直卡在第一步”。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 Maincloud 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 SpacetimeDB 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
|
||||
## 修复口径
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
这样可以覆盖两类常见情况:
|
||||
|
||||
1. Maincloud 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
1. SpacetimeDB 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
2. 用户打开草稿页时碰到短暂断链,不再被立即判定成稳定的坏网关故障。
|
||||
|
||||
## 落地范围
|
||||
|
||||
@@ -39,7 +39,7 @@ Genarrative-Database-Export
|
||||
关键参数:
|
||||
|
||||
1. `DATABASE`:目标 SpacetimeDB 数据库名;留空时读取仓库环境变量。
|
||||
2. `SERVER`:SpacetimeDB server 别名,默认 `maincloud`。
|
||||
2. `SERVER`:SpacetimeDB server 别名,默认 `dev`。
|
||||
3. `SERVER_URL`:显式服务地址;填写后优先于 `SERVER`。
|
||||
4. `DEPLOY_DIRECTORY`:固定部署目录,默认 `/var/lib/jenkins/deploy/Genarrative`。
|
||||
5. `ROOT_DIR`:可选,透传给 `spacetime --root-dir`;为空时使用 `<DEPLOY_DIRECTORY>/.spacetimedb`。
|
||||
@@ -91,7 +91,7 @@ Genarrative-Database-Import
|
||||
|
||||
## 5. 本地部署测试参数
|
||||
|
||||
`Genarrative-Build-And-Deploy` 增加以下本地发布包参数,便于在 Jenkins 中测试本地 SpacetimeDB,不依赖 Maincloud:
|
||||
`Genarrative-Build-And-Deploy` 增加以下本地发布包参数,便于在 Jenkins 中测试本地 SpacetimeDB:
|
||||
|
||||
1. `DATABASE`:发布包默认数据库名,默认 `genarrative-pipeline-local-test`。SpacetimeDB CLI 当前要求数据库名匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;不要使用大写字母、点号、下划线、首尾短横线或连续短横线。
|
||||
2. `API_PORT`:发布包内 api-server 端口,默认 `8082`。
|
||||
@@ -107,7 +107,7 @@ SERVER_URL=http://127.0.0.1:3101
|
||||
DEPLOY_DIRECTORY=/var/lib/jenkins/deploy/Genarrative
|
||||
```
|
||||
|
||||
这样脚本会自动使用 `/var/lib/jenkins/deploy/Genarrative/.spacetimedb` 作为 `spacetime --root-dir`,避免回退到 Jenkins 用户全局 CLI 登录态,也避免误连 Maincloud。
|
||||
这样脚本会自动使用 `/var/lib/jenkins/deploy/Genarrative/.spacetimedb` 作为 `spacetime --root-dir`,避免回退到 Jenkins 用户全局 CLI 登录态,也避免误连非本地目标。
|
||||
|
||||
## 6. 文件清单
|
||||
|
||||
|
||||
@@ -76,4 +76,4 @@ Responses 非流式解析优先读取 `output_text`,再兼容 `output[].conten
|
||||
3. `platform-llm` 单测覆盖 Responses 非流式、Responses SSE、Responses web_search tools 请求体。
|
||||
4. `cargo test -p platform-llm --manifest-path server-rs/Cargo.toml` 通过。
|
||||
5. `cargo test -p api-server creation_agent_llm_turn --manifest-path server-rs/Cargo.toml` 通过。
|
||||
6. 修改后按项目约束使用 `npm run api-server:maincloud` 重新启动后端,并执行相应自动测试。
|
||||
6. 修改后按项目约束使用 `npm run api-server` 重新启动后端,并执行相应自动测试。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
日期:`2026-04-22`
|
||||
|
||||
归档说明:截至 `2026-04-26`,Rust 迁移已完成,旧 `server-node/` 已删除,M7 阶段性预检包装入口已移除。后续长期检查统一使用 `server-rs/scripts/check.ps1`、`server-rs/scripts/smoke.ps1`、`server-rs/scripts/oss-smoke.ps1` 与 `npm run api-server:maincloud`。
|
||||
归档说明:截至 `2026-04-26`,Rust 迁移已完成,旧 `server-node/` 已删除,M7 阶段性预检包装入口已移除。后续长期检查统一使用 `server-rs/scripts/check.ps1`、`server-rs/scripts/smoke.ps1`、`server-rs/scripts/oss-smoke.ps1` 与 `npm run api-server`。
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
|
||||
@@ -784,7 +784,7 @@ B3 当前落地状态:
|
||||
1. 创作到发布到试玩主链通过。
|
||||
2. 运行态点击、入槽、三消、失败、胜利通过。
|
||||
3. 移动端视口检查通过。
|
||||
4. `npm run api-server:maincloud` 通过。
|
||||
4. `npm run api-server` 通过。
|
||||
5. 对应测试与 `npm run check:encoding` 通过。
|
||||
|
||||
---
|
||||
@@ -820,7 +820,7 @@ npm run check:encoding -- docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IM
|
||||
```powershell
|
||||
cargo test -p module-match3d
|
||||
cargo test -p shared-contracts
|
||||
npm run api-server:maincloud
|
||||
npm run api-server
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
|
||||
@@ -110,4 +110,4 @@ server-rs/crates/module-match3d
|
||||
1. `cargo test -p module-match3d` 通过。
|
||||
2. `cargo test -p shared-contracts match3d` 通过。
|
||||
3. `npm run check:encoding` 覆盖新增中文文档和新增源码。
|
||||
4. 本阶段不要求运行 `npm run api-server:maincloud`,因为未修改后端运行服务入口、SpacetimeDB 表或 `api-server` facade。
|
||||
4. 本阶段不要求运行 `npm run api-server`,因为未修改后端运行服务入口、SpacetimeDB 表或 `api-server` facade。
|
||||
|
||||
@@ -143,4 +143,4 @@ npm run check:encoding
|
||||
3. 不把 Match3D 公开广场并入更复杂的推荐、排行和运营榜单策略。
|
||||
4. 不删除 `/match3d` 本地 playground;它作为开发调试入口继续保留。
|
||||
5. 全量 `npm run typecheck` 曾存在非 Match3D 既有阻塞,本轮以 Q1 定向测试和后端定向检查作为集成验收口径。
|
||||
6. Maincloud 运行态仍依赖当前 SpacetimeDB 环境稳定性;如 `npm run api-server:maincloud` 现场遇到订阅 HTTP 500,应按 Maincloud/SpacetimeDB 联调链路单独排查。
|
||||
6. 运行态仍依赖当前 SpacetimeDB 环境稳定性;如 `npm run api-server` 现场遇到订阅 HTTP 500,应按本地 SpacetimeDB 联调链路单独排查。
|
||||
|
||||
@@ -119,10 +119,10 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p api-server --manifest-path server-rs\Cargo.toml
|
||||
cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml
|
||||
npm run check:encoding
|
||||
npm run api-server:maincloud
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
`api-server:maincloud` 是修改后端后的必跑项;如果本地缺少 Maincloud 环境或 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
|
||||
`api-server` 是修改后端后的必跑项;如果本地 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
|
||||
|
||||
## 7. 后续接入点
|
||||
|
||||
|
||||
33
docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md
Normal file
33
docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 新建作品入口配置说明 2026-05-01
|
||||
|
||||
## 背景
|
||||
|
||||
创作中心顶部“新建作品”入口和平台创作类型弹层都依赖同一组玩法模板。此前入口开放状态、隐藏状态和中文文案集中写在 `src/components/platform-entry/platformEntryCreationTypes.ts` 与入口组件中,后续切换玩法开放节奏时容易出现多个入口不一致。
|
||||
|
||||
## 落地规则
|
||||
|
||||
1. 新建作品入口配置统一放在 `src/config/newWorkEntryConfig.ts`。
|
||||
2. `visible` 控制玩法是否展示在新建作品入口和创作类型弹层中。
|
||||
3. `open` 控制玩法是否允许点击创建;`open: false` 时入口保持展示但禁用。
|
||||
4. `title`、`subtitle`、`badge` 控制玩法卡片文案。
|
||||
5. `startCard` 控制创作中心顶部新建作品模块的标题、辅助文案和移动端角标文案。
|
||||
6. `typeModal` 控制平台创作类型弹层标题和描述。
|
||||
7. 入口排序仍遵循“可创建玩法在前,未开放玩法在后”;同组内部沿用配置顺序。
|
||||
|
||||
## 当前状态
|
||||
|
||||
| 玩法 | 展示 | 开放 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 角色扮演 | 是 | 是 | 点击后进入 RPG Agent 共创工作台 |
|
||||
| 大鱼吃小鱼 | 否 | 是 | 功能仍保留,不在新建作品入口展示 |
|
||||
| 拼图 | 是 | 是 | 点击后进入拼图 Agent 共创工作台 |
|
||||
| 抓大鹅 | 是 | 是 | 点击后进入抓大鹅 Agent 共创工作台 |
|
||||
| AIRP | 是 | 否 | 保留入口,显示敬请期待 |
|
||||
| 视觉小说 | 是 | 否 | 保留入口,显示敬请期待 |
|
||||
|
||||
## 验收
|
||||
|
||||
1. 修改 `src/config/newWorkEntryConfig.ts` 后,创作中心顶部卡带和平台创作类型弹层应同步变化。
|
||||
2. 隐藏玩法不触发入口预加载,也不出现在新建作品入口中。
|
||||
3. 未开放玩法点击态保持禁用,不应进入鉴权或创建会话链路。
|
||||
4. 已开放玩法点击后必须进入对应创建链路;若用户未登录,先走登录保护。
|
||||
@@ -128,4 +128,4 @@
|
||||
- Rust/module-runtime:覆盖公共码、唯一码、私有码、失败场景、流水来源和余额累加。
|
||||
- Axum:覆盖用户鉴权、管理员鉴权、runtime error 到 400 的映射和兼容路径。
|
||||
- 前端:覆盖入口替换、独立 modal、成功刷新余额和失败展示后端 message。
|
||||
- 验证命令:`cargo test`、目标前端测试、`npm run api-server:maincloud`、`npm run check:encoding`。
|
||||
- 验证命令:`cargo test`、目标前端测试、`npm run api-server`、`npm run check:encoding`。
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# 公开作品详情页自有作品编辑分流
|
||||
|
||||
更新时间:`2026-05-02`
|
||||
|
||||
## 背景
|
||||
|
||||
平台统一作品详情页左下角一直使用“作品改造”动作。这个动作适合打开其他作者作品时复制一份新草稿,但当详情页展示的是当前登录用户自己的作品时,继续复制会产生一份新的自己的作品,和用户预期的“编辑原作品”不一致。
|
||||
|
||||
## 落地规则
|
||||
|
||||
1. 作品详情页以 `ownerUserId === 当前登录用户 id` 判断作品归属。
|
||||
2. 非本人作品保持“作品改造”,点击后继续走现有 remix / 复制草稿链路。
|
||||
3. 本人作品把左下角按钮显示为“作品编辑”,点击后进入该作品绑定的原草稿或结果编辑页。
|
||||
4. 本人作品编辑不调用 remix 接口,不创建新的同款作品。
|
||||
5. 如果本人作品缺少可恢复的草稿会话,只展示可定位错误,不静默复制。
|
||||
|
||||
## 分玩法入口
|
||||
|
||||
1. RPG:复用已保存作品编辑入口,直接打开当前 profile 的结果编辑页。
|
||||
2. 拼图:优先使用当前详情项的 `sourceSessionId` 恢复原拼图草稿。
|
||||
3. 大鱼吃小鱼:使用公开作品的 `sourceSessionId` 恢复原玩法草稿。
|
||||
4. 抓大鹅:保留并传递 `sourceSessionId`,恢复原创作会话后进入结果页。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 登录用户打开自己的公开作品详情时,左下角按钮为“作品编辑”。
|
||||
2. 点击“作品编辑”不会调用对应玩法的 remix 接口。
|
||||
3. 登录用户打开他人公开作品详情时,左下角按钮仍为“作品改造”。
|
||||
4. 未登录用户点击“作品改造”仍先触发登录拦截。
|
||||
@@ -0,0 +1,75 @@
|
||||
# 拼图 APIMart 图片模型路由接入 2026-05-01
|
||||
|
||||
## 背景
|
||||
|
||||
拼图创作已收口为填表式流程,首图生成和结果页关卡重新生成都由 `server-rs/crates/api-server/src/puzzle.rs` 执行外部图片 I/O,再把正式图写入 OSS 与 SpacetimeDB。新的模型选择只影响图片生成上游,不改变 SpacetimeDB 表结构、拼图草稿结构或前端运行时规则。
|
||||
|
||||
本轮参考 APIMart 文档:
|
||||
|
||||
1. `https://docs.apimart.ai/cn/api-reference/images/gpt-image-2/generation`
|
||||
2. `https://docs.apimart.ai/cn/api-reference/images/gemini-3.1-flash/generation`
|
||||
|
||||
两条文档均指向 OpenAI 兼容风格的图片生成入口:`POST https://api.apimart.ai/v1/images/generations`,头部使用 `Authorization: Bearer {APIMART_API_KEY}`。请求体至少包含 `model`、`prompt`、`n`、`size`。返回体按 OpenAI images 兼容格式优先读取 `data[].url`,若供应商返回异步任务结构,则继续按 `task_id` / `tasks/{task_id}` 轮询并提取图片 URL。
|
||||
|
||||
## 模型选项
|
||||
|
||||
拼图图片生成支持两个选项:
|
||||
|
||||
| 前端显示 | 请求值 | 上游 |
|
||||
| --- | --- | --- |
|
||||
| `gpt-image-2` | `gpt-image-2` | APIMart `/v1/images/generations` |
|
||||
| `nanobanana2` | `gemini-3.1-flash-image-preview` | APIMart `/v1/images/generations` |
|
||||
|
||||
默认值为 `gpt-image-2`。前端只负责展示和传递所选模型,不能把模型路由逻辑、上游请求体拼装或 API Key 暴露到浏览器。历史草稿或旧请求中的空值、`original`、未知值统一按 `gpt-image-2` 处理,不再把拼图生图路由回 DashScope 原模型。
|
||||
|
||||
## 前端交互
|
||||
|
||||
1. 拼图创作表单的“画面描述”输入框左下角显示当前调用模型。
|
||||
2. 拼图结果页关卡详情的“画面描述”输入框左下角同样显示当前调用模型。
|
||||
3. 点击模型标识弹出轻量选择菜单,只支持 `gpt-image-2`、`nanobanana2` 两项。
|
||||
4. 菜单只是模型选择控件,不写入说明性规则文案。
|
||||
5. 参考图入口继续在画面描述输入框右下角,模型选择在左下角,两者不得遮挡文本。
|
||||
6. 表单创建 session、自动保存表单草稿、首图生成失败重试时都要保留当前模型选择。
|
||||
7. 结果页关卡重新生成时将当前模型随 `generate_puzzle_images` action 传给后端。
|
||||
8. “生成草稿”和关卡详情“生成画面 / 重新生成画面”按钮文本右侧展示 `消耗2光点`。
|
||||
9. 关卡详情点击“生成画面 / 重新生成画面”后先弹出确认消耗光点弹窗,确认后开始请求;按钮区域切换为 30 秒倒计时进度条,并展示预计剩余生成完成时间。
|
||||
|
||||
## 后端路由
|
||||
|
||||
1. `CreatePuzzleAgentSessionRequest` 与 `ExecutePuzzleAgentActionRequest` 增加可选 `imageModel` 字段;该字段不进入 SpacetimeDB reducer 输入结构。
|
||||
2. `compile_puzzle_draft_with_initial_cover` 与 `generate_puzzle_image_candidates` 增加图片模型参数。
|
||||
3. `imageModel` 归一化规则:
|
||||
- 空值、`original` 或未知值统一回落为 `gpt-image-2`;
|
||||
- `gpt-image-2` 走 APIMart;
|
||||
- `gemini-3.1-flash-image-preview` 走 APIMart,前端显示名为 `nanobanana2`。
|
||||
4. APIMart 文生图和图生图共用 `POST /v1/images/generations`。有参考图时,后端将参考图 Data URL 作为 `image_urls` 数组传入;若上游不接受该字段,错误按上游失败返回,不在前端降级伪造结果。
|
||||
5. APIMart 尺寸使用文档要求的比例写法 `1:1`。`gemini-3.1-flash-image-preview` 额外带 `resolution = "1K"`,对齐约 1024px 的拼图正方形素材。
|
||||
6. APIMart 生成成功后仍下载远程图片,沿用现有 OSS 私有对象、`asset_object` 和 `asset_entity_binding` 写入流程。若图片已成功上传 OSS,但 Maincloud / SpacetimeDB 短暂返回 `503 Service Unavailable`,资产索引写入允许降级跳过,并返回本次生成图片;日志必须记录 `拼图图片资产索引写入因 SpacetimeDB 连接不可用而降级跳过`。
|
||||
7. `save_puzzle_generated_images` 写回草稿时若遇到 Maincloud 连接级 `503` 或断线,API 层基于本次生成结果合成 session 快照返回给前端,避免 APIMart 已成功出图却被后置持久化误报成服务不可用。余额不足、参数错误、上游生图失败仍按原错误返回,不做伪成功。
|
||||
8. 结果页 `generate_puzzle_images` 会携带当前作品信息和 `levelsJson`。当 Maincloud / SpacetimeDB 在读取 session 阶段就返回连接级 `503` 或断线时,后端必须先用这份结果页快照构造最小内存 session,再继续调用 APIMart;外部图片已经生成后仍按第 6、7 条处理持久化降级。余额不足、参数错误、缺少草稿快照、关卡不存在等业务错误不走此降级。
|
||||
9. APIMart 异步任务轮询按文档口径在提交后先等待 `10s`,再调用 `GET /v1/tasks/{task_id}`;图片地址提取同时支持 `url: "..."` 与 `url: ["..."]` 两种结构。
|
||||
10. APIMart 错误统一映射为 `502 UPSTREAM_ERROR`,`details.provider = "apimart"`,保留上游状态码、业务 message 和截断后的 raw excerpt。
|
||||
11. 拼图首图生成 `compile_puzzle_draft` 与关卡图片生成 `generate_puzzle_images` 每次预扣 `2` 光点;余额不足仍返回 `409 CONFLICT`,Maincloud 连接级 503 仍按既有降级策略处理。
|
||||
|
||||
## 环境变量
|
||||
|
||||
新增服务端环境变量:
|
||||
|
||||
```text
|
||||
APIMART_BASE_URL="https://api.apimart.ai/v1"
|
||||
APIMART_API_KEY="YOUR_APIMART_API_KEY"
|
||||
APIMART_IMAGE_REQUEST_TIMEOUT_MS=180000
|
||||
```
|
||||
|
||||
`APIMART_API_KEY` 只能存在于本地或部署环境,不写入 Git 跟踪文件。若选择 APIMart 模型但缺少 key,后端返回服务不可用错误,前端展示现有错误面板。
|
||||
|
||||
## 验收
|
||||
|
||||
1. 创作表单和关卡详情的画面描述框左下角能切换 `gpt-image-2`、`nanobanana2`,默认显示 `gpt-image-2`。
|
||||
2. 点击“生成草稿”时,后端首图生成使用当前表单选择的模型。
|
||||
3. 点击“生成画面 / 重新生成画面”时,后端当前关卡图片生成使用关卡详情选择的模型。
|
||||
4. 历史 `original` 或空模型值不会再触发 DashScope,统一按 `gpt-image-2` 请求 APIMart。
|
||||
5. 选择 APIMart 模型时,请求 `POST {APIMART_BASE_URL}/images/generations`,使用 `Authorization: Bearer {APIMART_API_KEY}`,`model` 等于请求值,`size = 1:1`。
|
||||
6. “生成草稿”和关卡详情生图按钮展示 `消耗2光点`;关卡详情确认后展示 30 秒预计剩余进度条。
|
||||
7. 不改 SpacetimeDB 表结构,因此无需更新 `migration.rs` 或重新生成 bindings。
|
||||
8. 后端改动后运行对应 Rust 测试,并按项目约束用 `npm run api-server:maincloud` 重启验证。
|
||||
@@ -14,9 +14,9 @@
|
||||
4. 玩家在生成草稿前退出,再次从创作中心点击这条拼图草稿时,必须恢复到填表页,并回填之前自动保存的作品名称、作品描述和画面描述;只有执行 `compile_puzzle_draft` 且生成结果页草稿后,草稿入口才进入结果页。
|
||||
5. 表单自动保存走 `save_puzzle_form_draft` action,不消耗光点,不生成图片,不改变 `stage = collecting_anchors`;生成草稿按钮仍单独触发 `compile_puzzle_draft` 并进入进度页。
|
||||
6. 点击拼图入口始终创建新草稿,不复用上一次未完成 session;恢复旧草稿只通过“我的创作”中的草稿卡进入。
|
||||
7. 若 Maincloud 仍运行旧 wasm,缺少 `save_puzzle_form_draft` procedure,前端提交生成或生成失败页重试时不得继续复用空 `seedText` 的表单 session,必须用当前表单 payload 新建带真实 seed 的 session 再执行 `compile_puzzle_draft`。
|
||||
7. 若运行中的旧 wasm 缺少 `save_puzzle_form_draft` procedure,前端提交生成或生成失败页重试时不得继续复用空 `seedText` 的表单 session,必须用当前表单 payload 新建带真实 seed 的 session 再执行 `compile_puzzle_draft`。
|
||||
8. api-server 也要兼容旧 wasm:`save_puzzle_form_draft` 缺失时,自动保存 action 降级返回当前 session;`compile_puzzle_draft` 前置保存缺失且当前 session 为空 seed 时,创建一条带表单 seed 的替代 session 后继续编译,避免再次暴露 `No such procedure`。
|
||||
9. 正式修复仍是发布最新 SpacetimeDB wasm。当前 Maincloud `xushi-p4wfr` 的迁移操作员表为空,但旧库引导密钥来自旧 wasm,本次临时生成的新引导密钥无法授权导出迁移,需使用已有迁移操作员 token 或数据库 owner 重新授权后发布;禁止为绕过冲突直接清库,除非明确接受数据丢失。
|
||||
9. 正式修复仍是发布最新 SpacetimeDB wasm。如果目标库的迁移操作员表为空,但旧库引导密钥来自旧 wasm,本次临时生成的新引导密钥无法授权导出迁移,需使用已有迁移操作员 token 或数据库 owner 重新授权后发布;禁止为绕过冲突直接清库,除非明确接受数据丢失。
|
||||
|
||||
1. 作品名称为必填字段,保存到 `workTitle`,兼容写入旧 `seedText`,同时作为作品级 `workTitle` 的真相源。
|
||||
2. 作品描述为必填字段,保存到 `workDescription`,作为作品详情页、作品列表和发布资料中的 `summary` 真相源。
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
### 1. 图片生成
|
||||
|
||||
1. 拼图生成图固定使用 `1024*1024`。
|
||||
2. 文生图和参考图生图共用同一个尺寸常量,禁止一条链路仍生成竖屏或横版图。
|
||||
3. 拼图图片提示词明确写入 `1:1 正方形画布`,继续保留适配 `3x3 / 4x4 / 5x5 / 6x6 / 7x7` 拼图切块、主体清晰、层次明确、无文字水印等约束。
|
||||
4. 文生图正向 prompt 必须由后端压缩到 `500` 字符以内,优先保留玩家画面描述开头与固定拼图约束,避免 DashScope 旧 text2image 协议把超长 prompt 判为“请求参数不合法”。
|
||||
5. DashScope 上游失败时,api-server 必须在错误 details 中保留业务 message、`upstreamStatus` 和截断后的 `rawExcerpt`,日志也要记录同样的摘要,避免生成进度页只能看到通用 HTTP 文案。
|
||||
6. 图片生成仍由 `api-server` 执行。SpacetimeDB reducer 不做网络 I/O。
|
||||
7. 拼图文生图请求体按 DashScope Wan text2image 协议收口:`input` 放 `prompt` 与非空 `negative_prompt`,`parameters` 放 `n`、`size`、`prompt_extend`、`watermark`。不要在 `input` 与 `parameters` 里重复写入反向提示词,否则上游容易返回参数非法。
|
||||
1. 拼图默认使用 APIMart `gpt-image-2` 生成图,外部请求尺寸固定为 `1:1`;`nanobanana2` 仍映射为 `gemini-3.1-flash-image-preview`。
|
||||
2. 历史 `original` 或空模型值只做兼容输入,不再进入 DashScope 原模型链路,统一按 `gpt-image-2` 路由。
|
||||
3. 文生图和参考图生图共用同一个正方形尺寸口径,禁止一条链路仍生成竖屏或横版图。
|
||||
4. 拼图图片提示词明确写入 `1:1 正方形画布`,继续保留适配 `3x3 / 4x4 / 5x5 / 6x6 / 7x7` 拼图切块、主体清晰、层次明确、无文字水印等约束。
|
||||
5. 文生图正向 prompt 必须由后端压缩到 `500` 字符以内,优先保留玩家画面描述开头与固定拼图约束,避免上游把超长 prompt 判为“请求参数不合法”。
|
||||
6. APIMart 上游失败时,api-server 必须在错误 details 中保留业务 message、`upstreamStatus` 和截断后的 `rawExcerpt`,日志也要记录同样的摘要,避免生成进度页只能看到通用 HTTP 文案。
|
||||
7. 图片生成仍由 `api-server` 执行。SpacetimeDB reducer 不做网络 I/O。
|
||||
8. 光点预扣失败属于钱包或 SpacetimeDB 服务链路错误,不得映射成 `400 BAD_REQUEST`。除余额不足返回 `409 CONFLICT` 外,其余预扣异常统一按上游/服务错误暴露,避免生成页误提示“请求参数不合法”。
|
||||
|
||||
### 2. 前端规则裁决
|
||||
@@ -47,10 +47,10 @@
|
||||
|
||||
## 验收
|
||||
|
||||
1. 点击拼图草稿生成或重新生成画面时,后端请求 DashScope 的 `size` 为 `1024*1024`。
|
||||
1. 点击拼图草稿生成或重新生成画面时,后端请求 APIMart 的 `size` 为 `1:1`,默认模型为 `gpt-image-2`。
|
||||
2. 图片提示词包含 `1:1 正方形拼图关卡`。
|
||||
3. 图片提示词长度不超过 `500` 字符,超长画面描述会被截断,但适配 `3x3 / 4x4 / 5x5 / 6x6 / 7x7` 拼图切块、`避免文字、水印、边框和 UI 元素` 等玩法约束不能丢。
|
||||
4. DashScope 返回参数错误、任务失败或非 2xx 时,前端错误优先展示后端 details.message,后端日志能看到 `upstreamStatus` 和 `rawExcerpt`。
|
||||
4. APIMart 返回参数错误、任务失败或非 2xx 时,前端错误优先展示后端 details.message,后端日志能看到 `upstreamStatus` 和 `rawExcerpt`。
|
||||
5. 正式拼图 run 中拖动拼块后,前端立即更新棋盘、合并块和通关状态,不再等待 `/drag`。
|
||||
6. 移动端运行时棋盘为正方形,并尽量贴近屏幕两侧边缘。
|
||||
7. 基础单块和合并块都能看到圆角,合并块的外凸角与内凹角都不是直角,且图片不会溢出圆角裁剪。
|
||||
|
||||
@@ -28,4 +28,4 @@
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
3. `npm run api-server:maincloud` 重启后,点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。
|
||||
3. `npm run api-server` 重启后,点击拼图结果页“生成或更换图片”,候选图应能写回并正常展示。
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# 拼图运行时首次退出改造引导 2026-05-02
|
||||
|
||||
## 背景
|
||||
|
||||
玩家从公开拼图作品进入运行态后,左上角返回会直接离开玩法。若玩家因为体验不佳准备退出,需要在首次退出时给出改造入口,让玩家可以把当前作品复制为自己的草稿继续调整。
|
||||
|
||||
本轮只改拼图运行时前端交互与既有改造链路,不新增后端表,不改变拼图存档投影规则,不接入旧 `server-node`。
|
||||
|
||||
## 交互规则
|
||||
|
||||
1. 触发点只限拼图运行态左上角返回按钮。
|
||||
2. 对同一浏览器里的同一拼图 `profileId`,首次点击返回时不直接退出,而是弹出独立面板。
|
||||
3. 面板标题固定为两行:
|
||||
- `体验不佳?`
|
||||
- `试试改造功能!`
|
||||
4. 面板主按钮为 `作品改造`,点击后复用公开详情页已有的拼图改造链路:
|
||||
- 使用当前运行关卡的 `currentLevel.profileId` 调用 `remixPuzzleGalleryWork(profileId)`,避免下一关或相似作品运行态误用旧详情页作品。
|
||||
- 成功后写入 `puzzleFlow.session`。
|
||||
- 进入 `puzzle-result`,即游戏作品改造页。
|
||||
5. 面板次按钮为 `保存并退出`,点击后关闭面板并执行原返回逻辑。
|
||||
6. 非首次点击返回不再弹出面板,直接执行原返回逻辑。
|
||||
|
||||
## 首次状态
|
||||
|
||||
首次曝光是浏览器侧 UI 引导状态,不是业务真相态:
|
||||
|
||||
1. 以 `currentLevel.profileId` 作为作品粒度。
|
||||
2. 使用 `localStorage` 记录已展示状态。
|
||||
3. `localStorage` 不可用时,使用当前组件生命周期内的内存集合兜底,避免同一挂载周期重复弹出。
|
||||
4. 点击 `作品改造` 或 `保存并退出` 都视为已经完成本次引导曝光。
|
||||
|
||||
## 验收
|
||||
|
||||
1. 首次点击拼图运行态左上角返回,出现标题为 `体验不佳?试试改造功能!` 的独立面板。
|
||||
2. 点击 `作品改造` 后进入拼图结果页改造草稿。
|
||||
3. 点击 `保存并退出` 后返回原目标页面。
|
||||
4. 同一作品再次点击左上角返回,不再出现面板。
|
||||
5. 不影响设置面板里的返回按钮、失败续时、通关结算和下一关入口。
|
||||
@@ -49,8 +49,9 @@
|
||||
- [SERVER_RS_DDD_FULL_REFACTOR_2026-04-28.md](./SERVER_RS_DDD_FULL_REFACTOR_2026-04-28.md):冻结 `server-rs` 一次性 DDD 重构总纲,明确 crate 依赖方向、模块目录、上下文聚合/命令/事件/读模型、SpacetimeDB adapter 映射和表结构变更约束。
|
||||
- [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md):冻结 SpacetimeDB 表结构变更约束、自动迁移可接受范围、冲突后的系统行为,以及保留旧数据的增量迁移流程;凡涉及 `spacetime publish`、表字段调整或 `migration.rs` 对齐时优先参考。
|
||||
- [PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md](./PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md):冻结当前对外中文命名,产品展示名统一为“百梦”,消费单位为“光点”,公开账号标识为“百梦号”,创作侧称谓为“百梦主”。
|
||||
- [SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md](./SPACETIMEDB_CLOUD_CONFIG_REMOVAL_2026-05-02.md):记录旧云端 SpacetimeDB 配置、发布脚本和默认文档口径的移除结果,冻结后续仅使用本地或显式 `SERVER_URL` 的运维规则。
|
||||
- [SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md](./SPACETIMEDB_LOCAL_REPLICA_IDENTITY_MISMATCH_FIX_2026-04-30.md):记录本地 standalone 启动时报 `mismatched database identity` 的 root-dir/replica 数据残留根因、备份重建步骤和脚本诊断口径。
|
||||
- [AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md](./AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md):记录 Maincloud `xushi-p4wfr` 挂起导致认证快照同步和抓大鹅创作失败的根因、认证同步非阻断修复、`/api/creation` Vite 代理补齐和本地 SpacetimeDB 可跑链路。
|
||||
- [AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md](./AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md):记录远端库挂起导致认证快照同步和抓大鹅创作失败的根因、认证同步非阻断修复、`/api/creation` Vite 代理补齐和本地 SpacetimeDB 可跑链路。
|
||||
- [LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md](./LLM_MODEL_ROUTING_RPG_AND_CREATION_2026-04-30.md):冻结 RPG 运行时剧情推理使用 `doubao-seed-character-251128` 的 `/chat/completions`,以及所有模板创作大模型推理使用 `deepseek-v3-2-251201` 的 `/responses`。
|
||||
- [PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md](./PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md):冻结邀请码从“我的 Tab 填写”迁到注册环节的前后端边界、`profile_invite_code.metadata_json` 表结构扩展、管理员邀请码虚拟主体和奖励规则。
|
||||
- [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md):冻结抓大鹅 Match3D 首版 demo 的独立玩法域、表与 procedure、HTTP facade、前端即时反馈/后端权威确认协议,以及可并行开发包。
|
||||
@@ -68,7 +69,7 @@
|
||||
- [RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md](./RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md):冻结 RPG 创作结果页保存、Agent session/result preview 真相优先级和结果页入口裁决迁移到后端 result-view 的落地边界。
|
||||
- [RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md](./RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md):记录 RPG 创作 profile 生成移除非浏览器 legacy AI 回退,统一通过 `server-rs` 的 `/api/runtime/custom-world/profile` 生成世界底稿。
|
||||
- [CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md](./CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md):记录 RPG Agent 旧 URL 恢复指针必须有本机用户归属才读取受保护 session,以及 Big Fish 公开广场读取失败按空广场降级的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 Maincloud 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 SpacetimeDB 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md](./BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md):记录大鱼吃小鱼草稿生成、生图、动作三类提示词从业务脚本中抽离到独立 `prompt/big_fish.rs` 模块的边界与职责划分。
|
||||
- [BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md](./BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md):记录大鱼吃小鱼等级主图与动作关键帧正式图在 Rust 后端复用 RPG 角色主图透明背景 alpha 后处理的对齐口径,并明确场地背景不走该处理。
|
||||
- [PUZZLE_IMAGE_AND_FRONTEND_RULES_ALIGNMENT_2026-04-29.md](./PUZZLE_IMAGE_AND_FRONTEND_RULES_ALIGNMENT_2026-04-29.md):记录拼图生成图片回到 1:1,运行时拖动、交换、合并与拆分由前端即时裁决,以及移动端棋盘贴近屏幕边缘的落地边界。
|
||||
@@ -88,7 +89,7 @@
|
||||
- [SPACETIMEDB_TABLE_CATALOG.md](./SPACETIMEDB_TABLE_CATALOG.md):持续维护当前 SpacetimeDB 表目录,按领域说明每张表的作用、字段结构、索引和常用 `spacetime sql` 查询模板。
|
||||
- [RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md](./RPG_OPENING_SCENE_ACT_IMAGE_PRESENTATION_SYNC_2026-04-26.md):记录开局场景与普通场景复用同一场景展示解析服务,修复列表幕缩略图和详情幕背景预览图片不一致的问题。
|
||||
- [FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md](./FRONTEND_FIRST_LOAD_PERFORMANCE_FIX_2026-04-26.md):记录网站启动后首次加载约三分钟的前端根因,收口 `RouteImageReadyGate` 首屏图片门控和 Vite dev server 无关文件监听范围。
|
||||
- [RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md](./RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md):记录 RPG 作品删除时报 `No such procedure` 的根因,补齐 `delete_custom_world_agent_session` 在有效 SpacetimeDB 模块入口中的导出,并要求发布后核验 Maincloud schema。
|
||||
- [RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md](./RPG_WORK_DELETE_SPACETIMEDB_PROCEDURE_EXPORT_FIX_2026-04-25.md):记录 RPG 作品删除时报 `No such procedure` 的根因,补齐 `delete_custom_world_agent_session` 在有效 SpacetimeDB 模块入口中的导出,并要求发布后核验 schema。
|
||||
- [CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md](./CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md):冻结当前后端唯一落地口径,明确新功能以 `server-rs + Axum + SpacetimeDB` 为准,旧 `server-node` / Express / PostgreSQL 与 Go 方向只允许作为迁移参考。
|
||||
- [RPG_DRAFT_GENERATION_CONTINUE_AND_ETA_FIX_2026-04-25.md](./RPG_DRAFT_GENERATION_CONTINUE_AND_ETA_FIX_2026-04-25.md):记录世界草稿生成失败/中断后进度不再误到 `100%`、主按钮改为“继续生成草稿”并复用已保存底稿续跑,以及按阶段耗时模型估算预计等待时间的修复口径。
|
||||
- [RUNTIME_NPC_CHAT_LLM_MIGRATION_2026-04-25.md](./RUNTIME_NPC_CHAT_LLM_MIGRATION_2026-04-25.md):冻结运行时 NPC 聊天从 Rust 确定性兜底迁到 `platform-llm` 的边界,要求旧 Node 聊天提示词原样迁移,覆盖回复、建议、好感变化与限轮收束。
|
||||
|
||||
@@ -48,4 +48,4 @@ Agent 路由保持原有 submit/finalize 分工:
|
||||
3. `cargo test -p api-server runtime_chat`
|
||||
4. `cargo test -p api-server creation_agent_llm_turn`
|
||||
5. `node scripts/check-encoding.mjs docs/technical/RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md server-rs/crates/api-server/src/runtime_chat.rs server-rs/crates/api-server/src/custom_world.rs server-rs/crates/api-server/src/big_fish.rs docs/technical/README.md`
|
||||
6. 修改后端代码后,使用 `npm run api-server:maincloud` 重启后端。
|
||||
6. 修改后端代码后,使用 `npm run api-server` 重启后端。
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# RPG foundation draft LLM 联网搜索降级修正(2026-05-01)
|
||||
|
||||
## 背景
|
||||
|
||||
本次现场错误为:
|
||||
|
||||
```text
|
||||
agent-foundation-story-outline-batch-1 LLM 请求失败:LLM 请求超时,累计尝试 2 次
|
||||
```
|
||||
|
||||
同一轮 `logs/llm-raw` 还记录了前置 `ToolNotOpen`:
|
||||
|
||||
```text
|
||||
Your account has not activated web search.
|
||||
```
|
||||
|
||||
当前 `custom_world_foundation_draft.rs` 的分阶段底稿生成全部硬编码 `.with_web_search(true)`。但这些批次只根据 Agent 已收集的八锚点、世界骨架、角色名单和场景名单生成结构化 JSON,本身不需要实时联网检索;联网搜索只能作为模板创作的增强能力,不能成为 foundation draft 的必经前置。
|
||||
|
||||
## 根因
|
||||
|
||||
1. `generate_custom_world_foundation_draft(...)` 没有接收 `AppConfig.creation_agent_llm_web_search_enabled`。
|
||||
2. `request_foundation_json_stage(...)` 对所有 Responses 请求固定开启 `web_search`。
|
||||
3. 非流式 foundation draft 调用没有复用创作 Agent SSE turn 中的 `ToolNotOpen` 降级策略。
|
||||
4. 当账号未开通 web search 或搜索工具链响应慢时,底稿批次会在内部 JSON 生成阶段失败,最终 operation 进入 failed。
|
||||
|
||||
## 落地策略
|
||||
|
||||
1. `api-server` 调用 foundation draft 生成器时显式传入 `state.config.creation_agent_llm_web_search_enabled`。
|
||||
2. foundation draft 每个业务 JSON 阶段先按配置决定是否带 `tools: [{ type: "web_search", max_keyword: 3 }]`。
|
||||
3. 若开启搜索后出现以下错误,自动使用同一 system/user prompt 无搜索重试一次:
|
||||
- `ToolNotOpen`
|
||||
- `has not activated web search`
|
||||
- `未开通`
|
||||
- 上游连接失败
|
||||
- 请求超时
|
||||
4. JSON 修复阶段继续不启用搜索,因为修复只处理已有响应文本。
|
||||
5. SpacetimeDB reducer / procedure 不新增任何外部 I/O;仍只接收 api-server 已生成的确定性 `draftProfile` 并落库。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. `agent-foundation-*-batch-*` 首次搜索增强失败时,日志出现一次降级 warning,operation 不应直接失败。
|
||||
2. 降级重试请求体不再包含 `tools` / `web_search`。
|
||||
3. `GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED=false` 时,foundation draft 全流程直接不带搜索工具。
|
||||
4. `cargo test -p api-server custom_world_foundation_draft --manifest-path server-rs/Cargo.toml` 通过。
|
||||
5. 修改后按项目约束使用 `npm run api-server:maincloud` 重启后端。
|
||||
@@ -10,7 +10,7 @@
|
||||
2. `GET /api/runtime/custom-world-gallery`
|
||||
3. 个人看板、浏览历史、存档等私有数据
|
||||
|
||||
其中 `custom-world-library` 通过 `api-server -> spacetime-client -> list_custom_world_profiles procedure` 读取当前用户作品。旧实现把每个作品的完整 `profile_payload_json` 一并返回给首页列表,而首页卡片只需要标题、摘要、封面、状态和计数字段。用户作品较多或 Maincloud 连接抖动时,这个 procedure 容易超过 `spacetime-client` 固定 `10s` 等待窗口,最终由 Axum 映射成 `502 Bad Gateway`,前端控制台显示 `SpacetimeDB procedure 调用超时`。
|
||||
其中 `custom-world-library` 通过 `api-server -> spacetime-client -> list_custom_world_profiles procedure` 读取当前用户作品。旧实现把每个作品的完整 `profile_payload_json` 一并返回给首页列表,而首页卡片只需要标题、摘要、封面、状态和计数字段。用户作品较多或 SpacetimeDB 连接抖动时,这个 procedure 容易超过 `spacetime-client` 固定 `10s` 等待窗口,最终由 Axum 映射成 `502 Bad Gateway`,前端控制台显示 `SpacetimeDB procedure 调用超时`。
|
||||
|
||||
## 2. 修复口径
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
1. `list_custom_world_profiles` 仍保持旧 procedure 名称和返回 envelope,避免本轮重新生成 bindings。
|
||||
2. 列表返回的 `profile_payload_json` 改为轻量摘要 JSON,只包含首页卡片和标签兜底需要的少量字段。
|
||||
3. 单条详情、发布、下架、编辑继续使用完整 profile snapshot,确保进入详情或结果页时仍有完整世界数据。
|
||||
4. `spacetime-client` 的 procedure 等待窗口从硬编码 `10s` 改为可配置,Maincloud 默认使用更宽的窗口吸收连接冷启动与短时抖动。
|
||||
5. Axum 的 `GET /api/runtime/custom-world-library` 首屏接口改走已有 `custom-world/works` 轻量读模型,并在用户点击详情/编辑时再调用 owner-only detail 接口取完整 profile,避免 Maincloud wasm 尚未发布轻量 profile procedure 时首页继续命中重 procedure。
|
||||
4. `spacetime-client` 的 procedure 等待窗口从硬编码 `10s` 改为可配置,用更宽的窗口吸收连接冷启动与短时抖动。
|
||||
5. Axum 的 `GET /api/runtime/custom-world-library` 首屏接口改走已有 `custom-world/works` 轻量读模型,并在用户点击详情/编辑时再调用 owner-only detail 接口取完整 profile,避免旧 wasm 尚未发布轻量 profile procedure 时首页继续命中重 procedure。
|
||||
|
||||
## 3. 轻量 profile JSON 字段
|
||||
|
||||
@@ -47,4 +47,4 @@
|
||||
3. `cargo check -p spacetime-client` 通过。
|
||||
4. `cargo check -p api-server` 通过。
|
||||
5. `npm run check:encoding` 通过。
|
||||
6. 修改后按项目约束使用 `npm run api-server:maincloud` 重启后端。
|
||||
6. 修改后按项目约束使用 `npm run api-server` 重启后端。
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
6. 修改后执行:
|
||||
- Rust 相关测试。
|
||||
- TypeScript 相关测试。
|
||||
- `npm run api-server:maincloud`。
|
||||
- `npm run api-server`。
|
||||
|
||||
## 5. 本次实现结果
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ server-rs/crates/api-server/src/prompt/rpg/
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyResponseOptions.test.ts`
|
||||
3. `cargo check -p api-server`
|
||||
4. `npm run api-server:maincloud`
|
||||
4. `npm run api-server`
|
||||
|
||||
## 后续编辑约定
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ npm run typecheck -- --pretty false
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
局部测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本次任务中修改,因此未执行 `npm run api-server:maincloud`。
|
||||
局部测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本次任务中修改,因此未执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第二轮复查修正
|
||||
|
||||
@@ -123,7 +123,7 @@ npm test -- --run src/data/sceneEncounterPreviews.test.ts src/hooks/rpg-runtime-
|
||||
npx eslint src/data/sceneEncounterPreviews.ts src/data/sceneEncounterPreviews.test.ts src/services/customWorldSceneActRuntime.ts src/hooks/rpg-runtime-story/storyChoiceRuntime.ts src/hooks/rpg-runtime-story/storyChoiceRuntime.test.ts src/hooks/rpg-runtime-story/uiTypes.ts src/components/rpg-runtime-panels/RpgAdventurePanelOverlays.tsx
|
||||
```
|
||||
|
||||
以上局部测试与局部 ESLint 已通过。后端代码未在本轮修改中触碰,因此不需要执行 `npm run api-server:maincloud`。
|
||||
以上局部测试与局部 ESLint 已通过。后端代码未在本轮修改中触碰,因此不需要执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第三轮复查修正
|
||||
|
||||
@@ -149,7 +149,7 @@ npx eslint src/hooks/rpg-session/useRpgSessionBootstrap.ts src/hooks/useGameFlow
|
||||
npm run typecheck -- --pretty false
|
||||
```
|
||||
|
||||
以上局部测试、局部 ESLint 与全量类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server:maincloud`。
|
||||
以上局部测试、局部 ESLint 与全量类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第四轮复查修正
|
||||
|
||||
@@ -183,7 +183,7 @@ npm run typecheck -- --pretty false
|
||||
npm run check:encoding
|
||||
```
|
||||
|
||||
以上相关测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本轮修改中触碰,因此未执行 `npm run api-server:maincloud`。
|
||||
以上相关测试、局部 ESLint、全量类型检查与编码检查均通过。后端代码未在本轮修改中触碰,因此未执行 `npm run api-server`。
|
||||
|
||||
## 2026-04-27 第五轮误导链路闭口
|
||||
|
||||
@@ -232,4 +232,4 @@ npx eslint src/hooks/rpg-session/useRpgSessionBootstrap.ts src/hooks/useGameFlow
|
||||
npm run typecheck -- --pretty false
|
||||
```
|
||||
|
||||
以上测试、ESLint 与类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server:maincloud`。
|
||||
以上测试、ESLint 与类型检查已通过。后端代码未在本轮修改中触碰,因此仍不需要执行 `npm run api-server`。
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
创作页或作品详情删除 RPG 作品时报 `No such procedure`。
|
||||
|
||||
本次核对 Maincloud `xushi-p4wfr` schema 后确认:
|
||||
本次核对 `xushi-p4wfr` schema 后确认:
|
||||
|
||||
1. 已发布 / 作品库 profile 删除依赖 `delete_custom_world_profile_and_return`。
|
||||
2. 草稿作品删除依赖 `delete_custom_world_agent_session`。
|
||||
3. 本地 Rust client 绑定里存在 `delete_custom_world_agent_session`,但 Maincloud schema 中没有该 procedure。
|
||||
3. 本地 Rust client 绑定里存在 `delete_custom_world_agent_session`,但目标 schema 中没有该 procedure。
|
||||
|
||||
## 根因
|
||||
|
||||
`server-rs/crates/spacetime-module/src/custom_world/mod.rs` 中有一份草稿删除实现,但当前有效发布入口仍是 `server-rs/crates/spacetime-module/src/lib.rs` 中的 custom world 实现。`lib.rs` 未导出 `delete_custom_world_agent_session`,导致发布到 Maincloud 的模块 schema 缺少该 procedure。
|
||||
`server-rs/crates/spacetime-module/src/custom_world/mod.rs` 中有一份草稿删除实现,但当前有效发布入口仍是 `server-rs/crates/spacetime-module/src/lib.rs` 中的 custom world 实现。`lib.rs` 未导出 `delete_custom_world_agent_session`,导致发布后的模块 schema 缺少该 procedure。
|
||||
|
||||
## 落地口径
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
1. `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`
|
||||
2. `npm run check:encoding`
|
||||
3. `npm run spacetime:publish:maincloud`
|
||||
4. 发布后用 `spacetime describe xushi-p4wfr --server maincloud --json` 确认 schema 包含:
|
||||
3. 发布最新 SpacetimeDB wasm。
|
||||
4. 发布后用 `spacetime describe xushi-p4wfr --server <目标服务> --json` 确认 schema 包含:
|
||||
- `delete_custom_world_profile_and_return`
|
||||
- `delete_custom_world_agent_session`
|
||||
|
||||
@@ -112,9 +112,9 @@ npm run dev:rust:logs -- --follow
|
||||
2. 仅供测试断言使用的辅助函数使用 `#[cfg(test)]` 限定,避免进入 `cargo run -p api-server` 的普通二进制编译。
|
||||
3. 已无调用入口且无迁移价值的映射函数直接删除;如果后续新增同类 SpacetimeDB 记录映射,再按实际调用路径补回,避免提前保留死代码。
|
||||
|
||||
Maincloud API 重启补充:
|
||||
api-server 单独重启补充:
|
||||
|
||||
1. `npm run api-server:maincloud` 会先读取 `.env`、`.env.local`,把 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 映射为 `api-server` 使用的 `GENARRATIVE_SPACETIME_*`,再运行 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
1. `npm run api-server` 会先读取 `.env`、`.env.local`,使用 `GENARRATIVE_SPACETIME_*` 启动 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
2. Windows 下脚本会尽力停止本仓库 `server-rs/target/debug/api-server.exe` 对应的旧进程,避免 cargo 重新编译时 exe 被占用。
|
||||
3. 旧进程已经退出或清理过程中出现瞬时等待失败时,不应阻断新的 `api-server` 启动;脚本只记录清理失败并继续启动。
|
||||
|
||||
@@ -191,7 +191,7 @@ cd build/<timestamp>
|
||||
./stop.sh
|
||||
```
|
||||
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;后台管理前端位于 `web/admin/`,随 `web/` 一并覆盖。文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。Jenkins 覆盖 `.env.local` 时会保留目标部署目录已有的 `GENARRATIVE_SPACETIME_TOKEN` / `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN`,避免后台表统计在部署后失去读取 private 表所需的 owner 身份。
|
||||
如果后续通过 Jenkins 的部署脚本把发布包覆盖到固定部署目录,部署阶段默认只替换 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md` 等发布产物;后台管理前端位于 `web/admin/`,随 `web/` 一并覆盖。文件产物使用普通复制,`web/`、`scripts/` 等目录产物递归复制,不会删除部署目录中的 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录。Jenkins 覆盖 `.env.local` 时会保留目标部署目录已有的 `GENARRATIVE_SPACETIME_TOKEN`,避免后台表统计在部署后失去读取 private 表所需的 owner 身份。
|
||||
|
||||
安全边界:
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# SpacetimeDB 云端配置移除记录
|
||||
|
||||
日期:`2026-05-02`
|
||||
|
||||
## 1. 目标
|
||||
|
||||
当前项目不再使用旧云端 SpacetimeDB 目标,仓库内不再保留云端专用配置、脚本入口和文档默认口径。后续开发、迁移、Jenkins 流水线与后台验证均以本地或显式传入的 SpacetimeDB 服务为准。
|
||||
|
||||
## 2. 入口调整
|
||||
|
||||
1. 根工程后端单独启动入口统一为:
|
||||
|
||||
```bash
|
||||
npm run api-server
|
||||
```
|
||||
|
||||
2. 该入口读取 `.env`、`.env.local` 与当前进程环境中的 `GENARRATIVE_SPACETIME_*`,默认服务地址回落到 `http://127.0.0.1:3101`。
|
||||
3. 已移除旧云端发布入口和脚本。SpacetimeDB 模块发布继续通过本地联调脚本、发布包 `start.sh` 或显式 `spacetime publish --server <server-url>` 执行。
|
||||
|
||||
## 3. 环境变量口径
|
||||
|
||||
`api-server`、迁移脚本和 Jenkins 部署脚本只使用以下运行变量:
|
||||
|
||||
```text
|
||||
GENARRATIVE_SPACETIME_SERVER_URL
|
||||
GENARRATIVE_SPACETIME_DATABASE
|
||||
GENARRATIVE_SPACETIME_TOKEN
|
||||
```
|
||||
|
||||
旧云端专用变量不再作为兼容回退读取。需要连接其它 SpacetimeDB 服务时,必须显式设置 `GENARRATIVE_SPACETIME_SERVER_URL` 或在脚本参数中传入 `--server-url`。
|
||||
|
||||
## 4. 迁移脚本口径
|
||||
|
||||
1. `scripts/spacetime-migration-common.mjs` 默认 server 为本地 `dev`,解析到 `http://127.0.0.1:3101`。
|
||||
2. 授权、撤销、导出等 CLI 调用会显式传 `-s`,避免落回机器上的 SpacetimeDB CLI 默认服务。
|
||||
3. Jenkins 数据库导入导出流水线默认 `SERVER=dev`,需要操作其它目标时必须显式填写 `SERVER_URL`。
|
||||
|
||||
## 5. 后续约束
|
||||
|
||||
1. 新增 SpacetimeDB 运维脚本时,不允许把云端服务写成默认值。
|
||||
2. 文档中的验证命令统一使用 `npm run api-server`。
|
||||
3. 如果某次任务需要连接非本地 SpacetimeDB,必须在文档和验证记录中写清楚实际 `SERVER_URL`、数据库名和 root-dir。
|
||||
@@ -13,7 +13,7 @@ SpacetimeDB reducer 必须保持确定性,不能访问文件系统和网络。
|
||||
|
||||
procedure 不再访问 HTTP 文件桥,也不接收部署机本地文件路径。这样可以避开 SpacetimeDB 对 private/special-purpose 地址的 HTTP 访问限制,并避免把 private 表内容通过临时 HTTP 服务转发。
|
||||
|
||||
SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedure 或 reducer 内需要当前时间时必须使用 `ctx.timestamp`。如果共享 crate 同时服务前端/本地纯逻辑与 SpacetimeDB 模块,应提供 `*_at(now_ms)` 或显式时间参数版本,SpacetimeDB 模块只调用注入时间的函数,避免发布后在 maincloud 触发 `time not implemented on this platform` panic。
|
||||
SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedure 或 reducer 内需要当前时间时必须使用 `ctx.timestamp`。如果共享 crate 同时服务前端/本地纯逻辑与 SpacetimeDB 模块,应提供 `*_at(now_ms)` 或显式时间参数版本,SpacetimeDB 模块只调用注入时间的函数,避免发布后触发 `time not implemented on this platform` panic。
|
||||
|
||||
`spacetime login show --token` 输出的是 CLI 登录 token,不是 HTTP `/v1/database/.../call` 所需的数据库连接 token。导入脚本如果没有显式传 `--token`,会自动调用 `POST /v1/identity` 获取 Web API token;迁移时不要把 CLI token 传给 `--token`。
|
||||
|
||||
@@ -41,17 +41,13 @@ SpacetimeDB Wasm 运行环境不支持 `std::time::SystemTime::now()`,procedur
|
||||
|
||||
运维流程:
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --database <database>
|
||||
# 控制台会输出:
|
||||
# [spacetime:maincloud] 迁移引导密钥: <本次发布随机密钥>
|
||||
```
|
||||
本地开发发布时,`npm run dev:rust` 会在发布模块前输出本次随机生成的迁移引导密钥。发布包部署时,`npm run deploy:rust:remote` 会把同一份密钥写入发布包根目录的 `migration-bootstrap-secret.txt`,目标服务器执行 `./start.sh` 发布 wasm 时也会再次显示该密钥。
|
||||
|
||||
发布完成后,在同一台机器上用当前 `spacetime login` 身份授权操作员:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <本次发布随机密钥> \
|
||||
--operator-identity <identity-hex> \
|
||||
@@ -62,7 +58,7 @@ node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-revoke-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--operator-identity <identity-hex>
|
||||
```
|
||||
@@ -71,9 +67,8 @@ node scripts/spacetime-revoke-migration-operator.mjs \
|
||||
|
||||
### 发布脚本密钥行为
|
||||
|
||||
当前所有会构建或发布 `spacetime-module` 的脚本默认都会生成并显示迁移引导密钥:
|
||||
当前会构建或发布 `spacetime-module` 的脚本默认都会生成并显示迁移引导密钥:
|
||||
|
||||
- `npm run spacetime:publish:maincloud`:在本机 `cargo build` 前生成密钥,控制台输出 `[spacetime:maincloud] 迁移引导密钥: ...`。
|
||||
- `npm run dev:rust`:在本地 `spacetime publish --module-path` 前生成密钥,控制台输出 `[dev:rust] 迁移引导密钥: ...`。
|
||||
- `npm run deploy:rust:remote`:在构建发布包 wasm 前生成密钥,控制台输出 `[deploy:rust] 迁移引导密钥: ...`,并把同一份密钥写入发布包根目录的 `migration-bootstrap-secret.txt`。服务器执行 `./start.sh` 发布 wasm 时也会再次显示该文件里的密钥。
|
||||
|
||||
@@ -145,11 +140,11 @@ Node 导入脚本默认在文件超过 `524288` bytes 时使用分片导入;
|
||||
|
||||
### 发布冲突自动迁移
|
||||
|
||||
`npm run spacetime:publish:maincloud` 默认采用冲突感知发布:
|
||||
Ubuntu 发布包的 `start.sh` 默认采用冲突感知发布:
|
||||
|
||||
1. 先不清库发布新 wasm。
|
||||
2. 如果发布成功,流程结束。
|
||||
3. 如果发布失败且输出可判定为 schema 冲突,脚本自动导出旧库迁移 JSON 到 `tmp/spacetime-migrations/maincloud/<database>/<timestamp>.json`。
|
||||
3. 如果发布失败且输出可判定为 schema 冲突,脚本自动导出旧库迁移 JSON 到 `database-migrations/<database>/<timestamp>.json` 或 `GENARRATIVE_SPACETIME_MIGRATION_DIR` 指定目录。
|
||||
4. 导出成功后执行清库发布新 wasm。
|
||||
5. 新 wasm 发布成功后,把第 3 步导出的 JSON 自动导入回灌。
|
||||
|
||||
@@ -159,15 +154,11 @@ SpacetimeDB 2.1 对 schema 冲突的报错文案可能不再包含 `schema confl
|
||||
|
||||
任一阶段失败都会中止流程,并保留已经导出的迁移 JSON。非 schema 冲突的发布失败不会进入迁移流程。
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --database xushi-p4wfr
|
||||
```
|
||||
|
||||
可选参数:
|
||||
|
||||
- `--no-migrate-on-conflict`:禁用冲突自动迁移,只保留原始发布失败。
|
||||
- `--migration-dir <dir>`:指定迁移 JSON 输出目录。
|
||||
- `--clear-database`:显式清库发布;该模式代表人工确认清库,不触发自动迁移。
|
||||
- `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT=false`:禁用冲突自动迁移,只保留原始发布失败。
|
||||
- `GENARRATIVE_SPACETIME_MIGRATION_DIR=<dir>`:指定迁移 JSON 输出目录。
|
||||
- `./start.sh --clear-database`:显式清库发布;该模式代表人工确认清库,不触发自动迁移。
|
||||
|
||||
冲突自动迁移需要发布脚本本次生成的 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET`。因此不要和 `--no-migration-bootstrap-secret` 同时使用。
|
||||
|
||||
@@ -237,7 +228,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--operator-identity <服务器 spacetime login show 中的 identity> \
|
||||
@@ -248,7 +239,7 @@ node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json
|
||||
@@ -258,7 +249,7 @@ node scripts/spacetime-import-migration-json.mjs \
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json \
|
||||
@@ -298,7 +289,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
--include ai_task,ai_task_stage,ai_text_chunk,ai_result_reference
|
||||
```
|
||||
|
||||
`--server` 支持 `dev`、`local`、`maincloud`,也可以直接传 SpacetimeDB 服务器 URL。导出、授权、撤销默认走 `spacetime call`,使用当前机器的 CLI 登录态;导入默认走 Web API request body,避免大 JSON 触发命令行长度限制。数据库名可通过 `--database`、`GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE` 或 `GENARRATIVE_SPACETIME_DATABASE` 提供。
|
||||
`--server` 支持 `dev`、`local`,也可以直接传 SpacetimeDB 服务器 URL。导出、授权、撤销默认走 `spacetime call`,使用当前机器的 CLI 登录态;导入默认走 Web API request body,避免大 JSON 触发命令行长度限制。数据库名可通过 `--database` 或 `GENARRATIVE_SPACETIME_DATABASE` 提供。
|
||||
|
||||
授权脚本额外支持:
|
||||
|
||||
@@ -319,7 +310,7 @@ node scripts/spacetime-export-migration-json.mjs \
|
||||
- 拼图:`puzzle_agent_session`、`puzzle_agent_message`、`puzzle_work_profile`、`puzzle_runtime_run`
|
||||
- 大鱼:`big_fish_creation_session`、`big_fish_agent_message`、`big_fish_asset_slot`
|
||||
|
||||
`big_fish_runtime_run` 当前运行态已由前端本地运行服务承接,不再加入迁移白名单;但 maincloud 旧库仍可能存在该表。为避免热升级被 “Removing the table big_fish_runtime_run requires a manual migration” 阻断,模块发布期可以保留兼容空壳表,后续确认旧数据可丢弃后再走正式删除表迁移。
|
||||
`big_fish_runtime_run` 当前运行态已由前端本地运行服务承接,不再加入迁移白名单;但旧库仍可能存在该表。为避免热升级被 “Removing the table big_fish_runtime_run requires a manual migration” 阻断,模块发布期可以保留兼容空壳表,后续确认旧数据可丢弃后再走正式删除表迁移。
|
||||
|
||||
后续新增 SpacetimeDB 表时,必须同步把表加入迁移白名单与本文档。
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ error starting database: failed to init replica 1 for <new-database-identity>: m
|
||||
2. `replica 1` 的持久化数据仍带有旧库 `c20037fcfaac4e5c4b1f492f026a4f6119a98f56319b77f21ef021ededf8b7ae`。
|
||||
3. SpacetimeDB 因同一个副本目录中 identity 不一致而拒绝继续启动。
|
||||
|
||||
这不是 Rust 编译错误,也不是 `api-server:maincloud` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 root-dir 数据目录污染处理。
|
||||
这不是 Rust 编译错误,也不是 `api-server` 的 token 错误。只要错误来自 `server-rs/.spacetimedb/local/.../spacetime-standalone.log`,优先按本地 root-dir 数据目录污染处理。
|
||||
|
||||
## 2. 根因
|
||||
|
||||
@@ -37,7 +37,7 @@ server-rs/.spacetimedb/local
|
||||
1. 不在脚本里默认删除 `.spacetimedb` 数据,避免误删本地开发数据。
|
||||
2. 如果只是本地开发库且数据可丢弃,优先备份后重建 `data` 目录。
|
||||
3. 如果数据必须保留,不要清理目录;应改回创建旧库时使用的 database/root-dir,或先导出迁移数据。
|
||||
4. Maincloud 发布与本地 standalone root-dir 是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
|
||||
4. 本地 standalone root-dir 与其它部署目标是两条链路;不要通过切回 `server-node` 或 PostgreSQL 绕过。
|
||||
|
||||
## 4. 本地可丢弃数据时的修复
|
||||
|
||||
@@ -77,7 +77,7 @@ npm run dev:rust
|
||||
|
||||
1. 用旧库对应的 database/root-dir 重新启动。
|
||||
2. 使用迁移导出脚本导出旧数据,再清理本地 root-dir 并导入到新库。
|
||||
3. 如目标其实是 Maincloud,改用 `npm run api-server:maincloud` 连接云端,避免误启动本地 standalone。
|
||||
3. 如目标其实是其它已运行的 SpacetimeDB 服务,改用 `GENARRATIVE_SPACETIME_SERVER_URL` 指向该服务,避免误启动本地 standalone。
|
||||
|
||||
## 6. 脚本诊断
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
# SpacetimeDB Maincloud 发布与 api-server 适配方案
|
||||
|
||||
## 目标
|
||||
|
||||
新增一条明确的 npm 命令链,用于把 `server-rs/crates/spacetime-module` 发布到 SpacetimeDB Maincloud,并让 `api-server` 可以使用同一套 Maincloud 数据库配置启动。
|
||||
|
||||
## 环境变量约定
|
||||
|
||||
Maincloud 发布不复用本地 `spacetime.local.json`,避免误把本地开发库名发布到云端。需要显式提供:
|
||||
|
||||
| 变量 | 用途 |
|
||||
| -------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE` | Maincloud 数据库名,发布脚本优先读取 |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL` | Maincloud 服务地址,默认 `https://maincloud.spacetimedb.com` |
|
||||
| `GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN` | `api-server` 连接 Maincloud 时使用的 token |
|
||||
|
||||
兼容 `api-server` 现有变量:
|
||||
|
||||
| 变量 | 用途 |
|
||||
| ---------------------------------- | --------------------------- |
|
||||
| `GENARRATIVE_SPACETIME_SERVER_URL` | `api-server` 实际连接地址 |
|
||||
| `GENARRATIVE_SPACETIME_DATABASE` | `api-server` 实际连接数据库 |
|
||||
| `GENARRATIVE_SPACETIME_TOKEN` | `api-server` 实际连接 token |
|
||||
|
||||
## npm 命令
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud
|
||||
```
|
||||
|
||||
执行内容:
|
||||
|
||||
1. 使用 `cargo build -p spacetime-module --target wasm32-unknown-unknown --release` 构建 wasm。
|
||||
2. 使用 `spacetime publish <database> --server maincloud --bin-path <wasm> --yes` 发布到 Maincloud。
|
||||
3. 发布前输出目标数据库名和 server,便于在 Jenkins 或手工日志中确认实际发布目标。
|
||||
4. 输出 `api-server` 需要的 Maincloud 环境变量,便于部署进程复用。
|
||||
|
||||
如需 schema 冲突时清库发布:
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --clear-database
|
||||
```
|
||||
|
||||
## api-server 启动
|
||||
|
||||
```bash
|
||||
npm run api-server:maincloud
|
||||
```
|
||||
|
||||
执行内容:
|
||||
|
||||
1. 从 `.env` 与 `.env.local` 读取默认环境。
|
||||
2. 将 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 映射为 `api-server` 已支持的 `GENARRATIVE_SPACETIME_*`。
|
||||
3. 在 Windows 启动前检查 `server-rs/target/debug/api-server.exe` 对应的旧进程;如果旧进程仍在运行,先停止它,避免 Rust 编译阶段覆盖 exe 时出现 `failed to remove file ... 拒绝访问。 (os error 5)`。
|
||||
4. 启动 `cargo run -p api-server --manifest-path server-rs/Cargo.toml`。
|
||||
|
||||
## 设计约束
|
||||
|
||||
- Maincloud 数据库名必须显式配置,不能默认读取本地 `spacetime.local.json`。
|
||||
- Maincloud 数据库名必须匹配 `^[a-z0-9]+(-[a-z0-9]+)*$`,只能使用小写字母、数字,并用单个短横线分隔;否则 `spacetime publish` 会报 `invalid characters in database name`。
|
||||
- 发布脚本只处理 SpacetimeDB 模块发布,不启动本地 SpacetimeDB。
|
||||
- `api-server` 继续通过 `SpacetimeClientConfig` 的 `server_url / database / token` 连接数据库,不在前端增加逻辑。
|
||||
- Windows 进程清理只能匹配本仓库 `server-rs/target/debug/api-server.exe` 的完整路径,不能按进程名泛化清理,避免影响其他 Rust 服务。
|
||||
@@ -20,7 +20,7 @@ SpacetimeDB 的数据库更新权限绑定到创建或被授权的身份。只
|
||||
|
||||
1. 部署机上执行 `start.sh` 的用户切换过 `spacetime login` 身份。
|
||||
2. 固定部署目录保留了旧 `.spacetimedb/`,但当前 CLI 身份不是旧数据库创建者。
|
||||
3. `GENARRATIVE_SPACETIME_SERVER_URL` 指向 Maincloud,而当前 CLI 身份不是该 Maincloud 数据库的所有者或授权成员。
|
||||
3. `GENARRATIVE_SPACETIME_SERVER_URL` 指向其它 SpacetimeDB 服务,而当前 CLI 身份不是该数据库的所有者或授权成员。
|
||||
4. `.env.local` 中的 `GENARRATIVE_SPACETIME_DATABASE` 指向了另一个环境的数据库名或数据库 identity。
|
||||
|
||||
## 3. 落地修复
|
||||
@@ -62,7 +62,7 @@ mv .spacetimedb ".spacetimedb.backup.$(date +%Y%m%d-%H%M%S)"
|
||||
2. 找到创建该数据库的 SpacetimeDB 身份。
|
||||
3. 用该身份对应的 CLI root 执行发布,或在 SpacetimeDB 侧补授权后再发布。
|
||||
|
||||
如果目标是 Maincloud:
|
||||
如果目标是其它 SpacetimeDB 服务:
|
||||
|
||||
1. 执行 `spacetime login show` 确认当前身份。
|
||||
2. 确认该身份对 `GENARRATIVE_SPACETIME_DATABASE` 有更新权限。
|
||||
|
||||
56
docs/technical/WORK_PUBLISH_SHARE_PANEL_2026-05-02.md
Normal file
56
docs/technical/WORK_PUBLISH_SHARE_PANEL_2026-05-02.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 作品发布完成分享面板 2026-05-02
|
||||
|
||||
## 背景
|
||||
|
||||
当前 RPG、拼图、大鱼吃小鱼、抓大鹅 Match3D 的发布链路已经能把作品同步到公开广场,但发布成功后的用户反馈主要是跳转到作品详情或按钮状态变化。用户完成发布后缺少一个明确的“分享给朋友”收口动作,导致公开作品号与链接不够显眼。
|
||||
|
||||
## 目标
|
||||
|
||||
发布动作确认成功后弹出独立平台风面板:
|
||||
|
||||
1. 面板标题固定为“分享给朋友”。
|
||||
2. 标题下显示可复制的分享文本。
|
||||
3. 分享文本下方显示主按钮“分享”,点击后复制完整分享文本。
|
||||
4. 页面底部显示三个分享渠道 icon:微信、QQ、抖音。
|
||||
5. 移动端使用底部弹层,桌面端居中展示,复用 `UnifiedModal` 的平台弹窗外壳。
|
||||
|
||||
## 分享文本
|
||||
|
||||
分享文本统一使用:
|
||||
|
||||
```text
|
||||
邀请你来玩《作品名》
|
||||
作品号:公开作品码
|
||||
公开链接
|
||||
```
|
||||
|
||||
公开作品码来源:
|
||||
|
||||
- RPG:优先使用发布后作品库 / 公开详情返回的 `publicWorkCode`。
|
||||
- 拼图:使用 `buildPuzzlePublicWorkCode(profileId)`。
|
||||
- 大鱼吃小鱼:使用 `buildBigFishPublicWorkCode(sourceSessionId)`。
|
||||
- 抓大鹅 Match3D:使用 `buildMatch3DPublicWorkCode(profileId)`。
|
||||
|
||||
公开链接统一使用 `buildPublicWorkStagePath(stage, publicWorkCode)` 转换为当前站点绝对链接。
|
||||
|
||||
## 渠道 icon 规则
|
||||
|
||||
本次只做前端分享引导,不接入微信、QQ、抖音的原生 SDK。点击渠道 icon 与主“分享”按钮保持一致,复制同一份分享文本。
|
||||
|
||||
仓库现有 `media/social-media-group/wechat.png` 与 `qq.png` 是社群二维码,不作为本面板渠道 icon 使用。渠道 icon 采用轻量圆形文字标识,避免误导用户进入社群。
|
||||
|
||||
## 接入范围
|
||||
|
||||
- `RpgCreationResultActionBar`:RPG 发布成功后由父层回传分享数据并打开面板。
|
||||
- `PuzzleResultView`:拼图发布 action 完成后由平台父层打开面板。
|
||||
- `BigFishResultView`:大鱼发布 action 完成后由平台父层打开面板。
|
||||
- `Match3DResultView`:本地 `publishMatch3DWork` 成功后直接触发面板数据,分享链接对齐现有作品详情入口。
|
||||
- `PlatformEntryFlowShellImpl`:集中维护发布完成分享状态,避免各玩法重复实现弹窗。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 用户完成作品发布后能看到“分享给朋友”面板。
|
||||
2. 面板内展示完整分享文本,主按钮点击后复制成功并短暂显示成功态。
|
||||
3. 底部固定展示微信、QQ、抖音三个渠道 icon。
|
||||
4. 关闭面板不影响已发布作品进入详情、刷新广场或继续游玩。
|
||||
5. 不新增后端接口,不改动 SpacetimeDB 表结构。
|
||||
Reference in New Issue
Block a user