424 lines
16 KiB
Plaintext
424 lines
16 KiB
Plaintext
generator client {
|
||
provider = "prisma-client-js"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// ==================== 交易配置 ====================
|
||
|
||
// 交易全局配置
|
||
model TradingConfig {
|
||
id String @id @default(uuid())
|
||
// 总积分股数量: 100.02B
|
||
totalShares Decimal @default(100020000000) @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")
|
||
// 启动时间
|
||
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")
|
||
}
|