generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } enum EntityStatus { ENABLED DISABLED @@map("entity_status") } enum CustomerBillingMode { PREPAID POSTPAID @@map("customer_billing_mode") } enum GatewayAuthMode { IP SIP_DIGEST MIXED @@map("gateway_auth_mode") } enum MatchMode { ANY EQUALS PREFIX @@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 REVERSED @@map("recharge_status") } enum PrefixRuleDirection { CALLER CALLEE @@map("prefix_rule_direction") } enum NumberCarrier { MOBILE UNICOM TELECOM BROADCAST MVNO UNKNOWN @@map("number_carrier") } enum PhoneNumberType { MOBILE LANDLINE INTERNATIONAL UNKNOWN @@map("phone_number_type") } enum RegionScope { PROVINCE CITY @@map("region_scope") } enum CdrRatingStatus { UNRATED RATED SKIPPED FAILED @@map("cdr_rating_status") } enum RecordingStatus { PENDING READY FAILED DELETED @@map("recording_status") } enum QualityReviewResult { PASS ISSUE ESCALATED @@map("quality_review_result") } enum AuditResult { SUCCESS FAILURE @@map("audit_result") } enum OutboxStatus { PENDING PROCESSING PUBLISHED FAILED @@map("outbox_status") } enum IdempotencyStatus { IN_PROGRESS SUCCEEDED FAILED EXPIRED @@map("idempotency_status") } model Customer { id String @id @db.VarChar(32) name String @unique @db.VarChar(120) contactName String? @map("contact_name") @db.VarChar(80) phone String? @db.VarChar(32) email String? @db.VarChar(160) domain String? @unique @db.VarChar(160) status EntityStatus @default(ENABLED) billingMode CustomerBillingMode @default(PREPAID) @map("billing_mode") balance Decimal @default(0) @db.Decimal(20, 6) creditLimit Decimal @default(0) @map("credit_limit") @db.Decimal(20, 6) minBalance Decimal @default(0) @map("min_balance") @db.Decimal(20, 6) notes String? @db.VarChar(500) 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) gateways CustomerGateway[] policies CustomerGatewayPolicy[] recharges CustomerRecharge[] rawCdrs RawCdr[] samplingRules QualitySamplingRule[] @@index([status]) @@index([deletedAt]) @@map("customers") } 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) 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) 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) gatewayId String @map("gateway_id") @db.VarChar(32) lineGroupId String @map("line_group_id") @db.VarChar(32) name String @db.VarChar(120) priority Int callerMode MatchMode @default(ANY) @map("caller_mode") callerValue String? @map("caller_value") @db.VarChar(64) calleeMode MatchMode @default(ANY) @map("callee_mode") calleeValue String? @map("callee_value") @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) customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict) gateway CustomerGateway @relation(fields: [gatewayId], references: [id], onDelete: Restrict) lineGroup LandingLineGroup @relation(fields: [lineGroupId], references: [id], onDelete: Restrict) rawCdrs RawCdr[] @@unique([gatewayId, priority]) @@index([customerId, status]) @@index([lineGroupId]) @@index([deletedAt]) @@map("customer_gateway_policies") } model CustomerRecharge { id String @id @db.VarChar(40) customerId String @map("customer_id") @db.VarChar(32) amount Decimal @db.Decimal(20, 6) beforeBalance Decimal @map("before_balance") @db.Decimal(20, 6) afterBalance Decimal @map("after_balance") @db.Decimal(20, 6) idempotencyKey String @unique @map("idempotency_key") @db.VarChar(128) remark String? @db.VarChar(500) status RechargeStatus @default(SUCCEEDED) occurredAt DateTime @default(now()) @map("occurred_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) createdBy String? @map("created_by") @db.VarChar(32) customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict) @@index([customerId, occurredAt]) @@map("customer_recharges") } model Vendor { id String @id @db.VarChar(32) name String @unique @db.VarChar(120) contactName String? @map("contact_name") @db.VarChar(80) phone String? @db.VarChar(32) email String? @db.VarChar(160) status EntityStatus @default(ENABLED) balance Decimal @default(0) @db.Decimal(20, 6) creditLimit Decimal @default(0) @map("credit_limit") @db.Decimal(20, 6) settlement String? @db.VarChar(80) notes String? @db.VarChar(500) 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) gateways VendorGateway[] recharges VendorRecharge[] rawCdrs RawCdr[] @@index([status]) @@index([deletedAt]) @@map("vendors") } model VendorRecharge { id String @id @db.VarChar(40) vendorId String @map("vendor_id") @db.VarChar(32) amount Decimal @db.Decimal(20, 6) beforeBalance Decimal @map("before_balance") @db.Decimal(20, 6) afterBalance Decimal @map("after_balance") @db.Decimal(20, 6) idempotencyKey String @unique @map("idempotency_key") @db.VarChar(128) remark String? @db.VarChar(500) status RechargeStatus @default(SUCCEEDED) occurredAt DateTime @default(now()) @map("occurred_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) createdBy String? @map("created_by") @db.VarChar(32) vendor Vendor @relation(fields: [vendorId], references: [id], onDelete: Restrict) @@index([vendorId, occurredAt]) @@map("vendor_recharges") } 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) 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[] callerRewritePool VendorGatewayCallerRewrite[] lineGroupItems LandingLineGroupItem[] rawCdrs RawCdr[] @@unique([vendorId, name]) @@index([vendorId, status]) @@index([host]) @@index([deletedAt]) @@map("vendor_gateways") } model GeoCity { code String @id @db.VarChar(12) provinceCode String @map("province_code") @db.VarChar(12) provinceName String @map("province_name") @db.VarChar(80) cityCode String @unique @map("city_code") @db.VarChar(12) cityName String @map("city_name") @db.VarChar(80) cityLevel String @map("city_level") @db.VarChar(32) status EntityStatus @default(ENABLED) effectiveFrom DateTime? @map("effective_from") @db.DateTime(3) effectiveTo DateTime? @map("effective_to") @db.DateTime(3) 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) phoneSegments PhoneNumberSegment[] areaCodes PhoneAreaCode[] blockedRegions VendorGatewayBlockedRegion[] @@index([provinceCode]) @@index([provinceName, cityName]) @@index([status]) @@index([deletedAt]) @@map("geo_cities") } model PhoneNumberSegment { segment7 String @id @map("segment7") @db.Char(7) cityCode String @map("city_code") @db.VarChar(12) provinceName String @map("province_name") @db.VarChar(80) cityName String @map("city_name") @db.VarChar(80) carrier NumberCarrier @default(UNKNOWN) source String? @db.VarChar(120) batchId String? @map("batch_id") @db.VarChar(64) effectiveFrom DateTime? @map("effective_from") @db.DateTime(3) effectiveTo DateTime? @map("effective_to") @db.DateTime(3) 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) city GeoCity @relation(fields: [cityCode], references: [cityCode], onDelete: Restrict) @@index([cityCode]) @@index([carrier]) @@index([batchId]) @@index([deletedAt]) @@map("phone_number_segments") } model PhoneAreaCode { areaCode String @id @map("area_code") @db.VarChar(8) cityCode String @map("city_code") @db.VarChar(12) provinceName String @map("province_name") @db.VarChar(80) cityName String @map("city_name") @db.VarChar(80) source String? @db.VarChar(120) batchId String? @map("batch_id") @db.VarChar(64) 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) city GeoCity @relation(fields: [cityCode], references: [cityCode], onDelete: Restrict) @@index([cityCode]) @@index([batchId]) @@index([deletedAt]) @@map("phone_area_codes") } model CarrierPrefixRule { prefix String @id @db.VarChar(4) carrier NumberCarrier priority Int @default(100) source String? @db.VarChar(120) batchId String? @map("batch_id") @db.VarChar(64) effectiveFrom DateTime? @map("effective_from") @db.DateTime(3) effectiveTo DateTime? @map("effective_to") @db.DateTime(3) 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) @@index([carrier]) @@index([priority]) @@index([batchId]) @@index([deletedAt]) @@map("carrier_prefix_rules") } model VendorGatewayBlockedRegion { id String @id @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) regionScope RegionScope @map("region_scope") provinceCode String? @map("province_code") @db.VarChar(12) provinceName String? @map("province_name") @db.VarChar(80) cityCode String? @map("city_code") @db.VarChar(12) cityName String? @map("city_name") @db.VarChar(80) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) createdBy String? @map("created_by") @db.VarChar(32) vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Cascade) city GeoCity? @relation(fields: [cityCode], references: [cityCode], onDelete: Restrict) @@unique([vendorGatewayId, regionScope, provinceCode, cityCode]) @@index([vendorGatewayId]) @@index([provinceCode]) @@index([cityCode]) @@map("vendor_gateway_blocked_regions") } model VendorGatewayForbiddenPeriod { id String @id @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) weekdayMask Int @map("weekday_mask") startTime String @map("start_time") @db.VarChar(8) endTime String @map("end_time") @db.VarChar(8) 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) vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Cascade) @@index([vendorGatewayId]) @@map("vendor_gateway_forbidden_periods") } model VendorGatewayCodec { id String @id @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) codec String @db.VarChar(32) priority Int 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) vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Cascade) @@unique([vendorGatewayId, codec]) @@unique([vendorGatewayId, priority]) @@map("vendor_gateway_codecs") } model VendorGatewayPrefixRule { id String @id @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) direction PrefixRuleDirection matchPrefix String @map("match_prefix") @db.VarChar(32) replacePrefix String @map("replace_prefix") @db.VarChar(32) priority Int 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) vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Cascade) @@unique([vendorGatewayId, direction, priority]) @@index([vendorGatewayId, direction]) @@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) status EntityStatus @default(ENABLED) notes String? @db.VarChar(500) 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) items LandingLineGroupItem[] gateways CustomerGateway[] policies CustomerGatewayPolicy[] rawCdrs RawCdr[] rules QualitySamplingRule[] @@index([status]) @@index([deletedAt]) @@map("landing_line_groups") } model LandingLineGroupItem { id String @id @db.VarChar(32) lineGroupId String @map("line_group_id") @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) priority Int weight Int @default(1) concurrencyCap Int @default(0) @map("concurrency_cap") 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) lineGroup LandingLineGroup @relation(fields: [lineGroupId], references: [id], onDelete: Cascade) vendorGateway VendorGateway @relation(fields: [vendorGatewayId], references: [id], onDelete: Restrict) @@unique([lineGroupId, vendorGatewayId]) @@unique([lineGroupId, priority]) @@index([vendorGatewayId]) @@map("landing_line_group_items") } model RawCdr { id String @id @db.VarChar(40) eventId String @unique @map("event_id") @db.VarChar(64) callId String @map("call_id") @db.VarChar(255) customerId String? @map("customer_id") @db.VarChar(32) customerGatewayId String? @map("customer_gateway_id") @db.VarChar(32) customerGatewayPolicyId String? @map("customer_gateway_policy_id") @db.VarChar(32) 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) calleeOperator NumberCarrier @default(UNKNOWN) @map("callee_operator") calleeNumberType PhoneNumberType @default(UNKNOWN) @map("callee_number_type") 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) durationSec Int @default(0) @map("duration_sec") sipCode Int @map("sip_code") hangupReason String? @map("hangup_reason") @db.VarChar(120) recordingKey String? @map("recording_key") @db.VarChar(255) configVersion Int? @map("config_version") ratingStatus CdrRatingStatus @default(UNRATED) @map("rating_status") payload Json? receivedAt DateTime @default(now()) @map("received_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) 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) ratedCdr RatedCdr? recording Recording? @@unique([callId, endedAt]) @@index([customerId, startedAt]) @@index([vendorId, startedAt]) @@index([calleeCityCode, startedAt]) @@index([calleeOperator, startedAt]) @@index([businessPrefixId, startedAt]) @@index([sipCode]) @@index([ratingStatus]) @@map("raw_cdrs") } model RatedCdr { id String @id @db.VarChar(40) rawCdrId String @unique @map("raw_cdr_id") @db.VarChar(40) billSec Int @map("bill_sec") customerFee Decimal @default(0) @map("customer_fee") @db.Decimal(20, 6) vendorCost Decimal @default(0) @map("vendor_cost") @db.Decimal(20, 6) grossProfit Decimal @default(0) @map("gross_profit") @db.Decimal(20, 6) customerRate Json? @map("customer_rate") vendorRate Json? @map("vendor_rate") ratedAt DateTime @default(now()) @map("rated_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) rawCdr RawCdr @relation(fields: [rawCdrId], references: [id], onDelete: Restrict) @@index([ratedAt]) @@map("rated_cdrs") } model Recording { id String @id @db.VarChar(40) rawCdrId String? @unique @map("raw_cdr_id") @db.VarChar(40) storageKey String @unique @map("storage_key") @db.VarChar(255) storagePath String @map("storage_path") @db.VarChar(500) sha256 String? @db.Char(64) bytes BigInt @default(0) durationSec Int @default(0) @map("duration_sec") status RecordingStatus @default(PENDING) movedAt DateTime? @map("moved_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) rawCdr RawCdr? @relation(fields: [rawCdrId], references: [id], onDelete: SetNull) reviews QualityReview[] @@index([status, createdAt]) @@map("recordings") } model QualitySamplingRule { id String @id @db.VarChar(32) name String @db.VarChar(120) customerId String? @map("customer_id") @db.VarChar(32) lineGroupId String? @map("line_group_id") @db.VarChar(32) ratio Decimal @db.Decimal(5, 2) status EntityStatus @default(ENABLED) effectiveAt DateTime @default(now()) @map("effective_at") @db.DateTime(3) expiresAt DateTime? @map("expires_at") @db.DateTime(3) 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: SetNull) lineGroup LandingLineGroup? @relation(fields: [lineGroupId], references: [id], onDelete: SetNull) @@index([customerId, status]) @@index([lineGroupId, status]) @@index([deletedAt]) @@map("quality_sampling_rules") } model QualityReview { id String @id @db.VarChar(40) recordingId String @map("recording_id") @db.VarChar(40) reviewerId String @map("reviewer_id") @db.VarChar(32) score Int? result QualityReviewResult issueTags Json? @map("issue_tags") notes String? @db.VarChar(1000) reviewedAt DateTime @default(now()) @map("reviewed_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) version Int @default(1) recording Recording @relation(fields: [recordingId], references: [id], onDelete: Restrict) reviewer User @relation(fields: [reviewerId], references: [id], onDelete: Restrict) @@index([recordingId]) @@index([reviewerId, reviewedAt]) @@map("quality_reviews") } model User { id String @id @db.VarChar(32) username String @unique @db.VarChar(80) displayName String @map("display_name") @db.VarChar(80) phone String? @db.VarChar(32) email String? @unique @db.VarChar(160) passwordHash String? @map("password_hash") @db.VarChar(255) passwordAlgo String? @map("password_algo") @db.VarChar(32) status EntityStatus @default(ENABLED) failedLoginCount Int @default(0) @map("failed_login_count") lockedUntil DateTime? @map("locked_until") @db.DateTime(3) requirePasswordChange Boolean @default(false) @map("require_password_change") lastLoginAt DateTime? @map("last_login_at") @db.DateTime(3) lastLoginIp String? @map("last_login_ip") @db.VarChar(45) 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) userRoles UserRole[] qualityReviews QualityReview[] sessions UserSession[] @@index([status]) @@index([deletedAt]) @@map("users") } model UserSession { id String @id @db.VarChar(40) userId String @map("user_id") @db.VarChar(32) refreshTokenHash String @unique @map("refresh_token_hash") @db.Char(64) userAgent String? @map("user_agent") @db.VarChar(500) ip String? @db.VarChar(45) expiresAt DateTime @map("expires_at") @db.DateTime(3) revokedAt DateTime? @map("revoked_at") @db.DateTime(3) rotatedFromId String? @map("rotated_from_id") @db.VarChar(40) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId, createdAt]) @@index([expiresAt]) @@index([revokedAt]) @@map("user_sessions") } model Role { id String @id @db.VarChar(32) name String @unique @db.VarChar(80) description String? @db.VarChar(300) builtIn Boolean @default(false) @map("built_in") 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) userRoles UserRole[] permissions RolePermission[] @@index([status]) @@index([deletedAt]) @@map("roles") } model Permission { id String @id @db.VarChar(80) module String @db.VarChar(80) action String @db.VarChar(80) description String? @db.VarChar(300) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) roles RolePermission[] @@unique([module, action]) @@map("permissions") } model UserRole { userId String @map("user_id") @db.VarChar(32) roleId String @map("role_id") @db.VarChar(32) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) createdBy String? @map("created_by") @db.VarChar(32) user User @relation(fields: [userId], references: [id], onDelete: Cascade) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) @@id([userId, roleId]) @@index([roleId]) @@map("user_roles") } model RolePermission { roleId String @map("role_id") @db.VarChar(32) permissionId String @map("permission_id") @db.VarChar(80) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) createdBy String? @map("created_by") @db.VarChar(32) role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) @@id([roleId, permissionId]) @@index([permissionId]) @@map("role_permissions") } model AuditLog { id String @id @db.VarChar(40) requestId String @map("request_id") @db.VarChar(64) userId String? @map("user_id") @db.VarChar(32) username String? @db.VarChar(80) roleNames String? @map("role_names") @db.VarChar(300) ip String? @db.VarChar(45) userAgent String? @map("user_agent") @db.VarChar(500) module String @db.VarChar(80) action String @db.VarChar(80) objectType String @map("object_type") @db.VarChar(80) objectId String? @map("object_id") @db.VarChar(80) beforeSummary Json? @map("before_summary") afterSummary Json? @map("after_summary") result AuditResult errorCode String? @map("error_code") @db.VarChar(80) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) @@index([userId, createdAt]) @@index([module, action, createdAt]) @@index([objectType, objectId]) @@map("audit_logs") } model OutboxEvent { id String @id @db.VarChar(40) aggregateType String @map("aggregate_type") @db.VarChar(80) aggregateId String @map("aggregate_id") @db.VarChar(80) eventType String @map("event_type") @db.VarChar(120) payload Json status OutboxStatus @default(PENDING) attempts Int @default(0) availableAt DateTime @default(now()) @map("available_at") @db.DateTime(3) lockedAt DateTime? @map("locked_at") @db.DateTime(3) processedAt DateTime? @map("processed_at") @db.DateTime(3) lastError String? @map("last_error") @db.VarChar(1000) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) @@index([status, availableAt]) @@index([aggregateType, aggregateId]) @@map("outbox_events") } model CallerAnalysisCall { id String @id @db.Char(64) payload Json? updatedAt DateTime @map("updated_at") @db.DateTime(3) @@map("caller_analysis_calls") } model CallerAnalysisEvent { id String @id @db.Char(64) callKey String @map("call_key") @db.Char(64) occurredAt DateTime @map("occurred_at") @db.DateTime(3) payload Json createdAt DateTime @map("created_at") @db.DateTime(3) @@index([callKey, occurredAt], map: "caller_events_call") @@index([createdAt], map: "caller_events_retention") @@map("caller_analysis_events") } model CallerAnalysisState { id String @id @db.Char(64) callKey String @map("call_key") @db.Char(64) view String @db.VarChar(16) startedAt DateTime @map("started_at") @db.DateTime(3) customerId String @map("customer_id") @db.VarChar(32) customerGatewayId String @map("customer_gateway_id") @db.VarChar(32) vendorId String @map("vendor_id") @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) caller String @db.VarChar(64) callee String @db.VarChar(64) city String @db.VarChar(12) carrier String @db.VarChar(20) counts Json payload Json updatedAt DateTime @map("updated_at") @db.DateTime(3) @@index([view, startedAt], map: "caller_states_window") @@index([customerId, view, startedAt], map: "caller_states_customer") @@index([view, caller, startedAt], map: "caller_states_number") @@index([callKey], map: "caller_states_call") @@map("caller_analysis_states") } model CallerAnalysisMinuteBucket { id String @id @db.Char(64) startedAt DateTime @map("started_at") @db.DateTime(3) view String @db.VarChar(16) customerId String @map("customer_id") @db.VarChar(32) customerGatewayId String @map("customer_gateway_id") @db.VarChar(32) vendorId String @map("vendor_id") @db.VarChar(32) vendorGatewayId String @map("vendor_gateway_id") @db.VarChar(32) caller String @db.VarChar(64) city String @db.VarChar(12) carrier String @db.VarChar(20) counts Json @@index([view, startedAt], map: "caller_buckets_window") @@index([customerId, view, startedAt], map: "caller_buckets_customer") @@index([view, caller, startedAt], map: "caller_buckets_number") @@map("caller_analysis_minute_buckets") } model CallerAnalysisAccess { userId String @map("user_id") @db.VarChar(32) customerId String @map("customer_id") @db.VarChar(32) @@id([userId, customerId]) @@map("caller_analysis_access") } model CallerAnalysisHealth { id String @id @db.VarChar(64) payload Json updatedAt DateTime @map("updated_at") @db.DateTime(3) @@map("caller_analysis_health") } model CallerAnalysisAlert { id String @id @db.Char(64) customerId String @map("customer_id") @db.VarChar(32) view String @db.VarChar(16) caller String @db.VarChar(64) status String @db.VarChar(20) payload Json updatedAt DateTime @map("updated_at") @db.DateTime(3) @@index([customerId, status, updatedAt], map: "caller_alerts_customer") @@map("caller_analysis_alerts") } model IdempotencyKey { id String @id @db.VarChar(40) key String @unique @db.VarChar(128) scope String @db.VarChar(80) requestHash String @map("request_hash") @db.Char(64) responseStatus Int? @map("response_status") responseBody Json? @map("response_body") status IdempotencyStatus @default(IN_PROGRESS) lockedUntil DateTime? @map("locked_until") @db.DateTime(3) expiresAt DateTime @map("expires_at") @db.DateTime(3) createdAt DateTime @default(now()) @map("created_at") @db.DateTime(3) updatedAt DateTime @updatedAt @map("updated_at") @db.DateTime(3) @@index([scope, status]) @@index([expiresAt]) @@map("idempotency_keys") }