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

128 lines
5.4 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// 转让订单表 (Saga 聚合根)
// ============================================
model TransferOrder {
id BigInt @id @default(autoincrement())
transferOrderNo String @unique @map("transfer_order_no") @db.VarChar(50)
// ========== 卖方信息 ==========
sellerUserId BigInt @map("seller_user_id")
sellerAccountSequence String @map("seller_account_sequence") @db.VarChar(20)
// ========== 买方信息 ==========
buyerUserId BigInt @map("buyer_user_id")
buyerAccountSequence String @map("buyer_account_sequence") @db.VarChar(20)
// ========== 转让标的 ==========
sourceOrderNo String @map("source_order_no") @db.VarChar(50)
sourceAdoptionId BigInt @map("source_adoption_id")
treeCount Int @map("tree_count")
contributionPerTree Decimal @map("contribution_per_tree") @db.Decimal(20, 10)
originalAdoptionDate DateTime @map("original_adoption_date") @db.Date
originalExpireDate DateTime @map("original_expire_date") @db.Date
selectedProvince String @map("selected_province") @db.VarChar(10)
selectedCity String @map("selected_city") @db.VarChar(10)
// ========== 价格与费用 ==========
transferPrice Decimal @map("transfer_price") @db.Decimal(20, 8)
platformFeeRate Decimal @map("platform_fee_rate") @db.Decimal(5, 4)
platformFeeAmount Decimal @map("platform_fee_amount") @db.Decimal(20, 8)
sellerReceiveAmount Decimal @map("seller_receive_amount") @db.Decimal(20, 8)
// ========== Saga 状态 ==========
status String @default("PENDING") @map("status") @db.VarChar(30)
sagaStep String @default("INIT") @map("saga_step") @db.VarChar(30)
failReason String? @map("fail_reason") @db.VarChar(500)
retryCount Int @default(0) @map("retry_count")
// ========== 各步骤确认时间戳 ==========
sellerConfirmedAt DateTime? @map("seller_confirmed_at")
paymentFrozenAt DateTime? @map("payment_frozen_at")
treesLockedAt DateTime? @map("trees_locked_at")
ownershipTransferredAt DateTime? @map("ownership_transferred_at")
contributionAdjustedAt DateTime? @map("contribution_adjusted_at")
statsUpdatedAt DateTime? @map("stats_updated_at")
paymentSettledAt DateTime? @map("payment_settled_at")
completedAt DateTime? @map("completed_at")
cancelledAt DateTime? @map("cancelled_at")
rolledBackAt DateTime? @map("rolled_back_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
statusLogs TransferStatusLog[]
@@index([sellerUserId])
@@index([buyerUserId])
@@index([sourceOrderNo])
@@index([status])
@@index([createdAt])
@@map("transfer_orders")
}
// ============================================
// 状态变更日志表 (审计)
// ============================================
model TransferStatusLog {
id BigInt @id @default(autoincrement())
transferOrderNo String @map("transfer_order_no") @db.VarChar(50)
fromStatus String @map("from_status") @db.VarChar(30)
toStatus String @map("to_status") @db.VarChar(30)
fromSagaStep String @map("from_saga_step") @db.VarChar(30)
toSagaStep String @map("to_saga_step") @db.VarChar(30)
operatorType String @map("operator_type") @db.VarChar(20)
operatorId String? @map("operator_id") @db.VarChar(50)
remark String? @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
transferOrder TransferOrder @relation(fields: [transferOrderNo], references: [transferOrderNo])
@@index([transferOrderNo])
@@map("transfer_status_logs")
}
// ============================================
// Outbox 事件表 (标准 Outbox Pattern)
// ============================================
model OutboxEvent {
id BigInt @id @default(autoincrement())
eventType String @map("event_type") @db.VarChar(100)
topic String @db.VarChar(200)
key String @db.VarChar(200)
payload Json
aggregateId String @map("aggregate_id") @db.VarChar(100)
aggregateType String @map("aggregate_type") @db.VarChar(100)
status String @default("PENDING") @db.VarChar(20)
retryCount Int @default(0) @map("retry_count")
maxRetries Int @default(5) @map("max_retries")
lastError String? @map("last_error") @db.VarChar(1000)
publishedAt DateTime? @map("published_at")
nextRetryAt DateTime? @map("next_retry_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([status, createdAt])
@@index([status, nextRetryAt])
@@map("outbox_events")
}
// ============================================
// 已处理事件表 (幂等性保证)
// ============================================
model ProcessedEvent {
id BigInt @id @default(autoincrement())
eventId String @unique @map("event_id") @db.VarChar(200)
eventType String @map("event_type") @db.VarChar(100)
processedAt DateTime @default(now()) @map("processed_at")
@@map("processed_events")
}