Back
NimBuild AI

NimBuild AI

为什么 AI SaaS Demo 在第一笔订单后就崩掉

为什么 AI SaaS Demo 在第一笔订单后就崩掉

AI 产品 Demo 通常运行在最好的条件下:一个已登录的开发者、一个已知提示词、一个额度充足的 API Key,并且没有任何真实支付事件。于是 Demo 看起来很完整,但商业产品需要的每一次状态转换都没有被验证。

难点不是生成结果,而是在登录、结账、订阅续费、积分发放、AI 生成、退款、管理员干预和客服排查之间,保持账户状态一致。

Demo 通过,是因为它跳过了状态转换

典型的“AI SaaS Demo”有一个表单和一个模型响应,可能还有精致的定价页。它缺少的是产品背后的状态机:

  1. 访客变成账户。
  2. 账户变成客户。
  3. 客户获得可消费积分。
  4. 积分在外部工作开始前被扣除。
  5. 提供商成功或失败后被重新对账。
  6. 订阅续费不会重复发放积分。
  7. 客服能看到发生了什么,并安全修复。

每个转换都可能独立失败。如果它们只存在于 UI 状态里,第一笔真实支付就会暴露缺口。

认证是授权边界,不是一个按钮

NimBuild Starter 刻意采用 Firebase Google 登录和 HttpOnly 服务端会话 Cookie。Firebase 验证身份;PostgreSQL 保存角色、套餐、积分和封禁状态等产品字段。受保护路由依赖服务端会话,而不是客户端登录标记。

这个区分很重要,因为“浏览器说自己已登录”并不等于授权。生产应用必须回答:

  • 会话是否有效?
  • 本地用户是否存在?
  • 用户是否被封禁?
  • 路由是否仅管理员可访问?
  • 刚刚修改的角色或访问状态是否需要让旧授权缓存失效?

没有这些问题,一个漂亮的 Google 按钮只是表演。

结账改变的不只是套餐标签

客户完成 Stripe Checkout 后,产品应该创建或更新多条关联记录:支付、订阅、用户套餐、积分和审计历史。如果只更新用户的套餐标签,UI 看起来正确,账务却在漂移。

Webhook 可能迟到、重复送达,或按不同于浏览器跳转的顺序到达。因此商业流程必须在发放任何权益前完成签名验证和幂等处理。

NimBuild 将 Stripe 作为支付提供商,同时保留显式本地账务。完成的 Checkout 会创建支付记录、更新订阅状态、通过积分账本路径发放积分,并发送确认邮件。这些记录必须一起成功,或一起失败。

积分需要审计轨迹

一个单独的 credits 整数很方便,但无法回答真实使用后的问题:

  • 这些积分是购买、发放、调整、退款,还是过期?
  • 哪个订阅周期发放了它们?
  • 余额为什么减少?
  • 提供商故障后,客服应该退多少?

NimBuild 使用三个关联概念:

  • user.credits:快速访问余额
  • credit_balance_bucket:包含来源、数量、优先级和可选过期时间的可消费积分桶
  • credit_ledger:不可变审计记录

每次变更都写入同一个数据库事务,兼顾速度和可解释性。

AI 调用引入第二个一致性问题

很多 AI 工作流必须在调用提供商前先扣积分。如果提供商随后失败,客户等于为无结果付费;如果先退款而提供商后来成功,业务又会损失收入。

实用模式是补偿:

  1. 事务内检查并扣除积分。
  2. 创建补偿对象。
  3. 调用 AI 提供商。
  4. 成功后标记为已结算。
  5. 失败后通过账本退款,并记录原因。

这就是 NimBuild 使用 ai_generationai_generation_refund 作为显式账本原因,而不是悄悄改回数字的原因。

管理后台是运营控制面

一旦客户付费,管理界面就不是装饰,而是团队安全回答“这个账户发生了什么”的途径。

NimBuild 包含用户管理、订阅可见性、积分调整和账本历史。最后那个页面尤其重要:只有能把一次调整和前后事件放在一起审查,这次调整才可信。

更好的验收方式

宣称 AI 产品生产可用之前,请运行这些场景:

  1. 登录和退出后刷新所有页面。
  2. 完成一次测试结账,检查支付、订阅、套餐、积分和账本记录。
  3. 重复发送同一个 webhook 事件。
  4. 在积分扣除后强制 AI 提供商失败。
  5. 让一批促销积分过期。
  6. 修改管理员角色,验证旧授权缓存已失效。
  7. 从管理后台审查每一次变更。

这些场景仍能产生一致记录时,你拥有的才不只是 AI Demo,而是商业 AI SaaS 的起点。