products.ts

产品、套餐、价格展示和购买后授予的访问权限。

config/products.ts 导出一个 Record<string, ProductConfig> 对象。第一层 Key 是产品 ID,每个产品的 plans 再以套餐 ID 为 Key。产品 ID 和套餐 ID 均可自行定义;saavo_starter、license、startup_monthly 等名称只是模板示例。

必须替换 Price ID

默认模板中的六个 priceId 都以 _replace_me 结尾,只是占位值。启用 Checkout 前,必须替换为当前 Stripe 账号中真实存在的 Price ID。界面显示的 salePrice 不参与扣款,实际金额和计费周期以 Stripe Price 为准。

产品 Key

产品 Key 必须是非空字符串,可以按项目需要增删或修改。配置中已有的产品 Key 会组成 ProductId 联合类型;没有产品时可以导出空对象。

产品对象

Prop

Type

plans

plans 保存该产品的套餐,类型为 Record<string, PlanConfig>。套餐 Key 必须是非空字符串,不同产品可以使用不同的 Key。配置中已有的套餐 Key 会组成 PlanIdOf<P> 和 PlanId 联合类型。

套餐对象

Prop

Type

订阅套餐字段

type 为 recurring 时,还必须填写以下字段:

Prop

Type

features

套餐卖点数组,类型为 LocalizedText[]。界面按照数组中的顺序显示;不需要展示套餐卖点时可以省略。

presentation

购买页的显示设置,只影响公开产品页和购买页中的文案,不会改变价格、购买状态或访问权限。

Prop

Type

purchaseFacts 是 LocalizedText[],用于填写购买须知。specifications 是规格数组,每项包含 label: LocalizedText、value: LocalizedText 和可选的 tone: "default" | "positive"。highlights 是亮点卡片数组,每项包含 icon、title 和 description;icon 可以填写 documentation、access、source 或 payment。

填写 presentation 时,purchaseFacts、specifications 和 highlights 都必须填写,数组可以为空。

couponOffers

通过 /offer/:id 链接启用的动态优惠活动数组。填写后至少要有一项。

Prop

Type

features 和 presentation 也可以在优惠活动中覆盖,格式与套餐字段相同。优惠活动不能修改 priceId、计费周期、购买状态或访问权限,也不能嵌套其他优惠活动。

access

购买成功后授予的角色和权益。一次性套餐可以省略;订阅套餐必须填写,并且 roles 和 entitlements 中至少有一个非空数组。

roles

角色数组。数组项可以直接填写角色 Key,也可以填写带授予参数的对象。

Prop

Type

config 可以填写 priority: number、description: string、metadata: Record<string, unknown>,以及 effective.startsAt、effective.endsAt 两个 Unix 毫秒时间戳。

entitlements

权益数组。一次性套餐可以直接填写权益 Key,也可以填写对象;订阅套餐必须使用对象写法。

Prop

Type

权益对象的 config 在订阅套餐中必填。

Prop

Type

kind 为 numeric 时,还可以填写以下字段:

Prop

Type

reset 用于设置额度重置周期。alignment: "calendar" 支持日、周、月、年;alignment: "fixed" 只支持日和周;count 必须是正整数。quotaUsedStrategy 可以填写 clear、drain、keep,也可以使用 { mode: "override", quotaUsed: number } 指定已用额度。

模板默认配置

模板默认配置只包含一个产品。表中的产品 ID 和套餐 ID 都是示例,可以按业务需求替换。改名或清空产品前,必须同步处理页面、购买流程、联盟推广、升级建议等引用,不能只改这一份配置就认为功能仍然完整。

产品 IDname.valuename.key套餐数量
saavo_starterSample SaaS subscriptioncomponents.billing.product.name6

description.value 为 Example monthly and yearly plans to replace with your product terms.,文案 Key 为 components.billing.product.description。

套餐

套餐 ID标题周期salePricepriceId标记
licenseHobby每月$19price_hobby_monthly_replace_medefault: true
hobby_yearlyHobby每年$190price_hobby_yearly_replace_me—
startup_monthlyStartup每月$49price_startup_monthly_replace_merecommended: true
startup_yearlyStartup每年$490price_startup_yearly_replace_merecommended: true
enterprise_monthlyEnterprise每月$149price_enterprise_monthly_replace_me—
enterprise_yearlyEnterprise每年$1,490price_enterprise_yearly_replace_me—

六个套餐的 type 都是 recurring,intervalCount 都是 1,allowRepurchase 都是 false。三个年付套餐还填写了“两个月免费”的 valueHint。

访问权限

套餐角色 Key权益 Key权益类型优先级
license、hobby_yearlypremiumstarter_downloadboolean100
startup_monthly、startup_yearlypremiumstarter_downloadboolean200
enterprise_monthly、enterprise_yearlypremiumstarter_downloadboolean300

premium 和 starter_download 同样只是模板默认配置中的示例 Key,分别来自 roles.ts 和 entitlements.ts。修改这些定义时,需要同步更新本文件中的引用。