Files
lislgosms/api/prisma/schema.prisma
T

1164 lines
36 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")
certificationStatus String @default("approved")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
users User[]
enterpriseCertifications EnterpriseCertification[]
operationLogs OperationLog[]
fileObjects FileObject[]
enterpriseBlacklists EnterpriseBlacklist[]
accounts TenantAccount[]
accountTransactions AccountTransaction[]
rechargeOrders RechargeOrder[]
smsBillingRecords SmsBillingRecord[]
smsApplications SmsApplication[]
smsSignatures SmsSignature[]
smsTemplates SmsTemplate[]
auditRecords AuditRecord[]
riskRules RiskRule[]
smsSendTasks SmsSendTask[]
riskHitRecords RiskHitRecord[]
smsBatchTasks SmsBatchTask[]
smsMessageRecords SmsMessageRecord[]
smsApiRequests SmsApiRequest[]
smsSubmitRecords SmsSubmitRecord[]
smsReceiptRecords SmsReceiptRecord[]
smsMessageSegmentAudits SmsMessageSegmentAudit[]
smsUplinkMessages SmsUplinkMessage[]
smsUplinkMatchCandidates SmsUplinkMatchCandidate[]
cmppDownstreamDeliveries CmppDownstreamDelivery[]
cmppConnectionStates CmppConnectionState[]
gatewayDownstreamRecoveryStatuses GatewayDownstreamRecoveryStatus[]
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
}
model EnterpriseCertification {
id String @id @default(cuid())
tenantId String
companyName String
licenseNo String?
contactName String?
contactPhone String?
materials Json?
status String @default("pending")
rejectReason String?
reviewerId String?
submittedAt DateTime @default(now())
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id])
@@index([tenantId, status, createdAt])
}
model User {
id String @id @default(cuid())
tenantId String?
username String @unique
email String? @unique
phone String? @unique
displayName String
passwordHash String
status String @default("active")
failedLoginCount Int @default(0)
lockedUntil DateTime?
lastLoginAt DateTime?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
roles UserRole[]
operationLogs OperationLog[]
auditRecords AuditRecord[]
createdSmsSendTasks SmsSendTask[] @relation("SmsSendTaskCreator")
reviewedSmsSendTasks SmsSendTask[] @relation("SmsSendTaskReviewer")
createdSmsBatchTasks SmsBatchTask[] @relation("SmsBatchTaskCreator")
}
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 PhoneCarrierRule {
id String @id @default(cuid())
carrier String
pattern String
priority Int @default(100)
status String @default("active")
remark String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([status, priority])
}
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?
cmppAccount String @unique
secretHash String
cmppMaxConnections Int @default(1)
cmppWindowSize Int @default(16)
dailyLimit Int?
customerUnitPrice Int @default(0)
queuePriority String @default("normal")
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[]
sendTasks SmsSendTask[]
batchTasks SmsBatchTask[]
messageRecords SmsMessageRecord[]
uplinkMessages SmsUplinkMessage[]
uplinkMatchCandidates SmsUplinkMatchCandidate[]
downstreamDeliveries CmppDownstreamDelivery[]
connectionStates CmppConnectionState[]
gatewayDownstreamRecoveryStatuses GatewayDownstreamRecoveryStatus[]
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
@@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[]
sendTasks SmsSendTask[]
batchTasks SmsBatchTask[]
messageRecords SmsMessageRecord[]
@@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?
sendRegion String @default("全国")
protocol String @default("CMPP")
gatewayHost String
gatewayPort Int
enterpriseCode String?
account String
passwordCipher String
srcId String
cmppVersion String @default("2.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[]
messageRecords SmsMessageRecord[]
submitSessions CmppSubmitSession[]
submitRecords SmsSubmitRecord[]
receiptRecords SmsReceiptRecord[]
segmentAudits SmsMessageSegmentAudit[]
uplinkMessages SmsUplinkMessage[]
connectionStates CmppConnectionState[]
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
@@index([status])
}
model CmppConnectionState {
id String @id @default(cuid())
tenantId String?
applicationId String?
channelId String
connectionId String
status String @default("disconnected")
desiredConnections Int @default(1)
currentConnections Int @default(0)
lastConnectedAt DateTime?
lastDisconnectedAt DateTime?
lastHeartbeatAt DateTime?
reconnectCount Int @default(0)
lastError String?
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
tenant Tenant? @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
channel SmsChannel @relation(fields: [channelId], references: [id])
@@unique([applicationId, channelId, connectionId])
@@index([tenantId, status])
@@index([applicationId, status])
@@index([channelId, status])
}
model SmsChannelGroup {
id String @id @default(cuid())
code String @unique
name String
description String?
carrier String @default("mobile")
status String @default("active")
retryEnabled Boolean @default(true)
retryTimeLimitHours Int @default(72)
retryTimeLimitMinutes Int @default(720)
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])
@@unique([groupId, 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)
}
model RiskRule {
id String @id @default(cuid())
tenantId String?
code String
name String
description String?
metric String
thresholdValue Float
action String @default("manual_review")
status String @default("active")
priority Int @default(100)
config Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
hits RiskHitRecord[]
@@unique([tenantId, code])
@@index([tenantId, status, priority])
}
model SmsSendTask {
id String @id @default(cuid())
tenantId String
applicationId String?
templateId String?
taskNo String @unique
content String
category String?
phoneTotal Int
uniquePhoneTotal Int
duplicateRatio Float @default(0)
illegalRatio Float @default(0)
blacklistHitRatio Float @default(0)
variableIssues Json?
status String @default("created")
riskDecision String @default("allow")
reviewReason String?
rejectReason String?
createdById String?
reviewedById String?
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
template SmsTemplate? @relation(fields: [templateId], references: [id])
createdBy User? @relation("SmsSendTaskCreator", fields: [createdById], references: [id])
reviewedBy User? @relation("SmsSendTaskReviewer", fields: [reviewedById], references: [id])
riskHits RiskHitRecord[]
@@index([tenantId, status, createdAt])
@@index([applicationId, createdAt])
}
model RiskHitRecord {
id String @id @default(cuid())
tenantId String
taskId String
ruleId String?
ruleCode String
ruleName String
thresholdValue Float
actualValue Float
action String
reason String
createdAt DateTime @default(now())
tenant Tenant @relation(fields: [tenantId], references: [id])
task SmsSendTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
rule RiskRule? @relation(fields: [ruleId], references: [id])
@@index([tenantId, createdAt])
@@index([taskId])
@@index([ruleCode])
}
model SmsBatchTask {
id String @id @default(cuid())
tenantId String
applicationId String?
templateId String?
taskNo String @unique
sourceType String @default("client")
content String
category String?
phoneTotal Int
status String @default("created")
riskTaskId String?
auditStatus String @default("approved")
reviewReason String?
rejectReason String?
progressTotal Int @default(0)
submittedTotal Int @default(0)
successTotal Int @default(0)
failedTotal Int @default(0)
unknownTotal Int @default(0)
timeoutTotal Int @default(0)
scheduledAt DateTime?
canceledAt DateTime?
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
template SmsTemplate? @relation(fields: [templateId], references: [id])
createdBy User? @relation("SmsBatchTaskCreator", fields: [createdById], references: [id])
apiRequests SmsApiRequest[]
messages SmsMessageRecord[]
submitRecords SmsSubmitRecord[]
receiptRecords SmsReceiptRecord[]
segmentAudits SmsMessageSegmentAudit[]
@@index([tenantId, status, createdAt])
@@index([status, scheduledAt])
@@index([applicationId, createdAt])
}
model SmsApiRequest {
id String @id @default(cuid())
tenantId String
batchTaskId String
requestId String @unique
sourceIp String?
userAgent String?
payloadSummary Json?
status String @default("accepted")
createdAt DateTime @default(now())
tenant Tenant @relation(fields: [tenantId], references: [id])
batchTask SmsBatchTask @relation(fields: [batchTaskId], references: [id], onDelete: Cascade)
@@index([tenantId, createdAt])
@@index([batchTaskId])
}
model SmsMessageRecord {
id String @id @default(cuid())
tenantId String?
batchTaskId String?
applicationId String?
templateId String?
messageId String @unique
phoneNumber String
content String
billingUnits Int @default(1)
unitPrice Int @default(0)
amountCents Int @default(0)
queuePriority String @default("normal")
channelId String?
submitId String?
gatewayMessageId String?
status String @default("queued")
submitStatus String?
receiptStatus String?
errorCode String?
errorMessage String?
queuedAt DateTime @default(now())
submittedAt DateTime?
deliveredAt DateTime?
timeoutAt DateTime?
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
batchTask SmsBatchTask? @relation(fields: [batchTaskId], references: [id], onDelete: Cascade)
application SmsApplication? @relation(fields: [applicationId], references: [id])
template SmsTemplate? @relation(fields: [templateId], references: [id])
channel SmsChannel? @relation(fields: [channelId], references: [id])
submitRecords SmsSubmitRecord[]
receiptRecords SmsReceiptRecord[]
segmentAudits SmsMessageSegmentAudit[]
matchedUplinks SmsUplinkMessage[] @relation("SmsUplinkMatchedMessage")
uplinkMatchCandidates SmsUplinkMatchCandidate[]
downstreamDeliveries CmppDownstreamDelivery[]
@@index([tenantId, status, queuedAt])
@@index([batchTaskId, status])
@@index([phoneNumber])
@@index([gatewayMessageId])
}
model CmppSubmitSession {
id String @id @default(cuid())
channelId String
sessionNo String @unique
status String @default("open")
submitTotal Int @default(0)
acceptedTotal Int @default(0)
rejectedTotal Int @default(0)
startedAt DateTime @default(now())
endedAt DateTime?
channel SmsChannel @relation(fields: [channelId], references: [id])
submitRecords SmsSubmitRecord[]
@@index([channelId, status])
}
model SmsSubmitRecord {
id String @id @default(cuid())
tenantId String?
batchTaskId String?
messageRecordId String
channelId String
sessionId String?
submitId String @unique
sequenceId Int?
gatewayMessageId String?
submitStatus String @default("queued")
errorCode String?
errorMessage String?
submittedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
batchTask SmsBatchTask? @relation(fields: [batchTaskId], references: [id], onDelete: Cascade)
messageRecord SmsMessageRecord @relation(fields: [messageRecordId], references: [id], onDelete: Cascade)
channel SmsChannel @relation(fields: [channelId], references: [id])
session CmppSubmitSession? @relation(fields: [sessionId], references: [id])
segmentAudits SmsMessageSegmentAudit[]
@@index([tenantId, createdAt])
@@index([messageRecordId])
@@index([gatewayMessageId])
}
model SmsMessageSegmentAudit {
id String @id @default(cuid())
tenantId String?
batchTaskId String?
messageRecordId String
submitRecordId String?
channelId String?
submitId String
attempt Int @default(0)
segmentTotal Int @default(1)
segmentIndex Int @default(1)
sequenceId Int?
gatewayMessageId String?
submitStatus String @default("queued")
receiptStatus String?
rawStatus String?
compensationType String?
errorCode String?
errorMessage String?
submittedAt DateTime?
deliveredAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
batchTask SmsBatchTask? @relation(fields: [batchTaskId], references: [id])
messageRecord SmsMessageRecord @relation(fields: [messageRecordId], references: [id], onDelete: Cascade)
submitRecord SmsSubmitRecord? @relation(fields: [submitRecordId], references: [id])
channel SmsChannel? @relation(fields: [channelId], references: [id])
@@unique([messageRecordId, submitId, segmentIndex])
@@index([tenantId, createdAt])
@@index([messageRecordId, segmentIndex])
@@index([submitRecordId])
@@index([gatewayMessageId])
@@index([submitStatus, receiptStatus])
}
model SmsReceiptRecord {
id String @id @default(cuid())
tenantId String?
batchTaskId String?
messageRecordId String?
channelId String?
messageId String
gatewayMessageId String
sequenceId Int?
receiptStatus String
rawStatus String
errorCode String?
deliveredAt DateTime
createdAt DateTime @default(now())
tenant Tenant? @relation(fields: [tenantId], references: [id])
batchTask SmsBatchTask? @relation(fields: [batchTaskId], references: [id])
messageRecord SmsMessageRecord? @relation(fields: [messageRecordId], references: [id])
channel SmsChannel? @relation(fields: [channelId], references: [id])
@@index([tenantId, createdAt])
@@index([messageId])
@@index([gatewayMessageId])
}
model SmsUplinkMessage {
id String @id @default(cuid())
tenantId String?
applicationId String?
channelId String
messageRecordId String?
messageId String?
sequenceId Int?
phoneNumber String
destId String
content String
matchStatus String @default("unmatched")
matchReason String?
receivedAt DateTime
createdAt DateTime @default(now())
tenant Tenant? @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
messageRecord SmsMessageRecord? @relation("SmsUplinkMatchedMessage", fields: [messageRecordId], references: [id])
channel SmsChannel @relation(fields: [channelId], references: [id])
matchCandidates SmsUplinkMatchCandidate[]
@@index([tenantId, createdAt])
@@index([applicationId, receivedAt])
@@index([channelId, receivedAt])
@@index([messageRecordId])
@@index([matchStatus])
@@index([phoneNumber])
}
model SmsUplinkMatchCandidate {
id String @id @default(cuid())
uplinkMessageId String
tenantId String
applicationId String
messageRecordId String?
matchSource String
confidence Int @default(50)
reason String?
status String @default("pending")
claimedAt DateTime?
claimedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
uplinkMessage SmsUplinkMessage @relation(fields: [uplinkMessageId], references: [id], onDelete: Cascade)
tenant Tenant @relation(fields: [tenantId], references: [id])
application SmsApplication @relation(fields: [applicationId], references: [id])
messageRecord SmsMessageRecord? @relation(fields: [messageRecordId], references: [id])
@@unique([uplinkMessageId, applicationId, messageRecordId])
@@index([uplinkMessageId, status])
@@index([tenantId, status, createdAt])
@@index([applicationId, status, createdAt])
@@index([messageRecordId])
}
model CmppDownstreamDelivery {
id String @id @default(cuid())
tenantId String
applicationId String
messageRecordId String?
messageId String?
deliveryType String
status String @default("pending")
payload Json
retryCount Int @default(0)
nextRetryAt DateTime?
deliveredAt DateTime?
lastError String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id])
application SmsApplication @relation(fields: [applicationId], references: [id])
messageRecord SmsMessageRecord? @relation(fields: [messageRecordId], references: [id])
@@index([tenantId, status, createdAt])
@@index([applicationId, status, createdAt])
@@index([messageId])
@@index([messageRecordId])
@@index([deliveryType, status])
}
model GatewaySubmitDeadLetter {
id String @id @default(cuid())
streamMessageId String @unique
tenantId String?
applicationId String?
channelId String?
traceId String?
messageId String?
submitId String?
status String @default("pending")
failureCode String
failureMessage String
attempts Int @default(1)
maxAttempts Int @default(3)
commandPayload Json?
rawPayload String?
manualRetryCount Int @default(0)
lastRetryStreamId String?
lastRetriedAt DateTime?
resolvedAt DateTime?
resolvedStatus String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
channel SmsChannel? @relation(fields: [channelId], references: [id])
@@index([status, createdAt])
@@index([tenantId, status, createdAt])
@@index([applicationId, status, createdAt])
@@index([channelId, status, createdAt])
@@index([messageId])
@@index([submitId])
}
model GatewayDownstreamRecoveryStatus {
id String @id @default(cuid())
account String @unique
tenantId String?
applicationId String?
gatewayInstanceId String?
state String
lockOwner String?
lockExpiresAt DateTime?
lastAttemptAt DateTime?
lastSuccessAt DateTime?
lastFailureAt DateTime?
nextRetryAt DateTime?
attemptCount Int @default(0)
failureCategory String?
lastError String?
lastSkipReason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant? @relation(fields: [tenantId], references: [id])
application SmsApplication? @relation(fields: [applicationId], references: [id])
@@index([tenantId, state, updatedAt])
@@index([applicationId, state, updatedAt])
@@index([failureCategory, updatedAt])
@@index([lockOwner, lockExpiresAt])
@@index([state, updatedAt])
@@index([nextRetryAt])
}