# 2.0 贡献值计算与钱包存储方案 ## 一、系统架构总览 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 1.0 系统 (数据源) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ auth-service │ │ planting-svc │ │ referral-svc │ │ │ │ (用户注册) │ │ (认种订单) │ │ (推荐关系) │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ └─────────┼──────────────────┼──────────────────┼─────────────────────────────┘ │ │ │ │ Kafka CDC │ Kafka CDC │ Kafka CDC ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 2.0 系统 │ │ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ contribution-service │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ CDC Consumer │ │ 贡献值计算引擎 │ │ Outbox 发布器 │ │ │ │ │ │ (同步数据) │→ │ (分配逻辑) │→ │ (Kafka) │ │ │ │ │ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ │ │ └──────────────────────────────────────────────────────┼─────────────────┘ │ │ │ │ │ Kafka: contribution.distribution.completed │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ mining-wallet-service │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ Kafka Consumer │ │ 钱包账户管理 │ │ 分类账记录 │ │ │ │ │ │ (接收分配结果) │→ │ (存储贡献值) │→ │ (交易明细) │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ mining-admin-service │ │ │ │ 订阅 contribution-service 和 mining-wallet-service 的事件进行数据同步 │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ ``` --- ## 二、贡献值分配规则 ### 2.1 分配比例 | 类型 | 比例 | 说明 | |------|------|------| | 个人贡献 | 70% | 认种人自己获得 | | 运营账户 | 12% | 系统运营账户(永不过期) | | 省级公司 | 1% | 认种所在省份公司 | | 市级公司 | 2% | 认种所在城市公司 | | 团队层级 | 7.5% | 上线1-15级,每级0.5% | | 团队奖励 | 7.5% | 直接上线的3档奖励,每档2.5% | ### 2.2 解锁条件 #### 层级解锁(每级0.5%,共15级) | 档位 | 层级 | 解锁条件 | |------|------|----------| | 第1档 | L1-L5 | 直推≥1人认种 | | 第2档 | L6-L10 | 直推≥3人认种 | | 第3档 | L11-L15 | 直推≥5人认种 | #### 奖励解锁(每档2.5%,共3档) | 档位 | 解锁条件 | |------|----------| | 第1档 | 自己认种 | | 第2档 | 直推≥2人认种 | | 第3档 | 直推≥4人认种 | ### 2.3 有效期规则 - **用户贡献值**:2年有效期(从认种次日开始计算) - **运营账户**:永不过期 - **未分配贡献值**:归总部账户(永不过期) --- ## 三、Kafka 事件设计 ### 3.1 用户注册事件 **Topic**: `auth.user.registered` ```typescript interface UserRegisteredEvent { eventType: 'UserRegistered'; eventId: string; timestamp: string; payload: { accountSequence: string; phone: string; referrerAccountSequence: string | null; registeredAt: string; source: 'LEGACY_MIGRATION' | 'NEW_REGISTRATION'; }; } ``` **消费者**: - `contribution-service` - 创建 ContributionAccount - `mining-wallet-service` - 创建用户钱包(CONTRIBUTION 类型) ### 3.2 认种完成事件 **Topic**: `planting.adoption.completed` ```typescript interface AdoptionCompletedEvent { eventType: 'AdoptionCompleted'; eventId: string; timestamp: string; payload: { adoptionId: string; accountSequence: string; treeCount: number; contributionPerTree: string; adoptionDate: string; provinceCode: string; cityCode: string; }; } ``` **消费者**: - `contribution-service` - 触发贡献值计算 ### 3.3 贡献值分配完成事件 **Topic**: `contribution.distribution.completed` ```typescript interface ContributionDistributionCompletedEvent { eventType: 'ContributionDistributionCompleted'; eventId: string; timestamp: string; payload: { // 认种信息 adoptionId: string; adopterAccountSequence: string; treeCount: number; adoptionDate: string; // 用户贡献值分配 userContributions: { accountSequence: string; contributionType: 'PERSONAL' | 'TEAM_LEVEL' | 'TEAM_BONUS'; amount: string; levelDepth?: number; // 1-15 for TEAM_LEVEL bonusTier?: number; // 1-3 for TEAM_BONUS effectiveDate: string; expireDate: string; sourceAdoptionId: string; sourceAccountSequence: string; }[]; // 系统账户分配 systemContributions: { accountType: 'OPERATION' | 'PROVINCE' | 'CITY' | 'HEADQUARTERS'; amount: string; provinceCode?: string; cityCode?: string; neverExpires: boolean; }[]; // 未分配(归总部) unallocatedToHeadquarters: { reason: string; amount: string; wouldBeAccountSequence?: string; levelDepth?: number; bonusTier?: number; }[]; }; } ``` **消费者**: - `mining-wallet-service` - 存储贡献值到钱包 ### 3.4 贡献值入账事件 **Topic**: `mining-wallet.contribution.credited` ```typescript interface ContributionCreditedEvent { eventType: 'ContributionCredited'; eventId: string; timestamp: string; payload: { accountSequence: string; walletType: 'CONTRIBUTION'; amount: string; balanceAfter: string; transactionId: string; sourceType: 'ADOPTION_DISTRIBUTION'; referenceId: string; }; } ``` **消费者**: - `mining-admin-service` - 同步数据用于展示 --- ## 四、Outbox 模式 ### 4.1 Outbox 表结构 ```prisma model OutboxEvent { id BigInt @id @default(autoincrement()) @map("outbox_id") eventType String @map("event_type") @db.VarChar(100) topic String @map("topic") @db.VarChar(100) key String @map("key") @db.VarChar(200) payload Json @map("payload") aggregateId String @map("aggregate_id") @db.VarChar(100) aggregateType String @map("aggregate_type") @db.VarChar(50) status String @default("PENDING") @map("status") @db.VarChar(20) retryCount Int @default(0) @map("retry_count") maxRetries Int @default(10) @map("max_retries") lastError String? @map("last_error") @db.Text createdAt DateTime @default(now()) @map("created_at") publishedAt DateTime? @map("published_at") nextRetryAt DateTime? @map("next_retry_at") @@index([status, createdAt]) @@index([status, nextRetryAt]) @@map("outbox_events") } ``` ### 4.2 退避策略(最大4小时) | 重试次数 | 等待时间 | 累计时间 | |---------|---------|---------| | 1 | 30秒 | 30秒 | | 2 | 1分钟 | 1.5分钟 | | 3 | 2分钟 | 3.5分钟 | | 4 | 5分钟 | 8.5分钟 | | 5 | 10分钟 | 18.5分钟 | | 6 | 30分钟 | 48.5分钟 | | 7 | 1小时 | 1小时48分 | | 8 | 2小时 | 3小时48分 | | 9 | 4小时 | 7小时48分 | | 10 | 4小时(max) | 11小时48分 | ```typescript const BACKOFF_INTERVALS = [ 30_000, // 30 seconds 60_000, // 1 minute 120_000, // 2 minutes 300_000, // 5 minutes 600_000, // 10 minutes 1_800_000, // 30 minutes 3_600_000, // 1 hour 7_200_000, // 2 hours 14_400_000, // 4 hours (max) 14_400_000, // 4 hours (max) ]; ``` ### 4.3 幂等性保证(4小时去重窗口) ```prisma model ProcessedEvent { id String @id @default(uuid()) eventId String @unique @map("event_id") eventType String @map("event_type") sourceService String @map("source_service") processedAt DateTime @default(now()) @map("processed_at") @@index([sourceService]) @@index([processedAt]) @@map("processed_events") } ``` - **Redis 缓存**:4小时 TTL,快速路径检查 - **DB 持久化**:ProcessedEvent 表,24小时后清理 - **双重检查**:先查 Redis,未命中再查 DB --- ## 五、服务职责划分 | 服务 | 职责 | 数据存储 | |------|------|----------| | **auth-service** | 用户注册/迁移,发送 UserRegistered 事件 | 用户基础信息 | | **planting-service** | 认种订单,发送 AdoptionCompleted 事件 | 认种订单 | | **contribution-service** | 贡献值计算逻辑,解锁状态管理 | 计算明细、解锁事件(用于审计) | | **mining-wallet-service** | 贡献值存储,余额管理,过期处理 | 钱包余额、交易明细(分类账) | | **mining-admin-service** | 数据聚合展示 | 同步缓存 | --- ## 六、数据模型 ### 6.1 contribution-service(已实现) - `ContributionAccount` - 用户贡献值账户(汇总) - `ContributionRecord` - 贡献值明细(审计) - `UnlockEvent` - 解锁事件记录 - `UnallocatedContribution` - 未分配贡献值 - `SystemAccount` - 系统账户(运营/省/市/总部) ### 6.2 mining-wallet-service(需扩展) 现有模型: - `UserWallet` - 用户钱包(CONTRIBUTION 类型) - `UserWalletTransaction` - 交易明细(分类账) - `SystemAccount` - 系统账户 需要添加: - SystemAccount 添加 `contributionBalance` 字段 - TransactionType 添加 `CONTRIBUTION_CREDIT`、`CONTRIBUTION_EXPIRE` 枚举值 --- ## 七、实施步骤 ### Phase 1: mining-wallet-service 扩展 1. 修改 schema 添加 SystemAccount 贡献值字段 2. 实现 ContributionWalletService 3. 实现 ContributionDistributionConsumer 4. 实现 UserRegisteredConsumer(创建用户钱包) 5. 实现 ContributionExpiryScheduler 6. 实现 Outbox Scheduler(4小时退避) ### Phase 2: contribution-service 扩展 1. 实现 ContributionDistributionPublisherService 2. 修改 ContributionCalculationService 调用发布器 3. 测试完整的分配流程 ### Phase 3: auth-service 集成 1. 确保 UserRegistered 事件正确发送 2. 包含 referrerAccountSequence 信息 ### Phase 4: 历史数据迁移 1. 批量处理1.0的历史认种数据 2. 逐笔计算并发送分配事件 3. 验证钱包余额正确性 --- ## 八、关键流程 ### 8.1 认种触发贡献值分配 ``` 1. planting-service 发送 AdoptionCompleted 事件 ↓ 2. contribution-service 消费事件 ├─ 查询认种人的上线链条(最多15级) ├─ 查询各上线的解锁状态 ├─ 计算贡献值分配 └─ 写入 Outbox 表 ↓ 3. Outbox Scheduler 发送到 Kafka ↓ 4. mining-wallet-service 消费 ContributionDistributionCompleted ├─ 幂等性检查 ├─ 更新用户钱包余额 ├─ 更新系统账户余额 └─ 记录交易明细 ↓ 5. mining-admin-service 消费 ContributionCredited └─ 同步缓存数据 ``` ### 8.2 贡献值过期处理 ``` 1. 每日凌晨1点定时任务启动 ↓ 2. 查询 expireDate <= today 的交易记录 ↓ 3. 逐笔处理过期 ├─ 扣减钱包余额 ├─ 创建过期交易记录 └─ 标记原交易为已过期 ``` --- ## 九、监控与告警 ### 9.1 关键指标 - Outbox 积压数量 - 事件处理延迟 - 重试次数分布 - 失败事件数量 ### 9.2 告警规则 - Outbox 积压 > 1000 条 - 事件处理延迟 > 5 分钟 - 失败事件数量 > 10 条/小时