Skip to content

存档图片默认云端保存:产品与工程建议 ​

状态:用户已批准云存档方案及资源分区预览 A。发布代码已实现,生产数据库安装和真实存储验证已完成,按试点方案发布。本文保留设计时的调查与建议;实际实现、限制和上线步骤见 实施说明。 用户要求先给方案,不预设预算。下列额度和试点指标均为建议,不是已上线限制或费用承诺。

建议 ​

建设平台统一的、默认私有的存档图片能力。新上传的游戏图片自动进入该能力,跨设备读取、检查点、分支和分享使用同一份受控引用。

复用现有对象存储、直传流程、账户容量和分享权限,补齐会话归属、图片版本、配额预留、私有读取、迁移及清理。 现有通用 api.storage 保留兼容语义,不通过猜测任意字符串内容来自动公开或迁移所有本地数据。 新卡片通过统一 SDK 默认获得云端图片能力;旧卡片逐类适配,不能承诺任意 FileReader/base64/blob 实现零改动兼容。

已查明的基础 ​

代码已有:

  • S3 兼容对象存储;配置注释与默认端点对应 Railway Storage Buckets。
  • 预签名直传与用户素材库;已有账户级配额:Free 100 MiB、Gold 500 MiB、Platinum 2 GiB、Diamond 5 GiB、Ascendant 20 GiB。
  • Sharp 图片处理,但当前处理会在繁忙/错误/部分格式/小图片时跳过,不适合作为新功能的强制安全校验。
  • 会话状态、检查点、分支及不可变分享快照。
  • 工作区内 pickChatImage、patchVariables 包含未提交改动,不能视为线上部署事实。

代码缺口:

  • 当前 /cdn/:assetId 和允许前缀的 /cdn/key/:encodedKey 无需登录;仅增加私有图片接口而保留旁路仍会泄露。
  • 当前配额入口检查已有用量,登记字节数来自客户端;缺少上传预留与最终对象核验。
  • 当前用户素材删除可直接删除 S3 文件,没有存档/分享保留语义。
  • 当前浏览器内写队列不解决不同设备之间的并发写入。
  • 当前图库若放进 AI 可读的普通变量,可能进入每轮提示词。
  • 当前图片读取由应用服务代理返回,缓存未命中的流量会经过应用服务。

实际规模:只读聚合结果 ​

来源:用户提供数据库的 user_assets 和 play_sessions,仅聚合计数与大小,未读取私人对话或玩家图片。

指标查询结果
登记图片20,938 张
有图片的用户4,105 人
登记图片大小16,294,697,140 字节,约 15.18 GiB
近 30 天登记图片11,650 张,约 7.47 GiB
单图中位数约 197 KiB
单图 P95约 3.04 MiB
有图片用户的图片总量 P95约 8.43 MiB
近 30 天有存档更新的用户14,851 人

限制:这些是数据库登记量,不是完整存储桶清单或已核验账单。它们包括现有用户素材,不能直接当成未来游戏图库的使用分布。未包含所有世界素材、孤儿上传、可能保留的对象版本等;客户端上报大小也可能不准确。

成本模型 ​

按 Railway Storage Buckets 官方公开价作条件估算:存储 $0.015/GB-month,桶 API 操作和桶出站免费;Railway 应用服务出站另计 $0.05/GB。实际使用的供应商、计量单位、缓存命中率和账单需在上线前核对。

假设每个使用者平均保留 50 MiB,包含主图和缩略图,保持整月:

使用者数量大约存量纯对象存储月费估算
1,00049 GiB$0.73
10,000488 GiB$7.32
100,0004,883 GiB$73.24

这些不含图像处理、服务流量、边缘鉴权、数据库、备份、监控和内容处置。50 MiB 是累计平均存量假设,不是每月新增量。若不断新增,费用会累积直到用户配额限制增长。

