feat: complete cmpp platform phases 0-5
This commit is contained in:
@@ -0,0 +1,601 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user