Files
biblical-guide.com/prisma/schema.prisma

393 lines
11 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
passwordHash String
name String?
role String @default("user") // "user", "admin", "moderator"
theme String @default("light")
fontSize String @default("medium")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
sessions Session[]
bookmarks Bookmark[]
chapterBookmarks ChapterBookmark[]
notes Note[]
chatMessages ChatMessage[]
chatConversations ChatConversation[]
prayerRequests PrayerRequest[]
userPrayers UserPrayer[]
readingHistory ReadingHistory[]
preferences UserPreference[]
createdPages Page[] @relation("PageCreator")
updatedPages Page[] @relation("PageUpdater")
uploadedFiles MediaFile[]
createdSocialMedia SocialMediaLink[] @relation("SocialMediaCreator")
updatedSocialMedia SocialMediaLink[] @relation("SocialMediaUpdater")
updatedMailgunSettings MailgunSettings[] @relation("MailgunSettingsUpdater")
@@index([role])
}
model Session {
id String @id @default(uuid())
userId String
token String @unique
expiresAt DateTime
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([token])
}
model BibleVersion {
id String @id @default(uuid())
name String // e.g., "King James Version", "Cornilescu"
abbreviation String // e.g., "KJV", "CORNILESCU", "NIV"
language String // e.g., "en", "ro", "es"
description String?
country String?
englishTitle String?
flagImageUrl String?
zipFileUrl String?
isDefault Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
books BibleBook[]
@@unique([abbreviation, language])
@@index([language])
@@index([isDefault])
}
model BibleBook {
id String @id @default(uuid())
versionId String
name String // Version-specific book name
testament String
orderNum Int
bookKey String // For cross-version matching (e.g., "genesis", "exodus")
chapters BibleChapter[]
chapterBookmarks ChapterBookmark[]
version BibleVersion @relation(fields: [versionId], references: [id])
@@unique([versionId, orderNum])
@@unique([versionId, bookKey])
@@index([versionId])
@@index([testament])
}
model BibleChapter {
id String @id @default(uuid())
bookId String
chapterNum Int
verses BibleVerse[]
book BibleBook @relation(fields: [bookId], references: [id])
@@unique([bookId, chapterNum])
@@index([bookId])
}
model BibleVerse {
id String @id @default(uuid())
chapterId String
verseNum Int
text String @db.Text
chapter BibleChapter @relation(fields: [chapterId], references: [id])
bookmarks Bookmark[]
notes Note[]
@@unique([chapterId, verseNum])
@@index([chapterId])
}
model BiblePassage {
id String @id @default(uuid())
testament String // 'OT' or 'NT'
book String
chapter Int
verse Int
ref String // Generated field: "book chapter:verse"
lang String @default("ro")
translation String @default("FIDELA")
textRaw String @db.Text
textNorm String @db.Text // Normalized text for embedding
embedding String? // Will be changed to vector later when extension is available
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([translation, lang, book, chapter, verse])
@@index([book, chapter])
@@index([testament])
}
model ChatConversation {
id String @id @default(uuid())
userId String? // Optional for anonymous users
title String // Auto-generated from first message
language String // 'ro' or 'en'
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastMessageAt DateTime @default(now())
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
messages ChatMessage[]
@@index([userId, language, lastMessageAt])
@@index([isActive, lastMessageAt])
}
model ChatMessage {
id String @id @default(uuid())
conversationId String
userId String? // Keep for backward compatibility
role ChatMessageRole
content String @db.Text
metadata Json? // Store verse references, etc.
timestamp DateTime @default(now())
conversation ChatConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([conversationId, timestamp])
@@index([userId, timestamp])
}
enum ChatMessageRole {
USER
ASSISTANT
SYSTEM
}
model Bookmark {
id String @id @default(uuid())
userId String
verseId String
note String?
color String @default("#FFD700")
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
verse BibleVerse @relation(fields: [verseId], references: [id])
@@unique([userId, verseId])
@@index([userId])
}
model ChapterBookmark {
id String @id @default(uuid())
userId String
bookId String
chapterNum Int
note String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
book BibleBook @relation(fields: [bookId], references: [id])
@@unique([userId, bookId, chapterNum])
@@index([userId])
}
model Note {
id String @id @default(uuid())
userId String
verseId String
content String @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
verse BibleVerse @relation(fields: [verseId], references: [id])
@@index([userId])
@@index([verseId])
}
model PrayerRequest {
id String @id @default(uuid())
userId String?
title String
description String @db.Text
category String // personal, family, health, work, ministry, world
author String // Display name (can be "Anonymous" or user's name)
isAnonymous Boolean @default(false)
prayerCount Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
prayers Prayer[]
userPrayers UserPrayer[]
@@index([createdAt])
@@index([category])
@@index([isActive])
}
model Prayer {
id String @id @default(uuid())
requestId String
ipAddress String // For anonymous prayer counting
createdAt DateTime @default(now())
request PrayerRequest @relation(fields: [requestId], references: [id], onDelete: Cascade)
@@unique([requestId, ipAddress])
}
model UserPrayer {
id String @id @default(uuid())
userId String
requestId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
request PrayerRequest @relation(fields: [requestId], references: [id], onDelete: Cascade)
@@unique([userId, requestId])
@@index([userId])
@@index([requestId])
}
model ReadingHistory {
id String @id @default(uuid())
userId String
bookId String
chapterNum Int
verseNum Int?
viewedAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, viewedAt])
}
model UserPreference {
id String @id @default(uuid())
userId String
key String
value String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, key])
}
model Page {
id String @id @default(uuid())
title String
slug String @unique
content String @db.Text
contentType PageContentType @default(RICH_TEXT)
excerpt String? @db.Text
featuredImage String?
seoTitle String?
seoDescription String?
status PageStatus @default(DRAFT)
showInNavigation Boolean @default(false)
showInFooter Boolean @default(false)
navigationOrder Int?
footerOrder Int?
createdBy String
updatedBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
publishedAt DateTime?
creator User @relation("PageCreator", fields: [createdBy], references: [id])
updater User @relation("PageUpdater", fields: [updatedBy], references: [id])
@@index([slug])
@@index([status])
@@index([showInNavigation, navigationOrder])
@@index([showInFooter, footerOrder])
}
model MediaFile {
id String @id @default(uuid())
filename String
originalName String
mimeType String
size Int
path String
url String
alt String?
uploadedBy String
createdAt DateTime @default(now())
uploader User @relation(fields: [uploadedBy], references: [id])
@@index([uploadedBy])
@@index([mimeType])
}
enum PageContentType {
RICH_TEXT
HTML
MARKDOWN
}
enum PageStatus {
DRAFT
PUBLISHED
ARCHIVED
}
model SocialMediaLink {
id String @id @default(uuid())
platform String // facebook, twitter, instagram, youtube, linkedin, tiktok, etc.
name String // Display name (e.g., "Facebook", "Instagram")
url String // Full URL to the social media profile
icon String // Icon identifier (material-ui icon name)
isEnabled Boolean @default(true)
order Int @default(0) // Display order in footer
createdBy String
updatedBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
creator User @relation("SocialMediaCreator", fields: [createdBy], references: [id])
updater User @relation("SocialMediaUpdater", fields: [updatedBy], references: [id])
@@unique([platform])
@@index([isEnabled, order])
}
model MailgunSettings {
id String @id @default(uuid())
apiKey String // Encrypted Mailgun API key
domain String // Mailgun domain (e.g., mg.yourdomain.com)
region String @default("US") // US or EU
fromEmail String // Default from email address
fromName String // Default from name
replyToEmail String? // Optional reply-to address
isEnabled Boolean @default(false)
testMode Boolean @default(true)
webhookUrl String? // Mailgun webhook URL for tracking
updatedBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
updater User @relation("MailgunSettingsUpdater", fields: [updatedBy], references: [id])
@@index([isEnabled])
}