重写
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
# `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_key`:bucket 内对象路径
|
||||
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_visual`、`scene_image`。 |
|
||||
| `created_at` | `Timestamp` | 是 | 创建时间。 |
|
||||
| `updated_at` | `Timestamp` | 是 | 最近更新时间。 |
|
||||
|
||||
补充约束:
|
||||
|
||||
1. `bucket` 与 `object_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-assets` 与 `spacetime-module` 已落真实 crate scaffold
|
||||
|
||||
## 10. 相关文档
|
||||
|
||||
1. [SPACETIMEDB_ASSET_OBJECT_STORAGE_DESIGN_2026-04-21.md](./SPACETIMEDB_ASSET_OBJECT_STORAGE_DESIGN_2026-04-21.md)
|
||||
2. [SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md](./SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md)
|
||||
3. [../../../server-rs/crates/module-assets/README.md](../../../server-rs/crates/module-assets/README.md)
|
||||
4. [../../../server-rs/crates/spacetime-module/README.md](../../../server-rs/crates/spacetime-module/README.md)
|
||||
Reference in New Issue
Block a user