摘要

一句话总结

t3dotgg/stripe-recommendations 是一个开源的 Stripe 订阅集成指南,通过将 Stripe 视为唯一真实数据源并采用全量覆盖的同步机制,帮助 JS/TS SaaS 应用解决状态不同步与竞态条件问题。

核心要点

  • 反“脑裂”设计:将 Stripe 视为唯一真实数据源(SSOT),不信任 Webhook 传递的局部数据和事件顺序,放弃复杂的增量更新。
  • 全量覆盖同步:提供核心函数 syncStripeDataToKV,直接从 Stripe 拉取特定客户的最新完整订阅数据,并覆盖写入本地 KV 存储(如 Redis/Upstash)。
  • 前置客户绑定:在发起 Checkout 流程前,强制检查并创建 Stripe Customer,将其与本地应用的 userId 绑定,消除匿名结账带来的追踪难题。
  • 双重触发机制:为防止 Webhook 延迟影响用户体验,在用户支付成功重定向至 /success 页面时主动触发同步,同时在后台通过 Webhook 再次触发同步。
  • 极简事件监听:在 Stripe 超过 258 种事件类型中,仅筛选并监听 18 种与订阅状态直接相关的核心事件。
  • 实战避坑配置:建议在 Stripe 设置中开启“限制客户只能有一个订阅”以防止重复结账,并建议禁用退款率较高的 “Cash App Pay” 支付方式。
  • 适用技术栈:专为基于 JavaScript/TypeScript 的 SaaS 应用设计,依赖已验证的用户身份系统和 KV 存储。

风险与不足

(注:以下为指南明确指出的不包含或未解决的范围,需开发者自行处理)

  • 未涵盖测试环境与生产环境的 Stripe 密钥(Secret/Publishable Key)管理。
  • 未解决多环境下的价格 ID(Price ID)管理问题。
  • 不包含向用户前端暴露和展示订阅数据的具体实现代码。
  • 不支持额度或用量追踪(Usage tracking,例如每月 100 次的调用限制)。
  • 未提供免费试用(Free trials)逻辑的管理方案。

功能与定位

这是一个开源的架构指南与代码示例库,旨在为 SaaS 应用提供一种简单、可靠的 Stripe 支付(特别是订阅功能)集成方案。该方案的核心目标是消除 Stripe 与应用本地数据库之间的状态不同步(“脑裂”)问题和竞态条件。

典型使用场景

  • 在基于 JavaScript/TypeScript 的 SaaS 应用中集成 Stripe 订阅支付。
  • 处理 Stripe Checkout 流程与 Webhook 事件。
  • 解决用户支付成功后状态更新延迟或不一致的问题。

核心功能

  • 单一状态同步机制:提供 syncStripeDataToKV 核心函数,直接从 Stripe 拉取特定客户的最新完整订阅数据,并覆盖写入本地 KV 存储(如 Redis),放弃处理复杂的增量更新。
  • 前置客户绑定:在发起 Checkout 流程前,强制检查并创建 Stripe Customer,将其与本地应用的 userId 绑定,避免匿名结账带来的状态追踪难题。
  • 双重触发更新
    • 前端重定向触发:用户支付成功跳转回 /success 页面时,主动触发同步函数,防止 Webhook 延迟导致的用户体验问题。
    • Webhook 触发:监听特定的 Stripe 订阅相关事件(如 checkout.session.completedcustomer.subscription.updated 等),在后台触发相同的同步函数。

特色与差异点

  • 反“脑裂”设计哲学:不信任 Webhook 传递的局部数据和事件顺序。将 Stripe 视为唯一真实数据源(SSOT),每次更新都重新拉取当前状态,大幅降低了状态管理的复杂度。
  • 极简的事件处理:Stripe 拥有超过 258 种事件类型,该方案仅筛选并监听与订阅状态直接相关的 18 种核心事件,忽略其他无关事件。
  • 实战经验总结:包含作者在实际项目(如 T3 Chat)中总结的避坑技巧,例如建议禁用退款率高的 “Cash App Pay”,以及在 Stripe 设置中开启“限制客户只能有一个订阅”以防止重复结账。

使用方式概览

  1. 环境准备:需要 TypeScript、JS 后端、已验证的用户身份系统以及一个 KV 存储(如 Redis/Upstash)。
  2. 结账路由:在用户点击订阅时,后端先查询 KV 存储获取 stripeCustomerId,若无则创建并绑定,随后使用该 ID 创建 Stripe Checkout Session。
  3. 成功回调:在 /success 路由中,获取用户 ID 并调用 syncStripeDataToKV 更新状态,然后重定向用户。
  4. Webhook 处理:配置 /api/stripe 接收 Webhook,验证签名后,提取事件中的 customerId 并调用 syncStripeDataToKV

限制与注意事项

该指南仅专注于核心的订阅状态同步,以下问题不在本方案的解决范围内,仍需开发者自行处理:

  • 测试环境与生产环境的 Stripe 密钥(Secret/Publishable Key)管理。
  • 多环境下的价格 ID(Price ID)管理。
  • 向用户前端暴露和展示订阅数据的具体实现。
  • 额度/用量追踪(Usage tracking,如每月 100 次调用限制)。
  • 免费试用(Free trials)逻辑的管理。

链接

关联主题