EasyApp

积分系统

了解如何在EasyApp中集成积分系统

概述

EasyApp积分系统是一个完整的用户积分管理解决方案,提供积分获取、消费、交易记录以及防滥用保护功能。系统支持多种积分来源,包括注册奖励、订阅、内购、推广活动等,并具备完善的反欺诈机制。

核心功能

1. 积分管理

  • FIFO消费机制: 积分按照先进先出的原则消费,确保用户较早获得的积分优先使用
  • 有效期支持: 支持永久积分和临时积分,可设置积分过期时间
  • 多来源追踪: 详细记录积分来源(注册、订阅、购买、推广、退款、管理员发放等)
  • 实时余额查询: 快速获取用户积分余额,包含永久积分、临时积分和即将过期积分

2. 交易系统

  • 完整交易记录: 记录所有积分操作的详细历史,包括获得、消费、过期、退款
  • 余额追踪: 每次交易后记录用户余额变化
  • 批次管理: 支持积分批次操作,便于管理和追踪

3. 功能计费

  • 灵活计费: 为不同功能设置不同的积分消费标准
  • 动态配置: 支持运行时调整功能的积分消费成本
  • 功能开关: 可动态启用或禁用特定功能的计费

4. 反滥用系统

  • 邮箱限制: 限制单个邮箱的注册次数和奖励发放
  • 设备指纹: 监控设备指纹,防止多账户滥用
  • 风险评分: 基于用户行为计算风险分数,自动识别可疑活动
  • 冷却期机制: 设置注册奖励的冷却期,防止频繁创建账户

5. 内购集成

  • RevenueCat集成: 完整支持RevenueCat内购平台
  • 一次性购买: 支持积分包购买,用户可直接购买积分
  • 订阅服务: 支持月度/年度订阅,自动发放订阅积分

数据库配置

积分包配置 (credit_packages)

目前只支持在 sql 中配置积分包,后续会做一套管理系统,支持在管理系统中配置积分包。无需修改 sql 代码,降低使用门槛。

积分包表用于配置可供用户购买的一次性积分包:

CREATE TABLE credit_packages (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,                    -- 积分包名称
  credits INTEGER NOT NULL,              -- 积分数量
  price DECIMAL(10,2) NOT NULL,          -- 价格
  product_id TEXT UNIQUE NOT NULL,       -- RevenueCat产品ID
  is_permanent BOOLEAN DEFAULT true,     -- 是否为永久积分
  is_active BOOLEAN DEFAULT true,        -- 是否启用
  sort_order INTEGER DEFAULT 0           -- 排序顺序
);

RevenueCat内购产品配置示例:

INSERT INTO credit_packages (name, credits, price, product_id) VALUES
  ('入门包', 1000, 9.99, 'easyapp_credits_1000'),
  ('热门包', 5000, 39.99, 'easyapp_credits_5000'),
  ('专业包', 10000, 69.99, 'easyapp_credits_10000'),
  ('超值包', 50000, 299.99, 'easyapp_credits_50000');

配置要点:

  1. product_id 必须与RevenueCat控制台中的产品ID完全一致
  2. 积分包通常设置为永久积分 (is_permanent = true)
  3. 通过 sort_order 控制在应用中的显示顺序
  4. 可通过 is_active 临时禁用某个积分包

订阅产品配置 (subscription_products)

订阅产品表用于配置月度/年度订阅服务:

CREATE TABLE subscription_products (
  id UUID PRIMARY KEY,
  product_id TEXT UNIQUE NOT NULL,       -- RevenueCat订阅产品ID
  product_name TEXT NOT NULL,            -- 产品名称
  subscription_type TEXT NOT NULL,       -- 订阅类型: 'monthly' 或 'yearly'
  credits_per_month INTEGER NOT NULL,    -- 每月发放的积分数
  price DECIMAL(10,2),                   -- 价格
  currency TEXT DEFAULT 'USD',           -- 货币单位
  is_active BOOLEAN DEFAULT true         -- 是否启用
);

RevenueCat订阅产品配置示例:

INSERT INTO subscription_products (
  product_id, product_name, subscription_type, credits_per_month, price
) VALUES
  ('subscription_credit_monthly_basic_1', '高级月费会员', 'monthly', 2000, 9.99),
  ('subscription_credit_yearly_basic_1', '高级年费会员', 'yearly', 2000, 83.99);