若有约 1,000 个计费 GB 的图片字节经过 Railway 应用服务发出,仅服务出站约 $50。浏览器直传桶、鉴权后短期直读桶,可以避免主要图片字节经过聊天服务;图片校验/转码写回仍有处理和流量成本。

不建议为这一功能先换存储供应商。现有方案的容量单价足够低,优先解决字节传输路径、处理次数、异常上传和数据重复。所有提价/新增套餐空间均留到试点得到实际成本后评估。

第一版产品规则 ​

  1. 登录用户主动选取并保存到游戏的图片默认云存档;不是后台扫描文件,也不自动搬运所有浏览器缓存。
  2. 文件归上传者所有;关联到具体会话。作者不能因为拥有世界而读取玩家私人图片。
  3. 账户现有容量统一计费;同账号同一文件被多个存档、检查点、分享引用只计算一份物理存储。跨账号另行保存必须有各自授权和逻辑配额,不能通过分支无限规避额度。
  4. 普通上传不消耗 AI Mushies。生成图片仍遵循独立生成计费,不与存储混为一谈。
  5. 满额后保留已有图片可读,暂停新增并清晰提示。套餐降级不自动删除,不允许旧账号继续无限增加字节。
  6. 第一版只支持静态 JPEG/PNG/WebP。动画、视频、大文件和云盘同步不纳入首发;已有素材能力保持原状。
  7. 建议初始原始文件上限 16 MiB,并另设解码像素上限;主图最长边目标 2048px,生成一份约 320px 缩略图。目标主图数百 KiB,建议最终单图硬上限 2 MiB;具体压缩质量须通过文字地图、透明图片、肖像和像素图样本验证。
  8. 默认仅保留适合游戏显示的处理后主图及缩略图,不永久保留手机原始大图。试点文案明确这一点;不批量压缩/覆盖历史素材。不能满足质量要求的文件明确失败,不能偷偷返回未校验原图。
  9. 去除定位等附带元数据、保留方向和透明度;真正解码核验格式和尺寸,不能只信扩展名、客户端 MIME 或文件大小。

最小完整架构 ​

复用现有存储组件;新增的是权限、配额和引用关系,不新建第二套素材云盘。

text
玩家选图
  -> 平台确认会话权限、预留容量、签发短期上传权限
  -> 浏览器直传私有临时对象
  -> 服务端核验、有限并发处理、生成不可变主图/缩略图
  -> 事务内登记实际大小、绑定当前会话、释放预留
  -> 返回稳定的媒体 ID,标记已保存

打开存档 / 分享
  -> 校验当前访问者对会话 / 分享的权限
  -> 根据已登记媒体引用换取短期读取地址
  -> 图片字节由对象存储返回,不由聊天服务持续转发

持久保存媒体 ID,不持久保存会过期的读取签名。图片不存进 PostgreSQL 的大段 base64,也不默认进入 AI 提示词。图库标题/人物绑定等属于有大小限制、独立于模型状态的媒体元数据。

最少需要的逻辑记录:媒体所有者和对象版本、实际大小与状态;会话/检查点/分享引用;上传配额预留。优先扩展现有素材记录和引用表,实际表结构在实现前根据现有约束确定。

上传对象不可成为永久可覆盖的正式文件:临时上传授权不能重写已校验内容;完成后使用没有暴露 PUT 权限的正式不可变对象。失败重试使用幂等标识,不能生成重复记录或重复扣配额。

容量必须校验 已用 + 已预留 + 本次上限,并在事务内更新;完成后使用服务端实际字节结算。过期/失败预留要释放。平台还要限制上传频率、待处理任务数和账户新增字节速率,避免反复上传删除绕过存量限制。

私有素材必须同时堵住 legacy CDN 的按 ID 和原始 key 两条旁路;使用隔离前缀或桶及服务端访问检查。不能只把 URL 变长或称为不可猜测。

