// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" output = "./client-generated" binaryTargets = ["native", "debian-openssl-3.0.x"] // Force OpenSSL 3.x for Debian Slim } datasource db { provider = "sqlite" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) name String? email String @unique emailVerified DateTime? password String? // Hashed password role String @default("USER") // "USER" or "ADMIN" image String? theme String @default("light") resetToken String? @unique resetTokenExpiry DateTime? accounts Account[] sessions Session[] notes Note[] labels Label[] notebooks Notebook[] // NEW: Relation to notebooks receivedShares NoteShare[] @relation("ReceivedShares") sentShares NoteShare[] @relation("SentShares") // Phase 1 AI Relations aiFeedback AiFeedback[] aiSettings UserAISettings? memoryEchoInsights MemoryEchoInsight[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Account { userId String type String provider String providerAccountId String refresh_token String? access_token String? expires_at Int? token_type String? scope String? id_token String? session_state String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([provider, providerAccountId]) } model Session { sessionToken String @unique userId String expires DateTime user User @relation(fields: [userId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model VerificationToken { identifier String token String expires DateTime @@id([identifier, token]) } // NEW: Notebook model for organizing notes model Notebook { id String @id @default(cuid()) name String icon String? // Emoji or icon name color String? // Hex color for personalization order Int // Manual order for drag & drop userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) notes Note[] // Notes can belong to a notebook labels Label[] // Labels are contextual to this notebook createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId, order]) @@index([userId]) } model Label { id String @id @default(cuid()) name String color String @default("gray") notebookId String? // TEMPORARY: Optional for migration, will be required later notebook Notebook? @relation(fields: [notebookId], references: [id], onDelete: Cascade) notes Note[] // NEW: Many-to-many relation with notes userId String? // DEPRECATED: Kept for migration, will be removed after migration user User? @relation(fields: [userId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([notebookId, name]) // NEW: Labels are unique within a notebook (ignored if notebookId is null) @@index([notebookId]) @@index([userId]) // DEPRECATED: Keep for now, remove after migration } model Note { id String @id @default(cuid()) title String? content String color String @default("default") isPinned Boolean @default(false) isArchived Boolean @default(false) type String @default("text") // "text" or "checklist" checkItems String? // For checklist items stored as JSON string labels String? // Array of label names stored as JSON string (DEPRECATED) images String? // Array of image URLs stored as JSON string links String? // Array of link metadata stored as JSON string reminder DateTime? // Reminder date and time isReminderDone Boolean @default(false) reminderRecurrence String? // "none", "daily", "weekly", "monthly", "custom" reminderLocation String? // Location for location-based reminders isMarkdown Boolean @default(false) // Whether content uses Markdown size String @default("small") // "small", "medium", "large" embedding String? // Vector embeddings stored as JSON string for semantic search sharedWith String? // Array of user IDs (collaborators) stored as JSON string userId String? // Owner of the note user User? @relation(fields: [userId], references: [id], onDelete: Cascade) shares NoteShare[] // All share records for this note order Int @default(0) // NEW: Notebook relation (optional - null = "Notes générales" / Inbox) notebookId String? // NULL = note is in general notes notebook Notebook? @relation(fields: [notebookId], references: [id], onDelete: SetNull) // NEW: Many-to-many relation with labels labelRelations Label[] // Uses implicit _NoteToLabel junction table createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Phase 1 AI Extensions autoGenerated Boolean? // True if title/content was AI-generated aiProvider String? // 'openai' | 'ollama' aiConfidence Int? // 0-100 (collected Phase 1, UI Phase 3) language String? // ISO 639-1: 'fr', 'en', 'es', 'de', 'fa' languageConfidence Float? // 0.0-1.0 lastAiAnalysis DateTime? // Timestamp of last AI analysis // Relations for Phase 1 AI aiFeedback AiFeedback[] memoryEchoAsNote1 MemoryEchoInsight[] @relation("EchoNote1") memoryEchoAsNote2 MemoryEchoInsight[] @relation("EchoNote2") @@index([isPinned]) @@index([isArchived]) @@index([order]) @@index([reminder]) @@index([userId]) @@index([userId, notebookId]) // NEW: For filtering notes by notebook } model NoteShare { id String @id @default(cuid()) noteId String note Note @relation(fields: [noteId], references: [id], onDelete: Cascade) userId String user User @relation("ReceivedShares", fields: [userId], references: [id], onDelete: Cascade) sharedBy String // User ID who shared the note sharer User @relation("SentShares", fields: [sharedBy], references: [id], onDelete: Cascade) status String @default("pending") // "pending", "accepted", "declined", "removed" permission String @default("view") // "view", "comment", "edit" notifiedAt DateTime? respondedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([noteId, userId]) @@index([userId]) @@index([status]) @@index([sharedBy]) } model SystemConfig { key String @id value String } // Phase 1 MVP AI Models model AiFeedback { id String @id @default(cuid()) noteId String userId String? feedbackType String // 'thumbs_up' | 'thumbs_down' | 'correction' feature String // 'title_suggestion' | 'memory_echo' | 'semantic_search' | 'paragraph_refactor' originalContent String // JSON string of AI-generated content correctedContent String? // User's modified version metadata String? // JSON string for additional data (provider, model, timestamp) createdAt DateTime @default(now()) note Note @relation(fields: [noteId], references: [id], onDelete: Cascade) user User? @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([noteId]) @@index([userId]) @@index([feature]) } model MemoryEchoInsight { id String @id @default(cuid()) userId String? note1Id String note2Id String similarityScore Float insight String // AI-generated explanation of the connection insightDate DateTime @default(now()) viewed Boolean @default(false) feedback String? // 'thumbs_up' | 'thumbs_down' dismissed Boolean @default(false) // User dismissed this connection note1 Note @relation("EchoNote1", fields: [note1Id], references: [id], onDelete: Cascade) note2 Note @relation("EchoNote2", fields: [note2Id], references: [id], onDelete: Cascade) user User? @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, insightDate]) @@index([userId, insightDate]) @@index([userId, dismissed]) // For filtering dismissed connections } model UserAISettings { userId String @id // Feature Flags (granular ON/OFF) titleSuggestions Boolean @default(true) semanticSearch Boolean @default(true) paragraphRefactor Boolean @default(true) memoryEcho Boolean @default(true) // Configuration memoryEchoFrequency String @default("daily") // 'daily' | 'weekly' | 'custom' aiProvider String @default("auto") // 'auto' | 'openai' | 'ollama' preferredLanguage String @default("auto") // 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl' fontSize String @default("medium") // 'small' | 'medium' | 'large' | 'extra-large' demoMode Boolean @default(false) // Demo mode for testing Memory Echo // Relation user User @relation(fields: [userId], references: [id], onDelete: Cascade) // Indexes for analytics @@index([memoryEcho]) @@index([aiProvider]) @@index([memoryEchoFrequency]) @@index([preferredLanguage]) }