9.0 KiB
9.0 KiB
恢复邀请体系并新增兑换卡密系统
1. 目标
在现有积分与支付体系上,恢复“我的邀请”业务闭环,并新增面向运营发放的卡密兑换体系。该任务覆盖协议、后端、web 前端、数据库迁移、运营脚本与审计留痕。
2. 当前现状(已确认)
2.1 邀请体系
- 后端当前只有
GET /api/v1/invite/me,返回{ code, used_count }。 web/当前没有邀请页或卡密兑换入口,但已有SettingsPage、StorePage、api.ts、resources.ts等可复用页面与资源层。- 注册时数据库 trigger
initialize_profile_and_invite_code_on_signup()会:- 为新用户生成自己的邀请码;
- 若
auth.users.raw_user_meta_data.invite_code合法,则给对应invite_codes.used_count + 1; - 将
profiles.referred_by写成邀请人的profiles.id。
- 当前邀请只记录“被使用次数”,不记录逐个受邀人的充值达成状态,也没有邀请奖励发放逻辑。
2.2 积分与支付体系
- 当前积分账本
points_ledger/points_audit_ledger支持register / consume / adjust / purchase / refund。 - 支付套餐当前定义在
backend/src/core/config/static/packages/mapping.yaml:new_user_pack(starter)starter_packpopular_packpremium_pack
- Apple IAP 与 Creem 支付成功后,现有代码会写入积分账本与积分审计账本。
2.3 审计与卡密
- 当前仓库没有通用
audit_logs或同类系统审计表落地实现。 - 当前没有卡密表、卡密生成脚本、卡密兑换接口或兑换 UI。
3. 用户要求(原始需求整理)
3.1 邀请恢复
- 恢复此前“藏起来”的邀请能力。
- 允许用户绑定别人的邀请码。
- 绑定后不可解绑。
- 每个账号只能绑定一次。
- 受邀人绑定邀请码后第一次 Creem 充值成功后:
- 邀请人获得奖励积分;
- 被邀请人获得奖励积分。
- 奖励积分值必须通过环境变量配置,当前目标值为
40。
3.2 我的邀请页展示
- 能看到邀请人数。
- 能看到每个受邀关系对应奖励是否到账。
- 用户给出的目标示例是:页面应区分“已邀请人数”“已达成绑定后充值人数”“未达成绑定后充值人数”,以及奖励到账情况。
3.3 卡密系统
- 覆盖除“新手专享包”以外的三个套餐。
- 按价格从低到高生成卡密数量:
- 最低价套餐:100 张
- 中间套餐:40 张
- 最高价套餐:20 张
- 生成脚本放在
infra/scripts下,由触发脚本执行。 - 生成一份 Excel,包含每个卡密及其对应套餐信息。
- 数据库允许新增表,用于分析卡密、套餐与激活状态。
- 在“我的邀请”页面下新增“兑换卡密”入口,点击弹窗输入卡密。
- 兑换成功后,显示“已激活某某套餐,获得 xx 积分”。
- 积分流水表与系统审计表都要记录卡密兑换链路。
4. 需求拆解
4.1 邀请业务数据补全
现有 profiles.referred_by 只能表示“我被谁邀请”,invite_codes.used_count 只能表示“邀请码被使用几次”,都不足以支撑:
- 单次绑定约束;
- 绑定后 Creem 充值达成判断;
- 奖励幂等发放;
- 页面按受邀人维度展示达成状态。
本任务需要新增显式邀请关系表,至少能表达:
- 邀请人用户 ID;
- 受邀人用户 ID;
- 绑定时使用的邀请码;
- 绑定时间;
- 是否已完成绑定后 Creem 充值;
- 绑定后 Creem 充值对应支付流水 ID;
- 邀请人奖励是否已发放;
- 受邀人奖励是否已发放;
- 对应账本 event_id / 审计事件 ID;
- 幂等字段与唯一约束。
4.2 邀请奖励触发
触发点应绑定在“绑定邀请码后第一次 Creem 充值成功”这个业务事件,而不是注册时:
- Apple IAP 成功入账;
- Creem 支付成功入账;
- 绑定后 Creem 充值成功判定必须以
creem交易表中的成功记录为准。
已确认规则:
- “绑定邀请码后第一次 Creem 充值成功”仅指真实付费购买成功;
- 必须在
creem交易表存在成功记录,才算邀请绑定奖励达成; - 卡密兑换不算作邀请绑定奖励达成;
- 邀请奖励只发一次,且邀请双方各一次。
4.3 邀请绑定入口
当前注册 trigger 支持“注册时带邀请码”,但需求要求恢复“绑定别人的代码”,且绑定后不可解绑、只能绑定一次。因此需要新增应用层接口,而不是只依赖注册 trigger:
- 绑定邀请码接口;
- 查询我的邀请详情接口;
- 接口错误码与前端文案;
- 明确禁止重复绑定、禁止绑定自己的码、禁止绑定不存在或失效的邀请码。
4.4 卡密体系
需要新增面向运营的可追踪卡密:
- 卡密主表;
- 套餐快照字段;
- 激活状态、激活人、激活时间;
- 生成批次;
- 导出字段;
- 幂等兑换保护。
建议卡密兑换本质上走“积分入账 + 审计 + 系统操作日志”一条完整链路,不直接绕过现有积分服务。
5. 协议与实现范围
5.1 协议文档(代码前必须更新)
以下协议需要先更新,再改实现:
docs/protocols/invite/invite-protocol.mddocs/protocols/common/user-points-chat-data-protocol.mddocs/protocols/common/http-error-codes.md- 如新增兑换接口,补充
docs/protocols/points/points-balance-protocol.md或新增兑换协议文档
5.2 后端
- Alembic 迁移:
- 邀请关系表
- 卡密表
- 如采用通用系统审计表,则新增审计表
core.config.settings:- 新增邀请奖励积分环境变量配置
- 邀请服务:
- 绑定邀请码
- 查询我的邀请详情(不仅仅是
used_count) - 绑定后 Creem 充值奖励发放
- 支付服务:
- Creem 绑定后 Creem 充值成功时触发邀请奖励检查
- 卡密服务:
- 兑换接口
- 幂等、校验、入账、审计
- 审计:
- 积分审计账本落地卡密兑换
- 系统审计表落地邀请绑定、邀请奖励发放、卡密生成、卡密兑换
5.3 前端(Web)
- 在现有
web设置体系中新增“我的邀请”入口或子页面:- 绑定邀请码
- 展示我的邀请码
- 展示邀请人数 / 达成绑定后充值人数 / 待达成人数
- 展示逐个受邀人的奖励状态
- 在“我的邀请”下新增“兑换卡密”
- 点击弹窗输入
- 成功后提示并刷新余额 / 邀请数据
- 更新 web 端本地化文案、API 调用与资源失效逻辑
5.4 Infra / 运营
- 新建
infra/scripts下卡密生成脚本 - 支持一键生成三档卡密
- 导出 Excel
- Excel 至少包含:
- 卡密
- 套餐编码
- 套餐名称/档位
- 对应积分
- 生成批次
- 是否已兑换
- 兑换人
- 兑换时间
6. 约束与实现原则
- 不加兜底分支,不用静默降级来掩盖绑定失败、绑定后 Creem 充值奖励失败或卡密兑换失败。
- 绑定邀请码必须是强约束:
- 一人最多绑定一次;
- 绑定后不可解绑;
- 禁止自绑定。
- 邀请奖励与卡密兑换都必须走幂等事件 ID。
- 积分账本与审计账本必须保持一致。
- 若新增系统审计表,不能替代
points_audit_ledger,而应补充业务操作审计。
7. 已确认口径
7.1 邀请页展示口径
用户已确认示例应为:
- 邀请了
3个人; - 奖励到账进度为
80/120; - 表示其中
2个人已完成绑定后 Creem 充值,1个人未完成。
因此页面至少需要稳定表达:
- 已邀请人数;
- 已达成绑定后充值人数;
- 未达成绑定后充值人数;
- 已到账邀请奖励 / 总可达邀请奖励。
按当前确认,若奖励环境变量值为 40,则:
- 已到账邀请奖励 =
已达成绑定后充值人数 * 40 - 总可达邀请奖励 =
已邀请人数 * 40
7.2 绑定后 Creem 充值与卡密口径
- 卡密兑换不算充值成功。
- 邀请绑定奖励达成必须以
creem成功交易记录为准。
8. 实施清单
- 更新邀请 / 积分 / 错误码协议文档
- 设计邀请关系表、卡密表、系统审计表
- 增加邀请奖励积分环境变量配置
- 实现邀请码绑定接口与查询接口
- 在 Creem 成功支付链路接入绑定后 Creem 充值邀请奖励
- 实现卡密生成脚本与 Excel 导出
- 实现卡密兑换接口与账本/审计入库
- 完成 web 邀请页与兑换弹窗改造
- 增加后端 / web 回归测试
9. 建议的相关文件
- 后端:
backend/src/v1/invite/**backend/src/v1/points/**backend/src/v1/payments/**backend/src/core/config/settings.pybackend/alembic/versions/*
- Web:
web/src/components/SettingsPage.tsxweb/src/lib/api.tsweb/src/lib/api-routes.tsweb/src/lib/resources.tsweb/src/i18n/utils.ts
- 协议:
docs/protocols/invite/invite-protocol.mddocs/protocols/common/user-points-chat-data-protocol.mddocs/protocols/common/http-error-codes.md