# Leaderboard Service 架构设计文档

## 1. 概述

Leaderboard Service（龙虎榜服务）是一个基于 NestJS 框架的微服务，负责管理和展示用户的团队认种排名。服务采用 **领域驱动设计（DDD）** 结合 **六边形架构（Hexagonal Architecture）** 的设计模式。

### 1.1 核心功能

- **日榜/周榜/月榜管理**: 支持多种时间周期的排行榜
- **排名计算**: 基于团队认种数据计算龙虎榜分值
- **虚拟排名**: 支持系统虚拟账户占位显示
- **实时更新**: 定时刷新排名数据
- **缓存优化**: Redis 缓存热点数据

### 1.2 技术栈

| 组件 | 技术 | 版本 |
|------|------|------|
| 框架 | NestJS | 10.x |
| 语言 | TypeScript | 5.x |
| 数据库 | PostgreSQL | 15.x |
| ORM | Prisma | 5.x |
| 缓存 | Redis (ioredis) | 7.x |
| 消息队列 | Kafka (kafkajs) | 2.x |
| 认证 | JWT + Passport | - |
| API 文档 | Swagger | 7.x |

## 2. 架构设计

### 2.1 六边形架构（端口与适配器）

```
                    ┌─────────────────────────────────────────┐
                    │              API Layer                   │
                    │  (Controllers, DTOs, Guards, Swagger)   │
                    └─────────────────┬───────────────────────┘
                                      │
                    ┌─────────────────▼───────────────────────┐
                    │          Application Layer               │
                    │   (Application Services, Schedulers)    │
                    └─────────────────┬───────────────────────┘
                                      │
        ┌─────────────────────────────┼─────────────────────────────┐
        │                             │                             │
        │            ┌────────────────▼────────────────┐            │
        │            │         Domain Layer            │            │
        │            │  (Aggregates, Entities, VOs,    │            │
        │            │   Domain Services, Events)      │            │
        │            └────────────────┬────────────────┘            │
        │                             │                             │
        └─────────────────────────────┼─────────────────────────────┘
                                      │
                    ┌─────────────────▼───────────────────────┐
                    │        Infrastructure Layer              │
                    │  (Repositories, External Services,      │
                    │   Cache, Messaging, Database)           │
                    └─────────────────────────────────────────┘
```

### 2.2 目录结构

```
src/
├── api/                          # API 层（入站适配器）
│   ├── controllers/              # HTTP 控制器
│   │   ├── health.controller.ts
│   │   ├── leaderboard.controller.ts
│   │   ├── leaderboard-config.controller.ts
│   │   └── virtual-account.controller.ts
│   ├── dto/                      # 数据传输对象
│   │   ├── leaderboard.dto.ts
│   │   ├── leaderboard-config.dto.ts
│   │   └── virtual-account.dto.ts
│   ├── guards/                   # 认证守卫
│   │   ├── jwt-auth.guard.ts
│   │   └── admin.guard.ts
│   ├── decorators/               # 自定义装饰器
│   │   ├── public.decorator.ts
│   │   └── current-user.decorator.ts
│   └── strategies/               # Passport 策略
│       └── jwt.strategy.ts
│
├── application/                  # 应用层
│   ├── services/                 # 应用服务
│   │   └── leaderboard-application.service.ts
│   └── schedulers/               # 定时任务
│       └── leaderboard-refresh.scheduler.ts
│
├── domain/                       # 领域层（核心业务逻辑）
│   ├── aggregates/               # 聚合根
│   │   ├── leaderboard-ranking/
│   │   │   └── leaderboard-ranking.aggregate.ts
│   │   └── leaderboard-config/
│   │       └── leaderboard-config.aggregate.ts
│   ├── entities/                 # 实体
│   │   └── virtual-account.entity.ts
│   ├── value-objects/            # 值对象
│   │   ├── leaderboard-type.enum.ts
│   │   ├── leaderboard-period.vo.ts
│   │   ├── ranking-score.vo.ts
│   │   ├── rank-position.vo.ts
│   │   ├── user-snapshot.vo.ts
│   │   └── virtual-account-type.enum.ts
│   ├── events/                   # 领域事件
│   │   ├── domain-event.base.ts
│   │   ├── leaderboard-refreshed.event.ts
│   │   ├── config-updated.event.ts
│   │   └── ranking-changed.event.ts
│   ├── repositories/             # 仓储接口（端口）
│   │   ├── leaderboard-ranking.repository.interface.ts
│   │   ├── leaderboard-config.repository.interface.ts
│   │   └── virtual-account.repository.interface.ts
│   └── services/                 # 领域服务
│       ├── leaderboard-calculation.service.ts
│       ├── virtual-ranking-generator.service.ts
│       └── ranking-merger.service.ts
│
├── infrastructure/               # 基础设施层（出站适配器）
│   ├── database/                 # 数据库
│   │   └── prisma.service.ts
│   ├── repositories/             # 仓储实现
│   │   ├── leaderboard-ranking.repository.impl.ts
│   │   ├── leaderboard-config.repository.impl.ts
│   │   └── virtual-account.repository.impl.ts
│   ├── cache/                    # 缓存服务
│   │   ├── redis.service.ts
│   │   └── leaderboard-cache.service.ts
│   ├── messaging/                # 消息队列
│   │   ├── kafka.service.ts
│   │   ├── event-publisher.service.ts
│   │   └── event-consumer.service.ts
│   └── external/                 # 外部服务客户端
│       ├── referral-service.client.ts
│       └── identity-service.client.ts
│
├── modules/                      # NestJS 模块定义
│   ├── domain.module.ts
│   ├── infrastructure.module.ts
│   ├── application.module.ts
│   └── api.module.ts
│
├── app.module.ts                 # 应用根模块
└── main.ts                       # 应用入口
```

