feat: strengthen risk controls and review workflows
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
DROP INDEX IF EXISTS "User_username_key";
|
||||
DROP INDEX IF EXISTS "User_email_key";
|
||||
DROP INDEX IF EXISTS "User_phone_key";
|
||||
|
||||
CREATE UNIQUE INDEX "User_active_username_key"
|
||||
ON "User" ("username")
|
||||
WHERE "deletedAt" IS NULL;
|
||||
|
||||
CREATE UNIQUE INDEX "User_active_email_key"
|
||||
ON "User" ("email")
|
||||
WHERE "deletedAt" IS NULL AND "email" IS NOT NULL;
|
||||
|
||||
CREATE UNIQUE INDEX "User_active_phone_key"
|
||||
ON "User" ("phone")
|
||||
WHERE "deletedAt" IS NULL AND "phone" IS NOT NULL;
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE "SmsApplication"
|
||||
ADD COLUMN "disablingAt" TIMESTAMP(3),
|
||||
ADD COLUMN "autoDisableAt" TIMESTAMP(3),
|
||||
ADD COLUMN "disableReason" TEXT;
|
||||
|
||||
CREATE INDEX "SmsApplication_status_autoDisableAt_idx"
|
||||
ON "SmsApplication"("status", "autoDisableAt");
|
||||
@@ -0,0 +1,39 @@
|
||||
-- Risk thresholds now inherit from global rules and may be overridden per application.
|
||||
-- Existing maxPhonesPerTask values are intentionally discarded because this environment
|
||||
-- contains test-only application data and the product owner explicitly declined migration.
|
||||
ALTER TABLE "RiskRule" ADD COLUMN "applicationId" TEXT;
|
||||
|
||||
-- Retain historical rules and hit records for audit, but remove them from the
|
||||
-- effective rule set and configuration page.
|
||||
UPDATE "RiskRule"
|
||||
SET "status" = 'deleted'
|
||||
WHERE "code" IN (
|
||||
'DUPLICATE_PHONE_RATIO',
|
||||
'ILLEGAL_PHONE_RATIO',
|
||||
'BLACKLIST_HIT_RATIO',
|
||||
'TEMPLATE_VARIABLE_ANOMALY'
|
||||
);
|
||||
|
||||
UPDATE "RiskRule"
|
||||
SET "status" = 'deleted'
|
||||
WHERE "tenantId" IS NOT NULL AND "applicationId" IS NULL;
|
||||
|
||||
DROP INDEX IF EXISTS "RiskRule_tenantId_code_key";
|
||||
DROP INDEX IF EXISTS "RiskRule_tenantId_status_priority_idx";
|
||||
|
||||
CREATE UNIQUE INDEX "RiskRule_applicationId_code_key"
|
||||
ON "RiskRule"("applicationId", "code");
|
||||
|
||||
CREATE UNIQUE INDEX "RiskRule_global_code_key"
|
||||
ON "RiskRule"("code")
|
||||
WHERE "applicationId" IS NULL AND "status" <> 'deleted';
|
||||
|
||||
CREATE INDEX "RiskRule_tenantId_applicationId_status_priority_idx"
|
||||
ON "RiskRule"("tenantId", "applicationId", "status", "priority");
|
||||
|
||||
ALTER TABLE "RiskRule"
|
||||
ADD CONSTRAINT "RiskRule_applicationId_fkey"
|
||||
FOREIGN KEY ("applicationId") REFERENCES "SmsApplication"("id")
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "SmsApplication" DROP COLUMN "maxPhonesPerTask";
|
||||
+31
-25
@@ -74,9 +74,9 @@ model EnterpriseCertification {
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
tenantId String?
|
||||
username String @unique
|
||||
email String? @unique
|
||||
phone String? @unique
|
||||
username String
|
||||
email String?
|
||||
phone String?
|
||||
displayName String
|
||||
passwordHash String
|
||||
status String @default("active")
|
||||
@@ -384,32 +384,34 @@ model SmsBillingRecord {
|
||||
}
|
||||
|
||||
model SmsApplication {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
tenantId String
|
||||
name String
|
||||
scene String?
|
||||
callbackUrl String?
|
||||
cmppAccount String @unique
|
||||
cmppAccount String @unique
|
||||
cmppEnterpriseCode String
|
||||
cmppApplicationExtension String?
|
||||
cmppAccessNumberFillEnabled Boolean @default(false)
|
||||
cmppAccessNumberFillEnabled Boolean @default(false)
|
||||
cmppAccessNumberFillPrefix String?
|
||||
cmppClientSrcId String? @unique
|
||||
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")
|
||||
maxPhonesPerTask Int @default(10000)
|
||||
templateMismatchMode String @default("reject")
|
||||
downstreamReceiptRetryEnabled Boolean @default(true)
|
||||
downstreamUplinkRetryEnabled Boolean @default(true)
|
||||
status String @default("active")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
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[]
|
||||
@@ -435,8 +437,10 @@ model SmsApplication {
|
||||
httpWebhookEvents HttpWebhookEvent[]
|
||||
dailyUsages SmsApplicationDailyUsage[]
|
||||
inboundLongMessages CmppInboundLongMessage[]
|
||||
riskRules RiskRule[]
|
||||
|
||||
@@index([tenantId, status])
|
||||
@@index([status, autoDisableAt])
|
||||
}
|
||||
|
||||
model SmsApplicationIpAllowlist {
|
||||
@@ -1213,6 +1217,7 @@ model ReportReceiptImport {
|
||||
model RiskRule {
|
||||
id String @id @default(cuid())
|
||||
tenantId String?
|
||||
applicationId String?
|
||||
code String
|
||||
name String
|
||||
description String?
|
||||
@@ -1225,11 +1230,12 @@ model RiskRule {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
||||
hits RiskHitRecord[]
|
||||
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
||||
application SmsApplication? @relation(fields: [applicationId], references: [id], onDelete: Cascade)
|
||||
hits RiskHitRecord[]
|
||||
|
||||
@@unique([tenantId, code])
|
||||
@@index([tenantId, status, priority])
|
||||
@@unique([applicationId, code])
|
||||
@@index([tenantId, applicationId, status, priority])
|
||||
}
|
||||
|
||||
model SmsSendTask {
|
||||
|
||||
Reference in New Issue
Block a user