第一版建议短期签名读取,URL 在有效期内属于持有者可访问的凭据,不可当成完全不可转发的权限体系。撤销分享会阻止新签名,已有签名需在明确的短期窗口内失效(例如不超过 5 分钟)。已下载的图片无法远程收回。如果需要即时撤销,应使用受控的边缘鉴权读取并计入成本,而不能承诺短期签名做不到的保证。

同步、快照和删除 ​

资源管理入口(用户补充要求) ​

  • 在现有「资源」内新增「存档图片」分区,与创作素材分开展示;两者共用账户总容量,不创建第二份额度。
  • 支持按存档、使用状态筛选,按文件大小排序,多选管理;显示实际大小、关联存档、检查点及分享。
  • 删除前查询最新引用及版本。仅移除当前存档关联时,清楚说明仍占用的容量;彻底删除前显示受影响的引用范围。
  • 删除完成且对象清理得到确认后,更新容量。异步清理中显示待释放,不提前声称已经释放。
  • 无引用图片显示回收期限,仍计入已用空间;支持提前彻底删除。已有引用的图片不可误列入「未使用」。
  • 列表分页,缩略图按需签名与加载;不得因打开资源页而读取整个图库或请求所有原图。
  • 「存档图片」默认私有,不继承创作素材的公开分享或复制永久 CDN 链接操作。
  • UI 预览方案 A:资源内双标签 + 图片网格 + 引用详情;方案 B:资源分类与存档侧栏 + 文件列表。两者均预览删除确认及占用变化;视觉批准后再接入实际界面。

生命周期规则 ​

  • 图片新增/移除使用逐项操作、幂等 ID 和服务器版本检查,不采用整库最后写入覆盖。
  • 图片二进制一旦完成不可变;替换图片生成新版本。设备可以缓存文件,但云端决定当前引用关系。
  • 分享冻结当时的引用集合,后续在私人存档新增图片不会自动进入旧分享。
  • 分享只授权这份快照相关图片,不授权整个账户素材库;已有年龄/访问范围限制必须同时作用到媒体读取。
  • 检查点恢复/分支复制引用集合,保持原图版本;图像字节不因每次存档重复复制。历史引用也必须受容量与保留规则约束。
  • 从单个图库移除仅解除该处关联。仍被用户其他存档/检查点/分享引用的图片继续占账户容量。
  • 完全无引用的文件进入延迟回收,例如 7 天可恢复期;临时/未完成上传更短,例如 24 小时。恢复期内物理字节仍有成本,不得在服务端完全忽略。
  • 明确“彻底删除”与普通移除不同:撤销所有受影响引用、停止新授权、执行清理;其他分享显示图片已删除。账户注销及内容下架不得被分享引用无限阻止。
  • 不对跨账号复制做首发全局去重,减少授权、删除、配额与存在性泄漏问题。同账号内容哈希去重足够。

旧卡片和迁移 ​

新卡片的生成指引、SDK 和平台上传控件统一走新机制。旧 api.storage 用途包括缓存与跨会话偏好,首发不能直接改语义。

先适配 Oncin 这一已知图库格式:识别当前会话的图库条目,从原设备读取图片;按稳定项目 ID/内容哈希逐项上传并合并;服务器确认绑定后记录迁移状态。PC/手机分别执行时不能整库覆盖。

需要防范旧存储只有 worldId、缺少账号归属的问题:共享浏览器或切换账号时,不能默认把所有旧数据归给当前账号。只迁移经确认属于当前会话的数据,无法判定时要求用户选择。

迁移失败保留本地原件,重试不重复创建;离线只能显示本地待同步,不能显示云端已保存。关闭页面时可提示未完成,但不能把阻止离开作为唯一可靠性机制。

新机制不承诺支持任意网页自己放在临时内存/Blob URL 的图片,也不自动抓取任意远程图片 URL。后者额外引入服务端请求、版权和访问权限问题,不属于首发。

分阶段实施与放量 ​

