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

580 lines
24 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")
}
// ============================================
// CDC 同步数据表(从其他服务同步)
// ============================================
// 同步的用户数据
model SyncedUser {
id BigInt @id @default(autoincrement())
accountSequence String @unique @map("account_sequence") @db.VarChar(20)
originalUserId BigInt @map("original_user_id")
phone String? @db.VarChar(20)
status String? @db.VarChar(20)
// CDC 同步元数据
sourceSequenceNum BigInt @map("source_sequence_num")
syncedAt DateTime @default(now()) @map("synced_at")
// 算力计算状态
contributionCalculated Boolean @default(false) @map("contribution_calculated")
contributionCalculatedAt DateTime? @map("contribution_calculated_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([originalUserId])
@@index([contributionCalculated])
@@map("synced_users")
}
// 同步的认种数据
model SyncedAdoption {
id BigInt @id @default(autoincrement())
originalAdoptionId BigInt @unique @map("original_adoption_id")
accountSequence String @map("account_sequence") @db.VarChar(20)
treeCount Int @map("tree_count")
adoptionDate DateTime @map("adoption_date") @db.Date
status String? @db.VarChar(30) // 与1.0 planting_orders.status保持一致
// 认种选择的省市(用于系统账户分配)
selectedProvince String? @map("selected_province") @db.VarChar(10)
selectedCity String? @map("selected_city") @db.VarChar(10)
// 贡献值计算参数(从认种时的配置)
contributionPerTree Decimal @map("contribution_per_tree") @db.Decimal(20, 10)
// CDC 同步元数据
sourceSequenceNum BigInt @map("source_sequence_num")
syncedAt DateTime @default(now()) @map("synced_at")
// 算力分配状态
contributionDistributed Boolean @default(false) @map("contribution_distributed")
contributionDistributedAt DateTime? @map("contribution_distributed_at")
// 分配明细摘要 (JSON 字符串格式)
// 格式: { personal: {rate, amount}, operation: {rate, amount}, province: {rate, amount}, city: {rate, amount}, team: {rate, amount, distributed, unallocated} }
distributionSummary String? @map("distribution_summary") @db.Text
createdAt DateTime @default(now()) @map("created_at")
@@index([accountSequence])
@@index([adoptionDate])
@@index([contributionDistributed])
@@index([selectedProvince, selectedCity])
@@map("synced_adoptions")
}
// 同步的推荐关系数据
model SyncedReferral {
id BigInt @id @default(autoincrement())
accountSequence String @unique @map("account_sequence") @db.VarChar(20)
// 推荐人信息:优先使用 account_sequence但也保存 user_id 以便后续解析
referrerAccountSequence String? @map("referrer_account_sequence") @db.VarChar(20)
referrerUserId BigInt? @map("referrer_user_id") // 1.0 的 referrer_id
originalUserId BigInt? @map("original_user_id") // 1.0 的 user_id
// 预计算的层级路径(便于快速查询上下级)
// 1.0 存储的是 BigInt[],这里转换为逗号分隔的字符串
ancestorPath String? @map("ancestor_path") @db.Text
depth Int @default(0)
// CDC 同步元数据
sourceSequenceNum BigInt @map("source_sequence_num")
syncedAt DateTime @default(now()) @map("synced_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([referrerAccountSequence])
@@index([referrerUserId])
@@index([originalUserId])
@@map("synced_referrals")
}
// ============================================
// 算力账户与明细表
// ============================================
// 算力账户表(汇总)
// 设计说明:
// - 个人算力:自己认种,立即生效
// - 层级算力下级1-15层认种的分成每层0.5%共7.5%
// - 加成算力团队加成3档各2.5%共7.5%
// 解锁规则:
// - 自己认种解锁层级1-5 + 加成第1档
// - 直推≥2人认种解锁加成第2档
// - 直推≥3人认种解锁层级6-10
// - 直推≥4人认种解锁加成第3档
// - 直推≥5人认种解锁层级11-15
model ContributionAccount {
id BigInt @id @default(autoincrement())
accountSequence String @unique @map("account_sequence") @db.VarChar(20)
// ========== 个人算力(立即生效)==========
personalContribution Decimal @default(0) @map("personal_contribution") @db.Decimal(30, 10)
// ========== 15级层级算力待解锁/已解锁)==========
// 每级0.5%,分三档解锁
// 第1档(1-5级):自己认种解锁
level1Pending Decimal @default(0) @map("level_1_pending") @db.Decimal(30, 10)
level2Pending Decimal @default(0) @map("level_2_pending") @db.Decimal(30, 10)
level3Pending Decimal @default(0) @map("level_3_pending") @db.Decimal(30, 10)
level4Pending Decimal @default(0) @map("level_4_pending") @db.Decimal(30, 10)
level5Pending Decimal @default(0) @map("level_5_pending") @db.Decimal(30, 10)
// 第2档(6-10级)直推≥3人认种解锁
level6Pending Decimal @default(0) @map("level_6_pending") @db.Decimal(30, 10)
level7Pending Decimal @default(0) @map("level_7_pending") @db.Decimal(30, 10)
level8Pending Decimal @default(0) @map("level_8_pending") @db.Decimal(30, 10)
level9Pending Decimal @default(0) @map("level_9_pending") @db.Decimal(30, 10)
level10Pending Decimal @default(0) @map("level_10_pending") @db.Decimal(30, 10)
// 第3档(11-15级)直推≥5人认种解锁
level11Pending Decimal @default(0) @map("level_11_pending") @db.Decimal(30, 10)
level12Pending Decimal @default(0) @map("level_12_pending") @db.Decimal(30, 10)
level13Pending Decimal @default(0) @map("level_13_pending") @db.Decimal(30, 10)
level14Pending Decimal @default(0) @map("level_14_pending") @db.Decimal(30, 10)
level15Pending Decimal @default(0) @map("level_15_pending") @db.Decimal(30, 10)
// ========== 3档加成算力待解锁==========
// 每档2.5%
bonusTier1Pending Decimal @default(0) @map("bonus_tier_1_pending") @db.Decimal(30, 10) // 自己认种解锁
bonusTier2Pending Decimal @default(0) @map("bonus_tier_2_pending") @db.Decimal(30, 10) // 直推≥2人认种解锁
bonusTier3Pending Decimal @default(0) @map("bonus_tier_3_pending") @db.Decimal(30, 10) // 直推≥4人认种解锁
// ========== 汇总字段 ==========
totalLevelPending Decimal @default(0) @map("total_level_pending") @db.Decimal(30, 10) // sum(level1-15 pending)
totalBonusPending Decimal @default(0) @map("total_bonus_pending") @db.Decimal(30, 10) // sum(tier1-3 pending)
totalPending Decimal @default(0) @map("total_pending") @db.Decimal(30, 10) // 所有待解锁总和
totalUnlocked Decimal @default(0) @map("total_unlocked") @db.Decimal(30, 10) // 所有已解锁总和
effectiveContribution Decimal @default(0) @map("effective_contribution") @db.Decimal(30, 10) // personal + unlocked
// ========== 解锁条件状态 ==========
hasAdopted Boolean @default(false) @map("has_adopted")
directReferralAdoptedCount Int @default(0) @map("direct_referral_adopted_count")
// 解锁深度0=未解锁, 5=第1档, 10=第2档, 15=全部解锁
unlockedLevelDepth Int @default(0) @map("unlocked_level_depth")
// 解锁加成档位0=未解锁, 1/2/3=对应档位
unlockedBonusTiers Int @default(0) @map("unlocked_bonus_tiers")
// 乐观锁
version Int @default(1)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([effectiveContribution(sort: Desc)])
@@index([hasAdopted])
@@index([directReferralAdoptedCount])
@@map("contribution_accounts")
}
// 算力明细表(分类账)
// 每笔算力变动都记录在此表,用于审计和追溯
// 状态流转PENDING -> UNLOCKED -> EXPIRED (或直接 EFFECTIVE -> EXPIRED)
model ContributionRecord {
id BigInt @id @default(autoincrement())
accountSequence String @map("account_sequence") @db.VarChar(20)
// ========== 来源信息(可追溯)==========
sourceType String @map("source_type") @db.VarChar(30) // PERSONAL / LEVEL_1~15 / BONUS_TIER_1~3
sourceAdoptionId BigInt @map("source_adoption_id") // 来源认种ID
sourceAccountSequence String @map("source_account_sequence") @db.VarChar(20) // 认种人账号
// ========== 计算参数(审计用)==========
treeCount Int @map("tree_count") // 认种棵数
baseContribution Decimal @map("base_contribution") @db.Decimal(20, 10) // 基础贡献值/棵
distributionRate Decimal @map("distribution_rate") @db.Decimal(10, 6) // 分配比例 (0.005=0.5%, 0.025=2.5%)
levelDepth Int? @map("level_depth") // 层级深度 (1-15)
bonusTier Int? @map("bonus_tier") // 加成档位 (1-3)
// ========== 金额 ==========
amount Decimal @map("amount") @db.Decimal(30, 10) // 算力金额
// ========== 解锁状态 ==========
status String @default("PENDING") @map("status") @db.VarChar(20) // PENDING/UNLOCKED/EFFECTIVE
unlockedAt DateTime? @map("unlocked_at") // 解锁时间
unlockReason String? @map("unlock_reason") @db.VarChar(200) // 解锁原因描述
// ========== 有效期 ==========
effectiveDate DateTime @map("effective_date") @db.Date // 生效日期
expireDate DateTime @map("expire_date") @db.Date // 过期日期
isExpired Boolean @default(false) @map("is_expired")
expiredAt DateTime? @map("expired_at")
// ========== 备注 ==========
remark String? @map("remark") @db.VarChar(500) // 备注说明
createdAt DateTime @default(now()) @map("created_at")
@@index([accountSequence, status])
@@index([accountSequence, createdAt(sort: Desc)])
@@index([sourceAdoptionId])
@@index([sourceAccountSequence])
@@index([sourceType])
@@index([status])
@@index([expireDate])
@@index([isExpired])
@@map("contribution_records")
}
// 解锁事件记录表
// 记录每次解锁的触发原因,便于审计和追溯
model UnlockEvent {
id BigInt @id @default(autoincrement())
accountSequence String @map("account_sequence") @db.VarChar(20) // 被解锁的账户
// ========== 触发信息 ==========
triggerType String @map("trigger_type") @db.VarChar(30) // SELF_ADOPT / REFERRAL_ADOPT
triggerAdoptionId BigInt @map("trigger_adoption_id") // 触发认种的ID
triggerAccountSequence String @map("trigger_account_sequence") @db.VarChar(20) // 触发认种的账户
// ========== 解锁内容 ==========
unlockType String @map("unlock_type") @db.VarChar(30) // LEVEL_1_5 / LEVEL_6_10 / LEVEL_11_15 / BONUS_TIER_1 / BONUS_TIER_2 / BONUS_TIER_3
unlockCondition String @map("unlock_condition") @db.VarChar(100) // 解锁条件描述,如 "自己认种" / "直推认种人数达到3人"
// ========== 解锁前后状态 ==========
beforeDirectReferralCount Int @map("before_direct_referral_count") // 解锁前直推认种人数
afterDirectReferralCount Int @map("after_direct_referral_count") // 解锁后直推认种人数
beforeUnlockedLevelDepth Int @map("before_unlocked_level_depth") // 解锁前层级深度
afterUnlockedLevelDepth Int @map("after_unlocked_level_depth") // 解锁后层级深度
beforeUnlockedBonusTiers Int @map("before_unlocked_bonus_tiers") // 解锁前加成档位
afterUnlockedBonusTiers Int @map("after_unlocked_bonus_tiers") // 解锁后加成档位
// ========== 解锁金额 ==========
unlockedAmount Decimal @map("unlocked_amount") @db.Decimal(30, 10) // 本次解锁的算力金额
unlockedRecordCount Int @map("unlocked_record_count") // 本次解锁的明细记录数
// ========== 备注 ==========
remark String? @map("remark") @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
@@index([accountSequence])
@@index([triggerAccountSequence])
@@index([triggerAdoptionId])
@@index([unlockType])
@@index([createdAt(sort: Desc)])
@@map("unlock_events")
}
// 未分配算力记录(归总部)
// 当上级未解锁对应层级/加成时,算力暂存于此
model UnallocatedContribution {
id BigInt @id @default(autoincrement())
sourceAdoptionId BigInt @map("source_adoption_id") // 来源认种ID
sourceAccountSequence String @map("source_account_sequence") @db.VarChar(20) // 认种人账号
// ========== 未分配类型 ==========
unallocType String @map("unalloc_type") @db.VarChar(30) // LEVEL_6~15_PENDING / BONUS_TIER_2_PENDING / BONUS_TIER_3_PENDING
wouldBeAccountSequence String? @map("would_be_account_sequence") @db.VarChar(20) // 应该归属的账户
levelDepth Int? @map("level_depth") // 层级深度
bonusTier Int? @map("bonus_tier") // 加成档位
amount Decimal @map("amount") @db.Decimal(30, 10)
reason String? @db.VarChar(200) // 未分配原因
// ========== 分配状态 ==========
status String @default("PENDING") @map("status") @db.VarChar(20) // PENDING / ALLOCATED_TO_USER / ALLOCATED_TO_HQ
allocatedAt DateTime? @map("allocated_at")
allocatedToAccountSequence String? @map("allocated_to_account_sequence") @db.VarChar(20) // 最终分配给的账户
// ========== 有效期 ==========
effectiveDate DateTime @map("effective_date") @db.Date
expireDate DateTime @map("expire_date") @db.Date
createdAt DateTime @default(now()) @map("created_at")
@@index([sourceAdoptionId])
@@index([wouldBeAccountSequence])
@@index([unallocType])
@@index([status])
@@map("unallocated_contributions")
}
// 系统账户(运营/省/市/总部)
model SystemAccount {
id BigInt @id @default(autoincrement())
accountType String @unique @map("account_type") @db.VarChar(20) // OPERATION / PROVINCE / CITY / HEADQUARTERS
name String @db.VarChar(100)
contributionBalance Decimal @default(0) @map("contribution_balance") @db.Decimal(30, 10)
contributionNeverExpires Boolean @default(false) @map("contribution_never_expires")
version Int @default(1)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
records SystemContributionRecord[]
@@map("system_accounts")
}
// 系统账户算力明细
model SystemContributionRecord {
id BigInt @id @default(autoincrement())
systemAccountId BigInt @map("system_account_id")
sourceAdoptionId BigInt @map("source_adoption_id")
sourceAccountSequence String @map("source_account_sequence") @db.VarChar(20)
distributionRate Decimal @map("distribution_rate") @db.Decimal(10, 6)
amount Decimal @map("amount") @db.Decimal(30, 10)
effectiveDate DateTime @map("effective_date") @db.Date
expireDate DateTime? @map("expire_date") @db.Date
isExpired Boolean @default(false) @map("is_expired")
createdAt DateTime @default(now()) @map("created_at")
systemAccount SystemAccount @relation(fields: [systemAccountId], references: [id])
@@index([systemAccountId])
@@index([sourceAdoptionId])
@@map("system_contribution_records")
}
// ============================================
// 快照与统计表
// ============================================
// 每日算力快照(用于挖矿分配计算)
model DailyContributionSnapshot {
id BigInt @id @default(autoincrement())
snapshotDate DateTime @map("snapshot_date") @db.Date
accountSequence String @map("account_sequence") @db.VarChar(20)
effectiveContribution Decimal @map("effective_contribution") @db.Decimal(30, 10)
networkTotalContribution Decimal @map("network_total_contribution") @db.Decimal(30, 10)
contributionRatio Decimal @map("contribution_ratio") @db.Decimal(30, 18)
createdAt DateTime @default(now()) @map("created_at")
@@unique([snapshotDate, accountSequence])
@@index([snapshotDate])
@@index([accountSequence])
@@map("daily_contribution_snapshots")
}
// 用户团队统计(缓存,定期更新)
model UserTeamStats {
id BigInt @id @default(autoincrement())
accountSequence String @map("account_sequence") @db.VarChar(20)
statsDate DateTime @map("stats_date") @db.Date
// 各级认种统计
level1Trees Int @default(0) @map("level_1_trees")
level2Trees Int @default(0) @map("level_2_trees")
level3Trees Int @default(0) @map("level_3_trees")
level4Trees Int @default(0) @map("level_4_trees")
level5Trees Int @default(0) @map("level_5_trees")
level6Trees Int @default(0) @map("level_6_trees")
level7Trees Int @default(0) @map("level_7_trees")
level8Trees Int @default(0) @map("level_8_trees")
level9Trees Int @default(0) @map("level_9_trees")
level10Trees Int @default(0) @map("level_10_trees")
level11Trees Int @default(0) @map("level_11_trees")
level12Trees Int @default(0) @map("level_12_trees")
level13Trees Int @default(0) @map("level_13_trees")
level14Trees Int @default(0) @map("level_14_trees")
level15Trees Int @default(0) @map("level_15_trees")
totalTeamTrees Int @default(0) @map("total_team_trees")
directAdoptedReferrals Int @default(0) @map("direct_adopted_referrals")
createdAt DateTime @default(now()) @map("created_at")
@@unique([accountSequence, statsDate])
@@index([accountSequence])
@@index([statsDate])
@@map("user_team_stats")
}
// ============================================
// CDC 同步状态追踪
// ============================================
// CDC 同步进度表
model CdcSyncProgress {
id BigInt @id @default(autoincrement())
sourceTopic String @unique @map("source_topic") @db.VarChar(100)
lastSequenceNum BigInt @default(0) @map("last_sequence_num")
lastSyncedAt DateTime? @map("last_synced_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("cdc_sync_progress")
}
// 已处理 CDC 事件表(幂等性)
// 使用 (sourceTopic, offset) 作为复合唯一键
// 这是事务性幂等消费的关键:在同一事务中插入此记录 + 执行业务逻辑
model ProcessedCdcEvent {
id BigInt @id @default(autoincrement())
sourceTopic String @map("source_topic") @db.VarChar(200) // CDC topic 名称
offset BigInt @map("offset") // Kafka offset 作为唯一标识
tableName String @map("table_name") @db.VarChar(100) // 表名
operation String @map("operation") @db.VarChar(10) // c/u/d/r
processedAt DateTime @default(now()) @map("processed_at")
@@unique([sourceTopic, offset])
@@index([processedAt])
@@map("processed_cdc_events")
}
// 已处理 Outbox 事件表(用于 2.0 服务间同步)
model ProcessedEvent {
id BigInt @id @default(autoincrement())
eventId String @map("event_id") @db.VarChar(100)
eventType String @map("event_type") @db.VarChar(50)
sourceService String @map("source_service") @db.VarChar(100)
processedAt DateTime @default(now()) @map("processed_at")
@@unique([sourceService, eventId])
@@index([eventType])
@@index([processedAt])
@@map("processed_events")
}
// ============================================
// 配置表
// ============================================
// 贡献值递增配置
model ContributionConfig {
id BigInt @id @default(autoincrement())
baseContribution Decimal @default(22617) @map("base_contribution") @db.Decimal(20, 10)
incrementPercentage Decimal @default(0.003) @map("increment_percentage") @db.Decimal(10, 6)
unitSize Int @default(100) @map("unit_size")
startTreeNumber Int @default(1000) @map("start_tree_number")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
@@index([isActive])
@@map("contribution_configs")
}
// 分配比例配置
model DistributionRateConfig {
id BigInt @id @default(autoincrement())
rateType String @unique @map("rate_type") @db.VarChar(30)
rateValue Decimal @map("rate_value") @db.Decimal(10, 6)
description String? @db.VarChar(100)
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
@@index([isActive])
@@map("distribution_rate_configs")
}
// 全网认种进度表(单行记录,实时更新)
// 记录当前全网累计认种数量和对应的算力系数
model NetworkAdoptionProgress {
id BigInt @id @default(autoincrement())
// ========== 全网累计认种统计 ==========
totalTreeCount Int @default(0) @map("total_tree_count") // 全网累计认种棵数
totalAdoptionOrders Int @default(0) @map("total_adoption_orders") // 全网累计认种订单数
totalAdoptedUsers Int @default(0) @map("total_adopted_users") // 全网累计认种用户数
// ========== 当前算力系数 ==========
// 基础值: 22617 (从第1棵到第999棵)
// 从第1000棵开始每100棵为1个单位每个单位递增 0.3%
// currentMultiplier = 1 + (currentUnit * 0.003)
// currentContributionPerTree = baseContribution * currentMultiplier
currentUnit Int @default(0) @map("current_unit") // 当前单位数 (0表示还没到1000棵)
currentMultiplier Decimal @default(1.0) @map("current_multiplier") @db.Decimal(10, 6) // 当前系数 (1.000, 1.003, 1.006...)
currentContributionPerTree Decimal @default(22617) @map("current_contribution_per_tree") @db.Decimal(20, 10) // 当前每棵树贡献值
// ========== 下一个单位的触发点 ==========
nextUnitTreeCount Int @default(1000) @map("next_unit_tree_count") // 下一个单位触发的棵数
// ========== 最后更新信息 ==========
lastAdoptionId BigInt? @map("last_adoption_id") // 最后处理的认种ID
lastAdoptionDate DateTime? @map("last_adoption_date") @db.Date // 最后认种日期
updatedAt DateTime @updatedAt @map("updated_at")
createdAt DateTime @default(now()) @map("created_at")
@@map("network_adoption_progress")
}
// 每日算力系数快照表
// 记录每天的算力系数,确保同一天认种的用户使用相同系数
model DailyContributionRate {
id BigInt @id @default(autoincrement())
// ========== 日期 ==========
effectiveDate DateTime @unique @map("effective_date") @db.Date // 生效日期
// ========== 当日起始状态 ==========
startTreeCount Int @default(0) @map("start_tree_count") // 当日开始时的全网棵数
startUnit Int @default(0) @map("start_unit") // 当日开始时的单位数
startMultiplier Decimal @default(1.0) @map("start_multiplier") @db.Decimal(10, 6) // 当日开始时的系数
contributionPerTree Decimal @map("contribution_per_tree") @db.Decimal(20, 10) // 当日每棵树贡献值(同一天内不变)
// ========== 当日结束状态 ==========
endTreeCount Int? @map("end_tree_count") // 当日结束时的全网棵数
endUnit Int? @map("end_unit") // 当日结束时的单位数
endMultiplier Decimal? @map("end_multiplier") @db.Decimal(10, 6) // 当日结束时的系数
// ========== 当日统计 ==========
dailyTreeCount Int @default(0) @map("daily_tree_count") // 当日新增认种棵数
dailyAdoptionOrders Int @default(0) @map("daily_adoption_orders") // 当日新增认种订单数
dailyAdoptedUsers Int @default(0) @map("daily_adopted_users") // 当日新增认种用户数
// ========== 状态 ==========
isClosed Boolean @default(false) @map("is_closed") // 是否已结算日终处理后置为true
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([effectiveDate])
@@index([isClosed])
@@map("daily_contribution_rates")
}
// ============================================
// Outbox 事件表(可靠事件发布)
// ============================================
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)
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")
@@index([status, createdAt])
@@index([status, nextRetryAt])
@@index([aggregateType, aggregateId])
@@index([topic])
@@map("outbox_events")
}