Keep/keep-notes/prisma/schema.prisma

265 lines
9.8 KiB
Plaintext

// 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"
}
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])
}