generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ==================== 交易配置 ==================== // 交易全局配置 model TradingConfig { id String @id @default(uuid()) // 总积分股数量: 100.02亿 (100亿 + 200万 = 10002000000) totalShares Decimal @default(10002000000) @map("total_shares") @db.Decimal(30, 8) // 目标销毁量: 100亿 (4年销毁完) burnTarget Decimal @default(10000000000) @map("burn_target") @db.Decimal(30, 8) // 销毁周期: 4年 (分钟数) 365*4*1440 = 2102400 burnPeriodMinutes Int @default(2102400) @map("burn_period_minutes") // 每分钟基础销毁量: 100亿÷(365*4*1440) = 4756.468797564687 minuteBurnRate Decimal @default(4756.468797564687) @map("minute_burn_rate") @db.Decimal(30, 18) // 是否启用交易 isActive Boolean @default(false) @map("is_active") // 是否启用买入功能(默认关闭) buyEnabled Boolean @default(false) @map("buy_enabled") // 启动时间 activatedAt DateTime? @map("activated_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("trading_configs") } // ==================== 黑洞账户(销毁池)==================== // 黑洞账户 model BlackHole { id String @id @default(uuid()) totalBurned Decimal @default(0) @map("total_burned") @db.Decimal(30, 8) // 已销毁总量 targetBurn Decimal @map("target_burn") @db.Decimal(30, 8) // 目标销毁量 (10B) remainingBurn Decimal @map("remaining_burn") @db.Decimal(30, 8) // 剩余待销毁 lastBurnMinute DateTime? @map("last_burn_minute") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") records BurnRecord[] @@map("black_holes") } // 销毁记录 model BurnRecord { id String @id @default(uuid()) blackHoleId String @map("black_hole_id") burnMinute DateTime @map("burn_minute") burnAmount Decimal @map("burn_amount") @db.Decimal(30, 18) remainingTarget Decimal @map("remaining_target") @db.Decimal(30, 8) // 销毁后剩余目标 // 来源信息 sourceType String? @map("source_type") // MINUTE_BURN (每分钟销毁), SELL_BURN (卖出销毁) sourceAccountSeq String? @map("source_account_seq") // 来源账户序列号(卖出时) sourceOrderNo String? @map("source_order_no") // 来源订单号(卖出时) memo String? @db.Text createdAt DateTime @default(now()) @map("created_at") blackHole BlackHole @relation(fields: [blackHoleId], references: [id]) @@index([burnMinute]) @@index([sourceAccountSeq]) @@index([sourceOrderNo]) @@index([sourceType]) @@map("burn_records") } // ==================== 积分股池(绿积分池)==================== // 积分股池(存储绿积分用于计算价格) model SharePool { id String @id @default(uuid()) // 绿积分总量(用于价格计算的分子) greenPoints Decimal @default(0) @map("green_points") @db.Decimal(30, 8) totalInflow Decimal @default(0) @map("total_inflow") @db.Decimal(30, 8) totalOutflow Decimal @default(0) @map("total_outflow") @db.Decimal(30, 8) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") transactions SharePoolTransaction[] @@map("share_pools") } // 积分股池交易记录 model SharePoolTransaction { id String @id @default(uuid()) poolId String @map("pool_id") type String // INJECT (注入), TRADE_IN (交易流入), TRADE_OUT (交易流出) amount Decimal @db.Decimal(30, 8) balanceBefore Decimal @map("balance_before") @db.Decimal(30, 8) balanceAfter Decimal @map("balance_after") @db.Decimal(30, 8) referenceId String? @map("reference_id") referenceType String? @map("reference_type") memo String? @db.Text createdAt DateTime @default(now()) @map("created_at") pool SharePool @relation(fields: [poolId], references: [id]) @@index([poolId, createdAt(sort: Desc)]) @@map("share_pool_transactions") } // ==================== 价格快照 ==================== // 价格快照(每分钟) model PriceSnapshot { id String @id @default(uuid()) snapshotTime DateTime @unique @map("snapshot_time") price Decimal @db.Decimal(30, 18) // 当时价格 greenPoints Decimal @map("green_points") @db.Decimal(30, 8) // 绿积分(股池) blackHoleAmount Decimal @map("black_hole_amount") @db.Decimal(30, 8) // 黑洞数量 circulationPool Decimal @map("circulation_pool") @db.Decimal(30, 8) // 流通池 effectiveDenominator Decimal @map("effective_denominator") @db.Decimal(30, 8) // 有效分母 minuteBurnRate Decimal @map("minute_burn_rate") @db.Decimal(30, 18) // 当时的每分钟销毁率 createdAt DateTime @default(now()) @map("created_at") @@index([snapshotTime(sort: Desc)]) @@map("price_snapshots") } // ==================== 交易账户 ==================== // 用户交易账户 model TradingAccount { id String @id @default(uuid()) accountSequence String @unique shareBalance Decimal @default(0) @db.Decimal(30, 8) // 积分股余额 cashBalance Decimal @default(0) @db.Decimal(30, 8) // 现金余额 frozenShares Decimal @default(0) @db.Decimal(30, 8) // 冻结积分股 frozenCash Decimal @default(0) @db.Decimal(30, 8) // 冻结现金 totalBought Decimal @default(0) @db.Decimal(30, 8) // 累计买入量 totalSold Decimal @default(0) @db.Decimal(30, 8) // 累计卖出量 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt orders Order[] transactions TradingTransaction[] @@map("trading_accounts") } // ==================== 订单 ==================== // 交易订单 model Order { id String @id @default(uuid()) orderNo String @unique // 订单号 accountSequence String type String // BUY, SELL status String // PENDING, PARTIAL, FILLED, CANCELLED price Decimal @db.Decimal(30, 18) // 挂单价格 quantity Decimal @db.Decimal(30, 8) // 订单数量 filledQuantity Decimal @default(0) @db.Decimal(30, 8) // 已成交数量 remainingQuantity Decimal @db.Decimal(30, 8) // 剩余数量 averagePrice Decimal @default(0) @db.Decimal(30, 18) // 平均成交价 totalAmount Decimal @default(0) @db.Decimal(30, 8) // 总成交金额 // 卖出销毁相关字段 burnQuantity Decimal @default(0) @map("burn_quantity") @db.Decimal(30, 8) // 卖出销毁量 burnMultiplier Decimal @default(0) @map("burn_multiplier") @db.Decimal(30, 18) // 销毁倍数 effectiveQuantity Decimal @default(0) @map("effective_quantity") @db.Decimal(30, 8) // 有效卖出量(含销毁) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt cancelledAt DateTime? completedAt DateTime? account TradingAccount @relation(fields: [accountSequence], references: [accountSequence]) trades Trade[] @@index([accountSequence, status]) @@index([type, status, price]) @@index([createdAt(sort: Desc)]) @@map("orders") } // 成交记录 model Trade { id String @id @default(uuid()) tradeNo String @unique buyOrderId String @map("buy_order_id") sellOrderId String @map("sell_order_id") buyerSequence String @map("buyer_sequence") sellerSequence String @map("seller_sequence") price Decimal @db.Decimal(30, 18) quantity Decimal @db.Decimal(30, 8) // 实际成交量 burnQuantity Decimal @default(0) @map("burn_quantity") @db.Decimal(30, 8) // 卖出销毁量 effectiveQty Decimal @default(0) @map("effective_qty") @db.Decimal(30, 8) // 有效量(quantity + burnQuantity) amount Decimal @db.Decimal(30, 8) // effectiveQty * price(卖出交易额) createdAt DateTime @default(now()) @map("created_at") buyOrder Order @relation(fields: [buyOrderId], references: [id]) @@index([buyerSequence]) @@index([sellerSequence]) @@index([createdAt(sort: Desc)]) @@map("trades") } // ==================== 交易流水 ==================== model TradingTransaction { id String @id @default(uuid()) accountSequence String type String // TRANSFER_IN, TRANSFER_OUT, BUY, SELL, FREEZE, UNFREEZE, DEPOSIT, WITHDRAW assetType String // SHARE, CASH amount Decimal @db.Decimal(30, 8) balanceBefore Decimal @db.Decimal(30, 8) balanceAfter Decimal @db.Decimal(30, 8) referenceId String? referenceType String? // 交易对手方信息(关键:用户ID和账户序列号) counterpartyType String? @map("counterparty_type") // USER, POOL, SYSTEM counterpartyAccountSeq String? @map("counterparty_account_seq") // 对手方账户序列号 counterpartyUserId String? @map("counterparty_user_id") // 对手方用户ID // 详细备注(包含完整交易信息,格式: "卖出给用户[U123456], 价格0.5USDT") memo String? @db.Text description String? // 保留兼容旧字段 createdAt DateTime @default(now()) account TradingAccount @relation(fields: [accountSequence], references: [accountSequence]) @@index([accountSequence, createdAt(sort: Desc)]) @@index([counterpartyAccountSeq]) @@index([counterpartyUserId]) @@map("trading_transactions") } // ==================== 流通池 ==================== // 流通池(交易所流通池) model CirculationPool { id String @id @default(uuid()) totalShares Decimal @default(0) @db.Decimal(30, 8) // 流通池中的积分股 totalCash Decimal @default(0) @db.Decimal(30, 8) // 流通池中的现金(股池) totalInflow Decimal @default(0) @db.Decimal(30, 8) // 累计流入 totalOutflow Decimal @default(0) @db.Decimal(30, 8) // 累计流出 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt transactions CirculationPoolTransaction[] @@map("circulation_pools") } // 流通池变动记录(包含交易对手方信息) model CirculationPoolTransaction { id String @id @default(uuid()) poolId String @map("pool_id") type String // SHARE_IN, SHARE_OUT, CASH_IN, CASH_OUT, TRADE_BUY, TRADE_SELL assetType String // SHARE, CASH 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 // 关联信息 referenceId String? @map("reference_id") // 关联业务ID(如订单ID、交易ID) referenceType String? @map("reference_type") // 关联类型(ORDER, TRADE, TRANSFER) // 详细备注(包含完整交易信息) // 格式示例: "用户[U123456]买入100股, 订单号ORD20240110001" memo String? @db.Text // 扩展数据 metadata Json? createdAt DateTime @default(now()) @map("created_at") pool CirculationPool @relation(fields: [poolId], references: [id]) @@index([poolId, createdAt(sort: Desc)]) @@index([type, assetType]) @@index([counterpartyAccountSeq]) @@index([counterpartyUserId]) @@index([referenceId]) @@index([createdAt(sort: Desc)]) @@map("circulation_pool_transactions") } // 保留旧的PoolTransaction以兼容(标记为废弃,后续迁移后删除) // @deprecated 使用 CirculationPoolTransaction 替代 model PoolTransaction { id String @id @default(uuid()) type String // SHARE_IN, SHARE_OUT, CASH_IN, CASH_OUT amount Decimal @db.Decimal(30, 8) referenceId String? description String? createdAt DateTime @default(now()) @@index([createdAt(sort: Desc)]) @@map("pool_transactions") } // ==================== K线数据 ==================== // 分钟K线 model MinuteKLine { id String @id @default(uuid()) minute DateTime @unique open Decimal @db.Decimal(30, 18) high Decimal @db.Decimal(30, 18) low Decimal @db.Decimal(30, 18) close Decimal @db.Decimal(30, 18) volume Decimal @db.Decimal(30, 8) // 成交量 amount Decimal @db.Decimal(30, 8) // 成交额 tradeCount Int @default(0) // 成交笔数 createdAt DateTime @default(now()) @@index([minute(sort: Desc)]) @@map("minute_klines") } // 小时K线 model HourKLine { id String @id @default(uuid()) hour DateTime @unique open Decimal @db.Decimal(30, 18) high Decimal @db.Decimal(30, 18) low Decimal @db.Decimal(30, 18) close Decimal @db.Decimal(30, 18) volume Decimal @db.Decimal(30, 8) amount Decimal @db.Decimal(30, 8) tradeCount Int @default(0) createdAt DateTime @default(now()) @@index([hour(sort: Desc)]) @@map("hour_klines") } // 日K线 model DayKLine { id String @id @default(uuid()) date DateTime @unique @db.Date open Decimal @db.Decimal(30, 18) high Decimal @db.Decimal(30, 18) low Decimal @db.Decimal(30, 18) close Decimal @db.Decimal(30, 18) volume Decimal @db.Decimal(30, 8) amount Decimal @db.Decimal(30, 8) tradeCount Int @default(0) createdAt DateTime @default(now()) @@index([date(sort: Desc)]) @@map("day_klines") } // ==================== 划转记录 ==================== // 从挖矿账户划转记录 model TransferRecord { id String @id @default(uuid()) transferNo String @unique accountSequence String direction String // IN (从挖矿账户划入), OUT (划出到挖矿账户) amount Decimal @db.Decimal(30, 8) status String // PENDING, COMPLETED, FAILED miningTxId String? // 挖矿服务的交易ID errorMessage String? createdAt DateTime @default(now()) completedAt DateTime? @@index([accountSequence]) @@index([status]) @@map("transfer_records") } // ==================== 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("trading.events") key String? status OutboxStatus @default(PENDING) retryCount Int @default(0) @map("retry_count") maxRetries Int @default(10) @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") } // ==================== 已处理事件(幂等性)==================== // 已处理事件记录(用于消费者幂等性检查) model ProcessedEvent { id String @id @default(uuid()) eventId String @unique @map("event_id") // 事件唯一ID eventType String @map("event_type") // 事件类型 sourceService String @map("source_service") // 来源服务 processedAt DateTime @default(now()) @map("processed_at") @@index([eventId]) @@index([processedAt]) @@map("processed_events") }