Skip to content

存档图片云端保存:实施与上线 ​

状态:2026-09-28,发布版本 0.0.62.0。用户批准了方案和资源分区预览 A,并授权上线。生产专用 DDL 已安装,真实存储验证通过;按已批准方案从 Oncin 三张已适配卡片试点。应用发布结果以对应 PR 与 Railway 部署状态为准。

已实现 ​

  • 资源 → 存档图片:缩略图网格、存档与使用状态筛选、容量、引用明细、批量彻底删除,以及从指定存档移除。
  • api.media.list/pick/upload/remove 提供统一能力。通用 api.storage 继续保留浏览器本地语义,不扫描任意数据或自动公开私人内容。
  • Oncin 已知三张卡片的 v2 图库适配:先验证存档归属,再迁移本机内嵌图片;保留本机原记录,逐图重试,不复活已删除的条目。元数据独立保存,不进入 AI 变量。
  • 服务端生成私有 WebP 主图与缩略图,同一账户按处理后内容去重。主图最长边 2048,质量 86;不是无损原图备份。
  • 检查点、同账户分支与分享创建时,在同一数据库事务复制引用;恢复检查点也恢复引用。分享媒体复用现有分享权限、内容级别及年龄检查。
  • 资源详情先展示删除影响,删除请求携带引用版本;引用变化会要求刷新。物理删除失败保留占用并自动重试。单纯移除当前引用不释放文件容量。

配额和清理 ​

复用套餐已有账户容量,与创作素材合计,不新增 Mushie 消耗或预设月预算。

  • 输入:静态 JPEG/PNG/WebP,最多 16 MiB、4000 万解码像素;拒绝动画和其他格式。清除 EXIF,保留透明度。
  • 输出:主图最多 2 MiB,缩略图最多 128 KiB;单进程最多同时处理两张。繁忙时明确失败,不跳过校验。
  • 每账户私有上传最多 60 次/小时、输入合计 128 MiB/小时、同时四个待处理上传;元数据历史修改最多 1000 条/小时。创作素材也计入共用上传次数。
  • 上传前在账户锁内预留原始输入和一次最大处理输出;重试才追加输出预留,最多三次处理。临时原件、失败尝试及去重产生的候选文件在清理成功前继续预留。
  • 直传链接有效 10 分钟;额外等待 2 分钟后清理,每分钟最多处理 100 个过期上传。无任何引用的文件保留 7 天再清理;清理失败继续重试。
  • 存档历史、检查点和分享仍是有效引用。彻底删除会让这些引用失去图片;不能通过“移除当前存档”绕过容量。
  • 公共创作素材也以真实对象大小登记、使用同一账户锁核算,采用临时对象到固定对象的条件复制。临时原件与固定对象会短暂同时存在;这部分实际桶占用可能高于界面已用量,按上传限速约束并清理。
  • 记录中只保留文件信息及引用,不保存图片字节。需要观测实际数据库历史增长;首期没有对所有历史记录实现按容量计费或自动裁剪。

隐私边界 ​

私有文件位于 private-session-media/,两个公开 CDN 入口均拒绝此路径。普通媒体接口仅允许存档玩家或图片所有者;世界作者身份不授予权限。读取链接有效 5 分钟,响应不缓存。授权撤销会阻止新链接;此前已发出的链接在剩余有效期内可能可用,已经下载的副本无法撤回。

分享只引用发布时图片,不获得之后新增的私人图片。跨账户续玩不能隐式复制私人媒体;未来若增加复制功能,必须显式授权并计入接收者配额。

上线顺序 ​

  1. 开发或手动安装可从 packages/server 运行 node node_modules/tsx/dist/cli.mjs scripts/install-session-media-schema.ts。发布环境由 scripts/prepare-deployment.mjs 自动执行 prepare-session-media.mjs,使用同一份 scripts/session-media.sql,在事务内幂等安装。
  2. 核实桶拒绝匿名读取私有前缀,CORS 允许实际应用来源的签名 PUT/GET,条件复制和签名 Content-Length 在当前 S3 服务正常。单靠应用 CDN 拦截不能替代桶权限。
  3. 部署本次代码。Railway 发布前检查自动安装幂等表、索引、引用快照和清理触发器;仅 db:push 不能替代它。凭据不写入文档或版本库。生产预安装已完成。
  4. SESSION_MEDIA_UPLOADS_ENABLED 留空,先设置少量 SESSION_MEDIA_PILOT_USERS 或 SESSION_MEDIA_PILOT_WORLDS,以逗号分隔。true 才为所有账户开启新增;显式 false 会覆盖试点名单并暂停新增。已上传图片的读取/删除和已开始上传的确认仍可用。
  5. 经过用户授权的浏览器验收后,验证手机与电脑互相读取、删除弹窗、实际慢网和断网、分享撤销、生产处理时延与图片质量。再按真实存量、读取量、处理资源和桶账单决定扩大范围。

安装 DDL 会同时启用创作素材的预留与条件复制流程,旧页面可能需要刷新后才能上传。回退优先关闭新增开关并保留新版读取、删除和清理;不要删除数据库表、桶对象或回退到只识别本地图库的旧客户端。

已知兼容范围 ​

旧图片只能从原来保存图片的浏览器迁移,服务端无法读取用户另一台设备的 localStorage。当前兼容已核实的 Oncin v2 字段结构,单图库上限 500 条;其他旧卡片需适配统一 SDK。远程 URL、GIF、视频和任意文件不自动抓取迁移。多个设备同时改同一元数据会返回冲突,不静默覆盖;失败的待提交副本在本机尽力保留,但浏览器容量满时不能保证新增恢复副本写入。

验证 ​

发布回归:服务端完整测试 4,152 项通过、14 项跳过、0 失败;前端完整测试 1,660 项通过、0 失败。全工作区构建与类型检查通过。隔离 PostgreSQL 用例覆盖 DDL 幂等、权限、配额并发、CDN 边界、检查点/多代分支/分享快照、恢复、重复确认、失败注入和清理。前端用例覆盖迁移、跨设备元数据冲突、旧页面不误删新条目、不复活删除记录、SDK 图片隔离、上传过期续传、额度失败和旧图库刷新。

真实生产存储探针验证签名上传、字节数、私有读取、匿名拒绝、no-store、错误大小拒绝、条件复制目的对象核验及清理。使用与生产相同的 path-style endpoint;修正桶 CORS,保留原有规则并允许正式域名。所有探针只使用新建的小型测试对象,已清理,没有读取玩家的私人图片或对话。

发布日志位于本地 artifacts/session-media-release-*-tests.log、session-media-release-build.log 和 session-media-release-typecheck.log。按照用户要求没有打开浏览器,因此跨设备的真实界面、弱网操作和视觉验收仍需实际玩家使用反馈;自动化与 HTTP 验证不冒充浏览器验收。