## 3. 领域模型设计

### 3.1 聚合根

#### LeaderboardRanking（排名聚合）

```typescript
class LeaderboardRanking {
  // 标识
  id: bigint;

  // 榜单信息
  leaderboardType: LeaderboardType;  // DAILY | WEEKLY | MONTHLY
  period: LeaderboardPeriod;

  // 用户信息
  userId: bigint;
  isVirtual: boolean;

  // 排名信息
  rankPosition: RankPosition;        // 实际排名
  displayPosition: RankPosition;     // 显示排名
  previousRank: RankPosition | null;

  // 分值信息
  score: RankingScore;

  // 用户快照
  userSnapshot: UserSnapshot;
}
```

#### LeaderboardConfig（配置聚合）

```typescript
class LeaderboardConfig {
  // 标识
  id: bigint;
  configKey: string;

  // 榜单开关
  dailyEnabled: boolean;
  weeklyEnabled: boolean;
  monthlyEnabled: boolean;

  // 虚拟排名设置
  virtualRankingEnabled: boolean;
  virtualAccountCount: number;

  // 显示设置
  displayLimit: number;
  refreshIntervalMinutes: number;
}
```

### 3.2 值对象

#### RankingScore（排名分值）

```typescript
// 龙虎榜分值计算公式：
// effectiveScore = totalTeamPlanting - maxDirectTeamPlanting

class RankingScore {
  totalTeamPlanting: number;      // 团队总认种
  maxDirectTeamPlanting: number;  // 最大单个直推团队认种
  effectiveScore: number;         // 有效分值（龙虎榜分值）

  static calculate(total: number, maxDirect: number): RankingScore {
    const effective = Math.max(0, total - maxDirect);
    return new RankingScore(total, maxDirect, effective);
  }
}
```

#### LeaderboardPeriod（周期）

```typescript
class LeaderboardPeriod {
  key: string;      // 2024-01-15 | 2024-W03 | 2024-01
  startAt: Date;
  endAt: Date;

  static currentDaily(): LeaderboardPeriod;
  static currentWeekly(): LeaderboardPeriod;
  static currentMonthly(): LeaderboardPeriod;
}
```

### 3.3 领域事件

| 事件 | 触发时机 | 数据 |
|------|----------|------|
| LeaderboardRefreshedEvent | 榜单刷新完成 | type, period, rankings |
| ConfigUpdatedEvent | 配置变更 | configKey, changes |
| RankingChangedEvent | 用户排名变化 | userId, oldRank, newRank |

## 4. 数据模型

### 4.1 数据库表设计

```
┌─────────────────────────────────────────────────────────────────┐
│                    leaderboard_rankings                          │
├─────────────────────────────────────────────────────────────────┤
│ ranking_id (PK)         │ 排名ID                                 │
│ leaderboard_type        │ 榜单类型 (DAILY/WEEKLY/MONTHLY)        │
│ period_key              │ 周期标识                               │
│ user_id                 │ 用户ID                                 │
│ is_virtual              │ 是否虚拟账户                           │
│ rank_position           │ 实际排名                               │
│ display_position        │ 显示排名                               │
│ previous_rank           │ 上次排名                               │
│ total_team_planting     │ 团队总认种                             │
│ max_direct_team_planting│ 最大直推团队认种                       │
│ effective_score         │ 有效分值                               │
│ user_snapshot           │ 用户快照 (JSON)                        │
│ period_start_at         │ 周期开始时间                           │
│ period_end_at           │ 周期结束时间                           │
│ calculated_at           │ 计算时间                               │
│ created_at              │ 创建时间                               │
├─────────────────────────────────────────────────────────────────┤
│ UK: (leaderboard_type, period_key, user_id)                     │
│ IDX: (leaderboard_type, period_key, display_position)           │
│ IDX: (leaderboard_type, period_key, effective_score DESC)       │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                    leaderboard_configs                           │
├─────────────────────────────────────────────────────────────────┤
│ config_id (PK)          │ 配置ID                                 │
│ config_key (UK)         │ 配置键 (GLOBAL)                        │
│ daily_enabled           │ 日榜开关                               │
│ weekly_enabled          │ 周榜开关                               │
│ monthly_enabled         │ 月榜开关                               │
│ virtual_ranking_enabled │ 虚拟排名开关                           │
│ virtual_account_count   │ 虚拟账户数量                           │
│ display_limit           │ 显示数量限制                           │
│ refresh_interval_minutes│ 刷新间隔（分钟）                       │
│ created_at              │ 创建时间                               │
│ updated_at              │ 更新时间                               │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                      virtual_accounts                            │
├─────────────────────────────────────────────────────────────────┤
│ virtual_account_id (PK) │ 虚拟账户ID                             │
│ account_type            │ 账户类型                               │
│ display_name            │ 显示名称                               │
│ avatar                  │ 头像URL                                │
│ province_code           │ 省份代码                               │
│ city_code               │ 城市代码                               │
│ min_score               │ 最小分值                               │
│ max_score               │ 最大分值                               │
│ current_score           │ 当前分值                               │
│ usdt_balance            │ USDT余额                               │
│ hashpower_balance       │ 算力余额                               │
│ is_active               │ 是否激活                               │
│ created_at              │ 创建时间                               │
│ updated_at              │ 更新时间                               │
└─────────────────────────────────────────────────────────────────┘
```

