- Copy apps/api (Fastify server with spamshield/voiceprint/darkwatch services) - Copy apps/web (SolidJS web app) - Copy apps/mobile (SolidJS mobile app) - Copy packages/shared-db (Prisma schema/models) - Add apps/* to pnpm-workspace.yaml
438 lines
10 KiB
Plaintext
438 lines
10 KiB
Plaintext
// 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[]
|
|
|
|
// 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])
|
|
}
|