Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
当前阶段只解决一件事:
|
||||
|
||||
1. 由 `Axum` 根据服务端配置,返回当前环境启用的登录方式列表。
|
||||
2. 密码登录入口由 Rust `password_entry` 固定承载,作为登录弹窗的保底入口。
|
||||
|
||||
本阶段明确不包含:
|
||||
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
```json
|
||||
{
|
||||
"availableLoginMethods": ["phone", "wechat"]
|
||||
"availableLoginMethods": ["phone", "password", "wechat"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -40,6 +41,7 @@
|
||||
1. `availableLoginMethods` 为字符串数组
|
||||
2. 当前阶段只允许出现:
|
||||
- `phone`
|
||||
- `password`
|
||||
- `wechat`
|
||||
|
||||
### 3.3 返回顺序
|
||||
@@ -47,7 +49,8 @@
|
||||
返回顺序固定为:
|
||||
|
||||
1. 先 `phone`
|
||||
2. 再 `wechat`
|
||||
2. 再 `password`
|
||||
3. 再 `wechat`
|
||||
|
||||
这样可以保证前端按钮顺序稳定,不因配置解析顺序变化而漂移。
|
||||
|
||||
@@ -61,8 +64,9 @@
|
||||
映射规则固定为:
|
||||
|
||||
1. `SMS_AUTH_ENABLED=true` 时返回 `phone`
|
||||
2. `WECHAT_AUTH_ENABLED=true` 时返回 `wechat`
|
||||
3. 两者都关闭时返回空数组
|
||||
2. Rust 密码登录主链可用时固定返回 `password`
|
||||
3. `WECHAT_AUTH_ENABLED=true` 时返回 `wechat`
|
||||
4. 短信与微信都关闭时仍返回 `["password"]`
|
||||
|
||||
## 5. crate 边界
|
||||
|
||||
@@ -84,13 +88,15 @@
|
||||
|
||||
1. 根据 `availableLoginMethods` 决定是否展示手机号 / 微信入口
|
||||
2. 不再假设某种登录方式一定存在
|
||||
3. 若 `/api/auth/login-options` 联调失败或返回空数组,前端仍保留 `password` 入口,避免登录弹窗显示“当前登录入口暂不可用”后无法继续操作。
|
||||
|
||||
## 6. 测试要求
|
||||
|
||||
至少覆盖:
|
||||
|
||||
1. 默认配置下返回空数组
|
||||
2. 同时启用短信与微信时返回 `["phone", "wechat"]`
|
||||
1. 默认配置下返回 `["password"]`
|
||||
2. 同时启用短信、密码与微信时返回 `["phone", "password", "wechat"]`
|
||||
3. 前端在 `login-options` 读取失败或返回空数组时,仍展示密码登录表单
|
||||
|
||||
## 7. 完成定义
|
||||
|
||||
|
||||
@@ -2,26 +2,34 @@
|
||||
|
||||
## 背景
|
||||
|
||||
当前大鱼运行时使用左下固定虚拟摇杆,玩家必须点到摇杆区域才能移动。移动端实际体验应改为屏幕任意位置触控:第一次触点只建立方向原点,不直接产生移动;后续触点相对原点形成方向向量,角色按恒定速度朝该方向行动。
|
||||
当前大鱼运行时使用左下固定虚拟摇杆,玩家必须点到摇杆区域才能移动。移动端实际体验应改为屏幕任意位置触控:按住屏幕时不再用“触点相对按下原点”的距离判断方向,而是按固定采样间隔比较“上一次触点位置”和“当前触点位置”的位移方向,角色按恒定速度朝采样方向行动。
|
||||
|
||||
## 交互规则
|
||||
|
||||
1. 玩家在玩法舞台内按下时,记录第一个触点坐标为本次操作原点。
|
||||
1. 玩家在玩法舞台内按下时,记录当前触点坐标为采样起点。
|
||||
2. 按下瞬间提交 `{ x: 0, y: 0 }`,保证一开始玩家不动。
|
||||
3. 手指/鼠标移动后,用“当前触点 - 原点”的向量计算方向。
|
||||
4. 输入只表达方向,不表达速度;超过死区后归一化为单位方向向量。
|
||||
5. 松开或取消触控后,清空操作原点并提交 `{ x: 0, y: 0 }`。
|
||||
6. 前端继续定时提交当前方向,即使没有玩家输入也提交零向量,让后端或本地直达局持续推进世界 tick。
|
||||
3. 按住期间每 `0.1` 秒采样一次当前触点坐标,并用“当前触点 - 上一次采样触点”的位移计算方向。
|
||||
4. 输入只表达方向,不表达速度;超过采样死区后归一化为单位方向向量,未超过死区则沿用上一段有效方向。
|
||||
5. 每次采样完成后,把当前触点写为下一次采样的“上一次位置”。
|
||||
6. 松开或取消触控后,清空采样状态并提交 `{ x: 0, y: 0 }`。
|
||||
7. 前端继续定时提交当前方向,即使没有玩家输入也提交零向量,让后端或本地直达局持续推进世界 tick。
|
||||
|
||||
## 本地直达局边界
|
||||
|
||||
- `/big-fish` 的本地占位局必须在玩家未操作时继续移动野生对象。
|
||||
- 大鱼吃小鱼的最终游玩部分统一放在前端本地 runtime,不再调用后端 start/input/get run 接口。
|
||||
- 后端只保留 Agent 创作、草稿编译、资产生成、发布和作品列表;不负责移动、碰撞、刷鱼、合成、屏外清理或胜负模拟。
|
||||
- `/big-fish` 的本地直达局和平台内测试玩法必须共用前端本地 runtime,并在玩家未操作时继续移动野生对象。
|
||||
- 玩家速度保持恒定,只由方向决定移动方向。
|
||||
- 野生对象使用确定性游动规则,避免直达入口看起来像静态截图。
|
||||
|
||||
## 验收口径
|
||||
|
||||
1. 在舞台任意位置按下时玩家不立即移动。
|
||||
2. 按住并拖动后,玩家朝拖动方向恒速移动。
|
||||
2. 按住并拖动后,玩家方向来自最近 `0.1` 秒位移,而不是来自按下原点。
|
||||
3. 松开后玩家停止。
|
||||
4. 不操作时野生对象仍会持续游动。
|
||||
|
||||
## 资产生成补充口径
|
||||
|
||||
- 大鱼实体主图、`idle_float` 和 `move_swim` 动作图都按 RPG 角色资产口径处理:单体完整入镜、中心构图、轮廓清晰、透明背景、无 UI/文字/水印。
|
||||
- 场地背景只生成环境,不生成规则说明、UI 或巨大主体遮挡;画面元素要少,中央活动区域要大,边缘只保留少量出生区提示。
|
||||
|
||||
@@ -26,3 +26,7 @@
|
||||
2. 新建拼图创作工作区后,顶部创作进度显示 `0%`。
|
||||
3. 发送第一条用户消息后,进度按模型回包或后续操作正常推进。
|
||||
4. 生成草稿、生成资产、发布等后续阶段的进度值不受本次调整影响。
|
||||
|
||||
## 2026-04-27 复核记录
|
||||
|
||||
大鱼吃小鱼创建链路曾回退为 `progress_percent = 20`。本次重新将 `create_big_fish_session_tx` 的初始进度锁定为 `0`,并用 `INITIAL_BIG_FISH_CREATION_PROGRESS_PERCENT` 常量表达该约束,避免欢迎语或初始锚点占位再次被误计为创作进度。
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
# SpacetimeDB JSON 字符串迁移 procedure 设计
|
||||
|
||||
## 背景
|
||||
|
||||
`spacetime sql` 只能稳定读取 public 表或数据库 owner 可见表。当前 `ai_result_reference` 等运行真相表保持 private,直接 SQL 导出会遇到 `no such table` 或 private table 提示,不能作为跨服务器迁移的稳定方案。
|
||||
|
||||
SpacetimeDB reducer 必须保持确定性,不能访问文件系统和网络。procedure 可以返回数据,也可以在事务中读取 private 表,因此迁移改为:
|
||||
|
||||
1. `spacetime-module` 内的导出 procedure 读取迁移白名单表,并直接返回迁移 JSON 字符串。
|
||||
2. Node 运维脚本默认通过 `spacetime call` 调用导出 procedure,把返回的 JSON 字符串写入本地文件。
|
||||
3. Node 运维脚本读取本地 JSON 文件内容。导入时默认先通过 `POST /v1/identity` 创建临时 Web API identity/token,再用当前 CLI 登录态把该 identity 授权为迁移操作员,最后通过 HTTP request body 把 JSON 字符串传给导入 procedure。
|
||||
4. 导入 procedure 校验 JSON 与表白名单后,在事务中写入目标数据库。
|
||||
|
||||
procedure 不再访问 HTTP 文件桥,也不接收部署机本地文件路径。这样可以避开 SpacetimeDB 对 private/special-purpose 地址的 HTTP 访问限制,并避免把 private 表内容通过临时 HTTP 服务转发。
|
||||
|
||||
`spacetime login show --token` 输出的是 CLI 登录 token,不是 HTTP `/v1/database/.../call` 所需的数据库连接 token。导入脚本如果没有显式传 `--token`,会自动调用 `POST /v1/identity` 获取 Web API token;迁移时不要把 CLI token 传给 `--token`。
|
||||
|
||||
## 接口
|
||||
|
||||
### 迁移操作员授权
|
||||
|
||||
迁移 procedure 会读取并写入 private 表,不能对任意登录身份开放。模块内新增私有表 `database_migration_operator` 作为迁移操作员白名单:
|
||||
|
||||
- `operator_identity`: 被授权调用迁移 procedure 的 SpacetimeDB identity。
|
||||
- `created_at`: 授权写入时间。
|
||||
- `created_by`: 发起授权的 identity。
|
||||
- `note`: 运维备注,只用于区分来源、环境或临时用途。
|
||||
|
||||
`database_migration_operator` 只控制迁移 procedure 调用权限,不会被导出或导入,避免把源库的运维权限复制到目标库。
|
||||
|
||||
首次授权时,操作员表为空,必须通过编译进模块的 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET` 引导密钥授权第一位操作员。发布脚本会在构建或发布 SpacetimeDB 模块时自动生成一份强随机引导密钥、注入 wasm 编译环境,并在控制台显示;运维人员必须记录对应数据库本次发布输出的密钥。表内已经存在操作员后,后续授权与撤销只能由已有操作员发起;此时不再接受引导密钥越权扩权。
|
||||
|
||||
新增 procedure:
|
||||
|
||||
- `authorize_database_migration_operator`: 授权或更新迁移操作员备注。
|
||||
- `revoke_database_migration_operator`: 撤销迁移操作员。
|
||||
|
||||
运维流程:
|
||||
|
||||
```bash
|
||||
npm run spacetime:publish:maincloud -- --database <database>
|
||||
# 控制台会输出:
|
||||
# [spacetime:maincloud] 迁移引导密钥: <本次发布随机密钥>
|
||||
```
|
||||
|
||||
发布完成后,在同一台机器上用当前 `spacetime login` 身份授权操作员:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <本次发布随机密钥> \
|
||||
--operator-identity <identity-hex> \
|
||||
--note "2026-04-27 migration"
|
||||
```
|
||||
|
||||
迁移完成后可以撤销临时操作员:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-revoke-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--database xushi-p4wfr \
|
||||
--operator-identity <identity-hex>
|
||||
```
|
||||
|
||||
生产环境建议迁移完成后用 `--no-migration-bootstrap-secret` 重新发布一个未设置 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET` 的模块版本,避免引导密钥长期留在 wasm 中。
|
||||
|
||||
### 发布脚本密钥行为
|
||||
|
||||
当前所有会构建或发布 `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 时也会再次显示该文件里的密钥。
|
||||
|
||||
如果迁移完成后不希望 wasm 继续携带引导密钥,重新发布时传 `--no-migration-bootstrap-secret`。远端发布包若使用 `--skip-spacetime-build`,必须同时传 `--no-migration-bootstrap-secret`,否则脚本会拒绝生成一个无法注入旧 wasm 的新密钥。
|
||||
|
||||
### 导出
|
||||
|
||||
`export_database_migration_to_file(ctx, input)`
|
||||
|
||||
输入字段:
|
||||
|
||||
- `include_tables`: 可选表名白名单。为空时导出当前实现支持的全部迁移表。
|
||||
|
||||
返回字段:
|
||||
|
||||
- `ok`: 是否成功。
|
||||
- `schema_version`: 迁移 JSON 结构版本。
|
||||
- `migration_json`: 成功时包含完整迁移 JSON 字符串,失败时为空。
|
||||
- `table_stats`: 表级导出统计。
|
||||
- `error_message`: 失败原因。
|
||||
|
||||
### 导入
|
||||
|
||||
`import_database_migration_from_file(ctx, input)`
|
||||
|
||||
`import_database_migration_incremental_from_file(ctx, input)`
|
||||
|
||||
输入字段:
|
||||
|
||||
- `migration_json`: 导出 procedure 生成的完整迁移 JSON 字符串。
|
||||
- `include_tables`: 可选表名白名单。为空时导入文件内所有支持表。
|
||||
- `replace_existing`: 是否先清空本次迁移文件内实际导入的目标表。不会清空迁移文件未包含的表;分批迁移时只覆盖当前批次。
|
||||
- `dry_run`: 只解析和统计,不写表。
|
||||
|
||||
导入模式:
|
||||
|
||||
- 默认严格追加:不清空目标表,逐行插入;遇到主键或唯一约束冲突时失败并回滚,适合确认目标库没有同表旧数据时使用。
|
||||
- 增量追加:调用 `import_database_migration_incremental_from_file`,不清空目标表;遇到已存在或唯一约束冲突的行会跳过并计入 `skipped_row_count`,只插入目标库缺失的行。该模式不会更新目标库已有行。
|
||||
- 覆盖导入:`replace_existing = true` 时先删除覆盖范围内的目标表旧数据,再插入迁移文件中的数据;只适合迁移文件是这些表完整快照的场景。
|
||||
|
||||
返回字段:
|
||||
|
||||
- `ok`: 是否成功。
|
||||
- `schema_version`: 迁移 JSON 结构版本。
|
||||
- `migration_json`: 导入场景恒为空,避免重复回传大 JSON。
|
||||
- `table_stats`: 表级导入或跳过统计。
|
||||
- `error_message`: 失败原因。
|
||||
|
||||
保留 `export_database_migration_to_file` / `import_database_migration_from_file` 名称,是为了减少已经记住的 procedure 名变更;语义上不再代表 module 直接读写文件。
|
||||
|
||||
## Node 脚本
|
||||
|
||||
本机导出时,先确保本机 SpacetimeDB 服务和源数据库可访问,然后授权本机调用身份:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <本机源库发布时输出的随机密钥> \
|
||||
--operator-identity <本机 spacetime login show 中的 identity> \
|
||||
--note "local export"
|
||||
```
|
||||
|
||||
导出脚本负责调用本机源库 procedure 并保存返回 JSON:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-export-migration-json.mjs \
|
||||
--server dev \
|
||||
--database xushi-p4wfr \
|
||||
--out tmp/spacetime-migrations/source-2026-04-27.json
|
||||
```
|
||||
|
||||
把 `tmp/spacetime-migrations/source-2026-04-27.json` 复制到服务器后,在服务器上登录目标 SpacetimeDB,并授权服务器侧调用身份:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-authorize-migration-operator.mjs \
|
||||
--server maincloud \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--operator-identity <服务器 spacetime login show 中的 identity> \
|
||||
--note "server import"
|
||||
```
|
||||
|
||||
导入脚本负责读取服务器本地文件并把 JSON 字符串通过 Web API request body 传入目标库 procedure。因为 JSON 不再放进 `spacetime call` 命令行参数,所以不会触发 Linux `spawn E2BIG`:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json
|
||||
```
|
||||
|
||||
如果目标库已有部分数据,且只想补充缺失行,使用增量模式:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-import-migration-json.mjs \
|
||||
--server maincloud \
|
||||
--database xushi-p4wfr \
|
||||
--bootstrap-secret <服务器目标库发布时输出的随机密钥> \
|
||||
--in tmp/spacetime-migrations/source-2026-04-27.json \
|
||||
--incremental
|
||||
```
|
||||
|
||||
如果目标库对应表已有数据,并且本次文件应作为这些表的覆盖来源,再显式追加 `--replace-existing`。脚本会把覆盖范围限定为迁移文件内实际包含且本次会导入的表,避免分批导入时清空文件外的其它表。
|
||||
|
||||
默认情况下,脚本会自动完成三步:
|
||||
|
||||
1. `POST /v1/identity` 创建临时 Web API identity/token。
|
||||
2. 使用当前机器 `spacetime` CLI 登录态调用 `authorize_database_migration_operator`,授权这个临时 identity。
|
||||
3. 使用 `Authorization: Bearer <临时 token>` 调用 `import_database_migration_from_file`,把完整迁移 JSON 放在 HTTP body 中。
|
||||
4. 导入请求结束后,脚本会用同一个临时 Web API token 调用 `revoke_database_migration_operator`,撤销该临时 identity。
|
||||
|
||||
所有直接访问 SpacetimeDB Web API 的 POST 请求必须显式发送 `Content-Type: application/json`。部分 SpacetimeDB 版本不会接受省略 content type 或附带非预期 media type 的请求,即使 body 本身是合法 JSON,也会返回 `HTTP 415`。
|
||||
|
||||
如果你已经有可用的数据库连接 token,也可以显式传 `--token <web-api-token>`。这种情况下脚本不会自动授权;该 token 对应的 identity 必须已经是迁移操作员。
|
||||
|
||||
正式导入前建议先加 `--dry-run`,确认 JSON 可解析、版本匹配、表名都在迁移白名单内。
|
||||
|
||||
`--dry-run` 不会模拟目标库主键或唯一约束冲突,因此增量模式的 `skipped_row_count` 只有真实导入时才准确。
|
||||
|
||||
不要在只想追加数据时使用 `--replace-existing`。该参数会先删除覆盖范围内的目标表旧数据,再插入迁移文件中的数据;如果源文件不是完整快照,会造成目标表数据丢失。
|
||||
|
||||
如需分批迁移,可用逗号分隔表名:
|
||||
|
||||
```bash
|
||||
node scripts/spacetime-export-migration-json.mjs \
|
||||
--database xushi-p4wfr \
|
||||
--out tmp/spacetime-migrations/ai.json \
|
||||
--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` 提供。
|
||||
|
||||
授权脚本额外支持:
|
||||
|
||||
- `--bootstrap-secret` 或 `GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET`
|
||||
- `--operator-identity` 或 `GENARRATIVE_SPACETIME_MIGRATION_OPERATOR_IDENTITY`
|
||||
- `--note`
|
||||
|
||||
## 表范围
|
||||
|
||||
首版覆盖当前 private table 报错相关与主运行真相表:
|
||||
|
||||
- 认证:`auth_store_snapshot`、`user_account`、`auth_identity`、`refresh_session`
|
||||
- AI:`ai_task`、`ai_task_stage`、`ai_text_chunk`、`ai_result_reference`
|
||||
- 运行存档与账户投影:`runtime_snapshot`、`runtime_setting`、`user_browse_history`、`profile_dashboard_state`、`profile_wallet_ledger`、`profile_invite_code`、`profile_referral_relation`、`profile_played_world`、`profile_membership`、`profile_recharge_order`、`profile_save_archive`
|
||||
- RPG 运行真相:`player_progression`、`chapter_progression`、`npc_state`、`story_session`、`story_event`、`inventory_slot`、`battle_state`、`treasure_record`、`quest_record`、`quest_log`
|
||||
- 自定义世界:`custom_world_profile`、`custom_world_session`、`custom_world_agent_session`、`custom_world_agent_message`、`custom_world_agent_operation`、`custom_world_draft_card`、`custom_world_gallery_entry`
|
||||
- 资产索引:`asset_object`、`asset_entity_binding`
|
||||
- 拼图:`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`
|
||||
|
||||
后续新增 SpacetimeDB 表时,必须同步把表加入迁移白名单与本文档。
|
||||
|
||||
## 风险与限制
|
||||
|
||||
迁移 JSON 作为 procedure 返回值和 HTTP request body 传递,会受 SpacetimeDB 调用响应体、请求体以及中间代理大小限制。数据量较大时,先按 `include_tables` 分批迁移;若单表本身过大,再补充分片 procedure,而不是恢复 HTTP 文件桥。
|
||||
|
||||
`spacetime call` 在 PowerShell 中手写 JSON 容易被剥掉双引号。导入大文件时也不能把完整 JSON 放进命令行参数,否则 Linux 会在启动子进程时返回 `spawn E2BIG`。推荐使用仓库里的 Node 脚本,由脚本直接走 Web API request body,避免 shell 二次处理和命令行长度限制。
|
||||
Reference in New Issue
Block a user