453 lines
18 KiB
Plaintext
453 lines
18 KiB
Plaintext
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 // 当前纪元开始日期
|
||
secondDistribution 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) // 已分配量
|
||
secondDistribution 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) // 当时的总算力
|
||
secondDistribution 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")
|
||
}
|