积分系统最重要的不是余额字段,而是每一次变化都能解释。Habit 将积分流水作为事实来源,余额和等级是由流水累积得到的业务状态。
完成任务后的数据流
sequenceDiagram participant C as 客户端 participant T as 训练服务 participant P as 积分服务 participant L as 积分流水 participant R as 奖励服务 C->>T: 提交任务完成结果 T->>T: 校验儿童、计划和重复提交 T->>P: 发放积分(业务编号) P->>L: 写入不可重复的积分流水 L-->>P: 返回最新余额与累计积分 P-->>T: 返回积分结果 T-->>C: 展示完成反馈 C->>R: 查询可兑换奖励 R-->>C: 按余额与规则返回列表
流水模型
一条积分流水至少应包含:
- 租户、儿童和账户标识;
- 增减方向与积分数量;
- 变动前余额和变动后余额;
- 来源类型与业务编号;
- 操作者、说明和创建时间。
来源类型 + 业务编号 + 儿童 可以组成幂等约束,防止同一次任务被重复奖励。
余额、累计积分与等级
这三个概念需要分开:
- 余额会在兑换奖励时减少,表示当前可用积分;
- 累计积分通常只随正向行为增长,用于反映长期成长;
- 等级根据累计积分计算,不应因一次兑换而下降。
等级结果由服务端根据规则计算,客户端只负责展示。这样可以避免不同端的规则版本不一致。
奖励处理
奖励可分为兑换、成就与惩罚三类记录:
- 兑换奖励先校验库存、状态、适用人群和余额;
- 在同一事务中扣减积分、写入流水并创建兑换记录;
- 实物奖励进入待履约状态,虚拟奖励可立即发放;
- 取消或失败时通过反向流水退回,不删除原流水;
- 惩罚同样写入独立来源的负向流水,保留原因和操作者。
账务型数据应采用“追加记录”而不是覆盖历史,这样余额异常时可以从流水追溯并重新核对。