后端接口字段需求文档 - JSON 美化功能
文档版本: v1.0.0
创建日期: 2026-01-13
适用范围: 后端 API 扩展
一、需求背景
为支持前端 JSON 美化功能,后端需要在现有 API 响应中新增字段,用于存储和传递:
- JSON 模板定义 (创作者配置的 UI 模板)
- 模板元数据 (版本、审核状态等)
- AI 生成的结构化数据 (已包含在
content字段中,无需额外修改)
二、涉及的 API 端点
2.1 核心游玩相关
| API 路径 | 说明 | 是否需要修改 |
|---|---|---|
POST /engine-play/new | 开始新游玩 | ✅ 需要返回模板 |
GET /engine-play/sessions/{id}/messages | 获取历史消息 | ✅ 需要返回模板 |
POST /chat/sessions/{id}/choice | 提交选择 (轮询) | ⚠️ 无需修改 (AI 输出在消息中) |
POST /engine-play/sessions/{id}/regenerate | 重新生成 | ⚠️ 无需修改 |
2.2 引擎管理相关
| API 路径 | 说明 | 是否需要修改 |
|---|---|---|
GET /engines/{id} | 获取引擎详情 | ✅ 需要返回模板列表 |
POST /engines | 创建引擎 | ✅ 需要接收模板数据 |
PUT /engines/{id} | 更新引擎 | ✅ 需要接收模板数据 |
2.3 新增 API (推荐)
| API 路径 | 方法 | 说明 |
|---|---|---|
GET /engines/{id}/templates | GET | 获取引擎的所有 JSON 模板 |
POST /engines/{id}/templates | POST | 创建新模板 |
PUT /engines/{id}/templates/{templateId} | PUT | 更新模板 |
DELETE /engines/{id}/templates/{templateId} | DELETE | 删除模板 |
POST /engines/{id}/templates/{templateId}/validate | POST | 校验模板语法 |
三、字段详细定义
3.1 引擎详情响应扩展
API: GET /engines/{id}
现有响应结构 (部分):
{
"data": {
"id": "engine_123",
"name": "星际迷航",
"description": "...",
"coverImageUrl": "...",
"backgroundImageUrl": "...",
"narrativeSettings": { ... },
"characterCard": { ... }
}
}新增字段 (建议添加在 data 下):
{
"data": {
"id": "engine_123",
// ... 现有字段 ...
"jsonTemplates": [
{
"id": "template_001",
"type": "status-card",
"name": "状态卡片",
"description": "显示指挥官状态的卡片组件",
"html": "<div class=\"status\"><h3>{{title}}</h3><p>{{comment}}</p></div>",
"style": ".status{padding:14px;border-radius:12px;background:skyblue;}",
"version": 1,
"isActive": true,
"createdAt": "2026-01-13T10:00:00Z",
"updatedAt": "2026-01-13T10:00:00Z"
},
{
"id": "template_002",
"type": "global-theme",
"name": "全局主题",
"description": "深色模式主题样式",
"html": "",
"style": ".markdown-body { background: #1f2933; color: #fff; }",
"version": 1,
"isActive": true,
"createdAt": "2026-01-13T10:00:00Z",
"updatedAt": "2026-01-13T10:00:00Z"
}
]
}
}字段说明:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
jsonTemplates | Array | 否 | JSON 模板数组,引擎没有模板时为空数组 |
jsonTemplates[].id | String | 是 | 模板唯一标识 (数据库主键) |
jsonTemplates[].type | String | 是 | 模板类型标识符 (如 status-card、global-theme) |
jsonTemplates[].name | String | 是 | 模板名称 (创作者可见) |
jsonTemplates[].description | String | 否 | 模板描述 |
jsonTemplates[].html | String | 是 | LiquidJS HTML 模板字符串 |
jsonTemplates[].style | String | 否 | CSS 样式字符串 |
jsonTemplates[].version | Integer | 是 | 模板版本号 (用于缓存失效) |
jsonTemplates[].isActive | Boolean | 是 | 是否启用 (支持禁用而非删除) |
jsonTemplates[].createdAt | String | 是 | 创建时间 (ISO 8601) |
jsonTemplates[].updatedAt | String | 是 | 更新时间 (ISO 8601) |
3.2 游玩会话响应扩展
API: POST /engine-play/new, GET /engine-play/sessions/{id}/messages
现有响应结构:
{
"data": {
"session": {
"id": "session_456",
"engineId": "engine_123",
// ...
},
"currentScene": {
"context": "欢迎来到星际迷航...",
"choices": [...]
},
"storyHistory": [...]
}
}方案 A: 嵌套模板数据 (推荐)
在 data 下新增 jsonTemplates 字段 (与引擎详情保持一致):
{
"data": {
"session": { ... },
"currentScene": { ... },
"storyHistory": [ ... ],
"jsonTemplates": [
// 与 3.1 中的结构相同
]
}
}方案 B: 仅返回模板引用
如果模板数据量大,可仅返回 templateIds,前端再调用 GET /engines/{id}/templates:
{
"data": {
"session": { ... },
"currentScene": { ... },
"storyHistory": [ ... ],
"templateIds": ["template_001", "template_002"]
}
}建议: 优先采用 方案 A,理由:
- 减少 API 调用次数 (1 次 vs 2 次)
- 避免模板数据与消息不同步
- 模板数量通常不超过 20 个,数据量可控
3.3 引擎创建/更新请求扩展
API: POST /engines, PUT /engines/{id}
现有请求 Body (部分):
{
"name": "星际迷航",
"description": "...",
"coverImageUrl": "...",
"narrativeSettings": { ... },
"characterCard": { ... }
}新增字段:
{
"name": "星际迷航",
// ... 现有字段 ...
"jsonTemplates": [
{
"type": "status-card",
"name": "状态卡片",
"description": "显示指挥官状态",
"html": "<div class=\"status\"><h3>{{title}}</h3></div>",
"style": ".status{padding:14px;}",
"isActive": true
}
]
}字段说明:
- 创建引擎时,
jsonTemplates可选 (默认空数组) - 更新引擎时,
jsonTemplates会 全量替换 现有模板 - 不需要传
id、version、createdAt、updatedAt(后端自动生成)
3.4 独立模板管理 API (可选,但强烈推荐)
3.4.1 获取模板列表
API: GET /engines/{id}/templates
响应:
{
"success": true,
"data": [
{
"id": "template_001",
"type": "status-card",
"name": "状态卡片",
"html": "...",
"style": "...",
"version": 2,
"isActive": true,
"createdAt": "2026-01-13T10:00:00Z",
"updatedAt": "2026-01-13T12:00:00Z"
}
]
}3.4.2 创建模板
API: POST /engines/{id}/templates
请求 Body:
{
"type": "inventory-card",
"name": "物品栏卡片",
"description": "显示玩家背包",
"html": "<div>{{slot:item-list}}</div>",
"style": ".inventory{background:#fff;}",
"isActive": true
}响应:
{
"success": true,
"data": {
"id": "template_003",
"type": "inventory-card",
// ... 完整模板数据
}
}3.4.3 更新模板
API: PUT /engines/{id}/templates/{templateId}
请求 Body:
{
"name": "物品栏卡片 V2",
"html": "<div class=\"v2\">{{slot:item-list}}</div>",
"style": ".v2{background:#f0f0f0;}",
"isActive": true
}响应:
{
"success": true,
"data": {
"id": "template_003",
"version": 3, // 版本号自动递增
"updatedAt": "2026-01-13T14:00:00Z",
// ... 完整模板数据
}
}3.4.4 删除模板
API: DELETE /engines/{id}/templates/{templateId}
响应:
{
"success": true,
"message": "模板已删除"
}软删除建议: 不物理删除记录,而是设置 isActive = false,避免历史会话中的模板失效。
3.4.5 校验模板 (推荐)
API: POST /engines/{id}/templates/validate
请求 Body:
{
"html": "<div>{{title}}</div>",
"style": ".test{color:red;}"
}响应 (成功):
{
"success": true,
"data": {
"isValid": true,
"warnings": [
"检测到未使用的 CSS 类: .unused"
]
}
}响应 (失败):
{
"success": false,
"data": {
"isValid": false,
"errors": [
{
"field": "html",
"message": "LiquidJS 语法错误: Unexpected token at line 3"
},
{
"field": "style",
"message": "检测到危险 CSS: @import"
}
]
}
}校验规则建议:
- LiquidJS 语法检查
- CSS 危险特性检测 (
@import,url(),@font-face) - HTML 标签白名单检查
- 插槽引用完整性检查 (如
{{slot:non-exist}}不存在)
四、数据库设计建议
4.1 表结构
表名: engine_json_templates
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
id | String (UUID) | PRIMARY KEY | 模板 ID |
engine_id | String (UUID) | FOREIGN KEY | 关联的引擎 ID |
type | String (50) | NOT NULL | 模板类型标识符 |
name | String (100) | NOT NULL | 模板名称 |
description | Text | NULL | 模板描述 |
html | Text | NOT NULL | HTML 模板 |
style | Text | NULL | CSS 样式 |
version | Integer | NOT NULL, DEFAULT 1 | 版本号 |
is_active | Boolean | NOT NULL, DEFAULT TRUE | 是否启用 |
created_at | Timestamp | NOT NULL | 创建时间 |
updated_at | Timestamp | NOT NULL | 更新时间 |
索引建议:
CREATE INDEX idx_engine_templates ON engine_json_templates(engine_id, is_active);
CREATE UNIQUE INDEX idx_engine_type ON engine_json_templates(engine_id, type) WHERE is_active = TRUE;唯一性约束: 同一引擎下,同一 type 只能有一个启用的模板 (支持版本管理时,历史版本可保留)。
4.2 数据迁移策略
Phase 1: 向后兼容
- 新增
jsonTemplates字段为可选 - 老引擎返回
jsonTemplates: [] - 前端检测到空数组时,降级为纯 Markdown 渲染
Phase 2: 逐步迁移
- 引擎编辑器 UI 中增加”JSON 模板”配置入口
- 创作者可选择是否启用 JSON 美化
- 后台统计使用率
Phase 3: 全量推广
- 提供默认模板库 (官方精选)
- 新引擎默认带 1-2 个示例模板
五、API 响应示例对比
5.1 修改前 (现有)
GET /engines/{id}:
{
"data": {
"id": "engine_123",
"name": "星际迷航",
"description": "探索未知星系",
"coverImageUrl": "https://...",
"narrativeSettings": {
"genre": "sci-fi",
"tone": "serious"
}
}
}5.2 修改后 (新增字段)
GET /engines/{id}:
{
"data": {
"id": "engine_123",
"name": "星际迷航",
"description": "探索未知星系",
"coverImageUrl": "https://...",
"narrativeSettings": {
"genre": "sci-fi",
"tone": "serious"
},
// ✨ 新增字段
"jsonTemplates": [
{
"id": "template_001",
"type": "status-card",
"name": "指挥官状态",
"description": "显示当前任务状态",
"html": "<div class=\"cmd-status\"><h3>{{title}}</h3><p>{{comment}}</p></div>",
"style": ".cmd-status{padding:16px;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border-radius:12px;}",
"version": 1,
"isActive": true,
"createdAt": "2026-01-13T10:00:00Z",
"updatedAt": "2026-01-13T10:00:00Z"
},
{
"id": "template_002",
"type": "crew-list",
"name": "船员名单",
"description": "显示当前船员状态",
"html": "<div class=\"crew\">{{#each members}}<p>{{name}} - {{role}}</p>{{/each}}</div>",
"style": ".crew{background:#fff;padding:12px;}",
"version": 1,
"isActive": true,
"createdAt": "2026-01-13T10:00:00Z",
"updatedAt": "2026-01-13T10:00:00Z"
}
]
}
}六、前后端协作要点
6.1 模板加载时机
前端行为:
- 进入会话时,从
GET /engine-play/sessions/{id}/messages响应中获取jsonTemplates - 调用
jsonRenderer.registerTemplate(template)注册所有模板 - 渲染消息时,按
type匹配模板
后端需保证:
- 所有包含 JSON 消息的 API (新建会话、获取历史) 都返回
jsonTemplates - 模板数据与引擎版本一致 (避免引擎更新后模板不同步)
6.2 模板版本管理
场景: 创作者更新了模板,但历史会话仍在使用旧版本
解决方案:
- 后端在
session表中新增template_snapshot字段 (JSON 类型) - 会话创建时,快照当前引擎的所有模板
- 历史会话恢复时,返回快照版本而非最新版本
示例:
// session 表
{
"id": "session_456",
"engine_id": "engine_123",
"template_snapshot": [
// 会话创建时的模板副本
],
"created_at": "2026-01-10T10:00:00Z"
}API 行为:
GET /engine-play/sessions/{id}/messages返回data.jsonTemplates = session.template_snapshot- 新会话创建时,自动生成快照
6.3 AI 输出内容格式
重要: 后端无需修改 AI 输出逻辑,JSON 块已包含在 content 字段中
示例:
{
"currentScene": {
"context": "你来到了指挥室...\n\n```json\n{\"type\":\"status-card\",\"title\":\"紧急状况\",\"comment\":\"敌舰逼近\"}\n```\n\n你需要做出决定。",
"choices": [...]
}
}前端处理:
- 正则提取
```json ... ```块 - 清理 Markdown:
你来到了指挥室...你需要做出决定。 - 解析 JSON:
{type: "status-card", ...} - 分别渲染
七、性能与安全考虑
7.1 模板数据量控制
建议:
- 单个引擎最多 20 个模板
- 单个模板 HTML 不超过 10KB
- 单个模板 CSS 不超过 5KB
超限处理:
- API 返回 HTTP 400,错误码
TEMPLATE_SIZE_EXCEEDED - 编辑器 UI 实时提示字符数
7.2 模板内容安全
后端校验规则 (在 POST /engines/{id}/templates/validate 中实施):
- HTML 标签白名单: 仅允许
div, p, span, h1-h6, button, form, input, select, textarea - HTML 属性白名单: 仅允许
class, data-action-*, data-display-*, data-target - 禁止属性:
onerror, onload, onclick, style, src, href(除非href值为内部路由) - CSS 黑名单: 禁止
@import, url(), @font-face, expression() - LiquidJS 语法检查: 使用 Liquid 引擎的
parse()方法预校验
校验失败响应示例:
{
"success": false,
"errors": [
{
"field": "html",
"message": "检测到危险标签: <script>"
}
]
}7.3 缓存策略
建议: 后端对模板数据启用 HTTP 缓存
响应头:
Cache-Control: public, max-age=3600
ETag: "template_version_2"前端行为:
- 使用
If-None-Match条件请求 - 模板版本号变化时,ETag 自动更新
八、实施检查清单
8.1 后端开发任务
- 创建
engine_json_templates数据表 - 扩展
GET /engines/{id}返回jsonTemplates - 扩展
POST /engine-play/new返回jsonTemplates - 扩展
GET /engine-play/sessions/{id}/messages返回jsonTemplates - 扩展
POST /engines接收jsonTemplates - 扩展
PUT /engines/{id}接收jsonTemplates - 新增
GET /engines/{id}/templatesAPI - 新增
POST /engines/{id}/templatesAPI - 新增
PUT /engines/{id}/templates/{templateId}API - 新增
DELETE /engines/{id}/templates/{templateId}API - 新增
POST /engines/{id}/templates/validateAPI - 实现模板内容安全校验 (HTML/CSS)
- 实现
session.template_snapshot快照机制 - 编写 API 单元测试
- 更新 OpenAPI 文档 (Swagger)
8.2 前端联调准备
- 更新 Orval 生成 TypeScript 类型
- 验证
jsonTemplates字段正确返回 - 验证模板 CRUD 操作
- 验证模板校验 API
- 验证历史会话使用快照版本
九、FAQ
Q1: 如果引擎没有配置模板,API 返回什么?
A: 返回 jsonTemplates: [] (空数组),前端自动降级为纯 Markdown 渲染。
Q2: 模板 type 字段有命名规范吗?
A: 建议使用 kebab-case (如 status-card, inventory-list),长度 3-50 字符,仅允许英文字母、数字、连字符。
Q3: global-theme 类型的模板如何处理?
A: 与普通模板一致存储,前端会识别 type === 'global-theme' 并仅注入 style,不渲染 html。
Q4: 模板更新后,旧会话会显示错误吗?
A: 不会。使用 template_snapshot 快照机制,历史会话固定使用创建时的模板版本。
Q5: 是否需要模板权限管理?
A: 当前版本不强制要求。如需权限,建议在 engine_json_templates 表增加 creator_id 字段,限制仅引擎创建者可修改模板。
十、总结
本文档详细定义了支持 JSON 美化功能所需的后端字段扩展,核心要点:
- 最小化侵入: 仅在现有 API 响应中新增
jsonTemplates数组字段 - 向后兼容: 旧引擎返回空数组,不影响现有功能
- 推荐独立 API: 提供模板 CRUD 端点,便于前端独立管理
- 安全优先: 提供模板校验 API,防止 XSS/CSS 注入
- 版本管理: 通过
template_snapshot确保历史会话稳定
下一步行动:
- 后端团队评审本文档
- 确认数据库表结构设计
- 实施 API 扩展开发
- 前端团队同步更新类型定义
📌 相关文档: