# 配置驱动应用的后台管理方案建议 本文用于整理当前这类“配置驱动型地图游戏应用”的后台管理建议,面向: - PostgreSQL 数据库 - Go 中间层 - 后台管理系统 - 客户端静态配置发布 目标是解决一个核心问题: **配置文件会越来越大,如何在后台可维护、可复用、可审核、可发布、可回滚。** --- ## 1. 总体原则 最稳的方案不是“数据库直接存一大份 `game.json` 给客户端读”,而是: **数据库管理编辑态,发布时编译成运行态静态配置文件。** 也就是两套形态: ### 编辑态 - 存在 PostgreSQL - 适合后台表单编辑 - 支持版本管理 - 支持对象复用 - 支持审核、比对、回滚 ### 运行态 - 由 Go 中间层装配生成 - 输出为静态 JSON - 上传到 OSS/CDN - 客户端只读取发布后的静态配置 这条路线最适合当前项目。 --- ## 2. 不建议的做法 不建议把后台做成: - 一张表里存一个超大的 `jsonb` - 后台直接编辑整份 `game.json` - 客户端通过 API 动态拼装所有配置 这样后面会遇到这些问题: - 配置复用困难 - diff 难看 - 回滚困难 - 审核困难 - 局部编辑体验差 - 客户端运行态不稳定 --- ## 3. 推荐的核心对象 建议后台和数据库先固定这 5 个核心对象: ### `Map` 地图底座。 负责: - 瓦片资源 - meta 信息 - 磁偏角 - 初始视角 ### `Playfield` 玩法空间对象定义。 负责: - KML 来源 - 控制点覆盖信息 - 区域对象 - 危险区 - 采集物 - 起终点信息 说明: - `Playfield` 是上位概念 - `course` 只是其中一种特化形式 ### `GameMode` 玩法模板。 负责: - 顺序赛 - 积分赛 - 后续幽灵赛、迷雾赛、金币赛等 也就是: - `game.mode` - `session` - `punch` - `scoring` - `guidance` - `visibility` - `finish` - `telemetry` - `feedback` ### `ResourcePack` 资源包。 负责: - 音效 profile - 文创内容 - 图标 - HUD 主题 - 动效 profile ### `Event` 最终活动实例。 负责引用: - 一个 `Map` - 一个 `Playfield` - 一个 `GameMode` - 一个 `ResourcePack` 并允许少量活动级覆盖。 一句话: **Event = Map + Playfield + GameMode + ResourcePack + EventOverrides** --- ## 4. 数据库建模建议 建议每个核心对象都分成: - 主表 - version 表 ### 4.1 主表 主表存稳定元信息: - `id` - `slug` - `name` - `status` - `current_version_id` - `created_at` - `updated_at` ### 4.2 version 表 version 表存每个版本的具体内容: - `id` - `parent_id` - `version_no` - `schema_version` - `content_jsonb` - `created_by` - `created_at` - `change_note` ### 4.3 推荐表 建议至少有: - `maps` - `map_versions` - `playfields` - `playfield_versions` - `game_modes` - `game_mode_versions` - `resource_packs` - `resource_pack_versions` - `events` - `event_versions` --- ## 5. 为什么要做版本表 版本表的价值非常大: - 支持草稿 - 支持发布版 - 支持 diff - 支持回滚 - 支持审计 - 支持多人协作 如果没有版本表,后面后台管理一定会越来越难维护。 --- ## 6. JSONB 的使用建议 推荐策略是: - 稳定字段结构化 - 变化快的配置内容放 `jsonb` 例如主表中: - `slug` - `name` - `status` 放结构化列。 而玩法具体配置、资源清单、覆盖字段,放在 `content_jsonb`。 这样兼顾: - 查询效率 - 结构灵活性 - 配置扩展性 --- ## 7. 后台编辑方式建议 后台不要直接给运营一个大 JSON 编辑框作为主要方式。 推荐做法: - 地图编辑页 - Playfield 编辑页 - 玩法规则页 - 资源包页 - 活动编排页 按模块表单化编辑。 最后由 Go 中间层负责装配成最终配置 JSON。 也就是: **后台是“编辑结构化对象”,不是“手工拼最终运行文件”。** --- ## 8. 发布机制建议 发布时建议按下面流程: 1. 后台选定某个 `Event Version` 2. Go 中间层读取它引用的: - `Map Version` - `Playfield Version` - `GameMode Version` - `ResourcePack Version` 3. 做装配 4. 做校验 5. 生成最终运行态 JSON 6. 上传 OSS/CDN 7. 记录一条 release 客户端只读: - 已发布的静态配置 URL 不要让客户端直接查数据库 API 动态拼。 --- ## 9. 推荐增加 Release 层 建议增加: - `event_releases` 字段例如: - `id` - `event_id` - `event_version_id` - `release_no` - `manifest_url` - `published_by` - `published_at` - `status` 它的作用: - 一键回滚 - 客户端锁定某次 release - 管理历史发布记录 - 灰度验证 --- ## 10. Go 中间层建议职责 Go 中间层不要只做 CRUD。 建议它至少承担这 4 类职责: ### 10.1 校验 - schema 校验 - 引用存在校验 - 字段完整性校验 - 规则约束校验 ### 10.2 装配 把: - `Map` - `Playfield` - `GameMode` - `ResourcePack` - `Event Overrides` 装配成最终配置结构。 ### 10.3 发布 - 生成最终静态 JSON - 上传到 OSS/CDN - 记录 release ### 10.4 对比与预览 - 给后台显示 diff - 给发布前做预览 一句话: **Go 中间层本质上是配置编译器。** --- ## 11. 校验建议 建议尽量做强校验。 至少包括: - schemaVersion 合法 - 引用对象存在 - KML 路径存在 - 地图 meta 存在 - 玩法字段完整 以及玩法特定约束,例如: - 顺序赛必须有 start / finish - 积分赛 control set 需要 score 或可派生 score - `punch.radiusMeters > 0` - `skip.radiusMeters > punch.radiusMeters` 这样能把很多错误挡在发布前。 --- ## 12. 和当前静态目录的关系 当前你已经有类似目录: - `map/` - `kml/` - `event/` 这很好,可以继续保留。 建议把它理解成: - 数据库 = 编辑态 - 这些目录 = 发布产物态 也就是后台发布后,Go 中间层继续生成: - `event/classic-sequential.json` - `event/score-o.json` - `map/...` - `kml/...` 客户端保持现有读取方式不变。 --- ## 13. 推荐的后续实施顺序 建议按这个顺序落地: ### 第一步 先建 5 个核心对象模型: - `Map` - `Playfield` - `GameMode` - `ResourcePack` - `Event` ### 第二步 为每个对象补版本表。 ### 第三步 Go 中间层实现“装配成最终 JSON”。 ### 第四步 实现“发布到 OSS/CDN”。 ### 第五步 后台逐步从 JSON 编辑过渡到模块化表单编辑。 --- ## 14. 一句话总结 这类配置驱动应用最稳的后台方案是: **PostgreSQL 管结构化、可版本化的编辑态对象;Go 中间层负责校验、装配和发布;客户端只消费发布后的静态 JSON。** 这样才能做到: - 可复用 - 可扩展 - 可审核 - 可回滚 - 可稳定运行