rwadurian/backend/services/trading-service/prisma/schema.prisma

424 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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")
}