# Reward Service 架构概览

## 服务概述

Reward Service 是 RWA Durian Queen 平台的核心收益分配服务，负责处理用户认种榴莲树后的收益计算、分配、领取和结算。

### 技术栈

- **框架**: NestJS 11.x
- **语言**: TypeScript 5.7
- **数据库**: PostgreSQL 15 (通过 Prisma 7.x ORM)
- **缓存**: Redis 7.x
- **消息队列**: Apache Kafka
- **测试**: Jest 30.x + Supertest 7.x
- **API文档**: Swagger/OpenAPI

---

## 领域驱动设计 (DDD) 架构

本服务采用领域驱动设计架构，分为以下四层：

```
┌─────────────────────────────────────────────────────────────┐
│                        API Layer                            │
│  Controllers, DTOs, Guards                                  │
├─────────────────────────────────────────────────────────────┤
│                    Application Layer                        │
│  Application Services, Schedulers, Use Cases                │
├─────────────────────────────────────────────────────────────┤
│                      Domain Layer                           │
│  Aggregates, Value Objects, Domain Events, Domain Services  │
├─────────────────────────────────────────────────────────────┤
│                   Infrastructure Layer                      │
│  Repositories, External Clients, Kafka, Redis               │
└─────────────────────────────────────────────────────────────┘
```

### 目录结构

```
src/
├── api/                          # API层
│   ├── controllers/              # 控制器
│   │   ├── health.controller.ts
│   │   ├── reward.controller.ts
│   │   └── settlement.controller.ts
│   └── dto/                      # 数据传输对象
│       ├── request/
│       └── response/
│
├── application/                  # 应用层
│   ├── services/
│   │   └── reward-application.service.ts
│   └── schedulers/
│       └── reward-expiration.scheduler.ts
│
├── domain/                       # 领域层 (核心)
│   ├── aggregates/              # 聚合根
│   │   ├── reward-ledger-entry/
│   │   └── reward-summary/
│   ├── value-objects/           # 值对象
│   │   ├── money.vo.ts
│   │   ├── hashpower.vo.ts
│   │   ├── reward-source.vo.ts
│   │   ├── reward-status.enum.ts
│   │   └── right-type.enum.ts
│   ├── events/                  # 领域事件
│   │   ├── reward-created.event.ts
│   │   ├── reward-claimed.event.ts
│   │   ├── reward-expired.event.ts
│   │   └── reward-settled.event.ts
│   ├── services/                # 领域服务
│   │   ├── reward-calculation.service.ts
│   │   └── reward-expiration.service.ts
│   └── repositories/            # 仓储接口
│
├── infrastructure/              # 基础设施层
│   ├── persistence/
│   │   ├── prisma/
│   │   ├── repositories/        # 仓储实现
│   │   └── mappers/             # 持久化映射
│   ├── external/                # 外部服务客户端
│   │   ├── referral-service/
│   │   ├── authorization-service/
│   │   └── wallet-service/
│   ├── kafka/                   # Kafka消息
│   └── redis/                   # Redis缓存
│
├── shared/                      # 共享模块
│   ├── guards/
│   └── strategies/
│
└── config/                      # 配置
```

---

## 核心领域模型

### 聚合根

#### 1. RewardLedgerEntry (奖励流水)

奖励流水是核心聚合根，记录每一笔奖励的详细信息和状态变化。

```typescript
class RewardLedgerEntry {
  // 身份
  id: bigint
  userId: bigint
  rewardSource: RewardSource

  // 金额
  usdtAmount: Money
  hashpowerAmount: Hashpower

  // 状态
  rewardStatus: RewardStatus  // PENDING | SETTLEABLE | SETTLED | EXPIRED

  // 时间戳
  createdAt: Date
  expireAt: Date | null       // 待领取奖励24h后过期
  claimedAt: Date | null
  settledAt: Date | null
  expiredAt: Date | null

  // 行为
  claim(): void      // 领取 (PENDING → SETTLEABLE)
  expire(): void     // 过期 (PENDING → EXPIRED)
  settle(): void     // 结算 (SETTLEABLE → SETTLED)
}
```

**状态机**:

```
                ┌──────────┐
                │ PENDING  │
                └────┬─────┘
                     │
        ┌────────────┼────────────┐
        │ 用户认种   │            │ 24h超时
        ▼            │            ▼
  ┌───────────┐      │      ┌─────────┐
  │ SETTLEABLE│      │      │ EXPIRED │
  └─────┬─────┘      │      └─────────┘
        │            │
        │ 用户结算   │
        ▼            │
  ┌──────────┐       │
  │ SETTLED  │       │
  └──────────┘       │
```

