138 KiB
server-rs 与 SpacetimeDB 数据契约
更新时间:2026-07-03
后端主线
当前后端固定为:
server-rs + Axum + SpacetimeDB
旧 server-node、Express、PostgreSQL、Go 服务端和 maincloud 口径全部为历史残留。新功能不得回到旧接口、旧兼容层或前端临时业务真相。
Rust workspace
server-rs/Cargo.toml 是 workspace 事实源。默认构建成员为 crates/api-server;第三方依赖版本和 workspace 内 crate path 统一放在 [workspace.dependencies]。
SpacetimeDB 版本口径:当前 Rust crate spacetimedb、spacetimedb-sdk、spacetimedb-lib 统一锁定 2.6.0;本地 spacetime CLI / standalone、生成的 spacetime-client bindings 和容器压测镜像也必须与 server-rs/Cargo.toml 锁定版本对齐,避免 BSATN / procedure result 反序列化错配。遇到版本不匹配时,不继续沿着业务超时排查,先把 CLI / standalone 直接升级到锁定版本并重启后再重试。
当前主要 crate:
- HTTP 服务:
api-server。 - 领域模块:
module-ai、module-assets、module-auth、module-bark-battle、module-big-fish、module-combat、module-creative-agent、module-editor-agent、module-custom-world、module-inventory、module-match3d、module-npc、module-progression、module-puzzle、module-quest、module-runtime、module-runtime-item、module-runtime-story、module-square-hole、module-story、module-visual-novel。 - 平台副作用:
platform-agent、platform-auth、platform-image、platform-llm、platform-matting、platform-oss、platform-wechat、platform-speech。 - 共享层:
shared-contracts、shared-kernel、shared-logging。 - SpacetimeDB:
spacetime-client、spacetime-module。 - 测试支撑:
tests-support。
DDD 边界
module-*不直接依赖 Axum、SpacetimeDB table/reducer/procedure、reqwest、OSS、LLM、spacetime-client、tokio或文件系统。- 业务规则、命令校验、领域错误和可纯测逻辑优先沉到
module-*。 - SpacetimeDB 表结构、reducer、procedure 和持久化 row shape 留在
spacetime-module。 - 后端访问 SpacetimeDB 必须经
spacetime-clientfacade。 - HTTP 鉴权、BFF 聚合、SSE、外部模型编排、OSS 上传和第三方回调在
api-server。 - 前端共享 DTO 通过
shared-contracts和packages/shared对齐,不在页面内重新发明旧接口;packages/shared还可复用无业务真相的 UI 组件和纯工具,领域规则、后端副作用与正式状态仍留在各自分层。 - 微信能力按两层收口:
server-rs/crates/platform-wechat承载微信协议 client、订阅消息stable_token/subscribeMessage.send、微信支付 V3 / 虚拟支付消息推送的 HTTP header、签名、验签、解密、mock 响应和协议 payload 解析;server-rs/crates/api-server/src/wechat.rs与wechat/*承载 Axum handler、AppConfig 到平台配置的映射、Genarrative 用户 / 订单 / 钱包 / SSE / 错误 envelope 编排。platform-auth当前仍承载微信 OAuth / 小程序登录 provider 协议,api-server::wechat::provider只作为组合根 adapter,不在业务 handler 内散落 provider 构造。
验证:
npm run check:server-rs-ddd
spacetime-client mapper 组织
server-rs/crates/spacetime-client/src/mapper.rs 只作为聚合入口,负责声明 src/mapper/ 下的领域子模块并 re-export 原有 record / mapper 能力;不要在该文件继续堆叠大段映射实现。
当前子模块按调用领域拆分:assets.rs、auth.rs、runtime.rs、runtime_profile.rs、custom_world.rs、puzzle.rs、match3d.rs、jump_hop.rs、wooden_fish.rs、square_hole.rs、visual_novel.rs、big_fish.rs、story.rs、ai.rs、bark_battle.rs、combat.rs、inventory.rs、npc.rs,跨领域轻量 helper 和共享 record 统一放在 common.rs。该拆分只改变 spacetime-client 文件组织,不改变 SpacetimeDB schema、生成绑定、procedure result 契约或外部 DTO;后续新增 mapper 时优先落到对应领域子模块,不得重新引入跨层 JSON 字符串兼容结构。
API 路由分组
路由树由 server-rs/crates/api-server/src/app.rs 统一构造。当前主要分组:
- 健康检查:
GET /healthz。 - 后台管理:
/admin/api/*,包括登录、Dashboard 运营看板、概览、HTTP debug、埋点、表查询、精选审核、素材查询、创作入口开关、作品互动配置、作品可见性、兑换码、邀请码、任务配置、充值商品配置和后台账号管理。环境变量管理员固定作为 owner,持久化 member 每次请求按当前enabled、token_version和一级 Tab 权限实时校验;账号管理仅 owner 可访问,未登记权限映射的新后台路由对 member 默认拒绝。完整权限矩阵见docs/technical/【后台管理】多账号与Tab访问权限方案-2026-07-14.md,Dashboard 指标口径见docs/technical/【后台管理】Dashboard运营看板方案-2026-06-23.md。 - 认证与账号:
/api/auth/*、/api/profile/me,包括短信、密码、微信、refresh session、多端会话和登出。 - 个人中心:
/api/profile/*,包括钱包流水、任务、领奖、充值、反馈、邀请和兑换等账号侧能力。 - 平台基础能力:
/api/llm/*、/api/speech/volcengine/*,只保留通用 LLM 和语音代理。 - 资产基础能力:
/api/assets/direct-upload-tickets、/api/assets/sts-upload-credentials、/api/assets/objects/*、/api/assets/read-url、/api/assets/read-bytes,负责直传、确认、绑定和读取。两个读取入口共用同一授权函数,并通过受 runtime service identity 限制的 procedure 在同一事务快照内按配置 bucket 与精确 key 权威查询asset_object、计算公开作品或公开精选派生授权;不得把任意连接的订阅 cache miss 或命中解释为当前授权真相。一旦存在 metadata,即使 key 命中 legacy 前缀,也必须按PublicRead、当前登录 owner、同 owner 的公开作品派生授权,或同 owner 且已通过、已展示、返还完成的editor_showcase_asset精确授权读取;只有同 bucket / key 的权威查询确认未登记时,才允许显式legacyPublicPath命中platform_oss::LEGACY_PUBLIC_PREFIXEScurated 白名单后匿名兼容。已登记资产继续保持private,公开作品和公开精选只获得与正式公开快照生命周期一致的精确派生读授权,不得批量改为PublicRead或放开generated-*前缀。任意未登记objectKey、跨 owner 和未获授权的匿名私有读取统一返回不存在,read-bytes不得成为绕过read-url授权的同源代理;公开派生授权、PublicRead和 legacy 兼容读取签发的 URL 统一限制为最长 600 秒,owner / admin 读取保持原有有效期口径。 - 外部 OpenAPI:
/api/external/v1/openapi.json、/api/external/v1/assets/direct-upload-tickets、/api/external/v1/assets/objects/confirm、/api/external/v1/assets/read-url、/api/external/v1/editor/*,使用 Bearer API Key 鉴权;API Key 管理仍在登录态/api/profile/api-keys,不进入外部 OpenAPI JSON。主站和 External 的 asset object confirm 都必须从已认证主体派生 owner,不能信任请求体 owner;同 bucket / key 已登记后不得改变 owner。 - 创作 / 游玩支撑能力:
/api/creation-entry/config、/api/ai/tasks*、/api/runtime/frontend-config、/api/runtime/chat/*、/api/runtime/settings、/api/runtime/save/snapshot、/api/profile/browse-history、/api/profile/save-archives*、/api/profile/play-stats、/api/assets/history、/api/assets/character-visual/*、/api/assets/character-animation/*、/api/assets/character-workflow-cache*、/api/assets/hyper3d/*、/api/runtime/custom-world/asset-studio/*、/api/editor/projects*、/api/editor/projects/{projectId}/agent-conversations、/api/editor/agent-conversations/{conversationId}*。/api/runtime/frontend-config由api-server从运行时环境变量下发非敏感 UI 开关;画板右侧 Agent 入口由GENARRATIVE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR控制,默认关闭,前端不再读取VITE_*构建期变量决定生产显示。/api/runtime/custom-world/asset-studio/*解析默认角色形象 / 动作提示词时可以在 OSS 缓存不可用或未配置时按无缓存返回默认提示;保存 workflow 缓存和真实素材读写仍必须要求 OSS 正常可用。 - 后台入口配置:
/admin/api/creation-entry/config、/admin/api/creation-entry/config/banners和/admin/api/creation-entry/config/interactions。 - 后台素材查询:
GET /admin/api/editor-assets通过admin_list_editor_assets_and_return后台只读 procedure 读取私有账号级editor_asset中source_type = 'generated'的素材,支持ownerUserId、keyword、createdAfter、createdBefore、cursor和limit;ownerUserId接受内部用户 ID 或精确陶泥号,精确SY-*keyword 也会在调用 procedure 前经认证服务解析成内部user_id,未知陶泥号直接返回空列表。带 owner 条件时 procedure 直接走by_editor_asset_owner_user_id,再按任务分组并以最终产物父项分页;响应中每个父项通过children携带可展开的中间产物,子项各占一行而不单独占分页名额。手动重拆图集保留真实editor-atlas-split-*task_id;来源任务只能通过私有 provenance 由服务端生成账号素材的 source resource / asset object / Object Key 推导,再写入group_task_id,不能信任素材库兼容推断值或普通资源创建接口可提交的task_id/asset_kind;procedure 只有当前 editor generation runtime service identity 才能写入归组与完成事实。没有可信来源的现代拆分显式归到自身任务,不进入 legacy 回溯。每个切片同时写入group_task_expected_asset_count,全部预期 asset ID 成功落库并逐行校验后写入不可逆 cohort 完成事实;read model 只让具有完成事实的一个拆分批次并入原图集父项,用户后来删除单片不会改变初始完成状态,部分失败批次与后续重复拆分按真实任务独立分页,避免残缺批次抢占根任务、单组无限增长或丢素材。历史行兼容沿项目资源链回溯,删除项目时只固化直接引用待删资源且尚未固化的历史行,持久化真实来源任务,不把有界展示 ID 反写覆盖来源。父项返回任务生成器和任务总成本,子项返回阶段生成器和阶段成本。provider 原图 / 角色动作预览承载模型生成成本,抠图、逐帧处理、透明图集和切片成本为 0;中间产物使用所属任务真实asset_kind,不再新写editor_green_screen_source,历史旧值只在 read model 中按 Object Key 映射为character、icon-spritesheet或character-animation并把旧任务成本只读归回 provider 原始产物。游标固定由父任务微秒时间和素材 ID 组成,API 必须同时识别整数微秒、seconds.microsZ与 RFC3339 时间文本;内部时间无法编码时返回服务错误,不得静默返回nextCursor = null。接口只用于查询,不提供分类筛选,也不执行精选审核、返还或展示状态修改,不通过后台 SQL 直查私有表。图片放大、视频和音频预览统一调用仅后台管理员会话可访问的GET /admin/api/assets/read-url;该入口仅为预览允许后台跨 owner 签名,不改变主站/api/assets/read-*或 External API 的 owner 边界。成功换签后必须写入event_key = admin_asset_read_url的tracking_event,记录管理员 subject、Object Key / legacy path 和有效期,不记录 signed URL。 - 自定义世界 / RPG:
/api/runtime/custom-world*、/api/story/*、/api/runtime/chat/*。 - 拼图:
/api/runtime/puzzle/*。 - 抓大鹅 Match3D:
/api/creation/match3d/*、/api/runtime/match3d/*。 - 敲木鱼:
/api/creation/wooden-fish/*、/api/runtime/wooden-fish/*。 - 方洞挑战:
/api/creation/square-hole/*、/api/runtime/square-hole/*。 - 视觉小说:
/api/creation/visual-novel/*、/api/runtime/visual-novel/*。 - 大鱼吃小鱼:
/api/runtime/big-fish/*。 - 跳一跳:
/api/creation/jump-hop/*、/api/runtime/jump-hop/*。 - 汪汪声浪:
/api/runtime/bark-battle/*。 - 儿童向创作:
/api/creation/edutainment/*。
需要新增路由时,先确认玩法入口配置和 tracking 分类,不要绕过 app.rs 的统一中间件、鉴权和入口开关。涉及创作、生成、作品、公开详情、试玩、正式运行态、运行态库存、运行态设置 / 存档、游玩历史、存档归档、游玩统计、AI task、角色资产工坊或玩法生成支撑资产的路由,不再直接在 app.rs 逐玩法 .merge(...),也不挂到 modules/platform.rs;必须先进入 server-rs/crates/api-server/src/modules/play_flow.rs 的统一玩法流程主干,再由主干注册表分发到各领域 HTTP Adapter 或支撑能力 handler。
图片画布 Agent 对话
/api/editor/projects/{projectId}/agent-conversations负责当前工程会话列表和新建;/api/editor/agent-conversations/{conversationId}负责详情读取、终态工具消息懒回填和软删;POST /api/editor/agent-conversations/{conversationId}/messages负责发送消息并返回普通 JSONEditorAgentMessageResponse,画布 Agent 不提供/messages/streamSSE 路由。消息请求必须携带最长 128 字符的clientMessageId;前端对该 POST 显式启用 1 次瞬时 transport 重试,并复用同一个序列化 body、clientMessageId和x-request-id。同一会话在锁内按该键幂等,重复键同内容返回已有回合或从已保存用户消息继续,异内容返回409。数字EditorAgentMessage.id仍只作为工具确认 / 取消的后端消息定位符,不能复用为客户端幂等键。module-editor-agent只承载纯领域校验:标题派生、附件上限、消息输入规则和会话软删访问规则;不直接依赖 Axum、SpacetimeDB、OSS、LLM 或 Tokio。spacetime-module的editor_agent_conversation只保存元数据;创建、列表、读取、更新时间和软删通过create_editor_agent_conversation_and_return、list_editor_agent_conversations_and_return、get_editor_agent_conversation_and_return、touch_editor_agent_conversation_and_return、delete_editor_agent_conversation_and_returnprocedure 完成,api-server只能经spacetime-clientfacade 访问。- 完整消息文档存 OSS
editor-agent/{conversationId}.json,由api-server负责 2 MiB 上限、会话内串行锁、读改写、消息与工具结果持久化和touch元数据更新时间;该 JSON 不进入editor_canvas.layers_json,也不作为画布布局真相。LLM / 规划失败必须写入role=system、正文以ERROR开头的消息,并通过deltaMessages返回,errorMessage保持为空;前端隐藏前缀并显示红色错误气泡,后端仍把该 system 消息注入后续 LLM memory,使 Agent 能读取失败上下文。工具失败同样必须形成可回读记录,不能只返回瞬时错误。 - 对话附件只允许引用当前工程
editor_project_resource或当前账号editor_asset的图片;前端可提交展示用imageSrc/thumbnailSrc,后端必须按resourceId/assetId重新归一、校验 owner / project 和objectKey,再给 LLM 或生成工具使用。 - 画布 Agent 工具复用既有编辑器图片生成 / 修改 / 图标 spritesheet BFF,并继续使用后端模型定价和
execute_billable_asset_operation_with_cost;前端不提交priceMudPoints。 /messages/{messageId}/confirm与/messages/{messageId}/cancel只返回成功确认;前端成功后立即重新读取整个会话,以会话详情中的权威消息状态和externalJobId驱动气泡展示与任务轮询。- 画布 Agent 是“正式任务 payload 不进入通用用户 read model”规则的窄例外消费者:
GET /api/editor/agent-conversations/{conversationId}只按会话中已有的externalJobId定向读取主任务,完成后由对应工具 formatter 从result_payload_json提取并归一有界的图片 / 视频 / 音频引用,写入 OSS 工具消息后返回。前端仍不得通过通用任务列表 / 状态接口读取或解析request_payload_json/result_payload_json;OSS 轻量媒体引用只是会话展示与后续 Agent 上下文,不替代editor_project_resource、editor_asset、editor_canvas.layers_json或external_generation_job的业务真相。
创作 / 游玩统一流程主干
modules/play_flow.rs 是后端创作与游玩流程的统一入口。现有外部 URL、DTO、错误 envelope、鉴权方式、入口开关语义和 SpacetimeDB schema 默认不变,但路由组织必须遵循:
app.rs只合并modules::play_flow::router(state),不直接合并 RPG、拼图、抓大鹅、跳一跳、敲木鱼、拼消消、汪汪声浪、视觉小说或儿童向创作等逐玩法模块。play_flow统一注册每个玩法的playId、领域模块 key、创作路由前缀和运行态路由前缀;后续新增玩法或迁移旧玩法时,先补这个注册表,再挂具体领域模块路由。- 新建创作、首次生成和 Remix 成草稿等会产生新创作的入口开关匹配规则同样归
play_flow管理;creation_entry_config.rs只复用该规则执行open=false熔断,不再维护第二份路径判断。 play_flow在进入领域 handler 前先解析并挂载PlayFlowRequestContext,统一标记请求处于Creation、Runtime、CreationEntryConfig、CreationSupport、RuntimeSupport、AiTask、PublicReadModel或RuntimeInventory阶段,并记录目标playId/ 领域模块 key;领域 handler 可以读取该上下文做后续收口,但不能绕过主干自建平行流程。play_flow只做平台共性编排和领域 Adapter 组合,不下沉玩法规则;最后一步的草稿编译、资产生成、发布、运行态 start/action/finish、计分和排行榜仍交给对应module-*、spacetime-moduleprocedure 和玩法 HTTP handler 处理。- 公开作品聚合、作品详情、运行态库存、运行态设置 / 存档、游玩历史、存档归档、游玩统计、历史素材、AI task、runtime chat、文档解析、角色资产工坊、角色图像 / 动画生成和 Hyper3D 代理属于跨玩法或玩法支撑流程,也从
play_flow主干挂入;modules/platform.rs只保留通用 LLM / 语音代理,不再承接创作 / 游玩支撑路由。 - 如果某个旧玩法仍使用历史
/api/runtime/<play>/agent/*作为创作命名空间,只保留外部兼容路径;新增实现和文档仍按“统一主干 -> 领域 Adapter”的语义描述,不把历史路径当新架构模板。
认证态用户与会话摘要下发口径
AuthUserPayload/AuthUser只保留前端当前会用到的身份与绑定展示字段:id、publicUserCode、displayName、avatarUrl、phoneNumber、phoneNumberMasked、loginMethod、bindingStatus、wechatBound、wechatDisplayName、wechatAccount。账号信息面板展示微信绑定时优先使用wechatDisplayName;该字段只能来自微信平台 profile、历史已保存的微信身份资料,或小程序原生input type="nickname"提交的displayName,不得用系统账号显示名或“微信旅人”这类假昵称兜底。小程序/api/auth/wechat/miniprogram-login与/api/auth/wechat/bind-phone可接收displayName;/api/auth/wechat/miniprogram-login额外返回created,供小程序壳在快捷登录后判断是否需要补采集微信昵称。jscode2session无法直接返回微信昵称或个人微信号,只能稳定拿到小程序维度openid,后端以wechatAccount下发可区分的绑定账号标识,前端在缺少真实昵称时展示账号尾号。AuthSessionSummaryPayload/AuthSessionSummary只保留设备卡片与撤销需要的摘要字段:sessionId、sessionIds、sessionCount、clientLabel、ipMasked、isCurrent、createdAt、lastSeenAt、expiresAt。- 设备诊断信息(例如原始
clientType/clientRuntime/clientPlatform/userAgent/miniProgramAppId/miniProgramEnv/deviceDisplayName)不再默认下发到前端;若未来确需展示,优先单独加窄 DTO,而不是把账号 / 会话快照恢复为全量对象。 - 多端登录语义以
refresh_session为粒度:同一账号可保留多个 active session,普通登录不会撤销旧设备;POST /api/auth/logout只撤销当前 refresh session,不提升token_version;POST /api/auth/logout-all、改密、重置密码才吊销全端 session 并提升token_version。鉴权中间件仍校验 Bearersid对应的 refresh session 是否 active,单独踢下线或当前设备退出可以让目标设备立即失效而不误伤其它设备。
api-server 模块化演进规则
api-server 的长期方向是从超大 app.rs 和超大 handler 文件收敛为按能力组织的 HTTP/BFF Module。后续改造必须保持 HTTP route、DTO、error envelope、SpacetimeDB schema、前端行为和计费语义默认不变;任何 contract 或 schema 变化都要先在当前文档中写清影响范围和迁移计划。
路由模块化规则:
- 每个能力 Module 只暴露
router(state) -> Router<AppState>;平台创作 / 游玩相关 Module 和支撑能力由modules/play_flow.rs统一.merge(...)或在支撑 router 内挂载,其它账号、资产基础、后台和平台基础能力再由app.rs直接合并。 app.rs只保留全局 middleware、TraceLayer、request context、tracking middleware、入口开关和少量顶层 glue;不得重新恢复逐玩法 creation/runtime merge 列表。- 能力 Module 可在路由内部用
FromRef<AppState>派生自己的 Feature State,例如PuzzleApiState。全局AppState仍作为进程组合根、鉴权层和全局中间件状态,但业务 handler 优先只提取对应 Feature State,不直接暴露完整AppState。 - Feature State 只暴露该能力实际需要的 facade / adapter / 配置快照;若必须复用仍要求
AppState的横切 helper(例如计费、外部失败审计或通用 tracking),应通过 Feature State 的窄方法或显式root_state()过渡,并在后续继续收窄。 - 路由迁移和业务重构分阶段处理;先移动路由装配,再拆 handler 内部实现,再收窄 handler 可见状态。
- 大 handler 拆分时优先按
router.rs、handlers.rs、application.rs、assets.rs、mapper.rs、errors.rs分层。handlers.rs只做 Axum extract、鉴权和 request/response,业务规则继续下沉到module-*。 - 手写 Rust 模块入口统一使用同名
.rs文件,例如puzzle.rs+puzzle/*.rs、match3d.rs+match3d/*.rs;不要再新增mod.rs入口。生成的 SpacetimeDB Rust bindings 也由生成脚本同步为module_bindings.rs+module_bindings/*.rs布局。
拼图 api-server 内部拆分:
server-rs/crates/api-server/src/modules/puzzle.rs只负责路由装配、鉴权层和参考图 body limit;对外继续引用同一批 handler 名称。server-rs/crates/api-server/src/state.rs中的PuzzleApiState是拼图 HTTP/BFF 的 Feature State,集中暴露SpacetimeClient、PuzzleGalleryCache、OSS client、作者查询所需认证服务、拼图 LLM client 和少量 VectorEngine / Agent 配置快照。拼图 handler 只提取State<PuzzleApiState>,不得重新改回State<AppState>。server-rs/crates/api-server/src/puzzle.rs只作为聚合入口,保留共享 import / 常量、内部模块声明和 handler re-export,不继续承载大段实现。server-rs/crates/api-server/src/puzzle/handlers.rs承接 Axum handler,负责 extract、鉴权上下文、调用 SpacetimeDB facade / 编排 helper,并返回 HTTP/SSE 响应。server-rs/crates/api-server/src/puzzle/draft.rs承接表单草稿保存、草稿编译、首关命名、UI 背景 prompt 和初始资产就绪校验。server-rs/crates/api-server/src/puzzle/generation.rs承接拼图图片与 UI 背景的生成编排、计费包裹和 reference image 路径选择。server-rs/crates/api-server/src/puzzle/vector_engine.rs承接 VectorEngine 请求体、HTTP 调用、下载 / base64 解码、OSS 写入、asset object / binding 持久化和上游错误归一。server-rs/crates/api-server/src/puzzle/mappers.rs承接 SpacetimeDB record 到 shared-contracts DTO 的映射。server-rs/crates/api-server/src/puzzle/tags.rs保留拼图标签生成、拼图通用错误映射和 SSE helper。
拼图发布 / 待发布门槛必须同时要求首图、关卡画面、UI spritesheet 与关卡背景资产包完整;module-puzzle::validate_publish_requirements 与 api-server::puzzle::tags::is_puzzle_session_snapshot_publish_ready 使用同一资产语言,不得只凭 cover、标题、描述和标签把半成品标为 publishReady 或 ready_to_publish。
该拆分只改变 api-server 文件组织,不改变 /api/runtime/puzzle/* route、DTO、error envelope、SpacetimeDB schema、公开 gallery cache 语义或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉。
/api/runtime/puzzle/runs* 当前接受 RuntimePrincipal,可同时识别登录用户 Bearer 和 runtime guest token。推荐页嵌入运行态的正式开局、交换、拖拽、下一关、暂停、道具与排行榜请求,应由前端在登录态下继续携带账号 access token;匿名游客仅在确认为未登录时走 runtime guest token。不要再把拼图 runtime 当成只认普通 Bearer 的纯账号接口。
公开正式 runtime 的启动与局内同步动作统一接受 RuntimePrincipal,包括拼图、拼消消、跳一跳、敲木鱼、抓大鹅 Match3D、方洞挑战、视觉小说、大鱼吃小鱼和汪汪声浪。登录用户仍使用账号 Bearer;未登录推荐页或公开运行态使用 Runtime Guest Token,后端以 principal.subject() 作为本局 owner / player subject,并用 WorkPlayTrackingDraft::runtime_principal(...) 记录游玩。创作、个人作品、删除、发布、Remix、点赞等账号或所有权动作不得改成 runtime guest 鉴权。
抓大鹅 Match3D api-server 内部拆分:
server-rs/crates/api-server/src/modules/match3d.rs继续负责路由装配和 body limit;对外 handler 名称保持不变。server-rs/crates/api-server/src/match3d.rs只作为聚合入口,保留共享 import / 常量 / 内部类型、模块声明和 handler re-export。server-rs/crates/api-server/src/match3d/handlers.rs承接 Axum handler,负责 extract、鉴权上下文、调用 SpacetimeDB facade / 编排 helper,并返回 HTTP 响应。/api/runtime/match3d/works/{profile_id}/runs、/api/runtime/match3d/runs/{run_id}、/click、/stop、/restart与/time-up属于正式运行态局部请求,必须接受RuntimePrincipal;登录用户使用账号 Bearer,推荐页匿名游客使用 runtime guest token,后端以 principal subject 作为本局 owner,不得退回只认普通 Bearer 的路由。server-rs/crates/api-server/src/match3d/draft.rs承接 Agent session、草稿编译、题材 / 难度 / 物品计划和草稿持久化编排。server-rs/crates/api-server/src/match3d/works.rs承接作品 CRUD、封面 / 背景 / 容器资产生成入口、发布 / Remix / 点赞 / 游玩记录和作品级 helper。server-rs/crates/api-server/src/match3d/item_assets.rs承接物品生成批次编排、append / replace / delete / sort / merge、计费外层和草稿素材映射;sheet prompt、绿幕 / 近白底透明化、切图和切片持久化复用generated_asset_sheets通用模块。server-rs/crates/api-server/src/match3d/vector_engine_gemini.rs仅保留历史 VectorEngine Gemini 物品 sheet helper;当前草稿物品 spritesheet 以关卡整图为参考走gpt-image-2编辑链路,提示词、绿幕透明化和 OSS 持久化由item_assets.rs/works.rs约束。server-rs/crates/api-server/src/match3d/runtime.rs保留运行态轻量归一 helper;mappers.rs/tags.rs/tests.rs分别承接 DTO 映射、标签 / 通用错误 helper 和原有单测。
该拆分只改变 api-server 文件组织,不改变 /api/creation/match3d/*、/api/runtime/match3d/* route、DTO、error envelope、SpacetimeDB schema、公开 gallery cache 语义、VectorEngine / OSS 副作用边界或计费语义;后续继续细分时也必须先保持行为不变,再单独讨论领域规则下沉到 module-match3d。
生成资产 Adapter 规则:
- 稳定单图链路可收敛到
api-server内部生成资产 Adapter:provider 生成、下载/base64 解码、MIME/extension 归一、OSS private upload、HEAD、asset object confirm、entity binding。 - Adapter 输入应显式包含 provider、prompt、reference images、OSS prefix/path/file name、asset kind、entity kind/id、slot、owner/profile/source job、metadata 和可选透明背景后处理。
- Adapter 输出应保留 legacy public path、object key、asset object id、MIME、extension、task id 和实际 prompt。
- Adapter 不负责扣费、退款或钱包读取;计费仍由调用方显式包裹。
- 图片 provider 协议不再放在玩法模块里实现。VectorEngine
gpt-image-2创建 / 编辑协议、URL / base64 图片解析、远端图片下载、请求超时 / 上游状态 / 响应解析 / 缺图 / 下载失败的结构化日志统一在server-rs/crates/platform-image/src/vector_engine/;其中client.rs只保留 provider 调用编排,transport.rs负责 HTTP client 与 reqwest 错误归一,request.rs负责请求体和路径,payload.rs负责响应 JSON 字段提取,response.rs负责响应状态分流和图片结果归一。api-server只负责配置校验、玩法 prompt 编排、OSS / asset object / binding 持久化、计费和外部 API 失败审计落库。 - OSS 平台适配日志统一在
server-rs/crates/platform-oss输出,覆盖sign_post_object、sign_get_object_url、head_object和put_object。日志字段固定使用provider、operation、bucket、endpoint、object_key/key_prefix、access、content_type、content_length、status、status_class、error_kind和elapsed_ms,只记录对象定位和排障信息;不得输出 AccessKey、policy、signature、Authorization header 或完整 signed URL。generated 私有对象上传时必须由 OSS 对象头承载浏览器 / CDN 缓存策略,默认写入Cache-Control: public, max-age=31536000, immutable,不得改成 api-server 本地磁盘静态资源兜底。 - Puzzle、Match3D、音频、GLB、视频等复杂媒体可以复用 OSS + asset object + binding 的底层持久化能力,但玩法专属处理规则留在各自编排层,不塞进公共接口。
- 拼图入口页与结果页新增关卡的本地参考图不走浏览器直传 OSS,前端读取为 Data URL 后随创作 action 提交,并在读取前限制 6MB、显示“图片≤6MB”。
api-server必须对 Data URL 实际字节数再次校验;历史图片才提交referenceImageAssetObjectId(s),后端校验asset_object的 bucket、kind、图片 MIME、大小和 owner 后签发只读 URL 给 VectorEngine 读取。 - 系列素材图集实现真相源在
server-rs/crates/platform-image/src/generated_asset_sheets/:调用方必须传入grid_size作为n*n的n,可选传入物品名称 prompt 模板和特殊设定 prompt;模块负责 sheet prompt 组装、按n*n切片、透明化、PNG 输出、OSS private upload 请求构造和 sheet / item / special prompt 元数据持久化。server-rs/crates/api-server/src/generated_asset_sheets.rs只保留AppState/AppError适配和兼容导出。玩法只负责规划 slot、调用具体生图 provider、计费、失败回写,以及把通用切片结果映射回自己的 DTO / 草稿 / runtime 字段。
SpacetimeDB schema 变更规则
- 任何 table、view、reducer、procedure、row shape 或 bindings 变化,都必须同步本文件表 / view 目录和生成绑定;真实 table 变化还必须同步
server-rs/crates/spacetime-module/src/migration.rs,view 属于派生投影,不写入迁移导入导出表清单。 - 已有表新增字段必须放在 Rust 表结构体最后,并设置明确
#[default(...)]。 - 已发布并持久化的 enum 新增 variant 只能追加到末尾,不能插入中间、删除、重命名或重排;否则会移动既有 variant 的判别序号,导致旧数据解释错误或生产发布 schema 迁移失败。
- 删除字段、改名、重排字段、改类型或修改字段属性前,必须先询问用户并确认迁移计划。
- Vec 字段不要直接写无法 const 求值的 default;需要默认空集合时优先使用
Option<Vec<T>>加#[default(None::<Vec<T>>)],业务层归一为空数组。 - 运行态读表必须按已声明索引访问。只要 table 上存在覆盖查询前缀的
#[index(...)]或主键 / unique accessor,列表、详情、快照组装和计数都先用对应 accessor.filter(...)/.find(...),再在内存中处理索引无法覆盖的残余条件;不得用.iter().filter(...)扫整表替代现成索引。 - 面向公开列表的只读投影优先做成 public view / public 读模型表,并由
api-server的spacetime-client长期订阅后读本地 cache。跨玩法公开作品统一主读模型是public_work_gallery_entry和public_work_detail_entry;公开作品资产读取授权投影是public_work_asset_read_grant;各玩法既有*_gallery_card_view/*_gallery_view/custom_world_gallery_entry保留为 source view 和兼容路径。短期不把作品列表整体交给浏览器前端直接订阅;不要让 HTTP 列表接口每次请求都调用 procedure 重新组装全量列表。需要请求时间窗口的轻量统计可订阅public_work_play_daily_stat后在api-server本地聚合,需要写入副作用的详情、点赞、游玩记录仍走玩法 procedure / reducer。前端不得直接订阅puzzle_work_profile、custom_world_profile等领域源表,也不得自己做 join、聚合或权限逻辑。首屏、排序、字段归一、权限降级和 HTTP fallback 由api-serverBFF 维持。 - 多列索引按 SpacetimeDB 绑定生成的元组参数直接传入,例如
.filter((source_type, profile_id, played_day));前缀查询只传前缀元组,例如.filter((scope_kind, scope_id.as_str()))。不要为了绕过类型问题退回整表遍历。 - procedure result 必须返回 typed snapshot / typed value。
spacetime-clientmapper 不得再通过row_json/session_json/work_json/items_json/run_json/event_json/feedback_json: Option<String>做跨层 JSON 字符串传输,也不得在 mapper 里反序列化旧*JsonRecord兼容结构。业务内部持久化字段如profile_payload_json、levels_json等不属于 procedure result 载荷例外,仍按各自表契约处理。 - 修改后运行:
npm run spacetime:generate
npm run check:spacetime-runtime-access
npm run check:spacetime-schema
npm run check:server-rs-ddd
本地联调和人工排障不要使用 spacetime --root-dir。本地数据隔离使用项目脚本或 --data-dir;发布目标显式传 --server / --server-url。
账户充值数据契约
profile_recharge_product_config是泥点和会员商品配置真相源,默认商品只在表为空时由 SpacetimeDB 播种。module-runtime中的默认商品 helper 只作为空库种子和兼容入口,不再作为运行期业务真相。- 默认泥点商品固定为四档:
points_60 = 60 泥点 / 600 分、points_180 = 180 + 90 泥点 / 1800 分、points_300 = 300 + 150 泥点 / 3000 分、points_680 = 680 + 340 泥点 / 6800 分。points_60的首充赠送为0;后三档首次购买分别赠送基础泥点的50%。 - 后台通过
/admin/api/profile/recharge-products读写充值商品配置;字段覆盖productId、标题、商品类型、金额分、基础泥点、首充赠送泥点、会员天数、徽标、说明、会员层级、会员每周期限时泥点、周期天数、队列上限、折扣率、启用状态和排序。 - 充值中心、下单校验和支付确认入账都读取
profile_recharge_product_config。充值中心 BFF 还必须在mudPointBalance下发totalPoints、permanentPoints、limitedPoints、limitedExpiresAt、dailyFreePoints、dailyFreeResetPoints和dailyFreeResetsAt;前端以该 read model 为真相源,不得自行用总额相减推算余额桶。当前版本公开 UI 只渲染不限时泥点和每日免费泥点,limitedPoints与limitedExpiresAt仅保留给存量兼容和后端结算。历史订单保留下单时写入的商品标题、金额、渠道、状态和 provider transaction id,不随配置改动回写。 - 泥点首充资格按
user_id + product_id的历史paid订单独立判断。某个档位已支付后,只隐藏该档位的首充赠送;其它未购买档位仍展示和结算首充赠送。 hasPointsRecharged只保留为账号是否发生过任一泥点充值的兼容字段,不得驱动所有商品展示隐藏或结算金额计算。前端只渲染后端返回的商品快照。- 当前版本公开充值 UI 只展示泥点商品,不渲染会员购买页签、会员商品、购买会员或升级会员入口。充值中心响应中的会员商品兼容字段、默认会员商品、
profile_membership和周期刷新逻辑继续保留;存量会员的cycle_remaining_points仍通过充值中心 read model 下发用于兼容和结算,但不作为限时泥点在当前版本前台展示。 - 默认会员商品为空库播种时使用
Starter / Basic / Pro / Ultimate四档,默认有效期均为 30 天,每周期限时泥点分别为200 / 800 / 2500 / 6000,队列上限分别为2 / 2 / 5 / 10。 - 会员有效期和周期重置时间是两条独立时间线。
expires_at只决定会员是否生效;cycle_resets_at只决定当前周期限时泥点何时重置。会员升级只更新档位并补齐当前周期限时泥点差额,不延长expires_at,不移动cycle_resets_at和周期天数。同级会员购买只从当前expires_at延长有效期,不发放额外当前周期泥点,也不移动重置时间。 - 会员周期刷新发生在个人中心、充值中心、任务中心、账单读取和钱包扣费入口:到达
cycle_resets_at时先清除上周期剩余限时泥点,再发放当前会员档位周期额度;会员过期时清除剩余限时泥点并把状态降为普通。周期发放和重置流水分别使用membership_period_grant、membership_period_reset。 paymentChannel缺失、未知或冒用小程序支付设备时必须拒绝;真实微信渠道只允许wechat_mp、wechat_mp_virtual、wechat_jsapi、wechat_h5、wechat_native,生产配置不得把真实支付静默降级为mock。- access JWT 只携带最小设备快照
device.client_type、device.client_runtime、device.client_platform。充值下单按该快照拦截小程序渠道:小程序只允许wechat_mp/wechat_mp_virtual;移动网页和微信内 H5 走wechat_h5;桌面网页和桌面微信走wechat_native;wechat_jsapi仅保留后端能力,未接微信开放平台前不由前端自动选择。历史普通 Web 登录态若缺少设备快照也允许继续进入 JSAPI / H5 / Native 渠道的后续支付配置校验,但不放宽小程序虚拟支付。 - 所有微信真实渠道都以微信支付通知或服务端查单确认
SUCCESS为到账事实;小程序、H5 跳转和 Native 二维码返回都不能直接发放泥点或会员。 - 微信 JSAPI / H5 / 小程序 / Native 下单统一显式传 5 分钟
time_expire,格式为 RFC3339 秒级时间;Native 额外通过wechatNativePayment.expiresAt下发给前端二维码弹窗展示。 - 真实微信渠道的新建 pending 充值订单会写入 SpacetimeDB 原生 scheduled 表
profile_recharge_order_expiration_timer。到期 reducer 只做数据库内状态转换:订单仍为pending时更新为expired并写expired_at,同时删除 timer。HTTPapi-server只订阅这张活跃 timer 表的删除事件,收到order_id后通过 procedure 重新读取订单,只有状态确认为expired才执行微信查单补偿;支付或主动关闭同样会删除 timer,但会被状态判断忽略。监听断线期间遗漏的删除事件由未检查过期订单 catch-up 补齐,不订阅完整profile_recharge_order历史表。普通微信支付查单中SUCCESS可把expired补确认成paid入账;NOTPAY会调用微信关单并把本地订单保持为expired;CLOSED/REVOKED/PAYERROR/ORDER_NOT_EXIST只记录检查结果。wechat_mp_virtual使用小程序access_token和虚拟支付 AppKey 调用官方/xpay/query_order,只在返回单号、支付类型order_type=0/7、金额、合法paid_time与本地契约一致且状态为2/3/4时补入账;退款类型1/8不得触发充值,其余已知状态只记录检查结果。short_series_goods从status=2恢复时先幂等入账,再调用/xpay/notify_provide_goods,失败后允许基于本地paid状态只重试发货;short_series_coin不调用现金单发货接口。external-generation-worker/ controller 不处理充值过期。 - 普通微信支付 V3 退款事实由
profile_recharge_refund保存,回调、退款 API 响应、主动查单和交易账单发现统一调用record_profile_recharge_refund_observation_and_return。out_refund_no是商户幂等键,provider_refund_id唯一;退款申请响应和主动查单等生产者生成 observation ID 时必须同时纳入来源和事实指纹,同一来源同一事实稳定重放、不同来源不得复用 ID;重复 observation 必须校验订单、交易、金额、状态、来源和指纹,不允许仅按主键直接吞掉冲突。 profile_recharge_order_refund_settlement按原订单聚合累计成功退款金额和权益回收。部分退款不改充值订单paid;累计金额等于订单金额时才改为refunded。历史支付和首充资格以paid_at是否存在判断,退款不把用户重新变成首充。- 泥点退款按累计成功退款比例计算目标回收量,全额退款强制精确回收原
points_delta。自动回收只扣普通永久泥点,每日免费和会员周期限时泥点保持不变;不足部分持久化为shortfall并冻结正式钱包消费,后续 worker 只重试本地回收。已成功退款的泥点订单若出现微信交易号、订单总额冲突或结算计划无效,必须将 settlement 标记为wallet_frozen并阻断普通消费。管理员只能对交易号或订单总额冲突执行“确认退款归属”:BFF 必须把微信退款事实的交易号、订单总额、当前冲突类型与本地订单值并排下发并展示,提交时携带管理员实际看到的expectedErrorCode,SpacetimeDB procedure 在同一事务内核对当前错误码一致后,才在退款行尾部不可变记录管理员、原因、时间和本次获批的错误码并重新运行标准结算;已处理请求只有管理员、归一化原因和错误码全部一致时才视为幂等重放,状态变化或任一审计内容不一致必须 fail-closed。一次确认只豁免对应的交易号或订单总额冲突,渠道、支付状态及其他未获批冲突继续 fail-closed。能追回的永久泥点照常扣除,余额不足继续形成欠账;不能直接清空冻结或伪造已追回量。非法结算计划仍保持冻结等待数据/代码修复。流水来源为recharge_refund_recovery。会员充值没有可逆 grant 快照,退款统一标记manual_review,不猜测回滚档位、有效期或周期泥点,也不复用泥点退款冻结语义。 - 外部现金退款
SUCCESS必须先持久化并 ACK,即使本地订单缺失、金额冲突、权益不足或会员需要人工处理,也不能回滚已经发生的现金事实。冲突 observation 记录 resolution code 并进入告警;只有验签、解密、契约解析或 SpacetimeDB 持久化失败才让微信重试。 - 主动查询与退款交易账单 worker 只由 HTTP 角色运行并由
WECHAT_PAY_REFUND_RECONCILIATION_ENABLED=true显式开启。生产 env 示例和 API deploy 会为缺失配置补true;当WECHAT_PAY_ENABLED=true + WECHAT_PAY_PROVIDER=real时显式关闭该开关必须阻断发布,启动日志也必须明确记录启用或异常关闭状态。非终态退款按 1 / 5 / 10 / 20 / 30 分钟衰减查单;北京时间次日 10 点后按 30 个稳定分片轮转补扫微信 API 可查询的近 90 天bill_type=REFUND交易账单,每 30 分钟覆盖完整窗口。单行失败不阻塞同日其他退款或其他日期,但该日不写完成 checkpoint 并继续重试;昨日返回NO_STATEMENT_EXIST时至少延迟到次日 10 点后再确认空账单。账单申请响应验签,GZIP 解压后按 SHA1 验真,CSV 用结构化 parser 和十进制定点金额解析;发现手工退款后必须再查单取得当前状态。 - 普通 V3 支付通知同时校验 AppID、商户号、本地订单渠道、金额和微信支付单号;
success_time缺失或非法时拒绝,不能用本机时间补齐。晚到通知遇到refunded订单只做交易号一致性幂等校验,不再次发放权益。 - 后台主动退款只支持
wechat_mp、wechat_jsapi、wechat_h5、wechat_native普通 V3 泥点订单。api-server必须先按正式支付渠道和商品类型拦截不支持的订单,再做微信支付订单查单预检,然后调用 SpacetimeDB procedure 原子创建退款 hold;只有 hold 成功才允许调用微信退款。wechat_mp_virtual、历史非正式渠道值、会员、未支付、对账未完成、退款已满额、人工冻结、退款欠账或永久泥点不足必须在调用普通 V3 provider 前 fail-closed。 profile_recharge_refund_hold以稳定out_refund_no为主键,保存订单、用户、本次退款金额、占用永久泥点、管理员、原因和active / settled / released状态。重试只有在订单、out_refund_no、退款金额、管理员和归一化原因全部与原 hold 一致时才可复用,任一不一致都按幂等内容冲突 fail-closed,不能用新原因调用微信后保留旧审计。部分退款的 hold 在累计应追回增量之外额外保留 1 泥点并发舍入缓冲,全额退款不加缓冲;活动 hold 不改变钱包总额,但普通钱包消费必须预留全部活动 hold;成功退款 observation 扣款并结算匹配 hold,关闭退款释放 hold,外部退款追回不得消耗其他活动 hold。- 退款欠账继续以
profile_recharge_order_refund_settlement.unrecovered_points为唯一真相;不新增平行 debt 累计。profile_wallet_manual_restriction只保存人工冻结,普通消费同时检查人工冻结与退款欠账。后续永久泥点到账后继续偿还欠账,每日免费与会员周期泥点不参与;解除人工冻结不得清除退款欠账限制。 - 管理员充值订单、用户详情、退款预检/执行、应急退款号登记、退款人工复核和钱包冻结接口只留在
api-server管理员鉴权路由。人工复核 BFF 必须从管理员会话写入操作人,要求非空原因,返回微信退款交易号、订单总额以及获批错误码等正式审计字段,并调用 runtime service identity 受限 procedure;后台确认面板必须展示这些后端事实,前端不得自行改 settlement 或钱包冻结。外部微信副作用由platform-wechat执行,退款/hold/钱包事务留在spacetime-module,后台前端只展示 BFF 返回的正式状态。
创作入口泥点扣费契约
creation_entry_type_config.unified_creation_spec_json内的mudPointCost是玩法新建草稿初始生成的泥点成本真相源,同时供入口卡展示和前端余额前置校验使用;旧契约缺失时允许按代码默认成本兜底。api-server执行拼图首图生成、抓大鹅完整草稿生成和汪汪声浪初始三图生成时,必须通过GET /api/creation-entry/config同源配置解析对应玩法成本后再调用钱包扣费 procedure,不得继续使用前端或后端硬编码常量作为实际扣费真相。- 结果页单图重生成、发布、道具使用和其它独立资产操作仍按各自业务操作成本执行;不要把初始草稿成本误套到这些单次操作上。
- 资产操作的预扣费必须 fail-closed:钱包或 SpacetimeDB 预扣费不可达、超时或返回业务错误时,
api-server直接返回错误,不允许继续调用图片、音频、GLB 等外部生成 provider。 - 需要支持 HTTP retry 的计费 ledger id 必须包含当前请求的
request_id;前端fetchWithApiAuth同一次业务请求的静默刷新重试复用同一个x-request-id,后端不得再使用 prompt 指纹或随机 asset id 作为扣费幂等键。 - 外部生成已预扣费但后续失败时必须先同步调用钱包退款;若 SpacetimeDB 暂不可用,退款请求写入
wallet-refund-outbox本地文件并由后台 worker 重放。默认启用,配置项为GENARRATIVE_WALLET_REFUND_OUTBOX_ENABLED、GENARRATIVE_WALLET_REFUND_OUTBOX_DIR、GENARRATIVE_WALLET_REFUND_OUTBOX_BATCH_SIZE、GENARRATIVE_WALLET_REFUND_OUTBOX_FLUSH_INTERVAL_MS和GENARRATIVE_WALLET_REFUND_OUTBOX_MAX_BYTES。outbox 文件按 refund ledger id 幂等落盘;成功重放后删除,坏文件隔离为corrupt-*。外部生成任务触发的扣费和退款必须在profile_wallet_ledger.metadata_json中写入externalGenerationJobId,outbox 重放也必须保留同一任务 ID,便于从退款记录追溯到正式生成任务。 - 拼图首图后台生成的跨实例互斥锁必须落在 SpacetimeDB
puzzle_background_compile_task表,claim id 由task_id + request_id构成,释放时必须校验 claim id,避免旧后台任务释放新请求抢到的租约。
用户钱包与编辑器生成扣费契约
- 新用户账号完成注册并成功同步正式认证表后,注册赠送金额读取
profile_wallet_config.initial_mud_points;后台通过/admin/api/profile/wallet-config维护“账号初始泥点数”。未写入配置时默认仍为100泥点。流水原因仍使用new_user_registration_reward,流水 ID 继续保持幂等,重复发放请求不得叠加余额。 - 用户钱包余额对外仍暴露为一个总余额,但后端扣费必须按“每日免费泥点 -> 会员周期限时泥点 -> 普通永久泥点”的顺序消耗,前端不得自行决定扣费桶。扣费流水
metadata_json必须记录dailyFreePointsDelta、dailyFreeDayKey、membershipPeriodPointsDelta、permanentPointsDelta和会员限时泥点所属cycleResetsAtMicros;资产退款中的会员限时泥点只在原周期仍有效时恢复会员额度,其余会员部分进入普通永久泥点。原每日免费消费部分在同一业务日退款时恢复原当日额度;跨北京时间业务日退款时叠加到退款当日每日免费桶,不进入普通永久泥点,当日granted_points与remaining_points均可因此超过20。原永久泥点消费部分无论是否跨业务日,均按退款流水中的permanentPointsDelta退回普通永久泥点。 - 每日免费泥点是独立于每日任务和会员周期的正式余额额度,基础发放量固定为
20,不得由前端或后台任务配置改写。profile_daily_free_points保存当前北京时间业务日、当日基础发放及跨日退款叠加后的总额度和剩余额度;北京时间每日00:00作为业务日边界,个人中心、充值中心、账单读取和钱包扣费入口在首次触达新业务日时原子清除昨日剩余及退款叠加量,并把今日granted_points、remaining_points重置为20。首次初始化使用daily_free_grant流水,跨日重置使用daily_free_reset流水。惰性落库不能改变“北京时间 00:00 后读取即为新日额度”的对外语义。 - 每日任务奖励继续使用
daily_task_reward流水并进入普通永久泥点,但主站隐藏每日任务卡片和任务中心入口,不再把每日登录任务描述为“每日免费泥点”。任务配置、进度、领取记录和后台管理能力暂时保留,除非后续需求明确删除。 - 编辑器画板所有会调用外部生成 provider 的入口都不从前端请求接收
priceMudPoints;同步请求以 SpacetimeDBeditor_generation_pricing_config当前全局配置计算,外部生成队列则以external_generation_job.price_mud_points保存的入队价格为准,worker 的扣费、退款、响应和资产成本不得按执行时配置重算。前端按钮泥点只作为展示。 - 编辑器图片生成 / 图片修改 / 图标 spritesheet / UI 设计图提取素材 / 视频 / 角色动作 / 音效 / 背景音乐必须在后端计算模型价格后使用
execute_billable_asset_operation_with_cost预扣泥点;预扣失败必须 fail-closed,不得继续提交 VectorEngine、Ark、Suno 或 Vidu 上游任务。 - 队列任务按
job_id + claim_attempt使用独立 consume/refund ledger。新 attempt 结算旧 attempt 时必须先写asset_operation_wallet_settlement:旧 consume 已存在则原子退款,尚不存在则写取消 intent;迟到 consume 在同一 SpacetimeDB 事务内看到 intent 后必须失败关闭。重复 consume/refund 只有用户、金额、来源和配对 ledger 全部一致时才可视为幂等成功。lease 过期时只有attempt < max_attempts才能递增并重领;最终 attempt 已耗尽时,claim transaction 必须直接把 job 收口为failed、清理 lease、写失败事件并结算当前 attempt,不能再把任务返回 worker 或调用 provider。 - 音频生成的编辑器链路虽然任务提交和结果发布分离,仍必须把提交时后端计算出的模型价格写入
AudioAssetBindingTarget.billing_points_cost,最终发布落资产时按该价格扣费;创作音频目标未提供该字段时才使用旧的创作音频固定成本。 - 编辑器进入外部生成持久队列的图片生成、图片修改、去背景、图标 spritesheet、UI 设计图提取、角色动作和视频参考图,只允许提交已登记的 generated
objectKey、resourceId或assetId;任务request_payload_json/result_payload_json任意层级都禁止data:/blob:,并受统一字节上限保护。objectKey 必须归属于当前账号的editor_project_resource、editor_asset或asset_object,后端通过归属校验后才签名读取 OSS。本地红框序号标注图必须先上传并确认对象,再把 objectKey 入队;不得把既有 objectKey 下载成 Data URL 后写入任务。图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入generationInputs展示快照;图片快速编辑当前不开放额外参考图。UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,图标素材上限 8 张额外参考图。同步且不持久化的历史兼容入口即使仍能解析 Data URL,也不能把该值转存到工程、素材、元数据、审计或任务表。
外部服务与资产
- LLM:通用 LLM 门面继续使用
GENARRATIVE_LLM_*;创意 Agentgpt-5.4-miniChat Completions 文本链路已于 2026-06 从 APIMart 迁移到 VectorEngine,使用VECTOR_ENGINE_BASE_URL/VECTOR_ENGINE_API_KEY构造 OpenAI-compatible client,api-server会把未带/v1的 VectorEngine base URL 规范化到/v1后请求/chat/completions。通用/api/llm/chat/completions代理使用GENARRATIVE_LLM_PROVIDER=openai-compatible、GENARRATIVE_LLM_BASE_URL=https://api.vectorengine.cn/v1、GENARRATIVE_LLM_MODEL=gpt-5.4-mini;未单独配置GENARRATIVE_LLM_API_KEY时可复用VECTOR_ENGINE_API_KEY。APIMART_BASE_URL/APIMART_API_KEY只作为历史残留,不再作为创意 Agent gpt-5.4-mini 客户端来源;后续排障时优先确认 VectorEngine/v1/models、/v1/chat/completions和/v1/responses可用性。 - 图片生成:VectorEngine
gpt-image-2图片 provider 归属platform-image,密钥只在后端环境变量中;api-server内的openai_image_generation.rs只是兼容调用面和外部失败审计桥接,不再承载 provider 协议实现。实际外部生成运行记录统一落tracking_event,event_key = external_generation_run,metadata 记录开始 / 结束时间、耗时、状态、成功标记、失败原因、provider task id 和结果摘要,不再写回过时的ai_task。DashScope 只按仍在使用的历史能力单独处理,不作为 GPT-image-2 兜底。VectorEngine/v1/images/generations和/v1/images/edits上游 POST 使用libcurl发送;reqwest只保留给参考图 URL 下载和响应中图片 URL 下载。/v1/images/edits的 multipart 参考图必须作为 libcurl 文件上传 part 发送,字段名为image,实现上使用Form::buffer(file_name, bytes)并设置Content-Type;不能只用contents(...).filename(...),否则上游会把请求转码为缺少图片并返回image is required。request_send阶段的 curl timeout / connect error 按可重试传输错误处理,最多尝试 5 次,并使用指数退避加短抖动;排障时优先看attempt、max_attempts、retry_delay_ms、reference_image_bytes_total和request_params,不要把SendRequest当成上游业务错误。 - 编辑器抠图服务:手动
POST /api/editor/images/background-removals继续代理独立 BiRefNet 服务,配置为GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL、GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN和GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_REQUEST_TIMEOUT_MS。角色形象生成、图标 spritesheet 生成和 UI 设计图素材提取的生成后纯色背景透明化改走独立 BgFilter 服务,配置为GENARRATIVE_EDITOR_BGFILTER_BASE_URL、GENARRATIVE_EDITOR_BGFILTER_TOKEN和GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS,默认 base URL 为http://58.87.105.82/bgfilter,默认请求超时为180000ms(BgFilter 当前为 CPU 推理,单次抠图较慢,必须留足超时),token 未配置时复用 BiRefNet token。BgFilter 请求必须显式传screen_color=<screenColor>和seg_model=<segModel>;前端用户路径不展示抠图模型选择并固定提交默认birefnet,后端仍识别内部保留的anime-seg,其中birefnet只表示 BgFilter 管线内部后端,不等同于手动去背景的独立 BiRefNet 服务。BgFilter 调用失败,或连续失败达到GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD(默认3)并在GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS(默认300)内打开熔断时,均跳过或结束 BgFilter 调用后复用同一兜底链:先调用阿里云通用抠图,阿里云失败才使用本地editor_green_screen键色扣除;熔断期不得直接退化到本地兜底。角色动作视频生成的背景色已与生图链路统一:screenColor=auto时由视觉 LLM(gpt-5-mini,Responses 协议、low 推理档)读源角色图自动决策,并经硬过滤器剔除与前景 / 皮肤撞色的候选,手动 hex 则尊重用户选择;透明源角色图在提交 Ark 图生视频前先合成到选定背景色实色,使视频背景等于抠图键色。抽帧后逐帧优先走阿里云通用抠图,失败时降级本地editor_green_screen键色兜底(按生成时选定的背景色,而非固定#00FF00)。阿里云通用抠图配置为GENARRATIVE_ALIYUN_MATTING_ENABLED、GENARRATIVE_ALIYUN_MATTING_ENDPOINT、GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_ID、GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_SECRET和GENARRATIVE_ALIYUN_MATTING_REQUEST_TIMEOUT_MS;未配置专用 AK/SK 时可复用ALIBABA_CLOUD_ACCESS_KEY_ID/ALIBABA_CLOUD_ACCESS_KEY_SECRET,默认 endpoint 为imageseg.cn-shanghai.aliyuncs.com。BgFilter 与阿里云抠图失败都写入external_api_call_failure审计。 - Match3D 物品 sheet:关卡整图完成后走 VectorEngine
/v1/images/editsmultipartimage,模型为gpt-image-2,2K 1:1输出10*10spritesheet;物品 sheet prompt 固定要求单一纯绿色#00FF00 / RGB(0,255,0)绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG,并把透明整图写入itemSpritesheetImageSrc/itemSpritesheetImageObjectKey。后端优先按透明 alpha 连通域从该 sheet 识别真实素材矩形并持久化 20 个物品、每个 5 个形态;识别数量不足时才回退10*10固定网格。通用系列素材图集的行列索引按每行 2 个物品计算,必须落在1..=10,难度只决定运行态加载 3 / 9 / 15 / 20 种。 - Match3D UI spritesheet 和背景派生图:关卡整图作为参考图并发生成
1K 1:1UI spritesheet 与1K 9:16背景图,模型均为gpt-image-2。UI spritesheet prompt 固定要求单一纯绿色#00FF00 / RGB(0,255,0)绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG;背景图必须合成为全画幅不透明 PNG。 - Match3D 1:1 容器 UI:VectorEngine
/v1/images/editsmultipart 参考图。该容器参考图是后端生图协议输入,必须通过include_bytes!随api-server编译进二进制,避免 API 单独发布或运行目录缺少public/时生成失败。 - 敲木鱼敲击物和背景环境图:VectorEngine
/v1/images/edits,模型固定gpt-image-2。敲击物支持 multipart 多参考图,第一张固定为后端内嵌默认木鱼图,用户上传图只作为新主题参考;prompt 必须要求1:1单一纯绿色#00FF00 / RGB(0,255,0)绿幕背景主体图,并禁止黑底、白底、棋盘格和任何实底背景。当前敲击物和返回按钮上传 OSS 前只做服务端绿幕去背后处理,避免泛抠图误伤玉米等主体像素。背景环境图只使用第一步抠图完成后的透明敲击物图作为参考,prompt 必须要求中央主体预留区保持干净,中央 40% 区域禁止出现主题主体、主体局部特写、轮廓影子或重复元素,主题元素只能作为外围氛围,且必须显式声明不继承任何绿色底色、绿幕底色或纯绿色画布。 - Hyper3D / Rodin:只保留后端安全代理和旧数据兼容;Rodin 提交、状态、下载和响应解析归属
platform-hyper3d,api-server/src/hyper3d_generation.rs只做路由、配置和错误 envelope 映射;新 Match3D 草稿和批量新增不再生成 GLB。 - 音频:视觉小说专用音频路由保留;VectorEngine Suno/Vidu provider 协议、任务提交/查询、音频 URL 提取、下载、MIME/extension 归一和 OSS put 请求准备归属
platform-audio。api-server/src/vector_engine_audio_generation.rs只做路由、配置、计费、asset object confirm、entity binding 和错误 envelope 映射;拼图、抓大鹅和敲木鱼提示词生成音效入口暂时关闭,通用/api/creation/audio/*对这些目标返回410 Gone。敲木鱼创作只接收上传 / 录音音频资产;前端选择或录音阶段只在浏览器本地处理待提交音频,统一限制裁切后最长 1 秒、裁掉前后声音过小片段,并用浏览器端近似响度算法平衡到-15 LKFS后做峰值保护。点击生成时才直传 OSS 并确认asset_object,创作 JSON 只提交轻量WoodenFishAudioAsset,不得继续上传 Data URL 音频;未提供时由api-server写回内置默认木鱼音/wooden-fish/default-hit-sound.mp3。 - OSS:私有 generated path 进入浏览器前必须通过
/api/assets/read-url换签;不要裸请求/generated-*。请求参数的安全语义不能混用:legacyPublicPath是历史公开作品兼容口,只允许platform_oss::LEGACY_PUBLIC_PREFIXES中的 curated 前缀匿名换签;objectKey是正式对象引用,绝不能复用该前缀旁路,必须查询asset_object并校验配置 bucket、精确 key、PublicRead或当前 owner。External OpenAPI 的/api/external/v1/assets/read-url还必须有editor:assetscope,并始终以 API Key 绑定的owner_user_id执行同一 owner 校验;后台跨账号预览只能走管理员鉴权后的/admin/api/assets/read-url。/api/assets/read-bytes与主站 read-url 共用完全相同的授权,默认仍应由浏览器使用 signed URL 直读,bytes 只作跨域字节读取 fallback。前端如果收到同一 OSS bucket 的完整https://*.oss-*.aliyuncs.com/generated-*地址,也必须先归一为 legacy path 后走同一换签链路,避免裸连私有 bucket 403 或绕过签名缓存。OSS 签名、读签名、HEAD 和 PUT 的结构化日志由platform-oss输出,排查资产写入 / 确认失败时优先按operation、object_key/key_prefix、status_class、error_kind和elapsed_ms下钻。新上传 generated 私有对象默认写入Cache-Control: public, max-age=31536000, immutable;旧对象若缺该头,只能依赖ETag/Last-Modified协商缓存,应通过 OSS 元数据刷新或 CDN 配置补齐,不要恢复 api-server 静态代理。editor-agent/前缀只用于服务端内部读写画布 Agent 会话消息文档,不属于浏览器直传 legacy public prefix;/api/assets/direct-upload-tickets必须拒绝legacyPrefix=editor-agent,内部读取只允许editor-agent/{conversationId}.json形态。 - 外部 API 失败审计:外部供应商调用未成功时,
api-server必须发送 OTLP 失败事件并写入tracking_event。VectorEngine 图片 provider 在platform-image内输出结构化日志和PlatformImageFailureAudit,覆盖request_send、response_body、upstream_status、response_parse、missing_image和image_download阶段;编辑器screenColor=auto的 gpt-5-mini 背景色决策同样必须审计每次已发出的 LLM 调用失败,包括传输 / 超时、上游拒绝、响应体解析、空响应和返回候选外颜色;即使随后降级默认背景色并继续主流程也不得只记 warning。api-server将这些失败映射成external_api_call_failure,scope_kind = module、scope_id = provider、module_key = external-api。metadata 固定包含 provider、endpoint、operation、failureStage、statusCode、statusClass、timeout、retryable、errorMessage、latencyMs、promptChars、referenceImageCount、imageModel、rawExcerpt,以及在调用方可获得上下文时补充的userId(触发者)和profileId(草稿 / 作品 / 场景作用域)。图片生成入口应优先把 owner user id 和 profile id 透传到失败审计,不要只保留 provider 级聚合,否则很难按“谁触发、哪个作品触发”定位问题。入库优先复用 tracking outbox,outbox 不可写或保护阈值拒绝时回退同步写 SpacetimeDB;不得新增前端兜底或在 SpacetimeDB reducer 内做外部 I/O。 - 外部生成运行记录:所有外部生成编排的完成态统一写入
tracking_event,event_key = external_generation_run,scope_kind = module,scope_id = provider,module_key = external-generation。metadata 固定包含runId、provider、operation、requestLabel、requestPayload、status、success、failureReason、providerRequestId、resultPayload、startedAtMicros、completedAtMicros和durationMs。这类记录只用于运行审计和排障,不再走ai_task旧表。
SpacetimeDB 表目录
下列 ### 标题是 schema guard 的机器可读表目录。新增、删除或改名表时必须同步这里。
ai_result_reference
- Rust 结构体:
AiResultReference - 源码:
server-rs/crates/spacetime-module/src/ai/stages.rs
ai_task
- Rust 结构体:
AiTask - 源码:
server-rs/crates/spacetime-module/src/ai/tasks.rs
ai_task_event
- Rust 结构体:
AiTaskEvent - 源码:
server-rs/crates/spacetime-module/src/ai/events.rs
ai_task_stage
- Rust 结构体:
AiTaskStage - 源码:
server-rs/crates/spacetime-module/src/ai/stages.rs
external_generation_job
- Rust 结构体:
ExternalGenerationJob - 源码:
server-rs/crates/spacetime-module/src/external_generation.rs - 用途:外部生成 worker 的内部持久任务队列;
GENARRATIVE_EXTERNAL_GENERATION_MODE=queue时,api-serverHTTP 角色只入队,external-generation-worker角色通过 claim lease 领取、续租、执行,并用lease_token栅栏回写完成 / 失败。队列行继续保存 worker 执行、计费与滚动发布兼容所需字段,但用户可见任务列表、价格、状态、未确认终态数量和通知确认时间的正式读取事实源已经迁到external_generation_job_summary;BFF 不得再为列表 / 详情 / acknowledge 读取该大表。拼图compile_puzzle_draft的前置compile_puzzle_agent_draft、generate_puzzle_images与generate_puzzle_ui_background的业务写回也在对应 SpacetimeDB transaction 内校验job_id + worker_id + lease_token、job kind、owner 和 source entity,避免过期 worker 写 session / work profile;图片画布编辑器的editor_image_generation、editor_image_edit、editor_background_removal、editor_icon_spritesheet_generation、editor_ui_design_asset_extraction、editor_character_animation_generation、editor_video_generation、editor_sound_effect_generation和editor_background_music_generation复用同一队列表,worker 成功后经api-serverfacade 写入editor_project_resource/editor_asset/editor_canvas.layers_json,前端只通过 BFF job 状态轮询和项目快照读取恢复完成态。GENARRATIVE_EXTERNAL_GENERATION_MODE=inline时不创建该队列行,三个 external generation guard 字段必须同时为空才允许 api-server 受控同步写回,半空 guard 仍会拒绝。worker 成功写回业务事实后才能 complete job;业务失败态写回成功后才能 fail job,失败态未写回时保留租约等待后续重领。 - 载荷约束:本次先对
source_module = editor-canvas的request_payload_json/result_payload_json实施有限大小合法 JSON、任意层级禁止data:/blob:的双层门禁,只保存 worker 执行必需的普通参数和已登记媒体引用;图标图集生成和 UI 素材提取成功但自动拆分降级时,worker 的result_payload_json只额外保存有界的warning.code/reason,不保存内联媒体。其它玩法在完成各自参考图资源化之前不由本次门禁静默改变既有请求契约。该主表只供 worker claim / 执行、受控维护以及画布 Agent 会话按已有externalJobId定向懒回填读取;正式用户任务列表、单任务状态、队列概览与 acknowledge 不得返回或解析这两个 payload。画布 Agent 懒回填必须经对应工具 formatter 归一为有界轻量媒体引用后写入 OSS 会话,不能把原始 payload 直接透传前端。
external_generation_job_summary
- Rust 结构体:
ExternalGenerationJobSummary - 源码:
server-rs/crates/spacetime-module/src/external_generation.rs - 用途:外部生成正式任务列表的轻量投影,按
job_id保存 owner、来源、状态、价格、有界错误摘要、有界非阻断告警warning_message、通知确认时间、各阶段时间和入队时提取的request_prompt,不包含 request/result payload、worker lease 或 dedupe 内部字段。错误与告警摘要都不复制内联媒体并限制为 2048 字符;warning_message由完成任务的轻量result_payload_json.warning.reason提取,complete 和历史 backfill 共用同一构建路径。列表在单次 owner 扫描中同时计数并只保留请求 limit 的固定大小 top-N,不得先收集全量历史再截断。enqueue、claim、renew、complete、fail 事务同步投影;acknowledge 只更新该轻量表并写审计事件,后续主任务同步必须保留已有确认时间,禁止为了写确认时间加载 / 重写大 payload 行。BFF 的列表、状态和确认只调用 summary procedure。历史终态任务由迁移操作员的游标分批 maintenance procedure 在压缩 payload 时同步回填摘要,正式列表不得为兼容旧数据回扫完整主表。 - 正式读取 procedure 为
get_external_generation_job_summary_and_return、list_external_generation_job_summaries_and_return和acknowledge_external_generation_job_summaries_and_return。历史维护 procedure 为compact_external_generation_job_payloads_and_return与backfill_external_generation_job_summaries_and_return,仅 migration operator 可调用;运维入口统一使用npm run spacetime:external-generation:maintain -- ...,默认 dry-run、单批最多 25 条。B-tree cursor 选择阶段最多反序列化limit + 1行,apply 再按主键逐条读取选中行;怀疑存在单行异常巨型 JSON 时必须先使用--limit 1。payload 压缩额外固定使用source_module = editor-canvas的复合 cursor 索引,不得静默改写其它玩法历史任务。
external_generation_job_event
- Rust 结构体:
ExternalGenerationJobEvent - 源码:
server-rs/crates/spacetime-module/src/external_generation.rs - 用途:外部生成任务审计事件表,按
job_id和owner_user_id记录enqueued、claimed、lease_renewed、completed、failed、acknowledged等状态转换事实。状态转换只能由 SpacetimeDB procedure 写入,不由前端或 worker 直接改表;该表用于追溯任务生命周期和排障,不替代external_generation_job当前状态。
ai_text_chunk
- Rust 结构体:
AiTextChunk - 源码:
server-rs/crates/spacetime-module/src/ai/stages.rs
analytics_date_dimension
- Rust 结构体:
AnalyticsDateDimension - 源码:
server-rs/crates/spacetime-module/src/runtime/analytics_date_dimension.rs
asset_entity_binding
- Rust 结构体:
AssetEntityBinding - 源码:
server-rs/crates/spacetime-module/src/asset_metadata/bindings.rs
asset_event
- Rust 结构体:
AssetEvent - 源码:
server-rs/crates/spacetime-module/src/asset_metadata/objects.rs
asset_object
- Rust 结构体:
AssetObject - 源码:
server-rs/crates/spacetime-module/src/asset_metadata/objects.rs - 说明:对象 metadata 以 bucket / key 标识正式对象及其 owner、访问策略。确认接口的 owner 必须来自登录会话或 External API Key 绑定的认证主体,不接受请求体指定 owner;同 bucket / key 首次登记后,重复 confirm 不得改变 owner。已登记对象默认并继续保持
private。API 通过get_asset_object_by_location_and_return/get_asset_object_by_id_and_return在服务端索引上权威查询 private table;资产读取 ACL 使用get_asset_read_access_by_location_and_return在同一事务快照内同时返回位置查询与公开作品派生授权,procedure 只允许 runtime service identity 调用。授权判断先取得资产 owner,再按各玩法现有 owner 索引定向扫描该作者公开作品,并仅对候选asset_object_id/ 精确object_keygrant ID 做匹配,不得为每张图片生成全站公开作品 grant 列表。spacetime-client不订阅全量asset_object,也不把公开资产授权 view 的连接级 cache 当成安全判断。位置查询发现重复 bucket / key 时失败关闭,不能任选一条继续授权。只有权威位置查询返回不存在的历史对象才能进入 curated legacy 白名单兼容。
SpacetimeDB view:public_work_asset_read_grant
- Rust view:
public_work_asset_read_grant - 返回类型:
Vec<PublicWorkAssetReadGrant> - 源码:
server-rs/crates/spacetime-module/src/public_asset_access.rs - 说明:匿名公开派生授权投影,仅从
Published + visible作品(custom-world还必须满足未删除)的正式发布快照收集实际使用的已登记资产。每条 grant 都携带作品 owner,读取时必须与asset_object.owner_user_id一致,并且只能按asset_object_id或精确object_key命中;跨 owner、同前缀或相似 key 不构成授权。历史公开作品由 view 现算自动补齐;资产读取 procedure 与 view 复用同一套玩法资产采集器,但安全判断按资产 owner 索引定向计算,不执行全站 view。作品隐藏、删除或取消发布提交后,后续事务立即拒绝授权。已签发的公开 URL 最长保留 600 秒,能力本身不承诺撤销已经签出的 OSS URL。投影明确排除参考图、未选中候选图和generationInputs;Custom World 只扫描角色、地标、营地、章节和 opening CG 等正式根,不递归 legacy payload 未知字段,避免把预览、编辑输入或同会话其他私有资产扩大为公开资产。
auth_identity
- Rust 结构体:
AuthIdentity - 源码:
server-rs/crates/spacetime-module/src/auth/tables.rs - 职责:只表达登录入口身份键到
user_account.user_id的绑定;provider_uid保存手机号 E.164 或微信 openid,provider_union_id保存微信 unionid。账户资料以user_account.phone_number_e164、user_account.display_name、user_account.avatar_url为准,auth_identity.phone_e164/display_name/avatar_url仅保留旧行兼容,不再作为写入或恢复真相。
auth_store_projection_meta
- Rust 结构体:
AuthStoreProjectionMeta - 源码:
server-rs/crates/spacetime-module/src/auth/tables.rs
认证恢复策略:api-server 启动时只从 SpacetimeDB 正式认证表(user_account / auth_identity / refresh_session)导出 typed AuthStoreProjectionView,再恢复 module-auth 的进程内认证工作集;运行中 Bearer sid 或 refresh cookie 在本进程工作集内未命中时直接按失效处理,不再从 SpacetimeDB 导出整包认证状态刷新内存,避免旧投影把重复手机号或旧会话重新灌回进程。module-auth 只保留内存工作集和 projection 导入 / 导出能力,不再保留 JSON 快照导入 / 导出能力,也不写本地持久化文件;auth-store.json / GENARRATIVE_AUTH_STORE_PATH 不再是兼容恢复源。认证创建、登录会话、刷新、退出、改密、重置密码、绑定和资料变更等写操作必须在返回客户端前通过 sync_auth_store_projection 成功同步 SpacetimeDB 正式认证表;同步失败时接口返回错误,不允许把只存在于当前进程内存的账号或会话当成成功结果。新用户注册奖励、邀请码绑定和登录埋点必须排在认证同步成功之后,避免认证没落库时先写出钱包或邀请关系。若启动恢复阶段 SpacetimeDB 不可连接或超时,api-server 会按固定间隔持续重试认证工作集恢复,恢复成功后才开始监听 HTTP,避免一次短超时让进程永久停留在依赖不可用状态。
auth_store_snapshot 表和旧 import_auth_store_snapshot_json / export_auth_store_snapshot_from_tables procedure 已删除。认证投影同步只读写 user_account、auth_identity、refresh_session 和 auth_store_projection_meta;auth_identity 不再写 phone_e164、display_name、avatar_url,这些账号资料只以 user_account 为准。
bark_battle_draft_config
- Rust 结构体:
BarkBattleDraftConfigRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
bark_battle_leaderboard_entry
- Rust 结构体:
BarkBattleLeaderboardEntryRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
bark_battle_personal_best_projection
- Rust 结构体:
BarkBattlePersonalBestProjectionRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
bark_battle_published_config
- Rust 结构体:
BarkBattlePublishedConfigRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
bark_battle_runtime_run
- Rust 结构体:
BarkBattleRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
bark_battle_score_record
- Rust 结构体:
BarkBattleScoreRecordRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
bark_battle_work_stats_projection
- Rust 结构体:
BarkBattleWorkStatsProjectionRow - 源码:
server-rs/crates/spacetime-module/src/bark_battle/tables.rs
battle_state
- Rust 结构体:
BattleState - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
big_fish_agent_message
- Rust 结构体:
BigFishAgentMessage - 源码:
server-rs/crates/spacetime-module/src/big_fish/tables.rs
big_fish_asset_slot
- Rust 结构体:
BigFishAssetSlot - 源码:
server-rs/crates/spacetime-module/src/big_fish/tables.rs
big_fish_creation_session
- Rust 结构体:
BigFishCreationSession - 源码:
server-rs/crates/spacetime-module/src/big_fish/tables.rs - 索引:
by_big_fish_session_owner_user_id、by_big_fish_session_stage。公开广场 view 使用by_big_fish_session_stage读取已发布会话,避免扫整表。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
big_fish_event
- Rust 结构体:
BigFishEvent - 源码:
server-rs/crates/spacetime-module/src/big_fish/events.rs
big_fish_runtime_run
- Rust 结构体:
BigFishRuntimeRun - 源码:
server-rs/crates/spacetime-module/src/big_fish/tables.rs
SpacetimeDB view:big_fish_gallery_view
- Rust view:
big_fish_gallery_view - 返回类型:
Vec<BigFishWorkSummarySnapshot> - 源码:
server-rs/crates/spacetime-module/src/big_fish/session.rs - 说明:大鱼吃小鱼公开 source 投影,只从
Publishedcreation session 组装公开卡片字段;统一公开列表 / 详情主路径通过public_work_gallery_entry/public_work_detail_entry消费该 view 并映射成跨玩法契约。玩法旧 gallery 路径保留兼容 shape;个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。
chapter_progression
- Rust 结构体:
ChapterProgression - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
creation_entry_config
- Rust 结构体:
CreationEntryConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs - 字段:
config_id、start_title、start_description、start_idle_badge、start_busy_badge、modal_title、modal_description、updated_at、event_title、event_description、event_cover_image_src、event_prize_pool_mud_points、event_starts_at_text、event_ends_at_text、event_banners_json、public_work_interactions_json。 - 迁移兼容:旧迁移包缺少活动横幅字段时,由
migration.rs写入None/58000默认值;旧库缺少event_banners_json时写入None,运行态读取层再按module-runtime默认公告数组归一,不覆盖后台已保存配置,也不把旧结构化eventBanner升格为前端优先数组。旧库缺少public_work_interactions_json时写入None,读取层按module-runtime默认作品互动矩阵补齐publicWorkInteractions,不覆盖后台已保存开关。HTTP 响应同时返回eventBanners数组、旧eventBanner单条兼容字段和publicWorkInteractions互动矩阵;前端优先消费数组与矩阵。后台新公告配置主格式为 HTML 公告字符串数组或{title, htmlCode}对象数组,旧结构化 banner 字段仅保留兼容。默认公告背景和旧结构化默认coverImageSrc必须引用public/下真实存在的静态资源,当前为/creation-type-references/puzzle.webp。
creation_entry_type_config
- Rust 结构体:
CreationEntryTypeConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs - 字段:
id、title、subtitle、badge、image_src、visible、open、sort_order、updated_at、category_id、category_label、category_sort_order、unified_creation_spec_json。 - 迁移兼容:旧迁移包缺少入口分类字段或统一创作契约字段时,由
migration.rs写入None/0/None默认值;入口分组展示由module-runtime和前端展示派生消费,统一创作契约由module-runtime解析为creationTypes[].unifiedCreationSpec,为空时按shared-contracts中当前支持的统一创作默认 spec 回退。unifiedCreationSpec.title是统一创作页表头契约内容,读取和保存时不按入口title自动覆盖。
feature_gate_config
- Rust 结构体:
FeatureGateConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/feature_gate_config.rs - 字段:
gate_key、enabled、rollout_percent、allow_user_ids、allow_user_tags、deny_user_ids、description、updated_at。 - 用途:通用功能灰度事实源。当前创作入口使用
creation-entry:<id>约定关联入口 ID;api-server按当前可选登录用户、用户标签和稳定百分比判定后,只把过滤后的入口配置返回普通前端,不下发灰度规则或用户标签。 - 迁移兼容:新增表不改已有入口表字段;未配置 gate 或
enabled=false时不限制功能,黑名单用户 ID 优先于白名单和百分比命中。
custom_world_agent_message
- Rust 结构体:
CustomWorldAgentMessage - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs
custom_world_agent_operation
- Rust 结构体:
CustomWorldAgentOperation - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs
custom_world_agent_session
- Rust 结构体:
CustomWorldAgentSession - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs - 发布约束:
publish_world的 action payload 不要求携带settingText;spacetime-module调用module-custom-world::resolve_custom_world_publish_setting_text(...),优先从当前draft_profile_json草稿真相派生正式setting_text,避免旧会话seed_text为空时在最终 compile / publish 阶段触发custom_world.setting_text 不能为空。
custom_world_draft_card
- Rust 结构体:
CustomWorldDraftCard - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs
custom_world_gallery_entry
- Rust 结构体:
CustomWorldGalleryEntry - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs - 作用:自定义世界公开 source 读模型。统一公开列表 / 详情主路径通过
public_work_gallery_entry/public_work_detail_entry消费该投影并映射成跨玩法契约;/api/runtime/custom-world-gallery保留旧 HTTP shape,并从统一 public cache 映射回旧 DTO。旧 procedure 只用于兼容旧库缺少 gallery 读模型行时的一次性同步兜底。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
custom_world_profile
- Rust 结构体:
CustomWorldProfile - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。 - 兼容约束:历史公开 RPG / 自定义世界 profile 可能存在
publication_status=Published但published_at=None。公开详情、点赞、游玩、Remix 和custom_world_gallery_entry同步都以Published + deleted_at=None + visible=true判断作品可公开互动;展示和 gallery 同步时间在published_at缺失时回退updated_at,不得仅因published_at为空返回“已发布作品不存在”。
custom_world_session
- Rust 结构体:
CustomWorldSession - 源码:
server-rs/crates/spacetime-module/src/custom_world.rs
database_migration_import_chunk
- Rust 结构体:
DatabaseMigrationImportChunk - 源码:
server-rs/crates/spacetime-module/src/migration.rs
database_migration_operator
- Rust 结构体:
DatabaseMigrationOperator - 源码:
server-rs/crates/spacetime-module/src/migration.rs - 说明:migration operator 与在线 runtime writer 必须身份互斥。当前 runtime writer 不能被授权为 operator,任何已登记 operator 也不能成为 runtime writer;一旦已有 operator,bootstrap secret 不得新增或接管 operator,后续授权只能由既有 operator 完成。
external_api_key
- Rust 结构体:
ExternalApiKey - 源码:
server-rs/crates/spacetime-module/src/external_api_key_storage.rs - 说明:外部 OpenAPI 调用使用的账号级 API Key 凭据表,只保存 key prefix、SHA-256 hash、作用域、撤销状态和使用时间;明文 Key 只在
/api/profile/api-keys创建接口返回一次,不进入 SpacetimeDB,且 API Key 管理接口不写入外部 OpenAPI JSON。v1 默认作用域为editor:project、editor:canvas、editor:image-generate、editor:asset;其中editor:project覆盖项目列表、最近项目、创建、读取、重命名和删除,editor:canvas覆盖默认画布布局保存,editor:image-generate覆盖编辑器现有图片生成、重绘 / 调整、规范图、宣发素材、图标 spritesheet 生成 / 拆分、UI 设计图素材拆分、角色动画、视频、音效和背景音乐生成,editor:asset覆盖素材直传凭证、素材对象确认、签名读取、账号级素材库和项目画布资源记录操作。 - 索引:
by_external_api_key_owner_user_id用于登录态 API Key 列表;key_hash唯一索引用于外部 API 鉴权。
admin_account
- Rust 结构体:
AdminAccount - 源码:
server-rs/crates/spacetime-module/src/admin_account_storage.rs - 说明:后台 member 私有账号表,保存规范化用户名、展示名、Argon2id 密码摘要、一级 Tab 权限 JSON、启停状态、会话版本和创建 / 更新审计字段。原环境变量管理员作为虚拟 owner,不写入该表。账号查询与写入 procedure 只接受 runtime service identity;HTTP 列表和写响应不返回密码摘要。
- 索引:
account_id为主键,username为唯一登录名;权限、密码或启停状态发生变化时在同一事务递增token_version,使旧 JWT 下一次请求立即失效。
editor_agent_conversation
- Rust 结构体:
EditorAgentConversation - 源码:
server-rs/crates/spacetime-module/src/editor_agent_storage.rs - 说明:画布Agent对话会话元数据表,归属单个
editor_project;只保存会话 ID、project、owner、标题、消息 OSS 对象键(editor-agent/{conversationId}.json)、软删标记和时间戳。消息正文整体存 OSS,按会话粒度整体读写,不进 SpacetimeDB、不进画布工程快照 payload。删除为软删(deleted = true,OSS 对象保留)。领域校验(标题截取、附件上限、归属 / 软删规则)沉在module-editor-agent。 - 过程:只通过
create_editor_agent_conversation_and_return、list_editor_agent_conversations_and_return、get_editor_agent_conversation_and_return、touch_editor_agent_conversation_and_return、delete_editor_agent_conversation_and_returnprocedure 操作;api-server不直接绕过spacetime-clientfacade 读写表。消息文档当前由api-server做单会话串行锁和 2 MiB 上限保护,避免同一 SSE 回合并发重写同一个 OSS JSON 文档。 - 索引:
by_editor_agent_conversation_project_id用于会话列表;by_editor_agent_conversation_owner_user_id用于账号级归属校验。
editor_project
- Rust 结构体:
EditorProject - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布工程真相表,保存 owner、标题和工程时间戳;viewport 与图层布局已拆到
editor_canvas,旧 layout columns 暂作为兼容列保留,不再作为权威数据源。只通过/api/editor/projects*、/api/editor/projects/{projectId}/agent-conversations、/api/editor/agent-conversations/{conversationId}*BFF 和spacetime-clientfacade 读写;项目页列表、重命名和删除也使用该能力,删除工程时级联清理默认画布和资源元数据。 - 索引:
by_editor_project_owner_user_id用于读取当前用户最近编辑工程和项目页工程列表。
editor_canvas
- Rust 结构体:
EditorCanvas - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布数据表,归属于
editor_project,保存默认画布的 viewport typed columns、图层布局 JSON、owner 和时间戳;当前编辑器读取 / 保存 project 的默认 canvas,后续支持一个工程多个 canvas。 - 索引:
by_editor_canvas_project_id、by_editor_canvas_owner_user_id。
editor_project_resource
- Rust 结构体:
EditorProjectResource - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布工程资源元数据表,保存已经放入某个 project 画布的上传 / 生成图片资源快照、OSS 引用、尺寸、来源类型、prompt、provider、task、源资源关系、
asset_kind、generation_inputs_json和历史public_showcase_enabled。asset_kind标记角色、图标、UI 设计图、视频、音频等素材类别;generation_inputs_json保存用户可见生成输入快照,供图片信息页刷新后恢复。public_showcase_enabled只保留旧接口兼容,不再作为/creation的陶泥儿精选事实源;精选公开改由账号级生成素材提交editor_showcase_asset审核决定。图片 / 图标 / UI 提取等生成 BFF 在请求携带project_id时负责创建该表记录并把 resource 快照返回前端;前端只保存布局引用,不能把同一生成结果再次作为正式业务真相写入。项目封面快照也落在该表,使用asset_kind = project-cover-snapshot、source_type = uploaded和私有 OSS / asset object 引用,代表画布当前视口栅格化后的静态封面;项目列表和创作主页最近项目只读取最新封面快照资源,不在列表页根据editor_canvas.layers_json临时拼画布。从账号级素材库把同一生成素材拖回同一项目画布时,后端优先复用同项目内同源同媒体资源,避免每个图层实例都插入新的资源行。账号级素材删除不级联删除该表,避免历史画布丢图。editor_canvas.layers_json只保存图层几何、层级、分组、资源引用和生成器对象;新写入不再把素材生成输入快照作为图层布局真相保存,旧布局字段只作为兼容兜底读取。 - 索引:
by_editor_project_resource_project_id、by_editor_project_resource_owner_user_id。
editor_asset_folder
- Rust 结构体:
EditorAssetFolder - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布账号级素材文件夹表,归属于用户账号而不是 project;首次读取素材库时自动创建系统默认“项目素材”文件夹。文件夹支持重命名、折叠和删除,系统默认文件夹不能删除。
- 索引:
by_editor_asset_folder_owner_user_id。
editor_asset
- Rust 结构体:
EditorAsset - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布账号级素材表,保存用户上传 / 生成素材的名称、文件夹、图片读取地址、可选封面
thumbnail_src、OSS 引用、尺寸、来源类型、prompt、provider、真实操作task_id、可选后台归组group_task_id、拆分批次预期数量group_task_expected_asset_count、asset_kind、generation_inputs_json、可选source_resource_id和generation_cost_mud_points。归组字段追加在表尾并默认None,只用于稳定派生任务的后台分组,不替代task_id;批次是否初始完整以独立完成事实为准,不按当前剩余素材数反推。素材在同一账号的所有项目中可见;图片 / 图标 / UI 提取等生成 BFF 在请求携带asset_folder_id时负责创建账号级生成素材并返回 asset 快照,若同次生成也创建了editor_project_resource,则把该resource_id写入source_resource_id。角色动作生成保留原始绿幕视频中间素材,同时把最终帧序列作为一条asset_kind = character-animation素材入库:首帧写入image_src/thumbnail_src,完整帧列表、FPS、时长和预览视频写入generation_inputs_json.characterAnimation,不把每帧拆成独立素材。生成视频会抽取首帧封面写入thumbnail_src,素材库和再次放入画布时用它作为 video poster。素材库快照通过asset_id回查对应editor_showcase_asset,供左侧素材菜单展示pending/approved/rejected审核状态;公开事实不落在账号素材表,素材库只发起提交审核。素材放入画布时复制为editor_project_resource并由图层引用 resourceId,画布从 resource / asset 级元数据恢复素材类别和用户可见生成输入快照。 - 索引:
by_editor_asset_owner_user_id、by_editor_asset_folder_id。
editor_asset_group_source_provenance
- Rust 结构体:
EditorAssetGroupSourceProvenance - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:手动图集拆分的私有可信来源索引。仅当账号素材由后端生成链路写入且具有正式
source_resource_id时,按 owner + source resource、asset object 和 Object Key 记录真实来源task_id;普通素材 / 资源创建请求不能直接写该表。跨项目复用素材后可通过稳定媒体引用找回原任务,历史行首次扫描命中后补写索引。 - 主键:
lookup_key。
editor_asset_group_cohort
- Rust 结构体:
EditorAssetGroupCohort - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:手动拆分批次的私有完成事实。api-server 只有在预期的全部 asset ID 已成功落库并由 runtime service identity 逐行校验 owner、真实 task、归组 task 和预期数量一致后才能插入;事实写入后不随用户删除单片素材而撤销。没有完成事实的现代批次不能并入来源根任务。
- 主键:
cohort_id。
editor_showcase_asset
- Rust 结构体:
EditorShowcaseAsset - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:
陶泥儿精选的独立审核与公开快照表。用户从账号级生成素材提交后,后端把素材媒体、提示词、生成输入、素材类型和generation_cost_mud_points快照到该表,初始review_status = pending、display_enabled = false且showcase_category = null。后台审核通过后写入approved,但仍保持不展示;运营可在后台按前台具体 Tab 手动设置showcase_category(characters、ui、music、marketing)并开启展示。未设置分类的素材不归入具体 Tab,但展示开启后仍进入前台“全部”。审核通过时生成确定性返还流水editor-showcase-refund:{showcase_id},BFF 按 50% 生成成本返还泥点后回写refund_completed_at;拒绝后写入rejected。公开精选GET /api/editor/showcase/resources读取review_status = approved、display_enabled = true且媒体非空的记录,按通过时间 /showcase_id倒序 cursor 分页。素材删除时,待审核记录标记asset_deleted_while_pending,已拒绝记录删除,已通过记录保留快照继续展示。 - 索引:
by_editor_showcase_asset_owner_user_id、by_editor_showcase_asset_review_status。
editor_showcase_asset_like
- Rust 结构体:
EditorShowcaseAssetLike - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:
陶泥儿精选点赞去重表,主键由showcase_id:user_id组成。点赞 / 取消点赞通过登录接口更新该表,并同步回写editor_showcase_asset.like_count;未通过审核或未展示的精选素材不能点赞。 - 索引:
by_editor_showcase_asset_like_showcase_id、by_editor_showcase_asset_like_user_id。
editor_showcase_campaign_config
- Rust 结构体:
EditorShowcaseCampaignConfig - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:
陶泥儿精选首位固定活动卡配置表,当前使用固定config_id = global。后台可配置启用状态、标题、图片地址、提示词、作者和成本文案;上传按钮通过后台受控上传票据把图片写入 OSS,保存时同时落image_src、内部图片 OSSimage_object_key、image_width和image_height。公开精选接口只在启用时返回该配置,前端优先用image_object_key走签名读地址展示,并按记录的图片宽高决定活动卡比例。 - 索引:主键
config_id。
editor_generation_pricing_config
- Rust 结构体:
EditorGenerationPricingConfig - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:图片画布生成类模型定价全局配置表,当前使用固定
config_id = global。models: Vec<EditorGenerationModelPricing>强类型保存模型、定价单位、单价或档位列表,procedure /spacetime-client边界不传递不透明 JSON;模块事务会再次校验完整正式模型矩阵、必需档位、单位、正价格和重复键。writer_identity只保留在 private 表内,记录首次初始化的真实ctx.sender(),不进入 procedure 返回快照;后续upsert_editor_generation_pricing_config_and_return只允许同一 identity 或已授权迁移操作员修改价格,但始终保留原 writer。表为空时只有 HTTP 角色通过initialize_editor_generation_pricing_config_if_missing_and_return在单事务内仅缺失时种子入库;worker / controller 启动只调用受鉴权的 queue-stats procedure 做只读身份预检。后台保存请求携带AppConfig中的受保护 bootstrap secret,以便配置行意外缺失时原子恢复;表存在时 bootstrap secret 不能接管 writer。原始 bootstrap secret 固定为 64 位十六进制;WASM 只嵌入其 SHA-256,procedure 对入参原文重新计算摘要并做常量时间比较。runtime queue / 钱包 procedure 只接受精确 writer,当前生产 API / worker / controller 因此继承同一 runtime token;迁移操作员不自动获得在线运行权限,且 operator / writer 身份必须互斥。SpacetimeDB 不可达时仅使用默认 JSON 或旧 override 缓存兜底。 - 索引:主键
config_id。
editor_generation_runtime_identity_rotation
- Rust 结构体:
EditorGenerationRuntimeIdentityRotation - 源码:
server-rs/crates/spacetime-module/src/editor_project_storage.rs - 说明:模型生成运行时服务 identity 显式轮换审计表。只有已授权迁移操作员可调用
rotate_editor_generation_runtime_service_identity_and_return,且新 writer 不能等于当前 writer,也不能是任一已登记 migration operator。每次记录旧 writer、新 writer、迁移操作员 identity、操作人、原因和服务端时间;轮换只修改 writer,不覆盖已有模型价格。生产人工入口为scripts/deploy/production-runtime-writer-identity-rotate.mjs,CLI 会核对当前登录 operator identity 并要求双录新 identity。 - 索引:自增主键
rotation_id。
inventory_slot
- Rust 结构体:
InventorySlot - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
jump_hop_agent_session
- Rust 结构体:
JumpHopAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/jump_hop/tables.rs
jump_hop_event
- Rust 结构体:
JumpHopEventRow - 源码:
server-rs/crates/spacetime-module/src/jump_hop/tables.rs
jump_hop_leaderboard_entry
- Rust 结构体:
JumpHopLeaderboardEntryRow - 源码:
server-rs/crates/spacetime-module/src/jump_hop/tables.rs - 说明:跳一跳作品维度排行榜 read model,每个
profile_id + player_id只保留 1 条最佳记录;排序口径为成功跳跃次数降序、游戏时长升序、更新时间升序,草稿试玩不作为公开排行榜语义。 - 展示契约:
player_id只作为后端去重和viewerBest匹配身份键,不得直接进入 HTTP/UI 展示字段;/api/runtime/jump-hop/works/{profile_id}/leaderboard必须补齐displayName,已登录玩家读取账号显示名,匿名游客展示“游客玩家”,失效账号展示“失效玩家”。
jump_hop_runtime_run
- Rust 结构体:
JumpHopRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/jump_hop/tables.rs - 说明:运行记录持久化
runtime_mode,取值为draft/published;草稿试玩只允许作品所有者启动,不累计公开游玩次数,也不写入公开排行榜。
jump_hop_work_profile
- Rust 结构体:
JumpHopWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/jump_hop/tables.rs - 说明:作品投影持久化独立
theme_text,用于生成主题和公开卡片主题展示;历史行为空时按work_title兜底。back_button_asset_json保存 image2 单独生成并去绿后的 1:1 左上角返回按钮资产快照;旧迁移数据按None兼容,运行态缺失该字段时使用同尺寸 CSS 主题按钮兜底。
SpacetimeDB view:jump_hop_gallery_card_view
- Rust view:
jump_hop_gallery_card_view - 返回类型:
Vec<JumpHopGalleryCardViewRow> - 源码:
server-rs/crates/spacetime-module/src/jump_hop.rs - 说明:跳一跳公开列表 source 投影,只暴露
publication_status = Published的作品卡片字段;统一公开列表主路径通过public_work_gallery_entry消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
SpacetimeDB view:jump_hop_gallery_view
- Rust view:
jump_hop_gallery_view - 返回类型:
Vec<JumpHopGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/jump_hop.rs - 说明:跳一跳公开详情兼容投影,包含作品、路径和素材字段;统一公开详情主路径通过
public_work_detail_entry消费该 view,只保留平台详情页展示摘要。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
wooden_fish_agent_session
- Rust 结构体:
WoodenFishAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/wooden_fish/tables.rs
wooden_fish_event
- Rust 结构体:
WoodenFishEventRow - 源码:
server-rs/crates/spacetime-module/src/wooden_fish/tables.rs
wooden_fish_runtime_run
- Rust 结构体:
WoodenFishRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/wooden_fish/tables.rs
wooden_fish_work_profile
- Rust 结构体:
WoodenFishWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/wooden_fish/tables.rs - 说明:敲木鱼作品 profile 真相,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效、飘字配置、发布状态和公开计数;
background_asset_json保存 image2 生成的 9:16 背景环境图资产快照,back_button_asset_json保存 image2 生成并去绿后的 1:1 返回按钮图资产快照,旧迁移数据按None兼容。
SpacetimeDB view:wooden_fish_gallery_card_view
- Rust view:
wooden_fish_gallery_card_view - 返回类型:
Vec<WoodenFishGalleryCardViewRow> - 源码:
server-rs/crates/spacetime-module/src/wooden_fish.rs - 说明:敲木鱼公开列表 source 投影,只暴露
publication_status = published的作品卡片字段;统一公开列表主路径通过public_work_gallery_entry消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布和运行态仍按 procedure 路径处理。
SpacetimeDB view:wooden_fish_gallery_view
- Rust view:
wooden_fish_gallery_view - 返回类型:
Vec<WoodenFishGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/wooden_fish.rs - 说明:敲木鱼公开详情兼容投影,包含敲击物图案、背景环境图、主题返回按钮图、敲击音效和飘字配置;统一公开详情主路径通过
public_work_detail_entry消费该 view,只保留平台详情页展示摘要。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
match3d_agent_message
- Rust 结构体:
Match3DAgentMessageRow - 源码:
server-rs/crates/spacetime-module/src/match3d/tables.rs
match3d_agent_session
- Rust 结构体:
Match3DAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/match3d/tables.rs
match3d_runtime_run
- Rust 结构体:
Match3DRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/match3d/tables.rs
match_3_d_work_profile
- Rust 结构体:
Match3DWorkProfileRow - Rust accessor:
match_3_d_work_profile - 源码:
server-rs/crates/spacetime-module/src/match3d/tables.rs - 兼容说明:dev 现有 SpacetimeDB 元数据中的真实表名 / 索引名为
match_3_d_work_profile与match_3_d_work_profile_*_idx_btree。module 内部 accessor 必须与该 canonical name 对齐,避免 Rust SDK 在index_id_from_name初始化二级索引时查找match3d_work_profile_*并触发No such indexpanic。migration.rs仍兼容旧迁移包中的match3d_work_profile表名补默认字段。
SpacetimeDB view:match_3_d_gallery_view
- Rust view:
match3d_gallery_view - 返回类型:
Vec<Match3DGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/match3d.rs - 说明:抓大鹅公开 source 投影,只暴露
publication_status = published的作品卡片字段;统一公开列表 / 详情主路径通过public_work_gallery_entry/public_work_detail_entry消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
npc_state
- Rust 结构体:
NpcState - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
player_progression
- Rust 结构体:
PlayerProgression - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
profile_dashboard_state
- Rust 结构体:
ProfileDashboardState - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_daily_free_points
- Rust 结构体:
ProfileDailyFreePoints - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:每日免费泥点事实源。
day_key使用北京时间业务日,基础发放量固定为20,remaining_points保存当日剩余额度;跨业务日退款的每日免费消费部分会叠加到退款当日,使granted_points和remaining_points可暂时超过20,下一业务日首次触达时旧余额与叠加量一并失效并重置为20。
profile_feedback_submission
- Rust 结构体:
ProfileFeedbackSubmission - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_invite_code
- Rust 结构体:
ProfileInviteCode - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 生效时间:
starts_at/expires_at均可为空;两者同时存在时必须满足starts_at < expires_at。开始时刻计入有效区间,截止时刻不计入有效区间。
profile_code_operation
- Rust 结构体:
ProfileCodeOperation - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:后台兑换码 / 邀请码的持久操作记录,记录新增、更新、停用的码值、操作人和操作时间。
profile_membership
- Rust 结构体:
ProfileMembership - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:会员有效期和当前周期限时泥点事实源。
started_at/expires_at表示会员有效期,cycle_started_at/cycle_resets_at/cycle_period_days表示当前周期,cycle_granted_points/cycle_remaining_points表示当前周期已发放和剩余限时泥点。
profile_recharge_product_config
- Rust 结构体:
ProfileRechargeProductConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:泥点和会员充值商品配置真相源,供充值中心展示、下单校验、支付确认和后台“充值商品”页维护;当前公开充值中心只展示四档泥点商品,会员商品配置留存但不公开购买或升级入口。
- 字段补充:会员商品追加
membership_period_points、membership_period_days、membership_queue_limit、membership_discount_bps;泥点商品这些字段必须为0。
profile_played_world
- Rust 结构体:
ProfilePlayedWorld - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_recharge_order
- Rust 结构体:
ProfileRechargeOrder - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:账户充值订单事实源。
status包含pending、paid、failed、closed、refunded、expired;过期补偿字段expired_at、expiration_checked_at、expiration_provider_state、expiration_last_error用于记录本地过期和微信查单结果。
profile_recharge_refund
- Rust 结构体:
ProfileRechargeRefund - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:普通微信支付 V3 退款单聚合。以
out_refund_no为主键、provider_refund_id唯一,保存原订单/微信支付单、四个分金额、微信状态、最近观察、权益目标/已回收/未回收量和人工处理错误码。管理员读取契约同步暴露微信交易号、订单总额和人工复核获批错误码。交易号或订单总额冲突经管理员确认归属后,追加保存处理管理员、非空原因、处理时间和本次获批的错误码;四字段只写一次,作为重新执行正式结算的审计事实。 - 索引:
by_profile_recharge_refund_order_id、by_profile_recharge_refund_status_updated_at。
profile_recharge_refund_observation
- Rust 结构体:
ProfileRechargeRefundObservation - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:退款事实的追加观察记录。保存 callback / api_request / query / trade_bill 来源、按“来源 + 事实指纹”稳定生成的 observation ID、金额、状态、脱敏通知引用、事实指纹和 resolution code;同一事实从不同来源进入时使用不同 ID,不保存回调密文、签名、密钥、原始 CSV 或短时下载 URL。
- 索引:
by_profile_recharge_refund_observation_out_refund_no、by_profile_recharge_refund_observation_order_id。
profile_recharge_order_refund_settlement
- Rust 结构体:
ProfileRechargeOrderRefundSettlement - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:原充值订单维度的退款与权益结算摘要,保存累计成功退款金额、目标/已回收/未回收泥点、权益状态和钱包冻结事实。部分退款不改订单终态;累计全额才把订单改为
refunded。 - 索引:主键
order_id,by_profile_recharge_order_refund_settlement_user_id用于钱包消费前检查退款欠款。
profile_recharge_refund_hold
- Rust 结构体:
ProfileRechargeRefundHold - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:后台主动退款调用微信前的永久泥点占用。活动占用保护退款所需泥点但不改钱包总额;匹配退款成功后结算,关闭或确认未创建的退款释放。相同
out_refund_no只允许内容完全一致的幂等重放。 - 索引:主键
out_refund_no,by_profile_recharge_refund_hold_order_id、by_profile_recharge_refund_hold_user_id、by_profile_recharge_refund_hold_status。
profile_wallet_manual_restriction
- Rust 结构体:
ProfileWalletManualRestriction - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:后台人工钱包冻结当前态,保存冻结原因、创建/更新管理员和时间。它不承载退款欠账;退款欠账仍来自订单退款 settlement,两个来源任一有效都阻断普通消费。
- 索引:主键
user_id。
profile_recharge_refund_bill_checkpoint
- Rust 结构体:
ProfileRechargeRefundBillCheckpoint - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:按交易账单日期记录已完成的退款 reconciliation,保存账单 SHA1(确认稳定无账单时保存
NO_STATEMENT_EXIST)、处理退款行数和完成时间。任一退款行失败时不写完成 checkpoint,成功前缀依赖 observation 幂等重放;重复下载、多实例执行或进程重启不会重复回收权益。
profile_recharge_order_expiration_schedule
- Rust 结构体:
ProfileRechargeOrderExpirationSchedule - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:旧普通微信充值订单到期查单调度表,保留 schema 兼容但当前不再写入;当前过期路径改由原生 scheduled 表
profile_recharge_order_expiration_timer触发。
profile_recharge_order_expiration_timer
- Rust 结构体:
ProfileRechargeOrderExpirationTimer - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:充值订单原生 scheduled 表,
scheduled_at到点触发expire_profile_recharge_order_timer;order_id唯一,支付成功、本地关闭或 scheduled reducer 执行后删除对应行。
profile_redeem_code
- Rust 结构体:
ProfileRedeemCode - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 生效时间:复用邀请码时间窗口语义,
starts_at/expires_at均可为空;两者同时存在时必须满足starts_at < expires_at。开始时刻计入有效区间,截止时刻不计入有效区间。用户兑换时以后端接收的redeemed_at_micros判定:未到开始时间拒绝为“兑换码未生效”,到达或超过截止时间拒绝为“兑换码已过期”。 - 后台契约:
AdminUpsertProfileRedeemCodeRequest通过可空startsAt/expiresAt接收 RFC3339 时间,列表与保存响应同步返回这两个字段;后台页只负责输入、回填和显示,真正兑换判定留在后端事务路径。
profile_redeem_code_usage
- Rust 结构体:
ProfileRedeemCodeUsage - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_referral_relation
- Rust 结构体:
ProfileReferralRelation - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_save_archive
- Rust 结构体:
ProfileSaveArchive - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_task_config
- Rust 结构体:
ProfileTaskConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_task_progress
- Rust 结构体:
ProfileTaskProgress - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_task_reward_claim
- Rust 结构体:
ProfileTaskRewardClaim - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
profile_wallet_ledger
- Rust 结构体:
ProfileWalletLedger - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 说明:账号钱包流水表。
created_at表示钱包事务实际结算时间,列表先按当前余额反向校验balance_after - amount_delta的结算链,再以该时间倒序兜底,避免支付回调或退款重放延迟时出现余额顺序倒置;支付平台确认时间继续保存在充值订单paid_at。metadata_json为可选 JSON 对象字符串,旧行缺失时读取层按{}归一;外部生成扣费 / 退款写入externalGenerationJobId,使退款记录可以追溯到对应external_generation_job。
asset_operation_wallet_settlement
- Rust 结构体:
AssetOperationWalletSettlement - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 说明:资产操作 consume/refund 配对结算事实表,主键为 consume ledger ID,并保存配对 refund ledger、用户、金额和结算时间。退款先到且 consume 尚不可见时,该表作为持久化取消 intent;迟到 consume 必须检测该行并拒绝扣费,避免 worker 崩溃重领期间双扣。
- 索引:主键
consume_ledger_id。
profile_wallet_config
- Rust 结构体:
ProfileWalletConfig - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 作用:账号钱包全局配置真相源,当前维护新账号注册初始泥点数;表为空时业务回退
100泥点。
public_work_like
- Rust 结构体:
PublicWorkLike - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
public_work_play_daily_stat
- Rust 结构体:
PublicWorkPlayDailyStat - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs
puzzle_agent_message
- Rust 结构体:
PuzzleAgentMessageRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs
puzzle_agent_session
- Rust 结构体:
PuzzleAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs
puzzle_background_compile_task
- Rust 结构体:
PuzzleBackgroundCompileTaskRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs - 说明:拼图首图后台生成的跨 api-server 实例互斥 claim 表,只保存活动任务租约,不表达最终生成结果;
task_id为主键,claim_id用于释放时防止误删新租约,租约超时时间为 30 分钟。
puzzle_event
- Rust 结构体:
PuzzleEvent - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs
puzzle_leaderboard_entry
- Rust 结构体:
PuzzleLeaderboardEntryRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs
puzzle_runtime_run
- Rust 结构体:
PuzzleRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs
puzzle_work_profile
- Rust 结构体:
PuzzleWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs - 说明:拼图作品 profile 表,保存草稿 / 已发布作品的标题、作者、关卡、封面、发布状态、可见性、基础游玩数、点赞数、改造数和积分激励领取状态。
- 字段变更:
visible控制是否进入公开列表 / 详情、通关后的推荐下一作品候选、公开点赞 / Remix 和正式公开 runtime;新作品默认false,旧迁移数据按历史公开默认补true。后台隐藏后作品可保留publication_status = Published,但公开消费路径必须按Published + visible=true判断。
puzzle_clear_agent_session
- Rust 结构体:
PuzzleClearAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs - 说明:拼消消创作会话表,保存轻表单草稿、生成状态、已发布 profile 关联和更新时间;只由拼消消 procedure 读写。
puzzle_clear_work_profile
- Rust 结构体:
PuzzleClearWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs - 说明:拼消消作品 profile 表,保存中央底图资产、4 张素材工作表切片后合成的最终 atlas、35 个复合图案组、95 个 1x1 卡牌切片、卡背占位图、发布状态、可见性和基础 play count;公开列表 / 详情只通过 read model 消费,不让前端直接订阅源表。
- 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
puzzle_clear_runtime_run
- Rust 结构体:
PuzzleClearRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs - 说明:拼消消正式 runtime run 表,保存当前关卡、已消除次数、棋盘 snapshot、开始 / 完成时间和 run 状态;正式胜负、重试、完成、超时和交换结果以后端 procedure 裁决为准。
puzzle_clear_event
- Rust 结构体:
PuzzleClearEventRow - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs - 说明:拼消消基础 runtime 事件表,记录 published run 的开局、关卡完成、全局完成、失败、超时和消除统计来源;首版不做排行榜。
SpacetimeDB view:puzzle_clear_gallery_view
- Rust view:
puzzle_clear_gallery_view - 返回类型:
Vec<PuzzleClearGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear.rs - 说明:拼消消公开详情 source 投影,只暴露
publication_status = published且visible = true的作品,包含 atlas、底图、图案组和卡牌切片等详情级字段;统一公开详情主路径通过public_work_detail_entry消费该 view,只保留平台详情页展示摘要。
SpacetimeDB view:puzzle_clear_gallery_card_view
- Rust view:
puzzle_clear_gallery_card_view - 返回类型:
Vec<PuzzleClearGalleryCardViewRow> - 源码:
server-rs/crates/spacetime-module/src/puzzle_clear.rs - 说明:拼消消公开列表 source 投影,只暴露平台卡片需要的公开字段;统一公开列表主路径通过
public_work_gallery_entry消费该 view,/api/runtime/puzzle-clear/gallery保留玩法专属 HTTP shape。
SpacetimeDB view:puzzle_gallery_view
- Rust view:
puzzle_gallery_view - 返回类型:
Vec<PuzzleWorkProfile> - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs - 说明:拼图广场公开详情 source / 兼容投影,只暴露
publication_status = Published且visible = true的作品,但返回完整PuzzleWorkProfile,包含 levels / anchor_pack 等详情级字段;统一公开详情主路径通过public_work_detail_entry消费该 view,只保留平台详情页展示摘要。
SpacetimeDB view:puzzle_gallery_card_view
- Rust view:
puzzle_gallery_card_view - 返回类型:
Vec<PuzzleGalleryCardViewRow> - 源码:
server-rs/crates/spacetime-module/src/puzzle.rs - 说明:拼图公开列表 source 投影,只暴露
publication_status = Published且visible = true的公开字段,不携带 levels / anchor_pack 等详情级载荷;统一公开列表主路径通过public_work_gallery_entry消费该 view,/api/runtime/puzzle/gallery保留旧 HTTP shape,并从统一 public cache 映射回PuzzleGalleryResponse。
拼图公开列表 HTTP 窗口缓存
- 接口:
GET /api/runtime/puzzle/gallery - 响应契约:保留
items字段兼容旧前端;当前items只返回前 10 个完整卡片,新增previewRefs返回后 10 个workId/profileId引用,并返回hasMore、nextCursor与totalCount。 - 缓存策略:
api-server在PuzzleGalleryCache中缓存最终PuzzleGalleryResponse的预序列化 data JSON。缓存 miss / 过期时单飞重建,避免并发请求重复排序、映射、DTO 深拷贝和serde_json::Value树构造;开启响应 envelope 时只按请求拼接轻量 meta,缓存短 TTL 刷新recentPlayCount7d,后台 cleanup task 周期清理超过最大空闲窗口的旧响应。OTLP 通过genarrative.puzzle_gallery.cache.*、genarrative.spacetime.read.*、genarrative.http.server.response_bodies.in_flight和genarrative.http.server.request_permits.available区分缓存重建、SpacetimeDB 本地订阅读、响应 body 生命周期和 HTTP 背压状态。 - 详情路径:公开详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理;前端拿到
previewRefs后如果需要展开更多内容,应优先使用后续列表窗口能力或详情 cache,不要把自动详情预取变成新的 procedure 热点。
api-server 长期订阅读模型
spacetime-client 建立每个池连接时会等待下列订阅初始同步:
SELECT * FROM public_work_gallery_entrySELECT * FROM public_work_detail_entrySELECT * FROM bark_battle_gallery_viewSELECT * FROM puzzle_gallery_card_viewSELECT * FROM puzzle_clear_gallery_card_viewSELECT * FROM jump_hop_gallery_card_viewSELECT * FROM wooden_fish_gallery_card_viewSELECT * FROM custom_world_gallery_entrySELECT * FROM match_3_d_gallery_viewSELECT * FROM square_hole_gallery_viewSELECT * FROM visual_novel_gallery_viewSELECT * FROM big_fish_gallery_viewSELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'jump-hop'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'wooden-fish'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'bark-battle'SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle-clear'SELECT * FROM creation_entry_configSELECT * FROM creation_entry_type_config
private asset_object 不进入长期订阅;安全判断通过受限 procedure 在服务端按主键或 (bucket, object_key) 索引读取事务内真相,避免全表复制、订阅失败和增量同步延迟把已登记私有对象误判为 legacy 未登记对象。
跨玩法公开作品列表 / 详情主读模型是 public_work_gallery_entry 与 public_work_detail_entry。拼图、自定义世界等旧玩法公开列表 HTTP 路由保留原响应 shape,由 BFF mapper 从统一 public cache 映射回当前 DTO;旧 *_gallery_card_view / *_gallery_view / custom_world_gallery_entry 继续作为 source view 和兼容缓存。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer;不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。
GET /api/creation-entry/config、入口熔断和公开作品互动熔断优先从订阅 cache 读取创作入口配置;cache 缺失时使用最近一次成功读取的内存快照,再兜底调用 get_creation_entry_config procedure 完成空库种子或旧库兼容。
入口配置快照包含 start card、类型弹窗、公告位兼容字段、入口类型列表和 publicWorkInteractions 作品互动矩阵;入口类型列表新增 category_id、category_label、category_sort_order 后,后台 upsert、shared-contracts、module-runtime 和 spacetime-client binding 必须同步,旧迁移 JSON 通过 migration.rs 默认值兼容。作品互动矩阵是全局公开作品详情能力配置,不属于单个 creation_entry_type_config;后台通过 /admin/api/creation-entry/config/interactions 保存,前端据此隐藏或拦截已接入的点赞 / Remix 入口,api-server 同时对已接入后端动作执行 public_work_interaction_disabled 熔断。
RPG 创作入口的配置 ID 是 rpg,当前 visible=true、open=true;历史 custom-world 路由仍是 RPG 的工程域与运行态源类型。入口熔断把 /api/runtime/custom-world*、/api/story/* 和 /api/runtime/chat/* 统一映射到 rpg,不要新增平行 airp 路由或用 airp 接管当前文字冒险链路。
结构化创作和 RPG 的 LLM JSON 链路默认不启用 Responses web_search;只有在明确需要联网增强时,才通过 GENARRATIVE_RPG_LLM_WEB_SEARCH_ENABLED 或 GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED 显式打开。否则未开通工具的上游会先吐自然语言再返回 ToolNotOpen,这类失败要按上游工具不可用处理,不要误判成模型返回结果解析失败。
统一公开作品 BFF 路由是 GET /api/public-works 与 GET /api/public-works/{publicWorkCode},响应契约由 shared-contracts::public_work 和 packages/shared/src/contracts/publicWork.ts 共同维护。前端首期仍走 BFF HTTP,不直接订阅 SpacetimeDB;后续若允许浏览器直连订阅,也只能订阅 public_work_gallery_entry / public_work_detail_entry 这类稳定公开 read model,不能订阅 puzzle_work_profile、custom_world_profile 等源表后自行拼装列表。设计细节见 docs/technical/【后端架构】统一公开作品ReadModel设计-2026-05-26.md。
- 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
quest_log
- Rust 结构体:
QuestLog - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
quest_record
- Rust 结构体:
QuestRecord - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
refresh_session
- Rust 结构体:
RefreshSession - 源码:
server-rs/crates/spacetime-module/src/auth/tables.rs
runtime_setting
- Rust 结构体:
RuntimeSetting - 源码:
server-rs/crates/spacetime-module/src/runtime/settings.rs
runtime_snapshot
- Rust 结构体:
RuntimeSnapshotRow - 源码:
server-rs/crates/spacetime-module/src/runtime/snapshots.rs
square_hole_agent_message
- Rust 结构体:
SquareHoleAgentMessageRow - 源码:
server-rs/crates/spacetime-module/src/square_hole/tables.rs
square_hole_agent_session
- Rust 结构体:
SquareHoleAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/square_hole/tables.rs
square_hole_runtime_run
- Rust 结构体:
SquareHoleRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/square_hole/tables.rs
square_hole_work_profile
- Rust 结构体:
SquareHoleWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/square_hole/tables.rs
SpacetimeDB view:square_hole_gallery_view
- Rust view:
square_hole_gallery_view - 返回类型:
Vec<SquareHoleGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/square_hole.rs - 说明:方洞挑战公开 source 投影,只暴露
publication_status = published的作品卡片字段;统一公开列表 / 详情主路径通过public_work_gallery_entry/public_work_detail_entry消费该 view 并映射成跨玩法契约。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。
story_event
- Rust 结构体:
StoryEvent - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
story_session
- Rust 结构体:
StorySession - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
tracking_daily_stat
- Rust 结构体:
TrackingDailyStat - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 写入:由单条或批量 tracking procedure 在同一事务中随
tracking_event更新,作为运营查询和个人任务进度的聚合投影。
tracking_event
- Rust 结构体:
TrackingEvent - 源码:
server-rs/crates/spacetime-module/src/runtime/profile.rs - 写入:关键业务埋点同步调用单条 procedure;普通 HTTP route tracking 由
api-server本机 outbox 批量调用record_tracking_events_and_return。outbox 到达批量阈值时先封存 active 文件并切新 active,后台 worker 异步 flush sealed 文件,HTTP 请求线程不等待 SpacetimeDB。FLUSH_INTERVAL_MS只负责兜底封存长时间未满批的 active 文件,MAX_BYTES只做磁盘保护阈值。event_id必须稳定且全局唯一,批量重试时用唯一索引做幂等跳过。 - 外部 API 失败:
event_key = external_api_call_failure使用同一张表落库;它是供应商失败审计事实,不新增 SpacetimeDB 表,查询时按module_key = 'external-api'或scope_kind = module AND scope_id = '<provider>'过滤。
treasure_record
- Rust 结构体:
TreasureRecord - 源码:
server-rs/crates/spacetime-module/src/gameplay.rs
user_account
- Rust 结构体:
UserAccount - 源码:
server-rs/crates/spacetime-module/src/auth/tables.rs - 职责:账号资料真相源,保存
phone_number_e164、display_name、avatar_url、created_at、登录状态、密码 hash、token version 和账号标签。module-auth进程内工作集必须通过 typed projection 与该表同步,不得再经 auth JSON 快照回灌。
user_browse_history
- Rust 结构体:
UserBrowseHistory - 源码:
server-rs/crates/spacetime-module/src/runtime/browse_history.rs
visual_novel_agent_message
- Rust 结构体:
VisualNovelAgentMessageRow - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
visual_novel_agent_session
- Rust 结构体:
VisualNovelAgentSessionRow - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
visual_novel_runtime_event
- Rust 结构体:
VisualNovelRuntimeEvent - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
visual_novel_runtime_history_entry
- Rust 结构体:
VisualNovelRuntimeHistoryEntryRow - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
visual_novel_runtime_run
- Rust 结构体:
VisualNovelRuntimeRunRow - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
visual_novel_work_profile
- Rust 结构体:
VisualNovelWorkProfileRow - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs
SpacetimeDB view:visual_novel_gallery_view
- Rust view:
visual_novel_gallery_view - 返回类型:
Vec<VisualNovelGalleryViewRow> - 源码:
server-rs/crates/spacetime-module/src/visual_novel.rs - 说明:视觉小说公开 source 投影,只暴露
publication_status = published的作品卡片字段,不把完整draft暴露给公开列表订阅;统一公开列表 / 详情主路径通过public_work_gallery_entry/public_work_detail_entry消费该 view 并映射成跨玩法契约。个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。 - 字段变更:
visible控制是否进入公开列表 / 详情,新作品默认false;旧迁移数据由migration.rs按历史公开默认补true。