版本 4.x 更新记录
提示
- 请查看
package.json文件中的version字段获取版本号- 3.x 的更新记录,请参考 版本 3.x 更新记录
4.0.0
4.0.0 是一次重写级别的升级:支付、积分、团队三个模块被完全重做,定价数据从数据库搬进代码,数据库迁移文件重建基线。从 3.x 升级不是 pnpm install 就能完成的,请先读下面的「破坏性变更」。
破坏性变更(从 3.x 升级必读)
- 定价不再存数据库:删除
pricing_plans、pricing_plan_groups两张表,删除管理后台的定价管理页面(/dashboard/admin/prices全部文件)。定价的唯一事实来源变成config/pricing.ts - 积分表重建:删除
usage、credit_logs,新增credit_balances、organization_credit_balances、credit_transactions - 新增组织相关表:
organization、member、invitation(Better Auth organization 插件)
定价:从数据库迁到代码
- 新增:
config/pricing.ts作为定价唯一事实来源。一个套餐 = 一个对象,里面同时写清楚 provider、provider 侧的价格 ID({ test, live }两套环境)、赠送积分、以及 en/zh/ja 三语文案,不再散落在 i18n 文件里 - 新增:
config/credits.ts存放非付费的积分发放规则,目前是注册赠送积分signupBonusCredits(默认 30,设为 0 即关闭) - 新增:套餐按
provider字段声明由谁收款,三家 provider 各自填对应字段:stripePriceId/creemProductId/paypalPlanId - 新增:
scripts/bootstrap-stripe-prices.ts(pnpm stripe:bootstrap),按配置文件在 Stripe 侧批量创建价格 - 优化:定价组件重写为
PricingSection/PricingCard/CheckoutButton三件套,删除原来的PricingAll/PricingByGroup/PricingByPaymentType/PricingCardDisplay/PricingCTA - 约定:
planId永不复用、售出过的套餐永不删除(历史订单和积分流水靠它反查),下架用active: false
支付履约:统一的 lib/billing
- 重构:新增
lib/billing/,把三家 provider 的 webhook 事件收敛到一套与 provider 无关的核心履约逻辑。原来的lib/payments/、app/api/*/webhook/handlers.ts、app/api/payment/verify-success/*全部删除types.ts:统一的订阅状态CanonicalSubscriptionStatus与各类履约入参,金额一律整数分fulfillment.ts:provider 无关的核心 —— 一次性购买、订阅付费、订阅升级、订阅同步、订阅终止、退款stripe.ts/creem.ts/paypal.ts:每家一个适配器,只负责把 webhook 负载翻译成核心入参,SDK 类型不外泄cancel.ts:cancelProviderSubscription统一取消实现,兼容三家「已取消」的不同报错duplicate.ts:重复订阅结算 —— 取消后开的那笔、退款、Redis 去重后告警;退款失败会抛出让 provider 重试reconcile.ts:定时对账,补救丢失的 webhook(续费重放 + PayPal 挂起捕获的推进)notify.ts:webhook 触发的通知(发放失败告警管理员、续费失败通知用户、欺诈预警),全部 Redis 去重customer.ts:stripeCustomerId的唯一读写口,遇到脏 ID 自愈
- 新增:订阅升级(跨套餐变更)走增量履约,按差额补发积分,并发订阅升级通知
- 新增:PayPal eCheck 等挂起付款先落
status='pending'订单行,由定时任务推进为成功或失败 - 新增:管理后台订单页支持退款操作(
RefundDialog) - 优化:幂等性做成结构性的 ——
orders(provider, provider_order_id)唯一索引 +onConflictDoNothing+ 累计退款额,不再靠防御式判断 - 优化:退款改写原订单行,而不是新增一行
- 优化:webhook 路由保持轻薄 —— 可重试错误返回 5xx,
PermanentFulfillmentError先告警再 ack - 优化:Creem SDK 从 0.4 升级到 1.6,移除
@creem_io/nextjs,lib/creem/client.ts与类型定义大幅精简
积分系统重写
- 重构:新增
lib/credits/,余额只能通过ledger.ts变更,credit_transactions为只追加日志(delta + 快照 + 序号) - 新增:双桶模型 —— 订阅积分(每次发放时重置,订阅结束清零)与购买积分(永不过期),消费优先扣订阅桶
- 新增:年付套餐的月度定投 —— 首月立即发放,剩余 11 次按月滴灌,定时任务与惰性结算共用同一入口,行锁 + 复检保证并发只发一次
- 新增:
app/api/cron/credits定时任务入口(POST+Authorization: Bearer $CRON_SECRET),负责积分定投结算、逾期续费对账、PayPal 挂起捕获对账 - 新增:注册赠送积分,事务内判重,重放无害
- 新增:
app/[locale]/(protected)/dashboard/credit-usage-example/积分消费示例 - 优化:余额永不为负,回收类操作在 0 处截断
团队 / 组织
- 新增:基于 Better Auth organization 插件的团队能力,组织即计费主体,共享一个积分池(
organization_credit_balances) - 新增:
/dashboard/team团队管理页 —— 订阅、共享积分池、成员与席位、积分流水四张卡片;未建团队时走创建/选择引导 - 新增:
components/shared/WorkspaceSwitcher.tsx个人/团队工作区切换 - 新增:邮件邀请加入团队,
emails/organization-invitation.tsx模板 +/accept-invitation/[id]接受页 - 新增:席位上限 = 团队套餐的
seats,无订阅时为 1(仅容纳 owner)。四个 Better Auth 钩子做前置校验,另有咨询锁 + 超额回收兜底并发 - 新增:组织删除守卫 —— 存在有效订阅或任何资金流水时拒绝删除,外键
RESTRICT作为数据库层兜底 - 约定:团队工作区内不售卖积分包;资金相关行在用户删除时
SET NULL,在组织删除时RESTRICT
管理后台
- 新增:优惠券控制台
/dashboard/admin/coupons。Stripe 是唯一存储,本地不建表不迁移 —— 一个优惠券 = Stripe Coupon(折扣、适用范围、计费时长)+ Stripe Promotion Code(对客码、次数上限、有效期、限制条件)。码创建后不可改,所以 UI 只提供启用/停用与「复制一份再改」 - 新增:积分管理页
/dashboard/admin/credits,全局积分流水审计 + 按邮箱批量发放(去重,单次上限 200,未匹配邮箱会回报) - 新增:用户详情页
/dashboard/admin/users/[userId],单用户 360 度视图:资料、积分余额、订阅、累计统计与历史,支持手工调整积分 - 新增:注册邮箱黑名单 —— 管理后台维护前缀/后缀/完整地址三类规则,存 Redis,注册钩子同时比对原始小写形式与归一化形式,防 Gmail 点号与
+后缀绕过。读取失败静默降级为空规则,不阻断正常注册 - 新增:删除用户账号时先清理该用户的 R2 资源(
lib/storage/account-purge.ts),清理失败则中止删除 - 重做:Overview 概览页。单一时间窗(
?range=7d|30d|90d,UTC 自然日)驱动整页,五个区块各自 Suspense 并行流式加载,任一区块失败不拖垮整页- KPI 行:净收入、MRR、新增注册、积分消耗
- 趋势图:单序列柱状图 + 指标切换(切换不重新请求)
- 待处理:逾期订阅、挂起订单、期末取消、未读反馈、失败订单、非本位币订单,每行直达对应管理页
- 分布卡 + 最近 8 笔订单
- 口径:金额为整数分,净收入 = 总额 − 退款,挂起/失败不计收入,本位币取定价配置中第一个启用套餐的币种,注册数排除匿名账号,积分消耗 = 消费 − 消费退回,MRR = active + past_due 按月度费率折算
- 优化:数据表容器与各管理页布局统一,移动端响应式改善
用户端
- 新增:
/dashboard/billing账单页 —— 两个积分桶、当前套餐、购买记录与积分流水(两张表独立分页)。团队工作区下顶部横幅引导去/dashboard/team - 重做:
components/layout/SidebarUserCard.tsx替换原来的SidebarUserNav与CurrentUserBenefitsDisplay,侧边栏直接展示积分余额 - 新增:
--credit主题色(金币金),浅色/深色主题下角色对调
其他
- 新增:
/api/health健康检查端点,并行探测各依赖服务并折叠成单一 HTTP 状态(200 / 503),未配置的依赖记为skipped而非失败。故意公开且故意不返回细节:不需要密钥,也不回传错误信息、版本号或主机名 - 新增:
components/shared/DomTranslationGuard.tsx,防御性处理浏览器整页翻译导致的 React DOM 崩溃 - 优化:字体体系整理,移除
@fontsource/science-gothic,Header、Footer、侧边栏等组件统一字体用法 - 优化:全仓库
CLAUDE.md与代码注释改写为英文
技术栈升级
- Next.js
16.1.1→16.3.3 - React
19.2.3→19.2.8 - creem
0.4.0→1.6.0(移除@creem_io/nextjs) - cloudflare
6.4.0→7.1.0 - Drizzle ORM 0.44(PostgreSQL,
publicschema) - Better Auth 1.4(启用 organization 插件)