Consolidate @shieldai/db and @shieldsai/shared-db packages (FRE-4603)
- Merged singleton pattern + type exports from shared-db - Kept FieldEncryptionService from original db package - Upgraded to Prisma v6.2.0 (newer version) - Adopted shared-db's complete schema for multi-service platform - Updated 17 consumer imports across darkwatch, voiceprint, jobs, api - Standardized on @shieldai/db namespace Files changed: - packages/db/package.json (v0.1.0 → v0.2.0) - packages/db/src/index.ts (consolidated exports) - packages/db/prisma/schema.prisma (merged schema) - packages/db/prisma/seed.ts (updated for new schema) - 17 consumer files updated Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
// Prisma schema for ShieldAI
|
||||
// All models for the multi-service SaaS platform
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
@@ -7,406 +10,428 @@ datasource db {
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum SubscriptionTier {
|
||||
BASIC
|
||||
PLUS
|
||||
PREMIUM
|
||||
}
|
||||
|
||||
enum IdentifierType {
|
||||
EMAIL
|
||||
PHONE
|
||||
SSN
|
||||
}
|
||||
|
||||
enum WatchListStatus {
|
||||
ACTIVE
|
||||
PAUSED
|
||||
}
|
||||
|
||||
enum Severity {
|
||||
LOW
|
||||
INFO
|
||||
MEDIUM
|
||||
WARNING
|
||||
HIGH
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
enum AlertChannel {
|
||||
EMAIL
|
||||
PUSH
|
||||
SMS
|
||||
}
|
||||
|
||||
enum AlertStatus {
|
||||
PENDING
|
||||
SENT
|
||||
READ
|
||||
}
|
||||
|
||||
enum ScanJobStatus {
|
||||
PENDING
|
||||
RUNNING
|
||||
COMPLETED
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum DataSource {
|
||||
HIBP
|
||||
SECURITY_TRAILS
|
||||
CENSYS
|
||||
SHODAN
|
||||
HONEYPOT
|
||||
}
|
||||
|
||||
enum AnalysisJobStatus {
|
||||
PENDING
|
||||
RUNNING
|
||||
COMPLETED
|
||||
FAILED
|
||||
}
|
||||
|
||||
enum AnalysisType {
|
||||
SYNTHETIC_DETECTION
|
||||
VOICE_MATCH
|
||||
BATCH
|
||||
}
|
||||
|
||||
enum DetectionVerdict {
|
||||
NATURAL
|
||||
SYNTHETIC
|
||||
UNCERTAIN
|
||||
}
|
||||
// ============================================
|
||||
// User & Authentication Models
|
||||
// ============================================
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
name String?
|
||||
subscriptionTier SubscriptionTier @default(BASIC)
|
||||
familyGroupId String?
|
||||
watchListItems WatchListItem[]
|
||||
alerts Alert[]
|
||||
scanJobs ScanJob[]
|
||||
scanSchedules ScanSchedule[]
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
name String?
|
||||
image String?
|
||||
role UserRole @default(user)
|
||||
|
||||
// Relationships
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
familyGroups FamilyGroupMember[]
|
||||
familyGroupOwned FamilyGroup[] @relation("FamilyGroupOwner")
|
||||
subscriptions Subscription[]
|
||||
alerts Alert[]
|
||||
voiceEnrollments VoiceEnrollment[]
|
||||
analysisJobs AnalysisJob[]
|
||||
spamFeedback SpamFeedback[]
|
||||
spamCallAnalyses SpamCallAnalysis[]
|
||||
spamAuditLogs SpamAuditLog[]
|
||||
normalizedAlerts NormalizedAlert[]
|
||||
correlationGroups CorrelationGroup[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
voiceAnalyses VoiceAnalysis[]
|
||||
spamFeedback SpamFeedback[]
|
||||
spamRules SpamRule[]
|
||||
|
||||
// Audit
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([email])
|
||||
@@index([role])
|
||||
}
|
||||
|
||||
model WatchListItem {
|
||||
id String @id @default(uuid())
|
||||
enum UserRole {
|
||||
user
|
||||
family_admin
|
||||
family_member
|
||||
support
|
||||
}
|
||||
|
||||
model Account {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
provider String
|
||||
providerAccountId String
|
||||
access_token String?
|
||||
refresh_token String?
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([userId, provider, providerAccountId])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
sessionToken String @unique
|
||||
expires DateTime
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([sessionToken])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Family & Subscription Models
|
||||
// ============================================
|
||||
|
||||
model FamilyGroup {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
ownerId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
owner User @relation("FamilyGroupOwner", fields: [ownerId], references: [id])
|
||||
members FamilyGroupMember[]
|
||||
subscriptions Subscription[]
|
||||
|
||||
@@index([ownerId])
|
||||
@@index([name])
|
||||
}
|
||||
|
||||
model FamilyGroupMember {
|
||||
id String @id @default(uuid())
|
||||
groupId String
|
||||
userId String
|
||||
role FamilyMemberRole @default(member)
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
group FamilyGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([groupId, userId])
|
||||
@@index([groupId])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
enum FamilyMemberRole {
|
||||
owner
|
||||
admin
|
||||
member
|
||||
}
|
||||
|
||||
model Subscription {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
identifierType IdentifierType
|
||||
identifierValue String
|
||||
identifierHash String @unique
|
||||
status WatchListStatus @default(ACTIVE)
|
||||
familyGroupId String?
|
||||
stripeId String? @unique
|
||||
tier SubscriptionTier @default(basic)
|
||||
status SubscriptionStatus @default(active)
|
||||
currentPeriodStart DateTime
|
||||
currentPeriodEnd DateTime
|
||||
cancelAtPeriodEnd Boolean @default(false)
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
familyGroup FamilyGroup? @relation(fields: [familyGroupId], references: [id])
|
||||
|
||||
watchlistItems WatchlistItem[]
|
||||
exposures Exposure[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
alerts Alert[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([identifierHash])
|
||||
@@index([familyGroupId])
|
||||
@@index([stripeId])
|
||||
@@index([tier])
|
||||
}
|
||||
|
||||
enum SubscriptionTier {
|
||||
basic
|
||||
plus
|
||||
premium
|
||||
}
|
||||
|
||||
enum SubscriptionStatus {
|
||||
active
|
||||
past_due
|
||||
canceled
|
||||
unpaid
|
||||
trialing
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// DarkWatch Models (Dark Web Monitoring)
|
||||
// ============================================
|
||||
|
||||
model WatchlistItem {
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
type WatchlistType
|
||||
value String
|
||||
hash String // SHA-256 hash for deduplication
|
||||
isActive Boolean @default(true)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
exposures Exposure[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([subscriptionId, type, hash])
|
||||
@@index([subscriptionId])
|
||||
@@index([type])
|
||||
@@index([hash])
|
||||
}
|
||||
|
||||
enum WatchlistType {
|
||||
email
|
||||
phoneNumber
|
||||
ssn
|
||||
address
|
||||
domain
|
||||
}
|
||||
|
||||
model Exposure {
|
||||
id String @id @default(uuid())
|
||||
watchListItemId String
|
||||
watchListItem WatchListItem @relation(fields: [watchListItemId], references: [id], onDelete: Cascade)
|
||||
dataSource DataSource
|
||||
breachName String
|
||||
exposedAt DateTime
|
||||
dataType String[]
|
||||
severity Severity
|
||||
details String?
|
||||
contentHash String @unique
|
||||
alert Alert?
|
||||
subscriptionId String
|
||||
watchlistItemId String?
|
||||
source ExposureSource
|
||||
dataType WatchlistType
|
||||
identifier String
|
||||
identifierHash String
|
||||
severity ExposureSeverity @default(info)
|
||||
metadata Json? // Additional source-specific data
|
||||
isFirstTime Boolean @default(false)
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
watchlistItem WatchlistItem? @relation(fields: [watchlistItemId], references: [id])
|
||||
alerts Alert[]
|
||||
|
||||
detectedAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([watchListItemId])
|
||||
@@index([contentHash])
|
||||
@@index([dataSource])
|
||||
@@index([subscriptionId])
|
||||
@@index([watchlistItemId])
|
||||
@@index([source])
|
||||
@@index([severity])
|
||||
@@index([detectedAt])
|
||||
}
|
||||
|
||||
enum ExposureSource {
|
||||
hibp // Have I Been Pwned
|
||||
securityTrails
|
||||
censys
|
||||
darkWebForum
|
||||
shodan
|
||||
honeypot
|
||||
}
|
||||
|
||||
enum ExposureSeverity {
|
||||
info
|
||||
warning
|
||||
critical
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Notification & Alert Models
|
||||
// ============================================
|
||||
|
||||
model Alert {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
exposureId String @unique
|
||||
exposure Exposure @relation(fields: [exposureId], references: [id], onDelete: Cascade)
|
||||
severity Severity
|
||||
channel AlertChannel
|
||||
status AlertStatus @default(PENDING)
|
||||
dedupKey String
|
||||
sentAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([dedupKey])
|
||||
}
|
||||
|
||||
model ScanJob {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
status ScanJobStatus @default(PENDING)
|
||||
source DataSource?
|
||||
resultCount Int @default(0)
|
||||
errorMessage String?
|
||||
scheduledBy String?
|
||||
webhookEvents WebhookEvent[]
|
||||
completedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
enum ScheduleStatus {
|
||||
ACTIVE
|
||||
PAUSED
|
||||
}
|
||||
|
||||
model ScanSchedule {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
subscriptionId String
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
intervalMinutes Int // minutes between scans
|
||||
cronExpression String // cron expression for scheduling
|
||||
status ScheduleStatus @default(ACTIVE)
|
||||
lastScanAt DateTime?
|
||||
nextScanAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
exposureId String?
|
||||
type AlertType
|
||||
title String
|
||||
message String
|
||||
severity AlertSeverity @default(info)
|
||||
isRead Boolean @default(false)
|
||||
readAt DateTime?
|
||||
channel AlertChannel[] // Array of notification channels
|
||||
|
||||
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
exposure Exposure? @relation(fields: [exposureId], references: [id])
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([userId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
enum WebhookEventType {
|
||||
SCAN_TRIGGER
|
||||
BREACH_DETECTED
|
||||
SUBSCRIPTION_CHANGE
|
||||
}
|
||||
|
||||
model WebhookEvent {
|
||||
id String @id @default(uuid())
|
||||
eventType WebhookEventType
|
||||
payload String
|
||||
source String?
|
||||
signature String?
|
||||
processed Boolean @default(false)
|
||||
processedAt DateTime?
|
||||
scanJobId String?
|
||||
scanJob ScanJob? @relation(fields: [scanJobId], references: [id], onDelete: SetNull)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([eventType, processed])
|
||||
@@index([subscriptionId])
|
||||
@@index([userId])
|
||||
@@index([isRead])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
enum AlertType {
|
||||
exposure_detected
|
||||
exposure_resolved
|
||||
scan_complete
|
||||
subscription_changed
|
||||
system_warning
|
||||
}
|
||||
|
||||
enum AlertSeverity {
|
||||
info
|
||||
warning
|
||||
critical
|
||||
}
|
||||
|
||||
enum AlertChannel {
|
||||
email
|
||||
push
|
||||
sms
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// VoicePrint Models (Voice Cloning Detection)
|
||||
// ============================================
|
||||
|
||||
model VoiceEnrollment {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
label String
|
||||
embeddingVector Float[]
|
||||
embeddingDim Int @default(192)
|
||||
audioFilePath String?
|
||||
sampleRate Int @default(16000)
|
||||
durationSec Float?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
name String
|
||||
voiceHash String // FAISS embedding hash
|
||||
audioMetadata Json? // Sample rate, duration, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
analyses VoiceAnalysis[]
|
||||
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([embeddingDim])
|
||||
@@index([voiceHash])
|
||||
}
|
||||
|
||||
model AnalysisJob {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
analysisType AnalysisType
|
||||
audioFilePath String
|
||||
status AnalysisJobStatus @default(PENDING)
|
||||
result AnalysisResult?
|
||||
errorMessage String?
|
||||
completedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
model VoiceAnalysis {
|
||||
id String @id @default(uuid())
|
||||
enrollmentId String?
|
||||
userId String
|
||||
audioHash String // Content hash of audio file
|
||||
isSynthetic Boolean
|
||||
confidence Float // 0.0 to 1.0
|
||||
analysisResult Json // Full ML analysis results
|
||||
audioUrl String // S3 storage URL
|
||||
|
||||
enrollment VoiceEnrollment? @relation(fields: [enrollmentId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([createdAt])
|
||||
@@index([userId])
|
||||
@@index([enrollmentId])
|
||||
@@index([audioHash])
|
||||
}
|
||||
|
||||
model AnalysisResult {
|
||||
id String @id @default(uuid())
|
||||
analysisJobId String @unique
|
||||
analysisJob AnalysisJob @relation(fields: [analysisJobId], references: [id], onDelete: Cascade)
|
||||
syntheticScore Float
|
||||
verdict DetectionVerdict
|
||||
matchedEnrollmentId String?
|
||||
matchedSimilarity Float?
|
||||
confidence Float
|
||||
processingTimeMs Int
|
||||
modelVersion String?
|
||||
metadata String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([analysisJobId])
|
||||
@@index([verdict])
|
||||
}
|
||||
|
||||
enum SpamDecision {
|
||||
BLOCK
|
||||
FLAG
|
||||
ALLOW
|
||||
}
|
||||
// ============================================
|
||||
// SpamShield Models (Spam Detection)
|
||||
// ============================================
|
||||
|
||||
model SpamFeedback {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
phoneNumber String // AES-256 encrypted PII
|
||||
phoneNumberHash String // SHA-256 hash for anonymized lookup
|
||||
isSpam Boolean
|
||||
label String?
|
||||
metadata String? // Unbounded JSON
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
phoneNumber String
|
||||
phoneNumberHash String // SHA-256 hash
|
||||
isSpam Boolean
|
||||
confidence Float? // ML model confidence
|
||||
feedbackType FeedbackType
|
||||
metadata Json? // Call duration, time, etc.
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([phoneNumberHash])
|
||||
@@index([createdAt])
|
||||
@@index([isSpam])
|
||||
}
|
||||
|
||||
model SpamCallAnalysis {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
phoneNumber String
|
||||
callTimestamp DateTime
|
||||
hiyaReputationScore Float?
|
||||
truecallerSpamScore Float?
|
||||
decision SpamDecision
|
||||
confidence Float
|
||||
ruleMatches String[] // IDs of matched rules
|
||||
auditLogs SpamAuditLog[]
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([phoneNumber])
|
||||
@@index([callTimestamp])
|
||||
enum FeedbackType {
|
||||
initial_detection
|
||||
user_confirmation
|
||||
user_rejection
|
||||
auto_learned
|
||||
}
|
||||
|
||||
model SpamRule {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
pattern String @db.VarChar(500) // Regex pattern - validated for ReDoS at application layer
|
||||
decision SpamDecision
|
||||
description String?
|
||||
isActive Boolean @default(true)
|
||||
priority Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([isActive])
|
||||
@@index([priority])
|
||||
}
|
||||
|
||||
model SpamAuditLog {
|
||||
id String @id @default(uuid())
|
||||
analysisId String?
|
||||
analysis SpamCallAnalysis? @relation(fields: [analysisId], references: [id], onDelete: SetNull)
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
phoneNumber String
|
||||
decision SpamDecision
|
||||
reason String
|
||||
ruleId String?
|
||||
createdAt DateTime @default(now())
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
isGlobal Boolean @default(false)
|
||||
ruleType RuleType
|
||||
pattern String
|
||||
action RuleAction
|
||||
priority Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([createdAt])
|
||||
@@index([decision])
|
||||
@@index([isGlobal])
|
||||
@@index([ruleType])
|
||||
}
|
||||
|
||||
enum AlertSource {
|
||||
DARKWATCH
|
||||
SPAMSHIELD
|
||||
VOICEPRINT
|
||||
CALL_ANALYSIS
|
||||
enum RuleType {
|
||||
phoneNumber
|
||||
areaCode
|
||||
prefix
|
||||
pattern
|
||||
reputation
|
||||
}
|
||||
|
||||
enum AlertCategory {
|
||||
BREACH_EXPOSURE
|
||||
SPAM_CALL
|
||||
SPAM_SMS
|
||||
SYNTHETIC_VOICE
|
||||
VOICE_MISMATCH
|
||||
CALL_QUALITY
|
||||
CALL_ANOMALY
|
||||
CALL_EVENT
|
||||
enum RuleAction {
|
||||
block
|
||||
flag
|
||||
allow
|
||||
challenge
|
||||
}
|
||||
|
||||
enum CorrelationStatus {
|
||||
ACTIVE
|
||||
RESOLVED
|
||||
FALSE_POSITIVE
|
||||
}
|
||||
// ============================================
|
||||
// Audit & Analytics Models
|
||||
// ============================================
|
||||
|
||||
enum EntityType {
|
||||
PHONE_NUMBER
|
||||
EMAIL
|
||||
USER_ID
|
||||
CALL_ID
|
||||
IP_ADDRESS
|
||||
}
|
||||
model AuditLog {
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
action String
|
||||
resource String
|
||||
resourceId String?
|
||||
changes Json? // Before/after values
|
||||
metadata Json?
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
model NormalizedAlert {
|
||||
id String @id @default(uuid())
|
||||
source AlertSource
|
||||
category AlertCategory
|
||||
severity Severity
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
description String
|
||||
entities Json // [{ type: EntityType, value: string }]
|
||||
sourceAlertId String
|
||||
groupId String?
|
||||
correlationGroup CorrelationGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull)
|
||||
payload Json
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId, createdAt])
|
||||
@@index([groupId])
|
||||
@@index([sourceAlertId])
|
||||
@@index([source])
|
||||
@@index([severity])
|
||||
}
|
||||
|
||||
model CorrelationGroup {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade, map: "corr_user_idx")
|
||||
entities Json // [{ type: EntityType, value: string }]
|
||||
highestSeverity Severity
|
||||
status CorrelationStatus @default(ACTIVE)
|
||||
alertCount Int @default(0)
|
||||
alerts NormalizedAlert[]
|
||||
summary String?
|
||||
resolvedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId, status])
|
||||
@@index([userId])
|
||||
@@index([action])
|
||||
@@index([resource])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model KPISnapshot {
|
||||
id String @id @default(uuid())
|
||||
date DateTime @unique
|
||||
metricName String
|
||||
metricValue Float
|
||||
metadata Json?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([metricName])
|
||||
@@index([date])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user