This commit is contained in:
2026-05-14 13:42:12 +08:00
112 changed files with 5766 additions and 626 deletions

View File

@@ -0,0 +1,343 @@
# Genarrative 视觉小说“一句话生成”最小闭环落地计划
生成时间2026-05-13 11:22
工作区:`C:/proj/Genarrative/.worktrees/hermes-visual-novel`
参考文档:`C:/Users/DSK/Documents/Interactive-fiction/一句话生成视觉小说整体流程总结.md`
## 1. 目标
把 Interactive-fiction 总结文档中的“一句话生成视觉小说”流程,映射并落地到 Genarrative 现有视觉小说能力中,优先做成一个可端到端验证的最小闭环:
1. 用户在视觉小说入口输入一句话并选择画风。
2. 前端进入生成过程页,展示分阶段进度。
3. 后端创建视觉小说创作会话,并基于 seedText 生成 `VisualNovelResultDraft`
4. 生成完成后进入草稿结果页,可看到世界观、角色、场景、剧情阶段、开场选择。
5. 草稿可编译/保存为作品 profile并进入视觉小说运行态测试/正式游玩。
本计划只覆盖 Genarrative 内部最小闭环,不引入 Interactive-fiction 原项目的独立 TXT 播放记录、分享播放包、外部活动运营、独立账号/交易/资产系统。
## 2. 当前上下文与已发现实现
### 2.1 Interactive-fiction 总结文档提炼
参考文档将整体流程分为:
- 输入侧:一句话创意、主题/风格、可选文档或素材。
- 生成侧:理解意图、扩展世界观、角色、场景、剧情阶段、开场与选择。
- 编辑侧:草稿页可查看和调整生成结果。
- 运行侧:从草稿进入视觉小说游玩,支持剧情推进、玩家选择、历史与状态。
- 资产侧:角色立绘、背景、音乐/音效可作为后续增强,最小闭环可先使用文字描述与空资产占位。
### 2.2 Genarrative 已有实现基础
已确认项目中视觉小说相关能力并非从零开始:
- 前端入口表单:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- 已有“一句话创作” textarea、6 个视觉画风选项、提交按钮“生成视觉小说草稿”。
- 前端入口 payload/progress
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- 已有 `VisualNovelEntryFormPayload`、锚点展示、一句话/画风生成进度步骤。
- 前端平台主流程:
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- 已接入 `createVisualNovelDraftFromForm`,会创建 session、stream message、进入 `visual-novel-generating`,完成后进入 `visual-novel-result`
- 前端 API client
- `src/services/visual-novel-creation/visualNovelCreationClient.ts`
- 已封装 session/message/action/compile 接口。
- 共享契约:
- `packages/shared/src/contracts/visualNovel.ts`
- 已定义 `VisualNovelResultDraft`、world/characters/scenes/storyPhases/opening/runtimeConfig/work/run/history 等结构。
- 后端 API
- `server-rs/crates/api-server/src/visual_novel.rs`
- 已有创建 session、发消息、流式消息、执行 action、compile、work、runtime run 等接口。
- 后端 prompt
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- 已有 `VISUAL_NOVEL_CREATION_SYSTEM_PROMPT`、结构化输出契约、runtime GM prompt、repair prompt。
- SpacetimeDB 模块:
- `server-rs/crates/spacetime-module/src/visual_novel.rs`
- 已有 session/message/work/run/history/event 表与 procedure。
- 文档参考:
- `docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md`
- `docs/technical/VISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.md`
- `docs/technical/VISUAL_NOVEL_PROMPT_AND_LLM_TOOLS_VN03_2026-05-05.md`
### 2.3 关键实现判断
当前项目已经实现了视觉小说的主要骨架,本次不应大规模重写。更合理的落地方式是补齐“一句话生成”闭环中最容易断裂的点:
- 入口输入与画风信息是否被稳定传给后端 prompt。
- 后端生成 draft 后是否自动保存/关联可编辑 work profile。
- 生成过程页是否能清晰展示 Interactive-fiction 文档中提到的阶段。
- 结果页是否有足够的字段展示与继续游玩入口。
- 运行态是否能基于 opening/choices 正常启动,而不依赖尚未生成的图片/音乐资产。
## 3. 拟采用方案
### 3.1 最小闭环范围
本次优先实现:
1. “一句话 + 视觉画风”作为 `sourceMode: 'idea'` 的 seedText。
2. 后端生成完整 `VisualNovelResultDraft`,包括:
- world
- 3-6 个角色
- 3-8 个场景
- 3-6 个剧情阶段
- opening narration/firstDialogue/2-4 个 choices
- runtimeConfig
3. 若 LLM 输出失败,使用 repair 或确定性 fallback保证可回到草稿页并显示错误/警告。
4. 结果页支持保存/编译为 work profile。
5. work profile 支持启动 runtime runopening 能展示初始场景、旁白、对话和选择。
暂不做或仅预留:
- 真实图片/音乐生成队列。
- 多文档解析导入的完整链路。
- 复杂分镜/节点图编辑器。
- 外部 Interactive-fiction 项目的播放器、TXT 记录包、分享活动、独立账号系统。
### 3.2 与 Genarrative 架构的映射
| Interactive-fiction 概念 | Genarrative 落点 |
| --- | --- |
| 一句话创意 | `VisualNovelEntryFormPayload.ideaText` / `seedText` |
| 画风/主题 | `seedText` 中的“视觉画风/画风要求”,后续可结构化为 metadata |
| 世界观设定 | `VisualNovelResultDraft.world` |
| 角色设定 | `VisualNovelResultDraft.characters` |
| 场景设定 | `VisualNovelResultDraft.scenes` |
| 剧情阶段/章节 | `VisualNovelResultDraft.storyPhases` |
| 开场文本与选项 | `VisualNovelResultDraft.opening` |
| 运行时剧情推进 | `VisualNovelRuntimeStep[]` + run snapshot/history |
| 发布/作品库 | `VisualNovelWorkProfileRecord` / works API |
## 4. 分步计划
### Step 1补齐入口 payload 与生成过程语义
涉及文件:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
任务:
1. 保持现有 6 个画风选项,但确认每个 option 的 prompt 会进入 `seedText`
2. 将生成过程阶段从当前 3 步细化为更贴合参考文档的 4-5 步,例如:
- 理解一句话创意
- 扩展世界观与玩家身份
- 设计角色/场景/剧情阶段
- 生成开场与选择
- 准备可编辑草稿
3. 生成过程页的 anchor 保留“一句话”和“视觉画风”,必要时增加“生成目标:视觉小说草稿”。
4. 确认 `createVisualNovelDraftFromForm` 对失败状态会保留返回入口/重试能力。
验收点:提交一句话后能进入 `visual-novel-generating`,看到阶段进度;完成后进入 `visual-novel-result`
### Step 2增强后端 creation prompt 与 fallback 约束
涉及文件:
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `server-rs/crates/api-server/src/visual_novel.rs`
- 如已有 domain crate`server-rs/crates/module-visual-novel/**` 或相关 normalize/validate 文件
任务:
1. 在 creation prompt 中显式吸收 Interactive-fiction 的“一句话生成”目标:
- 从 seedText 提取核心创意、视觉风格、故事类型。
- 生成可直接运行的 opening 和 choices。
- 图片/音乐资产先置 null但必须有可生成图像的描述。
2. 强化输出约束:
- `opening.sceneId` 必须指向存在且 availability 为 `opening` 的 scene。
- `opening.initialChoices` 必须 2-4 个。
- `storyPhases[0]` 必须包含 opening scene 和主要角色。
- `publishReady` 的判定与 validationIssues 一致。
3. 检查 `submit_visual_novel_message_turn` / `resolve_action_draft` / compile 相关代码:
- 如果 LLM 失败,是否已有 fallback没有则补确定性 fallback draft。
- 如果 draft 不完整,是否会 normalize/repair 并写入 session。
4. 保留现有“不要输出旧 TXT 播放记录、分享播放包、外部商业字段”的约束,避免把参考项目的外部概念误并入 Genarrative。
验收点:后端给定 seedText 时,返回 session.draft 不为空且满足共享契约。
### Step 3确认草稿结果页、保存/编译与作品库链路
涉及文件:
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- `src/components/visual-novel-creation/**`
- `src/services/visual-novel-works*` 或相关 visual novel works client
- `server-rs/crates/api-server/src/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
任务:
1. 查找并确认 `visual-novel-result` 页面组件:
- 是否显示 workTitle/workDescription/world/characters/scenes/storyPhases/opening。
- 是否有保存/发布/开始试玩按钮。
2. 确认 `compileVisualNovelWorkProfile``executeVisualNovelAction({kind:'compile_work_profile'})` 会生成/更新 work profile。
3. 确认作品架上使用 `profileId` 而不是 sessionId 作为稳定作品 ID。
4. 如果结果页缺少“一句话来源/画风”的可视化提示,可在结果页或 summary 中补轻量展示,避免用户以为画风丢失。
验收点:生成完成后能保存为作品;作品出现在“我的作品/创作架”;再次打开能读取同一 draft。
### Step 4确认运行态 opening 闭环
涉及文件:
- `src/components/visual-novel-runtime/**`
- `src/services/visual-novel-runtime*`
- `server-rs/crates/api-server/src/visual_novel.rs`
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
任务:
1. 启动 visual novel work run 时,优先使用 `draft.opening` 生成第一轮 runtime snapshot/history。
2. 如果没有图片/音乐,前端 runtime shell 必须可用文字 fallback不应白屏或阻断游玩。
3. 玩家选择 `choice` 后,后端 runtime GM prompt 生成下一轮 `VisualNovelRuntimeStep[]`
4. 确认正式游玩入口调用 `work_play_start`,并满足已有埋点约定:
- `scope_kind=work`
- `scope_id=稳定作品 ID`
- metadata 包含 `playType/workId/sourceRoute/userId` 等。
验收点:从生成出的作品进入运行态,能看到 opening 并点击至少一个选择推进一轮。
### Step 5补测试与文档
涉及文件:
- 前端测试:按仓库现有测试布局查找 `*.test.ts` / `*.test.tsx`
- Rust 测试:`server-rs/crates/api-server/src/**` 或 domain crate tests
- 文档:可追加到 `docs/technical/``.hermes/shared-memory/decision-log.md`(如团队约定需要)
建议测试:
1. TypeScript 单元测试:
- `buildVisualNovelEntryGenerationProgress` 阶段输出。
- `buildVisualNovelEntryGenerationAnchorEntries` 能展示一句话和画风。
2. Rust 单元测试:
- creation prompt 包含 seedText、sourceMode、输出契约。
- draft normalize/fallback 能生成合法 opening/choices。
- runtime opening 或 first-step 构造不依赖图片/音乐。
3. 集成/手工测试文档:
- 访问平台视觉小说入口。
- 输入一句话。
- 选择画风。
- 点击生成。
- 查看结果页。
- 保存作品。
- 启动试玩并点击选择。
## 5. 可能改动文件清单
高概率改动:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `server-rs/crates/api-server/src/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
中概率改动:
- `src/components/visual-novel-runtime/**`
- `src/services/visual-novel-creation/**`
- `src/services/visual-novel-runtime/**`
- `src/services/visual-novel-works/**`
- `server-rs/crates/spacetime-module/src/visual_novel.rs`
- `server-rs/crates/spacetime-client/**` 生成/绑定文件,若 SpacetimeDB contract 需要更新
低概率/仅文档:
- `docs/technical/VISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.md`
- `docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md`
- `.hermes/shared-memory/decision-log.md`
## 6. 验证计划
### 6.1 静态检查
在 worktree 根目录执行:
```bash
npm run typecheck
```
如仓库无统一 typecheck则按 package scripts 选择最接近的前端类型检查命令。
### 6.2 前端定向测试
优先运行与 visual novel / platform entry 相关测试,如存在:
```bash
npm test -- visual-novel
npm test -- platform-entry
```
若仓库使用 vitest
```bash
npm run test -- visual-novel
```
### 6.3 Rust 定向测试
`server-rs` 下运行 visual novel 相关测试:
```bash
cargo test -p api-server visual_novel
cargo test -p shared-contracts visual_novel
```
如改动 SpacetimeDB module
```bash
cargo test -p spacetime-module visual_novel
```
### 6.4 人工验收步骤
1. 启动本地 dev 栈。
2. 访问 Genarrative 主站。
3. 进入创作/视觉小说入口。
4. 输入:`一个雨夜,失忆的高中生在旧图书馆发现一本会回应她心声的日记。`
5. 选择任一画风,例如“映画动画”。
6. 点击“生成视觉小说草稿”。
7. 预期:进入生成过程页,能看到分阶段进度。
8. 预期:完成后进入草稿结果页,包含标题、简介、世界观、角色、场景、剧情阶段和 opening choices。
9. 点击保存/编译作品。
10. 从作品入口进入试玩。
11. 预期opening 文本出现,至少 2 个选择可点击;点击后剧情继续推进一轮。
## 7. 风险、权衡与开放问题
### 7.1 风险
- 现有视觉小说代码已较完整,贸然新增一套 parallel pipeline 会制造重复逻辑;应复用当前 `VisualNovelResultDraft` 与 creation agent flow。
- LLM 输出不稳定可能导致草稿结构不完整;需要 normalize/repair/fallback 确保最小闭环。
- 视觉/音乐资产生成未接入时UI 必须接受 null asset否则运行态可能白屏。
- `PlatformEntryFlowShellImpl.tsx` 文件很大,改动需局部、谨慎,避免影响其他玩法入口。
- 若改动 SpacetimeDB 表结构,可能牵涉 publish、client binding、清库/迁移;最小闭环阶段应尽量避免 schema 变更。
### 7.2 权衡
- 先让文字版视觉小说完整跑通,再补角色立绘/背景图生成。
- 先用 `seedText` 承载画风,再考虑把 `visualStyleId/Label/Prompt` 结构化进 draft metadata。
- 先用现有 result/work/runtime 页面闭环,不引入新编辑器。
### 7.3 开放问题
1. 用户是否要求把 Interactive-fiction 原项目中的具体 UI 样式/页面布局迁移到 Genarrative当前计划只迁移流程语义不迁移独立 UI。
2. 画风是否需要成为作品可编辑字段?当前以 seedText/prompt 影响生成内容,后续可在 draft 中增加 metadata。
3. 文档导入模式是否本期要做当前计划聚焦一句话模式document 模式只保留契约能力。
4. 是否需要真实图片/音乐生成?当前计划作为后续增强,不纳入最小闭环。
## 8. 建议实施顺序
1. 先做只改 prompt/progress/少量前端展示的轻量闭环修补。
2. 运行前后端定向测试,确认现有能力是否已足够。
3. 如果后端没有 fallback 或 normalize再补 Rust 层确定性兜底。
4. 手工跑通“一句话 -> 生成 -> 结果页 -> 保存 -> 试玩”。
5. 最后再考虑是否需要资产生成、文档导入、结构化画风 metadata。

View File

@@ -16,42 +16,42 @@
---
## 2026-05-14 抓大鹅草稿计划同时产出作品信息和默认封面
## 2026-05-13 认证运行期同步直接导入正式认证表
- 背景:抓大鹅草稿生成原本重点在物品名称和素材生成,作品名称、作品描述、作品标签和封面容易在结果页保持空值或只靠用户手动补齐
- 决策:`match3d_compile_draft` 的作品生成计划必须同时返回 `gameName``summary``tags`、背景音乐、背景提示词和物品计划。后端先把 `gameName``summary` 写入 `match3d_work_profile`,再基于题材、作品名和描述自动调用作品标签生成器;标签生成失败时才合并计划 tags 与本地兜底。若作品尚无用户封面,草稿生成完成后默认使用生成的抓大鹅容器 UI 图作为 `coverImageSrc`,容器图缺失时才回退到纯背景图
- 影响范围:`server-rs/crates/api-server/src/match3d.rs`、Match3D works shared contracts、`Match3DResultView` 手动标签生成、抓大鹅草稿素材生成流水线文档。
- 验证方式:执行 `cargo test -p api-server match3d --manifest-path server-rs\Cargo.toml``cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml``npm run test -- src\components\match3d-result\Match3DResultView.test.tsx``npm run typecheck``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
- 背景:`auth_store_snapshot` 是 Stage 1 整包快照过渡表,主键固定 `default`,会让所有用户状态集中在一条 `snapshot_json`Stage 2/3 已有 `user_account/auth_identity/refresh_session` 正式认证表,继续刷新 `default` 容易让运行时真相和表拆分目标混在一起
- 决策:运行期认证变更继续由 `module-auth` 生成一致内存快照,但 `api-server` 改为调用 `import_auth_store_snapshot_json` 直接覆盖导入 `user_account/auth_identity/refresh_session``auth_store_projection_meta/default` 只记录正式认证表最近一次导入时间;`upsert_auth_store_snapshot``import_auth_store_snapshot` 仅保留为旧库迁移和兜底入口
- 影响范围:`spacetime-module` auth procedures/tables、`spacetime-client` auth facade/bindings、`api-server` 认证同步和启动恢复、SpacetimeDB 表目录与认证 Stage 3 文档。
- 验证方式:执行 `npm run spacetime:generate -- --rust-only``cargo check -p api-server --manifest-path server-rs/Cargo.toml`认证相关定向测试和 `npm run check:encoding`
- 关联文档:`docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md``docs/technical/SPACETIMEDB_TABLE_CATALOG.md`
## 2026-05-13 抓大鹅草稿生成固定 10 光点且入口不生成点击音效
## 2026-05-13 微信小程序支付以后端通知为唯一入账事实
- 背景:抓大鹅入口草稿生成需要有明确、稳定的光点成本,且入口不再把点击音效作为草稿生成选项暴露,避免一次草稿生成混入额外音效任务与扣费
- 决策:`match3d_compile_draft` 草稿生成固定预扣 `10` 光点,失败时按钱包流水退款;创作页按钮展示 `消耗10光点`,不展示 `生成音效` Toggle入口表单和重试均固定传 `generateClickSound = false`。物品点击音效只保留在结果页 `素材配置 > 物品` 详情面板手动生成,并按独立音效任务扣费
- 影响范围:`server-rs/crates/api-server/src/match3d.rs``src/components/match3d-creation/Match3DAgentWorkspace.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`、抓大鹅 PRD、F1 入口文档、素材生成流水线文档和音频 Tab 文档
- 验证方式:执行 `npm run test -- src\components\match3d-creation\Match3DAgentWorkspace.interaction.test.tsx``npm run typecheck``cargo test -p api-server match3d --manifest-path server-rs\Cargo.toml``cargo check -p api-server --manifest-path server-rs\Cargo.toml``npm run check:encoding`
- 背景:“我的”账户充值需要接入微信小程序支付,同时保留本地 / H5 mock 支付联调能力
- 决策:`paymentChannel = "mock"` 继续创建即 paid 订单并立即入账;`paymentChannel = "wechat_mp"` 先在 `profile_recharge_order` 写入 `pending` 订单,再由 `api-server` 调微信支付 JSAPI 下单并返回小程序 `wx.requestPayment` 参数。小程序或 H5 的支付成功回调只触发刷新,不直接发放光点或会员;最终入账只由 `/api/profile/recharge/wechat/notify` 验签、解密并确认 `trade_state = SUCCESS` 后完成。`provider_transaction_id` 保存微信支付平台交易号,用于对账、查单、退款和客服排障
- 影响范围:`profile_recharge_order` 表、SpacetimeDB 充值 procedure、`api-server` 微信支付客户端、小程序 native 支付页、H5 充值弹窗与共享 contract
- 验证方式:执行 `npm run typecheck``npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx``cargo test -p module-runtime recharge --manifest-path server-rs/Cargo.toml``cargo test -p api-server wechat_pay --manifest-path server-rs/Cargo.toml`,后端联调仍用 `npm run api-server``/healthz`
- 关联文档:`docs/technical/MY_TAB_ACCOUNT_RECHARGE_IMPLEMENTATION_2026-04-25.md``docs/technical/SPACETIMEDB_TABLE_CATALOG.md`
## 2026-05-13 抓大鹅 5x5 物品素材固定绿幕生成并本地转透明
## 2026-05-13 修改密码后全设备强制下线
- 背景:抓大鹅 2D 五视角素材如果继续让上游自由生成白底、灰底、纹理底或透明感背景,切割后的物品图会带底色块,运行态叠加到中心容器时观感不稳定
- 决策:抓大鹅物品素材 sheet 的 VectorEngine prompt 固定要求每格使用统一纯绿色绿幕背景;`api-server` 在按 5x5 切割前先对整张素材图执行绿幕 alpha 处理,再做格内前景边界校准和 PNG 上传。物品本体不得使用与绿幕相同的纯绿色,天然绿色物品需要用描边和不同绿相区分
- 影响范围:`server-rs/crates/api-server/src/match3d.rs`、抓大鹅素材生成 prompt、5x5 切图、OSS 视角图上传和 Match3D 素材生成技术文档。
- 验证方式:`cargo test -p api-server match3d --manifest-path server-rs\Cargo.toml` 覆盖 prompt 中的绿幕约束、绿幕转透明和主体保留;执行 `npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
- 背景:修改密码原本只递增 `token_version`,旧 access token 会失效,但旧 refresh cookie 仍可通过 `/api/auth/refresh` 重新签发新 token不符合“改密后全设备强制下线”的账号安全预期
- 决策:`POST /api/auth/password/change` 成功后必须在同一认证真相更新中撤销该用户全部 active `refresh_session`,继续递增 `token_version`,响应清除当前 refresh cookie前端 `changePassword` 成功后清空本地 access token 并回到未登录态。用户需要使用新密码重新登录
- 影响范围:`module-auth` 修改密码用例、`api-server` password management route、`AuthGate``authService`、密码登录/重置技术文档。
- 验证方式:执行 `cargo test -p api-server --manifest-path server-rs/Cargo.toml password_change_allows_login_with_new_password_only -- --nocapture``npm run test -- AuthGate.test.tsx authService.test.ts``npm run check:encoding``git diff --check`
- 关联文档:`docs/technical/PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md``docs/technical/AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md`
## 2026-05-13 拼图和抓大鹅 UI 生图拆分为纯背景与运行态默认 UI
## 2026-05-13 refresh_session 会话组后端聚合与远端踢下线
- 背景:拼图和抓大鹅此前的 UI 背景生成容易把拼图槽、锅状竞技区或其它 UI 元素烘进背景图,导致运行态默认 UI、真实物品和生成图层重复
- 决策:拼图只生成 `9:16` 纯题材背景图不携带拼图槽、棋盘框、按钮、HUD、文字或物品拼图槽继续使用运行态默认样式。抓大鹅生成 `9:16` 纯背景图和一张独立 `1:1` 中心容器 UI 图;纯背景不得包含锅/圆盘/托盘/物品槽/HUD/文字/物品,容器图单独贴合题材设定并覆盖运行态中心容器,底部备选栏继续使用默认 UI
- 影响范围:拼图 UI 背景 prompt、抓大鹅 `backgroundAsset` JSON、Match3D shared contracts、运行态背景/容器渲染、生成进度工作量和对应 PRD/技术文档
- 验证方式:检查 VectorEngine 请求 prompt 不要求背景图生成锅或槽位;运行态有 `containerImageSrc/containerImageObjectKey` 时使用容器图,否则默认容器兜底;执行拼图/抓大鹅定向测试、`npm run typecheck``npm run check:encoding`
- 关联文档:`docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md``docs/prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md`
- 背景:账号安全页中同设备同 IP 的多条 active `refresh_session` 会重复展示;退出登录没有稳定撤销当前 refresh session前端“踢下线”只做本地状态变化未真正让远端设备失效
- 决策:`GET /api/auth/sessions` 由后端按“同设备 + 同 IP”聚合 active refresh sessions响应保留代表 `sessionId` 并新增 `sessionIds/sessionCount`;组内包含当前 refresh hash 或 Bearer `sid` 时整组视为当前设备组,前端不展示踢下线。新增 `POST /api/auth/sessions/{session_id}/revoke`,只允许撤销当前用户自己的非当前会话,不递增 `token_version`,但认证中间件会校验 access token `sid` 对应 active refresh session使被踢设备立即失效。`/api/auth/logout` 在 refresh cookie 缺失时回退用 Bearer `sid` 撤销当前 session并继续递增 `token_version`
- 影响范围:`module-auth` refresh session service、`api-server` auth middleware/logout/sessions route、`shared-contracts`/TS auth contract、`AuthGate``AccountModal`、认证会话技术文档和路由/埋点索引
- 验证方式:执行 `cargo test -p module-auth --manifest-path server-rs/Cargo.toml refresh_session``cargo test -p api-server --manifest-path server-rs/Cargo.toml auth_sessions -- --nocapture``cargo test -p api-server --manifest-path server-rs/Cargo.toml revoke_auth_session -- --nocapture``cargo test -p api-server --manifest-path server-rs/Cargo.toml logout_succeeds_without_refresh_cookie_when_bearer_token_is_valid -- --nocapture``npm run test -- AuthGate.test.tsx AccountModal.test.tsx authService.test.ts``npm run check:encoding``git diff --check`,并用 `npm run api-server` 检查 `/healthz`
- 关联文档:`docs/technical/AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md``docs/technical/SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md``docs/technical/SERVER_RS_DDD_G1_CONTRACT_AND_ROUTE_MATRIX_2026-04-29.md`
## 2026-05-12 抓大鹅入口素材风格改为 2D 常见素材风格
- 背景:抓大鹅草稿素材生成已经收敛为多视角 2D 图片素材,但入口页和旧参考图仍沿用黏土、低多边形、塑料、木雕、体素、金属等偏 3D 素材语言,容易让后续生成链路和用户预期继续漂移。
- 决策:抓大鹅创作入口 `2D素材风格` 固定为 `扁平图标 / 赛璐璐卡通 / 像素复古 / 手绘水彩 / 贴纸描边 / 厚涂图标 / 自定义`;默认风格为 `flat-icon`。入口参考图统一由 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成,输出到 `public/match3d-style-references/`2026-05-13 起,入口参考图固定只展示 `1` 个完整独立物品,不能展示 `5` 个物品样张或多物品散点图。旧 3D 风格参考图不再保留为入口资产。
- 2026-05-13 补充:`像素复古` 不能只写“复古像素”或“有限色板”;前端、参考图脚本和后端素材图 prompt 必须要求约 `64x64` 低分辨率像素块、整数倍放大、硬边方块像素、`12-24` 色有限色板,并禁止抗锯齿、柔焦、平滑渐变、真实 3D 渲染、PBR 材质和摄影光照。后端收到 `assetStyleId = pixel-retro``assetStyleLabel = 像素复古` 时必须兜底补齐这些约束。
- 决策:抓大鹅创作入口 `2D素材风格` 固定为 `扁平图标 / 赛璐璐卡通 / 像素复古 / 手绘水彩 / 贴纸描边 / 厚涂图标 / 自定义`;默认风格为 `flat-icon`。入口参考图统一由 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成,输出到 `public/match3d-style-references/`。旧 3D 风格参考图不再保留为入口资产。
- 影响范围:`Match3DAgentWorkspace`、抓大鹅入口交互测试、Match3D PRD、素材生成流水线技术文档、F1 入口文档和 `public/match3d-style-references/` 静态资产。
- 验证方式:执行 `npm run test -- src\components\match3d-creation\Match3DAgentWorkspace.interaction.test.tsx``cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml``npm run typecheck``npm run check:encoding`,并人工抽查 `.tmp/match3d-style-preview.png`
- 关联文档:`docs/prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md``docs/technical/MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md`
@@ -87,7 +87,6 @@
- 影响范围:平台个人页、登录弹窗、法律 Markdown 渲染和前端认证交互测试。
- 验证方式:执行 `npm run test -- src/components/auth/AuthGate.test.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`、触碰文件 ESLint、`npm run check:encoding`
- 关联文档:`docs/prd/PROFILE_LEGAL_INFO_AND_AUTH_AGREEMENT_PRD_2026-05-12.md`
## 2026-05-12 微信小程序待绑定手机号优先走原生手机号授权
- 背景:微信小程序 `web-view` 壳登录后若返回 `pending_bind_phone`H5 仍会展示手输手机号和短信验证码绑定页,体验上多了一步。
@@ -417,4 +416,4 @@
- 决策:埋点原始事实进入 `tracking_event`,聚合投影进入 `tracking_daily_stat`;个人任务配置/进度/领奖/钱包分别进入 `profile_task_config``profile_task_progress``profile_task_reward_claim``profile_wallet_ledger`;首版个人任务 scope 仅支持 `user`
- 影响范围:用户侧任务中心、后台任务配置、运营查询、埋点查询、钱包流水。
- 验证方式:非 `user` scope 的个人任务配置应被 API 和领域构造层拒绝;任务查询与埋点查询分别放在 `docs/operations/``docs/tracking/`
- 关联文档:`PROFILE_TASK_AND_TRACKING_SYSTEM_2026-05-03.md``RUNTIME_PROFILE_TASK_SCOPE_2026-05-04.md``ANALYTICS_DATE_DIMENSION_IMPLEMENTATION_2026-05-04.md`
- 关联文档:`PROFILE_TASK_AND_TRACKING_SYSTEM_2026-05-03.md``RUNTIME_PROFILE_TASK_SCOPE_2026-05-04.md``ANALYTICS_DATE_DIMENSION_IMPLEMENTATION_2026-05-04.md`

View File

@@ -493,6 +493,22 @@
- 验证:发布链路使用当前 `deploy/systemd``deploy/nginx``scripts/deploy``jenkins/Jenkinsfile.production-*`
- 关联:`docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Release Web 产物通过内网 rsync 拉取
- 现象:`Genarrative-Web-Deploy` 发布到 `release` 目标时release agent 本地没有 `/var/cache/genarrative-build/web-artifacts/<job>/<build>/<version>/web.tar.gz`,但 Jenkins controller 又只归档轻量元数据,导致发布阶段找不到 Web 大包。
- 原因Web 大包为了避免从 Linux 构建机拉回 Jenkins controller默认留在构建机稳定缓存目录development 目标与构建机同机可直接读取release 目标是独立机器,需要内网同步。
- 处理release 服务器的 Jenkins 运行用户配置 SSH Host `genarrative-build-internal` 指向构建机内网地址,`Genarrative-Web-Deploy``DEPLOY_TARGET=release` 且本地缺少大包时默认执行 `rsync` 拉取同一路径内容;真实内网 IP、用户和私钥路径只放在服务器本机 SSH config不写入 Jenkinsfile。
- 验证:在 release 服务器上先手工跑通 `rsync -av --progress "genarrative-build-internal:${SRC}/" "${DST}/"`,再运行 Web Deploy流水线会继续执行 `web.tar.gz.sha256` 校验。
- 关联:`jenkins/Jenkinsfile.production-web-deploy``docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Jenkins 生产流水线拉 Git 先本机再域名备用
- 现象:生产发布、数据库导入导出或服务器配置流水线在目标 Linux agent 上执行 `GitSCM checkout` 时,`http://127.0.0.1:3000/GenarrativeAI/Genarrative.git` 不可达,导致脚本还没拉下来就失败;若 fallback 到公网 Git 时没有限制 refspec、浅克隆和 tags还可能在约 10 分钟后出现 `git-remote-https died of signal 15``early EOF``invalid index-pack output`
- 原因:`127.0.0.1` 只代表当前执行阶段的 agent 自身;当 release agent 与 Git 服务不在同一台机器,或本机 Git/Web 服务临时不可用时,固定写死 localhost 会阻断 Jenkinsfile 内部源码/脚本 checkout。
- 处理Jenkins Job 的 `Pipeline script from SCM` 由 Windows controller 执行SCM URL 使用公网域名 `https://git.genarrative.world/GenarrativeAI/Genarrative.git`。运行于 Linux agent 的 Jenkinsfile 首次 `checkout([$class: 'GitSCM', ...])` 层先尝试 `GIT_REMOTE_URL=http://127.0.0.1:3000/GenarrativeAI/Genarrative.git`,失败后直接尝试 `GIT_REMOTE_FALLBACK_URL=https://git.genarrative.world/GenarrativeAI/Genarrative.git`,不再配置内网 IP fallback首次 checkout 必须使用目标分支 refspec、`CloneOption shallow=true depth=1 noTags=true honorRefspec=true`。后续统一走 `scripts/jenkins-checkout-source.sh`,该脚本也按主地址、域名备用地址顺序重新 fetch 并把 `origin` 切到实际可用地址;`COMMIT_HASH` 为空时继续 `--depth=1 --no-tags`,只有指定 commit 时才允许加深历史做分支归属校验。
- 验证:扫描本地 Jenkins live job `config.xml`,确认 SCM `<url>` 都是 `https://git.genarrative.world/GenarrativeAI/Genarrative.git`;扫描所有以 `127.0.0.1:3000` 拉 Git 且运行在 Linux agent 的生产 Jenkinsfile确认存在 `GIT_REMOTE_FALLBACK_URL``EFFECTIVE_GIT_REMOTE_URL` 和脚本层 `GIT_REMOTE_FALLBACK_URL` 透传;运行 `bash -n scripts/jenkins-checkout-source.sh`
- 关联:`jenkins/Jenkinsfile.production-web-deploy``jenkins/Jenkinsfile.production-api-deploy``jenkins/Jenkinsfile.production-stdb-module-publish``jenkins/Jenkinsfile.production-server-provision``jenkins/Jenkinsfile.production-database-export``jenkins/Jenkinsfile.production-database-import``scripts/jenkins-checkout-source.sh``docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Jenkins 可选参数在 set -u 下不能裸读
- 现象:数据库导入或导出流水线报 `INCLUDE_TABLES: unbound variable`,或其它可选参数在 Bash 中未定义即退出。
@@ -588,6 +604,14 @@
- 验证:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx` 覆盖抓大鹅和拼图生成后自动试玩 / 返回结果页。
- 关联:`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 微信支付回调验签不要用商户私钥
- 现象:微信小程序支付下单能返回 `prepay_id`,但真实支付通知验签失败,或者本地实现误把商户 API 私钥当作回调验签 key。
- 原因:商户私钥只用于商户请求微信支付和生成小程序 `paySign`;微信支付通知的 `Wechatpay-Signature` 需要使用微信支付平台公钥或平台证书公钥验签,并按通知头里的平台序列号匹配。
- 处理api-server 真实微信支付配置同时需要商户私钥与微信平台公钥:`WECHAT_PAY_PRIVATE_KEY_*` 用于签名,`WECHAT_PAY_PLATFORM_PUBLIC_KEY_*``WECHAT_PAY_PLATFORM_SERIAL_NO` 用于通知验签,`WECHAT_PAY_API_V3_KEY` 只用于解密通知 resource。支付成功后只通过通知里的 `out_trade_no` 确认本地 pending 订单,并保存 `transaction_id``profile_recharge_order.provider_transaction_id`
- 验证mock 通知测试只能覆盖本地回调推进;真实环境还需用微信支付平台公钥、真实通知头和 API v3 密钥验证签名与解密链路。
- 关联:`server-rs/crates/api-server/src/wechat_pay.rs``docs/technical/MY_TAB_ACCOUNT_RECHARGE_IMPLEMENTATION_2026-04-25.md`
## 抓大鹅历史草稿外部 Rodin GLB 链接必须转存后再试玩或发布
- 现象:草稿页预览模型失败并报 `GL_INVALID_ENUM: Invalid cap.`,或结果页能看到历史生成记录但试玩、发布和正式运行态仍显示默认积木。