Files
cmr-mini/t2b.md

837 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# T2B 协作清单
> 文档版本v1.10
> 最后更新2026-04-03 13:08:15
说明:
- 本文件由总控维护,写给后端线程
- 目标是把“后台生产闭环”第一阶段需要落地的东西讲清楚
- 只写当前阶段实施说明,不写长讨论稿
- 正式架构文档以 [后台生产闭环架构草案](D:/dev/cmr-mini/doc/backend/后台生产闭环架构草案.md) 为准
---
## 0. 当前阶段状态与下一步
backend 当前已完成:
- 生产骨架对象落库与 `/dev/workbench` 最小联调台
- `MapRuntimeBinding -> EventRelease -> launch.runtime` 主链接通
- `EventPresentation / ContentBundle / EventRelease` 第一阶段接通
- `Event` 默认 active 三元组固化:
- `currentPresentationId`
- `currentContentBundleId`
- `currentRuntimeBindingId`
- `publish` 默认继承当前 active 三元组
- `Bootstrap Demo``一键补齐 Runtime 并发布` 已可从空白状态跑完整测试链
- workbench 日志已补齐:
- 分步日志
- 真实错误
- stack
- 最后一次 curl
- 预期判定
当前主线不再是继续补对象,而是进入:
**联调标准化阶段**
本阶段 backend 的核心任务只有 3 件事:
1. 固化“一键测试”链路,确保从空白环境可重复跑通
2. 固化详细日志口径,失败时明确定位在哪一步
3. 固化稳定测试数据,并逐步支持更接近生产的真实输入
当前不建议 backend 继续发散去做:
- 更多新对象
- 更多 workbench 管理按钮
- 更复杂后台 UI
- 过早扩大奖励、社交、审核流
---
## 1. 本次目标
本次不是让 backend 一次性做完整后台,而是先搭出**最小生产骨架**,让下面这条链能真正闭环:
```text
地图输入
-> 瓦片版本
-> KML 导入
-> 赛道 variant
-> 活动绑定
-> release
-> launch
-> 客户端消费
```
当前重点是:
- 先把对象模型定下来
- 先让地图、KML、活动三条输入链有正式落点
- 先让客户端只认发布产物
补充确认:
- 本次接受 backend 采用**增量演进**方式推进
- 不要求一次性推翻当前已稳定联调的:
- `Event`
- `EventRelease`
- `Session`
主链
当前补充确认:
- 生产骨架第一阶段与活动运营域第二阶段第四刀已经完成
- backend 当前下一步应切到“联调标准化”,而不是继续新增对象层级
---
## 2. 本次范围
### 2.1 本次必须做
- 定义并落库以下核心对象:
- `Place`
- `MapAsset`
- `TileRelease`
- `CourseSet`
- `CourseVariant`
- `CourseSource`
- `Event`
- `EventPresentation`
- `ContentBundle`
- `MapRuntimeBinding`
- `EventRelease`
- 先让 KML 不再只是文件,而能转成 `CourseVariant`
- 先让活动不再只是页面概念,而能正式绑定:
- 展示定义
- 内容包
- 运行绑定
- 发布版本
- 第一阶段优先落以下对象:
- `Place`
- `MapAsset`
- `TileRelease`
- `CourseSource`
- `CourseSet`
- `CourseVariant`
- `MapRuntimeBinding`
- 第一阶段允许暂缓完整落库:
- `EventPresentation`
- `ContentBundle`
但对象语义必须先在架构上定清楚
### 2.2 本次先不做
- 奖励系统
- 社交系统
- 复杂审核流
- 完整后台 UI
- 大而全的素材编排器
- 高级权限体系
---
## 3. 后端对象最小理解
### 3.1 地图运行域
#### `Place`
- 地点
- 上层业务对象
- 一个地点下可有多张地图
#### `MapAsset`
- 某个地点下的一张地图资源
- 一张地图可有多个瓦片版本
#### `TileRelease`
- 某张地图的具体瓦片发布版本
#### `CourseSet`
- 一组赛道集合
- 例如:校园顺序赛、校园积分赛
#### `CourseVariant`
- 一个具体可运行赛道方案
- 顺序赛 8 点 / 12 点
- 积分赛 A / B / C 方案
- 客户端最终只应认这个对象
#### `CourseSource`
- 原始输入源
- KML 只是来源,不是最终业务对象
### 3.2 活动运营域
#### `Event`
- 活动业务对象
- 默认体验活动和定制活动都属于它
#### `EventPresentation`
- 活动卡片、详情页、H5 schema
#### `ContentBundle`
- 图片、音频、动画、文创、结果页资源等内容包
#### `MapRuntimeBinding`
- 活动运行时绑定哪张地图、哪条赛道、哪套瓦片、哪套配置
#### `EventRelease`
- 客户端真正消费的活动发布版本
---
## 4. 最小关系建议
建议 backend 先按这个关系理解:
- `Place 1 -> N MapAsset`
- `MapAsset 1 -> N TileRelease`
- `MapAsset 1 -> N CourseSet`
- `CourseSet 1 -> N CourseVariant`
- `CourseVariant N -> 1 CourseSource`
- `Event 1 -> N EventPresentation`
- `Event 1 -> N ContentBundle`
- `Event 1 -> N MapRuntimeBinding`
- `Event 1 -> N EventRelease`
其中:
- `MapRuntimeBinding` 负责引用:
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseSetId`
- `courseVariantId`
---
## 5. 后端第一阶段建议实施顺序
### 第一步:按增量方式落库最小对象
建议先把表和基础模型定下来。
第一阶段优先级建议:
1. `places`
2. `map_assets`
3. `tile_releases`
4. `course_sources`
5. `course_sets`
6. `course_variants`
7. `map_runtime_bindings`
第二阶段再补:
8. `event_presentations`
9. `content_bundles`
说明:
- 当前稳定的 `events / event_releases / sessions` 主链保留
- 本次是在现有骨架上增量补生产对象,不做一次性替换式重构
### 第二步:先打通 KML 导入链
目标:
- 上传 KML
- 保存 `CourseSource`
- 解析控制点与起终点
- 生成一个 `CourseVariant`
- 归入某个 `CourseSet`
### 第三步:先打通活动绑定链
目标:
- 一个 `Event` 可绑定:
- `EventPresentation`
- `ContentBundle`
- `MapRuntimeBinding`
### 第四步:先打通发布链
目标:
- 生成 `EventRelease`
- `launch` 先继续返回当前稳定字段:
- `resolvedRelease`
- `business`
- `variant`
- 第二阶段再补完整运行对象字段:
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseVariantId`
- `eventReleaseId`
### 第五步:把第一阶段生产骨架接口接入 `/dev/workbench`
目标:
- 不让第一阶段对象只停留在 API 目录里
- 在 workbench 里形成最小可操作联调面板
- 用于验证对象关系和生产闭环,不用于替代正式后台
本步建议只做:
#### A. 地点与地图
- `Place` 列表
- 新建 `Place`
-`Place` 下新建 `MapAsset`
-`MapAsset` 下新建 `TileRelease`
- 查看详情
#### B. 赛道与 KML
- `CourseSource` 列表
- 新建 `CourseSource`
- 新建 `CourseSet`
-`CourseSet` 下新建 `CourseVariant`
- 查看详情
#### C. 运行绑定
- `MapRuntimeBinding` 列表
- 新建 `MapRuntimeBinding`
- 选择:
- `place`
- `map`
- `tile release`
- `course variant`
- 查看详情
本步明确不做:
- 完整后台 UI
- Event 全量编辑
- `EventPresentation` 可视化搭建
- `ContentBundle` 大资源管理台
- Build / Release 全流程可视化
- 删除、批量操作、审核流
一句话:
**workbench 当前只做“第一阶段生产骨架联调台”,不做“正式后台管理系统”。**
### 第六步:进入“最小接线”阶段
目标:
-`MapRuntimeBinding` 和当前 `EventRelease` 接起来
- 让运行对象开始逐步进入 `launch`
- 保持当前前端稳定链不被打断
本步建议优先做:
#### A. `EventRelease` 接 `MapRuntimeBinding`
-`EventRelease` 上补 `runtimeBindingId`
- 查询 `EventRelease` 时可带出最小 `runtime binding` 摘要
#### B. `launch` 新增 `runtime` 摘要块
- 保留当前稳定字段:
- `resolvedRelease`
- `business`
- `variant`
- 新增一个兼容性的 `runtime` 块,建议最少返回:
- `runtimeBindingId`
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseSetId`
- `courseVariantId`
- 如字段成本不高,可附带:
- `placeName`
- `mapName`
- `routeCode`
#### C. `workbench` 最小接线验证
-`/dev/workbench` 上增加:
- `EventRelease` 选择或查看
- 绑定 `runtimeBinding`
- 查看 release 当前已接入的运行对象摘要
本步明确要求:
- 不修改旧字段语义
- 不移除旧字段
- 不让前端现有 `launch` 链断掉
- 先做到“后端可挂接、可透出、可验证”
---
## 6. 当前接口落地方向
当前阶段建议 backend 后续接口逐步收敛到:
### 6.1 生产侧接口
- 创建地点
- 创建地图
- 创建瓦片版本记录
- 上传 KML
- 生成赛道 variant
- 创建活动
- 保存活动展示定义
- 保存内容包引用
- 保存运行绑定
- 创建活动 release
### 6.2 客户端消费接口
- 活动列表
- 活动详情
- `launch`
- session start
- session finish
- result
- history
关键要求:
- 客户端只消费 release 产物
- 不再消费原始 KML
- 不再消费地图原始资产
- `launch` 采用两阶段兼容,不要求第一阶段打断当前前端稳定链
### 6.3 workbench 联调台
backend 下一步建议把以下接口先接到 `/dev/workbench`
- `Place`
- `MapAsset`
- `TileRelease`
- `CourseSource`
- `CourseSet`
- `CourseVariant`
- `MapRuntimeBinding`
接入目标:
- list
- create
- detail
- binding
不建议当前阶段接入:
- edit
- delete
- batch
- 审核流
### 6.4 最小接线阶段接口方向
backend 下一步建议新增或补齐以下能力:
- `EventRelease` 挂接 `runtimeBindingId`
- 查询 `EventRelease` 时返回最小运行绑定摘要
- `launch` 返回新增 `runtime` 摘要块
当前目标不是让前端强依赖新字段,而是先让:
- release 和 runtime binding 接上
- `launch` 能把运行对象透出来
- 前后端可以开始验证运行对象链是活的
### 6.5 第四刀:发布闭环阶段
在第三刀已经完成:
- `MapRuntimeBinding -> EventRelease`
- `launch.runtime` 兼容透出
之后,下一步建议进入真正的**发布闭环阶段**。
目标:
- 不再要求“先 publish再手工 bind runtime”
- 改为 publish 时就能直接产出带 `runtimeBindingId` 的完整 `EventRelease`
- 保持当前旧接口和旧字段完全兼容
本步建议优先做:
#### A. publish/build 接口支持 `runtimeBindingId`
- 在当前发布链中允许显式传入 `runtimeBindingId`
- 如果传入,则发布完成后直接把 release 绑好 runtime
- 如果不传入,则继续保持当前兼容行为
#### B. workbench publish 面板接入 runtime 选择
-`/dev/workbench` 的发布操作区增加 `Runtime Binding` 选择
- 支持一条完整联调链:
- 选 release source / build
-`runtimeBindingId`
- publish
- 直接 launch 验证
#### C. release 查询继续返回 runtime 摘要
- `Get Release`
- `launch`
都继续透出当前最小 `runtime` 摘要,供前端和总控验证。
本步关键要求:
- 只加能力,不改旧语义
- 新流程优先,但旧流程继续可用
- 发布结果尽量原子,避免漏掉 runtime 挂接
---
## 7. 当前需要 backend 重点注意的边界
1. KML 只是输入源,不是最终业务对象
2. 活动不是素材仓库,活动只引用 `ContentBundle`
3. 地图上层必须有 `Place`,不要让 `MapAsset` 直接当最上层
4. 客户端最终必须只认 `EventRelease`
5. launch 返回必须落到具体:
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseVariantId`
- `eventReleaseId`
---
## 8. 当前待 backend 回写确认
请 backend 线程后续重点回写以下确认:
1. 第一阶段表结构是否接受这套对象拆分
2. `Place / MapAsset / TileRelease / CourseSource / CourseSet / CourseVariant / MapRuntimeBinding` 是否按当前顺序推进
3. KML 导入链是否准备按 `CourseSource -> CourseVariant`
4. 活动是否接受拆成:
- `Event`
- `EventPresentation`
- `ContentBundle`
- `MapRuntimeBinding`
- `EventRelease`
5. `launch` 两阶段兼容方案是否按当前确认推进
6. workbench 是否按“第一阶段生产骨架联调台”接入,且只做 list / create / detail / binding
本轮新增执行项:
7. 是否按“第三刀最小接线”推进:
- `MapRuntimeBinding -> EventRelease`
- `launch.runtime` 摘要透出
- 继续保持旧字段兼容
8. 是否按“第四刀发布闭环”推进:
- publish 直接支持 `runtimeBindingId`
- workbench publish 面板增加 runtime 选择
- 继续保留“先 publish再 bind runtime”的兼容路径
9. 是否进入“活动运营域第二阶段”:
- `EventPresentation` 最小落库
- `ContentBundle` 最小落库
- `EventRelease` 明确绑定 `presentation / bundle / runtime`
10. 是否进入“活动运营域第二阶段第二刀”:
- `event detail` 透出最小 `presentation / bundle` 摘要
- `release detail` 透出最小 `presentation / bundle / runtime` 摘要
- `launch` 增加兼容性的 `presentation / contentBundle` 摘要块
- publish 在未显式传入时允许按 event 当前默认配置自动补齐 `presentation / bundle`
---
## 9. 一句话结论
本次给 backend 的实施要求很简单:
**先别继续围绕散装页面和散装配置推进,先把地图运行域和活动运营域的最小骨架搭起来。**
当前下一步重点已经进一步明确为:
**活动运营域第二阶段第三刀第一版已完成backend 下一步切到“展示定义统一导入与默认绑定”阶段。**
### 6.6 第五刀:前端正式接线阶段
当前 backend 已完成第四刀第一版:
- publish 直接支持 `runtimeBindingId`
- workbench publish 区支持直接填写 `Runtime Binding ID`
- 发布成功返回 `runtime`
- 旧的“先 publish再 bind runtime”路径继续兼容
因此下一步建议正式进入**前端接线阶段**。
目标:
- 前端开始正式消费 `launch.runtime`
- 活动准备页、地图页、结果页、历史页开始逐步展示运行对象摘要
- 继续保持旧字段兼容,不要求一轮切掉老逻辑
前端第一阶段建议优先做:
#### A. `launch.runtime` 消费
- 读取并缓存:
- `runtimeBindingId`
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseSetId`
- `courseVariantId`
- 如后端已返回名称摘要,也同步接入:
- `placeName`
- `mapName`
- `routeCode`
#### B. 准备页与地图页最小展示
- 在准备页展示当前地点 / 地图 / 赛道摘要
- 在地图页调试或摘要区透出当前 runtime 对象
#### C. 结果与历史摘要逐步接入
- 先不强改所有列表
- 优先让单局结果页和历史详情页能看见:
- `place`
- `map`
- `variant`
- `routeCode`
当前阶段原则:
- 前端正式上场,但只接新增摘要,不推翻现有稳定页面主链
- `resolvedRelease / business / variant` 旧字段仍继续保留和可用
- 如果后端某些名称摘要尚未补齐,前端先按 ID + 已有字段兜底
### 6.7 第六刀之后的下一步:活动运营域第二阶段第二刀
当前 backend 已完成:
- `0009_event_ops_phase2.sql`
- `EventPresentation` 最小落库
- `ContentBundle` 最小落库
- `EventRelease` 已可绑定:
- `presentationId`
- `bundleId`
- `runtimeBindingId`
- publish 已支持显式挂接:
- `presentationId`
- `contentBundleId`
- `runtimeBindingId`
因此下一步建议进入“活动运营域第二阶段第二刀”。目标是:
-`EventPresentation / ContentBundle` 不只存在于后台和 publish 输入里
- 而是正式进入可查询、可验证、可消费的发布摘要
建议顺序:
#### A. `event detail` 透出当前展示与内容包摘要
建议最少返回:
- `currentPresentation`
- `presentationId`
- `templateKey`
- `version`
- `currentContentBundle`
- `bundleId`
- `bundleType`
- `version`
#### B. `Get Release` 透出完整最小摘要
建议 `release detail` 同时包含:
- `presentation`
- `contentBundle`
- `runtime`
前两者先以摘要形式返回,不先做复杂 schema 下发。
#### C. `launch` 增加兼容性的活动运营摘要块
在保持旧字段与当前 `runtime` 不变的前提下,新增:
- `presentation`
- `contentBundle`
建议最少包括:
- `presentationId`
- `templateKey`
- `bundleId`
- `bundleType`
#### D. publish 增加默认补齐逻辑
如果 publish 未显式传入:
- `presentationId`
- `contentBundleId`
允许按 event 当前默认配置自动补齐。
本步明确不建议做:
- 前端立即全面消费 presentation / bundle
- 复杂活动页面 schema 下发
- 内容包全量资源编排
- 正式后台大 UI
### 6.8 活动运营域第二阶段第三刀:发布摘要闭环与内容包导入入口
当前已确认:
- frontend 已完成“活动运营域摘要第一刀”
- 当前前端进入联调回归与小范围修复阶段
- backend 下一步不应继续围绕前端页面做字段补丁,而应继续把活动运营域本身做完整
本刀建议拆成两步,但按一个阶段推进。
#### A. 先把 release 摘要闭环
目标:
-`EventRelease` 真正成为活动运营域统一发布产物
- 保证以下几处返回的摘要语义一致:
- `event detail`
- `event play`
- `launch`
- `release detail`
建议 `release detail` 最少透出:
- `presentation`
- `presentationId`
- `templateKey`
- `version`
- `contentBundle`
- `bundleId`
- `bundleType`
- `version`
- `runtime`
- `runtimeBindingId`
- `placeId`
- `mapId`
- `tileReleaseId`
- `courseVariantId`
同时建议 `/dev/workbench` 的 release 查看区,能直接验证这三类摘要。
#### B. 再打开 `ContentBundle` 统一导入入口
目标:
- 不再只手工创建 `ContentBundle`
- 让后续静态资源、音频、动画、文创等内容,先通过统一导入入口进入 bundle
当前阶段建议只做“入口”和“元信息”,不做完整资源平台。
建议最小能力:
- 新增 `ContentBundle Import` 最小接口
- 接收:
- `bundleType`
- `sourceType`
- `manifestUrl` 或等价资源清单入口
- `version`
- `title`
- 创建后生成:
- `bundleId`
- `bundleType`
- `version`
- `assetManifest`
- `status`
当前明确不做:
- 复杂资源上传工作流
- 大文件管理台
- 资源审核流
- 全量 H5 schema 组装
关键原则:
- `ContentBundle` 先做统一导入入口,不先做复杂资源管理系统
- frontend 当前不消费资源明细,只继续认摘要
- 先把“发布对象完整”和“内容资源有正式入口”两件事做起来
### 6.9 活动运营域第二阶段第四刀:展示定义统一导入与默认绑定
当前已确认:
- backend 已完成:
- `event detail / play / launch / release detail` 活动运营摘要闭环
- `ContentBundle` 统一导入入口第一版
- frontend 当前不再扩新页面链,继续联调回归
所以下一步 backend 不建议继续围绕玩家侧摘要补字段,而应继续把活动运营域生产链做完整。
#### A. 打开 `EventPresentation` 统一导入入口
目标:
- 后续外部活动卡片/H5 搭建系统,不再只靠手工创建 presentation
- 而是通过统一入口把展示定义正式导入 backend
建议最小能力:
- 新增 `EventPresentation Import` 最小接口
- 接收:
- `templateKey`
- `sourceType`
- `schemaUrl` 或等价 schema 入口
- `version`
- `title`
- 创建后生成:
- `presentationId`
- `templateKey`
- `version`
- `schema`
- `status`
#### B. 固化 `Event` 当前默认 active 绑定
目标:
-`Event` 当前默认使用的:
- `presentation`
- `contentBundle`
- `runtimeBinding`
三者关系稳定下来
建议至少明确:
- `currentPresentationId`
- `currentContentBundleId`
- `currentRuntimeBindingId`
以及 publish 在未显式传入时,默认如何继承这三者。
#### C. `/dev/workbench` 增加最小验证
建议补:
- `Import Presentation`
- 查看 event 当前 active
- presentation
- bundle
- runtime
- 在 publish 区验证默认继承是否正确
当前明确不做:
- 复杂展示编辑器
- 全量 H5 schema 编排平台
- 大型资源后台
关键原则:
- `EventPresentation``ContentBundle` 都要有统一导入入口
- `Event` 继续做业务壳和默认绑定,不吞大资源
- 玩家前端继续只认发布摘要,不认后台草稿对象