// prisma/schema.prisma generator client { provider = "prisma-client-js" previewFeatures = ["fullTextIndex"] } datasource db { provider = "mysql" url = env("DATABASE_URL") } // ============================================ // AUTHENTICATION & USERS // ============================================ model User { id String @id @default(uuid()) email String @unique displayName String? @map("display_name") passwordHash String? @map("password_hash") authProvider String @default("local") @map("auth_provider") // local, google, microsoft providerId String? @map("provider_id") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") documents Document[] comments Comment[] bugReports BugReport[] @@map("users") } // ============================================ // DICTIONARY / TERMS // ============================================ model Term { id String @id @default(uuid()) wordText String @map("word_text") @db.VarChar(255) normalizedText String @map("normalized_text") @db.VarChar(255) language String @default("hr") @db.VarChar(10) wordType WordType @map("word_type") cefrLevel CefrLevel @map("cefr_level") shortDescription String? @map("short_description") @db.Text tags String? @db.Text // JSON array stored as text iconAssetId String? @map("icon_asset_id") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") media TermMedia[] examples TermExample[] sentenceTokens SentenceToken[] @@index([normalizedText]) @@fulltext([wordText, normalizedText]) @@map("terms") } model TermMedia { id String @id @default(uuid()) termId String @map("term_id") kind MediaKind url String @db.VarChar(500) durationMs Int? @map("duration_ms") width Int? height Int? checksum String? @db.VarChar(64) createdAt DateTime @default(now()) @map("created_at") term Term @relation(fields: [termId], references: [id], onDelete: Cascade) @@index([termId]) @@map("term_media") } model TermExample { id String @id @default(uuid()) termId String @map("term_id") exampleText String @map("example_text") @db.Text notes String? @db.Text createdAt DateTime @default(now()) @map("created_at") term Term @relation(fields: [termId], references: [id], onDelete: Cascade) @@index([termId]) @@map("term_examples") } // ============================================ // DOCUMENTS & SENTENCES (ZNAKOPIS) // ============================================ model Document { id String @id @default(uuid()) ownerUserId String? @map("owner_user_id") title String @db.VarChar(255) description String? @db.Text visibility Visibility @default(PRIVATE) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") owner User? @relation(fields: [ownerUserId], references: [id], onDelete: SetNull) pages DocumentPage[] @@index([ownerUserId]) @@map("documents") } model DocumentPage { id String @id @default(uuid()) documentId String @map("document_id") pageIndex Int @map("page_index") title String? @db.VarChar(255) document Document @relation(fields: [documentId], references: [id], onDelete: Cascade) sentences Sentence[] @@unique([documentId, pageIndex]) @@index([documentId]) @@map("document_pages") } model Sentence { id String @id @default(uuid()) documentPageId String @map("document_page_id") sentenceIndex Int @map("sentence_index") rawText String? @map("raw_text") @db.Text documentPage DocumentPage @relation(fields: [documentPageId], references: [id], onDelete: Cascade) tokens SentenceToken[] @@unique([documentPageId, sentenceIndex]) @@index([documentPageId]) @@map("sentences") } model SentenceToken { id String @id @default(uuid()) sentenceId String @map("sentence_id") tokenIndex Int @map("token_index") termId String? @map("term_id") displayText String @map("display_text") @db.VarChar(255) isPunctuation Boolean @default(false) @map("is_punctuation") sentence Sentence @relation(fields: [sentenceId], references: [id], onDelete: Cascade) term Term? @relation(fields: [termId], references: [id], onDelete: SetNull) @@unique([sentenceId, tokenIndex]) @@index([sentenceId]) @@index([termId]) @@map("sentence_tokens") } // ============================================ // COMMUNITY & SUPPORT // ============================================ model Comment { id String @id @default(uuid()) userId String @map("user_id") content String @db.Text context String? @db.VarChar(255) // e.g., "term:uuid" or "general" createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@map("comments") } model BugReport { id String @id @default(uuid()) userId String? @map("user_id") title String @db.VarChar(255) description String @db.Text status BugStatus @default(OPEN) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@index([userId]) @@index([status]) @@map("bug_reports") } // ============================================ // ENUMS // ============================================ enum WordType { NOUN VERB ADJECTIVE ADVERB PRONOUN PREPOSITION CONJUNCTION INTERJECTION PHRASE OTHER } enum CefrLevel { A1 A2 B1 B2 C1 C2 } enum MediaKind { VIDEO IMAGE ILLUSTRATION } enum Visibility { PRIVATE SHARED PUBLIC } enum BugStatus { OPEN IN_PROGRESS RESOLVED CLOSED }