Xiuno BBS 重构记录贴(五)积分系统
贰先生 2小时前

Sample Markdown

This is # 积分系统 Spec

Why

Xiuno BBS 用户表已有 credits/golds/rmbs 三个积数字段,但缺少统一的服务层管理、变更日志、防刷机制和 API 接口。需要一个健壮的积分系统来支持多积分类型的增减操作、审计日志、防刷限制和插件扩展。

What Changes

  • 新建 bbs_credits_log 积分日志表(含 type, change, reason, ip, time)
  • 新建 lib/CreditsService.php 统一积分服务类(add/sub/get/log/checkNegative,行锁+事务,禁止负分)
  • 新建 api/v1/credits.php REST API 路由(GET 查询 / POST 增加扣减),需 Bearer token 鉴权
  • 新增插件钩子:credits_before_change / credits_after_change
  • 新增防刷机制:同一 reason + 用户每日限制次数(可配置)
  • 新建 cron/clean_credits_log.php 日志清理定时任务(保留最近90天)
  • 更新 UpgradeService.php 添加积分系统升级步骤
  • 更新 api/v1/bootstrap.php 注册 credits 路由
  • 更新 conf/conf.default.php 添加积分相关配置项
  • 更新 update.md 记录变更

Impact

  • Affected code: lib/CreditsService.php(新增), api/v1/credits.php(新增), api/v1/bootstrap.php(修改), lib/UpgradeService.php(修改), conf/conf.default.php(修改), cron/clean_credits_log.php(新增)
  • 数据库: 新建 bbs_credits_log 表,用户表已有 credits/golds/rmbs 字段无需修改
  • 兼容性: 不覆盖 Xiuno 原有积分函数,使用新的 CreditsService 类

ADDED Requirements

Requirement: 积分日志表

系统 SHALL 创建 bbs_credits_log 表,包含字段:logid(AI主键), uid, type(积分类型: credits/golds/rmbs), change(变动值,正负), balance(变动后余额), reason(变动原因), ip, create_date。索引:(uid, create_date), (uid, reason, create_date)。

Scenario: 记录积分变动

  • WHEN 用户积分发生变动
  • THEN 系统在 credits_log 表中插入一条记录,包含变动类型、变动值、变动后余额、原因、IP 和时间

Requirement: CreditsService 统一服务类

系统 SHALL 提供 CreditsService 类,包含方法:add($uid, $type, $amount, $reason)sub($uid, $type, $amount, $reason)get($uid, $type)log($uid, $page, $pagesize)checkNegative($uid, $type, $amount)。所有写操作使用行锁(SELECT FOR UPDATE)+ 事务,禁止余额为负。

Scenario: 增加积分

  • WHEN 调用 CreditsService::add() 增加积分
  • THEN 使用行锁读取当前余额,增加指定金额,写入日志,提交事务

Scenario: 扣减积分防止负分

  • WHEN 调用 CreditsService::sub() 扣减积分且余额不足
  • THEN 事务回滚,抛出异常或返回错误,余额不变

Scenario: 并发安全

  • WHEN 同一用户同时发生多笔积分变动
  • THEN 行锁确保串行执行,余额计算正确

Requirement: 积分 API 路由

系统 SHALL 提供 REST API 端点:

  • GET /api/v1/credits — 查询当前用户积分余额(需 Bearer token)
  • GET /api/v1/credits/log — 查询当前用户积分日志(分页)
  • POST /api/v1/credits/add — 增加积分(管理员或指定 reason 允许的操作)
  • POST /api/v1/credits/sub — 扣减积分(管理员或指定 reason 允许的操作)

所有端点需 Bearer token 鉴权,普通用户只能操作自己的积分。

Scenario: 普通用户查询自己的积分

  • WHEN 已登录用户 GET /api/v1/credits
  • THEN 返回该用户所有积分类型的余额

Scenario: 普通用户操作他人积分被拒绝

  • WHEN 普通用户 POST /api/v1/credits/add 指定 uid 不是自己
  • THEN 返回 403 权限不足错误

Scenario: 管理员操作任意用户积分

  • WHEN 管理员 POST /api/v1/credits/add 指定任意 uid
  • THEN 成功增加积分

Requirement: 插件钩子

系统 SHALL 在积分变动前后提供钩子:

  • credits_before_change — 变动前触发,可阻止操作或修改变动值
  • credits_after_change — 变动后触发,用于通知、统计等

Scenario: 钩子阻止积分变动

  • WHEN credits_before_change 钩子返回 false
  • THEN 积分变动被阻止,事务回滚

Scenario: 钩子修改变动值

  • WHEN credits_before_change 钩子修改 amount 值
  • THEN 使用修改后的 amount 执行积分变动

Requirement: 防刷机制

系统 SHALL 对同一 reason + uid 的每日操作次数进行限制,次数阈值通过配置设定(credits_daily_limit)。超出限制时拒绝操作。

Scenario: 防刷限制生效

  • WHEN 同一用户同一天对同一 reason 的操作次数超过配置限制
  • THEN 返回错误,拒绝本次积分变动

Scenario: 防刷限制未超

  • WHEN 同一用户同一天对同一 reason 的操作次数未超过限制
  • THEN 正常执行积分变动

Requirement: 日志清理定时任务

系统 SHALL 提供 cron/clean_credits_log.php 脚本,删除 90 天前的积分日志,保留天数可通过配置调整(credits_log_retention_days)。

Scenario: 清理过期日志

  • WHEN 运行清理脚本
  • THEN 删除 create_date 早于保留天数之前的所有日志记录

Requirement: 升级脚本

系统 SHALL 在 UpgradeService 中添加积分系统升级步骤,创建 credits_log 表并添加积分相关配置项。

Scenario: 从旧版升级

  • WHEN 执行升级流程
  • THEN 自动创建 credits_log 表,添加 credits_daily_limit 和 credits_log_retention_days 配置项

MODIFIED Requirements

Requirement: API 路由注册

修改 api/v1/bootstrap.php,在路由分发中新增 credits 资源的路由指向 credits.php,在端点列表中添加 credits

Requirement: 系统配置

后台设置新增配置项:

  • credits_daily_limit — 每日防刷限制次数(默认 10)
  • credits_log_retention_days — 日志保留天数(默认 90)
  • credits_types — 启用的积分类型列表(默认 ['credits', 'golds', 'rmbs']) 
最新回复 (0)
全部楼主
返回