Files
Keep/keep-notes/prisma/schema.prisma

382 lines
13 KiB
Plaintext

generator client {
provider = "prisma-client-js"
binaryTargets = ["debian-openssl-1.1.x", "native"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
password String?
role String @default("USER")
image String?
theme String @default("light")
cardSizeMode String @default("variable")
resetToken String? @unique
resetTokenExpiry DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
aiFeedback AiFeedback[]
labels Label[]
memoryEchoInsights MemoryEchoInsight[]
notes Note[]
sentShares NoteShare[] @relation("SentShares")
receivedShares NoteShare[] @relation("ReceivedShares")
notebooks Notebook[]
sessions Session[]
aiSettings UserAISettings?
agents Agent[]
workflows Workflow[]
conversations Conversation[]
canvases Canvas[]
}
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
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String
expires DateTime
@@id([identifier, token])
}
model Notebook {
id String @id @default(cuid())
name String
icon String?
color String?
order Int
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
labels Label[]
notes Note[]
agents Agent[]
workflows Workflow[]
conversations Conversation[]
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, order])
@@index([userId])
}
model Label {
id String @id @default(cuid())
name String
color String @default("gray")
notebookId String?
userId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
notebook Notebook? @relation(fields: [notebookId], references: [id], onDelete: Cascade)
notes Note[] @relation("LabelToNote")
@@unique([notebookId, name])
@@index([notebookId])
@@index([userId])
}
model Note {
id String @id @default(cuid())
title String?
content String
color String @default("default")
isPinned Boolean @default(false)
isArchived Boolean @default(false)
trashedAt DateTime?
type String @default("text")
dismissedFromRecent Boolean @default(false)
checkItems String?
labels String?
images String?
links String?
reminder DateTime?
isReminderDone Boolean @default(false)
reminderRecurrence String?
reminderLocation String?
isMarkdown Boolean @default(false)
size String @default("small")
sharedWith String?
userId String?
order Int @default(0)
notebookId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contentUpdatedAt DateTime @default(now())
autoGenerated Boolean?
aiProvider String?
aiConfidence Int?
language String?
languageConfidence Float?
lastAiAnalysis DateTime?
aiFeedback AiFeedback[]
memoryEchoAsNote2 MemoryEchoInsight[] @relation("EchoNote2")
memoryEchoAsNote1 MemoryEchoInsight[] @relation("EchoNote1")
notebook Notebook? @relation(fields: [notebookId], references: [id])
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
shares NoteShare[]
labelRelations Label[] @relation("LabelToNote")
noteEmbedding NoteEmbedding?
@@index([isPinned])
@@index([isArchived])
@@index([trashedAt])
@@index([order])
@@index([reminder])
@@index([userId])
@@index([userId, notebookId])
}
model NoteShare {
id String @id @default(cuid())
noteId String
userId String
sharedBy String
status String @default("pending")
permission String @default("view")
notifiedAt DateTime?
respondedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sharer User @relation("SentShares", fields: [sharedBy], references: [id], onDelete: Cascade)
user User @relation("ReceivedShares", fields: [userId], references: [id], onDelete: Cascade)
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
@@unique([noteId, userId])
@@index([userId])
@@index([status])
@@index([sharedBy])
}
model SystemConfig {
key String @id
value String
}
model AiFeedback {
id String @id @default(cuid())
noteId String
userId String?
feedbackType String
feature String
originalContent String
correctedContent String?
metadata String?
createdAt DateTime @default(now())
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
note Note @relation(fields: [noteId], 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
insightDate DateTime @default(now())
viewed Boolean @default(false)
feedback String?
dismissed Boolean @default(false)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
note2 Note @relation("EchoNote2", fields: [note2Id], references: [id], onDelete: Cascade)
note1 Note @relation("EchoNote1", fields: [note1Id], references: [id], onDelete: Cascade)
@@unique([userId, insightDate])
@@index([userId, insightDate])
@@index([userId, dismissed])
}
model UserAISettings {
userId String @id
titleSuggestions Boolean @default(true)
semanticSearch Boolean @default(true)
paragraphRefactor Boolean @default(true)
memoryEcho Boolean @default(true)
memoryEchoFrequency String @default("daily")
aiProvider String @default("auto")
preferredLanguage String @default("auto")
fontSize String @default("medium")
demoMode Boolean @default(false)
showRecentNotes Boolean @default(true)
/// "masonry" = grille cartes Muuri ; "tabs" = onglets + panneau (type OneNote). Ancienne valeur "list" migrée vers "tabs" en lecture.
notesViewMode String @default("masonry")
emailNotifications Boolean @default(false)
desktopNotifications Boolean @default(false)
anonymousAnalytics Boolean @default(false)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([memoryEcho])
@@index([aiProvider])
@@index([memoryEchoFrequency])
@@index([preferredLanguage])
}
model NoteEmbedding {
id String @id @default(cuid())
noteId String @unique
embedding String
createdAt DateTime @default(now())
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
@@index([noteId])
}
// ============================================================================
// NEW MODELS FOR AGENTIC SYSTEM & LAB
// ============================================================================
model Agent {
id String @id @default(cuid())
name String
description String?
type String? @default("scraper") // scraper, researcher, monitor, custom
role String // System prompt / Persona
sourceUrls String? // JSON list of URLs to scrape
frequency String @default("manual") // manual, hourly, daily, weekly, monthly
lastRun DateTime?
nextRun DateTime?
isEnabled Boolean @default(true)
targetNotebookId String?
sourceNotebookId String? // For monitor type: notebook to watch
tools String? @default("[]") // JSON array: ["web_search", "note_search", ...]
maxSteps Int @default(10) // Max tool-use iterations
notifyEmail Boolean @default(false) // Send email notification after execution
includeImages Boolean @default(false) // Extract images from scraped pages
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
notebook Notebook? @relation(fields: [targetNotebookId], references: [id])
actions AgentAction[]
@@index([userId])
@@index([isEnabled])
}
model AgentAction {
id String @id @default(cuid())
agentId String
status String @default("pending") // pending, running, success, failure
result String? // ID of the created note or summary message
log String? // Error message or execution log
input String? // JSON: prompt initial + config
toolLog String? // JSON: trace [{step, toolCalls, toolResults}]
tokensUsed Int? // Token consumption
createdAt DateTime @default(now())
agent Agent @relation(fields: [agentId], references: [id], onDelete: Cascade)
@@index([agentId])
}
model Conversation {
id String @id @default(cuid())
title String?
userId String
notebookId String? // Optional context
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
notebook Notebook? @relation(fields: [notebookId], references: [id])
messages ChatMessage[]
@@index([userId])
@@index([notebookId])
}
model ChatMessage {
id String @id @default(cuid())
conversationId String
role String // user, assistant, system
content String
createdAt DateTime @default(now())
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
@@index([conversationId])
}
model Canvas {
id String @id @default(cuid())
name String
data String // Large JSON blob for tldraw state
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
// ============================================================================
// VISUAL WORKFLOW BUILDER
// ============================================================================
model Workflow {
id String @id @default(cuid())
name String
description String?
graph String @default("{\"nodes\":[],\"edges\":[]}") // JSON: React Flow nodes[] + edges[]
isEnabled Boolean @default(true)
userId String
notebookId String? // default target notebook for Create Note nodes
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
notebook Notebook? @relation(fields: [notebookId], references: [id])
runs WorkflowRun[]
@@index([userId])
@@index([isEnabled])
}
model WorkflowRun {
id String @id @default(cuid())
workflowId String
status String @default("running") // running, success, failure
log String? // JSON: per-node status + timing
createdAt DateTime @default(now())
workflow Workflow @relation(fields: [workflowId], references: [id], onDelete: Cascade)
@@index([workflowId])
@@index([status])
}