--- name: world_snapshot description: 世界状态快照模块(W-04 快照管理)——world_snapshot 表(checksum/version 递增)、快照生成(事务批量+checksum 一致性校验)、查询(分页 {list,total})、恢复(事务回滚无脏数据)、编码字典 snapshot_status/snapshot_type 幂等落库、REST /api/* 统一前缀与错误结构 {code,message,field,detail}。 --- # world_snapshot 模块(W-04 快照管理) ## 架构 world_snapshot 是域内业务模块:聚合 world/scene/entity 当前状态生成快照,支持查询与恢复。 通过 `load_world_snapshot()` 挂载到宿主应用(唯一集成点),无独立 app.py/端口。 ## 数据模型 表 `world_snapshot`(models/world_snapshot.json): | 字段 | 类型 | 说明 | |---|---|---| | id | str(32) PK | 主键(getID) | | world_id | str(32) | 世界ID(关联 world) | | name | str(255) | 快照名称 | | snapshot_type | str(32) | full / incremental | | snapshot_json | text | 快照内容 JSON(world/scene/entity 聚合) | | checksum | str(64) | sha256 校验和 | | version | int | 快照版本,按 world 递增(max+1) | | status | str(32) | active / restored / expired | | snapshot_date | timestamp | 快照日期 | | created_at / updated_at | timestamp | 审计时间 | 唯一索引 `uk_snap_world_version(world_id, version)` 保证同世界版本不重复。 编码字典(init/data.json 幂等落库): - `snapshot_status`:active 生效中 / restored 已恢复 / expired 已过期 - `snapshot_type`:full 全量快照 / incremental 增量快照 ## 核心逻辑 ### 快照生成 create_snapshot 1. 输入白名单校验(world_id 必填且 ≤32、snapshot_type ∈ {full,incremental}、name ≤255)——非法输入 100% 拦截不落库 2. 同一事务内:`select world ... for update` 行锁该世界 → 批量聚合 scene/entity → 拼 snapshot_json → sha256 checksum 3. `max(version)+1` 递增(行锁 + 唯一索引双保险) 4. 事务提交;任何异常整体回滚,返回 `{code,message,field,detail}` ### 快照查询 get_snapshot / list_snapshots - get:读单条,checksum 重算比对,不匹配返回 `CHECKSUM_MISMATCH`(数据损坏检测) - list:分页 `{list,total,page,page_size}`;page/page_size 非整数、status/snapshot_type 不在白名单 → 拦截 ### 快照恢复 restore_snapshot 1. 校验快照存在 + checksum 一致性 2. 同一事务内:先删后插写回 scene/entity(按目标表 information_schema 字段过滤防脏列)→ 更新 world.mode=active → 快照置 restored 3. 任一步异常 → 事务整体回滚,无脏数据 ## REST 端点(统一前缀 /api/*) | 端点 | 方法 | 说明 | |---|---|---| | /world_snapshot/api/snapshot_create.dspy | POST | 生成快照 | | /world_snapshot/api/snapshot_get.dspy | GET/POST | 查询单个(含 checksum 校验) | | /world_snapshot/api/snapshot_list.dspy | GET/POST | 分页列表 {list,total} | | /world_snapshot/api/snapshot_update.dspy | POST | 更新(白名单字段) | | /world_snapshot/api/snapshot_delete.dspy | POST | 删除快照记录 | | /world_snapshot/api/snapshot_restore.dspy | POST | 恢复快照(事务回滚) | | /world_snapshot/api/snapshot_types.dspy | GET | 编码字典:快照类型 [{value,text}] | | /world_snapshot/api/snapshot_statuses.dspy | GET | 编码字典:快照状态 [{value,text}] | | /world_snapshot/api/snapshot_worlds.dspy | GET | 可选世界列表 [{value,text}] | 成功结构:`{"success":true, ...}` 错误结构:`{"code":"...","message":"...","field":"...","detail":"..."}` ## 函数注册(三处同步) `world_snapshot/world_snapshot/init.py` 实现 + `world_snapshot/world_snapshot/__init__.py` import + `load_world_snapshot()` 里 `env.xxx = xxx`。新增/删除函数必须三处同步。 ## 陷阱 - **取库名禁止硬编码**:`.py` 用 `ServerEnv().get_module_dbname('world_snapshot')`;.dspy 直接用全局 `get_module_dbname()` - **事务 return 位置**:`return` 必须在 `async with` 块外(块内 return 返回 None) - **sor.U 仅 2 参数**:主键放 data 里;仅主键时校验非空更新字段 - **sqlExe 必须带 ns**:无参数查询也传 `{}` - **.dspy 禁止 import**:函数经 load_*() 导出;预加载全局 json/debug/getID 等直接可用 - **dbpools 单例 fork 陷阱**:函数内 `db = DBPools()` 局部创建 - **sor.C 不自动补 created_at**:插入时显式设置 `created_at`/`updated_at` = curDateString() - **LIMIT/OFFSET 用整数**:字符串会渲染成 `LIMIT '5'` 语法错误