游戏化服务端实施计划
来源设计文档:docs/GAMIFICATION_DESIGN.md
创建时间:2026-05-11
状态标记:[ ] 未开始,[~] 进行中,[x] 已完成,[!] 阻塞或需产品确认
目标
把第一版游戏化规则落到服务端可裁决、可持久化、可审计的实现中。客户端负责展示和交互,服务端负责挑战组、资源消耗、奖励结算、背包库存、周榜统计和广告恢复幂等。
当前差异
- 当前挑战接口以单题为单位,设计要求一组挑战 5 题。
- 当前每日挑战次数更接近“可挑战次数”,设计要求改为“每日高奖励挑战次数”,次数耗尽后仍可继续学习。
- 当前等级为固定 400 XP 一级,设计要求 50 级分段曲线。
- 当前已有红心、订阅、广告恢复 session、基础 XP、连对 XP 和排行榜底座,但还缺金币、道具、背包、任务、挑战组完成奖励和本周 XP 榜。
- 当前排行榜仍按累计 XP 排名,设计要求按本周 XP 排名,每周一刷新。
执行原则
- 先更新
src/db/schema.ts,再通过 bun run db:generate 生成迁移文件。
- 服务端奖励统一通过一个奖励结算层发放,避免 UI 或单个 route 直接修改资源。
- 所有资源变更必须有幂等边界或流水记录,尤其是广告恢复、购买、挑战完成和排行榜结算。
- 保留现有
/v1/rewards/ad-recovery/session 和 /v1/rewards/ad-recovery/complete 作为广告恢复主入口。
- 调整公开接口后同步更新
docs/api-reference.md。
- 每完成一个阶段至少运行
bun run typecheck、bun run test;涉及 lint 规则时运行 bun run lint。
Phase G0:规则常量与数据模型
| # |
任务 |
状态 |
验收标准 |
| G0-1 |
梳理游戏化规则常量模块 |
[x] |
新增集中规则定义,覆盖红心、挑战组、XP、等级、金币、道具、广告恢复、周榜周期 |
| G0-2 |
新增挑战组数据模型 |
[x] |
支持 challenge session、session answers、组状态、正确数、完成时间、幂等提交 |
| G0-3 |
新增钱包和道具库存模型 |
[x] |
支持金币余额、道具库存、道具获得/消耗流水 |
| G0-4 |
新增奖励流水模型 |
[x] |
记录奖励来源、幂等 key、奖励快照、发放前后状态 |
| G0-5 |
新增每日任务或每日进度模型 |
[x] |
可统计每日首组挑战、每日任务完成、每日高奖励次数 |
| G0-6 |
新增周 XP 统计模型或扩展周榜快照 |
[x] |
可按自然周统计 XP,支持每周一刷新和历史快照 |
| G0-7 |
生成并提交数据库迁移 |
[x] |
db/migrations/ 包含 schema 变更,迁移文件不被 .gitignore 遗漏 |
Phase G1:挑战组与答题结算
| # |
任务 |
状态 |
验收标准 |
| G1-1 |
实现创建挑战组服务 |
[x] |
一次返回 5 题,题目不泄露正确答案,绑定 track/node/chapter |
| G1-2 |
实现挑战组答题提交 |
[x] |
单题提交可幂等记录,重复提交不会重复扣资源或发奖励 |
| G1-3 |
实现挑战组完成结算 |
[x] |
组内 5 题完成后统一计算完成奖励、全对奖励、主题节点进度和每日高奖励状态 |
| G1-4 |
调整红心扣除边界 |
[x] |
答错扣 1 颗;Plus 用户不被红心阻断;新用户前 3 天最低保留 1 颗 |
| G1-5 |
调整每日高奖励挑战次数 |
[x] |
免费用户每日 3 组,Plus 8 组或按产品确认无限;次数为 0 后仍可继续学习但高价值奖励降级 |
| G1-6 |
更新挑战 API DTO |
[x] |
/challenges/next 或新增 session API 能表达组、题、组进度、资源状态 |
| G1-7 |
添加挑战组测试 |
[x] |
覆盖创建、答对、答错、重复提交、完成结算、资源不足和 Plus 分支 |
Phase G2:XP、等级、连续学习和知识卡奖励
| # |
任务 |
状态 |
验收标准 |
| G2-1 |
实现 50 级等级曲线 |
[x] |
Lv.1-50 按设计表计算,xpToNextLevel 准确,超过 50 级有明确封顶或溢出策略 |
| G2-2 |
扩展 XP 奖励来源 |
[x] |
支持普通题 10、困难题 15、看解析 3、完成挑战 20、全对 30、首次知识卡 15、每日任务、主题节点奖励 |
| G2-3 |
修正连对奖励 |
[x] |
3 连对 +5,5 连对 +10,10 连对 +25,并返回客户端可展示奖励 |
| G2-4 |
将连续学习改为按挑战组完成计算 |
[x] |
每天至少完成 1 组挑战才更新 streak,不再依赖当天正确题数阈值 |
| G2-5 |
实现连续学习里程碑奖励 |
[x] |
3/7/14/30/100 天奖励可发放且不可重复领取 |
| G2-6 |
实现每日首次进入送红心 |
[x] |
每日首次 bootstrap 或专用 check-in 最多补 1 颗,不超过上限 |
| G2-7 |
添加 XP/streak 测试 |
[x] |
覆盖等级边界、首次知识卡、完成组奖励、全对奖励、看解析奖励、连续学习保护 |
验证记录(2026-05-13):G2-2 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;bun 当前 shell 不在 PATH,./node_modules/.bin/vitest run 启动阶段被 macOS 拒绝加载未签名的 @rolldown/binding-darwin-x64 原生 binding,需修复本地依赖安装或签名后复跑。
验证记录(2026-05-13):G2-3 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/progress/xp-service.test.ts src/__tests__/services/learning/challenge-service.test.ts 仍在启动阶段被同一个 @rolldown/binding-darwin-x64 原生 binding 签名问题阻塞。
验证记录(2026-05-13):G2-4 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts 仍在启动阶段被同一个 @rolldown/binding-darwin-x64 原生 binding 签名问题阻塞。
验证记录(2026-05-13):G2-5 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts 仍在启动阶段被同一个 @rolldown/binding-darwin-x64 原生 binding 签名问题阻塞。
验证记录(2026-05-13):G2-6 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/learning/progress-summary-service.test.ts 仍在启动阶段被同一个 @rolldown/binding-darwin-x64 原生 binding 签名问题阻塞。
验证记录(2026-05-13):G2-7 已通过 ./node_modules/.bin/tsc --noEmit 和 ./node_modules/.bin/eslint .;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/progress/xp-service.test.ts src/__tests__/services/progress/streak-service.test.ts src/__tests__/services/learning/challenge-service.test.ts src/__tests__/services/learning/progress-summary-service.test.ts 仍在启动阶段被同一个 @rolldown/binding-darwin-x64 原生 binding 签名问题阻塞。
Phase G3:金币、商店和道具
| # |
任务 |
状态 |
验收标准 |
| G3-1 |
实现金币发放服务 |
[x] |
支持每日首组挑战 20、每日任务 30-80、升级 100、主题节点 50、宝箱 20-200 |
| G3-2 |
实现宝箱奖励服务 |
[ ] |
支持基础概率、10 连对概率提升、高奖励次数耗尽后的概率降级 |
| G3-3 |
实现道具库存服务 |
[ ] |
支持连胜护盾、双倍 XP 药水、爱心补给、提示羽毛的获得和消耗 |
| G3-4 |
实现商店商品和购买接口 |
[ ] |
商品价格符合设计:提示羽毛 80、爱心补给 150、双倍 XP 250、连胜护盾 400、装扮 800-3000 |
| G3-5 |
实现道具使用接口 |
[ ] |
爱心补给恢复满心,双倍 XP 药水 15 分钟生效,提示羽毛返回可排除选项,连胜护盾可保护断签 |
| G3-6 |
更新 bootstrap/shop DTO |
[ ] |
客户端能拿到金币、库存、可购买商品、广告商品、订阅权益 |
| G3-7 |
添加金币/商店测试 |
[ ] |
覆盖余额不足、重复购买、使用道具、药水时效、库存扣减和流水记录 |
验证记录(2026-05-13):G3-1 已通过 ./node_modules/.bin/tsc --noEmit、./node_modules/.bin/eslint . 和 git diff --check;定向运行 ./node_modules/.bin/vitest run src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/learning/challenge-service.test.ts 仍在启动阶段被 @rolldown/binding-darwin-x64 原生 binding 未签名问题阻塞。
Phase G4:广告恢复与订阅权益对齐
| # |
任务 |
状态 |
验收标准 |
| G4-1 |
对齐广告恢复奖励到统一奖励服务 |
[ ] |
session complete 后通过统一奖励结算层发放,记录奖励流水 |
| G4-2 |
确认恢复爱心规则 |
[ ] |
免费用户广告恢复直接恢复至 5 颗,每日最多 3 次 |
| G4-3 |
确认恢复高奖励挑战规则 |
[ ] |
每次只恢复 1 组高奖励挑战,每日最多 3 次 |
| G4-4 |
确认连续学习保护规则 |
[ ] |
每 7 天最多广告恢复 1 次,当天补一次保护 |
| G4-5 |
收敛旧恢复接口用途 |
[ ] |
旧的直接恢复接口仅保留内部、测试或明确废弃,并在 API 文档中说明 |
| G4-6 |
明确 Plus 分支 |
[ ] |
Plus 用户无需看广告;同入口返回订阅权益或已订阅原因,不消耗广告次数 |
| G4-7 |
添加广告恢复回归测试 |
[ ] |
覆盖 idempotency、过期、provider token 缺失、每日上限、Plus、重复 complete |
Phase G5:本周排行榜与周期结算
| # |
任务 |
状态 |
验收标准 |
| G5-1 |
改造排行榜数据源为本周 XP |
[ ] |
排行榜不再按累计 XP 排名,展示本周 XP |
| G5-2 |
实现每周一刷新逻辑 |
[ ] |
自然周边界清晰,UTC/本地时区策略写入代码注释和文档 |
| G5-3 |
实现 20-30 人分组 |
[ ] |
每个用户进入稳定榜组,分页和我的排名基于组内排名 |
| G5-4 |
实现前三奖励结算 |
[ ] |
周结算给前 3 名发金币、徽章碎片或头像框奖励,幂等执行 |
| G5-5 |
暴露周榜元信息 |
[ ] |
API 返回 weekStart、weekEnd、nextRefreshAt、groupId、rank、rewardPreview |
| G5-6 |
添加排行榜测试 |
[ ] |
覆盖周 XP 累加、分组、我的排名、周结算、重复结算 |
Phase G6:API 文档、Admin 和运维
| # |
任务 |
状态 |
验收标准 |
| G6-1 |
更新 docs/api-reference.md |
[ ] |
文档只保留最终客户端契约,包含挑战组、奖励、商店、背包、周榜、错误码 |
| G6-2 |
更新 docs/implementation-plan.md |
[ ] |
将本计划作为 Phase 1d 或 Game Economy 阶段索引进去 |
| G6-3 |
增加 Admin 配置或只读查看能力 |
[ ] |
管理端至少能查看用户金币、道具、奖励流水、广告恢复记录 |
| G6-4 |
增加 E2E 或集成测试 |
[ ] |
覆盖游客登录、完成挑战组、广告恢复、购买道具、周榜查询 |
| G6-5 |
增加定时任务入口 |
[ ] |
周榜结算和订阅/资源周期任务有可部署入口,支持手动 dry-run |
| G6-6 |
完成最终验证 |
[ ] |
bun run typecheck、bun run test、bun run lint 通过或记录明确环境阻塞 |
推荐执行顺序
- G0 数据模型与规则常量。
- G1 挑战组会话与完成结算。
- G2 XP、等级、连续学习规则。
- G3 金币、道具、商店。
- G4 广告恢复接入统一奖励服务。
- G5 本周排行榜与周期结算。
- G6 文档、Admin、E2E 和运维入口。
需要产品确认的决策点
- Plus 用户的每日高奖励挑战次数采用 8 组还是无限。
- 等级达到 Lv.50 后是否继续累计 XP,以及
xpToNextLevel 如何展示。
- 宝箱概率和高奖励次数耗尽后的降级比例。
- 排行榜前三奖励的具体数值:金币、徽章碎片、头像框是否第一版都上线。
- 吉祥物装扮、头像框、称号是否第一版需要完整库存模型,还是先作为奖励流水中的展示型权益。
完成定义
- 服务端可以独立裁决所有第一版游戏化资源和奖励。
- 客户端不能通过直接改本地状态绕过红心、挑战次数、金币、道具和广告恢复限制。
- 所有可重复触发的奖励都有幂等保护。
- 所有资源变更可追踪来源和结果。
- API 文档与真实路由、DTO、错误码保持一致。