#### 2. RewardSummary (奖励汇总)

用户维度的奖励汇总，提供快速查询能力。

```typescript
class RewardSummary {
  userId: bigint

  // 待领取 (24h倒计时)
  pendingUsdt: Money
  pendingHashpower: Hashpower
  pendingExpireAt: Date | null

  // 可结算
  settleableUsdt: Money
  settleableHashpower: Hashpower

  // 累计已结算
  settledTotalUsdt: Money
  settledTotalHashpower: Hashpower

  // 累计已过期
  expiredTotalUsdt: Money
  expiredTotalHashpower: Hashpower
}
```

### 值对象

| 值对象 | 描述 | 不变式 |
|--------|------|--------|
| `Money` | 货币金额 | 金额 >= 0, 货币类型不可变 |
| `Hashpower` | 算力 | 值 >= 0 |
| `RewardSource` | 奖励来源 | 关联订单和用户不可变 |
| `RewardStatus` | 奖励状态 | 枚举值 |
| `RightType` | 权益类型 | 枚举值 |

---

## 收益类型

系统支持6种收益类型，每种有不同的计算规则：

| 权益类型 | USDT金额 | 算力百分比 | 接收方 |
|---------|---------|-----------|--------|
| 分享权益 (SHARE_RIGHT) | 500 U/棵 | 0% | 直接推荐人 |
| 省区域权益 (PROVINCE_AREA_RIGHT) | 15 U/棵 | 1% | 系统省公司 |
| 省团队权益 (PROVINCE_TEAM_RIGHT) | 20 U/棵 | 0% | 授权省公司 |
| 市区域权益 (CITY_AREA_RIGHT) | 35 U/棵 | 2% | 系统市公司 |
| 市团队权益 (CITY_TEAM_RIGHT) | 40 U/棵 | 0% | 授权市公司 |
| 社区权益 (COMMUNITY_RIGHT) | 80 U/棵 | 0% | 所属社区 |

**总计**: 690 USDT + 3% 算力 / 棵

---

## 核心业务流程

### 1. 奖励分配流程

```
订单支付成功事件
       │
       ▼
┌─────────────────┐
│ 计算6种权益奖励  │
│ RewardCalculation│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 保存奖励流水    │
│ RewardLedgerEntry│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 更新用户汇总    │
│ RewardSummary   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 发布领域事件    │
│ Kafka           │
└─────────────────┘
```

### 2. 分享权益24小时机制

```
推荐人已认种？
    │
    ├── 是 → 直接可结算 (SETTLEABLE)
    │
    └── 否 → 待领取 (PENDING, 24h倒计时)
              │
              ├── 24h内认种 → claim() → 可结算
              │
              └── 24h超时 → expire() → 进总部社区
```

### 3. 结算流程

```
用户发起结算请求 (选择BNB/OG/USDT/DST)
            │
            ▼
    ┌───────────────┐
    │ 获取可结算奖励 │
    └───────┬───────┘
            │
            ▼
    ┌───────────────┐
    │ 调用钱包服务   │
    │ 执行SWAP      │
    └───────┬───────┘
            │
            ▼
    ┌───────────────┐
    │ 更新奖励状态   │
    │ SETTLED       │
    └───────┬───────┘
            │
            ▼
    ┌───────────────┐
    │ 发布结算事件   │
    └───────────────┘
```

---

## 外部服务集成

### 防腐层设计

通过接口定义与外部服务解耦：

```typescript
// 推荐关系服务
interface IReferralServiceClient {
  getReferralChain(userId: bigint): Promise<{
    ancestors: Array<{ userId: bigint; hasPlanted: boolean }>;
  }>;
}

// 授权体系服务
interface IAuthorizationServiceClient {
  findNearestAuthorizedProvince(userId: bigint, provinceCode: string): Promise<bigint | null>;
  findNearestAuthorizedCity(userId: bigint, cityCode: string): Promise<bigint | null>;
  findNearestCommunity(userId: bigint): Promise<bigint | null>;
}

// 钱包服务
interface IWalletServiceClient {
  executeSwap(params: {
    userId: bigint;
    usdtAmount: number;
    targetCurrency: string;
  }): Promise<SwapResult>;
}
```

### 服务依赖

```
┌──────────────────┐     ┌───────────────────┐
│ Planting Service │────▶│                   │
│ (认种服务)        │     │                   │
└──────────────────┘     │                   │
                         │  Reward Service   │
┌──────────────────┐     │                   │
│ Referral Service │────▶│                   │
│ (推荐服务)        │     │                   │
└──────────────────┘     │                   │
                         │                   │
┌──────────────────┐     │                   │
│Authorization Svc │────▶│                   │
│ (授权服务)        │     │                   │
└──────────────────┘     └─────────┬─────────┘
                                   │
                                   ▼
                         ┌───────────────────┐
                         │  Wallet Service   │
                         │  (钱包服务)        │
                         └───────────────────┘
```

