rwadurian/backend/services/mining-admin-service/DEVELOPMENT_GUIDE.md

27 KiB
Raw Permalink Blame History

Mining Admin Service (挖矿管理服务) 开发指导

1. 服务概述

1.1 核心职责

Mining Admin Service 是挖矿系统的管理中枢,负责配置管理、系统监控、数据报表等后台管理功能。

主要功能:

  • 系统参数配置(贡献值递增比例、分配比例等)
  • 系统开关控制(转账开关等)
  • 系统账户管理(运营/省/市/总部账户)
  • 全局状态监控与报表
  • 用户算力/积分股查询
  • 历史数据初始化(老用户算力计算)
  • 操作日志与审计

1.2 技术栈

  • 框架: NestJS + TypeScript
  • 数据库: PostgreSQL (CRUD为主)
  • ORM: Prisma
  • 消息队列: Kafka (接收其他服务事件)
  • 缓存: Redis

1.3 端口分配

  • HTTP: 3023
  • 数据库: rwa_mining_admin

2. 架构设计

2.1 目录结构

mining-admin-service/
├── src/
│   ├── api/
│   │   ├── controllers/
│   │   │   ├── config.controller.ts               # 配置管理API
│   │   │   ├── system-account.controller.ts       # 系统账户API
│   │   │   ├── user-query.controller.ts           # 用户查询API
│   │   │   ├── dashboard.controller.ts            # 仪表盘API
│   │   │   ├── report.controller.ts               # 报表API
│   │   │   ├── initialization.controller.ts       # 初始化API
│   │   │   ├── audit-log.controller.ts            # 审计日志API
│   │   │   └── health.controller.ts
│   │   └── dto/
│   │       ├── request/
│   │       │   ├── update-config.request.ts
│   │       │   ├── query-user.request.ts
│   │       │   └── initialize-users.request.ts
│   │       └── response/
│   │           ├── config.response.ts
│   │           ├── dashboard.response.ts
│   │           ├── user-detail.response.ts
│   │           └── report.response.ts
│   │
│   ├── application/
│   │   ├── commands/
│   │   │   ├── update-contribution-config.command.ts
│   │   │   ├── update-distribution-config.command.ts
│   │   │   ├── toggle-transfer.command.ts
│   │   │   ├── initialize-legacy-users.command.ts
│   │   │   ├── create-system-account.command.ts
│   │   │   └── manual-adjustment.command.ts
│   │   ├── queries/
│   │   │   ├── get-dashboard-stats.query.ts
│   │   │   ├── get-user-contribution-detail.query.ts
│   │   │   ├── get-user-mining-detail.query.ts
│   │   │   ├── get-global-state.query.ts
│   │   │   ├── get-system-accounts.query.ts
│   │   │   ├── get-audit-logs.query.ts
│   │   │   └── generate-report.query.ts
│   │   ├── services/
│   │   │   ├── config-management.service.ts
│   │   │   ├── initialization.service.ts
│   │   │   ├── report-generator.service.ts
│   │   │   └── audit.service.ts
│   │   └── event-handlers/
│   │       ├── contribution-calculated.handler.ts
│   │       ├── shares-distributed.handler.ts
│   │       ├── trade-completed.handler.ts
│   │       └── price-updated.handler.ts
│   │
│   ├── domain/
│   │   ├── aggregates/
│   │   │   ├── system-config.aggregate.ts
│   │   │   ├── system-account.aggregate.ts
│   │   │   └── audit-log.aggregate.ts
│   │   ├── repositories/
│   │   │   ├── system-config.repository.interface.ts
│   │   │   ├── system-account.repository.interface.ts
│   │   │   ├── audit-log.repository.interface.ts
│   │   │   └── synced-data.repository.interface.ts
│   │   ├── value-objects/
│   │   │   ├── config-key.vo.ts
│   │   │   └── audit-action.vo.ts
│   │   └── events/
│   │       ├── config-updated.event.ts
│   │       └── initialization-completed.event.ts
│   │
│   ├── infrastructure/
│   │   ├── persistence/
│   │   │   ├── prisma/
│   │   │   │   └── prisma.service.ts
│   │   │   ├── repositories/
│   │   │   │   ├── system-config.repository.impl.ts
│   │   │   │   ├── system-account.repository.impl.ts
│   │   │   │   ├── audit-log.repository.impl.ts
│   │   │   │   └── synced-data.repository.impl.ts
│   │   │   └── unit-of-work/
│   │   │       └── unit-of-work.service.ts
│   │   ├── kafka/
│   │   │   ├── contribution-event-consumer.service.ts
│   │   │   ├── mining-event-consumer.service.ts
│   │   │   ├── trading-event-consumer.service.ts
│   │   │   ├── event-publisher.service.ts
│   │   │   └── kafka.module.ts
│   │   ├── redis/
│   │   │   ├── config-cache.service.ts
│   │   │   └── stats-cache.service.ts
│   │   ├── external/
│   │   │   ├── contribution-client.service.ts
│   │   │   ├── mining-client.service.ts
│   │   │   └── trading-client.service.ts
│   │   └── infrastructure.module.ts
│   │
│   ├── shared/
│   │   ├── guards/
│   │   │   └── admin-auth.guard.ts
│   │   └── decorators/
│   │       └── audit-log.decorator.ts
│   ├── config/
│   ├── app.module.ts
│   └── main.ts
│
├── prisma/
│   ├── schema.prisma
│   └── migrations/
├── package.json
├── tsconfig.json
├── Dockerfile
└── docker-compose.yml

