docs: add planting architecture optimization documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-09 02:36:51 -08:00
parent 781721a659
commit 27bd9d9d0a
1 changed files with 550 additions and 0 deletions

View File

@ -0,0 +1,550 @@
# 认种功能架构优化方案
## 概述
本文档描述认种Planting功能的架构优化方案基于现有微服务架构进行扩展实现 2199 USDT 的完整分配流程。
**核心原则:**
- 所有账户地址通过 MPC 按需生成
- 所有资金操作都是区块链转账(从认种人钱包转出)
- 不创建新服务,只扩展现有服务
---
## 一、2199 USDT 分配明细
每棵树认种费用 2199 USDT分配如下
| 序号 | 账户类型 | 金额(USDT) | 说明 |
|------|----------|------------|------|
| 1 | 成本账户 | 400 | 固定成本 |
| 2 | 运营账户 | 300 | 运营费用 |
| 3 | 总部社区账户 | 9 | 总部社区收益 |
| 4 | RWAD矿池 | 800 | 注入矿池30天后开始挖矿 |
| 5 | 直接推荐人 | 500 | 仅直推,无多级 |
| 6 | 省公司区域权益 | 15 | 正式省公司含1%算力) |
| 7 | 省公司团队权益 | 20 | 授权省公司 |
| 8 | 市公司区域权益 | 35 | 正式市公司含2%算力) |
| 9 | 市公司团队权益 | 40 | 授权市公司 |
| 10 | 社区权益 | 80 | 社区授权 |
| **合计** | | **2199** | |
---
## 二、系统账户设计
### 2.1 系统账户类型
```typescript
enum SystemAccountType {
COST_ACCOUNT = 'COST_ACCOUNT', // 成本账户
OPERATION_ACCOUNT = 'OPERATION_ACCOUNT', // 运营账户
HQ_COMMUNITY = 'HQ_COMMUNITY', // 总部社区账户
RWAD_POOL_PENDING = 'RWAD_POOL_PENDING', // RWAD矿池待注入
SYSTEM_PROVINCE = 'SYSTEM_PROVINCE', // 系统省账户(无授权时)
SYSTEM_CITY = 'SYSTEM_CITY', // 系统市账户(无授权时)
}
```
### 2.2 数据库表设计(扩展 authorization-service
```prisma
// ============================================
// 系统账户表
// 管理成本、运营、总部社区、矿池等系统级账户
// ============================================
model SystemAccount {
id BigInt @id @default(autoincrement()) @map("account_id")
// 账户类型
accountType String @map("account_type") @db.VarChar(30)
// 区域信息(仅 SYSTEM_PROVINCE/SYSTEM_CITY 需要)
regionCode String? @map("region_code") @db.VarChar(10)
regionName String? @map("region_name") @db.VarChar(50)
// MPC 生成的钱包地址(按需生成)
walletAddress String? @map("wallet_address") @db.VarChar(42)
mpcPublicKey String? @map("mpc_public_key") @db.VarChar(130)
// 余额
usdtBalance Decimal @default(0) @map("usdt_balance") @db.Decimal(20, 8)
hashpower Decimal @default(0) @map("hashpower") @db.Decimal(20, 8)
// 累计统计
totalReceived Decimal @default(0) @map("total_received") @db.Decimal(20, 8)
totalTransferred Decimal @default(0) @map("total_transferred") @db.Decimal(20, 8)
// 状态
status String @default("ACTIVE") @map("status") @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
ledgerEntries SystemAccountLedger[]
@@unique([accountType, regionCode], name: "uk_account_region")
@@index([accountType], name: "idx_account_type")
@@index([walletAddress], name: "idx_wallet_address")
@@map("system_accounts")
}
// ============================================
// 系统账户流水表
// 记录系统账户的所有资金变动
// ============================================
model SystemAccountLedger {
id BigInt @id @default(autoincrement()) @map("ledger_id")
accountId BigInt @map("account_id")
// 流水类型
entryType String @map("entry_type") @db.VarChar(50)
// 金额
amount Decimal @map("amount") @db.Decimal(20, 8)
balanceAfter Decimal @map("balance_after") @db.Decimal(20, 8)
// 关联信息
sourceOrderId BigInt? @map("source_order_id") // 来源认种订单
txHash String? @map("tx_hash") @db.VarChar(66) // 链上交易哈希
memo String? @map("memo") @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
account SystemAccount @relation(fields: [accountId], references: [id])
@@index([accountId, createdAt(sort: Desc)], name: "idx_account_created")
@@index([sourceOrderId], name: "idx_source_order")
@@index([txHash], name: "idx_tx_hash")
@@map("system_account_ledgers")
}
```
---
## 三、MPC 按需生成地址流程
### 3.1 触发条件
当系统账户需要接收资金但尚未生成钱包地址时:
```typescript
async function ensureWalletAddress(systemAccount: SystemAccount): Promise<string> {
if (systemAccount.walletAddress) {
return systemAccount.walletAddress;
}
// 调用 MPC 服务生成地址
const { publicKey, address } = await mpcService.generateAddress({
accountType: 'SYSTEM',
accountId: systemAccount.id.toString(),
});
// 更新系统账户
await prisma.systemAccount.update({
where: { id: systemAccount.id },
data: {
walletAddress: address,
mpcPublicKey: publicKey,
},
});
// 注册到 blockchain-service 进行监听
await blockchainService.registerMonitoredAddress({
address,
accountType: 'SYSTEM',
accountId: systemAccount.id,
});
return address;
}
```
### 3.2 用户账户按需生成
用户钱包地址在以下场景按需生成:
- 首次认种时(需要从钱包扣款)
- 首次充值时(需要收款地址)
- 查询收款地址时
---
## 四、认种完整流程
### 4.1 流程图
```
用户发起认种请求
验证用户钱包余额 ≥ 2199 USDT × 数量
创建认种订单PENDING
计算分配方案(查询省市授权状态)
执行链上转账(多笔转账)
├── 400 → 成本账户
├── 300 → 运营账户
├── 9 → 总部社区账户
├── 800 → RWAD矿池账户
├── 500 → 直接推荐人(作为待领取奖励)
├── 15+1%算力 → 省区域权益接收方
├── 20 → 省团队权益接收方
├── 35+2%算力 → 市区域权益接收方
├── 40 → 市团队权益接收方
└── 80 → 社区权益接收方
更新订单状态COMPLETED
更新团队统计referral-service
更新授权考核进度authorization-service
30天后启动挖矿矿池注入
```
### 4.2 分配目标确定逻辑
```typescript
interface AllocationTarget {
targetType: string;
targetUserId?: bigint; // 用户账户
targetSystemAccountId?: bigint; // 系统账户
amount: Decimal;
hashpowerPercent?: Decimal;
}
async function calculateAllocation(
planterId: bigint,
treeCount: number,
provinceCode: string,
cityCode: string,
): Promise<AllocationTarget[]> {
const unitPrice = new Decimal(2199);
const totalAmount = unitPrice.mul(treeCount);
const allocations: AllocationTarget[] = [];
// 1. 固定系统账户分配
allocations.push(
{ targetType: 'COST_ACCOUNT', targetSystemAccountId: costAccountId, amount: new Decimal(400).mul(treeCount) },
{ targetType: 'OPERATION_ACCOUNT', targetSystemAccountId: operationAccountId, amount: new Decimal(300).mul(treeCount) },
{ targetType: 'HQ_COMMUNITY', targetSystemAccountId: hqCommunityAccountId, amount: new Decimal(9).mul(treeCount) },
{ targetType: 'RWAD_POOL', targetSystemAccountId: rwadPoolAccountId, amount: new Decimal(800).mul(treeCount) },
);
// 2. 直接推荐人500 USDT
const referrer = await referralService.getDirectReferrer(planterId);
if (referrer) {
allocations.push({
targetType: 'DIRECT_REFERRER',
targetUserId: referrer.userId,
amount: new Decimal(500).mul(treeCount),
});
} else {
// 无推荐人,归入运营账户
allocations.push({
targetType: 'OPERATION_ACCOUNT',
targetSystemAccountId: operationAccountId,
amount: new Decimal(500).mul(treeCount),
});
}
// 3. 省公司权益15 区域 + 20 团队)
const provinceAuth = await authorizationService.getActiveProvinceAuth(provinceCode);
if (provinceAuth?.roleType === 'PROVINCE_COMPANY' && provinceAuth.benefitActive) {
// 正式省公司 - 区域权益 15U + 1% 算力
allocations.push({
targetType: 'PROVINCE_REGION',
targetUserId: provinceAuth.userId,
amount: new Decimal(15).mul(treeCount),
hashpowerPercent: new Decimal(1),
});
} else {
// 无正式省公司,归入系统省账户
const systemProvince = await getOrCreateSystemAccount('SYSTEM_PROVINCE', provinceCode);
allocations.push({
targetType: 'SYSTEM_PROVINCE',
targetSystemAccountId: systemProvince.id,
amount: new Decimal(15).mul(treeCount),
});
}
// 授权省公司 - 团队权益 20U
if (provinceAuth?.roleType === 'AUTH_PROVINCE_COMPANY' && provinceAuth.benefitActive) {
allocations.push({
targetType: 'PROVINCE_TEAM',
targetUserId: provinceAuth.userId,
amount: new Decimal(20).mul(treeCount),
});
} else {
const systemProvince = await getOrCreateSystemAccount('SYSTEM_PROVINCE', provinceCode);
allocations.push({
targetType: 'SYSTEM_PROVINCE',
targetSystemAccountId: systemProvince.id,
amount: new Decimal(20).mul(treeCount),
});
}
// 4. 市公司权益35 区域 + 40 团队)- 类似省公司逻辑
// ...
// 5. 社区权益80 USDT
const communityAuth = await authorizationService.getCommunityAuth(planterId);
if (communityAuth && communityAuth.benefitActive) {
allocations.push({
targetType: 'COMMUNITY',
targetUserId: communityAuth.userId,
amount: new Decimal(80).mul(treeCount),
});
} else {
allocations.push({
targetType: 'OPERATION_ACCOUNT',
targetSystemAccountId: operationAccountId,
amount: new Decimal(80).mul(treeCount),
});
}
return allocations;
}
```
---
## 五、24小时待领取奖励机制
### 5.1 奖励状态流转
```
PENDING待领取
↓ 用户认种
CLAIMABLE可结算
↓ 用户结算
SETTLED已结算
PENDING待领取
↓ 24小时未认种
EXPIRED已过期
```
### 5.2 reward-service 现有表结构
```prisma
model RewardLedgerEntry {
// 奖励状态: PENDING → CLAIMABLE → SETTLED 或 PENDING → EXPIRED
rewardStatus String @default("PENDING")
expireAt DateTime? // 24小时后过期时间
claimedAt DateTime? // 用户认种时间(领取)
settledAt DateTime? // 结算时间
expiredAt DateTime? // 实际过期时间
}
```
### 5.3 定时任务
```typescript
// 每分钟检查过期奖励
@Cron('* * * * *')
async checkExpiredRewards() {
const expiredRewards = await prisma.rewardLedgerEntry.findMany({
where: {
rewardStatus: 'PENDING',
expireAt: { lt: new Date() },
},
});
for (const reward of expiredRewards) {
await prisma.$transaction([
// 更新奖励状态
prisma.rewardLedgerEntry.update({
where: { id: reward.id },
data: {
rewardStatus: 'EXPIRED',
expiredAt: new Date(),
},
}),
// 更新用户汇总
prisma.rewardSummary.update({
where: { userId: reward.userId },
data: {
pendingUsdt: { decrement: reward.usdtAmount },
expiredTotalUsdt: { increment: reward.usdtAmount },
},
}),
]);
// 将过期金额转入运营账户
await transferToOperationAccount(reward.usdtAmount, reward.id);
}
}
```
---
## 六、授权考核规则
### 6.1 省市公司授权考核
| 角色 | 初始目标 | 月度考核 | 权益 |
|------|----------|----------|------|
| 授权省公司 | 500棵 | 阶梯递增 | 团队权益 20U |
| 正式省公司 | 已达标 | 无 | 区域权益 15U + 1%算力 |
| 授权市公司 | 200棵 | 阶梯递增 | 团队权益 40U |
| 正式市公司 | 已达标 | 无 | 区域权益 35U + 2%算力 |
### 6.2 阶梯考核目标authorization-service 已有)
```prisma
model LadderTargetConfig {
roleType RoleType
monthIndex Int // 第几个月
monthlyTarget Int // 当月目标
cumulativeTarget Int // 累计目标
}
```
### 6.3 社区考核
- 认种 1 棵后获得社区授权
- 每月保持认种 10 棵维持权益
- 连续 2 个月不达标,降级为普通用户
---
## 七、龙虎榜规则
### 7.1 排名计算referral-service 已有)
```prisma
model TeamStatistics {
// 龙虎榜分值 = 团队总认种量 - 最大单个直推团队认种量
maxSingleTeamPlantingCount Int @default(0)
effectivePlantingCountForRanking Int @default(0)
}
```
### 7.2 计算公式
```typescript
function calculateLeaderboardScore(userId: bigint): number {
const stats = await getTeamStatistics(userId);
// 有效分值 = 团队总认种 - 最大单线团队认种
return stats.totalTeamPlantingCount - stats.maxSingleTeamPlantingCount;
}
```
---
## 八、服务职责划分
| 服务 | 职责 |
|------|------|
| **planting-service** | 认种订单管理、分配计算、矿池注入批次 |
| **wallet-service** | 用户钱包余额、链上转账执行 |
| **blockchain-service** | 地址监听、交易广播、MPC 交互 |
| **reward-service** | 奖励流水、24h过期处理、结算 |
| **referral-service** | 推荐关系、团队统计、龙虎榜 |
| **authorization-service** | 省市社区授权、考核进度、**系统账户管理** |
| **identity-service** | 用户身份、MPC 钱包创建 |
---
## 九、待实现功能清单
### 9.1 authorization-service 扩展
- [ ] 添加 `SystemAccount`
- [ ] 添加 `SystemAccountLedger`
- [ ] 实现系统账户 CRUD API
- [ ] 实现按需生成 MPC 地址逻辑
### 9.2 planting-service 扩展
- [ ] 实现完整分配计算逻辑
- [ ] 集成 wallet-service 执行链上转账
- [ ] 集成 authorization-service 查询授权状态
- [ ] 集成 referral-service 查询推荐人
### 9.3 reward-service 扩展
- [ ] 实现 24 小时过期定时任务
- [ ] 实现用户认种触发奖励领取
- [ ] 实现过期奖励转入运营账户
### 9.4 wallet-service 扩展
- [ ] 实现批量链上转账 API
- [ ] 支持系统账户转账
### 9.5 blockchain-service 扩展
- [ ] 支持系统账户地址监听
- [ ] 实现 MPC 签名批量交易
---
## 十、数据流示意
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 认种数据流 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户钱包 (wallet-service) │
│ │ │
│ │ 2199 USDT × N │
│ ▼ │
│ planting-service │
│ │ │
│ ├─── 400 ──→ 成本账户 (authorization-service.SystemAccount) │
│ ├─── 300 ──→ 运营账户 (authorization-service.SystemAccount) │
│ ├─── 9 ──→ 总部社区 (authorization-service.SystemAccount) │
│ ├─── 800 ──→ RWAD矿池 (authorization-service.SystemAccount) │
│ ├─── 500 ──→ 直推人钱包 (wallet-service) → reward-service (待领取) │
│ ├─── 15 ──→ 省区域 (用户钱包 或 系统省账户) │
│ ├─── 20 ──→ 省团队 (用户钱包 或 系统省账户) │
│ ├─── 35 ──→ 市区域 (用户钱包 或 系统市账户) │
│ ├─── 40 ──→ 市团队 (用户钱包 或 系统市账户) │
│ └─── 80 ──→ 社区 (用户钱包 或 运营账户) │
│ │
│ 所有转账通过 blockchain-service 执行链上交易 │
│ 所有地址通过 MPC 按需生成 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 附录:关键配置
### A. 系统账户初始化
```sql
-- 初始化固定系统账户(地址按需生成)
INSERT INTO system_accounts (account_type, region_code, status) VALUES
('COST_ACCOUNT', NULL, 'ACTIVE'),
('OPERATION_ACCOUNT', NULL, 'ACTIVE'),
('HQ_COMMUNITY', NULL, 'ACTIVE'),
('RWAD_POOL_PENDING', NULL, 'ACTIVE');
```
### B. 环境变量
```env
# MPC 服务配置
MPC_SERVICE_URL=http://mpc-service:3010
# 认种相关
PLANTING_UNIT_PRICE=2199
REWARD_EXPIRE_HOURS=24
MINING_START_DELAY_DAYS=30
```
---
*文档版本: v1.0*
*创建日期: 2025-12-08*
*最后更新: 2025-12-08*