aslan-server/ROCKET_REQUIREMENT_DOC.md
2025-11-12 14:10:05 +08:00

13 KiB
Raw Blame History

🚀 语聊房火箭系统 - 完整需求文档


📋 文档信息

项目 内容
文档名称 语聊房火箭系统需求文档
版本 v1.0
创建日期 2025-01-15
所属项目 Likei Services
所属模块 rc-service-other
项目路径 D:\workspace\likei-services\rc-service\rc-service-other

1. 业务需求

1.1 功能概述

语聊房火箭是一个房间级互动玩法,用户通过送礼积累火箭能量,达到阈值后自动发射并分发奖励。

1.2 核心规则

能量积累规则

  • 基础规则1金币礼物 = 1火箭能量点
  • 幸运加成幸运礼物额外增加4%能量
  • 实时累积:每次送礼立即增加能量

火箭等级系统

等级 能量阈值 说明
Lv1 150,000 一级火箭
Lv2 500,000 二级火箭
Lv3 1,000,000 三级火箭

发射机制

  • 能量达到阈值自动触发发射
  • 发射后进入"领取中"状态
  • 领取有效期1分钟

奖励领取规则

  • 房间内所有用户可领取
  • 贡献者和普通用户奖励不同(配置待定)
  • 每人限领一次
  • 过期后自动重置

每日重置

  • 每天00:00重置火箭状态
  • 历史记录保存到MongoDB

2. 技术架构

2.1 技术栈

组件 技术
语言 Java 17+
框架 Spring Boot
数据库 MySQL + MongoDB
缓存 Redis
架构模式 DDD + CQRS

2.2 数据库设计

MongoDB 集合

room_rocket_status - 火箭实时状态

{
  "_id": ObjectId,
  "room_id": NumberLong,
  "date": "2025-01-15",
  "level": 1,  // 1/2/3
  "current_energy": NumberLong(85000),
  "max_energy": NumberLong(150000),
  "status": 1,  // 1:CHARGING 2:LAUNCHED 3:CLAIMING
  "contributors": [
    {
      "user_id": NumberLong,
      "user_name": "张三",
      "user_avatar": "https://...",
      "energy": NumberLong(50000),
      "contribution_rate": 58.82,
      "gift_count": 125,
      "first_contribute_time": ISODate,
      "last_contribute_time": ISODate
    }
  ],
  "launch_time": ISODate,
  "claim_expire_time": ISODate,
  "claim_count": 0,
  "created_at": ISODate,
  "updated_at": ISODate
}

// 索引
db.room_rocket_status.createIndex({"room_id": 1, "date": 1}, {unique: true})
db.room_rocket_status.createIndex({"status": 1})

MySQL 表

rocket_config - 火箭配置表