阶段 A:上线前基线与基础约束 ​

  • 核对真实供应商、桶容量/孤儿对象、实际账单、图片请求数、源站服务流量、缓存命中率。
  • 实现私有访问和 CDN 旁路拦截、配额预留/完成核验、图片限额与不可变版本。
  • 复用现有上传流程与存储 SDK;不改套餐,不购买/迁移供应商。

阶段 B:完整链路的受控试点 ​

  • Oncin 加少量不同图库实现的创作者;平台能力先按账号/世界开关开放。
  • 同时完成跨设备、只读分享、删除、迁移、满额及失败重试,不以“只上传成功”视为试点完成。
  • 建议观察至少 7 天并覆盖足够成功与失败样本;不是仅凭时间到就自动放量。

阶段 C:默认推广 ​

  • 新建卡片和已适配卡片从 10% 放量到全部;未知旧格式继续保留原行为,并提供适配路径。
  • 功能开关可暂停新上传和新迁移,已保存图片仍可读取。不能回滚成只读本地导致云端数据消失。
  • UI/提示文案变化依用户规则先做具体预览;当前建议本身不代表视觉批准。

放量前必须验证 ​

场景验收要求
PC 新增,手机重开读取同一媒体与元数据
PC/手机同时新增、删除、改标题无静默覆盖,冲突可识别
上传完成但确认请求丢失重试同一记录,不重复扣费
断网/满额/转码失败保留原件,明确未保存
两个并发上传抢最后容量配额不能被并发突破
更换账号或猜测媒体 ID/key无权访问;CDN 旧路由不可旁路
作者访问玩家存档媒体不因世界所有权而获得权限
分享后私人会话新增/替换图片原分享内容不变
撤销分享/彻底删除无新授权,已签 URL 在约定窗口失效
检查点、分支、恢复引用版本正确,无复制倍增
清理临时对象与无引用文件不删除活跃会话或有效分享的图片
PC/手机分批迁移无丢图/重复,旧账号数据不串入
恶意大尺寸/伪造 MIME/动画有界资源使用,拒绝不支持内容

必须补自动化并发、权限、快照与故障注入测试;UI 操作与低网速/跨设备验收在用户授权浏览器验证后执行。

观测:成功率、确认延迟、转码失败、配额预留泄漏、每用户实际字节、每图处理成本、临时对象积压、桶与服务的流量、分享读取量、被拒绝请求。日志只存标识/大小/错误码,不存图片字节、签名 URL 或私人标题。

成本保护以分层限速、处理队列和暂停新增为主;不能因为预算预警删除玩家已有数据。按照实际单用户存量和读取分布再制定费用目标,当前不预设月预算。

首发不做 ​

  • 全站历史 localStorage 自动同步:无法可靠确定内容类型、归属与分享范围。
  • 任意文件、视频、动画及无限原图备份:成本/处理边界不同,另行评估。
  • 跨账号全局文件去重:首发收益不足以抵消权限和删除复杂度。
  • 本地离线优先的通用数据库同步:超出当前缺图问题。
  • 自动让模型分析所有上传图片:不是保存所需步骤,增加成本和隐私传播。
  • 先更换供应商或提高付费套餐额度:先测量现有路径,不用迁移掩盖设计问题。

仍待核实的事实 ​

真实对象清单和账单、生产桶配置、媒体转码质量/速度、CDN 命中率、所有旧卡片格式分布、用户对原图保真的需求。所提数值是可测试的初始建议,不能冒充已有测量结论。

来源 ​

  • Railway Storage Buckets Billing:容量、桶请求/流量与服务出站的区别。
  • Railway Pricing Plans:应用服务出站、CPU 和 RAM 计价。
  • Railway CLI bucket:官方示例默认端点与项目配置对应。
  • 仓库:packages/server/src/routes/user-assets.ts、routes/cdn.ts、routes/shared-playthroughs.ts、lib/image-resize.ts、lib/plan-config.ts、lib/account-deletion.ts、packages/app/src/lib/asset-upload.ts。
  • 前序调查:docs/oncin-gallery-storage-investigation-2026-09-28.md。