generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ==================== 挖矿配置 ==================== // 挖矿全局配置 model MiningConfig { id String @id @default(uuid()) totalShares Decimal @db.Decimal(30, 8) // 总积分股数量 (100.02B) distributionPool Decimal @db.Decimal(30, 8) // 分配池 (200M) remainingDistribution Decimal @db.Decimal(30, 8) // 剩余可分配 halvingPeriodYears Int @default(2) // 减半周期(年) currentEra Int @default(1) // 当前纪元 eraStartDate DateTime // 当前纪元开始日期 minuteDistribution Decimal @db.Decimal(30, 18) // 每分钟分配量 isActive Boolean @default(false) // 是否已激活挖矿 activatedAt DateTime? // 激活时间 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("mining_configs") } // 减半纪元记录 model MiningEra { id String @id @default(uuid()) eraNumber Int @unique startDate DateTime endDate DateTime? initialDistribution Decimal @db.Decimal(30, 8) // 纪元初始可分配量 totalDistributed Decimal @default(0) @db.Decimal(30, 8) // 已分配量 minuteDistribution Decimal @db.Decimal(30, 18) // 每分钟分配量 isActive Boolean @default(true) createdAt DateTime @default(now()) @@map("mining_eras") } // ==================== 用户挖矿账户 ==================== // 用户挖矿账户 model MiningAccount { id String @id @default(uuid()) accountSequence String @unique totalMined Decimal @default(0) @db.Decimal(30, 8) // 总挖到的积分股 availableBalance Decimal @default(0) @db.Decimal(30, 8) // 可用余额 frozenBalance Decimal @default(0) @db.Decimal(30, 8) // 冻结余额 totalContribution Decimal @default(0) @db.Decimal(30, 8) // 当前算力(从 contribution-service 同步) lastSyncedAt DateTime? // 最后同步算力时间 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt records MiningRecord[] transactions MiningTransaction[] @@index([totalContribution(sort: Desc)]) @@map("mining_accounts") } // 挖矿记录(分钟级别) model MiningRecord { id String @id @default(uuid()) accountSequence String miningMinute DateTime // 挖矿分钟(精确到分钟) contributionRatio Decimal @db.Decimal(30, 18) // 当时的算力占比 totalContribution Decimal @db.Decimal(30, 8) // 当时的总算力 minuteDistribution Decimal @db.Decimal(30, 18) // 当分钟总分配量 minedAmount Decimal @db.Decimal(30, 18) // 挖到的数量 createdAt DateTime @default(now()) account MiningAccount @relation(fields: [accountSequence], references: [accountSequence]) @@unique([accountSequence, miningMinute]) @@index([miningMinute]) @@map("mining_records") } // 挖矿交易流水 model MiningTransaction { id String @id @default(uuid()) accountSequence String type String // MINE, FREEZE, UNFREEZE, TRANSFER_OUT, TRANSFER_IN, BURN amount Decimal @db.Decimal(30, 8) balanceBefore Decimal @db.Decimal(30, 8) balanceAfter Decimal @db.Decimal(30, 8) referenceId String? // 关联ID(如交易ID、划转ID) referenceType String? // 关联类型 // 交易对手方信息 counterpartyType String? @map("counterparty_type") // USER, POOL, SYSTEM counterpartyAccountSeq String? @map("counterparty_account_seq") // 对手方账户序列号 counterpartyUserId String? @map("counterparty_user_id") // 对手方用户ID // 详细备注(包含完整交易信息,格式: "划转到用户[U123456]") memo String? @db.Text description String? // 保留兼容旧字段 createdAt DateTime @default(now()) account MiningAccount @relation(fields: [accountSequence], references: [accountSequence]) @@index([accountSequence, createdAt(sort: Desc)]) @@index([type]) @@index([counterpartyAccountSeq]) @@index([counterpartyUserId]) @@map("mining_transactions") } // ==================== 挖矿收益分配明细 ==================== // 特别关注:待解锁算力产生的收益分配到总部的情况 // 每日挖矿收益分配明细 // 记录每天挖矿时,算力产生的收益分配给谁 model MiningRewardAllocation { id BigInt @id @default(autoincrement()) // ========== 挖矿日期 ========== miningDate DateTime @map("mining_date") @db.Date // ========== 算力来源(可追溯到认种)========== contributionRecordId BigInt @map("contribution_record_id") // 关联 contribution-service 的算力明细记录ID sourceAdoptionId BigInt @map("source_adoption_id") // 来源认种ID sourceAccountSequence String @map("source_account_sequence") @db.VarChar(20) // 认种人账号 // ========== 算力归属账户 ========== ownerAccountSequence String @map("owner_account_sequence") @db.VarChar(20) // 算力归属账户(收到分成的上级) // ========== 算力类型 ========== contributionType String @map("contribution_type") @db.VarChar(30) // PERSONAL / LEVEL_1~15 / BONUS_TIER_1~3 // ========== 算力金额与挖矿收益 ========== contributionAmount Decimal @map("contribution_amount") @db.Decimal(30, 10) // 参与挖矿的算力 networkTotalContribution Decimal @map("network_total_contribution") @db.Decimal(30, 10) // 当日全网算力 contributionRatio Decimal @map("contribution_ratio") @db.Decimal(30, 18) // 算力占比 dailyMiningPool Decimal @map("daily_mining_pool") @db.Decimal(30, 10) // 当日挖矿池总量 rewardAmount Decimal @map("reward_amount") @db.Decimal(30, 10) // 应得挖矿收益 // ========== 分配状态(核心:是否因未解锁而归总部)========== allocationStatus String @map("allocation_status") @db.VarChar(20) // TO_USER / TO_HEADQUARTERS isUnlocked Boolean @map("is_unlocked") // 算力是否已解锁 // ========== 实际分配去向 ========== allocatedToAccountSequence String? @map("allocated_to_account_sequence") @db.VarChar(20) // 实际分配给的账户 allocatedToSystemAccount String? @map("allocated_to_system_account") @db.VarChar(20) // 或分配给系统账户(HEADQUARTERS) // ========== 未解锁原因说明 ========== unlockedReason String? @map("unlocked_reason") @db.VarChar(200) // 如果归总部,记录原因 // ========== 资质条件快照(便于追溯)========== ownerHasAdopted Boolean @map("owner_has_adopted") // 归属账户当时是否已认种 ownerDirectReferralCount Int @map("owner_direct_referral_count") // 归属账户当时直推认种人数 ownerUnlockedLevelDepth Int @map("owner_unlocked_level_depth") // 归属账户当时解锁层级深度 ownerUnlockedBonusTiers Int @map("owner_unlocked_bonus_tiers") // 归属账户当时解锁加成档位 // ========== 备注 ========== remark String? @map("remark") @db.VarChar(500) createdAt DateTime @default(now()) @map("created_at") @@index([miningDate]) @@index([ownerAccountSequence, miningDate]) @@index([sourceAccountSequence]) @@index([sourceAdoptionId]) @@index([allocationStatus]) @@index([contributionRecordId]) @@map("mining_reward_allocations") } // 每日挖矿汇总(按账户) // 汇总每个账户每天的挖矿收益 model DailyMiningRewardSummary { id BigInt @id @default(autoincrement()) miningDate DateTime @map("mining_date") @db.Date accountSequence String @map("account_sequence") @db.VarChar(20) // ========== 收益汇总 ========== // 来自已解锁算力的收益(归用户) unlockedReward Decimal @default(0) @map("unlocked_reward") @db.Decimal(30, 10) // 来自待解锁算力的收益(本应归用户,但因未解锁归了总部) pendingRewardToHq Decimal @default(0) @map("pending_reward_to_hq") @db.Decimal(30, 10) // ========== 明细统计 ========== // 已解锁的各类算力收益 personalReward Decimal @default(0) @map("personal_reward") @db.Decimal(30, 10) // 个人算力收益 levelReward Decimal @default(0) @map("level_reward") @db.Decimal(30, 10) // 层级算力收益(已解锁部分) bonusReward Decimal @default(0) @map("bonus_reward") @db.Decimal(30, 10) // 加成算力收益(已解锁部分) // 待解锁转总部的明细 pendingLevelToHq Decimal @default(0) @map("pending_level_to_hq") @db.Decimal(30, 10) // 待解锁层级收益归总部 pendingBonusToHq Decimal @default(0) @map("pending_bonus_to_hq") @db.Decimal(30, 10) // 待解锁加成收益归总部 createdAt DateTime @default(now()) @map("created_at") @@unique([miningDate, accountSequence]) @@index([miningDate]) @@index([accountSequence]) @@map("daily_mining_reward_summaries") } // 总部待解锁收益明细账 // 记录总部收到的来自各用户待解锁算力的收益 model HeadquartersPendingReward { id BigInt @id @default(autoincrement()) miningDate DateTime @map("mining_date") @db.Date // ========== 应归属账户(如果解锁了会归他)========== wouldBeAccountSequence String @map("would_be_account_sequence") @db.VarChar(20) // ========== 算力来源 ========== sourceAdoptionId BigInt @map("source_adoption_id") sourceAccountSequence String @map("source_account_sequence") @db.VarChar(20) contributionRecordId BigInt @map("contribution_record_id") // ========== 算力类型与金额 ========== contributionType String @map("contribution_type") @db.VarChar(30) // LEVEL_1~15 / BONUS_TIER_1~3 contributionAmount Decimal @map("contribution_amount") @db.Decimal(30, 10) rewardAmount Decimal @map("reward_amount") @db.Decimal(30, 10) // ========== 未解锁原因 ========== reason String @map("reason") @db.VarChar(200) // 如 "账户未认种,层级1-5未解锁" / "直推认种人数不足3人,层级6-10未解锁" // ========== 资质条件快照 ========== ownerHasAdopted Boolean @map("owner_has_adopted") ownerDirectReferralCount Int @map("owner_direct_referral_count") requiredCondition String @map("required_condition") @db.VarChar(100) // 需要满足的条件 createdAt DateTime @default(now()) @map("created_at") @@index([miningDate]) @@index([wouldBeAccountSequence]) @@index([sourceAdoptionId]) @@map("headquarters_pending_rewards") } // ==================== 挖矿统计 ==================== // 每分钟挖矿统计 model MinuteMiningStat { id String @id @default(uuid()) minute DateTime @unique totalContribution Decimal @db.Decimal(30, 8) // 参与挖矿的总算力 totalDistributed Decimal @db.Decimal(30, 18) // 该分钟分配的总量 participantCount Int // 参与者数量 burnAmount Decimal @default(0) @db.Decimal(30, 8) // 该分钟销毁量 createdAt DateTime @default(now()) @@index([minute(sort: Desc)]) @@map("minute_mining_stats") } // 每日挖矿统计 model DailyMiningStat { id String @id @default(uuid()) date DateTime @unique @db.Date totalContribution Decimal @db.Decimal(30, 8) totalDistributed Decimal @db.Decimal(30, 8) totalBurned Decimal @db.Decimal(30, 8) participantCount Int avgContributionRate Decimal @db.Decimal(10, 8) // 平均算力利用率 createdAt DateTime @default(now()) @@map("daily_mining_stats") } // ==================== 销毁机制 ==================== // 黑洞账户 model BlackHole { id String @id @default(uuid()) totalBurned Decimal @default(0) @db.Decimal(30, 8) // 已销毁总量 targetBurn Decimal @db.Decimal(30, 8) // 目标销毁量 (10B) remainingBurn Decimal @db.Decimal(30, 8) // 剩余待销毁 lastBurnMinute DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt records BurnRecord[] @@map("black_holes") } // 销毁记录 model BurnRecord { id String @id @default(uuid()) blackHoleId String burnMinute DateTime burnAmount Decimal @db.Decimal(30, 18) remainingTarget Decimal @db.Decimal(30, 8) // 销毁后剩余目标 // 来源信息(从哪个池/用户销毁) sourceType String? @map("source_type") // CIRCULATION_POOL, USER, SYSTEM sourceAccountSeq String? @map("source_account_seq") // 来源账户序列号 sourceUserId String? @map("source_user_id") // 来源用户ID // 详细备注 memo String? @db.Text createdAt DateTime @default(now()) blackHole BlackHole @relation(fields: [blackHoleId], references: [id]) @@unique([blackHoleId, burnMinute]) @@index([burnMinute]) @@index([sourceAccountSeq]) @@map("burn_records") } // ==================== 价格相关 ==================== // 价格快照(每分钟) model PriceSnapshot { id String @id @default(uuid()) snapshotTime DateTime @unique price Decimal @db.Decimal(30, 18) // 当时价格 sharePool Decimal @db.Decimal(30, 8) // 股池 blackHoleAmount Decimal @db.Decimal(30, 8) // 黑洞数量 circulationPool Decimal @db.Decimal(30, 8) // 流通池 effectiveDenominator Decimal @db.Decimal(30, 8) // 有效分母 createdAt DateTime @default(now()) @@index([snapshotTime(sort: Desc)]) @@map("price_snapshots") } // ==================== 池账户系统 ==================== // 池账户类型枚举 enum PoolAccountType { SHARE_POOL // 积分股池 - 总股池 BLACK_HOLE_POOL // 黑洞积分股池 - 销毁池 CIRCULATION_POOL // 流通积分股池 - 流通池 } // 池账户交易类型枚举 enum PoolTransactionType { // 积分股池操作 MINING_DISTRIBUTE // 挖矿分配(股池 -> 用户) FEE_COLLECT // 手续费收取(用户 -> 股池) INITIAL_INJECT // 初始注入 // 黑洞池操作 BURN // 销毁(流通池 -> 黑洞) // 流通池操作 USER_TRANSFER_IN // 用户划入(用户 -> 流通池) USER_TRANSFER_OUT // 用户划出(流通池 -> 用户) TRADE_BUY // 交易买入 TRADE_SELL // 交易卖出 // 通用操作 POOL_TRANSFER // 池间划转 ADJUSTMENT // 系统调整 } // 池账户(管理三大池:积分股池、黑洞积分股池、流通积分股池) model PoolAccount { id String @id @default(uuid()) poolType PoolAccountType @unique @map("pool_type") // 池类型 name String // 池名称 balance Decimal @default(0) @db.Decimal(30, 8) // 当前余额 totalInflow Decimal @default(0) @db.Decimal(30, 8) // 累计流入 totalOutflow Decimal @default(0) @db.Decimal(30, 8) // 累计流出 isActive Boolean @default(true) @map("is_active") description String? createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") transactions PoolTransaction[] @@index([poolType]) @@map("pool_accounts") } // 池账户交易明细(包含交易对手方信息) model PoolTransaction { id String @id @default(uuid()) poolAccountId String @map("pool_account_id") poolType PoolAccountType @map("pool_type") transactionType PoolTransactionType @map("transaction_type") // 金额信息 amount Decimal @db.Decimal(30, 8) balanceBefore Decimal @map("balance_before") @db.Decimal(30, 8) balanceAfter Decimal @map("balance_after") @db.Decimal(30, 8) // 交易对手方信息(关键:用户ID和账户序列号) counterpartyType String? @map("counterparty_type") // USER, POOL, SYSTEM, EXTERNAL counterpartyAccountSeq String? @map("counterparty_account_seq") // 对手方账户序列号 counterpartyUserId String? @map("counterparty_user_id") // 对手方用户ID counterpartyPoolType PoolAccountType? @map("counterparty_pool_type") // 如果对手方是池账户 // 关联信息 referenceId String? @map("reference_id") // 关联业务ID(如订单ID、划转ID) referenceType String? @map("reference_type") // 关联类型 txHash String? @map("tx_hash") // 链上交易哈希(如有) // 详细备注(包含完整交易信息) // 格式示例: "挖矿分配给用户[U123456], 算力占比0.5%, 分钟2024-01-10 10:30" memo String? @db.Text // 扩展数据(JSON格式存储更多业务细节) metadata Json? createdAt DateTime @default(now()) @map("created_at") poolAccount PoolAccount @relation(fields: [poolAccountId], references: [id]) @@index([poolAccountId, createdAt(sort: Desc)]) @@index([poolType, transactionType]) @@index([counterpartyAccountSeq]) @@index([counterpartyUserId]) @@index([referenceId]) @@index([createdAt(sort: Desc)]) @@map("pool_transactions") } // ==================== Outbox ==================== enum OutboxStatus { PENDING PUBLISHED FAILED } model OutboxEvent { id String @id @default(uuid()) aggregateType String @map("aggregate_type") aggregateId String @map("aggregate_id") eventType String @map("event_type") payload Json topic String @default("mining.events") key String? status OutboxStatus @default(PENDING) retryCount Int @default(0) @map("retry_count") maxRetries Int @default(5) @map("max_retries") lastError String? @map("last_error") publishedAt DateTime? @map("published_at") nextRetryAt DateTime? @map("next_retry_at") createdAt DateTime @default(now()) @map("created_at") @@index([status]) @@index([nextRetryAt]) @@index([createdAt]) @@map("outbox_events") }