支付与积分
01MVP 的 ZPay 主路径、支付 Provider 扩展和积分系统配置指南
概览

01MVP 内置支付和积分系统。稳定主路径是 ZPay:用于会员购买、数字商品一次性付款、Webhook 履约、会员开通和 credits 发放。Stripe、微信支付、支付宝、PayPal 保留 Provider 代码和接入文档,作为扩展能力处理。
- 已支持会员购买、数字商品一次性付款和 credits 发放
- 已内置 ZPay webhook(支付平台在用户付款成功后主动通知你服务器的方式)处理,自动更新订单状态和权益
- 积分系统独立于支付方式,扩展其他渠道后也可以复用同一套 credits 账本
支付方式状态
| 支付提供商 | 当前状态 | 适用场景 |
|---|---|---|
| ZPay / 易支付 | Stable,默认自动履约路径 | 国内一次性付款、数字商品自动发货、轻量会员售卖 |
| Stripe | Extension,需要补齐 checkout、webhook 和权益同步 | 国际用户、信用卡/借记卡、订阅制产品 |
| 微信支付 | Extension,需要按具体商户和场景接入 | 中国大陆用户 |
| 支付宝 | Extension,需要按具体商户和场景接入 | 中国大陆用户 |
| PayPal | Extension,需要按具体商户和场景接入 | 国际用户、PayPal 余额/银行卡 |
@01mvp/payment 提供统一的 PaymentProvider 接口。Provider 文件存在不等于当前业务已经自动履约;会员和数字商品的默认生产闭环以 ZPay 为准。
配置支付渠道
通过 PAYMENT_ENABLED_CHANNELS 限定开放的支付渠道;不设置时,系统会启用所有密钥已经配置完整的渠道。
# products/01mvp/packages/config/.env.local
PAYMENT_ENABLED_CHANNELS=zpay:alipay,zpay:wxpay当前默认可直接用于会员和数字商品的是 zpay:alipay 和 zpay:wxpay。账单页和数字商品页都会只展示当前环境已配置、已启用、且支持对应业务的支付方式。
数字商品 V1 优先用于项目包、资料包、模板包和兑换码的一次性交付。详情见 数字商品。
积分系统
积分系统独立于支付方式,适用于按次付费的场景(如 AI 生成次数、导出次数等)。
CreditService API
积分服务位于 products/01mvp/packages/credits/,提供以下方法:
| 方法 | 说明 | 返回值 |
|---|---|---|
getBalance(userId) | 查询用户当前积分余额 | number |
addCredits(params) | 增加积分(购买、奖励等) | 交易记录 |
consumeCredits(params) | 消耗积分(使用功能时扣费) | ConsumeCreditsResult |
hasEnoughCredits(userId, amount) | 检查余额是否充足 | boolean |
getStatus(userId) | 获取余额及收支汇总 | { balance, totalPurchased, totalConsumed } |
getTransactions(userId, options) | 查询交易历史记录 | 交易记录数组 |
交易类型
积分交易支持以下类型:purchase(购买)、consumption(消费)、refund(退款)、bonus(赠送)、adjustment(手动调整)。
使用示例
在 API 路由中使用积分:
import { CreditService } from "@01mvp/credits";
import { db } from "@/lib/database";
const creditService = new CreditService(db);
// 检查余额
const hasEnough = await creditService.hasEnoughCredits(userId, 10);
if (!hasEnough) {
return Response.json({ error: "积分不足" }, { status: 402 });
}
// 扣除积分
const result = await creditService.consumeCredits({
userId,
amount: 10,
description: "AI 工具执行",
metadata: { feature: "ai-tool" },
});
if (!result.success) {
return Response.json({ error: result.error }, { status: 402 });
}购买成功后添加积分:
// 在 Webhook 处理中
await creditService.addCredits({
userId,
amount: 100,
type: "purchase",
orderId: "order_xxx",
description: "购买 100 积分套餐",
});所有积分操作都在数据库事务中执行,保证余额计算的原子性和一致性。用户余额存储在 User.creditBalance 字段中。
订阅管理
01MVP 当前会员路径是年费购买和有效期判断。要做 Stripe 自动续费、Customer Portal 或其他自动续费 provider,可以从下面的订阅模型开始接。
订阅生命周期
- 创建订阅 — 用户选择计划,跳转到支付页面完成首次付款
- 生效中(active) — 订阅有效,用户可正常使用付费功能
- 试用期(trialing) — 可选,设置试用天数,试用期内免费
- 续费 — 接入自动续费 provider 后,由对应 webhook 触发
- 到期未续(past_due) — 自动续费失败后进入待处理状态
- 取消 — 用户主动取消或到期不续,状态变为
canceled - 过期(expired) — 当前付费周期结束,功能降级
订阅工具函数
@01mvp/payment 提供了一组数据库无关的工具函数:
| 函数 | 说明 |
|---|---|
isSubscriptionValid(subscription) | 检查订阅是否有效(active 或 trialing 且未过期) |
isSubscriptionExpired(subscription) | 检查订阅是否已过期 |
getSubscriptionDisplayStatus(subscription) | 获取可读的状态文案 |
checkSubscription(subscription) | 综合检查,返回 { hasSubscription, subscription } |
路由保护
在 oRPC procedure 或 server-only module 中使用 createSubscriptionGuard 限制付费用户访问:
import { checkSubscription, createSubscriptionGuard } from "@01mvp/payment";
const subscription = await db.subscription.findFirst({
where: { userId: user.id },
});
const guard = createSubscriptionGuard(subscription, {
redirectUrl: "/pricing",
});
if (guard) {
throw errors.SUBSCRIPTION_REQUIRED({
data: { redirectUrl: guard.redirectUrl },
});
}常见问题
各支付方式接入指南
这篇文档有问题?