配置要点:

  1. product_id 必须与RevenueCat控制台中的订阅产品ID完全一致
  2. 月度和年度订阅通常设置相同的 credits_per_month(年度用户每月获得相同积分)
  3. 年度订阅价格通常比月度价格×12要便宜(如示例中的30%折扣)
  4. 系统会根据订阅类型自动处理积分发放周期

功能计费配置 (feature_credit_costs)

功能计费表定义各项功能的积分消费标准:

INSERT INTO feature_credit_costs (feature_name, credit_cost, description) VALUES
  ('text2image', 100, '文本生成图片'),
  ('image2image', 150, '图片到图片转换'),
  ('receipt_analysis', 50, '收据分析'),
  ('receipt_analysis_pro', 100, '高级收据分析');

RevenueCat集成配置

1. 产品ID映射关系

积分包
  • RevenueCat产品ID → credit_packages.product_id
  • 用于一次性购买积分包
  • 购买成功后立即发放对应积分

接下来,介绍下如何创建一次性积分包产品。

这里您必须有 Apple 开发者账号,并且已经创建了 App,才能创建一次性积分包产品。 如果您忘记了如何创建内购产品,可以回看

1: 首先进入App Store Connect,选择应用内购买。 因为我们创建的是一次性积分包产品,所以要选择应用内购买,不要选择订阅。

creditInAppP

点击+,创建一次性积分包产品。

Type选择Consumable,代表非消耗型商品。(积分属于消耗型商品)

Reference NameProduct ID: Product ID 按照您在credit_packages表中,您定义的product_id字段,一定要一致,因为在购买时,会根据product_id来确定购买的是哪个积分包。 至于Reference Name,您可以跟product_id一致,也可以不一致,这个是您自己定义的。

Product ID 按照您在credit_packages表中,您定义的product_id字段,一定要一致,因为在购买时,会根据product_id来确定购买的是哪个积分包。

设置价格时,也要保持跟credit_packages表中,您定义的price字段,一致。

了解如何集成 RevenueCat 这一章,详细的介绍了如何创建内购产品,包括:国际化、销售范围、以及审核必备的Screenshot。如果您忘记了,可以回看。这里就不再赘述如何创建内购产品了。

RevenueCat

了解如何集成 RevenueCat 服务

EasyApp举例,填写的例子如下:按照credit_packages表,创建了4个积分包 creditIn-AppPruProduct

2: 接下来,需要配置RevenueCat

登录RevenueCat

ReProducts

  • 选择Product catalog

  • 选择Product

  • 选择New Product

  • 点击New Product

ReNewProducts

它会自动拉取刚才您创建的内购产品。选择您期望的积分包。

导入内购产品完成之后,我们需要来配置Offerings,Easyapp 会根据Offerings来拉取积分包。

newOffer

点击New Offering

addnewOffer

  • 填写您的Identifier Display Name Packages。 其中PackagesIdentifier,您可以选择 CustomProduct就选择您刚才导入的内购产品即可。

addnewOfferCustom

EasyApp举例,填写如下:

easyapp_credits

再次强调: Product ID 按照您在credit_packages表中,您定义的product_id字段,一定要一致,因为在购买时,会根据product_id来确定购买的是哪个积分包。

设置价格时,也要保持跟credit_packages表中,您定义的price字段,一致。

3: 来到EasyAppSwiftUI项目中,在Constants/Constants.swift文件中,配置RevenueCatcreditPackagesEntitlementID的值。

   enum RevenueCat {

   	//  ...
   	/// Credit Packages entitlement ID
   	static let creditPackagesEntitlementID = "easyapp_credits"

   	// ...
   }

到这里,积分包配置就完全完成了。

订阅
  • RevenueCat产品ID → subscription_products.product_id
  • 用于月度/年度订阅服务
  • 根据订阅周期自动发放积分

订阅产品的步骤跟积分包的步骤是一样的,只不过是配置的是订阅产品。

creditSub

剩余的步骤就参考下面这篇文章即可

填写订阅产品的价格、id、name、订阅时长。这一块在RevenueCat 订阅产品创建有详细介绍,请查看。

EasyApp举例,我们创建的订阅产品信息如下:

creditSubLizi

