1
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
创作 Tab 恢复为模板选择入口,但不回到旧的大卡片选择面板:
|
||||
|
||||
1. 首屏保留现有创作页布局骨架,顶部标题固定为“10分钟创作一个精品互动玩法”。
|
||||
2. 选择模板入口改为横向 Tab,数据来自 `src/config/newWorkEntryConfig.ts` 的可见玩法配置。
|
||||
2. 选择模板入口改为横向 Tab,数据来自 `GET /api/creation-entry/config` 返回的可见玩法配置。
|
||||
3. 默认选中“拼图”模板,并在创作 Tab 内直接展示拼图创作表单。
|
||||
4. 智能创作入口从可见模板中隐藏,保留既有 `creative-agent` 运行链路用于后续内部恢复或草稿目标打开。
|
||||
5. 草稿、发现、我的等一级 Tab 职责不变,作品管理仍在草稿 Tab。
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
```text
|
||||
标题:10分钟创作一个精品互动玩法
|
||||
模板 Tab:拼图 / 方洞挑战 / 视觉小说 / AIRP
|
||||
模板 Tab:拼图 / 抓大鹅 / 视觉小说 / AIRP
|
||||
默认内容:拼图创作表单
|
||||
```
|
||||
|
||||
@@ -36,19 +36,22 @@
|
||||
3. 拼图表单内的模板按钮使用 `tablist / tab` 语义,点击后只填充画面描述。
|
||||
4. 点击非拼图且已开放的模板 Tab 时,进入该玩法既有工作台;未开放模板保持禁用。
|
||||
5. `creative-agent` 不出现在模板 Tab 和选择弹层中,不再作为创作 Tab 首屏入口。
|
||||
6. 方洞挑战暂时从创作页完全隐藏,不出现在模板 Tab、旧选择弹层和创作 Hub 卡片中;既有作品链路继续保留。
|
||||
|
||||
## 4. 验收
|
||||
|
||||
1. 点击“创作”后首屏出现“10分钟创作一个精品互动玩法”。
|
||||
2. 顶部选择模板入口为 Tab,拼图 Tab 默认 `aria-selected=true`。
|
||||
3. 创作 Tab 默认显示拼图创作表单内容,且不显示旧“Hi, 朋友”、输入框或智能创作快捷按钮。
|
||||
4. 隐藏的智能创作类型不出现在模板 Tab、旧选择弹层和创作 Hub 卡片中。
|
||||
4. 隐藏的智能创作类型与方洞挑战不出现在模板 Tab、旧选择弹层和创作 Hub 卡片中。
|
||||
5. 草稿页返回创作页后仍回到同一模板入口,并可保留拼图表单草稿内容。
|
||||
|
||||
## 5. 嵌入式表单 UI 细节
|
||||
|
||||
2026-05-10 补充:抓大鹅与视觉小说作为创作 Tab 内嵌表单时,风格类横滑选择器应统一使用浅底卡片、柔和玫瑰色选中态和小圆点确认标记。不要使用大面积黑色渐变、黑底胶囊标签或高饱和红色外框,以免在输入框下方误读为错误提示。
|
||||
|
||||
2026-05-10 追加:视觉小说画风选项已改为使用 `public/visual-novel-style-references/` 下由 VectorEngine `gpt-image-2-all` 生成的参考图,作为横向卡片主视觉。
|
||||
|
||||
嵌入式表单控件保持以下口径:
|
||||
|
||||
1. 大文本输入框使用白底、低饱和边框和轻量 focus ring。
|
||||
|
||||
@@ -124,7 +124,7 @@ Match3D 必须形成独立玩法域,后续技术方案至少需要覆盖:
|
||||
3. 不做排行榜正式展示。
|
||||
4. 不做道具,但需要预留功能口。
|
||||
5. 不做洗牌、重置、旋转、放大等局内操作。
|
||||
6. 不做真实 3D 模型。
|
||||
6. 不做多批次真实 3D 模型生成;当前草稿生成只固定产出 `3` 个 GLB 模型并写入 OSS。
|
||||
7. 不做真实 3D 物理遮挡。
|
||||
8. 不做真实物理碰撞结算。
|
||||
9. 不做必须试玩通关才能发布的门槛。
|
||||
@@ -161,7 +161,7 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
|
||||
|
||||
题材决定后续生成或选择物品素材的方向。用户可以自定义主题,例如水果、玩具、食物、符号等。
|
||||
|
||||
首版 demo 不接入真实图片生成。当前运行态可消除物统一使用题材方向的 25 个积木件类型表现,不使用透明气泡,也不在图案上放文字标识。前端首版用差异化颜色、积木造型和 3D 程序化模型表现可消除物,避免玩家在堆叠状态下难以辨认。
|
||||
当前抓大鹅草稿生成会固定生成 `3` 个题材物品:素材图切割出的独立图片会作为 Rodin 图生 3D 参考图,生成出的 GLB 模型必须转存 OSS,并随作品 profile 的 `generatedItemAssets` 持久化。运行态优先使用这些生成模型;只有模型缺失、加载失败或未进入 3D 渲染模式时,才回退到 25 个默认积木件视觉键。默认素材不使用透明气泡,也不在图案上放文字标识。
|
||||
|
||||
可消除物尺寸使用五档相对体积规则:XL 型相对体积为 `1.60~2.30`,L 型为 `1.25~1.60`,M 型为 `1.00`,XS 型为 `0.65~0.85`,S 型为 `0.35~0.50`。单局中 XL / L / M / XS / S 按本局使用的消除物类型数的 `20% / 30% / 30% / 15% / 5%` 分配;非整数配额按最大余数补齐,确保总数等于本局使用类型数量。同一关卡内同一个颜色和造型的物品只能对应一个尺寸档位;可存在同尺寸但不同颜色和造型的物品。后端运行态通过 `radius` 下发权威尺寸,前端只按快照表现。
|
||||
|
||||
@@ -195,7 +195,7 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
|
||||
|
||||
## 6.3 参考图片
|
||||
|
||||
抓大鹅入口页不展示参考图片上传。题材表现先由题材文本和草稿切割图片链路承接;后续需要 3D 模型时,在结果页 `3D素材` Tab 以切割图片作为图生模型参考图手动触发。
|
||||
抓大鹅入口页不展示参考图片上传。题材表现由题材文本和草稿切割图片链路承接;草稿生成阶段会直接以切割图片作为 Rodin 图生模型参考图生成首批 GLB。结果页 `3D素材` Tab 仍可对单个素材触发重新生成。
|
||||
|
||||
---
|
||||
|
||||
@@ -222,9 +222,9 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
|
||||
|
||||
## 7.3 素材生成边界
|
||||
|
||||
抓大鹅草稿生成链路会生成首批 `3` 个题材物品素材:文本模型生成物品名,VectorEngine 生成 `2*2` 素材图并切割独立图片。入口页选择的 `assetStylePrompt` 必须写入素材图提示词;结果页手动 Rodin 图生模型时,继续以该物品图片和默认提示词作为起点。
|
||||
抓大鹅草稿生成链路会生成首批 `3` 个题材物品素材:文本模型生成物品名,VectorEngine 生成 `2*2` 素材图并切割独立图片,再以每张独立图片调用 Rodin 图生 3D,下载 `.glb` 并转存 OSS。入口页选择的 `assetStylePrompt` 必须写入素材图提示词;结果页手动 Rodin 图生模型时,继续以该物品图片和默认提示词作为起点。
|
||||
|
||||
生成出的独立图片先作为草稿页 `3D素材` Tab 的预览资产返回,状态为 `image_ready`,模型文件为空。正式平台资产绑定、Rodin 生成模型转存和二次编辑流程以后续技术方案为准。
|
||||
生成出的独立图片与 GLB 模型都必须作为草稿页 `3D素材` Tab 的预览资产返回。模型生成成功时 `generatedItemAssets[].status = model_ready`,并携带 `modelSrc`、`modelObjectKey`、`modelFileName`、`taskUuid` 和 `subscriptionKey`;正式平台资产绑定和更完整的二次编辑流程以后续技术方案为准。
|
||||
|
||||
## 7.4 发布前试玩
|
||||
|
||||
@@ -297,12 +297,14 @@ itemTypeCount = clearCount <= 25 ? clearCount : 25
|
||||
|
||||
## 8.5 物品资产
|
||||
|
||||
首版 demo 使用 2D 图案素材。
|
||||
当前 demo 使用生成 GLB 优先、默认积木兜底的物品资产策略。
|
||||
|
||||
1. demo 至少提供 `25` 种彼此不同的颜色与几何造型组合素材,支撑 `clearCount > 25` 时的类型上限。
|
||||
2. 当前 demo 使用 25 个积木件视觉键作为默认素材池;前端首版必须把这些视觉键映射为无文字的纯色 2D 图标和程序化 3D 积木模型,不能显示为透明气泡或文字标记。
|
||||
3. 后续可以尝试替换为伪 3D 或 3D 模型。
|
||||
4. 用户题材主题后续会映射为符合常识预期的物品集合。
|
||||
1. demo 至少提供 `25` 种彼此不同的颜色与几何造型组合默认素材,支撑 `clearCount > 25` 时的类型上限和 GLB 缺失兜底。
|
||||
2. 有 `generatedItemAssets[].modelSrc` 或 `modelObjectKey` 时,运行态与备选栏必须优先读取该 GLB;默认积木件只作为加载失败、模型缺失或 2D 回退时的兜底素材池。
|
||||
3. 前端读取生成模型必须通过 `/api/assets/read-bytes` 获取私有 OSS 字节,再交给 Three.js `GLTFLoader` 解析;不得直接把 `/generated-match3d-assets/...` 当裸 URL 请求。
|
||||
4. 当前固定 `clearCount = 3` 的生成草稿中,运行态 `match3d-type-01/02/03` 按类型编号顺序映射到生成出的 `3` 个模型;后续恢复更大生成数量时,模型列表顺序必须继续与类型编号稳定对应。
|
||||
5. 默认积木视觉键仍需映射为无文字的纯色 2D 图标和程序化 3D 积木模型,不能显示为透明气泡或文字标记。
|
||||
6. 用户题材主题后续会映射为符合常识预期的物品集合。
|
||||
|
||||
示例:水果题材可以对应红色苹果、黄色香蕉、紫色葡萄等。
|
||||
|
||||
@@ -706,10 +708,10 @@ GET /api/runtime/match3d/runs/:runId
|
||||
3. 入口页不展示参考图上传。
|
||||
4. 内置风格显示画风参考图,自定义风格通过独立面板填写并进入提交 payload。
|
||||
5. 移动端入口页所有内容一屏展示,不产生纵向滚动。
|
||||
6. 系统可生成待发布结果页,并在草稿中返回首批切割图片素材预览。
|
||||
6. 系统可生成待发布结果页,并在草稿中返回首批切割图片与 OSS GLB 模型素材预览。
|
||||
7. 用户可编辑游戏名称、标签、封面图等基础信息。
|
||||
8. 用户可发布前试玩,且试玩失败不阻断发布。
|
||||
9. 运行态能展示圆形空间、倒计时、物品和 `7` 格备选栏。
|
||||
9. 运行态能展示圆形空间、倒计时、物品和 `7` 格备选栏;存在 `generatedItemAssets` 模型时必须优先展示生成 GLB,而不是默认积木素材。
|
||||
10. 物品可重叠、遮挡、堆叠。
|
||||
11. 被完全遮挡物品不可点击,露出可点击区域的物品可点击。
|
||||
12. 点击通过后物品飞入备选栏。
|
||||
|
||||
@@ -50,18 +50,18 @@
|
||||
|
||||
外部仓库文件只作为玩法语义参考,不能作为目录结构迁入依据:
|
||||
|
||||
| 外部参考 | 可参考内容 | Genarrative 落点 |
|
||||
| --- | --- | --- |
|
||||
| `interface/routes/visual.js` | 视觉小说创作和运行时路由语义 | `server-rs/crates/api-server/src/visual_novel.rs` |
|
||||
| `interface/handlers/visual/sendActionStream.js` | 流式动作推进事件 | Axum SSE handler + `shared-contracts` typed envelope |
|
||||
| `interface/handlers/visual/getHistory.js` | 历史记录读取 | 平台 runtime history API |
|
||||
| `interface/handlers/visual/saves.js` | 存档语义 | 平台统一 `profile/save-archives` |
|
||||
| `services/visual/gameLogic.js` | step 解析、会话状态推进 | `server-rs/crates/module-visual-novel` |
|
||||
| `services/visual/storyGeneration.js` | 创作底稿生成语义 | `platform-agent` / `platform-llm` + visual novel Tool |
|
||||
| `prompts/visual.gm.system/1.0.1/body.js` | 视觉小说 GM 输出结构经验 | 新 prompt 必须适配 Genarrative 契约,不原样照搬平台规则 |
|
||||
| `src/page/Galgame.tsx` | 运行时界面结构 | `src/components/visual-novel-runtime/VisualNovelRuntimeShell.tsx` |
|
||||
| `src/hooks/galgame/useGalgameController.ts` | 前端运行时状态组织 | visual novel runtime hooks |
|
||||
| `src/page/GameSettingsEditor.tsx` | 创作编辑器模块划分 | visual novel result / workspace 组件 |
|
||||
| 外部参考 | 可参考内容 | Genarrative 落点 |
|
||||
| ----------------------------------------------- | ---------------------------- | ----------------------------------------------------------------- |
|
||||
| `interface/routes/visual.js` | 视觉小说创作和运行时路由语义 | `server-rs/crates/api-server/src/visual_novel.rs` |
|
||||
| `interface/handlers/visual/sendActionStream.js` | 流式动作推进事件 | Axum SSE handler + `shared-contracts` typed envelope |
|
||||
| `interface/handlers/visual/getHistory.js` | 历史记录读取 | 平台 runtime history API |
|
||||
| `interface/handlers/visual/saves.js` | 存档语义 | 平台统一 `profile/save-archives` |
|
||||
| `services/visual/gameLogic.js` | step 解析、会话状态推进 | `server-rs/crates/module-visual-novel` |
|
||||
| `services/visual/storyGeneration.js` | 创作底稿生成语义 | `platform-agent` / `platform-llm` + visual novel Tool |
|
||||
| `prompts/visual.gm.system/1.0.1/body.js` | 视觉小说 GM 输出结构经验 | 新 prompt 必须适配 Genarrative 契约,不原样照搬平台规则 |
|
||||
| `src/page/Galgame.tsx` | 运行时界面结构 | `src/components/visual-novel-runtime/VisualNovelRuntimeShell.tsx` |
|
||||
| `src/hooks/galgame/useGalgameController.ts` | 前端运行时状态组织 | visual novel runtime hooks |
|
||||
| `src/page/GameSettingsEditor.tsx` | 创作编辑器模块划分 | visual novel result / workspace 组件 |
|
||||
|
||||
---
|
||||
|
||||
@@ -160,8 +160,8 @@
|
||||
5. 玩家身份。
|
||||
6. 3 到 6 个主要角色。
|
||||
7. 3 到 8 个可用场景。
|
||||
7. 3 到 6 个剧情阶段。
|
||||
8. 初始场景、初始旁白和第一轮可选行动。
|
||||
8. 3 到 6 个剧情阶段。
|
||||
9. 初始场景、初始旁白和第一轮可选行动。
|
||||
|
||||
### 5.2 文档创建 `document`
|
||||
|
||||
@@ -399,7 +399,15 @@ export type VisualNovelAgentActionKind =
|
||||
```ts
|
||||
export type VisualNovelAgentStreamEvent =
|
||||
| { type: 'start'; sessionId: string }
|
||||
| { type: 'phase'; phase: 'perception' | 'reasoning' | 'drafting' | 'reflection' | 'finalizing' }
|
||||
| {
|
||||
type: 'phase';
|
||||
phase:
|
||||
| 'perception'
|
||||
| 'reasoning'
|
||||
| 'drafting'
|
||||
| 'reflection'
|
||||
| 'finalizing';
|
||||
}
|
||||
| { type: 'text_delta'; text: string }
|
||||
| { type: 'draft_patch'; patch: VisualNovelDraftPatch }
|
||||
| { type: 'action_required'; action: VisualNovelAgentPendingAction }
|
||||
@@ -558,35 +566,35 @@ export type VisualNovelRuntimeStreamEvent =
|
||||
|
||||
### 9.1 创作 session
|
||||
|
||||
| 方法 | 路由 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/api/creation/visual-novel/sessions` | 创建视觉小说创作 session |
|
||||
| `GET` | `/api/creation/visual-novel/sessions/{session_id}` | 读取 session snapshot |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/messages` | 非流式发送创作消息 |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/messages/stream` | 流式发送创作消息 |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/actions` | 执行结构化创作 action |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/compile` | 编译为 work profile 草稿 |
|
||||
| 方法 | 路由 | 用途 |
|
||||
| ------ | ------------------------------------------------------------------ | ------------------------ |
|
||||
| `POST` | `/api/creation/visual-novel/sessions` | 创建视觉小说创作 session |
|
||||
| `GET` | `/api/creation/visual-novel/sessions/{session_id}` | 读取 session snapshot |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/messages` | 非流式发送创作消息 |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/messages/stream` | 流式发送创作消息 |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/actions` | 执行结构化创作 action |
|
||||
| `POST` | `/api/creation/visual-novel/sessions/{session_id}/compile` | 编译为 work profile 草稿 |
|
||||
|
||||
### 9.2 作品草稿与发布
|
||||
|
||||
| 方法 | 路由 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/creation/visual-novel/works` | 读取当前用户视觉小说作品草稿列表 |
|
||||
| `GET` | `/api/creation/visual-novel/works/{profile_id}` | 读取作品详情 |
|
||||
| `PUT/PATCH` | `/api/creation/visual-novel/works/{profile_id}` | 更新作品草稿 |
|
||||
| `DELETE` | `/api/creation/visual-novel/works/{profile_id}` | 删除未发布草稿或用户自有作品 |
|
||||
| `POST` | `/api/creation/visual-novel/works/{profile_id}/publish` | 发布到平台作品体系 |
|
||||
| 方法 | 路由 | 用途 |
|
||||
| ----------- | ------------------------------------------------------- | -------------------------------- |
|
||||
| `GET` | `/api/creation/visual-novel/works` | 读取当前用户视觉小说作品草稿列表 |
|
||||
| `GET` | `/api/creation/visual-novel/works/{profile_id}` | 读取作品详情 |
|
||||
| `PUT/PATCH` | `/api/creation/visual-novel/works/{profile_id}` | 更新作品草稿 |
|
||||
| `DELETE` | `/api/creation/visual-novel/works/{profile_id}` | 删除未发布草稿或用户自有作品 |
|
||||
| `POST` | `/api/creation/visual-novel/works/{profile_id}/publish` | 发布到平台作品体系 |
|
||||
|
||||
### 9.3 运行时
|
||||
|
||||
| 方法 | 路由 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/runtime/visual-novel/gallery` | 读取平台聚合后的视觉小说公开作品列表 |
|
||||
| `POST` | `/api/runtime/visual-novel/works/{profile_id}/runs` | 创建测试或正式 run |
|
||||
| `GET` | `/api/runtime/visual-novel/runs/{run_id}` | 读取 run snapshot |
|
||||
| `POST` | `/api/runtime/visual-novel/runs/{run_id}/actions/stream` | 提交选择 / 自由行动并流式推进 |
|
||||
| `GET` | `/api/runtime/visual-novel/runs/{run_id}/history` | 读取当前 run 历史 |
|
||||
| `POST` | `/api/runtime/visual-novel/runs/{run_id}/regenerate` | 从历史节点重生成 |
|
||||
| 方法 | 路由 | 用途 |
|
||||
| ------ | -------------------------------------------------------- | ------------------------------------ |
|
||||
| `GET` | `/api/runtime/visual-novel/gallery` | 读取平台聚合后的视觉小说公开作品列表 |
|
||||
| `POST` | `/api/runtime/visual-novel/works/{profile_id}/runs` | 创建测试或正式 run |
|
||||
| `GET` | `/api/runtime/visual-novel/runs/{run_id}` | 读取 run snapshot |
|
||||
| `POST` | `/api/runtime/visual-novel/runs/{run_id}/actions/stream` | 提交选择 / 自由行动并流式推进 |
|
||||
| `GET` | `/api/runtime/visual-novel/runs/{run_id}/history` | 读取当前 run 历史 |
|
||||
| `POST` | `/api/runtime/visual-novel/runs/{run_id}/regenerate` | 从历史节点重生成 |
|
||||
|
||||
### 9.4 存档
|
||||
|
||||
@@ -627,16 +635,16 @@ GET /api/runtime/profile/save-archives
|
||||
|
||||
### 10.1 crate 职责
|
||||
|
||||
| crate / 层 | 职责 |
|
||||
| --- | --- |
|
||||
| crate / 层 | 职责 |
|
||||
| -------------------------------------- | ------------------------------------------------------------- |
|
||||
| `server-rs/crates/module-visual-novel` | 纯领域规则:草稿校验、step 解析、run 状态推进、历史重生成边界 |
|
||||
| `server-rs/crates/shared-contracts` | DTO、请求响应、SSE envelope、草稿和运行时契约 |
|
||||
| `server-rs/crates/spacetime-module` | 表、reducer、procedure、migration 和事务编排 |
|
||||
| `server-rs/crates/spacetime-client` | api-server 到 SpacetimeDB 的 typed facade |
|
||||
| `server-rs/crates/api-server` | Axum 路由、鉴权、SSE、LLM 编排、资产和钱包 facade 调用 |
|
||||
| `server-rs/crates/platform-llm` | 视觉小说创作和运行时 GM 的模型调用 |
|
||||
| `server-rs/crates/platform-oss` | 文档、图片、音乐等资产对象读写 |
|
||||
| `server-rs/crates/platform-agent` | 如复用创意 Agent,负责 Agent 编排和工具注册 |
|
||||
| `server-rs/crates/shared-contracts` | DTO、请求响应、SSE envelope、草稿和运行时契约 |
|
||||
| `server-rs/crates/spacetime-module` | 表、reducer、procedure、migration 和事务编排 |
|
||||
| `server-rs/crates/spacetime-client` | api-server 到 SpacetimeDB 的 typed facade |
|
||||
| `server-rs/crates/api-server` | Axum 路由、鉴权、SSE、LLM 编排、资产和钱包 facade 调用 |
|
||||
| `server-rs/crates/platform-llm` | 视觉小说创作和运行时 GM 的模型调用 |
|
||||
| `server-rs/crates/platform-oss` | 文档、图片、音乐等资产对象读写 |
|
||||
| `server-rs/crates/platform-agent` | 如复用创意 Agent,负责 Agent 编排和工具注册 |
|
||||
|
||||
### 10.2 领域规则
|
||||
|
||||
@@ -654,14 +662,14 @@ GET /api/runtime/profile/save-archives
|
||||
|
||||
新增表必须同步 `migration.rs`、表目录和 bindings:
|
||||
|
||||
| 表 | 用途 |
|
||||
| --- | --- |
|
||||
| `visual_novel_agent_session` | 创作 session 主表 |
|
||||
| `visual_novel_agent_message` | 创作消息和模型回复 |
|
||||
| `visual_novel_work_profile` | 视觉小说作品草稿 / 发布 profile |
|
||||
| `visual_novel_runtime_run` | 玩家或测试 run |
|
||||
| `visual_novel_runtime_history_entry` | 运行时历史 |
|
||||
| `visual_novel_runtime_event` | 可审计事件,不用于回放 |
|
||||
| 表 | 用途 |
|
||||
| ------------------------------------ | ------------------------------- |
|
||||
| `visual_novel_agent_session` | 创作 session 主表 |
|
||||
| `visual_novel_agent_message` | 创作消息和模型回复 |
|
||||
| `visual_novel_work_profile` | 视觉小说作品草稿 / 发布 profile |
|
||||
| `visual_novel_runtime_run` | 玩家或测试 run |
|
||||
| `visual_novel_runtime_history_entry` | 运行时历史 |
|
||||
| `visual_novel_runtime_event` | 可审计事件,不用于回放 |
|
||||
|
||||
不得新增:
|
||||
|
||||
@@ -781,6 +789,8 @@ service client 要复用现有请求封装、鉴权和错误提示风格,不
|
||||
3. 生成草稿按钮。
|
||||
4. 错误、忙碌与禁用态。
|
||||
|
||||
视觉画风卡片使用 `public/visual-novel-style-references/` 下的 `gpt-image-2-all` 参考图,分别对应映画动画、水彩绘本、像素霓虹、水墨幻想、柔彩校园和暗色哥特。卡片只承载图像和标签,不额外展示说明文案。
|
||||
|
||||
点击生成草稿后进入 `visual-novel-generating` 过程页,过程页复用平台已有生成进度面板,展示一句话输入、画风和草稿生成阶段;完成后自动进入 `visual-novel-result` 草稿页。
|
||||
|
||||
不展示:
|
||||
@@ -975,13 +985,13 @@ V1 默认提供平台统一存档能力;如果平台存档 UI 当前按槽位
|
||||
|
||||
### 16.1 并行批次总览
|
||||
|
||||
| 批次 | 可并行任务 | 进入条件 | 汇合点 |
|
||||
| --- | --- | --- | --- |
|
||||
| Batch 0 | `VN-00` | PRD 已冻结 | 所有人以本文为唯一口径 |
|
||||
| Batch 1 | `VN-01`、`VN-02`、`VN-03`、`VN-04` | `VN-00` 完成 | 契约、领域、UI 骨架、Prompt 口径可对齐 |
|
||||
| Batch 2 | `VN-05`、`VN-06`、`VN-07`、`VN-08` | `VN-01` 产出契约初稿;`VN-02` 产出表草案 | 后端 API、前端创作、前端运行时可联调 |
|
||||
| Batch 3 | `VN-09`、`VN-10`、`VN-11` | `VN-05`、`VN-06`、`VN-07`、`VN-08` 主链路可跑 | 发布、存档、广场、负向扫描收口 |
|
||||
| Batch 4 | `VN-12`、`VN-13` | 主链路完成 | 全链路验收和文档同步 |
|
||||
| 批次 | 可并行任务 | 进入条件 | 汇合点 |
|
||||
| ------- | ---------------------------------- | --------------------------------------------- | -------------------------------------- |
|
||||
| Batch 0 | `VN-00` | PRD 已冻结 | 所有人以本文为唯一口径 |
|
||||
| Batch 1 | `VN-01`、`VN-02`、`VN-03`、`VN-04` | `VN-00` 完成 | 契约、领域、UI 骨架、Prompt 口径可对齐 |
|
||||
| Batch 2 | `VN-05`、`VN-06`、`VN-07`、`VN-08` | `VN-01` 产出契约初稿;`VN-02` 产出表草案 | 后端 API、前端创作、前端运行时可联调 |
|
||||
| Batch 3 | `VN-09`、`VN-10`、`VN-11` | `VN-05`、`VN-06`、`VN-07`、`VN-08` 主链路可跑 | 发布、存档、广场、负向扫描收口 |
|
||||
| Batch 4 | `VN-12`、`VN-13` | 主链路完成 | 全链路验收和文档同步 |
|
||||
|
||||
并行规则:
|
||||
|
||||
@@ -992,22 +1002,22 @@ V1 默认提供平台统一存档能力;如果平台存档 UI 当前按槽位
|
||||
|
||||
### 16.2 并行任务具体要求速查表
|
||||
|
||||
| 任务 | 可并行窗口 | 输入依赖 | 必须完成 | 禁止事项 | 验收口径 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `VN-00` 口径冻结 | Batch 0 | 本 PRD、旧 TXT 文档、Hermes 决策记录 | 冻结 `visual-novel` 只做模板玩法、平台接口、删除回放;标注旧文档冲突口径 | 不再使用“原样迁入外部平台工程”作为实现目标 | 文档和 Hermes 记录明确三条硬边界;`npm run check:encoding` 通过 |
|
||||
| `VN-01` 契约与领域 | Batch 1 | PRD 第 6 到 8 章契约 | TS contracts、Rust shared-contracts、`module-visual-novel`、领域单测 | 不写 HTTP、DB reducer、LLM、UI;不出现 replay 类型 | TS/Rust 契约一致;草稿校验、step 解析、状态推进、重生成测试通过 |
|
||||
| `VN-02` SpacetimeDB 与 facade | Batch 1 | `VN-01` 契约草案、SpacetimeDB 约束文档 | 表、reducer/procedure、migration、表目录、bindings、`spacetime-client` facade | 不手改 bindings 绕过 schema;不建 replay 表或私有 save 表 | schema 可生成;表目录写明 event 不是回放;`cargo check -p spacetime-client` 通过 |
|
||||
| `VN-03` Prompt / LLM 工具 | Batch 1 | `VN-01` draft 与 step 契约 | 创作 prompt、运行 GM prompt、repair prompt、工具参数 | 不照搬外部平台规则、扣费规则、回放规则;不让前端猜业务 step | fixture 输出可解析;坏格式进入 repair 或可重试错误 |
|
||||
| `VN-04` 前端 UI 骨架 | Batch 1 | PRD 第 12 章 UI 要求 | workspace、result、runtime mock 骨架;移动端优先布局;独立面板模式 | 不接真实 API;不写规则长文;不出现回放入口 | 桌面 / 移动基础布局可检查;长文本不撑破按钮 |
|
||||
| `VN-05` API Server | Batch 2 | `VN-01`、`VN-02`,真实 LLM 依赖 `VN-03` | creation、works、runtime、history、regenerate 路由;SSE;平台 save archive 接入 | 不把领域规则塞 handler;不新增 replay 路由;不新增私有 save API | `/api/creation/visual-novel/*` 和 `/api/runtime/visual-novel/*` 可 smoke;`cargo check -p api-server` 通过 |
|
||||
| `VN-06` 前端 service 与入口 | Batch 2 | `VN-01` TS 契约草案;mock 可先行 | service client、selection stage、入口分流、壳层挂载、登录态清理 | 不设计表单细节;不写 runtime UI 细节;不绕过平台入口 | 创作中心可进入 workspace;service 路由与 PRD 一致;`npm run typecheck` 通过 |
|
||||
| `VN-07` 创作工作台与结果页 | Batch 2 | `VN-04`、`VN-06`,真实生成依赖 `VN-05` | `idea` / `document` / `blank`、Agent 进度、结果页表单、保存草稿、测试 run 入口 | 不做正式玩家 runtime;不新增说明页;复杂内容不在卡片下展开 | 三种创建起点可用;草稿写入 `VisualNovelResultDraft`;发布校验 issue 可见 |
|
||||
| `VN-08` 前端运行时 | Batch 2 | `VN-04`、`VN-06`,真实运行依赖 `VN-05` | runtime shell、SSE 消费、step 渲染、历史、设置、存档、重生成 | 不做回放 UI;历史不生成分享播放页;`raw_text` 不作为业务真相 | typed step 可渲染;历史与重生成可用;save archive 可继续体验 |
|
||||
| `VN-09` 作品架 / 广场 / 发布 | Batch 3 | `VN-05` works/gallery API、`VN-06` 壳层 | work summary 聚合、作品架、公开聚合、public work code、详情跳转 | 不新增独立视觉小说市场;不迁入外部平台详情页;不做分享回放 | 发布后作品架可见;公开作品可启动 run;聚合 key 不冲突 |
|
||||
| `VN-10` 资产与文档输入 | Batch 3 | `VN-05` action/API、平台资产接口 | 文档资产读取、封面/场景/角色/音乐资产引用、可选图片生成 action | 不迁入外部 R2;不存大 Data URL;不绕过资产鉴权 | 文档创建使用资产引用;SpacetimeDB 不保存二进制或大 base64 |
|
||||
| `VN-11` 负向扫描 | Batch 1 到发布前 | 所有任务增量改动 | 扫描 replay 和外部平台功能;补负向测试或脚本清单 | 不把历史误判为回放;不做大范围重构 | 新工程代码无 replay;外部平台账号/订单/会员/后台等未误入 |
|
||||
| `VN-12` 全链路验收 | Batch 4 | `VN-05` 到 `VN-10` 主链路完成 | 创作、结果页、测试 run、发布、正式 run、历史、重生成、存档联调 | 不跳过移动端;不只测 mock;不忽略负向验收 | 全链路可跑;前端 typecheck、后端相关 cargo 检查、编码检查通过 |
|
||||
| `VN-13` 文档与交接 | Batch 4 | 实际工程落地结果 | PRD、技术方案、表目录、Hermes 决策 / 踩坑同步 | 不让旧 TXT 文档重新成为实现口径;不留下过期接口描述 | 新开发者可按最新文档维护;文档与代码一致 |
|
||||
| 任务 | 可并行窗口 | 输入依赖 | 必须完成 | 禁止事项 | 验收口径 |
|
||||
| ----------------------------- | ---------------- | --------------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `VN-00` 口径冻结 | Batch 0 | 本 PRD、旧 TXT 文档、Hermes 决策记录 | 冻结 `visual-novel` 只做模板玩法、平台接口、删除回放;标注旧文档冲突口径 | 不再使用“原样迁入外部平台工程”作为实现目标 | 文档和 Hermes 记录明确三条硬边界;`npm run check:encoding` 通过 |
|
||||
| `VN-01` 契约与领域 | Batch 1 | PRD 第 6 到 8 章契约 | TS contracts、Rust shared-contracts、`module-visual-novel`、领域单测 | 不写 HTTP、DB reducer、LLM、UI;不出现 replay 类型 | TS/Rust 契约一致;草稿校验、step 解析、状态推进、重生成测试通过 |
|
||||
| `VN-02` SpacetimeDB 与 facade | Batch 1 | `VN-01` 契约草案、SpacetimeDB 约束文档 | 表、reducer/procedure、migration、表目录、bindings、`spacetime-client` facade | 不手改 bindings 绕过 schema;不建 replay 表或私有 save 表 | schema 可生成;表目录写明 event 不是回放;`cargo check -p spacetime-client` 通过 |
|
||||
| `VN-03` Prompt / LLM 工具 | Batch 1 | `VN-01` draft 与 step 契约 | 创作 prompt、运行 GM prompt、repair prompt、工具参数 | 不照搬外部平台规则、扣费规则、回放规则;不让前端猜业务 step | fixture 输出可解析;坏格式进入 repair 或可重试错误 |
|
||||
| `VN-04` 前端 UI 骨架 | Batch 1 | PRD 第 12 章 UI 要求 | workspace、result、runtime mock 骨架;移动端优先布局;独立面板模式 | 不接真实 API;不写规则长文;不出现回放入口 | 桌面 / 移动基础布局可检查;长文本不撑破按钮 |
|
||||
| `VN-05` API Server | Batch 2 | `VN-01`、`VN-02`,真实 LLM 依赖 `VN-03` | creation、works、runtime、history、regenerate 路由;SSE;平台 save archive 接入 | 不把领域规则塞 handler;不新增 replay 路由;不新增私有 save API | `/api/creation/visual-novel/*` 和 `/api/runtime/visual-novel/*` 可 smoke;`cargo check -p api-server` 通过 |
|
||||
| `VN-06` 前端 service 与入口 | Batch 2 | `VN-01` TS 契约草案;mock 可先行 | service client、selection stage、入口分流、壳层挂载、登录态清理 | 不设计表单细节;不写 runtime UI 细节;不绕过平台入口 | 创作中心可进入 workspace;service 路由与 PRD 一致;`npm run typecheck` 通过 |
|
||||
| `VN-07` 创作工作台与结果页 | Batch 2 | `VN-04`、`VN-06`,真实生成依赖 `VN-05` | `idea` / `document` / `blank`、Agent 进度、结果页表单、保存草稿、测试 run 入口 | 不做正式玩家 runtime;不新增说明页;复杂内容不在卡片下展开 | 三种创建起点可用;草稿写入 `VisualNovelResultDraft`;发布校验 issue 可见 |
|
||||
| `VN-08` 前端运行时 | Batch 2 | `VN-04`、`VN-06`,真实运行依赖 `VN-05` | runtime shell、SSE 消费、step 渲染、历史、设置、存档、重生成 | 不做回放 UI;历史不生成分享播放页;`raw_text` 不作为业务真相 | typed step 可渲染;历史与重生成可用;save archive 可继续体验 |
|
||||
| `VN-09` 作品架 / 广场 / 发布 | Batch 3 | `VN-05` works/gallery API、`VN-06` 壳层 | work summary 聚合、作品架、公开聚合、public work code、详情跳转 | 不新增独立视觉小说市场;不迁入外部平台详情页;不做分享回放 | 发布后作品架可见;公开作品可启动 run;聚合 key 不冲突 |
|
||||
| `VN-10` 资产与文档输入 | Batch 3 | `VN-05` action/API、平台资产接口 | 文档资产读取、封面/场景/角色/音乐资产引用、可选图片生成 action | 不迁入外部 R2;不存大 Data URL;不绕过资产鉴权 | 文档创建使用资产引用;SpacetimeDB 不保存二进制或大 base64 |
|
||||
| `VN-11` 负向扫描 | Batch 1 到发布前 | 所有任务增量改动 | 扫描 replay 和外部平台功能;补负向测试或脚本清单 | 不把历史误判为回放;不做大范围重构 | 新工程代码无 replay;外部平台账号/订单/会员/后台等未误入 |
|
||||
| `VN-12` 全链路验收 | Batch 4 | `VN-05` 到 `VN-10` 主链路完成 | 创作、结果页、测试 run、发布、正式 run、历史、重生成、存档联调 | 不跳过移动端;不只测 mock;不忽略负向验收 | 全链路可跑;前端 typecheck、后端相关 cargo 检查、编码检查通过 |
|
||||
| `VN-13` 文档与交接 | Batch 4 | 实际工程落地结果 | PRD、技术方案、表目录、Hermes 决策 / 踩坑同步 | 不让旧 TXT 文档重新成为实现口径;不留下过期接口描述 | 新开发者可按最新文档维护;文档与代码一致 |
|
||||
|
||||
每个任务的交付回复必须包含:
|
||||
|
||||
@@ -1143,20 +1153,20 @@ cd server-rs
|
||||
cargo check -p spacetime-client
|
||||
```
|
||||
|
||||
阻塞关系:
|
||||
|
||||
1. 依赖 `VN-01` 的 Rust 契约。
|
||||
2. 阻塞 `VN-05` 的真实数据库联调。
|
||||
阻塞关系:
|
||||
|
||||
VN-02 实施收口记录(2026-05-05):
|
||||
1. 依赖 `VN-01` 的 Rust 契约。
|
||||
2. 阻塞 `VN-05` 的真实数据库联调。
|
||||
|
||||
1. 已新增 `server-rs/crates/spacetime-module/src/visual_novel.rs`,落地 `visual_novel_agent_session`、`visual_novel_agent_message`、`visual_novel_work_profile`、`visual_novel_runtime_run`、`visual_novel_runtime_history_entry`、`visual_novel_runtime_event` 六张表及对应 procedure。
|
||||
2. 已同步 `server-rs/crates/spacetime-module/src/lib.rs`、`server-rs/crates/spacetime-module/src/migration.rs`、`docs/technical/SPACETIMEDB_TABLE_CATALOG.md` 和 Rust bindings。
|
||||
3. 已新增 `server-rs/crates/spacetime-client/src/visual_novel.rs` typed facade,并从 `server-rs/crates/spacetime-client/src/lib.rs` 导出视觉小说 record / input 类型。
|
||||
4. `visual_novel_runtime_event` 只作为 `public event` 审计事件表使用;`visual_novel_runtime_history_entry` 只保存继续体验与历史重生成所需 step 和快照哈希,二者均不是 replay 数据源。
|
||||
5. 本阶段未新增 Axum 路由、LLM prompt、前端 UI、replay 表、replay 路由或私有 save 表;后续 VN-05 只应通过本阶段 facade 接入真实数据库。
|
||||
|
||||
### VN-03:创作与运行 Prompt / LLM 工具
|
||||
VN-02 实施收口记录(2026-05-05):
|
||||
|
||||
1. 已新增 `server-rs/crates/spacetime-module/src/visual_novel.rs`,落地 `visual_novel_agent_session`、`visual_novel_agent_message`、`visual_novel_work_profile`、`visual_novel_runtime_run`、`visual_novel_runtime_history_entry`、`visual_novel_runtime_event` 六张表及对应 procedure。
|
||||
2. 已同步 `server-rs/crates/spacetime-module/src/lib.rs`、`server-rs/crates/spacetime-module/src/migration.rs`、`docs/technical/SPACETIMEDB_TABLE_CATALOG.md` 和 Rust bindings。
|
||||
3. 已新增 `server-rs/crates/spacetime-client/src/visual_novel.rs` typed facade,并从 `server-rs/crates/spacetime-client/src/lib.rs` 导出视觉小说 record / input 类型。
|
||||
4. `visual_novel_runtime_event` 只作为 `public event` 审计事件表使用;`visual_novel_runtime_history_entry` 只保存继续体验与历史重生成所需 step 和快照哈希,二者均不是 replay 数据源。
|
||||
5. 本阶段未新增 Axum 路由、LLM prompt、前端 UI、replay 表、replay 路由或私有 save 表;后续 VN-05 只应通过本阶段 facade 接入真实数据库。
|
||||
|
||||
### VN-03:创作与运行 Prompt / LLM 工具
|
||||
|
||||
负责范围:
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ Admin Web
|
||||
-> spacetime-module creation_entry_type_config 表
|
||||
```
|
||||
|
||||
`visible=false` 会让创作中心不展示对应入口;`open=false` 会让前端展示锁定态;api-server 的运行态熔断继续以 `visible && open` 判断路由是否可用。
|
||||
`visible=false` 会让创作中心不展示对应入口;`open=false` 会让前端展示锁定态,并让 api-server 熔断对应玩法 API。隐藏入口但仍保留既有作品号、广场详情或试玩链路时,应只关闭 `visible`,不要关闭 `open`。
|
||||
|
||||
## 注意
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ SpacetimeDB 新增两张表:
|
||||
其中:
|
||||
|
||||
- `visible=false`:前端隐藏入口。
|
||||
- `open=false`:前端展示为锁定/暂不可创建,api-server 也可据此熔断运行时入口。
|
||||
- `open=false`:前端展示为锁定/暂不可创建,api-server 据此熔断对应玩法 API;只隐藏创作页入口但保留既有作品链路时不要关闭 `open`。
|
||||
- `sort_order`:数据库排序字段,前端只做可见/锁定分组派生。
|
||||
|
||||
## API
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
生成页步骤固定为:
|
||||
|
||||
```text
|
||||
生成游戏名称 -> 生成物品名称 -> 生成素材图 -> 切割独立图片 -> 上传图片资产 -> 写入草稿页
|
||||
生成游戏名称 -> 生成物品名称 -> 生成素材图 -> 切割独立图片 -> 上传图片资产 -> 生成3D模型 -> 写入草稿页
|
||||
```
|
||||
|
||||
生成页只展示题材和物品数量,不展示玩法规则说明。
|
||||
@@ -36,13 +36,14 @@
|
||||
4. 调用文本模型生成 `3` 个题材下的短物品名称。
|
||||
5. 调用项目当前图片链路 VectorEngine `gpt-image-2-all` 生成一张 `1:1` 素材图,提示词必须合入入口页选择的 `assetStylePrompt`。历史 `nanobanana2` 图片选项当前按项目统一决策回落到 VectorEngine,不重新接入 APIMart 图片网关。
|
||||
6. 将素材图按 `n*n` 网格切割成独立图片。当前 `3` 件物品使用 `2*2` 网格,取前 `3` 格。
|
||||
7. 将素材图和每张独立图片上传到 OSS,其中独立图片作为草稿页素材预览和后续 Rodin 图生模型参考图。
|
||||
8. 调用现有 SpacetimeDB compile procedure 写入草稿,并把本次生成的独立物品图片列表序列化写入 `match3d_work_profile.generated_item_assets_json`。这一步对标拼图的 `save_puzzle_generated_images`:生成资产不能只挂在本次 HTTP response 上,否则退出结果页后从草稿架读取 `getMatch3DWorkDetail` 会丢失素材列表。
|
||||
9. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息,独立图片状态为 `image_ready`,模型字段保持为空;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 恢复同一批素材。
|
||||
7. 将素材图和每张独立图片上传到 OSS,其中独立图片作为草稿页素材预览和 Rodin 图生模型参考图。
|
||||
8. 使用每张独立图片作为参考图,并行调用 Hyper3D Rodin 图生模型;所有 3D 模型任务必须在同一阶段同时提交、同时轮询状态、同时下载并转存 OSS,禁止逐个物品串行等待模型完成。每个任务按官方 minimal example 轮询状态;只有 `jobs` 全部进入 `Done` 才能视为任务完成,任一 job `Failed` 则失败。完成后选择 `.glb` 下载文件,并把 GLB 转存到 OSS。Rodin 的 `subscriptionKey` 是上游 opaque token,不做 256 字符这类短文本长度限制。Rodin 任务状态进入完成态后,下载列表仍可能延迟发布;后端必须对下载列表继续轮询,并兼容 `url`、`downloadUrl`、`fileUrl`、`signedUrl` 等下载字段别名,只有预览图而没有模型文件时不能伪装成 GLB 成功。
|
||||
9. 调用现有 SpacetimeDB compile procedure 写入草稿,并把本次生成的独立物品图片和模型列表序列化写入 `match3d_work_profile.generated_item_assets_json`。这一步对标拼图的 `save_puzzle_generated_images`:生成资产不能只挂在本次 HTTP response 上,否则退出结果页后从草稿架读取 `getMatch3DWorkDetail` 会丢失素材列表。
|
||||
10. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息,模型生成成功的素材状态为 `model_ready`;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 恢复同一批素材。
|
||||
|
||||
若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅` 与本地标签兜底,不阻断素材生成;但描述仍保持空字符串。
|
||||
|
||||
草稿生成阶段不调用 Hyper3D Rodin,不等待 `subscriptionKey`,也不下载模型文件;Rodin 生成只在结果页 `3D素材` Tab 由用户手动触发。手动生成得到的上游下载 URL 仍不得直接写入 Match3D profile,后续正式资产绑定以独立技术方案为准。
|
||||
草稿生成阶段会调用 Hyper3D Rodin 并等待 GLB 下载完成;前端 `match3d_compile_draft` action 请求超时必须覆盖该长耗时链路,当前 Match3D client 使用 20 分钟超时。Rodin 单模型状态轮询预算为 10 分钟,下载列表发布轮询预算为 5 分钟;由于 3 个模型并行生成,总耗时按最慢模型计算,不能按模型数量线性叠加。结果页 `3D素材` Tab 直接加载已生成模型;用户点击 `重新生成` 时再复用 Rodin 安全代理,首版重新生成只更新当前页面内预览状态,后续正式资产绑定以独立技术方案为准。
|
||||
|
||||
## 4. 图片提示词
|
||||
|
||||
@@ -83,12 +84,34 @@ generated-match3d-assets
|
||||
|
||||
```text
|
||||
generated-match3d-assets/{sessionId}/{profileId}/material-sheet/{taskId}/sheet.png
|
||||
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/image.png
|
||||
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/image/image.png
|
||||
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/model/{taskUuid}/model.glb
|
||||
```
|
||||
|
||||
`itemSlug` 必须带 `itemId` 前缀,例如 `match3d-item-1-item`。中文物品名清洗后可能都退回 `item`,不能只用物品名做路径,否则多张切割图会写到同一个 object key,导致草稿页预览图全部一致。
|
||||
|
||||
HTTP DTO 同时返回 `imageSrc`、`imageObjectKey`、空的 `modelSrc`、空的 `modelObjectKey` 和 `status = image_ready`。前端预览图片继续走 `ResolvedAssetImage` 换签;后续手动生成的模型文件也必须通过 `useResolvedAssetReadUrl` / `/api/assets/read-url` 换签后打开,不直接请求裸 `/generated-match3d-assets/...` 路径。
|
||||
HTTP DTO 同时返回 `imageSrc`、`imageObjectKey`、`modelSrc`、`modelObjectKey`、`modelFileName`、`taskUuid`、`subscriptionKey` 和 `status`。模型生成成功后 `status = model_ready`;若后续允许部分模型失败降级,失败素材必须带 `error`,且不能伪装成可预览模型。前端模型预览必须通过 `/api/assets/read-bytes` 读取私有 GLB 字节并转成 Blob URL 后交给 Three.js,不直接请求裸 `/generated-match3d-assets/...` 路径。
|
||||
|
||||
## 5.1 运行态模型消费
|
||||
|
||||
生成模型不仅用于结果页预览,也必须进入游戏运行态。运行态入口的传递链路为:
|
||||
|
||||
```text
|
||||
Match3DWorkProfile / PlatformMatch3DGalleryCard
|
||||
-> Match3DRuntimeShell(generatedItemAssets)
|
||||
-> Match3DPhysicsBoard / Match3DTrayPreviewBoard
|
||||
```
|
||||
|
||||
`Match3DPhysicsBoard` 与 `Match3DTrayPreviewBoard` 按运行快照中的 `itemTypeId` 稳定排序后,把生成出的模型顺序映射到对应类型。当前 MVP 固定 `clearCount = 3`,因此 `match3d-type-01/02/03` 分别对应生成列表的第 `1/2/3` 个模型;后续恢复更多物品生成时,后端必须继续保证 `generatedItemAssets` 顺序与类型编号一致。
|
||||
|
||||
前端加载规则:
|
||||
|
||||
1. 优先读取 `modelSrc`;为空时使用 `modelObjectKey`。
|
||||
2. 通过 `readAssetBytes` 调用 `/api/assets/read-bytes`,由同源后端读取 OSS 私有对象字节。
|
||||
3. 使用 Three.js `GLTFLoader.parseAsync` 解析 GLB 字节,并按物品类型缓存模板。
|
||||
4. 场内每个物品和备选栏预览都从模板 clone 独立对象,点击命中继续写入 `itemInstanceId`。
|
||||
5. 物理碰撞和边界仍沿用现有 `visualKey` 的程序化几何,生成 GLB 只替换视觉模型,不承接规则真相。
|
||||
6. 模型缺失、读取失败或 WebGL 回退时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算。
|
||||
|
||||
## 6. 自动保存与草稿恢复
|
||||
|
||||
@@ -135,4 +158,4 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml
|
||||
```
|
||||
|
||||
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_API_KEY` 和 OSS 访问变量;`HYPER3D_API_KEY` 只在结果页手动生成 3D 模型时需要。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`。
|
||||
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_API_KEY`、`HYPER3D_API_KEY` 和 OSS 访问变量。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`。
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
|
||||
## 3. Rodin 任务边界
|
||||
|
||||
前端只维护当前页面内的临时重新生成任务状态:
|
||||
前端只维护当前页面内的临时重新生成任务状态;草稿生成得到的正式模型资产从 `generatedItemAssets.modelSrc` 恢复:
|
||||
|
||||
1. 素材槽位名称。
|
||||
2. 模型预览。草稿生成的 `/generated-match3d-assets/...` GLB 必须通过同源 `/api/assets/read-bytes` 由后端换签并读取字节,前端再转成 Blob URL 后交给 Three.js GLTFLoader,避免浏览器直接 `fetch` OSS 签名 URL 时被 CORS 拦截。
|
||||
3. 图生模型参考图只作为重新生成的隐藏输入来源,不在详情页展示。上传图片在前端直接读成 Data URL;草稿生成的 `/generated-match3d-assets/...` 图片必须通过 `/api/assets/read-bytes` 转成 Data URL 后提交给 Hyper3D。
|
||||
4. Hyper3D `taskUuid` 与 `subscriptionKey`。
|
||||
5. 查询到的状态、进度与下载文件列表。
|
||||
4. Hyper3D `taskUuid` 与 `subscriptionKey` 仅用于重新生成过程,不在详情页展示。
|
||||
5. 查询到的状态、进度与下载文件列表仅作为内部状态,不在详情页展示。
|
||||
|
||||
正式资产链后续再接:
|
||||
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
|
||||
## 背景
|
||||
|
||||
创作中心的模板 Tab、平台创作类型弹层和旧“新建作品”卡片配置都依赖同一组玩法模板。此前入口开放状态、隐藏状态和中文文案集中写在 `src/components/platform-entry/platformEntryCreationTypes.ts` 与入口组件中,后续切换玩法开放节奏时容易出现多个入口不一致。
|
||||
创作中心的模板 Tab、平台创作类型弹层和旧“新建作品”卡片配置都依赖同一组玩法模板。此前入口开放状态、隐藏状态和中文文案集中写在前端配置与入口组件中,后续切换玩法开放节奏时容易出现多个入口不一致。当前入口配置事实源已经迁移到 SpacetimeDB,由 `api-server` 通过 `GET /api/creation-entry/config` 下发。
|
||||
|
||||
## 落地规则
|
||||
|
||||
1. 新建作品入口配置统一放在 `src/config/newWorkEntryConfig.ts`。
|
||||
1. 新建作品入口配置统一存放在 SpacetimeDB 的 `creation_entry_config` / `creation_entry_type_config` 表;默认种子位于 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs`。
|
||||
2. `visible` 控制玩法是否展示在创作 Tab 模板入口、新建作品入口和创作类型弹层中。
|
||||
3. `open` 控制玩法是否允许点击创建;`open: false` 时入口保持展示但禁用。
|
||||
3. `open` 控制玩法是否允许点击创建以及对应 runtime/API 路由是否放行;`open: false` 时入口保持展示但禁用,并由 `api-server` 熔断对应玩法 API。
|
||||
4. `title`、`subtitle`、`badge` 控制玩法卡片文案。
|
||||
5. `startCard` 控制旧创作中心顶部新建作品模块的标题、辅助文案和移动端角标文案;当前创作 Tab 首屏标题固定在 `PlatformEntryFlowShellImpl.tsx`,不再由 `startCard` 控制。
|
||||
6. `typeModal` 控制平台创作类型弹层标题和描述。
|
||||
7. 入口排序仍遵循“可创建玩法在前,未开放玩法在后”;同组内部沿用配置顺序。
|
||||
8. `creative-agent` 可以继续保留运行链路,但默认 `visible: false`,不出现在创作 Tab 模板入口。
|
||||
9. 前端 `src/components/platform-entry/platformEntryCreationTypes.ts` 只做展示派生,不再承载默认入口配置。
|
||||
|
||||
## 当前状态
|
||||
|
||||
@@ -23,17 +24,17 @@
|
||||
| 大鱼吃小鱼 | 否 | 是 | 功能仍保留,不在新建作品入口展示 |
|
||||
| 拼图 | 是 | 是 | 创作 Tab 默认选中并内嵌展示拼图创作表单,提交后进入拼图草稿生成 |
|
||||
| 抓大鹅 | 是 | 是 | 点击后进入抓大鹅 Match3D Agent 共创工作台 |
|
||||
| 方洞挑战 | 是 | 是 | 点击后进入方洞挑战 Agent 共创工作台,支持草稿、结果页、发布、试玩、作品架与广场 |
|
||||
| 方洞挑战 | 否 | 是 | 创作页入口暂时完全隐藏,既有草稿、结果页、发布、试玩、作品架与广场链路保留 |
|
||||
| AIRP | 是 | 否 | 保留入口,显示敬请期待 |
|
||||
| 视觉小说 | 是 | 是 | 点击后进入视觉小说创作工作台 |
|
||||
| 智能创作 | 否 | 是 | 入口隐藏,既有 `creative-agent` 链路保留 |
|
||||
|
||||
## 验收
|
||||
|
||||
1. 修改 `src/config/newWorkEntryConfig.ts` 后,创作 Tab 模板入口、创作中心顶部卡带和平台创作类型弹层应同步变化。
|
||||
1. 修改 SpacetimeDB 入口配置后,创作 Tab 模板入口、创作中心顶部卡带和平台创作类型弹层应同步变化。
|
||||
2. 隐藏玩法不触发入口预加载,也不出现在新建作品入口中。
|
||||
3. 未开放玩法点击态保持禁用,不应进入鉴权或创建会话链路。
|
||||
4. 已开放玩法点击后必须进入对应创建链路;若用户未登录,先走登录保护。
|
||||
5. 创作 Tab 首屏应显示“10分钟创作一个精品互动玩法”,并默认展示拼图创作表单。
|
||||
6. 智能创作入口隐藏后,不应出现“Hi, 朋友”“问一问百梦”或“一句话生成闪应用”等旧首页入口。
|
||||
7. 方洞挑战作品发布后应生成 `SH-` 作品号,并能从作品架、广场详情和试玩 runtime 回到同一作品详情。
|
||||
7. 方洞挑战入口隐藏后,不应出现在创作 Tab 模板入口、创作中心顶部卡带、平台创作类型弹层和创作页作品架中;既有 `SH-` 作品号、广场详情和试玩 runtime 链路不因此删除。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
- [CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md](./CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md):冻结儿童动作识别互动玩法 Demo 固定热身关的开发落地规格,覆盖横屏展示、摄像头背景虚化、角色剪影、绿色圆环 2 秒保持、动作教学、当前会话内空间边界记录和后续关卡安全暂停规则。
|
||||
- [RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md](./RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md):记录运行态输入设备抽象层,明确鼠标、触控、mocap 等设备统一归一为通用拖拽语义,玩法组件只负责解释目标和落点。
|
||||
- [RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md](./RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md):记录 `server-rs` Cargo 依赖集中配置口径,第三方版本和 workspace 内部 crate path 统一维护在根 `server-rs/Cargo.toml`,成员 crate 只保留 feature/optional 差异。
|
||||
- [RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md](./RUST_WORKSPACE_DEPENDENCY_CONSOLIDATION_2026-05-07.md):记录 `server-rs` Cargo 依赖集中配置口径,第三方版本和 workspace 内部 crate path 统一维护在根 `server-rs/Cargo.toml`,成员 crate 只保留 feature/optional 差异;同时冻结 `shared-contracts` 不得反向依赖 `platform-*`,避免 SpacetimeDB 模块发布时拉入 `wasm-bindgen`。
|
||||
- [DEV_RUST_STACK_PORT_CONFLICT_PRECHECK_2026-05-09.md](./DEV_RUST_STACK_PORT_CONFLICT_PRECHECK_2026-05-09.md):记录本地完整 Rust 栈启动时 `api-server`、主站 Vite 和后台 Vite 端口占用的误判根因、脚本预检策略和 Windows 排障命令。
|
||||
- [VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md](./VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md):记录 GPT-image-2 图片生成从 APIMart 迁移到 VectorEngine `gpt-image-2-all` 的接口、环境变量、尺寸映射、错误口径和验收命令。
|
||||
- [SPACETIMEDB_PUBLISH_SCCACHE_FALLBACK_2026-05-09.md](./SPACETIMEDB_PUBLISH_SCCACHE_FALLBACK_2026-05-09.md):记录本地 `spacetime publish` 被 sccache wrapper 通信异常阻断时的根因、debug 构建参数口径和手动排障命令。
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
4. 成员 crate 只保留自身需要表达的差异,例如 `features`、`optional = true` 或 target-specific dependency。
|
||||
5. 需要关闭 default features 的依赖,应优先在 workspace 根依赖中声明;成员 crate 不再重复覆盖同一项。
|
||||
6. `module-assets` 这类有默认服务端 feature 的领域 crate,在 workspace 根内按 `default-features = false` 维护;需要服务端 OSS/HTTP 能力的 adapter crate 显式启用 `features = ["server-service"]`。
|
||||
7. `shared-contracts` 只能承载前后端公开 DTO 和轻量枚举,禁止直接依赖 `platform-*` 服务实现 crate;需要把平台实现响应转换为公开 DTO 时,转换函数放在 `api-server` 等 adapter 层。
|
||||
8. `spacetime-module` 的传递依赖不能包含 `reqwest`、`web-sys`、`js-sys`、`wasm-bindgen` 等 Web/HTTP 客户端链路;发布前可用 `cargo tree -i wasm-bindgen --manifest-path server-rs/Cargo.toml -p spacetime-module --target wasm32-unknown-unknown` 排查。
|
||||
|
||||
## 3. 本次收敛范围
|
||||
|
||||
@@ -53,3 +55,29 @@ npm.cmd run check:encoding -- docs/technical/RUST_WORKSPACE_DEPENDENCY_CONSOLIDA
|
||||
```
|
||||
|
||||
若仅改 Cargo 依赖配置且未触碰 API smoke 相关代码,不强制启动 `npm run api-server`;若后续改动同时涉及 API 路由、SpacetimeDB facade 或运行时行为,仍按 `AGENTS.md` 和 DDD 文档执行后端 smoke。
|
||||
|
||||
## 6. SpacetimeDB 模块依赖边界补充
|
||||
|
||||
2026-05-11 本地重置 SpacetimeDB 并重新发布 `xushi-p4wfr` 时,`spacetime publish` 在 Rust 编译成功后报 `wasm-bindgen detected`。排查命令显示链路为:
|
||||
|
||||
```text
|
||||
spacetime-module -> module-runtime -> shared-contracts -> platform-oss -> reqwest -> wasm-bindgen
|
||||
```
|
||||
|
||||
根因是 `shared-contracts` 为了复用 OSS 直传/读签名返回类型,直接依赖了 `platform-oss`。这违反 DDD 分层边界:契约 crate 不能依赖平台副作用实现,否则所有引用契约的纯领域和 SpacetimeDB 模块都会被迫拉入 HTTP client。
|
||||
|
||||
修正口径:
|
||||
|
||||
1. `shared-contracts::assets` 定义独立的公开 DTO 和 `DirectUploadObjectAccess` 轻量枚举。
|
||||
2. `platform-oss` 保持 OSS 签名、读写请求和错误分类实现,不被契约层引用。
|
||||
3. `api-server::assets` 负责把 `platform_oss::OssPostObjectResponse` / `OssSignedGetObjectUrlResponse` 转成 `shared-contracts` DTO。
|
||||
4. 后续新增外部平台能力时,重复使用这个边界:平台 crate 不得被 `shared-contracts`、`module-*` 或 `spacetime-module` 反向依赖。
|
||||
|
||||
最小验证:
|
||||
|
||||
```powershell
|
||||
cargo tree -i wasm-bindgen --manifest-path server-rs\Cargo.toml -p spacetime-module --target wasm32-unknown-unknown
|
||||
cargo check -p shared-contracts --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p api-server --manifest-path server-rs\Cargo.toml
|
||||
spacetime publish xushi-p4wfr --server local --module-path server-rs\crates\spacetime-module --build-options="--debug" -c=on-conflict --yes
|
||||
```
|
||||
|
||||
@@ -72,8 +72,8 @@ SELECT * FROM auth_store_snapshot WHERE snapshot_id = 'default';
|
||||
### `user_account`
|
||||
|
||||
- 作用:用户账号主表,保存用户名、公开百梦号、手机号掩码、登录方式、密码登录开关、token 版本和默认不前端展示的运营标签。
|
||||
- 结构:`user_id PK: String`, `public_user_code: String`, `username: String`, `display_name: String`, `avatar_url: Option<String>`, `phone_number_masked: Option<String>`, `phone_number_e164: Option<String>`, `login_method: String`, `binding_status: String`, `wechat_bound: bool`, `password_hash: String`, `password_login_enabled: bool`, `token_version: u64`, `user_tags: Vec<String>`。
|
||||
- 说明:`user_tags` 默认空数组,只允许后端白名单投影到特定业务接口;不得在登录态、个人资料等通用前端响应中直接暴露。
|
||||
- 结构:`user_id PK: String`, `public_user_code: String`, `username: String`, `display_name: String`, `avatar_url: Option<String>`, `phone_number_masked: Option<String>`, `phone_number_e164: Option<String>`, `login_method: String`, `binding_status: String`, `wechat_bound: bool`, `password_hash: String`, `password_login_enabled: bool`, `token_version: u64`, `user_tags: Option<Vec<String>>`。
|
||||
- 说明:`user_tags` 数据库默认 `None`,业务读取时按空数组归一化;只允许后端白名单投影到特定业务接口,不得在登录态、个人资料等通用前端响应中直接暴露。
|
||||
- 索引:`username`, `public_user_code`。
|
||||
|
||||
```sql
|
||||
@@ -256,11 +256,11 @@ SELECT * FROM profile_redeem_code_usage WHERE user_id = '<user_id>';
|
||||
|
||||
### `profile_invite_code`
|
||||
|
||||
- 作用:用户邀请中心的邀请码主表,也承载后台运营预置邀请码和使用后授予账号的运营标签。
|
||||
- 结构:`user_id PK: String`, `invite_code: String`, `metadata_json: String`, `created_at: Timestamp`, `updated_at: Timestamp`, `starts_at: Option<Timestamp>`, `expires_at: Option<Timestamp>`, `granted_user_tags: Vec<String>`。
|
||||
- 作用:用户邀请中心的邀请码主表,也承载后台运营预置邀请码和使用后授予账号的运营标签配置。
|
||||
- 结构:`user_id PK: String`, `invite_code: String`, `metadata_json: String`, `created_at: Timestamp`, `updated_at: Timestamp`, `starts_at: Option<Timestamp>`, `expires_at: Option<Timestamp>`。
|
||||
- 索引:主键 `user_id`,唯一索引 `invite_code`。
|
||||
- 后台读取:`GET /admin/api/profile/invite-codes` 只返回 `user_id` 以 `admin:` 开头的后台预置码;普通用户自己的邀请码不得进入后台运营列表。
|
||||
- 说明:`granted_user_tags` 默认空数组;用户注册填写该邀请码后合并进 `user_account.user_tags`,不回改历史用户。
|
||||
- 说明:使用该邀请码后授予的标签存放在 `metadata_json.userTags`,服务端兼容读取 `metadata_json.user_tags`;用户注册填写该邀请码后合并进 `user_account.user_tags`,不回改历史用户。
|
||||
|
||||
```sql
|
||||
SELECT * FROM profile_invite_code WHERE user_id = '<user_id>';
|
||||
@@ -665,7 +665,7 @@ SELECT * FROM match3d_agent_message WHERE session_id = '<session_id>' ORDER BY c
|
||||
|
||||
- 作用:抓大鹅 Match3D 作品主表,保存作品基础信息、配置、发布状态、游玩次数和草稿生成出的独立物品素材引用。
|
||||
- 结构:`profile_id PK: String`, `owner_user_id: String`, `source_session_id: String`, `author_display_name: String`, `game_name: String`, `theme_text: String`, `summary_text: String`, `tags_json: String`, `cover_image_src: String`, `cover_asset_id: String`, `clear_count: u32`, `difficulty: u32`, `config_json: String`, `publication_status: String`, `play_count: u32`, `updated_at: Timestamp`, `published_at: Option<Timestamp>`, `generated_item_assets_json: Option<String>`。
|
||||
- 说明:`generated_item_assets_json` 保存 `Match3DGeneratedItemAsset` 数组 JSON,用于草稿页退出后从作品架重进时恢复 `3D素材` Tab 中的切割图片预览;基础信息自动保存和发布必须保留该字段。
|
||||
- 说明:`generated_item_assets_json` 保存 `Match3DGeneratedItemAsset` 数组 JSON,用于草稿页退出后从作品架重进时恢复 `3D素材` Tab 中的切割图片和 GLB 模型预览;运行态也通过该字段拿到 `modelSrc` / `modelObjectKey` 并优先渲染生成模型。基础信息自动保存和发布必须保留该字段。
|
||||
- 索引:`owner_user_id`, `publication_status`。
|
||||
|
||||
```sql
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 用户标签、邀请码授予与拼图榜单展示方案
|
||||
|
||||
更新时间:`2026-05-10`
|
||||
更新时间:`2026-05-11`
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本次新增用户标签系统的最小闭环:
|
||||
|
||||
1. `user_account` 增加账号标签字段,默认空。
|
||||
2. 后台预置邀请码可配置授予标签。
|
||||
1. `user_account` 增加账号标签字段,数据库默认空,业务读取时按空数组处理。
|
||||
2. 后台预置邀请码可通过原有 `metadata` 字段配置授予标签。
|
||||
3. 用户填写带标签的邀请码后,把标签合并到自己的账号。
|
||||
4. 标签默认不在前端资料页、邀请中心或通用接口展示。
|
||||
5. 拼图排行榜仅对白名单标签做展示,首版只展示 `北科`。
|
||||
@@ -16,19 +16,21 @@
|
||||
|
||||
### `user_account.user_tags`
|
||||
|
||||
- 类型:`Vec<String>`。
|
||||
- 默认:空数组。
|
||||
- 类型:`Option<Vec<String>>`。
|
||||
- 默认:`None`,业务层读取时统一按空数组处理。
|
||||
- 语义:账号级运营标签,属于后台与服务端投影数据,不作为普通前端个人资料字段。
|
||||
- 写入:首版只由邀请码兑换链路合并写入。
|
||||
- 迁移:旧迁移包和旧数据库按空数组兼容。
|
||||
- 迁移:旧迁移包和旧数据库按 `null` 兼容,再由业务层归一化为空数组。
|
||||
|
||||
### `profile_invite_code.granted_user_tags`
|
||||
### `profile_invite_code.metadata_json.userTags`
|
||||
|
||||
- 类型:`Vec<String>`。
|
||||
- 默认:空数组。
|
||||
- 类型:`metadata_json` 对象里的 `userTags: string[]`。
|
||||
- 默认:字段缺失或空数组时不授予标签。
|
||||
- 语义:使用该邀请码后授予被邀请账号的标签列表。
|
||||
- 范围:后台运营预置码和普通用户个人邀请码都可存字段,但后台表单首版只允许管理员配置预置码。
|
||||
- 迁移:旧邀请码按空数组兼容。
|
||||
- 存储:不再新增或使用独立的邀请码标签列;后台保存时把用户标签写回 `metadata.userTags`。
|
||||
- 解析:服务端优先读取 `metadata_json.userTags`,并兼容解析 `metadata_json.user_tags`。
|
||||
- 迁移:旧邀请码缺少 `metadata_json` 时按 `{}` 兼容;旧迁移包里已废弃的独立字段会在导入时丢弃。
|
||||
|
||||
## 3. 标签归一化
|
||||
|
||||
@@ -45,35 +47,38 @@
|
||||
|
||||
1. 写入 `profile_referral_relation`。
|
||||
2. 发放原有双方奖励。
|
||||
3. 读取 `profile_invite_code.granted_user_tags`。
|
||||
3. 从 `profile_invite_code.metadata_json` 解析 `userTags` / `user_tags`。
|
||||
4. 将这些标签合并进 `user_account.user_tags`。
|
||||
|
||||
管理员更新邀请码时,`grantedUserTags` 代表覆盖该邀请码之后授予的标签集合;空数组代表不授予标签。更新邀请码不会回溯修改已经使用过该邀请码的账号。
|
||||
管理员更新邀请码时,后台表单里的用户标签会覆盖写入 `metadata.userTags`;空数组代表不授予标签。更新邀请码不会回溯修改已经使用过该邀请码的账号。
|
||||
|
||||
## 5. API 契约
|
||||
|
||||
后台邀请码 upsert 请求增加:
|
||||
后台邀请码 upsert 请求继续只提交 `metadata`,标签写在 `metadata.userTags` 中:
|
||||
|
||||
```json
|
||||
{
|
||||
"inviteCode": "BEIKE2026",
|
||||
"grantedUserTags": ["北科"],
|
||||
"metadata": {},
|
||||
"metadata": {
|
||||
"userTags": ["北科"]
|
||||
},
|
||||
"startsAt": null,
|
||||
"expiresAt": null
|
||||
}
|
||||
```
|
||||
|
||||
后台邀请码列表和 upsert 返回增加同名字段:
|
||||
后台邀请码列表和 upsert 返回继续回传 `metadata`:
|
||||
|
||||
```json
|
||||
{
|
||||
"inviteCode": "BEIKE2026",
|
||||
"grantedUserTags": ["北科"]
|
||||
"metadata": {
|
||||
"userTags": ["北科"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
用户侧邀请中心、账号资料、登录返回和普通 profile 接口不返回 `userTags`。
|
||||
后台表单展示时从 `metadata.userTags` 回显用户标签;用户侧邀请中心、账号资料、登录返回和普通 profile 接口不返回 `userTags`。
|
||||
|
||||
## 6. 拼图排行榜展示
|
||||
|
||||
@@ -94,9 +99,10 @@
|
||||
|
||||
## 7. 验收
|
||||
|
||||
1. 新账号 `user_account.user_tags` 默认为空。
|
||||
2. 后台创建邀请码时可填写 `北科`,列表和结果面板可回显。
|
||||
1. 新账号 `user_account.user_tags` 数据库默认为 `None`,业务读取为空数组。
|
||||
2. 后台创建邀请码时可填写 `北科`,请求和返回的 `metadata.userTags` 可回显。
|
||||
3. 用户填写该邀请码后,账号表 `user_tags` 包含 `北科`。
|
||||
4. 不带标签的邀请码不改变账号标签。
|
||||
5. 拼图排行榜中带 `北科` 的用户昵称下方显示 `北科`,其它标签不显示。
|
||||
6. 执行 `npm run check:encoding`、`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`,并按影响范围执行后台 typecheck / 拼图前端测试。
|
||||
6. 生成 SpacetimeDB bindings 后,不再出现独立的邀请码标签字段。
|
||||
7. 执行 `npm run check:encoding`、`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`,并按影响范围执行后台 typecheck / 拼图前端测试。
|
||||
|
||||
Reference in New Issue
Block a user