177 lines
5.7 KiB
Plaintext
177 lines
5.7 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// 用户账户表
|
|
model UserAccount {
|
|
id BigInt @id @default(autoincrement()) @map("user_id")
|
|
accountSequence BigInt @unique @map("account_sequence")
|
|
|
|
// 基本信息
|
|
phoneNumber String? @unique @map("phone_number") @db.VarChar(20)
|
|
nickname String @db.VarChar(100)
|
|
avatarUrl String? @map("avatar_url") @db.VarChar(500)
|
|
|
|
// 推荐信息
|
|
inviterSequence BigInt? @map("inviter_sequence")
|
|
referralCode String @unique @map("referral_code") @db.VarChar(10)
|
|
|
|
// 区域信息
|
|
provinceCode String @map("province_code") @db.VarChar(10)
|
|
cityCode String @map("city_code") @db.VarChar(10)
|
|
address String? @db.VarChar(500)
|
|
|
|
// KYC信息
|
|
kycStatus String @default("NOT_VERIFIED") @map("kyc_status") @db.VarChar(20)
|
|
realName String? @map("real_name") @db.VarChar(100)
|
|
idCardNumber String? @map("id_card_number") @db.VarChar(20)
|
|
idCardFrontUrl String? @map("id_card_front_url") @db.VarChar(500)
|
|
idCardBackUrl String? @map("id_card_back_url") @db.VarChar(500)
|
|
kycVerifiedAt DateTime? @map("kyc_verified_at")
|
|
|
|
// 账户状态
|
|
status String @default("ACTIVE") @db.VarChar(20)
|
|
|
|
// 时间戳
|
|
registeredAt DateTime @default(now()) @map("registered_at")
|
|
lastLoginAt DateTime? @map("last_login_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// 关联
|
|
devices UserDevice[]
|
|
walletAddresses WalletAddress[]
|
|
events UserEvent[]
|
|
|
|
@@index([phoneNumber])
|
|
@@index([accountSequence])
|
|
@@index([referralCode])
|
|
@@index([inviterSequence])
|
|
@@index([provinceCode, cityCode])
|
|
@@index([kycStatus])
|
|
@@index([status])
|
|
@@map("user_accounts")
|
|
}
|
|
|
|
// 用户设备表
|
|
model UserDevice {
|
|
id BigInt @id @default(autoincrement())
|
|
userId BigInt @map("user_id")
|
|
deviceId String @map("device_id") @db.VarChar(100)
|
|
deviceName String? @map("device_name") @db.VarChar(100)
|
|
|
|
addedAt DateTime @default(now()) @map("added_at")
|
|
lastActiveAt DateTime @default(now()) @map("last_active_at")
|
|
|
|
user UserAccount @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, deviceId])
|
|
@@index([deviceId])
|
|
@@index([userId])
|
|
@@index([lastActiveAt])
|
|
@@map("user_devices")
|
|
}
|
|
|
|
// 区块链钱包地址表
|
|
model WalletAddress {
|
|
id BigInt @id @default(autoincrement()) @map("address_id")
|
|
userId BigInt @map("user_id")
|
|
|
|
chainType String @map("chain_type") @db.VarChar(20)
|
|
address String @db.VarChar(100)
|
|
encryptedMnemonic String? @map("encrypted_mnemonic") @db.Text
|
|
|
|
status String @default("ACTIVE") @db.VarChar(20)
|
|
boundAt DateTime @default(now()) @map("bound_at")
|
|
|
|
user UserAccount @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, chainType])
|
|
@@unique([chainType, address])
|
|
@@index([userId])
|
|
@@index([address])
|
|
@@map("wallet_addresses")
|
|
}
|
|
|
|
// 设备Token表
|
|
model DeviceToken {
|
|
id BigInt @id @default(autoincrement())
|
|
userId BigInt @map("user_id")
|
|
deviceId String @map("device_id") @db.VarChar(100)
|
|
|
|
refreshTokenHash String @unique @map("refresh_token_hash") @db.VarChar(64)
|
|
|
|
expiresAt DateTime @map("expires_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
revokedAt DateTime? @map("revoked_at")
|
|
|
|
@@index([userId, deviceId])
|
|
@@index([expiresAt])
|
|
@@map("device_tokens")
|
|
}
|
|
|
|
// 用户事件表
|
|
model UserEvent {
|
|
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.Timestamptz(6)
|
|
version Int @default(1)
|
|
|
|
user UserAccount? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([aggregateType, aggregateId])
|
|
@@index([eventType])
|
|
@@index([userId])
|
|
@@index([occurredAt])
|
|
@@map("user_events")
|
|
}
|
|
|
|
// 短信验证码表
|
|
model SmsCode {
|
|
id BigInt @id @default(autoincrement())
|
|
phoneNumber String @map("phone_number") @db.VarChar(20)
|
|
code String @db.VarChar(6)
|
|
type String @db.VarChar(20) // REGISTER, LOGIN, BIND, RECOVER
|
|
|
|
expiresAt DateTime @map("expires_at")
|
|
usedAt DateTime? @map("used_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@index([phoneNumber, type])
|
|
@@index([expiresAt])
|
|
@@map("sms_codes")
|
|
}
|
|
|
|
// 死信队列表
|
|
model DeadLetterEvent {
|
|
id BigInt @id @default(autoincrement())
|
|
topic String @db.VarChar(100)
|
|
eventId String @map("event_id") @db.VarChar(50)
|
|
eventType String @map("event_type") @db.VarChar(50)
|
|
aggregateId String @map("aggregate_id") @db.VarChar(100)
|
|
aggregateType String @map("aggregate_type") @db.VarChar(50)
|
|
payload Json
|
|
errorMessage String @map("error_message") @db.Text
|
|
errorStack String? @map("error_stack") @db.Text
|
|
retryCount Int @default(0) @map("retry_count")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
processedAt DateTime? @map("processed_at")
|
|
|
|
@@index([topic])
|
|
@@index([eventType])
|
|
@@index([createdAt])
|
|
@@index([processedAt])
|
|
@@map("dead_letter_events")
|
|
}
|