// Prisma schema for ShieldAI // All models for the multi-service SaaS platform generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ============================================ // User & Authentication Models // ============================================ model User { 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[] voiceAnalyses VoiceAnalysis[] spamFeedback SpamFeedback[] spamRules SpamRule[] normalizedAlerts NormalizedAlert[] correlationGroups CorrelationGroup[] // Audit createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([email]) @@index([role]) } 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 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[] alerts Alert[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId]) @@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()) 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([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()) subscriptionId String userId String 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 @@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 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([voiceHash]) } 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]) @@index([enrollmentId]) @@index([audioHash]) } // ============================================ // SpamShield Models (Spam Detection) // ============================================ model SpamFeedback { 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([isSpam]) } enum FeedbackType { initial_detection user_confirmation user_rejection auto_learned } model SpamRule { 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([isGlobal]) @@index([ruleType]) } enum RuleType { phoneNumber areaCode prefix pattern reputation } enum RuleAction { block flag allow challenge } // ============================================ // Audit & Analytics Models // ============================================ 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()) @@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]) } // ============================================ // Cross-Service Alert Correlation Models // ============================================ enum AlertSource { DARKWATCH SPAMSHIELD VOICEPRINT CALL_ANALYSIS } enum AlertCategory { BREACH_EXPOSURE SPAM_CALL SPAM_SMS SYNTHETIC_VOICE VOICE_MISMATCH CALL_ANOMALY CALL_QUALITY CALL_EVENT } enum NormalizedAlertSeverity { LOW INFO MEDIUM WARNING HIGH CRITICAL } enum CorrelationStatus { ACTIVE RESOLVED } model NormalizedAlert { id String @id @default(uuid()) source AlertSource category AlertCategory severity NormalizedAlertSeverity userId String title String description String entities Json sourceAlertId String groupId String? payload Json? createdAt DateTime updatedAt DateTime @default(now()) @updatedAt correlationGroup CorrelationGroup? @relation(fields: [groupId], references: [id]) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([sourceAlertId]) @@index([userId]) @@index([groupId]) @@index([source]) @@index([severity]) @@index([createdAt]) @@index([userId, createdAt]) } model CorrelationGroup { id String @id @default(uuid()) userId String entities Json highestSeverity NormalizedAlertSeverity status CorrelationStatus @default(ACTIVE) alertCount Int @default(0) summary String? resolvedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt alerts NormalizedAlert[] user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([status]) @@index([userId, status]) @@index([createdAt]) }