评估与调整

为什么一个五积分任务能测试整个 SaaS

了解一个简单图像提供器如何证明身份、积分、持久任务、私有存储、运维与恢复之间最困难的连接。

基于 starter 提交 2a1a04a

多数 starter 演示只能证明按钮可以调用 API,却没有证明浏览器重试、进程在两个写入之间退出、提供器已接受但响应超时、对象已保存但数据库失败,或退款暂时无法写入时会发生什么。

Sushi SaaS 用一个刻意简单的图像任务测试这些接缝。图像本身只是本地 SVG;周围的工作流才是产品参考。

一个请求经过什么

它经过同源保护、限流、Better Auth、组织成员、套餐权限、月度上限、共享积分账本、任务状态、持久队列、提供器幂等、私有 S3 存储、签名交付、本地化错误、管理任务恢复、结构化日志和多层测试。

浏览器请求有一个 Idempotency-Key,任务保存请求指纹。任务 UUID 又稳定派生账本交易、Job 去重键、提供器身份、文件记录和对象键。因此重试可以发现并完成已有效果,而不是猜测是否创建新的效果。

  • 任务已插入但未消费:重放写入唯一的确定性消耗;
  • 已消费但未派发:重放找到消耗并只创建一个 Job;
  • 对象已上传但任务未完成:Worker 找到确定性文件并修复任务;
  • 已退款但失败状态未写入:补偿重放找到已有退款并完成状态。

失败需要独立预算

提供器最多尝试五次,Job 最多八次。额外三次不是再次调用提供器,而是在 PostgreSQL 暂时不可用时完成补偿。

最终提供器失败后,任务先进入 refunding。只有确定性账本退款存在后,任务才能变为 failed。重放 refunding 不会再次调用提供器。

为什么使用 mock

商业提供器会让默认测试变慢、收费、依赖凭据且不稳定。本地 adapter 可以强制前 N 次失败,并让每位贡献者用真实 PostgreSQL、Redis 和 Garage 验证完整链路。

E2E 会重复创建同一请求、确认一个任务和精确五积分消费、运行真实 Worker、读取组织任务与签名对象。独立数据库测试强制最终失败并证明重放后只有一次消费和一次退款。

采用者只需替换 src/services/ai/image.ts,保留幂等键、AbortSignal、字节/类型输出与公开错误边界。任务、积分、Worker、私有存储、UI 与运营恢复无需知道模型是谁。

这就是 starter 中“面向生产”的含义:不是宣称 clone 可直接认证,而是让昂贵的失败问题可见、可执行且难以意外绕过。

继续阅读五积分图像生成工作流测试与 CI 契约

为什么一个五积分任务能测试整个 SaaS · Sushi SaaS