133 lines
5.3 KiB
Plaintext
133 lines
5.3 KiB
Plaintext
// ============================================
|
||
// [2026-02-17] 预种计划独立 Prisma Schema
|
||
// ============================================
|
||
//
|
||
// 本 schema 仅包含预种计划在 contribution-service 中的追踪表。
|
||
// 与主 schema (prisma/schema.prisma) 完全隔离,拥有独立的:
|
||
// - Prisma Client(生成到 src/pre-planting/infrastructure/prisma/generated/)
|
||
// - Migration 目录(prisma/pre-planting/migrations/)
|
||
//
|
||
// 预种的算力分配结果仍然写入主 schema 的 contribution_accounts、
|
||
// contribution_records 等表(通过现有 Repository),以便挖矿系统读取。
|
||
// 本 schema 仅负责预种 CDC 同步追踪、冻结状态等预种专属数据。
|
||
|
||
generator client {
|
||
provider = "prisma-client-js"
|
||
output = "../../src/pre-planting/infrastructure/prisma/generated"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// ============================================
|
||
// 预种 CDC 同步追踪表
|
||
// ============================================
|
||
|
||
/// 预种订单同步记录(从 planting-service CDC 同步)
|
||
/// 用于追踪每笔预种订单的算力分配状态
|
||
model PrePlantingSyncedOrder {
|
||
id BigInt @id @default(autoincrement())
|
||
originalOrderId BigInt @unique @map("original_order_id")
|
||
orderNo String @map("order_no") @db.VarChar(50)
|
||
userId BigInt @map("user_id")
|
||
accountSequence String @map("account_sequence") @db.VarChar(20)
|
||
portionCount Int @map("portion_count")
|
||
pricePerPortion Decimal @map("price_per_portion") @db.Decimal(20, 8)
|
||
totalAmount Decimal @map("total_amount") @db.Decimal(20, 8)
|
||
provinceCode String @map("province_code") @db.VarChar(10)
|
||
cityCode String @map("city_code") @db.VarChar(10)
|
||
status String @map("status") @db.VarChar(20) // CREATED, PAID, MERGED
|
||
mergedToMergeId BigInt? @map("merged_to_merge_id")
|
||
paidAt DateTime? @map("paid_at")
|
||
createdAt DateTime @map("created_at")
|
||
|
||
// 算力追踪
|
||
contributionPerPortion Decimal @map("contribution_per_portion") @db.Decimal(20, 10)
|
||
contributionDistributed Boolean @default(false) @map("contribution_distributed")
|
||
contributionDistributedAt DateTime? @map("contribution_distributed_at")
|
||
|
||
// CDC 同步元数据
|
||
sourceTopic String @map("source_topic") @db.VarChar(200)
|
||
sourceOffset BigInt @map("source_offset")
|
||
syncedAt DateTime @default(now()) @map("synced_at")
|
||
|
||
@@index([accountSequence])
|
||
@@index([status])
|
||
@@index([contributionDistributed])
|
||
@@map("pre_planting_synced_orders")
|
||
}
|
||
|
||
/// 预种持仓同步记录(从 planting-service CDC 同步)
|
||
/// 用于追踪用户预种总量,判断冻结条件
|
||
model PrePlantingSyncedPosition {
|
||
id BigInt @id @default(autoincrement())
|
||
userId BigInt @unique @map("user_id")
|
||
accountSequence String @unique @map("account_sequence") @db.VarChar(20)
|
||
totalPortions Int @default(0) @map("total_portions")
|
||
mergedPortions Int @default(0) @map("merged_portions")
|
||
totalTreesMerged Int @default(0) @map("total_trees_merged")
|
||
firstPurchaseAt DateTime? @map("first_purchase_at")
|
||
|
||
// CDC 同步元数据
|
||
sourceTopic String @map("source_topic") @db.VarChar(200)
|
||
sourceOffset BigInt @map("source_offset")
|
||
syncedAt DateTime @default(now()) @map("synced_at")
|
||
|
||
@@map("pre_planting_synced_positions")
|
||
}
|
||
|
||
// ============================================
|
||
// 预种冻结状态表
|
||
// ============================================
|
||
|
||
/// 预种算力冻结状态(每用户一条)
|
||
///
|
||
/// 冻结规则:
|
||
/// - firstPurchaseAt + 1 年后仍未满 5 份 → 所有预种算力冻结(暂停分配)
|
||
/// - 后续累积满 5 份 → 解冻,恢复分配
|
||
/// - 解冻后的失效期 = 解冻日起算 + 2 年
|
||
/// - 未被冻结过的正常到期 = 首次产生挖矿收益日 + 2 年
|
||
model PrePlantingFreezeState {
|
||
id BigInt @id @default(autoincrement())
|
||
accountSequence String @unique @map("account_sequence") @db.VarChar(20)
|
||
totalPortions Int @default(0) @map("total_portions")
|
||
totalTreesMerged Int @default(0) @map("total_trees_merged")
|
||
firstPurchaseAt DateTime? @map("first_purchase_at")
|
||
|
||
// 冻结状态
|
||
isFrozen Boolean @default(false) @map("is_frozen")
|
||
frozenAt DateTime? @map("frozen_at")
|
||
unfrozenAt DateTime? @map("unfrozen_at")
|
||
|
||
// 解冻后的过期日期(解冻日 + 2 年)
|
||
postUnfreezeExpireDate DateTime? @map("post_unfreeze_expire_date")
|
||
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([isFrozen])
|
||
@@index([firstPurchaseAt])
|
||
@@map("pre_planting_freeze_states")
|
||
}
|
||
|
||
// ============================================
|
||
// 预种 CDC 幂等性追踪表
|
||
// ============================================
|
||
|
||
/// 已处理的预种 CDC 事件(幂等性保证)
|
||
/// 使用 (sourceTopic, offset) 作为复合唯一键
|
||
model PrePlantingProcessedCdcEvent {
|
||
id BigInt @id @default(autoincrement())
|
||
sourceTopic String @map("source_topic") @db.VarChar(200)
|
||
offset BigInt @map("offset")
|
||
tableName String @map("table_name") @db.VarChar(100)
|
||
operation String @map("operation") @db.VarChar(10)
|
||
processedAt DateTime @default(now()) @map("processed_at")
|
||
|
||
@@unique([sourceTopic, offset])
|
||
@@index([processedAt])
|
||
@@map("pre_planting_processed_cdc_events")
|
||
}
|