3. 数据库设计

3.1 数据库类型

Mining Admin Service 以查询和配置管理为主,使用 PostgreSQL 作为主数据库,大部分表为 CRUD 操作。

3.2 核心表结构

-- ============================================
-- 系统配置表
-- ============================================

-- 通用配置表Key-Value
CREATE TABLE system_configs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    config_key VARCHAR(100) NOT NULL UNIQUE,
    config_value TEXT NOT NULL,
    config_type VARCHAR(20) NOT NULL,              -- STRING / NUMBER / BOOLEAN / JSON
    description VARCHAR(200),

    is_active BOOLEAN DEFAULT TRUE,
    version INT DEFAULT 1,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_by VARCHAR(50)                         -- 操作人
);

-- 初始化配置数据
INSERT INTO system_configs (config_key, config_value, config_type, description) VALUES
('contribution.base_value', '22617', 'NUMBER', '基础贡献值'),
('contribution.increment_percentage', '0.003', 'NUMBER', '递增百分比 0.3%'),
('contribution.unit_size', '100', 'NUMBER', '单位大小(100棵)'),
('contribution.start_tree_number', '1000', 'NUMBER', '起始树编号'),
('distribution.personal_rate', '0.70', 'NUMBER', '个人分配比例 70%'),
('distribution.operation_rate', '0.12', 'NUMBER', '运营账户比例 12%'),
('distribution.province_rate', '0.01', 'NUMBER', '省公司比例 1%'),
('distribution.city_rate', '0.02', 'NUMBER', '市公司比例 2%'),
('distribution.team_rate', '0.15', 'NUMBER', '团队比例 15%'),
('distribution.level_rate_per', '0.005', 'NUMBER', '每级比例 0.5%'),
('distribution.bonus_rate_per', '0.025', 'NUMBER', '每档奖励比例 2.5%'),
('mining.transfer_enabled', 'false', 'BOOLEAN', '转账功能开关'),
('trading.buy_fee_rate', '0.10', 'NUMBER', '买入手续费率 10%'),
('trading.sell_fee_rate', '0.10', 'NUMBER', '卖出手续费率 10%');

-- 贡献值递增配置表(历史记录)
CREATE TABLE contribution_increment_configs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    base_contribution DECIMAL(20,10) NOT NULL,
    increment_percentage DECIMAL(10,6) NOT NULL,
    unit_size INT NOT NULL,
    start_tree_number INT NOT NULL,

    effective_from DATE NOT NULL,
    effective_to DATE,
    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_by VARCHAR(50)
);

-- 分配比例配置表(历史记录)
CREATE TABLE distribution_rate_configs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    rate_type VARCHAR(30) NOT NULL,                -- PERSONAL/OPERATION/PROVINCE/CITY/TEAM_LEVEL/TEAM_BONUS
    rate_value DECIMAL(10,6) NOT NULL,
    level_depth INT,                               -- TEAM_LEVEL时使用
    bonus_tier INT,                                -- TEAM_BONUS时使用

    effective_from DATE NOT NULL,
    effective_to DATE,
    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_by VARCHAR(50)
);

-- ============================================
-- 系统账户表
-- ============================================

