Files
Genarrative/docs/technical/SPACETIMEDB_ASSET_OBJECT_TABLE_DESIGN_2026-04-21.md
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

6.2 KiB
Raw Permalink Blame History

asset_object 表设计

日期:2026-04-21

1. 文档目的

这份文档用于把 asset_object 从“概念字段列表”推进到可以直接编码的级别。

当前要冻结的不只是字段名,还包括:

  1. 表职责边界
  2. bucket + object_key 的正式主存储口径
  3. 首版字段类型
  4. 当前阶段必须先落下的索引
  5. api-server / platform-oss / 后续业务绑定表 的边界

2. 当前已确认前提

目前与 asset_object 直接相关的事实已经确认如下:

  1. 阿里云 OSS 当前按私有 bucket 模式接入。
  2. 浏览器上传通过 POST /api/assets/direct-upload-tickets 下发的 PostObject 票据完成。
  3. platform-oss 已输出:
    • bucket
    • objectKey
    • legacyPublicPath
    • access
  4. 匿名公开 URL 当前返回 403,不能作为正式读取真相。

因此 asset_object 必须承担的真实职责是:

  1. 记录对象在 OSS 中的唯一定位
  2. 记录对象元数据
  3. 为后续业务绑定表提供稳定引用
  4. 不把 URL 当成正式主键

3. 表职责边界

3.1 asset_object 负责的内容

  1. asset_object_id:对象主键
  2. bucket:对象所属 bucket
  3. object_keybucket 内对象路径
  4. access_policy:对象访问策略
  5. content_type
  6. content_length
  7. content_hash
  8. version
  9. 来源任务、归属用户、profile、业务实体等轻量关联键
  10. asset_kind
  11. created_at / updated_at

3.2 asset_object 不负责的内容

  1. 不负责大对象二进制本体
  2. 不负责生成任务完整编排状态
  3. 不负责直接暴露公共 URL
  4. 不负责角色、动作、场景、精灵表等强业务关系本身

3.3 与其他表的边界

  1. asset_job 负责任务态,不替代对象真相。
  2. asset_manifest 负责对象集合或发布清单,不替代单对象行。
  3. character_visual_asset / scene_image_asset / sprite_sheet_asset 这类强业务关系表优先引用 asset_object_id

4. 表访问级别

asset_object 当前固定为 private table

原因:

  1. bucket 当前是私有读写。
  2. 对象读取需要服务端签名 URL 或下载代理。
  3. 前端不应直接把 asset_object 当公开订阅表使用。

补充口径:

  1. 当前阶段先不把 asset_object 做成 public。
  2. 未来若要给客户端读对象列表,优先通过 view 或 Axum facade 输出脱敏 DTO。

5. 首版字段设计

字段名 类型 必填 说明
asset_object_id String 主键,固定使用 assetobj_ 前缀的稳定字符串 ID。
bucket String 正式对象仓名称。
object_key String bucket 内对象路径,不带前导 /
access_policy AssetObjectAccessPolicy 当前先冻结为 private / public_read
content_type Option<String> 真实对象 MIME。
content_length u64 已确认对象大小,单位字节。
content_hash Option<String> 内容摘要,当前先保留为空间,不预设算法强制值。
version u32 对象版本号,首版默认 1
source_job_id Option<String> 来源任务 ID。
owner_user_id Option<String> 归属用户 ID。
profile_id Option<String> 归属 profile ID。
entity_id Option<String> 归属业务实体 ID。
asset_kind String 资产业务类型,例如 character_visualscene_image
created_at Timestamp 创建时间。
updated_at Timestamp 最近更新时间。

补充约束:

  1. bucketobject_key 是正式对象定位真相。
  2. 允许存在 asset_object_id,但不允许回退成单列 storage_path 作为真相字段。
  3. content_hash 先允许为空,避免在上传确认链路未落地前把 schema 卡死。

6. 索引与查询约束

6.1 当前阶段必须先落的索引

  1. bucket + object_key 组合 B-Tree 索引 作用:按真实对象定位回查对象元数据
  2. asset_kind 单列索引 作用:后续按业务类型聚合或清理对象

6.2 为什么先不加更多索引

当前阶段只先解决:

  1. 正式对象定位
  2. 业务类型过滤

而以下能力尚未落地:

  1. asset_job
  2. 上传完成确认 reducer
  3. 业务绑定 reducer

因此暂不提前为每个可空关联键堆索引,避免在真实访问模式还没固定前把 schema 复杂度拉高。

7. 写入约束

7.1 当前阶段允许的对象写入时机

后续真正写 asset_object 时,必须满足以下前提之一:

  1. 浏览器直传成功,服务端确认对象存在
  2. 后台 worker 成功上传对象到 OSS
  3. 旧对象迁移脚本确认对象存在并完成元数据回填

7.2 当前阶段不允许的漂移

  1. 只根据 legacyPublicPath 就写入对象真相
  2. 只存完整 URL不拆 bucket/object_key
  3. asset_object 里重复塞角色、场景、动作等业务专属冗余字段
  4. 先落 bucket/object_key 之外的单列字符串路径,再计划后续拆列

8. 与当前代码的对接关系

当前工程中的直接对接关系固定如下:

  1. platform-oss
    • 负责生成 bucket + object_key 对象定位
  2. api-server
    • 负责输出直传票据与私有读签名 URL
  3. module-assets
    • 负责沉淀 AssetObjectAccessPolicy 与字段校验 helper
  4. spacetime-module
    • 负责聚合 asset_object 首版表骨架

9. 当前阶段完成定义

当以下条件满足时,asset_object 的首版设计与骨架视为完成:

  1. bucket + object_key 已在表结构中固定为两列
  2. 表访问级别已固定为 private
  3. 字段和索引已具体到可直接编码
  4. module-assetsspacetime-module 已落真实 crate scaffold

10. 相关文档

  1. SPACETIMEDB_ASSET_OBJECT_STORAGE_DESIGN_2026-04-21.md
  2. SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md
  3. ../../server-rs/crates/module-assets/README.md
  4. ../../server-rs/crates/spacetime-module/README.md