2467 lines
81 KiB
Plaintext
2467 lines
81 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[]
|
|
smsDrainageInfos SmsDrainageInfo[]
|
|
smsTemplates SmsTemplate[]
|
|
auditRecords AuditRecord[]
|
|
riskRules RiskRule[]
|
|
smsSendTasks SmsSendTask[]
|
|
riskHitRecords RiskHitRecord[]
|
|
phoneFrequencyStates PhoneFrequencyState[]
|
|
phoneFrequencyHits PhoneFrequencyHit[]
|
|
smsBatchTasks SmsBatchTask[]
|
|
smsMessageRecords SmsMessageRecord[]
|
|
smsApiRequests SmsApiRequest[]
|
|
smsSubmitRecords SmsSubmitRecord[]
|
|
smsReceiptRecords SmsReceiptRecord[]
|
|
smsMessageSegmentAudits SmsMessageSegmentAudit[]
|
|
smsUplinkMessages SmsUplinkMessage[]
|
|
smsUplinkMatchCandidates SmsUplinkMatchCandidate[]
|
|
cmppDownstreamDeliveries CmppDownstreamDelivery[]
|
|
downstreamRequeueTasks DownstreamRequeueTask[]
|
|
cmppDownstreamConnections CmppDownstreamConnection[]
|
|
cmppConnectionStates CmppConnectionState[]
|
|
gatewayDownstreamRecoveryStatuses GatewayDownstreamRecoveryStatus[]
|
|
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
|
|
smsReceiptAnomalies SmsReceiptAnomaly[]
|
|
openApiRequests OpenApiRequest[]
|
|
httpWebhookEvents HttpWebhookEvent[]
|
|
cmppInboundLongMessages CmppInboundLongMessage[]
|
|
}
|
|
|
|
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
|
|
email String?
|
|
phone String?
|
|
displayName String
|
|
passwordHash String
|
|
status String @default("active")
|
|
sessionVersion Int @default(0)
|
|
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")
|
|
createdDownstreamRequeueTasks DownstreamRequeueTask[] @relation("DownstreamRequeueTaskCreator")
|
|
releasedPhoneFrequencyHits PhoneFrequencyHit[] @relation("PhoneFrequencyHitReleaser")
|
|
createdPhoneFrequencyWhitelistEntries PhoneFrequencyWhitelist[] @relation("PhoneFrequencyWhitelistCreator")
|
|
updatedPhoneFrequencyWhitelistEntries PhoneFrequencyWhitelist[] @relation("PhoneFrequencyWhitelistUpdater")
|
|
infrastructureAlertReads InfrastructureAlertRead[]
|
|
}
|
|
|
|
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])
|
|
@@index([createdAt])
|
|
@@index([resource, createdAt])
|
|
}
|
|
|
|
model OperationLogArchive {
|
|
originalId String @id
|
|
tenantId String?
|
|
userId String?
|
|
action String
|
|
resource String
|
|
resourceId String?
|
|
ipAddress String?
|
|
userAgent String?
|
|
detail Json?
|
|
createdAt DateTime
|
|
archiveMonth String
|
|
archivedAt DateTime @default(now())
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([userId, createdAt])
|
|
@@index([createdAt])
|
|
@@index([resource, createdAt])
|
|
@@index([archiveMonth])
|
|
}
|
|
|
|
model ProtocolInteractionLog {
|
|
id String @id @default(cuid())
|
|
protocol String
|
|
direction String
|
|
eventType String
|
|
status String
|
|
tenantId String?
|
|
applicationId String?
|
|
channelId String?
|
|
account String?
|
|
messageId String?
|
|
gatewayMessageId String?
|
|
traceId String?
|
|
requestId String?
|
|
phoneMasked String?
|
|
phoneNumber String?
|
|
resultCode String?
|
|
durationMs Int?
|
|
payloadBytes Int?
|
|
retryCount Int?
|
|
detail Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([createdAt])
|
|
@@index([protocol, direction, createdAt])
|
|
@@index([eventType, createdAt])
|
|
@@index([status, createdAt])
|
|
@@index([channelId, createdAt])
|
|
@@index([applicationId, createdAt])
|
|
@@index([messageId])
|
|
@@index([gatewayMessageId])
|
|
@@index([requestId])
|
|
}
|
|
|
|
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
|
|
applicationId String
|
|
phoneNumber String
|
|
reason String?
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id])
|
|
|
|
@@unique([applicationId, 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
|
|
|
|
channelReportFields ChannelReportField[]
|
|
commonReportFields CommonReportField[]
|
|
}
|
|
|
|
model DrainageDetectionRule {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
category String
|
|
pattern String
|
|
flags String @default("giu")
|
|
priority Int @default(100)
|
|
status String @default("active")
|
|
description String?
|
|
version Int @default(1)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status, priority])
|
|
}
|
|
|
|
model TenantAccount {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
balanceCents BigInt @default(0)
|
|
creditCents BigInt @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
|
|
idempotencyKey String? @unique
|
|
amountCents BigInt @default(0)
|
|
balanceAfter BigInt @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 BigInt
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model RechargeOrder {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
orderNo String @unique
|
|
amountCents BigInt
|
|
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])
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([payMethod, createdAt])
|
|
}
|
|
|
|
model SmsBillingRecord {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String?
|
|
taskId String?
|
|
messageId String?
|
|
phoneNumber String?
|
|
contentLength Int
|
|
billingUnits Int
|
|
unitPrice BigInt
|
|
amountCents BigInt
|
|
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
|
|
cmppEnterpriseCode String
|
|
cmppApplicationExtension String?
|
|
cmppAccessNumberFillEnabled Boolean @default(false)
|
|
cmppAccessNumberFillPrefix String?
|
|
cmppClientSrcId String? @unique
|
|
secretHash String
|
|
interfaceEnabled Boolean @default(true)
|
|
interfaceType String @default("cmpp20")
|
|
cmppMaxConnections Int @default(1)
|
|
cmppWindowSize Int @default(16)
|
|
dailyLimit Int @default(100000)
|
|
customerUnitPrice BigInt @default(0)
|
|
queuePriority String @default("normal")
|
|
templateMismatchMode String @default("reject")
|
|
downstreamReceiptRetryEnabled Boolean @default(true)
|
|
downstreamUplinkRetryEnabled Boolean @default(true)
|
|
status String @default("active")
|
|
disablingAt DateTime?
|
|
autoDisableAt DateTime?
|
|
disableReason String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
ipAllowlist SmsApplicationIpAllowlist[]
|
|
signatures SmsSignature[]
|
|
drainageInfos SmsDrainageInfo[]
|
|
templates SmsTemplate[]
|
|
enterpriseBlacklists EnterpriseBlacklist[]
|
|
sendTasks SmsSendTask[]
|
|
batchTasks SmsBatchTask[]
|
|
messageRecords SmsMessageRecord[]
|
|
uplinkMessages SmsUplinkMessage[]
|
|
uplinkMatchCandidates SmsUplinkMatchCandidate[]
|
|
downstreamDeliveries CmppDownstreamDelivery[]
|
|
downstreamRequeueTasks DownstreamRequeueTask[]
|
|
downstreamConnections CmppDownstreamConnection[]
|
|
connectionStates CmppConnectionState[]
|
|
gatewayDownstreamRecoveryStatuses GatewayDownstreamRecoveryStatus[]
|
|
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
|
|
receiptAnomalies SmsReceiptAnomaly[]
|
|
httpConfig SmsApplicationHttpConfig?
|
|
httpIpAllowlist SmsApplicationHttpIpAllowlist[]
|
|
httpApiCredentials HttpApiCredential[]
|
|
openApiRequests OpenApiRequest[]
|
|
httpWebhookEndpoints HttpWebhookEndpoint[]
|
|
httpWebhookEvents HttpWebhookEvent[]
|
|
dailyUsages SmsApplicationDailyUsage[]
|
|
inboundLongMessages CmppInboundLongMessage[]
|
|
riskRules RiskRule[]
|
|
phoneFrequencyStates PhoneFrequencyState[]
|
|
phoneFrequencyHits PhoneFrequencyHit[]
|
|
|
|
@@index([tenantId, status])
|
|
@@index([status, createdAt])
|
|
@@index([status, autoDisableAt])
|
|
}
|
|
|
|
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 SmsApplicationHttpConfig {
|
|
id String @id @default(cuid())
|
|
applicationId String @unique
|
|
enabled Boolean @default(false)
|
|
sendEnabled Boolean @default(true)
|
|
messageQueryEnabled Boolean @default(true)
|
|
receiptWebhookEnabled Boolean @default(true)
|
|
uplinkWebhookEnabled Boolean @default(true)
|
|
uplinkQueryEnabled Boolean @default(true)
|
|
credentialSelfServiceEnabled Boolean @default(true)
|
|
qpsLimit Int @default(10)
|
|
timestampToleranceSeconds Int @default(300)
|
|
maxCredentialCount Int @default(2)
|
|
uplinkRetentionDays Int @default(90)
|
|
maxQueryRangeDays Int @default(31)
|
|
maxPageSize Int @default(100)
|
|
receiptDeliveryMode String @default("http")
|
|
uplinkDeliveryMode String @default("http")
|
|
webhookRetryEnabled Boolean @default(true)
|
|
webhookMaxAttempts Int @default(7)
|
|
webhookTimeoutSeconds Int @default(10)
|
|
requireHttps Boolean @default(true)
|
|
allowClientManualRetry Boolean @default(true)
|
|
allowClientTest Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model SmsApplicationDailyUsage {
|
|
id String @id @default(cuid())
|
|
applicationId String
|
|
usageDate DateTime @db.Date
|
|
usedCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([applicationId, usageDate])
|
|
@@index([usageDate])
|
|
}
|
|
|
|
model SmsApplicationHttpIpAllowlist {
|
|
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 HttpApiCredential {
|
|
id String @id @default(cuid())
|
|
applicationId String
|
|
name String
|
|
accessKey String @unique
|
|
secretEncrypted String
|
|
secretLast4 String
|
|
status String @default("active")
|
|
expiresAt DateTime?
|
|
lastUsedAt DateTime?
|
|
lastUsedIp String?
|
|
createdById String?
|
|
revokedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
requests OpenApiRequest[]
|
|
|
|
@@index([applicationId, status])
|
|
}
|
|
|
|
model OpenApiRequest {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
credentialId String
|
|
requestId String @unique
|
|
idempotencyKey String
|
|
bodyHash String
|
|
clientMessageId String?
|
|
messageRecordId String?
|
|
httpStatus Int?
|
|
businessCode String?
|
|
responseBody Json?
|
|
sourceIp String?
|
|
userAgent String?
|
|
durationMs Int?
|
|
status String @default("processing")
|
|
completedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
credential HttpApiCredential @relation(fields: [credentialId], references: [id])
|
|
|
|
@@unique([applicationId, idempotencyKey])
|
|
@@index([applicationId, createdAt])
|
|
}
|
|
|
|
model HttpWebhookEndpoint {
|
|
id String @id @default(cuid())
|
|
applicationId String
|
|
eventType String
|
|
url String
|
|
secretEncrypted String
|
|
secretLast4 String
|
|
status String @default("active")
|
|
lastTestAt DateTime?
|
|
lastTestStatus String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
deliveries HttpWebhookDelivery[]
|
|
|
|
@@unique([applicationId, eventType])
|
|
}
|
|
|
|
model HttpWebhookEvent {
|
|
id String @id @default(cuid())
|
|
eventId String @unique
|
|
tenantId String
|
|
applicationId String
|
|
eventType String
|
|
messageRecordId String?
|
|
messageId String?
|
|
uplinkMessageId String?
|
|
payload Json
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
deliveries HttpWebhookDelivery[]
|
|
|
|
@@index([applicationId, createdAt])
|
|
}
|
|
|
|
model HttpWebhookDelivery {
|
|
id String @id @default(cuid())
|
|
eventId String
|
|
endpointId String
|
|
status String @default("pending")
|
|
attemptCount Int @default(0)
|
|
nextRetryAt DateTime?
|
|
lastHttpStatus Int?
|
|
lastError String?
|
|
deliveredAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
event HttpWebhookEvent @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
|
endpoint HttpWebhookEndpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade)
|
|
attempts HttpWebhookAttempt[]
|
|
|
|
@@unique([eventId, endpointId])
|
|
@@index([status, nextRetryAt])
|
|
}
|
|
|
|
model HttpWebhookAttempt {
|
|
id String @id @default(cuid())
|
|
deliveryId String
|
|
attemptNo Int
|
|
requestHeaders Json?
|
|
responseStatus Int?
|
|
responseSummary String?
|
|
errorMessage String?
|
|
durationMs Int?
|
|
createdAt DateTime @default(now())
|
|
|
|
delivery HttpWebhookDelivery @relation(fields: [deliveryId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([deliveryId, attemptNo])
|
|
}
|
|
|
|
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?
|
|
materialVersion Int @default(1)
|
|
pendingReport Boolean @default(true)
|
|
reportChangedAt DateTime @default(now())
|
|
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[]
|
|
drainageReportMaterials DrainageReportMaterial[]
|
|
drainageItems SmsDrainageInfo[]
|
|
reportTasks ChannelSignatureReportTask[]
|
|
messageRecords SmsMessageRecord[]
|
|
reportBatchItems ReportMaterialBatchItem[]
|
|
|
|
@@index([tenantId, auditStatus])
|
|
@@index([tenantId, updatedAt])
|
|
@@index([tenantId, reportStatus])
|
|
}
|
|
|
|
model SmsDrainageInfo {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
signatureId String
|
|
applicationId String?
|
|
siteName String
|
|
url String
|
|
remark String?
|
|
reportValues Json?
|
|
auditStatus String @default("pending")
|
|
rejectReason String?
|
|
materialVersion Int @default(1)
|
|
pendingReport Boolean @default(true)
|
|
reportChangedAt DateTime @default(now())
|
|
submittedAt DateTime @default(now())
|
|
reviewedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
signature SmsSignature @relation(fields: [signatureId], references: [id], onDelete: Cascade)
|
|
application SmsApplication? @relation(fields: [applicationId], references: [id])
|
|
reportTasks ChannelSignatureReportTask[]
|
|
messageRecords SmsMessageRecord[]
|
|
reportBatchItems ReportMaterialBatchItem[]
|
|
|
|
@@index([tenantId, auditStatus, updatedAt])
|
|
@@index([signatureId, auditStatus])
|
|
@@index([applicationId])
|
|
}
|
|
|
|
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, createdAt])
|
|
@@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?
|
|
carriers String[] @default([])
|
|
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 BigInt @default(0)
|
|
status String @default("active")
|
|
config Json?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
groupItems SmsChannelGroupItem[]
|
|
routeRules ChannelRouteRule[]
|
|
healthMetrics ChannelHealthMetric[]
|
|
reportFields ChannelReportField[]
|
|
drainageReportMaterials DrainageReportMaterial[]
|
|
reportTasks ChannelSignatureReportTask[]
|
|
reportRecords ChannelSignatureReportRecord[]
|
|
messageRecords SmsMessageRecord[]
|
|
submitSessions CmppSubmitSession[]
|
|
submitRecords SmsSubmitRecord[]
|
|
receiptRecords SmsReceiptRecord[]
|
|
segmentAudits SmsMessageSegmentAudit[]
|
|
uplinkMessages SmsUplinkMessage[]
|
|
connectionStates CmppConnectionState[]
|
|
gatewaySubmitDeadLetters GatewaySubmitDeadLetter[]
|
|
receiptAnomalies SmsReceiptAnomaly[]
|
|
|
|
@@index([status])
|
|
@@index([status, createdAt])
|
|
}
|
|
|
|
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)
|
|
lastReconnectAttemptAt DateTime?
|
|
nextReconnectAt DateTime?
|
|
lastErrorCategory String?
|
|
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])
|
|
@@index([status, nextReconnectAt])
|
|
}
|
|
|
|
model CmppDownstreamConnection {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
account String
|
|
enterpriseCode String
|
|
connectionId String @unique
|
|
remoteIp String?
|
|
protocol String?
|
|
status String @default("connected")
|
|
connectedAt DateTime @default(now())
|
|
lastHeartbeatAt DateTime?
|
|
lastSubmitAt DateTime?
|
|
lastDeliverAt DateTime?
|
|
disconnectedAt DateTime?
|
|
lastError String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id])
|
|
|
|
@@index([applicationId, status, updatedAt])
|
|
@@index([tenantId, status, updatedAt])
|
|
@@index([account, 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[]
|
|
submitRecords SmsSubmitRecord[]
|
|
}
|
|
|
|
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)
|
|
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
|
|
drainageFieldId String?
|
|
reportType String @default("both")
|
|
code String
|
|
name String
|
|
exportName String?
|
|
fieldType String
|
|
required Boolean @default(false)
|
|
description String?
|
|
sortOrder Int @default(100)
|
|
columnWidth Int @default(18)
|
|
imageWidth Int @default(120)
|
|
imageHeight Int @default(80)
|
|
defaultValue String?
|
|
transform String?
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
channel SmsChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
|
|
drainageField DrainageField? @relation(fields: [drainageFieldId], references: [id])
|
|
|
|
@@unique([channelId, code, reportType])
|
|
@@index([drainageFieldId, reportType])
|
|
}
|
|
|
|
model CommonReportField {
|
|
id String @id @default(cuid())
|
|
drainageFieldId String
|
|
reportType String
|
|
required Boolean @default(false)
|
|
sortOrder Int @default(100)
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
drainageField DrainageField @relation(fields: [drainageFieldId], references: [id], onDelete: Restrict)
|
|
|
|
@@unique([drainageFieldId, reportType])
|
|
@@index([reportType, status, sortOrder])
|
|
}
|
|
|
|
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 DrainageReportMaterial {
|
|
id String @id @default(cuid())
|
|
signatureId String
|
|
drainageItemId 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)
|
|
channel SmsChannel @relation(fields: [channelId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([signatureId, drainageItemId, channelId, fieldCode])
|
|
@@index([channelId, fieldCode])
|
|
}
|
|
|
|
model ChannelSignatureReportTask {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
signatureId String
|
|
channelId String
|
|
carrier String?
|
|
approvedAt DateTime?
|
|
approvalScope String @default("legacy_channel")
|
|
reportType String @default("signature")
|
|
drainageItemId 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])
|
|
drainageInfo SmsDrainageInfo? @relation(fields: [drainageItemId], references: [id])
|
|
records ChannelSignatureReportRecord[]
|
|
exportFiles ReportExportFile[]
|
|
receiptImports ReportReceiptImport[]
|
|
exportItems ReportExportFileItem[]
|
|
|
|
@@index([tenantId, status])
|
|
@@index([status, createdAt])
|
|
@@index([signatureId, channelId])
|
|
@@index([signatureId, channelId, carrier])
|
|
@@index([signatureId, drainageItemId, channelId])
|
|
@@index([reportType, status])
|
|
}
|
|
|
|
model SignatureRetirementRule {
|
|
id String @id @default(cuid())
|
|
ruleType String
|
|
targetId String?
|
|
targetKey String @default("")
|
|
enabled Boolean @default(true)
|
|
mobileWindowDays Int @default(30)
|
|
mobileThreshold Int @default(1)
|
|
unicomWindowDays Int @default(30)
|
|
unicomThreshold Int @default(1)
|
|
telecomWindowDays Int @default(30)
|
|
telecomThreshold Int @default(1)
|
|
messageTemplate String?
|
|
version Int @default(1)
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([ruleType, targetKey])
|
|
@@index([ruleType, enabled])
|
|
}
|
|
|
|
model SignatureRetirementWebhook {
|
|
id String @id @default(cuid())
|
|
name String
|
|
platform String
|
|
urlEncrypted String
|
|
urlMasked String
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status, createdAt])
|
|
}
|
|
|
|
model SignatureRetirementCycle {
|
|
id String @id @default(cuid())
|
|
dimensionType String
|
|
signatureId String
|
|
channelId String?
|
|
channelKey String @default("")
|
|
carrier String
|
|
status String @default("open")
|
|
startedOn DateTime @db.Date
|
|
lastDetectedOn DateTime @db.Date
|
|
resolvedOn DateTime? @db.Date
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([dimensionType, signatureId, channelKey, carrier, status])
|
|
@@index([status, lastDetectedOn])
|
|
}
|
|
|
|
model SignatureRetirementDetection {
|
|
id String @id @default(cuid())
|
|
detectionDate DateTime @db.Date
|
|
dimensionType String
|
|
tenantId String
|
|
applicationId String?
|
|
signatureId String
|
|
channelId String?
|
|
channelKey String @default("")
|
|
carrier String
|
|
windowDays Int
|
|
threshold Int
|
|
submittedAttempts Int @default(0)
|
|
acceptedBusinessCount Int @default(0)
|
|
deliveredBusinessCount Int @default(0)
|
|
approvedAt DateTime
|
|
ruleId String?
|
|
ruleVersion Int @default(1)
|
|
status String
|
|
cycleId String?
|
|
suppressed Boolean @default(false)
|
|
notificationTitle String?
|
|
notificationContent String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([detectionDate, dimensionType, signatureId, channelKey, carrier])
|
|
@@index([detectionDate, dimensionType, status])
|
|
@@index([signatureId, carrier, detectionDate])
|
|
@@index([channelId, carrier, detectionDate])
|
|
}
|
|
|
|
model SignatureRetirementMessage {
|
|
id String @id @default(cuid())
|
|
detectionId String @unique
|
|
cycleId String
|
|
tenantId String
|
|
title String
|
|
content String
|
|
isRead Boolean @default(false)
|
|
suppressed Boolean @default(false)
|
|
readAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([createdAt, isRead, suppressed])
|
|
@@index([tenantId, createdAt])
|
|
}
|
|
|
|
model SignatureRetirementSuppression {
|
|
id String @id @default(cuid())
|
|
dimensionType String
|
|
signatureId String
|
|
channelId String?
|
|
channelKey String @default("")
|
|
carrier String
|
|
mode String
|
|
muteUntil DateTime? @db.Date
|
|
active Boolean @default(true)
|
|
reason String?
|
|
operatorId String?
|
|
cancelledAt DateTime?
|
|
cancelledById String?
|
|
cancelReason String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([dimensionType, signatureId, channelKey, carrier])
|
|
@@index([active, muteUntil])
|
|
}
|
|
|
|
model SignatureRetirementWebhookDelivery {
|
|
id String @id @default(cuid())
|
|
detectionDate DateTime @db.Date
|
|
webhookId String
|
|
groupKey String
|
|
payload Json
|
|
status String @default("pending")
|
|
attemptCount Int @default(0)
|
|
nextRetryAt DateTime?
|
|
lastHttpStatus Int?
|
|
lastError String?
|
|
deliveredAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([webhookId, detectionDate, groupKey])
|
|
@@index([status, nextRetryAt])
|
|
}
|
|
|
|
model ChannelSignatureReportRecord {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
channelId String
|
|
action String
|
|
statusBefore String?
|
|
statusAfter String
|
|
reason String?
|
|
operatorId String?
|
|
sourceEntry String @default("system")
|
|
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])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model ReportExportFile {
|
|
id String @id @default(cuid())
|
|
taskId String?
|
|
batchId String?
|
|
channelId 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)
|
|
batch ReportMaterialBatch? @relation(fields: [batchId], references: [id], onDelete: Cascade)
|
|
items ReportExportFileItem[]
|
|
|
|
@@index([batchId, channelId])
|
|
}
|
|
|
|
model ReportMaterialBatch {
|
|
id String @id @default(cuid())
|
|
batchNo String @unique
|
|
status String @default("generating")
|
|
createdById String?
|
|
selectedCount Int @default(0)
|
|
channelCount Int @default(0)
|
|
fileCount Int @default(0)
|
|
errorMessage String?
|
|
createdAt DateTime @default(now())
|
|
completedAt DateTime?
|
|
|
|
items ReportMaterialBatchItem[]
|
|
exportFiles ReportExportFile[]
|
|
|
|
@@index([status, createdAt])
|
|
}
|
|
|
|
model ReportMaterialBatchItem {
|
|
id String @id @default(cuid())
|
|
batchId String
|
|
signatureId String
|
|
drainageItemId String?
|
|
reportType String
|
|
materialVersion Int
|
|
snapshot Json
|
|
createdAt DateTime @default(now())
|
|
|
|
batch ReportMaterialBatch @relation(fields: [batchId], references: [id], onDelete: Cascade)
|
|
signature SmsSignature @relation(fields: [signatureId], references: [id])
|
|
drainageInfo SmsDrainageInfo? @relation(fields: [drainageItemId], references: [id])
|
|
exportItems ReportExportFileItem[]
|
|
|
|
@@index([batchId, reportType])
|
|
@@index([signatureId, drainageItemId])
|
|
}
|
|
|
|
model ReportExportFileItem {
|
|
id String @id @default(cuid())
|
|
exportFileId String
|
|
batchItemId String
|
|
taskId String
|
|
rowNumber Int
|
|
|
|
exportFile ReportExportFile @relation(fields: [exportFileId], references: [id], onDelete: Cascade)
|
|
batchItem ReportMaterialBatchItem @relation(fields: [batchItemId], references: [id], onDelete: Cascade)
|
|
task ChannelSignatureReportTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([exportFileId, batchItemId])
|
|
@@index([taskId])
|
|
}
|
|
|
|
model ReportMaterialImportProfile {
|
|
id String @id @default(cuid())
|
|
name String
|
|
reportType String
|
|
tenantId String?
|
|
applicationId String?
|
|
sheetName String?
|
|
headerRowCount Int @default(1)
|
|
dataStartRow Int @default(2)
|
|
status String @default("active")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
columns ReportMaterialImportProfileColumn[]
|
|
|
|
@@index([reportType, status])
|
|
@@index([tenantId, applicationId])
|
|
}
|
|
|
|
model ReportMaterialImportProfileColumn {
|
|
id String @id @default(cuid())
|
|
profileId String
|
|
sourceHeader String
|
|
sourceHeaderPath String?
|
|
sourceColumnIndex Int
|
|
targetFieldCode String
|
|
targetKind String @default("dynamic")
|
|
fieldType String @default("string")
|
|
required Boolean @default(false)
|
|
transform String?
|
|
sortOrder Int @default(100)
|
|
createdAt DateTime @default(now())
|
|
|
|
profile ReportMaterialImportProfile @relation(fields: [profileId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([profileId, sourceColumnIndex])
|
|
@@index([profileId, sortOrder])
|
|
}
|
|
|
|
model ReportMaterialImportBatch {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String?
|
|
profileId String?
|
|
fileObjectId String
|
|
fileName String
|
|
reportType String
|
|
status String @default("analyzed")
|
|
sheetName String
|
|
headerRowCount Int @default(1)
|
|
dataStartRow Int @default(2)
|
|
mapping Json
|
|
preview Json?
|
|
result Json?
|
|
rowCount Int @default(0)
|
|
successCount Int @default(0)
|
|
failedCount Int @default(0)
|
|
reviewedById String?
|
|
reviewedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
completedAt DateTime?
|
|
|
|
items ReportMaterialImportItem[]
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([status, createdAt])
|
|
}
|
|
|
|
model ReportMaterialImportItem {
|
|
id String @id @default(cuid())
|
|
batchId String
|
|
rowNumber Int
|
|
reportType String
|
|
operation String
|
|
targetId String?
|
|
status String @default("pending_review")
|
|
payload Json
|
|
originalSnapshot Json?
|
|
errorMessage String?
|
|
reviewReason String?
|
|
reviewedById String?
|
|
reviewedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
batch ReportMaterialImportBatch @relation(fields: [batchId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([batchId, rowNumber])
|
|
@@index([batchId, status])
|
|
@@index([reportType, status, createdAt])
|
|
@@index([targetId])
|
|
}
|
|
|
|
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?
|
|
applicationId 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])
|
|
application SmsApplication? @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
hits RiskHitRecord[]
|
|
phoneFrequencyStates PhoneFrequencyState[]
|
|
phoneFrequencyHits PhoneFrequencyHit[]
|
|
|
|
@@unique([applicationId, code])
|
|
@@index([tenantId, applicationId, status, priority])
|
|
}
|
|
|
|
model SmsSendTask {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String?
|
|
templateId String?
|
|
taskNo String @unique
|
|
sourceType String @default("risk")
|
|
aggregationKey String? @unique
|
|
contentHash String?
|
|
windowStartedAt DateTime?
|
|
windowEndsAt DateTime?
|
|
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[]
|
|
messageRecords SmsMessageRecord[]
|
|
|
|
@@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 PhoneFrequencyState {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
ruleId String?
|
|
ruleCode String
|
|
phoneNumber String
|
|
windowStartedAt DateTime
|
|
windowEndsAt DateTime
|
|
count Int @default(0)
|
|
generation Int @default(0)
|
|
activeHitId String? @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
rule RiskRule? @relation(fields: [ruleId], references: [id], onDelete: SetNull)
|
|
activeHit PhoneFrequencyHit? @relation("ActivePhoneFrequencyHit", fields: [activeHitId], references: [id], onDelete: SetNull)
|
|
|
|
@@unique([applicationId, ruleCode, phoneNumber])
|
|
@@index([tenantId, applicationId, windowEndsAt])
|
|
@@index([ruleId])
|
|
}
|
|
|
|
model PhoneFrequencyHit {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
ruleId String?
|
|
ruleCode String
|
|
ruleName String
|
|
phoneNumber String
|
|
thresholdValue Int
|
|
actualValue Int
|
|
windowStartedAt DateTime
|
|
windowEndsAt DateTime
|
|
generation Int @default(0)
|
|
action String @default("block")
|
|
sourceType String?
|
|
releasedAt DateTime?
|
|
releasedById String?
|
|
releaseReason String?
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id])
|
|
rule RiskRule? @relation(fields: [ruleId], references: [id], onDelete: SetNull)
|
|
releasedBy User? @relation("PhoneFrequencyHitReleaser", fields: [releasedById], references: [id])
|
|
activeForState PhoneFrequencyState? @relation("ActivePhoneFrequencyHit")
|
|
|
|
@@unique([applicationId, ruleCode, phoneNumber, windowStartedAt, generation])
|
|
@@index([tenantId, applicationId, createdAt])
|
|
@@index([applicationId, phoneNumber, createdAt])
|
|
@@index([windowEndsAt, releasedAt])
|
|
@@index([ruleId])
|
|
@@index([releasedById])
|
|
}
|
|
|
|
model PhoneFrequencyWhitelist {
|
|
id String @id @default(cuid())
|
|
phoneNumber String @unique
|
|
status String @default("active")
|
|
reason String
|
|
remark String?
|
|
createdById String
|
|
updatedById String
|
|
deletedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
createdBy User @relation("PhoneFrequencyWhitelistCreator", fields: [createdById], references: [id])
|
|
updatedBy User @relation("PhoneFrequencyWhitelistUpdater", fields: [updatedById], references: [id])
|
|
|
|
@@index([status, updatedAt])
|
|
@@index([createdById])
|
|
@@index([updatedById])
|
|
}
|
|
|
|
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?
|
|
signatureId String?
|
|
drainageInfoId String?
|
|
reviewTaskId String?
|
|
messageId String @unique
|
|
clientMessageId String?
|
|
phoneNumber String
|
|
carrier String?
|
|
province String?
|
|
content String
|
|
hasDrainageContent Boolean?
|
|
drainageDetection Json?
|
|
drainageDetectionVersion String?
|
|
drainageEvaluatedAt DateTime?
|
|
billingUnits Int @default(1)
|
|
unitPrice BigInt @default(0)
|
|
amountCents BigInt @default(0)
|
|
queuePriority String @default("normal")
|
|
channelId String?
|
|
submitId String?
|
|
gatewayMessageId String?
|
|
cmppSubmitSequenceId String?
|
|
cmppSubmitGroupMessageId String?
|
|
cmppRegisteredDelivery Boolean?
|
|
clientSrcId String?
|
|
applicationExtension String?
|
|
status String @default("queued")
|
|
submitStatus String?
|
|
receiptStatus String?
|
|
receiptRawStatus String?
|
|
errorCode String?
|
|
errorMessage String?
|
|
queuedAt DateTime @default(now())
|
|
submittedAt DateTime?
|
|
deliveredAt DateTime?
|
|
timeoutAt DateTime?
|
|
timeoutReceiptQueuedAt 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])
|
|
signature SmsSignature? @relation(fields: [signatureId], references: [id])
|
|
drainageInfo SmsDrainageInfo? @relation(fields: [drainageInfoId], references: [id])
|
|
reviewTask SmsSendTask? @relation(fields: [reviewTaskId], references: [id])
|
|
channel SmsChannel? @relation(fields: [channelId], references: [id])
|
|
submitRecords SmsSubmitRecord[]
|
|
receiptRecords SmsReceiptRecord[]
|
|
segmentAudits SmsMessageSegmentAudit[]
|
|
receiptAnomalies SmsReceiptAnomaly[]
|
|
matchedUplinks SmsUplinkMessage[] @relation("SmsUplinkMatchedMessage")
|
|
uplinkMatchCandidates SmsUplinkMatchCandidate[]
|
|
downstreamDeliveries CmppDownstreamDelivery[]
|
|
|
|
@@unique([applicationId, clientMessageId])
|
|
@@index([tenantId, status, queuedAt])
|
|
@@index([queuedAt])
|
|
@@index([batchTaskId, status])
|
|
@@index([reviewTaskId, status])
|
|
@@index([phoneNumber])
|
|
@@index([gatewayMessageId])
|
|
@@index([drainageInfoId, queuedAt])
|
|
@@index([hasDrainageContent, queuedAt])
|
|
}
|
|
|
|
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
|
|
channelGroupId String?
|
|
channelGroupName String?
|
|
sessionId String?
|
|
retryOfSubmitRecordId String? @unique
|
|
submitId String @unique
|
|
sequenceId Int?
|
|
gatewayMessageId String?
|
|
submitStatus String @default("queued")
|
|
resultEventId String? @unique
|
|
resultProcessedAt DateTime?
|
|
costUnitPrice BigInt @default(0)
|
|
costAmountCents BigInt @default(0)
|
|
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])
|
|
channelGroup SmsChannelGroup? @relation(fields: [channelGroupId], references: [id], onDelete: SetNull)
|
|
session CmppSubmitSession? @relation(fields: [sessionId], references: [id])
|
|
retryOfSubmitRecord SmsSubmitRecord? @relation("SmsSubmitRetry", fields: [retryOfSubmitRecordId], references: [id])
|
|
retrySubmit SmsSubmitRecord? @relation("SmsSubmitRetry")
|
|
segmentAudits SmsMessageSegmentAudit[]
|
|
receiptAnomalies SmsReceiptAnomaly[]
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([messageRecordId])
|
|
@@index([gatewayMessageId])
|
|
@@index([channelId, gatewayMessageId])
|
|
@@index([channelGroupId])
|
|
}
|
|
|
|
model DailyReconciliationReport {
|
|
id String @id @default(cuid())
|
|
reportDate DateTime @db.Date
|
|
tenantId String
|
|
tenantName String
|
|
applicationId String
|
|
applicationName String
|
|
submittedUnits Int @default(0)
|
|
sentUnits Int @default(0)
|
|
unknownUnits Int @default(0)
|
|
successUnits Int @default(0)
|
|
failedUnits Int @default(0)
|
|
generatedAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([reportDate, tenantId, applicationId])
|
|
@@index([reportDate])
|
|
@@index([tenantId, reportDate])
|
|
@@index([applicationId, reportDate])
|
|
}
|
|
|
|
model DailyProfitReport {
|
|
id String @id @default(cuid())
|
|
reportDate DateTime @db.Date
|
|
dimensionType String
|
|
dimensionId String
|
|
dimensionName String
|
|
tenantId String?
|
|
tenantName String?
|
|
applicationId String?
|
|
channelId String?
|
|
submittedUnits Int @default(0)
|
|
sentUnits Int @default(0)
|
|
unknownUnits Int @default(0)
|
|
successUnits Int @default(0)
|
|
failedUnits Int @default(0)
|
|
revenueCents BigInt @default(0)
|
|
refundCents BigInt @default(0)
|
|
costCents BigInt @default(0)
|
|
profitCents BigInt @default(0)
|
|
profitRateBps Int @default(0)
|
|
generatedAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([reportDate, dimensionType, dimensionId])
|
|
@@index([dimensionType, reportDate])
|
|
@@index([tenantId, reportDate])
|
|
@@index([applicationId, reportDate])
|
|
@@index([channelId, reportDate])
|
|
}
|
|
|
|
model DailyQualityReport {
|
|
id String @id @default(cuid())
|
|
reportDate DateTime @db.Date
|
|
dimensionType String
|
|
dimensionId String
|
|
dimensionName String
|
|
tenantId String?
|
|
tenantName String?
|
|
applicationId String?
|
|
channelId String?
|
|
signatureId String?
|
|
drainageInfoId String?
|
|
submittedUnits Int @default(0)
|
|
sentUnits Int @default(0)
|
|
unknownUnits Int @default(0)
|
|
successUnits Int @default(0)
|
|
failedUnits Int @default(0)
|
|
successRateBps Int @default(0)
|
|
avgArrivalMs Int?
|
|
generatedAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([reportDate, dimensionType, dimensionId])
|
|
@@index([dimensionType, reportDate, sentUnits])
|
|
@@index([tenantId, reportDate])
|
|
@@index([applicationId, reportDate])
|
|
@@index([channelId, reportDate])
|
|
@@index([signatureId, reportDate])
|
|
@@index([drainageInfoId, reportDate])
|
|
}
|
|
|
|
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 CmppInboundLongMessage {
|
|
id String @id @default(cuid())
|
|
tenantId String
|
|
applicationId String
|
|
groupKey String
|
|
account String
|
|
srcId String?
|
|
phoneNumbers Json
|
|
concatReference Int
|
|
segmentTotal Int
|
|
msgFmt Int
|
|
messageId String @unique
|
|
status String @default("collecting")
|
|
response Json?
|
|
expiresAt DateTime
|
|
completedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
|
segments CmppInboundLongMessageSegment[]
|
|
|
|
@@index([groupKey, status, createdAt])
|
|
@@index([applicationId, status, expiresAt])
|
|
}
|
|
|
|
model CmppInboundLongMessageSegment {
|
|
id String @id @default(cuid())
|
|
groupId String
|
|
segmentIndex Int
|
|
sequenceId String?
|
|
registeredDelivery Boolean @default(true)
|
|
content String
|
|
contentHash String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
group CmppInboundLongMessage @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([groupId, segmentIndex])
|
|
@@index([sequenceId])
|
|
}
|
|
|
|
model SmsReceiptRecord {
|
|
id String @id @default(cuid())
|
|
tenantId String?
|
|
batchTaskId String?
|
|
messageRecordId String?
|
|
receiptKey String @unique
|
|
channelId String?
|
|
messageId String
|
|
gatewayMessageId String
|
|
phoneNumber String?
|
|
sequenceId Int?
|
|
receiptStatus String
|
|
rawStatus String
|
|
errorCode String?
|
|
errorMessage 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])
|
|
anomalies SmsReceiptAnomaly[]
|
|
|
|
@@index([tenantId, createdAt])
|
|
@@index([messageId])
|
|
@@index([gatewayMessageId])
|
|
@@index([channelId, gatewayMessageId])
|
|
@@index([channelId, gatewayMessageId, phoneNumber])
|
|
}
|
|
|
|
model SmsReceiptAnomaly {
|
|
id String @id @default(cuid())
|
|
anomalyKey String @unique
|
|
tenantId String?
|
|
applicationId String?
|
|
channelId String?
|
|
messageRecordId String?
|
|
submitRecordId String?
|
|
receiptRecordId String?
|
|
anomalyType String
|
|
status String @default("pending")
|
|
previousStatus String?
|
|
incomingStatus String?
|
|
rawStatus String?
|
|
errorCode String?
|
|
detail Json?
|
|
occurrenceCount Int @default(1)
|
|
firstOccurredAt DateTime @default(now())
|
|
lastOccurredAt DateTime @default(now())
|
|
resolvedAt DateTime?
|
|
resolutionNote String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: SetNull)
|
|
application SmsApplication? @relation(fields: [applicationId], references: [id], onDelete: SetNull)
|
|
channel SmsChannel? @relation(fields: [channelId], references: [id], onDelete: SetNull)
|
|
messageRecord SmsMessageRecord? @relation(fields: [messageRecordId], references: [id], onDelete: SetNull)
|
|
submitRecord SmsSubmitRecord? @relation(fields: [submitRecordId], references: [id], onDelete: SetNull)
|
|
receiptRecord SmsReceiptRecord? @relation(fields: [receiptRecordId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([status, lastOccurredAt])
|
|
@@index([lastOccurredAt])
|
|
@@index([anomalyType, lastOccurredAt])
|
|
@@index([tenantId, status, lastOccurredAt])
|
|
@@index([applicationId, status, lastOccurredAt])
|
|
@@index([channelId, status, lastOccurredAt])
|
|
@@index([messageRecordId])
|
|
@@index([submitRecordId])
|
|
}
|
|
|
|
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([receivedAt])
|
|
@@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?
|
|
dedupeKey String? @unique
|
|
deliveryType String
|
|
status String @default("pending")
|
|
payload Json
|
|
retryEnabled Boolean @default(true)
|
|
retryCount Int @default(0)
|
|
manualRetryCount Int @default(0)
|
|
lastRetriedAt DateTime?
|
|
nextRetryAt DateTime?
|
|
sentAt DateTime?
|
|
acknowledgedAt DateTime?
|
|
ackDeadlineAt DateTime?
|
|
ackResult Int?
|
|
ackSequenceId String?
|
|
ackMessageId String?
|
|
connectionId String?
|
|
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])
|
|
attempts CmppDownstreamDeliveryAttempt[]
|
|
requeueItems DownstreamRequeueTaskItem[]
|
|
|
|
@@index([tenantId, status, createdAt])
|
|
@@index([applicationId, status, createdAt])
|
|
@@index([messageId])
|
|
@@index([messageRecordId])
|
|
@@index([deliveryType, status])
|
|
@@index([status, ackDeadlineAt])
|
|
}
|
|
|
|
model DownstreamRequeueTask {
|
|
id String @id @default(cuid())
|
|
taskNo String @unique
|
|
tenantId String?
|
|
applicationId String?
|
|
status String @default("queued")
|
|
filterSnapshot Json
|
|
snapshotAt DateTime
|
|
reason String
|
|
ratePerSecond Int @default(10)
|
|
consecutiveFailureLimit Int @default(10)
|
|
totalCount Int @default(0)
|
|
successCount Int @default(0)
|
|
failedCount Int @default(0)
|
|
skippedCount Int @default(0)
|
|
waitingCount Int @default(0)
|
|
consecutiveFailures Int @default(0)
|
|
applicationFailures Json @default("{}")
|
|
lastError String?
|
|
scanLeaseOwner String?
|
|
scanLeaseUntil DateTime?
|
|
createdById String?
|
|
startedAt DateTime?
|
|
pausedAt DateTime?
|
|
finishedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
application SmsApplication? @relation(fields: [applicationId], references: [id])
|
|
createdBy User? @relation("DownstreamRequeueTaskCreator", fields: [createdById], references: [id])
|
|
items DownstreamRequeueTaskItem[]
|
|
|
|
@@index([status, createdAt])
|
|
@@index([applicationId, status, createdAt])
|
|
@@index([tenantId, createdAt])
|
|
}
|
|
|
|
model DownstreamRequeueRateWindow {
|
|
id String @id @default(cuid())
|
|
applicationId String
|
|
windowStartedAt DateTime
|
|
consumed Int @default(0)
|
|
updatedAt DateTime @updatedAt
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([applicationId, windowStartedAt])
|
|
@@index([windowStartedAt])
|
|
}
|
|
|
|
model DownstreamRequeueTaskItem {
|
|
id String @id @default(cuid())
|
|
taskId String
|
|
deliveryId String
|
|
applicationId String
|
|
status String @default("queued")
|
|
previousStatus String
|
|
skipReason String?
|
|
errorMessage String?
|
|
claimedAt DateTime?
|
|
completedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
task DownstreamRequeueTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
|
|
delivery CmppDownstreamDelivery @relation(fields: [deliveryId], references: [id], onDelete: Restrict)
|
|
|
|
@@unique([taskId, deliveryId])
|
|
@@index([taskId, status, createdAt])
|
|
@@index([applicationId, status, createdAt])
|
|
@@index([deliveryId, status])
|
|
}
|
|
|
|
model CmppDownstreamDeliveryAttempt {
|
|
id String @id @default(cuid())
|
|
deliveryId String
|
|
attemptKey String @unique
|
|
attemptNo Int
|
|
connectionId String?
|
|
sequenceId String?
|
|
messageId String?
|
|
status String
|
|
sentAt DateTime?
|
|
ackDeadlineAt DateTime?
|
|
acknowledgedAt DateTime?
|
|
ackResult Int?
|
|
failureType String?
|
|
errorMessage String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
delivery CmppDownstreamDelivery @relation(fields: [deliveryId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([deliveryId, attemptNo])
|
|
@@index([status, ackDeadlineAt])
|
|
@@index([connectionId, sequenceId])
|
|
}
|
|
|
|
model UpstreamReceiptInbox {
|
|
id String @id @default(cuid())
|
|
receiptKey String @unique
|
|
incomingChannelId String
|
|
incomingConnectionId String?
|
|
upstreamAccount String
|
|
upstreamHost String
|
|
upstreamPort Int
|
|
protocol String
|
|
protocolVersion String
|
|
provisionalMessageId String?
|
|
sequenceId Int?
|
|
gatewayMessageId String
|
|
phoneNumber String?
|
|
receiptStatus String
|
|
rawStatus String
|
|
errorCode String?
|
|
errorMessage String?
|
|
deliveredAt DateTime
|
|
receivedAt DateTime @default(now())
|
|
status String @default("pending")
|
|
matchedMessageRecordId String?
|
|
matchedSubmitRecordId String?
|
|
matchedChannelId String?
|
|
attemptCount Int @default(0)
|
|
nextRetryAt DateTime?
|
|
lastError String?
|
|
processedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status, nextRetryAt, receivedAt])
|
|
@@index([gatewayMessageId, phoneNumber])
|
|
@@index([incomingChannelId, receivedAt])
|
|
@@index([matchedMessageRecordId])
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
model SecurityDetectionRule {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
sourceType String
|
|
enabled Boolean @default(true)
|
|
threshold Int
|
|
windowSeconds Int
|
|
cooldownSeconds Int
|
|
severity String
|
|
defaultBlockSeconds Int
|
|
maximumBlockSeconds Int
|
|
configVersion Int @default(1)
|
|
effectiveVersion Int @default(0)
|
|
applyStatus String @default("pending")
|
|
lastApplyError String?
|
|
pendingConfig Json?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
events SecurityDetectionEvent[]
|
|
alerts SecurityAlert[]
|
|
|
|
@@index([enabled, sourceType])
|
|
}
|
|
|
|
model SecurityDetectionEvent {
|
|
id String @id @default(cuid())
|
|
eventKey String @unique
|
|
ruleId String
|
|
sourceIp String
|
|
sourcePort Int?
|
|
accountHash String?
|
|
path String?
|
|
protocol String?
|
|
resultCode String?
|
|
evidence Json?
|
|
occurredAt DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
rule SecurityDetectionRule @relation(fields: [ruleId], references: [id], onDelete: Restrict)
|
|
|
|
@@index([ruleId, occurredAt])
|
|
@@index([sourceIp, occurredAt])
|
|
}
|
|
|
|
model SecurityAlert {
|
|
id String @id @default(cuid())
|
|
fingerprint String @unique
|
|
ruleId String
|
|
sourceIp String
|
|
severity String
|
|
status String @default("open")
|
|
eventCount Int @default(0)
|
|
windowStartedAt DateTime
|
|
firstOccurredAt DateTime
|
|
lastOccurredAt DateTime
|
|
acknowledgedAt DateTime?
|
|
acknowledgedById String?
|
|
ignoredAt DateTime?
|
|
ignoredById String?
|
|
ignoreReason String?
|
|
blockId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
rule SecurityDetectionRule @relation(fields: [ruleId], references: [id], onDelete: Restrict)
|
|
|
|
@@index([status, severity, lastOccurredAt])
|
|
@@index([sourceIp, status, lastOccurredAt])
|
|
@@index([ruleId, status, lastOccurredAt])
|
|
}
|
|
|
|
model SecurityBlock {
|
|
id String @id @default(cuid())
|
|
operationKey String @unique
|
|
alertId String?
|
|
sourceIp String
|
|
executor String
|
|
status String @default("requested")
|
|
durationSeconds Int
|
|
reason String
|
|
requestedById String
|
|
requestedAt DateTime @default(now())
|
|
appliedAt DateTime?
|
|
expiresAt DateTime?
|
|
releasedAt DateTime?
|
|
releasedById String?
|
|
executorReference String?
|
|
lastError String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([status, expiresAt])
|
|
@@index([sourceIp, status, requestedAt])
|
|
@@index([alertId])
|
|
}
|
|
|
|
model SecurityProtectedNetwork {
|
|
id String @id @default(cuid())
|
|
network String @unique
|
|
name String
|
|
reason String
|
|
enabled Boolean @default(true)
|
|
createdById String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([enabled, createdAt])
|
|
}
|
|
|
|
model InfrastructureAlertSetting {
|
|
id String @id @default("global")
|
|
configVersion Int @default(1)
|
|
effectiveVersion Int @default(1)
|
|
thresholds Json
|
|
effectiveThresholds Json
|
|
applyStatus String @default("effective")
|
|
lastError String?
|
|
updatedById String?
|
|
appliedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model InfrastructureAlertRead {
|
|
id String @id @default(cuid())
|
|
fingerprint String
|
|
activeAt DateTime
|
|
userId String
|
|
readAt DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([fingerprint, userId])
|
|
@@index([userId, readAt])
|
|
}
|