### 4.2 缓存设计

```
Redis Key 设计:

leaderboard:{type}:{period}:rankings    # 排名列表 (ZSET)
leaderboard:{type}:{period}:user:{id}   # 用户排名详情 (HASH)
leaderboard:config                       # 全局配置 (HASH)
leaderboard:virtual:accounts            # 虚拟账户列表 (LIST)

TTL:
- 日榜: 10 分钟
- 周榜: 30 分钟
- 月榜: 1 小时
- 配置: 5 分钟
```

## 5. 核心业务流程

### 5.1 排名刷新流程

```
┌─────────────┐     ┌──────────────┐     ┌─────────────────┐
│  Scheduler  │────▶│ Application  │────▶│ ReferralService │
│  (Cron)     │     │   Service    │     │    (External)   │
└─────────────┘     └──────┬───────┘     └────────┬────────┘
                          │                       │
                          │  获取团队数据          │
                          │◀──────────────────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │ LeaderboardCalculation│
              │      Service          │
              │  - 计算有效分值        │
              │  - 排序               │
              │  - 生成排名           │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │ VirtualRanking        │
              │    Generator          │
              │  - 生成虚拟排名        │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │   RankingMerger       │
              │  - 合并真实/虚拟排名   │
              │  - 调整显示位置        │
              └───────────┬───────────┘
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
        ▼                 ▼                 ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│   Database    │ │    Cache      │ │    Kafka      │
│  (Persist)    │ │   (Update)    │ │   (Publish)   │
└───────────────┘ └───────────────┘ └───────────────┘
```

### 5.2 排名查询流程

```
┌─────────┐     ┌────────────┐     ┌─────────┐
│ Client  │────▶│ Controller │────▶│  Cache  │
└─────────┘     └─────┬──────┘     └────┬────┘
                      │                 │
                      │   Cache Hit?    │
                      │◀────────────────┘
                      │
              ┌───────┴───────┐
              │ Yes          No│
              ▼               ▼
        ┌──────────┐   ┌──────────┐
        │  Return  │   │ Database │
        │  Cached  │   │  Query   │
        └──────────┘   └────┬─────┘
                            │
                            ▼
                     ┌──────────┐
                     │  Update  │
                     │  Cache   │
                     └────┬─────┘
                          │
                          ▼
                     ┌──────────┐
                     │  Return  │
                     └──────────┘
```

## 6. 安全设计

### 6.1 认证与授权

| 端点 | 认证要求 | 权限要求 |
|------|----------|----------|
| GET /leaderboard/* | 无 (公开) | - |
| GET /leaderboard/my-rank | JWT | 用户 |
| GET /leaderboard/config | JWT | 管理员 |
| POST /leaderboard/config/* | JWT | 管理员 |
| * /virtual-accounts/* | JWT | 管理员 |

### 6.2 数据安全

- 用户敏感信息脱敏
- BigInt ID 防止遍历
- 输入验证与清洗
- SQL 注入防护 (Prisma)

## 7. 性能优化

### 7.1 缓存策略

- **L1**: 应用内存缓存（热点数据）
- **L2**: Redis 分布式缓存
- **缓存预热**: 服务启动时加载

### 7.2 数据库优化

- 合理索引设计
- 分页查询
- 批量操作
- 读写分离（可选）

### 7.3 异步处理

- 排名计算异步执行
- 事件驱动更新
- 消息队列削峰

## 8. 可观测性

### 8.1 日志

```typescript
// 结构化日志
{
  level: 'info',
  timestamp: '2024-01-15T10:30:00Z',
  service: 'leaderboard-service',
  traceId: 'abc123',
  message: 'Leaderboard refreshed',
  context: {
    type: 'DAILY',
    period: '2024-01-15',
    totalRankings: 100
  }
}
```

### 8.2 健康检查

- `/health` - 服务存活检查
- `/health/ready` - 服务就绪检查（含依赖）

### 8.3 指标 (Metrics)

- 请求延迟
- 缓存命中率
- 排名计算耗时
- 数据库连接池状态

## 9. 扩展性考虑

### 9.1 水平扩展

- 无状态服务设计
- Redis 集群支持
- Kafka 分区消费

### 9.2 垂直扩展

- 异步任务队列
- 数据库分片（未来）
- 冷热数据分离
