feat: add wooden fish play template

This commit is contained in:
2026-05-21 23:34:07 +08:00
parent ef09a23c35
commit 5b0f9f3763
121 changed files with 11580 additions and 159 deletions

View File

@@ -179,6 +179,14 @@
- 验证:执行 `node scripts/generate-edutainment-tv-map-concepts.mjs --dry-run`,输出应只显示 `imageReferenceCount: 1`,不出现完整 base64。
- 关联:`scripts/generate-edutainment-tv-map-concepts.mjs``docs/design/【前端体验】寓教于乐电视端乐园地图入口概念图-2026-05-18.md`
## 生成图资产不能只拼 generated legacy path
- 现象:结果页或运行态拿到 `/generated-*-assets/.../image.png` 后图片不显示;前端 `ResolvedAssetImage` 会先调用 `/api/assets/read-url?legacyPublicPath=...`,但换签后的 OSS URL 仍指向不存在对象。
- 原因:后端只写了看起来像生成图的 legacy path没有真正调用 image2、上传 OSS、登记 `asset_object` 并绑定实体。`/api/assets/read-url` 只负责签名读取,不会凭空生成或补写对象。
- 处理:玩法生成链路必须在 `api-server` 完成外部副作用:调用 VectorEngine `gpt-image-2-all`,用 `GeneratedImageAssetAdapter` 准备 `PutObject`,上传 OSS 私有对象,调用 `confirm_asset_object``bind_asset_object_to_entity`,再把返回的 `legacyPublicPath` 写入玩法 profile。
- 验证:`cargo check -p api-server --manifest-path server-rs/Cargo.toml`;契约测试应断言前端 JSON 自带的 `hitObjectAsset` 会被忽略spacetime-client 定向测试应断言缺少服务端注入的真实 `hitObjectAsset` 时不能编译;浏览器 Network 中 generated 图片应先换签,签名 URL 指向已存在对象。
- 关联:`server-rs/crates/api-server/src/wooden_fish.rs``server-rs/crates/spacetime-client/src/wooden_fish.rs``src/components/ResolvedAssetImage.tsx``src/services/assetReadUrlService.ts`
## 忘记密码后仍提示手机号或密码错误先查认证快照同步
- 现象:用户通过“忘记密码”重设密码后,接口返回成功或页面进入登录态,但再次使用新密码登录仍提示“手机号或密码错误”;重启后还可能出现 `Bearer JWT 版本已失效`,日志里的 token version 与本地快照不一致。
@@ -558,7 +566,7 @@
- 现象:登录弹窗可以进入短信页签,但点击“获取验证码”后,手机没有收到短信。
- 原因:本地 `.env.local` 里如果是 `SMS_AUTH_PROVIDER="mock"`,后端不会发真实短信,只会返回固定 mock 验证码;真实阿里云链路已经改为普通短信 `SendSms`,验证码由当前 `api-server` 进程本地生成、哈希存储和校验,旧 `SendSmsVerifyCode` / `CheckSmsVerifyCode` 托管验证码参数不再参与真实校验。若接口直接返回“手机号登录暂未启用”,说明当前运行中的 `api-server` 进程内 `sms_auth_enabled=false`:常见原因是修改 `.env.local` 后没有重启后端,或外层 shell 已经设置了非空 `SMS_AUTH_ENABLED` 导致 dotenv 不覆盖。历史上 cmd 里 `set SMS_AUTH_ENABLED="true"` 会把引号也传进进程Rust bool 解析失败后保持默认 false。
- 处理:真实短信联调时把 `.env.local``SMS_AUTH_ENABLED=true``SMS_AUTH_PROVIDER=aliyun` 显式打开,并确认 `ALIYUN_SMS_ENDPOINT=dysmsapi.aliyuncs.com``ALIYUN_SMS_SIGN_NAME=北京亓盒网络科技``ALIYUN_SMS_TEMPLATE_CODE=SMS_506245486``ALIYUN_SMS_TEMPLATE_PARAM_KEY=code` 后重启 `api-server`;如果只想验证 UI账号链路,则保留 `mock` 并使用 `SMS_AUTH_MOCK_VERIFY_CODE`。Shell 临时覆盖时 PowerShell 用 `$env:SMS_AUTH_ENABLED="true"`cmd 用 `set SMS_AUTH_ENABLED=true`,不要把引号作为值的一部分。`api-server` 重启会清掉未校验的本地验证码。
- 处理:真实短信联调时把 `.env.local``SMS_AUTH_ENABLED=true``SMS_AUTH_PROVIDER=aliyun` 显式打开,并确认 `ALIYUN_SMS_ENDPOINT=dysmsapi.aliyuncs.com``ALIYUN_SMS_SIGN_NAME=北京亓盒网络科技``ALIYUN_SMS_TEMPLATE_CODE=SMS_506245486``ALIYUN_SMS_TEMPLATE_PARAM_KEY=code` 后重启 `api-server`;如果只想验证 UI账号链路`/healthz`,则保留 / 切换为 `mock` 并使用 `SMS_AUTH_MOCK_VERIFY_CODE`注意 `npm run dev:api-server` 会先合并 `.env.local`,且 `SMS_AUTH_ENABLED``SMS_AUTH_PROVIDER``SMS_AUTH_MOCK_VERIFY_CODE` 属于允许本地文件覆盖的键;如果 `.env.local` 写着 `SMS_AUTH_PROVIDER=aliyun` 但没有 `ALIYUN_SMS_ACCESS_KEY_*`,单纯在 PowerShell 里临时设置 mock 仍可能被覆盖health smoke 会在启动阶段报“阿里云短信 AccessKey 未配置”。不改 `.env.local` 的临时 smoke 可以直接运行 `cargo run -p api-server --manifest-path server-rs\Cargo.toml` 并在同一 shell 中显式设置 `SMS_AUTH_PROVIDER=mock``GENARRATIVE_API_HOST``GENARRATIVE_API_PORT``GENARRATIVE_SPACETIME_SERVER_URL``GENARRATIVE_SPACETIME_DATABASE`Shell 临时覆盖时 PowerShell 用 `$env:SMS_AUTH_ENABLED="true"`cmd 用 `set SMS_AUTH_ENABLED=true`,不要把引号作为值的一部分。`api-server` 重启会清掉未校验的本地验证码。
- 验证:分别请求浏览器域名和 Rust API 直连的 `/api/auth/login-options`,都应返回 `["phone","password"]``api-server` 日志里 `provider=aliyun` 才说明真实短信链路已生效。需要直接确认平台层真实调用阿里云时,配置 `ALIYUN_SMS_ACCESS_KEY_ID``ALIYUN_SMS_ACCESS_KEY_SECRET``ALIYUN_SMS_REAL_TEST_PHONE_NUMBER` 后手动执行 `cargo test -p platform-auth --manifest-path server-rs/Cargo.toml aliyun_send_sms_real_provider_sends_verify_code -- --ignored --nocapture`
- 关联:`server-rs/crates/api-server/src/config.rs``scripts/dev-utils.mjs``docs/technical/AUTH_LOGIN_OPTIONS_DESIGN_2026-04-21.md``docs/technical/PHONE_SMS_REAL_PROVIDER_MANUAL_VERIFICATION_RUNBOOK_2026-04-23.md`