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