rwadurian/backend/services/contribution-service/DEVELOPMENT_GUIDE.md

721 lines
24 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.

# Contribution Service (贡献值/算力服务) 开发指导
## 1. 服务概述
### 1.1 核心职责
Contribution Service 负责管理用户的贡献值(算力),这是挖矿系统的核心计算基础。
**主要功能:**
- 通过 Debezium CDC 同步用户、认种、推荐关系数据
- 计算用户算力(来自自己认种 + 团队贡献)
- 维护算力明细账(每笔算力的来源可追溯)
- 处理算力过期2年有效期
- 管理未分配算力归总部逻辑
### 1.2 技术栈
- **框架**: NestJS + TypeScript
- **数据库**: PostgreSQL (事务型)
- **ORM**: Prisma
- **消息队列**: Kafka (Debezium CDC + 事件发布)
- **缓存**: Redis
### 1.3 端口分配
- HTTP: 3020
- 数据库: rwa_contribution
---
## 2. 架构设计
### 2.1 六边形架构分层
```
┌─────────────────────────────────────────────────────────────┐
│ API Layer (api/) │
│ Controllers, DTOs - 处理 HTTP 请求 │
├─────────────────────────────────────────────────────────────┤
│ Application Layer (application/) │
│ Commands, Queries, Event Handlers - 业务流程编排 │
├─────────────────────────────────────────────────────────────┤
│ Domain Layer (domain/) │
│ Aggregates, Value Objects, Domain Events - 核心业务规则 │
├─────────────────────────────────────────────────────────────┤
│ Infrastructure Layer (infrastructure/) │
│ Prisma, Kafka, Redis - 技术实现细节 │
└─────────────────────────────────────────────────────────────┘
```
### 2.2 目录结构
```
contribution-service/
├── src/
│ ├── api/ # API层
│ │ ├── controllers/
│ │ │ ├── contribution.controller.ts # 算力查询API
│ │ │ ├── sync-status.controller.ts # 同步状态API
│ │ │ └── health.controller.ts
│ │ └── dto/
│ │ ├── request/
│ │ └── response/
│ │ ├── contribution-account.response.ts
│ │ └── contribution-detail.response.ts
│ │
│ ├── application/ # 应用层
│ │ ├── commands/
│ │ │ ├── calculate-user-contribution.command.ts
│ │ │ ├── process-adoption-contribution.command.ts
│ │ │ ├── expire-contributions.command.ts
│ │ │ └── recalculate-all-contributions.command.ts
│ │ ├── queries/
│ │ │ ├── get-user-contribution.query.ts
│ │ │ ├── get-contribution-details.query.ts
│ │ │ └── get-network-total-contribution.query.ts
│ │ ├── services/
│ │ │ └── contribution-calculation.service.ts
│ │ ├── event-handlers/
│ │ │ ├── adoption-synced.handler.ts
│ │ │ ├── user-synced.handler.ts
│ │ │ └── referral-synced.handler.ts
│ │ └── schedulers/
│ │ ├── contribution-expiry.scheduler.ts
│ │ └── daily-snapshot.scheduler.ts
│ │
│ ├── domain/ # 领域层
│ │ ├── aggregates/
│ │ │ ├── contribution-account.aggregate.ts
│ │ │ └── contribution-record.aggregate.ts
│ │ ├── repositories/
│ │ │ ├── contribution-account.repository.interface.ts
│ │ │ ├── contribution-record.repository.interface.ts
│ │ │ ├── synced-user.repository.interface.ts
│ │ │ ├── synced-adoption.repository.interface.ts
│ │ │ └── synced-referral.repository.interface.ts
│ │ ├── value-objects/
│ │ │ ├── contribution-amount.vo.ts
│ │ │ ├── distribution-rate.vo.ts
│ │ │ └── account-sequence.vo.ts
│ │ ├── events/
│ │ │ ├── contribution-calculated.event.ts
│ │ │ ├── contribution-expired.event.ts
│ │ │ └── daily-snapshot-created.event.ts
│ │ └── services/
│ │ ├── contribution-calculator.service.ts
│ │ └── team-contribution-calculator.service.ts
│ │
│ ├── infrastructure/ # 基础设施层
│ │ ├── persistence/
│ │ │ ├── prisma/
│ │ │ │ └── prisma.service.ts
│ │ │ ├── repositories/
│ │ │ │ ├── contribution-account.repository.impl.ts
│ │ │ │ ├── contribution-record.repository.impl.ts
│ │ │ │ ├── synced-user.repository.impl.ts
│ │ │ │ ├── synced-adoption.repository.impl.ts
│ │ │ │ └── synced-referral.repository.impl.ts
│ │ │ └── unit-of-work/
│ │ │ └── unit-of-work.service.ts
│ │ ├── kafka/
│ │ │ ├── cdc-consumers/
│ │ │ │ ├── user-cdc.consumer.ts
│ │ │ │ ├── adoption-cdc.consumer.ts
│ │ │ │ └── referral-cdc.consumer.ts
│ │ │ ├── event-publisher.service.ts
│ │ │ └── kafka.module.ts
│ │ ├── redis/
│ │ │ └── contribution-cache.service.ts
│ │ └── infrastructure.module.ts
│ │
│ ├── shared/
│ ├── config/
│ ├── app.module.ts
│ └── main.ts
├── prisma/
│ ├── schema.prisma
│ └── migrations/
├── package.json
├── tsconfig.json
├── Dockerfile
└── docker-compose.yml
```
---
## 3. 数据库设计
### 3.1 数据库类型选择
| 表类型 | 数据库类型 | 原因 |
|--------|-----------|------|
| 同步数据表 | 事务型 (PostgreSQL) | CDC 数据需要精确同步,支持事务 |
| 算力账户表 | 事务型 (PostgreSQL) | 余额变更需要强一致性 |
| 算力明细表 | 事务型 (PostgreSQL) | 明细账需要完整性约束 |
| 快照表 | 事务型 (PostgreSQL) | 历史数据需要持久化 |
### 3.2 核心表结构
```sql
-- ============================================
-- CDC 同步数据表(从其他服务同步)
-- ============================================
-- 同步的用户数据
CREATE TABLE synced_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_sequence VARCHAR(20) NOT NULL UNIQUE, -- 跨服务关联键
original_user_id UUID NOT NULL,
phone VARCHAR(20),
status VARCHAR(20),
created_at TIMESTAMP WITH TIME ZONE,
-- CDC 同步元数据
source_sequence_num BIGINT NOT NULL, -- 源数据的序列号
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- 算力计算状态
contribution_calculated BOOLEAN DEFAULT FALSE,
contribution_calculated_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_synced_users_sequence ON synced_users(account_sequence);
CREATE INDEX idx_synced_users_not_calculated ON synced_users(contribution_calculated) WHERE contribution_calculated = FALSE;
-- 同步的认种数据
CREATE TABLE synced_adoptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
original_adoption_id UUID NOT NULL UNIQUE,
account_sequence VARCHAR(20) NOT NULL,
tree_count INT NOT NULL,
adoption_date DATE NOT NULL,
status VARCHAR(20),
-- 贡献值计算参数(从认种时的配置)
contribution_per_tree DECIMAL(20,10) NOT NULL,
-- CDC 同步元数据
source_sequence_num BIGINT NOT NULL,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- 算力分配状态
contribution_distributed BOOLEAN DEFAULT FALSE,
contribution_distributed_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_synced_adoptions_account ON synced_adoptions(account_sequence);
CREATE INDEX idx_synced_adoptions_not_distributed ON synced_adoptions(contribution_distributed) WHERE contribution_distributed = FALSE;
-- 同步的推荐关系数据
CREATE TABLE synced_referrals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_sequence VARCHAR(20) NOT NULL, -- 用户
referrer_account_sequence VARCHAR(20), -- 推荐人
-- 预计算的层级路径(便于快速查询上下级)
ancestor_path TEXT, -- 格式: /root/seq1/seq2/.../
depth INT DEFAULT 0,
-- CDC 同步元数据
source_sequence_num BIGINT NOT NULL,
synced_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(account_sequence)
);
CREATE INDEX idx_synced_referrals_referrer ON synced_referrals(referrer_account_sequence);
CREATE INDEX idx_synced_referrals_path ON synced_referrals USING gin(ancestor_path gin_trgm_ops);
-- ============================================
-- 算力账户与明细表
-- ============================================
-- 算力账户表(汇总)
CREATE TABLE contribution_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_sequence VARCHAR(20) NOT NULL UNIQUE,
-- 算力汇总
personal_contribution DECIMAL(30,10) DEFAULT 0, -- 来自自己认种 (70%)
team_level_contribution DECIMAL(30,10) DEFAULT 0, -- 来自团队层级 (0.5%×N级)
team_bonus_contribution DECIMAL(30,10) DEFAULT 0, -- 来自团队额外奖励 (2.5%×N)
total_contribution DECIMAL(30,10) DEFAULT 0, -- 总算力
effective_contribution DECIMAL(30,10) DEFAULT 0, -- 有效算力(未过期)
-- 用户条件(决定能获得多少团队算力)
has_adopted BOOLEAN DEFAULT FALSE,
direct_referral_adopted_count INT DEFAULT 0,
-- 解锁状态
unlocked_level_depth INT DEFAULT 0, -- 5/10/15
unlocked_bonus_tiers INT DEFAULT 0, -- 1/2/3
-- 版本号(乐观锁)
version INT DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 算力明细表(分类账)
CREATE TABLE contribution_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_sequence VARCHAR(20) NOT NULL, -- 算力归属用户
-- 来源信息(可追溯)
source_type VARCHAR(30) NOT NULL, -- PERSONAL / TEAM_LEVEL / TEAM_BONUS
source_adoption_id UUID NOT NULL, -- 来源认种记录
source_account_sequence VARCHAR(20) NOT NULL, -- 认种人
-- 计算参数(审计用)
tree_count INT NOT NULL,
base_contribution DECIMAL(20,10) NOT NULL,
distribution_rate DECIMAL(10,6) NOT NULL, -- 70% / 0.5% / 2.5%
level_depth INT, -- 层级TEAM_LEVEL时
bonus_tier INT, -- 档位TEAM_BONUS时1/2/3
-- 结果
amount DECIMAL(30,10) NOT NULL,
-- 有效期
effective_date DATE NOT NULL, -- 次日生效
expire_date DATE NOT NULL, -- 2年后过期
is_expired BOOLEAN DEFAULT FALSE,
expired_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_contribution_records_account ON contribution_records(account_sequence);
CREATE INDEX idx_contribution_records_source ON contribution_records(source_adoption_id);
CREATE INDEX idx_contribution_records_expire ON contribution_records(expire_date) WHERE is_expired = FALSE;
-- 未分配算力记录(归总部)
CREATE TABLE unallocated_contributions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source_adoption_id UUID NOT NULL,
source_account_sequence VARCHAR(20) NOT NULL,
unalloc_type VARCHAR(30) NOT NULL, -- LEVEL_OVERFLOW / BONUS_TIER_1/2/3
would_be_account_sequence VARCHAR(20), -- 本应获得的上线
level_depth INT,
amount DECIMAL(30,10) NOT NULL,
reason VARCHAR(200),
-- 归总部后的处理
allocated_to_headquarters BOOLEAN DEFAULT FALSE,
allocated_at TIMESTAMP WITH TIME ZONE,
effective_date DATE NOT NULL,
expire_date DATE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 系统账户(运营/省/市/总部)
CREATE TABLE system_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_type VARCHAR(20) NOT NULL UNIQUE, -- OPERATION/PROVINCE/CITY/HEADQUARTERS
name VARCHAR(100) NOT NULL,
contribution_balance DECIMAL(30,10) DEFAULT 0,
contribution_never_expires BOOLEAN DEFAULT FALSE,
version INT DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 系统账户算力明细
CREATE TABLE system_contribution_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
system_account_id UUID NOT NULL REFERENCES system_accounts(id),
source_adoption_id UUID NOT NULL,
source_account_sequence VARCHAR(20) NOT NULL,
distribution_rate DECIMAL(10,6) NOT NULL, -- 12% / 1% / 2%
amount DECIMAL(30,10) NOT NULL,
effective_date DATE NOT NULL,
expire_date DATE, -- NULL = 永不过期
is_expired BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- ============================================
-- 快照与统计表
-- ============================================
-- 每日算力快照(用于挖矿分配计算)
CREATE TABLE daily_contribution_snapshots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
snapshot_date DATE NOT NULL,
account_sequence VARCHAR(20) NOT NULL,
effective_contribution DECIMAL(30,10) NOT NULL,
network_total_contribution DECIMAL(30,10) NOT NULL,
contribution_ratio DECIMAL(30,18) NOT NULL, -- 占比(高精度)
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(snapshot_date, account_sequence)
);
CREATE INDEX idx_daily_snapshots_date ON daily_contribution_snapshots(snapshot_date);
-- 用户团队统计(缓存,定期更新)
CREATE TABLE user_team_stats (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_sequence VARCHAR(20) NOT NULL,
stats_date DATE NOT NULL,
-- 各级认种统计
level_1_trees INT DEFAULT 0,
level_2_trees INT DEFAULT 0,
level_3_trees INT DEFAULT 0,
level_4_trees INT DEFAULT 0,
level_5_trees INT DEFAULT 0,
level_6_trees INT DEFAULT 0,
level_7_trees INT DEFAULT 0,
level_8_trees INT DEFAULT 0,
level_9_trees INT DEFAULT 0,
level_10_trees INT DEFAULT 0,
level_11_trees INT DEFAULT 0,
level_12_trees INT DEFAULT 0,
level_13_trees INT DEFAULT 0,
level_14_trees INT DEFAULT 0,
level_15_trees INT DEFAULT 0,
total_team_trees INT DEFAULT 0,
direct_adopted_referrals INT DEFAULT 0, -- 直推认种用户数
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(account_sequence, stats_date)
);
-- ============================================
-- CDC 同步状态追踪
-- ============================================
-- CDC 同步进度表
CREATE TABLE cdc_sync_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source_topic VARCHAR(100) NOT NULL UNIQUE,
last_sequence_num BIGINT DEFAULT 0,
last_synced_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 已处理事件表(幂等性)
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()
);
-- ============================================
-- 配置表
-- ============================================
-- 贡献值递增配置
CREATE TABLE contribution_configs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
base_contribution DECIMAL(20,10) DEFAULT 22617,
increment_percentage DECIMAL(10,6) DEFAULT 0.003, -- 0.3%
unit_size INT DEFAULT 100,
start_tree_number INT DEFAULT 1000,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 分配比例配置
CREATE TABLE distribution_rate_configs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rate_type VARCHAR(30) NOT NULL UNIQUE, -- PERSONAL/OPERATION/PROVINCE/CITY/LEVEL_PER/BONUS_PER
rate_value DECIMAL(10,6) NOT NULL,
description VARCHAR(100),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
---
## 4. 核心业务逻辑
### 4.1 算力计算公式
```typescript
/**
* 计算用户 X 的总算力
*/
function calculateUserContribution(accountSequence: string): ContributionResult {
const user = getUserWithTeamStats(accountSequence);
// 1. 来自自己认种 (70%)
const personalContribution = user.ownAdoptions.reduce((sum, adoption) => {
return sum + adoption.treeCount * adoption.contributionPerTree * 0.70;
}, 0);
// 2. 来自团队层级 (每级0.5%)
const unlockedLevels = getUnlockedLevelDepth(user.directReferralAdoptedCount);
let teamLevelContribution = 0;
for (let level = 1; level <= unlockedLevels; level++) {
const levelTrees = user.teamStats[`level_${level}_trees`];
const levelContribution = levelTrees * baseContribution * 0.005; // 0.5%
teamLevelContribution += levelContribution;
}
// 3. 来自团队额外奖励 (只看第1级最多3个2.5%)
const unlockedBonusTiers = getUnlockedBonusTiers(user);
const level1Trees = user.teamStats.level_1_trees;
const teamBonusContribution = level1Trees * baseContribution * 0.025 * unlockedBonusTiers;
return {
personalContribution,
teamLevelContribution,
teamBonusContribution,
totalContribution: personalContribution + teamLevelContribution + teamBonusContribution
};
}
/**
* 根据直推认种用户数确定解锁层级
*/
function getUnlockedLevelDepth(directReferralAdoptedCount: number): number {
if (directReferralAdoptedCount >= 5) return 15;
if (directReferralAdoptedCount >= 3) return 10;
if (directReferralAdoptedCount >= 1) return 5;
return 0;
}
/**
* 根据用户条件确定解锁的额外奖励档位数
*/
function getUnlockedBonusTiers(user: User): number {
let tiers = 0;
if (user.hasAdopted) tiers++; // 自己认种过 → +1档
if (user.directReferralAdoptedCount >= 2) tiers++; // 直推≥2 → +1档
if (user.directReferralAdoptedCount >= 4) tiers++; // 直推≥4 → +1档
return tiers; // 0/1/2/3
}
```
### 4.2 认种事件处理流程
```typescript
/**
* 当新认种发生时的处理流程
*/
async function processAdoptionContribution(adoption: SyncedAdoption): Promise<void> {
const totalContribution = adoption.treeCount * adoption.contributionPerTree;
await unitOfWork.runInTransaction(async (tx) => {
// 1. 分配给认种人 (70%)
await createContributionRecord(tx, {
accountSequence: adoption.accountSequence,
sourceType: 'PERSONAL',
sourceAdoptionId: adoption.id,
amount: totalContribution * 0.70,
distributionRate: 0.70,
});
// 2. 分配给系统账户 (15%)
await createSystemContribution(tx, 'OPERATION', adoption, 0.12);
await createSystemContribution(tx, 'PROVINCE', adoption, 0.01);
await createSystemContribution(tx, 'CITY', adoption, 0.02);
// 3. 分配给上线团队 (15%)
await distributeTeamContribution(tx, adoption, totalContribution * 0.15);
// 4. 标记已分配
await markAdoptionDistributed(tx, adoption.id);
});
}
/**
* 分配团队贡献值给上线链条
*/
async function distributeTeamContribution(
tx: Transaction,
adoption: Adoption,
teamTotal: number
): Promise<void> {
const ancestors = await getAncestorChain(adoption.accountSequence, 15);
let distributedLevel = 0;
let distributedBonus = 0;
for (let i = 0; i < ancestors.length && i < 15; i++) {
const ancestor = ancestors[i];
const level = i + 1;
// 层级部分 (0.5% 每级)
const levelAmount = teamTotal * 0.5 / 15; // 7.5% / 15 = 0.5%
if (ancestor.unlockedLevelDepth >= level) {
await createContributionRecord(tx, {
accountSequence: ancestor.accountSequence,
sourceType: 'TEAM_LEVEL',
levelDepth: level,
amount: levelAmount,
});
distributedLevel += levelAmount;
} else {
// 未解锁,归总部
await createUnallocatedContribution(tx, {
type: 'LEVEL_OVERFLOW',
wouldBeAccount: ancestor.accountSequence,
levelDepth: level,
amount: levelAmount,
});
}
}
// 额外奖励部分 (只给直接上线)
if (ancestors.length > 0) {
const directReferrer = ancestors[0];
const bonusPerTier = teamTotal * 0.5 / 3; // 7.5% / 3 = 2.5%
for (let tier = 1; tier <= 3; tier++) {
if (directReferrer.unlockedBonusTiers >= tier) {
await createContributionRecord(tx, {
accountSequence: directReferrer.accountSequence,
sourceType: 'TEAM_BONUS',
bonusTier: tier,
amount: bonusPerTier,
});
distributedBonus += bonusPerTier;
} else {
await createUnallocatedContribution(tx, {
type: `BONUS_TIER_${tier}`,
wouldBeAccount: directReferrer.accountSequence,
amount: bonusPerTier,
});
}
}
}
}
```
### 4.3 CDC 数据同步
```typescript
/**
* Debezium CDC Consumer - 用户数据同步
*/
@Consumer({ topic: 'dbserver1.rwa_identity.users' })
async handleUserCdc(message: DebeziumMessage): Promise<void> {
const { op, after, source } = message;
const sequenceNum = source.sequence;
// 幂等性检查
if (await isEventProcessed(`user-cdc-${sequenceNum}`)) {
return;
}
switch (op) {
case 'c': // CREATE
case 'u': // UPDATE
await syncedUserRepository.upsert({
accountSequence: after.account_sequence,
originalUserId: after.id,
phone: after.phone,
status: after.status,
sourceSequenceNum: sequenceNum,
});
break;
case 'd': // DELETE
// 通常不处理删除,或标记为 inactive
break;
}
await markEventProcessed(`user-cdc-${sequenceNum}`);
}
```
---
## 5. 服务间通信
### 5.1 事件发布Outbox Pattern
```typescript
// 发布算力计算完成事件
interface ContributionCalculatedEvent {
eventId: string;
eventType: 'ContributionCalculated';
accountSequence: string;
totalContribution: string;
effectiveContribution: string;
calculatedAt: string;
}
// Mining Service 订阅此事件用于挖矿分配
```
### 5.2 订阅的 CDC Topics
| Topic | 来源服务 | 数据内容 |
|-------|---------|---------|
| `dbserver1.rwa_identity.users` | identity-service | 用户基本信息 |
| `dbserver1.rwa_planting.adoptions` | planting-service | 认种记录 |
| `dbserver1.rwa_referral.referral_relations` | referral-service | 推荐关系 |
---
## 6. 关键注意事项
### 6.1 数据一致性
- 所有算力变更必须在事务中完成
- 使用乐观锁 (version 字段) 处理并发更新
- 明细账与汇总账必须保持一致
### 6.2 幂等性
- CDC 消息可能重复,使用 sequence_num 去重
- 认种分配使用 contribution_distributed 标记防止重复
### 6.3 性能优化
- 团队统计表 (user_team_stats) 定期预计算
- 使用 Redis 缓存热点用户算力
- 批量处理历史数据计算
### 6.4 跨服务关联
- **始终使用 account_sequence不使用 userId**
- account_sequence 是唯一的跨服务关联标识
---
## 7. 开发检查清单
- [ ] 实现 CDC Consumer 同步用户/认种/推荐数据
- [ ] 实现算力计算核心逻辑
- [ ] 实现算力明细账记录
- [ ] 实现未分配算力归总部逻辑
- [ ] 实现算力过期处理定时任务
- [ ] 实现每日快照生成
- [ ] 实现查询 API
- [ ] 编写单元测试
- [ ] 编写集成测试
- [ ] 配置 Debezium Connector
---
## 8. 启动命令
```bash
# 开发环境
npm run start:dev
# 生成 Prisma Client
npx prisma generate
# 运行迁移
npx prisma migrate dev
# 生产环境
npm run build && npm run start:prod
```