rwadurian/backend/services/leaderboard-service/docs/ARCHITECTURE.md

21 KiB
Raw Blame History

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排名聚合

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配置聚合

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

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

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

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

3.2 值对象

RankingScore排名分值

// 龙虎榜分值计算公式:
// 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周期

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 日志

// 结构化日志
{
  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 垂直扩展

  • 异步任务队列
  • 数据库分片(未来)
  • 冷热数据分离