# 恢复邀请体系并新增兑换卡密系统 ## 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_pack` - `popular_pack` - `premium_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.md` - `docs/protocols/common/user-points-chat-data-protocol.md` - `docs/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.py` - `backend/alembic/versions/*` - Web: - `web/src/components/SettingsPage.tsx` - `web/src/lib/api.ts` - `web/src/lib/api-routes.ts` - `web/src/lib/resources.ts` - `web/src/i18n/utils.ts` - 协议: - `docs/protocols/invite/invite-protocol.md` - `docs/protocols/common/user-points-chat-data-protocol.md` - `docs/protocols/common/http-error-codes.md`