feat: complete phase2 baseline cdr quality rbac

This commit is contained in:
hectorzhao
2026-06-24 18:40:21 +08:00
parent 7057fd3c42
commit a86de6545f
63 changed files with 7853 additions and 3678 deletions
@@ -108,7 +108,7 @@ CREATE TABLE `vendor_gateway_blocked_regions` (
INDEX `vendor_gateway_blocked_regions_vendor_gateway_id_idx`(`vendor_gateway_id`),
INDEX `vendor_gateway_blocked_regions_province_code_idx`(`province_code`),
INDEX `vendor_gateway_blocked_regions_city_code_idx`(`city_code`),
UNIQUE INDEX `vendor_gateway_blocked_regions_vendor_gateway_id_region_scope_province_code_city_code_key`(`vendor_gateway_id`, `region_scope`, `province_code`, `city_code`),
UNIQUE INDEX `vgb_regions_gateway_scope_region_key`(`vendor_gateway_id`, `region_scope`, `province_code`, `city_code`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -0,0 +1,167 @@
-- V2 phase-2 gateway matching and landing rewrite expansion.
-- This migration is additive and keeps legacy customer_gateway_policies and
-- vendor_gateway_prefix_rules in place for staged API/OpenSIPS rollout.
CREATE TABLE `business_prefixes` (
`id` VARCHAR(32) NOT NULL,
`prefix` VARCHAR(32) NOT NULL,
`name` VARCHAR(120) NOT NULL,
`description` VARCHAR(500) NULL,
`priority` INTEGER NOT NULL DEFAULT 100,
`status` ENUM('ENABLED', 'DISABLED') NOT NULL DEFAULT 'ENABLED',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
`created_by` VARCHAR(32) NULL,
`updated_by` VARCHAR(32) NULL,
`version` INTEGER NOT NULL DEFAULT 1,
`deleted_at` DATETIME(3) NULL,
UNIQUE INDEX `business_prefixes_prefix_key`(`prefix`),
INDEX `business_prefixes_status_priority_idx`(`status`, `priority`),
INDEX `business_prefixes_deleted_at_idx`(`deleted_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `customer_gateways`
ADD COLUMN `line_group_id` VARCHAR(32) NULL,
ADD COLUMN `billing_cycle_sec` INTEGER NOT NULL DEFAULT 60,
ADD COLUMN `cycle_rate` DECIMAL(20, 6) NOT NULL DEFAULT 0,
ADD COLUMN `caller_match_mode` ENUM('ANY', 'PREFIXES') NOT NULL DEFAULT 'ANY',
ADD COLUMN `callee_match_mode` ENUM('ANY', 'BUSINESS_PREFIXES') NOT NULL DEFAULT 'ANY';
CREATE INDEX `customer_gateways_line_group_id_idx` ON `customer_gateways`(`line_group_id`);
ALTER TABLE `customer_gateways`
ADD CONSTRAINT `customer_gateways_line_group_id_fkey`
FOREIGN KEY (`line_group_id`) REFERENCES `landing_line_groups`(`id`)
ON DELETE RESTRICT ON UPDATE CASCADE;
CREATE TABLE `customer_gateway_ips` (
`id` VARCHAR(32) NOT NULL,
`gateway_id` VARCHAR(32) NOT NULL,
`source_ip` VARCHAR(45) NOT NULL,
`status` ENUM('ENABLED', 'DISABLED') NOT NULL DEFAULT 'ENABLED',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
`created_by` VARCHAR(32) NULL,
`updated_by` VARCHAR(32) NULL,
`version` INTEGER NOT NULL DEFAULT 1,
`deleted_at` DATETIME(3) NULL,
UNIQUE INDEX `customer_gateway_ips_gateway_id_source_ip_key`(`gateway_id`, `source_ip`),
INDEX `customer_gateway_ips_source_ip_status_idx`(`source_ip`, `status`),
INDEX `customer_gateway_ips_deleted_at_idx`(`deleted_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `customer_gateway_ips`
ADD CONSTRAINT `customer_gateway_ips_gateway_id_fkey`
FOREIGN KEY (`gateway_id`) REFERENCES `customer_gateways`(`id`)
ON DELETE CASCADE ON UPDATE CASCADE;
INSERT INTO `customer_gateway_ips` (
`id`,
`gateway_id`,
`source_ip`,
`status`,
`created_at`,
`updated_at`,
`created_by`,
`updated_by`,
`version`,
`deleted_at`
)
SELECT
CONCAT('cgip_', LEFT(REPLACE(UUID(), '-', ''), 27)),
`id`,
`source_ip`,
`status`,
`created_at`,
`updated_at`,
`created_by`,
`updated_by`,
`version`,
`deleted_at`
FROM `customer_gateways`
WHERE `source_ip` IS NOT NULL
AND `source_ip` <> '';
CREATE TABLE `customer_gateway_business_prefixes` (
`id` VARCHAR(32) NOT NULL,
`gateway_id` VARCHAR(32) NOT NULL,
`business_prefix_id` VARCHAR(32) NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` VARCHAR(32) NULL,
UNIQUE INDEX `cgbp_gateway_business_prefix_key`(`gateway_id`, `business_prefix_id`),
INDEX `customer_gateway_business_prefixes_business_prefix_id_idx`(`business_prefix_id`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `customer_gateway_business_prefixes`
ADD CONSTRAINT `customer_gateway_business_prefixes_gateway_id_fkey`
FOREIGN KEY (`gateway_id`) REFERENCES `customer_gateways`(`id`)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `customer_gateway_business_prefixes`
ADD CONSTRAINT `customer_gateway_business_prefixes_business_prefix_id_fkey`
FOREIGN KEY (`business_prefix_id`) REFERENCES `business_prefixes`(`id`)
ON DELETE RESTRICT ON UPDATE CASCADE;
CREATE TABLE `customer_gateway_caller_prefixes` (
`id` VARCHAR(32) NOT NULL,
`gateway_id` VARCHAR(32) NOT NULL,
`prefix` VARCHAR(64) NOT NULL,
`priority` INTEGER NOT NULL DEFAULT 100,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`created_by` VARCHAR(32) NULL,
UNIQUE INDEX `customer_gateway_caller_prefixes_gateway_id_prefix_key`(`gateway_id`, `prefix`),
INDEX `customer_gateway_caller_prefixes_gateway_id_priority_idx`(`gateway_id`, `priority`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `customer_gateway_caller_prefixes`
ADD CONSTRAINT `customer_gateway_caller_prefixes_gateway_id_fkey`
FOREIGN KEY (`gateway_id`) REFERENCES `customer_gateways`(`id`)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `vendor_gateways`
ADD COLUMN `landing_callee_prefix` VARCHAR(64) NULL;
CREATE TABLE `vendor_gateway_caller_rewrite_pool` (
`id` VARCHAR(32) NOT NULL,
`vendor_gateway_id` VARCHAR(32) NOT NULL,
`caller` VARCHAR(64) NOT NULL,
`weight` INTEGER NOT NULL DEFAULT 1,
`status` ENUM('ENABLED', 'DISABLED') NOT NULL DEFAULT 'ENABLED',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL,
`created_by` VARCHAR(32) NULL,
`updated_by` VARCHAR(32) NULL,
`version` INTEGER NOT NULL DEFAULT 1,
`deleted_at` DATETIME(3) NULL,
INDEX `vendor_gateway_caller_rewrite_pool_vendor_gateway_id_status_idx`(`vendor_gateway_id`, `status`),
INDEX `vendor_gateway_caller_rewrite_pool_deleted_at_idx`(`deleted_at`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `vendor_gateway_caller_rewrite_pool`
ADD CONSTRAINT `vendor_gateway_caller_rewrite_pool_vendor_gateway_id_fkey`
FOREIGN KEY (`vendor_gateway_id`) REFERENCES `vendor_gateways`(`id`)
ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `raw_cdrs`
ADD COLUMN `raw_callee` VARCHAR(64) NULL,
ADD COLUMN `business_prefix_id` VARCHAR(32) NULL,
ADD COLUMN `business_prefix` VARCHAR(32) NULL,
ADD COLUMN `landing_caller` VARCHAR(64) NULL,
ADD COLUMN `landing_callee` VARCHAR(64) NULL;
CREATE INDEX `raw_cdrs_business_prefix_id_started_at_idx` ON `raw_cdrs`(`business_prefix_id`, `started_at`);
ALTER TABLE `raw_cdrs`
ADD CONSTRAINT `raw_cdrs_business_prefix_id_fkey`
FOREIGN KEY (`business_prefix_id`) REFERENCES `business_prefixes`(`id`)
ON DELETE SET NULL ON UPDATE CASCADE;
+171 -45
View File
@@ -37,6 +37,20 @@ enum MatchMode {
@@map("match_mode")
}
enum CustomerGatewayCallerMatchMode {
ANY
PREFIXES
@@map("customer_gateway_caller_match_mode")
}
enum CustomerGatewayCalleeMatchMode {
ANY
BUSINESS_PREFIXES
@@map("customer_gateway_callee_match_mode")
}
enum RechargeStatus {
SUCCEEDED
FAILED
@@ -162,34 +176,116 @@ model Customer {
}
model CustomerGateway {
id String @id @db.VarChar(32)
customerId String @map("customer_id") @db.VarChar(32)
name String @db.VarChar(120)
authMode GatewayAuthMode @map("auth_mode")
sourceIp String? @map("source_ip") @db.VarChar(45)
sipUsername String? @map("sip_username") @db.VarChar(120)
sipDomain String? @map("sip_domain") @db.VarChar(160)
sipHa1 String? @map("sip_ha1") @db.VarChar(128)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
id String @id @db.VarChar(32)
customerId String @map("customer_id") @db.VarChar(32)
name String @db.VarChar(120)
authMode GatewayAuthMode @map("auth_mode")
sourceIp String? @map("source_ip") @db.VarChar(45)
sipUsername String? @map("sip_username") @db.VarChar(120)
sipDomain String? @map("sip_domain") @db.VarChar(160)
sipHa1 String? @map("sip_ha1") @db.VarChar(128)
lineGroupId String? @map("line_group_id") @db.VarChar(32)
billingCycleSec Int @default(60) @map("billing_cycle_sec")
cycleRate Decimal @default(0) @map("cycle_rate") @db.Decimal(20, 6)
callerMatchMode CustomerGatewayCallerMatchMode @default(ANY) @map("caller_match_mode")
calleeMatchMode CustomerGatewayCalleeMatchMode @default(ANY) @map("callee_match_mode")
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict)
policies CustomerGatewayPolicy[]
rawCdrs RawCdr[]
customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict)
lineGroup LandingLineGroup? @relation(fields: [lineGroupId], references: [id], onDelete: Restrict)
ips CustomerGatewayIp[]
businessPrefixes CustomerGatewayBusinessPrefix[]
callerPrefixes CustomerGatewayCallerPrefix[]
policies CustomerGatewayPolicy[]
rawCdrs RawCdr[]
@@unique([customerId, name])
@@unique([sipUsername, sipDomain])
@@index([customerId, status])
@@index([lineGroupId])
@@index([sourceIp])
@@index([deletedAt])
@@map("customer_gateways")
}
model BusinessPrefix {
id String @id @db.VarChar(32)
prefix String @unique @db.VarChar(32)
name String @db.VarChar(120)
description String? @db.VarChar(500)
priority Int @default(100)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
customerGateways CustomerGatewayBusinessPrefix[]
rawCdrs RawCdr[]
@@index([status, priority])
@@index([deletedAt])
@@map("business_prefixes")
}
model CustomerGatewayIp {
id String @id @db.VarChar(32)
gatewayId String @map("gateway_id") @db.VarChar(32)
sourceIp String @map("source_ip") @db.VarChar(45)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
gateway CustomerGateway @relation(fields: [gatewayId], references: [id], onDelete: Cascade)
@@unique([gatewayId, sourceIp])
@@index([sourceIp, status])
@@index([deletedAt])
@@map("customer_gateway_ips")
}
model CustomerGatewayBusinessPrefix {
id String @id @db.VarChar(32)
gatewayId String @map("gateway_id") @db.VarChar(32)
businessPrefixId String @map("business_prefix_id") @db.VarChar(32)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
gateway CustomerGateway @relation(fields: [gatewayId], references: [id], onDelete: Cascade)
businessPrefix BusinessPrefix @relation(fields: [businessPrefixId], references: [id], onDelete: Restrict)
@@unique([gatewayId, businessPrefixId])
@@index([businessPrefixId])
@@map("customer_gateway_business_prefixes")
}
model CustomerGatewayCallerPrefix {
id String @id @db.VarChar(32)
gatewayId String @map("gateway_id") @db.VarChar(32)
prefix String @db.VarChar(64)
priority Int @default(100)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
gateway CustomerGateway @relation(fields: [gatewayId], references: [id], onDelete: Cascade)
@@unique([gatewayId, prefix])
@@index([gatewayId, priority])
@@map("customer_gateway_caller_prefixes")
}
model CustomerGatewayPolicy {
id String @id @db.VarChar(32)
customerId String @map("customer_id") @db.VarChar(32)
@@ -287,34 +383,36 @@ model VendorRecharge {
}
model VendorGateway {
id String @id @db.VarChar(32)
vendorId String @map("vendor_id") @db.VarChar(32)
name String @db.VarChar(120)
authMode GatewayAuthMode @map("auth_mode")
host String @db.VarChar(160)
port Int @default(5060)
transport String @default("udp") @db.VarChar(16)
sipUsername String? @map("sip_username") @db.VarChar(120)
sipHa1 String? @map("sip_ha1") @db.VarChar(128)
cpsLimit Int @default(0) @map("cps_limit")
concurrencyLimit Int @default(0) @map("concurrency_limit")
billingCycleSec Int @default(60) @map("billing_cycle_sec")
cycleRate Decimal @default(0) @map("cycle_rate") @db.Decimal(20, 6)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
id String @id @db.VarChar(32)
vendorId String @map("vendor_id") @db.VarChar(32)
name String @db.VarChar(120)
authMode GatewayAuthMode @map("auth_mode")
host String @db.VarChar(160)
port Int @default(5060)
transport String @default("udp") @db.VarChar(16)
sipUsername String? @map("sip_username") @db.VarChar(120)
sipHa1 String? @map("sip_ha1") @db.VarChar(128)
cpsLimit Int @default(0) @map("cps_limit")
concurrencyLimit Int @default(0) @map("concurrency_limit")
billingCycleSec Int @default(60) @map("billing_cycle_sec")
cycleRate Decimal @default(0) @map("cycle_rate") @db.Decimal(20, 6)
landingCalleePrefix String? @map("landing_callee_prefix") @db.VarChar(64)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
vendor Vendor @relation(fields: [vendorId], references: [id], onDelete: Restrict)
forbiddenPeriods VendorGatewayForbiddenPeriod[]
blockedRegions VendorGatewayBlockedRegion[]
codecs VendorGatewayCodec[]
prefixRules VendorGatewayPrefixRule[]
lineGroupItems LandingLineGroupItem[]
rawCdrs RawCdr[]
vendor Vendor @relation(fields: [vendorId], references: [id], onDelete: Restrict)
forbiddenPeriods VendorGatewayForbiddenPeriod[]
blockedRegions VendorGatewayBlockedRegion[]
codecs VendorGatewayCodec[]
prefixRules VendorGatewayPrefixRule[]
callerRewritePool VendorGatewayCallerRewrite[]
lineGroupItems LandingLineGroupItem[]
rawCdrs RawCdr[]
@@unique([vendorId, name])
@@index([vendorId, status])
@@ -498,6 +596,26 @@ model VendorGatewayPrefixRule {
@@map("vendor_gateway_prefix_rules")
}
model VendorGatewayCallerRewrite {
id String @id @db.VarChar(32)
vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32)
caller String @db.VarChar(64)
weight Int @default(1)
status EntityStatus @default(ENABLED)
createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3)
updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3)
createdBy String? @map("created_by") @db.VarChar(32)
updatedBy String? @map("updated_by") @db.VarChar(32)
version Int @default(1)
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Cascade)
@@index([vendorGatewayId, status])
@@index([deletedAt])
@@map("vendor_gateway_caller_rewrite_pool")
}
model LandingLineGroup {
id String @id @db.VarChar(32)
name String @unique @db.VarChar(120)
@@ -511,6 +629,7 @@ model LandingLineGroup {
deletedAt DateTime? @map("deleted_at") @db.DateTime(3)
items LandingLineGroupItem[]
gateways CustomerGateway[]
policies CustomerGatewayPolicy[]
rawCdrs RawCdr[]
rules QualitySamplingRule[]
@@ -553,6 +672,9 @@ model RawCdr {
sourceIp String? @map("source_ip") @db.VarChar(45)
caller String @db.VarChar(64)
callee String @db.VarChar(64)
rawCallee String? @map("raw_callee") @db.VarChar(64)
businessPrefixId String? @map("business_prefix_id") @db.VarChar(32)
businessPrefix String? @map("business_prefix") @db.VarChar(32)
calleeCityCode String? @map("callee_city_code") @db.VarChar(12)
calleeCityName String? @map("callee_city_name") @db.VarChar(80)
calleeProvinceName String? @map("callee_province_name") @db.VarChar(80)
@@ -561,6 +683,8 @@ model RawCdr {
vendorId String? @map("vendor_id") @db.VarChar(32)
vendorGatewayId String? @map("vendor_gateway_id") @db.VarChar(32)
lineGroupId String? @map("line_group_id") @db.VarChar(32)
landingCaller String? @map("landing_caller") @db.VarChar(64)
landingCallee String? @map("landing_callee") @db.VarChar(64)
startedAt DateTime @map("started_at") @db.DateTime(3)
answeredAt DateTime? @map("answered_at") @db.DateTime(3)
endedAt DateTime @map("ended_at") @db.DateTime(3)
@@ -577,6 +701,7 @@ model RawCdr {
customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
customerGateway CustomerGateway? @relation(fields: [customerGatewayId], references: [id], onDelete: SetNull)
customerGatewayPolicy CustomerGatewayPolicy? @relation(fields: [customerGatewayPolicyId], references: [id], onDelete: SetNull)
businessPrefixRef BusinessPrefix? @relation(fields: [businessPrefixId], references: [id], onDelete: SetNull)
vendor Vendor? @relation(fields: [vendorId], references: [id], onDelete: SetNull)
vendorGateway VendorGateway? @relation(fields: [vendorGatewayId], references: [id], onDelete: SetNull)
lineGroup LandingLineGroup? @relation(fields: [lineGroupId], references: [id], onDelete: SetNull)
@@ -588,6 +713,7 @@ model RawCdr {
@@index([vendorId, startedAt])
@@index([calleeCityCode, startedAt])
@@index([calleeOperator, startedAt])
@@index([businessPrefixId, startedAt])
@@index([sipCode])
@@index([ratingStatus])
@@map("raw_cdrs")