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

623 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🚀 语聊房火箭系统 - 完整需求文档
---
## 📋 文档信息
| 项目 | 内容 |
|-----|------|
| **文档名称** | 语聊房火箭系统需求文档 |
| **版本** | 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** - 火箭实时状态
```javascript
{
"_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** - 火箭配置表
```sql
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** - 奖励领取记录表
```sql
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`
**请求参数**:
```json
{
"roomId": 123456,
"currentUserId": 789 // 可选
}
```
**响应数据**:
```json
{
"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`
**请求参数**:
```json
{
"roomId": 123456,
"userId": 789,
"rocketHistoryId": "507f1f77bcf86cd799439011"
}
```
**响应数据**:
```json
{
"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/`
**功能**: 监听送礼事件,自动触发能量增加
```java
@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 索引创建
```javascript
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` 中补充
```java
// 注入 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检查
```java
// 查询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 单元测试
```java
@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 配置示例
```yaml
# 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. **初始化数据库**
```sql
-- 执行 MySQL 建表语句
-- 插入火箭配置数据
```
2. **创建 MongoDB 索引**
```javascript
use likei
db.room_rocket_status.createIndex({"room_id": 1, "date": 1}, {unique: true})
```
3. **启动应用**
```bash
cd other-start
mvn spring-boot:run
```
4. **测试接口**
```bash
# 查询状态
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自动重置或手动调用重置方法
---
**祝开发顺利!🚀**