602 lines
16 KiB
Plaintext
602 lines
16 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
model Tenant {
|
|
id String @id @default(cuid())
|
|
name String
|
|
code String @unique
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
users User[]
|
|
operationLogs OperationLog[]
|
|
fileObjects FileObject[]
|
|
enterpriseBlacklists EnterpriseBlacklist[]
|
|
accounts TenantAccount[]
|
|
accountTransactions AccountTransaction[]
|
|
rechargeOrders RechargeOrder[]
|
|
smsBillingRecords SmsBillingRecord[]
|
|
smsApplications SmsApplication[]
|
|
smsSignatures SmsSignature[]
|
|
smsTemplates SmsTemplate[]
|
|
auditRecords AuditRecord[]
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
username String @unique
|
|
displayName String
|
|
passwordHash String
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
roles UserRole[]
|
|
operationLogs OperationLog[]
|
|
auditRecords AuditRecord[]
|
|
}
|
|
|
|
model Role {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
scope String @default("platform")
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
users UserRole[]
|
|
permissions RolePermission[]
|
|
}
|
|
|
|
model Permission {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
|
|
roles RolePermission[]
|
|
}
|
|
|
|
model UserRole {
|
|
userId String
|
|
roleId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([userId, roleId])
|
|
}
|
|
|
|
model RolePermission {
|
|
roleId String
|
|
permissionId String
|
|
|
|
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([roleId, permissionId])
|
|
}
|
|
|
|
model OperationLog {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
userId String?
|
|
action String
|
|
resource String
|
|
resourceId String?
|
|
ipAddress String?
|
|
userAgent String?
|
|
detail Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([userId, createdAt])
|
|
}
|
|
|
|
model FileObject {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
bucket String
|
|
objectKey String @unique
|
|
fileName String
|
|
contentType String
|
|
sizeBytes BigInt
|
|
checksum String?
|
|
purpose String
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
}
|
|
|
|
model PhoneSegment {
|
|
id String @id @default(cuid())
|
|
prefix String @unique
|
|
carrier String
|
|
province String?
|
|
city String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model SensitiveWord {
|
|
id String @id @default(cuid())
|
|
word String @unique
|
|
level String @default("block")
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model EnterpriseBlacklist {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
phoneNumber String
|
|
reason String?
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
|
|
@@unique([tenantId, phoneNumber])
|
|
}
|
|
|
|
model GlobalBlacklist {
|
|
id String @id @default(cuid())
|
|
phoneNumber String @unique
|
|
reason String?
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model DrainageField {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
fieldType String
|
|
required Boolean @default(false)
|
|
status String @default("active")
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model BillingPlan {
|
|
id String @id @default(cuid())
|
|
name String
|
|
priceCents Int
|
|
smsUnits Int
|
|
validDays Int
|
|
status String @default("active")
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
rechargeOrders RechargeOrder[]
|
|
}
|
|
|
|
model TenantAccount {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
balanceCents Int @default(0)
|
|
smsUnits Int @default(0)
|
|
creditCents Int @default(0)
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
|
|
@@unique([tenantId])
|
|
}
|
|
|
|
model AccountTransaction {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
transactionType String
|
|
amountCents Int @default(0)
|
|
smsUnits Int @default(0)
|
|
balanceAfter Int @default(0)
|
|
relatedType String?
|
|
relatedId String?
|
|
remark String?
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([relatedType, relatedId])
|
|
}
|
|
|
|
model BillingRule {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
chargeBasis String @default("submit_success")
|
|
unitPrice Int
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model RechargeOrder {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
planId String?
|
|
orderNo String @unique
|
|
amountCents Int
|
|
smsUnits Int @default(0)
|
|
status String @default("created")
|
|
payMethod String?
|
|
paidAt DateTime?
|
|
operatorId String?
|
|
remark String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
plan BillingPlan? @relation(fields: [planId], references: [id])
|
|
|
|
@@index([tenantId, createdAt])
|
|
}
|
|
|
|
model SmsBillingRecord {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String?
|
|
taskId String?
|
|
messageId String?
|
|
phoneNumber String?
|
|
contentLength Int
|
|
billingUnits Int
|
|
unitPrice Int
|
|
amountCents Int
|
|
billingStatus String @default("estimated")
|
|
transactionId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([taskId])
|
|
@@index([messageId])
|
|
}
|
|
|
|
model SmsApplication {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
name String
|
|
scene String?
|
|
callbackUrl String?
|
|
secretHash String
|
|
dailyLimit Int?
|
|
maxPhonesPerTask Int @default(1000000)
|
|
templateMismatchMode String @default("reject")
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
ipAllowlist SmsApplicationIpAllowlist[]
|
|
signatures SmsSignature[]
|
|
templates SmsTemplate[]
|
|
|
|
@@index([tenantId, status])
|
|
}
|
|
|
|
model SmsApplicationIpAllowlist {
|
|
id String @id @default(cuid())
|
|
applicationId String
|
|
ipCidr String
|
|
remark String?
|
|
createdAt DateTime @default(now())
|
|
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([applicationId, ipCidr])
|
|
}
|
|
|
|
model SmsSignature {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String?
|
|
name String
|
|
purpose String?
|
|
drainageInfo Json?
|
|
auditStatus String @default("draft")
|
|
reportStatus String @default("waiting_material")
|
|
rejectReason String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication? @relation(fields: [applicationId], references: [id])
|
|
materials SignatureMaterial[]
|
|
templates SmsTemplate[]
|
|
reportMaterials SignatureReportMaterial[]
|
|
reportTasks ChannelSignatureReportTask[]
|
|
|
|
@@index([tenantId, auditStatus])
|
|
@@index([tenantId, reportStatus])
|
|
}
|
|
|
|
model SignatureMaterial {
|
|
id String @id @default(cuid())
|
|
signatureId String
|
|
fileObjectId String?
|
|
materialType String
|
|
title String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
|
|
signature SmsSignature @relation(fields: [signatureId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model SmsTemplate {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
signatureId String?
|
|
name String
|
|
content String
|
|
category String?
|
|
auditStatus String @default("draft")
|
|
rejectReason String?
|
|
billingUnits Int @default(1)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id])
|
|
signature SmsSignature? @relation(fields: [signatureId], references: [id])
|
|
variables TemplateVariable[]
|
|
|
|
@@index([tenantId, auditStatus])
|
|
@@index([applicationId])
|
|
}
|
|
|
|
model TemplateVariable {
|
|
id String @id @default(cuid())
|
|
templateId String
|
|
name String
|
|
example String?
|
|
required Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
template SmsTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([templateId, name])
|
|
}
|
|
|
|
model AuditRecord {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
targetType String
|
|
targetId String
|
|
action String
|
|
statusBefore String?
|
|
statusAfter String
|
|
reason String?
|
|
reviewerId String?
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
reviewer User? @relation(fields: [reviewerId], references: [id])
|
|
|
|
@@index([targetType, targetId])
|
|
@@index([tenantId, createdAt])
|
|
}
|
|
|
|
model SmsChannel {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
carrier String?
|
|
protocol String @default("CMPP")
|
|
gatewayHost String
|
|
gatewayPort Int
|
|
enterpriseCode String?
|
|
account String
|
|
passwordCipher String
|
|
srcId String
|
|
cmppVersion String @default("3.0")
|
|
rateLimitPerSecond Int @default(100)
|
|
unitPrice Int @default(0)
|
|
status String @default("active")
|
|
config Json?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
groupItems SmsChannelGroupItem[]
|
|
routeRules ChannelRouteRule[]
|
|
healthMetrics ChannelHealthMetric[]
|
|
reportFields ChannelReportField[]
|
|
reportTasks ChannelSignatureReportTask[]
|
|
reportRecords ChannelSignatureReportRecord[]
|
|
|
|
@@index([status])
|
|
}
|
|
|
|
model SmsChannelGroup {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
items SmsChannelGroupItem[]
|
|
routeRules ChannelRouteRule[]
|
|
}
|
|
|
|
model SmsChannelGroupItem {
|
|
id String @id @default(cuid())
|
|
groupId String
|
|
channelId String
|
|
carrier String?
|
|
province String?
|
|
priority Int @default(100)
|
|
weight Int @default(1)
|
|
isBackup Boolean @default(false)
|
|
rateLimitPerSecond Int?
|
|
createdAt DateTime @default(now())
|
|
|
|
group SmsChannelGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
channel SmsChannel @relation(fields: [channelId], references: [id])
|
|
|
|
@@unique([groupId, channelId, carrier, province])
|
|
@@index([channelId])
|
|
}
|
|
|
|
model ChannelRouteRule {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
applicationId String?
|
|
groupId String
|
|
channelId String?
|
|
carrier String?
|
|
province String?
|
|
priority Int @default(100)
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
group SmsChannelGroup @relation(fields: [groupId], references: [id])
|
|
channel SmsChannel? @relation(fields: [channelId], references: [id])
|
|
|
|
@@index([tenantId, applicationId, status])
|
|
@@index([groupId, priority])
|
|
}
|
|
|
|
model ChannelHealthMetric {
|
|
id String @id @default(cuid())
|
|
channelId String
|
|
submitTotal Int @default(0)
|
|
submitSuccess Int @default(0)
|
|
submitFailed Int @default(0)
|
|
receiptSuccess Int @default(0)
|
|
receiptFailed Int @default(0)
|
|
unknownTotal Int @default(0)
|
|
windowStart DateTime
|
|
windowEnd DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
channel SmsChannel @relation(fields: [channelId], references: [id])
|
|
|
|
@@index([channelId, windowStart])
|
|
}
|
|
|
|
model ChannelReportField {
|
|
id String @id @default(cuid())
|
|
channelId String
|
|
code String
|
|
name String
|
|
fieldType String
|
|
required Boolean @default(false)
|
|
description String?
|
|
sortOrder Int @default(100)
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
channel SmsChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([channelId, code])
|
|
}
|
|
|
|
model SignatureReportMaterial {
|
|
id String @id @default(cuid())
|
|
signatureId String
|
|
channelId String
|
|
fieldCode String
|
|
fieldValue String?
|
|
fileObjectId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
signature SmsSignature @relation(fields: [signatureId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([signatureId, channelId, fieldCode])
|
|
@@index([channelId])
|
|
}
|
|
|
|
model ChannelSignatureReportTask {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
signatureId String
|
|
channelId String
|
|
status String @default("pending")
|
|
reason String?
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
signature SmsSignature @relation(fields: [signatureId], references: [id])
|
|
channel SmsChannel @relation(fields: [channelId], references: [id])
|
|
records ChannelSignatureReportRecord[]
|
|
exportFiles ReportExportFile[]
|
|
receiptImports ReportReceiptImport[]
|
|
|
|
@@index([tenantId, status])
|
|
@@index([signatureId, channelId])
|
|
}
|
|
|
|
model ChannelSignatureReportRecord {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
channelId String
|
|
action String
|
|
statusBefore String?
|
|
statusAfter String
|
|
reason String?
|
|
operatorId String?
|
|
createdAt DateTime @default(now())
|
|
|
|
task ChannelSignatureReportTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
channel SmsChannel @relation(fields: [channelId], references: [id])
|
|
|
|
@@index([taskId, createdAt])
|
|
@@index([channelId, createdAt])
|
|
}
|
|
|
|
model ReportExportFile {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
fileObjectId String?
|
|
fileName String
|
|
rowCount Int @default(0)
|
|
status String @default("generated")
|
|
createdAt DateTime @default(now())
|
|
|
|
task ChannelSignatureReportTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model ReportReceiptImport {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
fileObjectId String?
|
|
fileName String
|
|
rowCount Int @default(0)
|
|
successCount Int @default(0)
|
|
failedCount Int @default(0)
|
|
status String @default("imported")
|
|
result Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
task ChannelSignatureReportTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
}
|