18 KiB
开发说明
文档版本:v1.25 最后更新:2026-04-03 18:56:46
1. 环境变量
参考 .env.example。
当前最关键的变量:
APP_ENVHTTP_ADDRDATABASE_URLJWT_ACCESS_SECRETAUTH_SMS_PROVIDERAUTH_DEV_SMS_CODEWECHAT_MINI_APP_IDWECHAT_MINI_APP_SECRETWECHAT_MINI_DEV_PREFIXLOCAL_EVENT_DIRASSET_BASE_URLASSET_PUBLIC_BASE_URLASSET_BUCKET_ROOTOSSUTIL_PATHOSSUTIL_CONFIG_FILE
2. 本地启动
cd D:\dev\cmr-mini\backend
.\start-backend.ps1
如果你想固定跑开发工作台常用端口 18090,直接执行:
cd D:\dev\cmr-mini\backend
.\scripts\start-dev.ps1
3. Workbench 当前重点
- 推荐联调入口:
Bootstrap DemoUse Classic Demo / Use Score-O Demo / Use Manual Variant Demo整条链一键验收
- 当前玩法切换除了切
event / release / source / build,还会自动切换:presentation schemacontent manifestasset manifest
- 这些 demo 资源现在由 backend 提供,避免继续在 workbench 里保留
example.com占位地址:GET /dev/demo-assets/presentations/{demoKey}GET /dev/demo-assets/content-manifests/{demoKey}
- 如果 frontend 需要把页面侧调试日志直接打到 backend,优先使用:
POST /dev/client-logs- 然后在 workbench 的
前端调试日志面板里查看
- 如果需要判断前端到底拿到了哪份配置,优先看 workbench 的:
当前 Launch 实际配置摘要
- 这块会直接显示:
configUrlreleaseIdmanifestUrlschemaVersionplayfield.kindgame.mode
- 这组信息用于和前端地图页实际消费结果对口排查,避免只靠口头描述“像顺序赛/像积分赛”。
- 注意:
- 这块摘要由 backend 代读 manifest,只用于 workbench 调试
- 这样做是为了避免浏览器直接读取 OSS 时受跨域影响
- 它不替代正式客户端加载逻辑
- 正式客户端仍必须直接消费
launch.config.configUrl或launch.resolvedRelease.manifestUrl
前端调试日志也是调试专用能力:- backend 当前只在内存里保留最近 200 条
- 适合前端把关键事实直接打进来,避免只靠截图和口头描述
- 不替代正式生产日志体系
Bootstrap Demo准备出的联调文案也已换成中文样例:领秀城公园顺序赛领秀城公园积分赛领秀城公园多赛道挑战
4. 活动卡片列表最小摘要
当前 backend 已为以下入口统一补齐活动卡片最小摘要字段:
/cards/home/me/entry-home
当前字段集:
titlesubtitlesummarystatusstatusCodetimeWindowctaTextcoverUrlisDefaultExperienceeventTypecurrentPresentationcurrentContentBundle
当前派生规则:
summary- 无值时回退为:
当前暂无活动摘要
- 无值时回退为:
statusrunning->进行中upcoming->即将开始ended->已结束- 其余 ->
状态待确认
timeWindow- 由
cards.starts_at / ends_at派生 - 缺失时回退为:
时间待公布
- 由
ctaText- 默认体验活动:
进入体验 - 进行中:
进入活动 - 已结束:
查看回顾 - 其余:
查看详情
- 默认体验活动:
currentPresentation / currentContentBundle- 当前继续表示已发布 release 实际绑定摘要
- 不是 event 草稿默认值
默认会设置:
APP_ENV=developmentHTTP_ADDR=:18090DATABASE_URL=postgres://postgres:asdf*123@192.168.100.77:5432/cmr20260401?sslmode=disableAUTH_SMS_PROVIDER=consoleWECHAT_MINI_DEV_PREFIX=dev-
启动后可直接打开:
当前 workbench 已覆盖两类调试链:
- 用户主链:
bootstrap -> auth -> entry/home -> event play/launch -> session -> result - 后台运营链:
maps/playfields/resource-packs -> admin event source -> build -> publish -> rollback - 第一阶段生产骨架联调台:
places -> map-assets -> tile-releases -> course-sources -> course-sets -> course-variants -> runtime-bindings - 第三刀最小接线验证:
runtimeBinding -> release -> launch.runtime - 第四刀发布闭环验证:
runtimeBinding -> publish(runtimeBindingId) -> release -> launch.runtime - 活动运营域第二阶段验证:
presentation -> content bundle -> publish(presentationId, contentBundleId, runtimeBindingId) -> release - 活动运营域第二阶段第二刀验证:
event detail / play / launch -> presentation + content bundle 摘要 - 活动运营域第二阶段第三刀验证:
release 摘要闭环 + content bundle import - 活动运营域第二阶段第四刀验证:
presentation import -> event 默认 active 绑定 -> publish 空参继承 - workbench 一键验证增强:
一键默认绑定发布与一键补齐 Runtime 并发布 /dev/bootstrap-demo现在也会回填最小生产骨架:place / map asset / tile release / course source / course set / course variant / runtime binding
2.1 当前推荐验证方式
如果目标是验证“从测试数据准备到 release 继承是否完整”,优先使用 workbench 的一键流,而不是手工逐个点按钮。
当前推荐顺序:
Bootstrap Demo(只准备数据)- 选择一种玩法入口:
Use Classic DemoUse Score-O DemoUse Manual Variant Demo
- 如果只是想看发布过程,点
Bootstrap + 发布当前玩法 - 如果想只测发布链,点
一键补齐 Runtime 并发布 - 如果想直接验整条链,点
一键标准回归
当前这几个按钮的职责已经拆开:
Bootstrap Demo(只准备数据)- 只负责准备 demo event / source / build / release / runtime 等测试数据
- 不会基于当前玩法再额外重新发布一版
Bootstrap + 发布当前玩法- 会先执行一遍
Bootstrap Demo - 然后对当前选中的玩法执行“发布活动配置(自动补 Runtime)”
- 会先执行一遍
一键补齐 Runtime 并发布- 不再隐式 bootstrap
- 只基于当前已选玩法和当前表单上下文执行发布链
当前这条一键链会自动完成:
- demo event / source / build / release 准备
- presentation 导入
- content bundle 导入
- event 默认 active 绑定保存
- 最小生产骨架准备:
placemap assettile releasecourse sourcecourse setcourse variantruntime binding
- publish
- release 回读校验
play / launch / result / history回归汇总- demo 活动残留 ongoing session 清理:
- 会把 demo event 下历史遗留的
launched / runningsession 自动改成cancelled
- 会把 demo event 下历史遗留的
- 真实输入替换第一刀:
CourseSource.fileUrl当前已切到真实 KML:https://oss-mbh5.colormaprun.com/gotomars/kml/lxcb-001/10/c01.kmlhttps://oss-mbh5.colormaprun.com/gotomars/kml/lxcb-001/10/c02.kml
TileRelease.tileBaseUrl / metaUrl当前已切到真实地图资源:https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/meta.json
- manual 多赛道 demo 当前已使用两条真实赛道输入:
variant_a -> c01.kmlvariant_b -> c02.kml
- 显式玩法测试入口:
- 顺序赛:
evt_demo_001 -> rel_demo_001 -> classic-sequential.json - 积分赛:
evt_demo_score_o_001 -> rel_demo_score_o_001 -> score-o.json - 多赛道:
evt_demo_variant_manual_001 -> rel_demo_variant_manual_001
- 顺序赛:
当前日志能力:
- 每一步都会写到“响应日志”
- 失败时会直接输出:
- 错误消息
- stack
- 最后一次 curl
- 成功时“预期结果”面板会直接给出:
Release IDPresentationContent BundleRuntime Binding判定
- 成功跑完标准回归后,“回归结果汇总”会直接给出:
发布链PlayLaunchResultHistorySession ID总判定
- workbench 现在还支持查看 frontend 主动上报的调试日志:
拉取前端日志清空前端日志- 前端建议最少带:
eventIdreleaseIdsessionIdmanifestUrlroutegame.modeplayfield.kind- 当前页面阶段或动作名
2.2 前端调试日志最小约定
dev 环境下,frontend 可直接把关键调试事实发到 backend:
POST /dev/client-logs
建议请求体最少包含:
{
"source": "miniprogram",
"level": "info",
"category": "runtime",
"message": "map page loaded manifest",
"eventId": "evt_demo_score_o_001",
"releaseId": "rel_xxx",
"sessionId": "sess_xxx",
"manifestUrl": "https://oss-mbh5.colormaprun.com/...",
"route": "pages/map/map",
"occurredAt": "2026-04-03T16:16:38+08:00",
"details": {
"schemaVersion": "1",
"playfield.kind": "control-set",
"game.mode": "score-o",
"phase": "map-init"
}
}
当前说明:
source:建议填终端来源,例如miniprogramlevel:建议填info / warn / errorcategory:建议填launch / runtime / cache / networkmessage:一句话说明当前发生了什么details:放结构化调试细节,backend 原样收下
辅助接口:
GET /dev/client-logs?limit=50DELETE /dev/client-logs
3. 当前开发约定
3.0 玩家进入规则
当前要明确一条玩家链路规则:
- 玩家进入游戏,必须基于“已发布 release”
- 不能基于:
- event 草稿默认绑定
- 未发布 presentation
- 未发布 content bundle
- 未发布 runtime
当前接口中的:
currentPresentationcurrentContentBundle
在玩家链路里表示的是:
- 当前已发布 release 上实际绑定的展示版本摘要
- 当前已发布 release 上实际绑定的内容包摘要
不是:
- event 草稿默认值摘要
所以如果当前 release 还没绑定这些对象,玩家页看到空值是正常行为。前端页面应优先:
- 用
play.canLaunch判定是否允许进入 - 把空值解释成“当前未发布或当前发布未绑定”
当前 canLaunch 已按正式进入规则收紧:
- 只有当当前 event 满足以下条件时,
play.canLaunch = true- event
status = active - 已存在当前发布 release
- 当前发布 release 有
manifest - 当前发布 release 已绑定
runtime - 当前发布 release 已绑定
presentation - 当前发布 release 已绑定
content bundle
- event
当前 POST /events/{eventPublicID}/launch 也已与 canLaunch 保持同一套前置条件。
3.1 开发阶段先不用 Redis
当前第一版全部依赖:
- PostgreSQL
- JWT
- refresh token 持久化
Redis 后面只在需要性能优化、限流或短期票据缓存时再接。
3.2 开发环境短信
当前默认可走 console provider。
用途:
- 本地联调无需接真实短信供应商
3.3 微信小程序开发态
当前支持 dev- 前缀 code。
适合:
- 后端联调
- workbench 快速验证
3.4 本地配置目录
当前支持从根目录 event 导入本地配置文件。
相关环境变量:
LOCAL_EVENT_DIRASSET_BASE_URL
作用:
LOCAL_EVENT_DIR决定本地 source config 从哪里读ASSET_BASE_URL决定 preview build 时如何把相对资源路径归一化成可运行 URLASSET_PUBLIC_BASE_URL决定 publish 时如何把公开 URL 映射到 OSS 对象 keyASSET_BUCKET_ROOT决定发布对象上传到哪个 bucket 根路径OSSUTIL_PATH和OSSUTIL_CONFIG_FILE决定 backend 发布 manifest 时使用哪个 OSS 客户端
4. Migration
当前 migration 文件在 migrations。
执行原则:
- 按编号顺序执行
- schema 变更只通过新增 migration 完成
- 不直接改线上已执行 migration
5. 开发工作台
POST /dev/bootstrap-demo
它会保证 demo 数据存在:
tenant_demomini-demoevt_demo_001rel_demo_001card_demo_001
GET /dev/workbench
这是当前最重要的联调工具。
可以直接测试:
- 登录
- 入口解析
- 首页聚合
- event play
- 第一阶段生产骨架对象
- 配置导入、preview build、publish build
- launch
- session start / finish
- result
- profile
补充说明:
publish build现在会真实上传manifest.json和asset-index.json到 OSS- 如果上传失败,接口会直接报错,不再出现“数据库里已有 release,但 OSS 上没有对象”的假成功
Save Event Defaults会把当前 event 的默认 active 绑定写入:currentPresentationIdcurrentContentBundleIdcurrentRuntimeBindingId
- 之后
Publish Build如果不显式填写这三项,会优先继承 event 默认 active 绑定
并且支持:
- quick flow
- scenario 保存/导入/导出
- curl 导出
- request history
当前第一阶段生产骨架联调台只做:
listcreatedetailbinding
明确不做:
- 正式后台 UI
editdeletebatch- 审核流
活动运营域第二阶段当前也只做最小动作:
listcreatedetailpublish 绑定import
6. 当前推荐联调顺序
场景一:小程序快速进入
bootstrap-demologin/wechat-minime/entry-homeevents/{id}/playevents/{id}/launchsessions/{id}/startsessions/{id}/finishsessions/{id}/result
场景二:APP 主身份
auth/sms/sendauth/login/smsme/entry-homelaunchsessionresult
场景三:微信轻账号绑定手机号
login/wechat-miniauth/sms/sendwithscene=bind_mobileauth/bind/mobileme/profile
场景四:配置发布到可启动 release
bootstrap-demodev/events/{eventPublicID}/config-sources/import-localdev/config-builds/previewdev/config-builds/publishevents/{id}events/{id}/launch
场景五:第一阶段生产骨架最小闭环
在 /dev/workbench 的 后台运营 模式中,按下面顺序操作:
List Places或Create Place- 在该
Place下Create Map Asset - 在该
MapAsset下Create Tile Release Create Course Source- 在该
MapAsset下Create Course Set - 在该
CourseSet下Create Variant Create Runtime Binding
成功后应能拿到这些 ID:
placeIdmapAssetIdtileReleaseIdcourseSourceIdcourseSetIdcourseVariantIdruntimeBindingId
建议第一次联调时用这组最小规则:
Place先建 1 个- 每个
Place先只建 1 个MapAsset - 每个
MapAsset先只建 1 个TileRelease - 每个
CourseSet先只建 1 个默认CourseVariant RuntimeBinding先只绑定当前正在验证的Event
这条链当前只验证对象关系闭环,不验证:
- 发布链切换
launch返回运行对象字段EventPresentationContentBundle
场景六:第三刀最小接线验证
在 /dev/workbench 的 后台运营 模式中,先完成“场景五”,再按下面顺序操作:
Get Pipeline- 确认当前
Release ID - 填或复用
Runtime Binding ID Bind RuntimeGet Release- 切回
前台联调 - 对同一个
event执行Launch
场景七:活动运营域第二阶段最小闭环
在 /dev/workbench 的 后台运营 模式中,按下面顺序操作:
Get EventCreate PresentationCreate BundleAssemble SourceBuild Source- 在发布区填:
Runtime Binding IDPresentation IDContent Bundle ID
Publish BuildGet Release
成功后应能在 release 返回中看到:
runtimepresentationcontentBundle
并且这 3 类绑定当前都已固化到 event_release。
成功后应能看到:
GET /admin/releases/{releasePublicID}返回runtimePOST /events/{eventPublicID}/launch返回launch.runtime
当前阶段的约束是:
- 只新增
runtime字段块 - 不改旧的:
resolvedReleasebusinessvariant
- release 如果没挂
runtimeBindingId,则launch.runtime为空
场景八:活动运营域第二阶段第三刀验证
在 /dev/workbench 的 后台运营 模式中,先完成“场景七”,再按下面顺序操作:
Create Presentation或直接复用现有Presentation IDImport BundleGet BundleGet PipelinePublish BuildGet Release- 切回
前台联调 Event DetailEvent PlayLaunch
成功后应能同时看到这三组摘要:
release.presentation.templateKey / versionrelease.contentBundle.bundleType / versionrelease.runtime.placeId / mapId / tileReleaseId / courseVariantId
同时客户端消费侧应保持一致:
GET /events/{eventPublicID}GET /events/{eventPublicID}/playPOST /events/{eventPublicID}/launch
当前 Content Bundle Import 只做统一导入入口,不做复杂资源平台:
- 输入:
titlebundleTypesourceTypemanifestUrlversionassetManifest
- 输出:
bundleIdbundleTypeversionassetManifeststatus
场景七:第四刀发布闭环验证
在 /dev/workbench 的 后台运营 模式中,先完成“场景五”,再按下面顺序操作:
Create Runtime BindingGet Pipeline- 确认
Build ID - 在发布区填
Runtime Binding ID Publish BuildGet Release- 切回
前台联调 - 对同一个
event执行Launch
成功后应能看到:
POST /admin/builds/{buildID}/publish返回带runtimeGET /admin/releases/{releasePublicID}返回同一条runtimePOST /events/{eventPublicID}/launch返回同一条launch.runtime
当前第四刀的兼容要求是:
- 旧的“先
publish,再bind runtime”路径继续可用 - 新的“
publish时直接传runtimeBindingId”优先推荐 - 不修改旧的:
resolvedReleasebusinessvariant
7. 当前后续开发建议
文档整理完之后,后面建议按这个顺序继续:
- 抽出更通用的
play context -> launch模型 - 补赛事与报名层
- 补页面配置和白标首页
- 再考虑实时网关票据
不要跳回去把玩法规则塞进 backend。