CREATE TABLE `rocket_config` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `level` TINYINT UNSIGNED NOT NULL COMMENT '等级 1/2/3',
  `max_energy` BIGINT UNSIGNED NOT NULL COMMENT '最大能量值',
  `reward_config` JSON DEFAULT NULL COMMENT '奖励配置(预留)',
  `status` TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '状态',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_level` (`level`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `rocket_config` (`level`, `max_energy`) VALUES
(1, 150000),
(2, 500000),
(3, 1000000);

rocket_reward_claim_log - 奖励领取记录表

CREATE TABLE `rocket_reward_claim_log` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `rocket_history_id` VARCHAR(32) NOT NULL COMMENT 'MongoDB _id',
  `room_id` BIGINT UNSIGNED NOT NULL,
  `user_id` BIGINT UNSIGNED NOT NULL,
  `is_contributor` TINYINT UNSIGNED NOT NULL COMMENT '是否贡献者',
  `reward_type` VARCHAR(32) NOT NULL COMMENT 'GOLD/DIAMOND/PROP',
  `reward_amount` BIGINT UNSIGNED NOT NULL,
  `claimed_at` DATETIME NOT NULL,
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_rocket_user` (`rocket_history_id`, `user_id`),
  KEY `idx_room_id` (`room_id`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.3 Redis 缓存设计

Key 类型 TTL 用途
ROCKET:STATUS:{roomId} String(JSON) 24h 状态缓存
ROCKET:LOCK:{roomId} String 5s 分布式锁
ROCKET:CLAIMED:{historyId} Set 2min 已领取用户
ROCKET:CONFIG:{level} String(JSON) 1h 配置缓存

3. 核心流程

3.1 能量积累流程

用户送礼 → GiftSendEvent
    ↓
RocketEnergyAddCmdExe
    ↓
1. 获取分布式锁 (Redis)
2. 查询火箭状态 (MongoDB)
3. 计算能量值 (普通/幸运)
4. 更新能量和贡献者
5. 检查等级提升
6. 保存状态
7. 判断是否达到发射条件
    ├─ 是 → 触发发射
    └─ 否 → 推送能量更新

3.2 火箭发射流程

能量达到阈值
    ↓
RocketLaunchCmdExe
    ↓
1. 获取分布式锁
2. 校验状态和能量
3. 发射火箭 (status → LAUNCHED)
4. 设置领取过期时间 (+1分钟)
5. 进入领取状态 (status → CLAIMING)
6. 保存状态
7. 推送发射动画 (TODO: WebSocket)
8. 保存历史记录 (TODO)

3.3 奖励领取流程

用户点击领取
    ↓
RocketRewardClaimCmdExe
    ↓
1. 获取分布式锁
2. 校验领取资格
    ├─ 状态是否为CLAIMING
    ├─ 是否过期
    └─ 是否重复领取
3. 判断是否贡献者
4. 计算奖励金额 (TODO: 配置)
5. 调用钱包服务发放 (TODO)
6. 记录领取日志 (MySQL)
7. 更新领取人数
8. 返回奖励详情

3.4 每日重置流程

定时任务 00:00
    ↓
RocketDailyResetTask
    ↓
1. 查询所有CHARGING状态火箭
2. 保存历史记录 (TODO)
3. 重置火箭状态
    ├─ level = 1
    ├─ current_energy = 0
    ├─ contributors = []
    └─ date = 今天
4. 清除Redis缓存

4. API 接口设计

4.1 查询火箭状态

接口: GET /api/rocket/status

请求参数:

{
  "roomId": 123456,
  "currentUserId": 789  // 可选
}

响应数据:

{
  "roomId": 123456,
  "date": "2025-01-15",
  "level": 2,
  "levelName": "二级火箭",
  "currentEnergy": 350000,
  "maxEnergy": 500000,
  "energyPercent": 70.00,
  "status": "CHARGING",
  "statusDesc": "充能中",
  "topContributors": [
    {
      "userId": 789,
      "userName": "张三",
      "userAvatar": "https://...",
      "energy": 200000,
      "contributionRate": 57.14,
      "rank": 1,
      "giftCount": 500
    }
  ],
  "totalContributors": 25,
  "claimCount": 0,
  "canClaim": false,
  "hasClaimed": false,
  "myContribution": 200000,
  "myContributionRate": 57.14
}

4.2 领取奖励

接口: POST /api/rocket/claim

请求参数:

{
  "roomId": 123456,
  "userId": 789,
  "rocketHistoryId": "507f1f77bcf86cd799439011"
}

响应数据:

{
  "rewardType": "GOLD",
  "rewardAmount": 1000,
  "isContributor": true,
  "contributionEnergy": 200000,
  "contributionRate": 57.14,
  "message": "恭喜您获得贡献者奖励!"
}

4.3 手动触发发射 (测试用)

接口: POST /api/rocket/manual-launch

请求参数:

roomId=123456

5. 已实现文件清单

5.1 Domain 层

✅ RocketLevel.java - 等级枚举
✅ RocketStatusEnum.java - 状态枚举
✅ RocketContributor.java - 贡献者值对象
✅ RocketStatus.java - 火箭状态领域对象
✅ RocketStatusGateway.java - Gateway接口

5.2 Infrastructure 层

✅ RocketKeys.java - Redis Key枚举
✅ RocketStatusDocument.java - MongoDB文档
✅ RocketStatusRepository.java - MongoDB Repository
✅ RocketStatusGatewayImpl.java - Gateway实现

5.3 Client 层

✅ RocketEnergyAddCmd.java - 能量增加命令
✅ RocketRewardClaimCmd.java - 奖励领取命令
✅ RocketStatusQueryCmd.java - 状态查询命令
✅ RocketStatusCO.java - 状态客户端对象
✅ RocketContributorCO.java - 贡献者客户端对象
✅ RocketRewardCO.java - 奖励客户端对象
✅ RocketService.java - 服务接口

5.4 Application 层

✅ RocketEnergyAddCmdExe.java - 能量增加执行器
✅ RocketLaunchCmdExe.java - 火箭发射执行器
✅ RocketStatusQryExe.java - 状态查询执行器
✅ RocketRewardClaimCmdExe.java - 奖励领取执行器
✅ RocketServiceImpl.java - 服务实现
✅ RocketDailyResetTask.java - 每日重置任务
✅ RocketClaimExpireTask.java - 过期检查任务

5.5 Adapter 层

✅ RocketRestController.java - REST控制器

6. 待实现功能清单

6.1 高优先级 (P0)

1. 礼物事件监听

文件: GiftSendRocketListener.java 位置: other-application/src/.../app/listener/ 功能: 监听送礼事件,自动触发能量增加

@EventListener
public void onGiftSend(GiftSendEvent event) {
    RocketEnergyAddCmd cmd = new RocketEnergyAddCmd();
    cmd.setRoomId(event.getRoomId());
    cmd.setUserId(event.getUserId());
    cmd.setGiftGoldValue(event.getGiftGoldValue());
    cmd.setIsLucky(event.getIsLuckyGift());
    cmd.setBizNo("GIFT_" + event.getGiftOrderId());
    rocketService.addEnergy(cmd);
}

2. MySQL 表创建

执行SQL:

  • rocket_config 配置表
  • rocket_reward_claim_log 领取记录表

3. MongoDB 索引创建

db.room_rocket_status.createIndex(
  {"room_id": 1, "date": 1}, 
  {unique: true, name: "uk_room_date"}
)
db.room_rocket_status.createIndex(
  {"status": 1}, 
  {name: "idx_status"}
)

4. 奖励发放集成

需要: 调用 wallet-inner-api 实现: 在 RocketRewardClaimCmdExe 中补充

// 注入 Feign Client
@Autowired
private WalletGoldClient walletGoldClient;

// 发放奖励
String bizNo = "ROCKET_" + rocketHistoryId + "_" + userId;
WalletReceiptReqDTO req = new WalletReceiptReqDTO();
req.setUserId(userId);
req.setAmount(rewardAmount);
req.setBizType(WalletBizType.ROCKET_REWARD);
req.setBizNo(bizNo);
walletGoldClient.income(req);

5. 领取防重实现

实现: MySQL唯一索引 + Redis检查

// 查询MySQL
boolean hasClaimed = rocketRewardLogGateway.existsByRocketAndUser(
    rocketHistoryId, userId
);
if (hasClaimed) {
    throw new RuntimeException("您已经领取过奖励了");
}

6.2 中优先级 (P1)

6. 历史记录保存

文件: RocketHistoryDocument.java + RocketHistoryRepository.java 功能: 发射后保存完整历史

7. WebSocket 推送

功能:

  • 能量更新推送
  • 发射动画推送
  • 领取通知推送

8. 奖励配置管理

功能: 后台配置各等级奖励规则

9. 排行榜查询

文件: RocketRankingQryExe.java 功能: 查询贡献排行榜

6.3 低优先级 (P2)

10. 管理后台接口

功能:

  • 配置管理
  • 数据统计
  • 手动重置

11. 数据统计报表

功能: 发射次数、领取人数等统计

12. 监控告警

功能: 关键指标监控、异常告警


7. 测试用例

7.1 单元测试

@Test
public void testEnergyAdd_Normal() {
    // 正常送礼增加能量
}

@Test
public void testEnergyAdd_Lucky() {
    // 幸运礼物增加能量
}

@Test
public void testRocketLaunch_AutoTrigger() {
    // 能量满自动发射
}

@Test
public void testRewardClaim_Contributor() {
    // 贡献者领取奖励
}

@Test
public void testRewardClaim_Duplicate() {
    // 重复领取防重
}

7.2 集成测试场景

  1. 完整流程: 送礼 → 发射 → 领取
  2. 并发送礼: 100人同时送礼
  3. 分布式锁: 高并发下的锁测试
  4. 过期重置: 领取过期自动重置

8. 部署说明

8.1 环境要求

  • MongoDB 4.4+
  • MySQL 8.0+
  • Redis 6.0+

8.2 配置示例

# application.yml
spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/likei
  datasource:
    url: jdbc:mysql://localhost:3306/likei
    username: root
    password: password

rocket:
  enabled: true
  lucky-bonus-rate: 0.04
  claim-expire-seconds: 60

8.3 启动顺序

  1. 启动 MongoDB
  2. 启动 MySQL
  3. 启动 Redis
  4. 执行数据库初始化脚本
  5. 启动应用

9. 注意事项

9.1 幂等性

  • 能量增加使用 bizNo 防重
  • 奖励领取使用 MySQL 唯一索引防重

9.2 并发控制

  • 使用 Redis 分布式锁
  • 锁粒度:房间级别

9.3 数据一致性

  • MongoDB 保存实时状态
  • MySQL 保存领取记录
  • 通过业务逻辑保证一致性

9.4 性能优化

  • 热点房间使用 Redis 缓存
  • 批量查询贡献者
  • 异步推送消息

d

10. 联系方式

技术支持: system
文档维护: Leo
最后更新: 2025-01-15


附录:快速上手指南

A. 快速测试流程

  1. 初始化数据库
-- 执行 MySQL 建表语句
-- 插入火箭配置数据
  1. 创建 MongoDB 索引
use likei
db.room_rocket_status.createIndex({"room_id": 1, "date": 1}, {unique: true})
  1. 启动应用
cd other-start
mvn spring-boot:run
  1. 测试接口
# 查询状态
curl "http://localhost:8080/api/rocket/status?roomId=123456"

# 手动发射 (测试用)
curl -X POST "http://localhost:8080/api/rocket/manual-launch?roomId=123456"

# 领取奖励
curl -X POST "http://localhost:8080/api/rocket/claim" \
  -H "Content-Type: application/json" \
  -d '{"roomId":123456,"userId":789,"rocketHistoryId":"xxx"}'

B. 常见问题

Q: 如何手动触发能量增加? A: 调用 RocketService.addEnergy(cmd) 或监听送礼事件

Q: 如何查看当前火箭状态? A: 访问 MongoDB room_rocket_status 集合或调用查询接口

Q: 如何重置火箭? A: 等待每日00:00自动重置或手动调用重置方法


祝开发顺利!🚀