CREATE TABLE system_accounts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    account_type VARCHAR(20) NOT NULL,             -- OPERATION / PROVINCE / CITY / HEADQUARTERS
    account_name VARCHAR(100) NOT NULL,
    account_code VARCHAR(50) UNIQUE,               -- 账户编码

    -- 关联信息(省/市公司时使用)
    region_code VARCHAR(20),
    region_name VARCHAR(100),

    -- 余额(从其他服务同步)
    contribution_balance DECIMAL(30,10) DEFAULT 0,
    share_balance DECIMAL(30,10) DEFAULT 0,
    green_points_balance DECIMAL(30,10) DEFAULT 0,

    -- 特殊标记
    contribution_never_expires BOOLEAN DEFAULT FALSE,

    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 初始化数据
INSERT INTO system_accounts (account_type, account_name, account_code, contribution_never_expires) VALUES
('OPERATION', '运营账户', 'SYS_OPERATION', TRUE),
('HEADQUARTERS', '总部账户', 'SYS_HEADQUARTERS', TRUE),
('PROVINCE', '省公司账户', 'SYS_PROVINCE', FALSE),
('CITY', '市公司账户', 'SYS_CITY', FALSE);

-- ============================================
-- 仪表盘统计快照表
-- ============================================

CREATE TABLE dashboard_snapshots (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    snapshot_time TIMESTAMP WITH TIME ZONE NOT NULL,

    -- 全局状态
    total_users INT DEFAULT 0,
    total_adopted_users INT DEFAULT 0,
    total_trees INT DEFAULT 0,

    -- 算力统计
    total_contribution DECIMAL(30,10) DEFAULT 0,
    effective_contribution DECIMAL(30,10) DEFAULT 0,

    -- 积分股统计
    total_supply DECIMAL(30,10),
    black_hole_amount DECIMAL(30,10),
    circulation_pool DECIMAL(30,10),
    current_price DECIMAL(30,18),

    -- 交易统计
    total_trade_volume DECIMAL(30,10) DEFAULT 0,
    today_trade_volume DECIMAL(30,10) DEFAULT 0,
    total_trade_count INT DEFAULT 0,
    today_trade_count INT DEFAULT 0,

    -- 分配统计
    total_distributed DECIMAL(30,10) DEFAULT 0,
    today_distributed DECIMAL(30,10) DEFAULT 0,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_dashboard_snapshots_time ON dashboard_snapshots(snapshot_time);

-- ============================================
-- 同步数据表(从其他服务汇总)
-- ============================================

-- 用户汇总视图表(定期同步)
CREATE TABLE synced_user_summaries (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    account_sequence VARCHAR(20) NOT NULL UNIQUE,

    -- 基本信息
    phone VARCHAR(20),
    status VARCHAR(20),

    -- 认种信息
    total_trees INT DEFAULT 0,
    first_adoption_date DATE,
    last_adoption_date DATE,

    -- 推荐信息
    referrer_account_sequence VARCHAR(20),
    direct_referral_count INT DEFAULT 0,
    direct_referral_adopted_count INT DEFAULT 0,
    total_team_size INT DEFAULT 0,

    -- 算力信息
    personal_contribution DECIMAL(30,10) DEFAULT 0,
    team_level_contribution DECIMAL(30,10) DEFAULT 0,
    team_bonus_contribution DECIMAL(30,10) DEFAULT 0,
    total_contribution DECIMAL(30,10) DEFAULT 0,
    effective_contribution DECIMAL(30,10) DEFAULT 0,

    -- 积分股信息
    share_balance DECIMAL(30,10) DEFAULT 0,
    total_mined DECIMAL(30,10) DEFAULT 0,
    total_sold DECIMAL(30,10) DEFAULT 0,
    total_bought DECIMAL(30,10) DEFAULT 0,

    -- 同步状态
    last_synced_at TIMESTAMP WITH TIME ZONE,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_synced_user_summaries_phone ON synced_user_summaries(phone);

-- ============================================
-- 审计日志表
-- ============================================

CREATE TABLE audit_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- 操作信息
    action_type VARCHAR(50) NOT NULL,              -- CONFIG_UPDATE / ACCOUNT_CREATE / MANUAL_ADJUST / INIT_USERS / TOGGLE_SWITCH
    action_target VARCHAR(100),                    -- 操作目标如配置key、账户ID等
    action_detail JSONB,                           -- 操作详情

    -- 操作前后值
    before_value JSONB,
    after_value JSONB,

    -- 操作人
    operator_id VARCHAR(50) NOT NULL,
    operator_name VARCHAR(100),
    operator_ip VARCHAR(50),

    -- 操作结果
    result VARCHAR(20) NOT NULL,                   -- SUCCESS / FAILED
    error_message TEXT,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_audit_logs_action ON audit_logs(action_type);
CREATE INDEX idx_audit_logs_time ON audit_logs(created_at);
CREATE INDEX idx_audit_logs_operator ON audit_logs(operator_id);

-- ============================================
-- 初始化任务表
-- ============================================

CREATE TABLE initialization_tasks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    task_type VARCHAR(50) NOT NULL,                -- LEGACY_USER_CONTRIBUTION / GLOBAL_STATE / SYSTEM_ACCOUNTS
    task_status VARCHAR(20) NOT NULL,              -- PENDING / RUNNING / COMPLETED / FAILED

    -- 进度
    total_count INT DEFAULT 0,
    processed_count INT DEFAULT 0,
    failed_count INT DEFAULT 0,

    -- 参数
    task_params JSONB,

    -- 结果
    result_summary JSONB,
    error_message TEXT,

    started_at TIMESTAMP WITH TIME ZONE,
    completed_at TIMESTAMP WITH TIME ZONE,

    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_by VARCHAR(50)
);

-- ============================================
-- 已处理事件(幂等性)
-- ============================================

CREATE TABLE processed_events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    event_id VARCHAR(100) NOT NULL UNIQUE,
    event_type VARCHAR(50) NOT NULL,
    source_service VARCHAR(50),
    processed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

4. 核心业务逻辑

4.1 老用户算力初始化

/**
 * 初始化老用户算力
 * 这是系统上线时的一次性任务
 */
async initializeLegacyUserContributions(): Promise<InitializationResult> {
  // 创建初始化任务
  const task = await this.initTaskRepo.create({
    taskType: 'LEGACY_USER_CONTRIBUTION',
    taskStatus: 'RUNNING',
    startedAt: new Date(),
  });

  try {
    // 1. 获取所有已认种用户
    const adoptedUsers = await this.userRepo.findAllAdoptedUsers();

    await this.initTaskRepo.updateProgress(task.id, {
      totalCount: adoptedUsers.length,
    });

    let processedCount = 0;
    let failedCount = 0;

    // 2. 批量处理用户
    for (const user of adoptedUsers) {
      try {
        // 调用 contribution-service 计算算力
        await this.contributionClient.calculateUserContribution(user.accountSequence);
        processedCount++;
      } catch (error) {
        this.logger.error(`Failed to initialize user ${user.accountSequence}`, error);
        failedCount++;
      }

      // 更新进度
      if ((processedCount + failedCount) % 100 === 0) {
        await this.initTaskRepo.updateProgress(task.id, {
          processedCount,
          failedCount,
        });
      }
    }

    // 3. 完成任务
    await this.initTaskRepo.complete(task.id, {
      processedCount,
      failedCount,
      resultSummary: {
        totalUsers: adoptedUsers.length,
        successCount: processedCount,
        failedCount,
      },
    });

    // 4. 记录审计日志
    await this.auditService.log({
      actionType: 'INIT_USERS',
      actionDetail: { taskId: task.id },
      afterValue: { processedCount, failedCount },
      result: 'SUCCESS',
    });

    return { taskId: task.id, processedCount, failedCount };

  } catch (error) {
    await this.initTaskRepo.fail(task.id, error.message);
    throw error;
  }
}

4.2 配置管理

/**
 * 更新系统配置
 * 所有配置更新都需要记录审计日志
 */
@AuditLog('CONFIG_UPDATE')
async updateConfig(key: string, value: string, operatorId: string): Promise<void> {
  const existing = await this.configRepo.findByKey(key);

  if (!existing) {
    throw new ConfigNotFoundException(key);
  }

  const beforeValue = existing.configValue;

  // 验证值格式
  this.validateConfigValue(key, value, existing.configType);

  // 更新配置
  await this.configRepo.update(key, {
    configValue: value,
    updatedBy: operatorId,
    version: existing.version + 1,
  });

  // 清除缓存
  await this.configCache.invalidate(key);

  // 发布配置更新事件
  await this.eventPublisher.publish('mining-admin.config-updated', {
    eventId: uuid(),
    configKey: key,
    beforeValue,
    afterValue: value,
    updatedBy: operatorId,
    updatedAt: new Date().toISOString(),
  });
}

/**
 * 切换转账开关
 */
@AuditLog('TOGGLE_SWITCH')
async toggleTransfer(enabled: boolean, operatorId: string): Promise<void> {
  const key = 'mining.transfer_enabled';

  await this.updateConfig(key, String(enabled), operatorId);

  // 通知 mining-service
  await this.miningClient.updateTransferSwitch(enabled);
}

4.3 仪表盘统计

/**
 * 获取仪表盘统计数据
 */
async getDashboardStats(): Promise<DashboardStatsDto> {
  // 优先从缓存获取
  const cached = await this.statsCache.get('dashboard');
  if (cached) {
    return cached;
  }

  // 聚合各服务数据
  const [
    globalState,
    contributionStats,
    tradingStats,
    userStats,
  ] = await Promise.all([
    this.miningClient.getGlobalState(),
    this.contributionClient.getNetworkStats(),
    this.tradingClient.getTodayStats(),
    this.getUserStats(),
  ]);

  const stats: DashboardStatsDto = {
    // 全局状态
    currentPrice: globalState.currentPrice,
    blackHoleAmount: globalState.blackHoleAmount,
    circulationPool: globalState.circulationPool,
    minuteBurnRate: globalState.minuteBurnRate,

    // 算力统计
    networkTotalContribution: contributionStats.totalContribution,
    networkEffectiveContribution: contributionStats.effectiveContribution,

    // 用户统计
    totalUsers: userStats.totalUsers,
    adoptedUsers: userStats.adoptedUsers,
    totalTrees: userStats.totalTrees,

    // 交易统计
    todayTradeVolume: tradingStats.volume,
    todayTradeCount: tradingStats.count,

    // 分配统计
    totalDistributed: globalState.totalDistributed,
    distributionPhase: globalState.distributionPhase,
    dailyDistribution: globalState.dailyDistribution,

    updatedAt: new Date().toISOString(),
  };

  // 缓存 30 秒
  await this.statsCache.set('dashboard', stats, 30);

  // 保存快照
  await this.dashboardSnapshotRepo.create(stats);

  return stats;
}

4.4 用户详情查询

/**
 * 查询用户算力和挖矿详情
 */
async getUserDetail(accountSequence: string): Promise<UserDetailDto> {
  const [
    contribution,
    shareAccount,
    miningRecords,
    tradeOrders,
    referralInfo,
  ] = await Promise.all([
    this.contributionClient.getUserContribution(accountSequence),
    this.miningClient.getUserShareAccount(accountSequence),
    this.miningClient.getUserMiningRecords(accountSequence, { limit: 30 }),
    this.tradingClient.getUserOrders(accountSequence, { limit: 30 }),
    this.getUserReferralInfo(accountSequence),
  ]);

  return {
    accountSequence,

    // 算力信息
    contribution: {
      personal: contribution.personalContribution,
      teamLevel: contribution.teamLevelContribution,
      teamBonus: contribution.teamBonusContribution,
      total: contribution.totalContribution,
      effective: contribution.effectiveContribution,
      hasAdopted: contribution.hasAdopted,
      directReferralAdoptedCount: contribution.directReferralAdoptedCount,
      unlockedLevelDepth: contribution.unlockedLevelDepth,
      unlockedBonusTiers: contribution.unlockedBonusTiers,
    },

    // 积分股信息
    shares: {
      available: shareAccount.availableBalance,
      frozen: shareAccount.frozenBalance,
      totalMined: shareAccount.totalMined,
      totalSold: shareAccount.totalSold,
      totalBought: shareAccount.totalBought,
      perSecondEarning: shareAccount.perSecondEarning,
    },

    // 推荐信息
    referral: referralInfo,

    // 最近挖矿记录
    recentMiningRecords: miningRecords,

    // 最近交易记录
    recentTradeOrders: tradeOrders,
  };
}

5. 服务间通信

5.1 订阅的事件

Topic 来源服务 数据内容 处理方式
contribution.contribution-calculated contribution-service 用户算力计算完成 更新本地用户汇总
mining.shares-distributed mining-service 积分股分配完成 更新分配统计
mining.price-updated mining-service 价格更新 更新仪表盘
trading.trade-completed trading-service 交易完成 更新交易统计

5.2 发布的事件

Topic 事件类型 订阅者
mining-admin.config-updated ConfigUpdated contribution/mining/trading

5.3 调用其他服务

// 调用 contribution-service
this.contributionClient.getUserContribution(accountSequence);
this.contributionClient.calculateUserContribution(accountSequence);
this.contributionClient.getNetworkStats();

// 调用 mining-service
this.miningClient.getGlobalState();
this.miningClient.getUserShareAccount(accountSequence);
this.miningClient.getUserMiningRecords(accountSequence);
this.miningClient.updateTransferSwitch(enabled);

// 调用 trading-service
this.tradingClient.getUserOrders(accountSequence);
this.tradingClient.getTodayStats();
this.tradingClient.getKlineData(period);

6. API 设计

6.1 配置管理 API

GET    /api/admin/configs                    # 获取所有配置
GET    /api/admin/configs/:key               # 获取单个配置
PUT    /api/admin/configs/:key               # 更新配置
POST   /api/admin/configs/toggle-transfer    # 切换转账开关

6.2 系统账户 API

GET    /api/admin/system-accounts            # 获取所有系统账户
GET    /api/admin/system-accounts/:id        # 获取单个账户详情
POST   /api/admin/system-accounts            # 创建系统账户
PUT    /api/admin/system-accounts/:id        # 更新系统账户

6.3 用户查询 API

GET    /api/admin/users                      # 用户列表(分页)
GET    /api/admin/users/:accountSequence     # 用户详情
GET    /api/admin/users/:accountSequence/contribution-records  # 算力明细
GET    /api/admin/users/:accountSequence/mining-records        # 挖矿明细
GET    /api/admin/users/:accountSequence/trade-orders          # 交易记录

6.4 仪表盘 API

GET    /api/admin/dashboard                  # 仪表盘统计
GET    /api/admin/dashboard/realtime         # 实时数据WebSocket推送
GET    /api/admin/dashboard/charts           # 图表数据

6.5 报表 API

GET    /api/admin/reports/daily              # 日报表
GET    /api/admin/reports/contribution       # 算力报表
GET    /api/admin/reports/mining             # 挖矿报表
GET    /api/admin/reports/trading            # 交易报表
POST   /api/admin/reports/export             # 导出报表

6.6 初始化 API

POST   /api/admin/initialization/legacy-users   # 初始化老用户算力
POST   /api/admin/initialization/global-state   # 初始化全局状态
GET    /api/admin/initialization/tasks          # 获取初始化任务列表
GET    /api/admin/initialization/tasks/:id      # 获取任务详情

6.7 审计日志 API

GET    /api/admin/audit-logs                 # 审计日志列表
GET    /api/admin/audit-logs/:id             # 审计日志详情

7. 审计日志装饰器

/**
 * 审计日志装饰器
 * 自动记录操作前后的值变化
 */
export function AuditLog(actionType: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = async function (...args: any[]) {
      const auditService = this.auditService;
      const operatorId = this.getCurrentOperatorId();

      // 记录操作前状态(如果需要)
      let beforeValue = null;
      if (actionType === 'CONFIG_UPDATE') {
        beforeValue = await this.getBeforeValue(args);
      }

      try {
        const result = await originalMethod.apply(this, args);

        // 记录成功日志
        await auditService.log({
          actionType,
          actionTarget: this.getActionTarget(args),
          actionDetail: this.getActionDetail(args),
          beforeValue,
          afterValue: this.getAfterValue(args, result),
          operatorId,
          result: 'SUCCESS',
        });

        return result;
      } catch (error) {
        // 记录失败日志
        await auditService.log({
          actionType,
          actionTarget: this.getActionTarget(args),
          actionDetail: this.getActionDetail(args),
          beforeValue,
          operatorId,
          result: 'FAILED',
          errorMessage: error.message,
        });

        throw error;
      }
    };

    return descriptor;
  };
}

8. 关键注意事项

8.1 权限控制

  • 所有 API 需要管理员认证
  • 敏感操作需要二次确认
  • 配置修改需要记录操作人

8.2 数据一致性

  • 本地汇总数据定期与源服务同步
  • 仪表盘数据缓存有 TTL
  • 重要操作使用事务

8.3 审计要求

  • 所有配置变更记录审计日志
  • 记录操作前后值
  • 保留操作人信息和 IP

8.4 性能优化

  • 使用 Redis 缓存频繁查询的数据
  • 仪表盘统计定期快照
  • 用户列表查询分页

9. 开发检查清单

  • 实现配置管理 API
  • 实现系统账户管理
  • 实现用户查询 API
  • 实现仪表盘统计
  • 实现老用户初始化功能
  • 实现审计日志记录
  • 配置与其他服务的 HTTP 客户端
  • 配置 Kafka Consumer
  • 实现管理员认证
  • 编写测试

10. 启动命令

# 开发环境
npm run start:dev

# 生成 Prisma Client
npx prisma generate

# 运行迁移
npx prisma migrate dev

# 生产环境
npm run build && npm run start:prod