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

222 lines
9.3 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// 奖励流水表 (聚合根1 - 行为表, append-only)
// 记录每一笔奖励的创建、领取、结算、过期
// ============================================
model RewardLedgerEntry {
id BigInt @id @default(autoincrement()) @map("entry_id")
userId BigInt @map("user_id") // 接收奖励的用户ID
accountSequence String @map("account_sequence") @db.VarChar(20) // 账户序列号
// === 奖励来源 ===
sourceOrderNo String @map("source_order_no") @db.VarChar(50) // 来源认种订单号(字符串格式如PLT1765391584505Q0Q6QD)
sourceUserId BigInt @map("source_user_id") // 触发奖励的用户ID(认种者)
rightType String @map("right_type") @db.VarChar(50) // 权益类型
// === 奖励金额 ===
usdtAmount Decimal @map("usdt_amount") @db.Decimal(20, 8)
hashpowerAmount Decimal @default(0) @map("hashpower_amount") @db.Decimal(20, 8)
// === 奖励状态 ===
rewardStatus String @default("PENDING") @map("reward_status") @db.VarChar(20)
// === 时间戳 ===
createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6)
expireAt DateTime? @map("expire_at") // 过期时间(24h后)
claimedAt DateTime? @map("claimed_at") // 领取时间(用户认种)
settledAt DateTime? @map("settled_at") // 结算时间
expiredAt DateTime? @map("expired_at") // 实际过期时间
// === 备注 ===
memo String? @map("memo") @db.VarChar(500)
@@map("reward_ledger_entries")
@@index([userId, rewardStatus], name: "idx_user_status")
@@index([userId, createdAt(sort: Desc)], name: "idx_user_created")
@@index([accountSequence, rewardStatus], name: "idx_account_status")
@@index([accountSequence, createdAt(sort: Desc)], name: "idx_account_created")
@@index([sourceOrderNo], name: "idx_source_order")
@@index([sourceUserId], name: "idx_source_user")
@@index([rightType], name: "idx_right_type")
@@index([rewardStatus], name: "idx_status")
@@index([expireAt], name: "idx_expire")
@@index([createdAt], name: "idx_created")
}
// ============================================
// 奖励汇总表 (聚合根2 - 状态表)
// 每个用户的收益汇总,从流水表聚合
// ============================================
model RewardSummary {
id BigInt @id @default(autoincrement()) @map("summary_id")
userId BigInt @unique @map("user_id")
accountSequence String @unique @map("account_sequence") @db.VarChar(20) // 账户序列号
// === 待领取收益 (24h倒计时) ===
pendingUsdt Decimal @default(0) @map("pending_usdt") @db.Decimal(20, 8)
pendingHashpower Decimal @default(0) @map("pending_hashpower") @db.Decimal(20, 8)
pendingExpireAt DateTime? @map("pending_expire_at") // 最早过期时间
// === 可结算收益 ===
settleableUsdt Decimal @default(0) @map("settleable_usdt") @db.Decimal(20, 8)
settleableHashpower Decimal @default(0) @map("settleable_hashpower") @db.Decimal(20, 8)
// === 已结算收益 (累计) ===
settledTotalUsdt Decimal @default(0) @map("settled_total_usdt") @db.Decimal(20, 8)
settledTotalHashpower Decimal @default(0) @map("settled_total_hashpower") @db.Decimal(20, 8)
// === 已过期收益 (累计) ===
expiredTotalUsdt Decimal @default(0) @map("expired_total_usdt") @db.Decimal(20, 8)
expiredTotalHashpower Decimal @default(0) @map("expired_total_hashpower") @db.Decimal(20, 8)
// === 时间戳 ===
lastUpdateAt DateTime @default(now()) @updatedAt @map("last_update_at")
createdAt DateTime @default(now()) @map("created_at")
@@map("reward_summaries")
@@index([userId], name: "idx_summary_user")
@@index([accountSequence], name: "idx_summary_account")
@@index([settleableUsdt(sort: Desc)], name: "idx_settleable_desc")
@@index([pendingExpireAt], name: "idx_pending_expire")
}
// ============================================
// 权益定义表 (配置表)
// 定义每种权益的奖励规则
// ============================================
model RightDefinition {
id BigInt @id @default(autoincrement()) @map("definition_id")
rightType String @unique @map("right_type") @db.VarChar(50)
// === 奖励规则 ===
usdtPerTree Decimal @map("usdt_per_tree") @db.Decimal(20, 8)
hashpowerPercent Decimal @default(0) @map("hashpower_percent") @db.Decimal(5, 2)
// === 分配目标 ===
payableTo String @map("payable_to") @db.VarChar(50) // USER_ACCOUNT/SYSTEM_ACCOUNT/HEADQUARTERS
// === 规则描述 ===
ruleDescription String? @map("rule_description") @db.Text
// === 启用状态 ===
isEnabled Boolean @default(true) @map("is_enabled")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("right_definitions")
@@index([rightType], name: "idx_def_right_type")
@@index([isEnabled], name: "idx_def_enabled")
}
// ============================================
// 结算记录表 (行为表)
// 记录每次结算的详情
// ============================================
model SettlementRecord {
id BigInt @id @default(autoincrement()) @map("settlement_id")
userId BigInt @map("user_id")
accountSequence String @map("account_sequence") @db.VarChar(20) // 账户序列号
// === 结算金额 ===
usdtAmount Decimal @map("usdt_amount") @db.Decimal(20, 8)
hashpowerAmount Decimal @map("hashpower_amount") @db.Decimal(20, 8)
// === 结算币种 ===
settleCurrency String @map("settle_currency") @db.VarChar(10) // BNB/OG/USDT/DST
receivedAmount Decimal @map("received_amount") @db.Decimal(20, 8) // 实际收到的币种数量
// === 交易信息 ===
swapTxHash String? @map("swap_tx_hash") @db.VarChar(100)
swapRate Decimal? @map("swap_rate") @db.Decimal(20, 8) // SWAP汇率
// === 状态 ===
status String @default("PENDING") @map("status") @db.VarChar(20) // PENDING/SUCCESS/FAILED
// === 时间戳 ===
createdAt DateTime @default(now()) @map("created_at")
completedAt DateTime? @map("completed_at")
// === 关联的奖励条目ID列表 ===
rewardEntryIds BigInt[] @map("reward_entry_ids")
@@map("settlement_records")
@@index([userId], name: "idx_settlement_user")
@@index([accountSequence], name: "idx_settlement_account")
@@index([status], name: "idx_settlement_status")
@@index([createdAt], name: "idx_settlement_created")
}
// ============================================
// 奖励事件表 (行为表, append-only)
// 用于事件溯源和审计
// ============================================
model RewardEvent {
id BigInt @id @default(autoincrement()) @map("event_id")
eventType String @map("event_type") @db.VarChar(50)
// 聚合根信息
aggregateId String @map("aggregate_id") @db.VarChar(100)
aggregateType String @map("aggregate_type") @db.VarChar(50)
// 事件数据
eventData Json @map("event_data")
// 元数据
userId BigInt? @map("user_id")
occurredAt DateTime @default(now()) @map("occurred_at") @db.Timestamp(6)
version Int @default(1) @map("version")
@@map("reward_events")
@@index([aggregateType, aggregateId], name: "idx_reward_event_aggregate")
@@index([eventType], name: "idx_reward_event_type")
@@index([userId], name: "idx_reward_event_user")
@@index([occurredAt], name: "idx_reward_event_occurred")
}
// ============================================
// Outbox 事件发件箱表 (Outbox Pattern)
// 保证事件发布的可靠性:
// 1. 业务数据和 Outbox 记录在同一个事务中写入
// 2. 后台任务轮询 Outbox 表并发布到 Kafka
// 3. 消费方确认后标记为 CONFIRMED
// ============================================
model OutboxEvent {
id BigInt @id @default(autoincrement()) @map("outbox_id")
// 事件信息
eventType String @map("event_type") @db.VarChar(100)
topic String @map("topic") @db.VarChar(100)
key String @map("key") @db.VarChar(200)
payload Json @map("payload")
// 聚合根信息 (用于幂等性检查)
aggregateId String @map("aggregate_id") @db.VarChar(100)
aggregateType String @map("aggregate_type") @db.VarChar(50)
// 发布状态: PENDING -> SENT -> CONFIRMED 或 FAILED
status String @default("PENDING") @map("status") @db.VarChar(20)
retryCount Int @default(0) @map("retry_count")
maxRetries Int @default(5) @map("max_retries")
lastError String? @map("last_error") @db.Text
// 时间戳
createdAt DateTime @default(now()) @map("created_at")
publishedAt DateTime? @map("published_at")
nextRetryAt DateTime? @map("next_retry_at")
@@map("outbox_events")
@@index([status, createdAt], name: "idx_outbox_status_created")
@@index([status, nextRetryAt], name: "idx_outbox_status_retry")
@@index([aggregateType, aggregateId], name: "idx_outbox_aggregate")
@@index([topic], name: "idx_outbox_topic")
}