feat: integrate Stripe payment with subscription plans
Add Stripe payment integration across the project: - Add @stripe/stripe-js dependency - Configure Stripe environment variables (secret key, publishable key, webhook secret) for dev, local, and production environments - Add Product/Price IDs for monthly, quarterly, and annual subscription tiers - Extend subscription plan data with voiceMinutesPerDay quotas (30/45/60 minutes per tier) - Update .gitignore to exclude implementation_plan.md
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Stripe product / price id 映射
|
||||
*
|
||||
* 为什么不直接存到 `subscription-plans.ts`:
|
||||
* - product/price id 是部署环境配置(不同环境不同 product)
|
||||
* - 套餐本身的 `name` / `price` / `highlight` 是业务常量(不随环境变)
|
||||
* - 分离后,套餐表只包含业务字段,产品 id 走 env —— 避免硬编码 + 生产安全
|
||||
*
|
||||
* env 命名规范:
|
||||
* - STRIPE_PRODUCT_<PLAN_ID_UPPER> → Product ID
|
||||
* - STRIPE_PRICE_<PLAN_ID_UPPER> → Price ID
|
||||
* - 例:STRIPE_PRODUCT_MONTHLY, STRIPE_PRICE_QUARTERLY
|
||||
*/
|
||||
import type { SubscriptionPlanId } from "@/data/constants/subscription-plans";
|
||||
|
||||
/**
|
||||
* 获取 Stripe Product ID(从 env)
|
||||
*
|
||||
* @throws Error 如果 env 未配置(避免 silent failure)
|
||||
*/
|
||||
export function getPlanProductId(planId: SubscriptionPlanId): string {
|
||||
const envKey = `STRIPE_PRODUCT_${planId.toUpperCase()}`;
|
||||
const productId = process.env[envKey];
|
||||
if (!productId || productId.startsWith("prod_replace_")) {
|
||||
throw new Error(
|
||||
`Stripe product id is not configured. Set ${envKey} in .env.local.`,
|
||||
);
|
||||
}
|
||||
return productId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Stripe Price ID(从 env)
|
||||
*
|
||||
* Price ID 是真正用在 `stripe.checkout.sessions.create({ line_items: [{ price: "price_xxx" }] })` 里的
|
||||
*
|
||||
* @throws Error 如果 env 未配置
|
||||
*/
|
||||
export function getPlanPriceId(planId: SubscriptionPlanId): string {
|
||||
const envKey = `STRIPE_PRICE_${planId.toUpperCase()}`;
|
||||
const priceId = process.env[envKey];
|
||||
if (!priceId || priceId.startsWith("price_replace_")) {
|
||||
throw new Error(
|
||||
`Stripe price id is not configured. Set ${envKey} in .env.local.`,
|
||||
);
|
||||
}
|
||||
return priceId;
|
||||
}
|
||||
Reference in New Issue
Block a user