---

## 消息与事件

### Kafka Topics

| Topic | 描述 | 生产者 | 消费者 |
|-------|------|--------|--------|
| `planting.order.paid` | 认种订单支付成功 | Planting Service | Reward Service |
| `planting.user.planted` | 用户完成认种 | Planting Service | Reward Service |
| `reward.created` | 奖励创建 | Reward Service | - |
| `reward.claimed` | 奖励领取 | Reward Service | - |
| `reward.settled` | 奖励结算 | Reward Service | Wallet Service |
| `reward.expired` | 奖励过期 | Reward Service | - |

### 领域事件

```typescript
// 奖励创建事件
interface RewardCreatedEvent {
  entryId: string;
  userId: string;
  sourceOrderId: string;
  rightType: RightType;
  usdtAmount: number;
  hashpowerAmount: number;
  rewardStatus: RewardStatus;
  expireAt: Date | null;
}

// 奖励领取事件
interface RewardClaimedEvent {
  entryId: string;
  userId: string;
  usdtAmount: number;
  hashpowerAmount: number;
}

// 奖励结算事件
interface RewardSettledEvent {
  entryId: string;
  userId: string;
  usdtAmount: number;
  settleCurrency: string;
  receivedAmount: number;
}

// 奖励过期事件
interface RewardExpiredEvent {
  entryId: string;
  userId: string;
  usdtAmount: number;
  transferredTo: string;  // 'HEADQUARTERS_COMMUNITY'
}
```

---

## 定时任务

### 奖励过期检查

```typescript
@Cron('0 * * * * *')  // 每分钟执行
async handleExpiredRewards() {
  await this.rewardApplicationService.expireOverdueRewards();
}
```

处理逻辑:
1. 查找所有过期的待领取奖励
2. 将奖励状态改为已过期
3. 更新原用户的汇总数据
4. 将金额转入总部社区账户
5. 发布过期事件

---

## 数据库设计

### 核心表结构

```sql
-- 奖励流水表
CREATE TABLE reward_ledger_entries (
  id BIGSERIAL PRIMARY KEY,
  user_id BIGINT NOT NULL,
  source_order_id BIGINT NOT NULL,
  source_user_id BIGINT NOT NULL,
  right_type VARCHAR(50) NOT NULL,
  usdt_amount DECIMAL(18,2) NOT NULL,
  hashpower_amount DECIMAL(18,8) NOT NULL,
  reward_status VARCHAR(20) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  expire_at TIMESTAMP,
  claimed_at TIMESTAMP,
  settled_at TIMESTAMP,
  expired_at TIMESTAMP,
  memo TEXT,

  INDEX idx_user_status (user_id, reward_status),
  INDEX idx_expire_at (expire_at) WHERE reward_status = 'PENDING'
);

-- 用户奖励汇总表
CREATE TABLE reward_summaries (
  user_id BIGINT PRIMARY KEY,
  pending_usdt DECIMAL(18,2) NOT NULL DEFAULT 0,
  pending_hashpower DECIMAL(18,8) NOT NULL DEFAULT 0,
  pending_expire_at TIMESTAMP,
  settleable_usdt DECIMAL(18,2) NOT NULL DEFAULT 0,
  settleable_hashpower DECIMAL(18,8) NOT NULL DEFAULT 0,
  settled_total_usdt DECIMAL(18,2) NOT NULL DEFAULT 0,
  settled_total_hashpower DECIMAL(18,8) NOT NULL DEFAULT 0,
  expired_total_usdt DECIMAL(18,2) NOT NULL DEFAULT 0,
  expired_total_hashpower DECIMAL(18,8) NOT NULL DEFAULT 0,
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

## 安全设计

### 认证与授权

- **JWT认证**: 所有API请求需要携带有效的JWT Token
- **用户隔离**: 用户只能访问自己的奖励数据
- **Passport策略**: 使用`passport-jwt`进行Token验证

```typescript
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get('JWT_SECRET'),
    });
  }
}
```

### 数据完整性

- 使用数据库事务保证数据一致性
- 领域模型不变式检查
- 状态机约束防止非法状态转换

---

## 性能优化

### 缓存策略

- Redis缓存用户奖励汇总
- 热点数据预加载

### 数据库优化

- 复合索引优化查询
- 分页查询避免全表扫描
- 批量写入减少IO

### 消息处理

- Kafka消费者组实现负载均衡
- 幂等性设计防止重复处理