1: 在 App Store Connect 中,创建订阅完成之后,回到RevenueCat 中,配置Offerings

2: 在上述创建积分包的步骤中,我们已经详细介绍了如何配置Offerings。这里就不再赘述了。

3: 对于订阅产品,我们除了要创建Offerings,还要创建Entitlements

creditSubEntitlements

  • 填写Identifier
  • 填写Description
  • 关联您在 App Store Connect 中创建的订阅产品

EasyApp举例,创建的Entitlements填写如下:

creditSubEntitlementsLizi

4: 来到EasyAppSwiftUI项目中,在Constants/Constants.swift文件中,配置RevenueCatcreditSubscriptionEntitlementID的值。

   enum RevenueCat {

   	//  ...
   	/// Credit Packages entitlement ID
   	static let creditSubscriptionEntitlementID = "subscription_credit"

   	// ...
   }

创建订阅产品时: Product ID 按照您在subscription_products表中,您定义的product_id字段,一定要一致,因为在购买时,会根据product_id来确定购买的是哪个订阅产品。

设置价格时,也要保持跟subscription_products表中,您定义的price字段,一致。

2. Webhook配置

系统通过RevenueCat Webhook自动处理购买和订阅事件:

支持的事件类型:

  • INITIAL_PURCHASE: 首次购买/订阅
  • RENEWAL: 订阅续费
  • CANCELLATION: 取消订阅
  • EXPIRATION: 订阅过期
  • PRODUCT_CHANGE: 订阅升级/降级
  • BILLING_ISSUE: 支付问题

Webhook URL配置:

https://your-project.supabase.co/functions/v1/subscription-webhook

对于开发环境如何设置Webhook URL配置,我们推荐使用ngrok来设置。

关于ngrok的安装和使用,请参考ngrok

执行命令:

ngrok http 54321

然后配置RevenueCat的Webhook URL为https://your-ngrok-url/functions/v1/subscription-webhook

如下图所示:

RevenueCatWebhook

当我们准备上线时,不要忘记配置生产环境的Webhook URL。 RevenueCat 支持配置多个Webhook URL。您可以新增一个Webhook URL,然后专门配置生产环境的Webhook URL。

续订触发时间:

对于测试环境,沙盒订阅触发的时间,您可以在 App Store Connect 中,配置沙盒订阅触发的时间。也就是说,如果您设置的是 5 分钟间隔,那么 Webhook URL 会每 5 分钟触发一次。

xuding

3. 用户ID映射

我们已经在EasyApp 登录时,已经将RevenueCat的 app_user_id 设置为Supabase用户的UUID,确保系统能够正确识别用户身份。

  // logInRevenueCat
  try await logInRevenueCat(userId: response.user.id.lowercasedString)

系统配置

动态配置系统

系统支持运行时动态调整配置,无需重启服务:

积分系统配置 (system_config.credit_system):

{
  "enabled": true,
  "registration_bonus": 3000,
  "enable_anti_abuse": true,
  "refund_on_failure": true
}

功能开关配置 (system_config.features):

{
  "image_generation": true,
  "receipt_analysis": true
}

反滥用配置 (system_config.anti_abuse):

{
  "max_registrations_per_email": 1,
  "max_bonus_per_email": 3000,
  "max_accounts_per_device": 10,
  "registration_cooldown_days": 30,
  "risk_score_threshold": 70,
  "refund_time_limit_hours": 24
}

安全特性

  1. 行级安全 (RLS): 所有数据表启用RLS,确保用户只能访问自己的数据
  2. 权限控制: Edge Functions使用Service Role进行管理操作
  3. 参数验证: 所有接口进行严格的参数验证
  4. 防重复处理: 通过事件ID确保Webhook事件不被重复处理
  5. 审计日志: 完整记录所有积分操作的审计trail

最佳实践

  1. 定期清理: 建议定期清理过期的积分记录和交易日志
  2. 监控报警: 设置积分异常消费和批量操作的监控报警
  3. 性能优化: 使用预计算视图提高积分余额查询性能
  4. 备份策略: 定期备份积分相关数据,确保数据安全
  5. 测试验证: 在生产环境部署前,务必在沙箱环境充分测试

通过以上配置和集成,你将拥有一个功能完整、安全可靠的积分管理系统,支持多种业务场景和变现模式。

Last updated on