Files
Genarrative/docs/technical/SPACETIMEDB_ASSET_OBJECT_STORAGE_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

5.8 KiB
Raw Blame History

SpacetimeDB 资产对象存储设计

日期:2026-04-21

1. 文档目的

这份文档用于冻结当前 assets / OSS 前置落地后的两个关键口径:

  1. 阿里云 OSS 当前按私有 bucket 模式接入。
  2. 后续 SpacetimeDB 的资产对象引用统一按 bucketobject_key 两列存储,而不是拼成单个路径字符串。

这份文档直接服务于以下工程收口动作:

  1. platform-oss 的输出 contract 收敛。
  2. api-server 的直传票据接口收敛。
  3. 后续 asset_objectasset_manifest、业务绑定表的字段设计收敛。

2. 当前已确认事实

2.1 Bucket 访问策略

当前阿里云 OSS bucket

  • bucketxushi-dev
  • endpointoss-cn-beijing.aliyuncs.com

已确认:

  1. bucket 当前为私有读写
  2. 服务端可通过 AccessKeyId / AccessKeySecret 正常访问 bucket。
  3. 浏览器可通过服务端签发的 PostObject 票据完成上传。
  4. 未签名的对象公开 URL 返回 403,不能当成正式读取链路。

2.2 当前工程能力状态

当前 server-rs 已落地:

  1. platform-oss:浏览器 PostObject 直传签名
  2. api-serverPOST /api/assets/direct-upload-tickets
  3. platform-oss:私有对象短期签名读取 URL
  4. api-serverGET /api/assets/read-url
  5. server-rs/scripts/oss-smoke.ps1:真实 OSS 联调脚本
  6. platform-oss:私有 HEAD Object 探测
  7. api-serverPOST /api/assets/objects/confirm
  8. module-assets:进程内 asset_object 确认服务
  9. platform-oss:服务端 PutObject 上传 helper
  10. api-serverPOST /api/assets/sts-upload-credentials 禁用式 contract

当前仍未落地:

  1. STS 真实临时授权下发
  2. multipart 分片上传
  3. 内容 hash 自动计算与版本字段细化

当前上传完成确认接口的详细请求、校验顺序与写入规则见:

  1. ASSET_OBJECT_CONFIRM_FLOW_DESIGN_2026-04-21.md

服务端上传与 STS 禁用式 contract 的详细设计见:

  1. M6_OSS_SERVER_UPLOAD_AND_STS_POLICY_2026-04-21.md

3. 正式存储口径

3.1 SpacetimeDB 中的对象引用格式

后续 SpacetimeDB 中凡是需要引用 OSS 对象的地方,统一按以下两列存储:

  1. bucket
  2. object_key

不采用以下做法作为正式真相:

  1. 不存完整公开 URL
  2. 不存 bucket/object_key 拼接后的单字符串
  3. 不存依赖 bucket 权限假设的匿名可读 URL

3.2 为什么必须拆成两列

原因固定如下:

  1. bucket 后续可能按环境、业务线或冷热分层拆桶。
  2. object_key 本身才是对象路径主键;bucket 是对象所属仓。
  3. 后续签名下载 URL、服务端代理读取、对象迁移都需要分别拿到 bucketobject_key
  4. 若只存拼接字符串,后续查询、迁移、批量回填和索引都更差。

4. 推荐表字段

4.1 asset_object

后续 asset_object 至少应包含:

  1. id
  2. bucket
  3. object_key
  4. access_policy
  5. content_type
  6. content_length
  7. content_hash
  8. version
  9. source_job_id
  10. owner_user_id
  11. profile_id
  12. entity_id
  13. asset_kind
  14. created_at
  15. updated_at

当前已落到可编码级别的字段类型、索引和访问级别见:

  1. SPACETIMEDB_ASSET_OBJECT_TABLE_DESIGN_2026-04-21.md

4.2 业务资产表

如:

  1. character_visual_asset
  2. character_animation_asset
  3. scene_image_asset
  4. sprite_sheet_asset

这些表不直接重复存 URL而是引用

  1. asset_object_id
  2. 或明确的 bucket + object_key

优先建议:

  1. 强业务关系表引用 asset_object_id
  2. asset_object 再统一承载 bucket + object_key

5. API 输出口径

5.1 直传票据接口

POST /api/assets/direct-upload-tickets 的正式输出应以以下字段为核心:

  1. bucket
  2. objectKey
  3. legacyPublicPath
  4. access
  5. formFields
  6. expiresAt

补充说明:

  1. publicUrl 在私有 bucket 模式下不是正式读取真相。
  2. 若当前为了调试保留 publicUrl,也只能视为“候选直连 URL”不能代表对象一定可匿名读取。

5.2 私有读取链路

后续正式读取私有对象时,应采用以下方案之一:

  1. api-server 输出短期签名 URL
  2. api-server 做下载代理
  3. CDN 私有回源 + 服务端签名

当前仓库已实现第一种最小闭环:

  1. 服务端落库保存 bucket + object_key
  2. Web 端请求 GET /api/assets/read-url
  3. api-server 返回短期 signedUrl
  4. 浏览器再使用该 signedUrl 执行展示或下载

当前阶段不允许:

  1. 把长期 AccessKeyId / AccessKeySecret 下发给客户端
  2. 让浏览器直接持有长期主凭证读取私有对象

6. platform-oss 的实现约束

从当前版本开始,platform-oss 需要遵守以下约束:

  1. 默认按私有对象思维设计,不假设对象可匿名读取。
  2. PostObject 直传输出必须显式带 bucketobject_key
  3. publicUrl 若存在,只能作为派生信息,不能替代 bucket/object_key
  4. 后续新增签名下载能力时,输入必须是 bucket + object_key

7. SpacetimeDB 表设计约束

结合 SpacetimeDB 的 schema 演进约束,当前先冻结:

  1. 资产对象表必须尽早固定 bucketobject_key 两列。
  2. 不要先落单列字符串,后续再拆列,这会放大 schema 迁移成本。
  3. 对象 URL、签名 URL、CDN URL 都属于派生读模型,不是主存储字段。

8. 一句话结论

当前 assets / OSS 的正式真相应当是:

阿里云 OSS 用私有 bucket 持有二进制对象,SpacetimeDBbucket + object_key 两列持有对象引用,任何 URL 都只能是运行时派生结果。