feat: brainstorm sessions, PDF document Q&A, embedding fixes, and UI improvements
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
- Add brainstorm feature with collaborative canvas, AI idea generation, live cursors, playback, and export - Add PDF upload/extraction/ingestion pipeline with pgvector document search (RAG) - Add document Q&A overlay with streaming chat and PDF preview - Add note attachments UI with status polling, grid layout, and auto-scroll - Add task extraction AI tool and agent executor improvements - Fix NoteEmbedding missing updatedAt column, re-index 66 notes with 1536-dim embeddings - Fix brainstorm 'Create Note' button: add success toast and redirect to created note - Fix memory echo notification infinite polling - Fix chat route to always include document_search tool - Add brainstorm i18n keys across all 14 locales - Add socket server for real-time brainstorm collaboration - Add hierarchical notebook selector and organize notebook dialog improvements - Add sidebar brainstorm section with session management - Update prisma schema with brainstorm tables, attachments, and document chunks
This commit is contained in:
@@ -9,35 +9,40 @@ datasource db {
|
||||
}
|
||||
|
||||
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")
|
||||
resetToken String? @unique
|
||||
resetTokenExpiry DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
cardSizeMode String @default("variable")
|
||||
accounts Account[]
|
||||
agents Agent[]
|
||||
aiFeedback AiFeedback[]
|
||||
canvases Canvas[]
|
||||
conversations Conversation[]
|
||||
labels Label[]
|
||||
memoryEchoInsights MemoryEchoInsight[]
|
||||
notes Note[]
|
||||
noteHistories NoteHistory[]
|
||||
sentShares NoteShare[] @relation("SentShares")
|
||||
receivedShares NoteShare[] @relation("ReceivedShares")
|
||||
notebooks Notebook[]
|
||||
sessions Session[]
|
||||
aiSettings UserAISettings?
|
||||
workflows Workflow[]
|
||||
notifications Notification[]
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
password String?
|
||||
role String @default("USER")
|
||||
image String?
|
||||
theme String @default("light")
|
||||
resetToken String? @unique
|
||||
resetTokenExpiry DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
cardSizeMode String @default("variable")
|
||||
accounts Account[]
|
||||
agents Agent[]
|
||||
aiFeedback AiFeedback[]
|
||||
brainstormActivities BrainstormActivity[]
|
||||
brainstormParticipant BrainstormParticipant[]
|
||||
brainstormSessions BrainstormSession[]
|
||||
canvases Canvas[]
|
||||
conversations Conversation[]
|
||||
labels Label[]
|
||||
memoryEchoInsights MemoryEchoInsight[]
|
||||
notes Note[]
|
||||
noteHistories NoteHistory[]
|
||||
sentShares NoteShare[] @relation("SentShares")
|
||||
receivedShares NoteShare[] @relation("ReceivedShares")
|
||||
sentBrainstormShares BrainstormShare[] @relation("SentBrainstormShares")
|
||||
receivedBrainstormShares BrainstormShare[] @relation("ReceivedBrainstormShares")
|
||||
notebooks Notebook[]
|
||||
notifications Notification[]
|
||||
sessions Session[]
|
||||
aiSettings UserAISettings?
|
||||
workflows Workflow[]
|
||||
}
|
||||
|
||||
model Account {
|
||||
@@ -82,19 +87,19 @@ model Notebook {
|
||||
icon String?
|
||||
color String?
|
||||
order Int
|
||||
parentId String?
|
||||
trashedAt DateTime?
|
||||
userId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
parentId String?
|
||||
trashedAt DateTime?
|
||||
agents Agent[]
|
||||
conversations Conversation[]
|
||||
labels Label[]
|
||||
notes Note[]
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
workflows Workflow[]
|
||||
parent Notebook? @relation("NotebookTree", fields: [parentId], references: [id], onDelete: Cascade)
|
||||
children Notebook[] @relation("NotebookTree")
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
workflows Workflow[]
|
||||
|
||||
@@index([userId, order])
|
||||
@@index([userId])
|
||||
@@ -106,11 +111,11 @@ model Label {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
color String @default("gray")
|
||||
type String @default("user") // "ai" or "user"
|
||||
notebookId String?
|
||||
userId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
type String @default("user")
|
||||
notebook Notebook? @relation(fields: [notebookId], references: [id], onDelete: Cascade)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
notes Note[] @relation("LabelToNote")
|
||||
@@ -121,51 +126,56 @@ model Label {
|
||||
}
|
||||
|
||||
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("richtext")
|
||||
dismissedFromRecent Boolean @default(false)
|
||||
checkItems String?
|
||||
labels String?
|
||||
images String?
|
||||
id String @id @default(cuid())
|
||||
title String?
|
||||
content String
|
||||
color String @default("default")
|
||||
isPinned Boolean @default(false)
|
||||
isArchived Boolean @default(false)
|
||||
type String @default("richtext")
|
||||
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?
|
||||
trashedAt DateTime?
|
||||
historyEnabled Boolean @default(false)
|
||||
/// Illustration SVG (sanitized) for editorial feed thumbnail — optional, peut être généré par IA
|
||||
illustrationSvg String?
|
||||
links String?
|
||||
reminder DateTime?
|
||||
isReminderDone Boolean @default(false)
|
||||
reminderRecurrence String?
|
||||
reminderLocation String?
|
||||
isMarkdown Boolean @default(false) // DEPRECATED: use type = 'markdown' instead
|
||||
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?
|
||||
trashedAt DateTime?
|
||||
tsv Unsupported("tsvector")?
|
||||
aiFeedback AiFeedback[]
|
||||
memoryEchoAsNote1 MemoryEchoInsight[] @relation("EchoNote1")
|
||||
memoryEchoAsNote2 MemoryEchoInsight[] @relation("EchoNote2")
|
||||
notebook Notebook? @relation(fields: [notebookId], references: [id])
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
noteEmbedding NoteEmbedding?
|
||||
shares NoteShare[]
|
||||
labelRelations Label[] @relation("LabelToNote")
|
||||
historyEntries NoteHistory[]
|
||||
historyEnabled Boolean @default(false)
|
||||
illustrationSvg String?
|
||||
tsv Unsupported("tsvector")?
|
||||
aiFeedback AiFeedback[]
|
||||
convertedBrainstormIdeas BrainstormIdea[] @relation("ConvertedBrainstormIdea")
|
||||
exportedBrainstormSessions BrainstormSession[] @relation("ExportedBrainstorm")
|
||||
sourceBrainstormSessions BrainstormSession[] @relation("SourceBrainstorm")
|
||||
memoryEchoAsNote1 MemoryEchoInsight[] @relation("EchoNote1")
|
||||
memoryEchoAsNote2 MemoryEchoInsight[] @relation("EchoNote2")
|
||||
notebook Notebook? @relation(fields: [notebookId], references: [id])
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
noteEmbedding NoteEmbedding?
|
||||
historyEntries NoteHistory[]
|
||||
shares NoteShare[]
|
||||
labelRelations Label[] @relation("LabelToNote")
|
||||
attachments NoteAttachment[]
|
||||
brainstormNoteRefs BrainstormNoteRef[]
|
||||
|
||||
@@index([isPinned])
|
||||
@@index([isArchived])
|
||||
@@ -178,26 +188,26 @@ model Note {
|
||||
|
||||
model NoteHistory {
|
||||
id String @id @default(cuid())
|
||||
noteId String
|
||||
userId String
|
||||
version Int
|
||||
reason String?
|
||||
title String?
|
||||
content String
|
||||
color String
|
||||
isPinned Boolean
|
||||
isArchived Boolean
|
||||
type String
|
||||
checkItems String?
|
||||
labels String?
|
||||
images String?
|
||||
links String?
|
||||
isMarkdown Boolean
|
||||
size String
|
||||
notebookId String?
|
||||
createdAt DateTime @default(now())
|
||||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
noteId String
|
||||
userId String
|
||||
version Int
|
||||
reason String?
|
||||
title String?
|
||||
content String
|
||||
color String
|
||||
isPinned Boolean
|
||||
isArchived Boolean
|
||||
type String
|
||||
checkItems String?
|
||||
labels String?
|
||||
images String?
|
||||
links String?
|
||||
isMarkdown Boolean
|
||||
size String
|
||||
notebookId String?
|
||||
createdAt DateTime @default(now())
|
||||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([noteId, version])
|
||||
@@index([noteId, createdAt(sort: Desc)])
|
||||
@@ -284,10 +294,10 @@ model UserAISettings {
|
||||
desktopNotifications Boolean @default(false)
|
||||
anonymousAnalytics Boolean @default(false)
|
||||
autoLabeling Boolean @default(true)
|
||||
fontFamily String @default("inter")
|
||||
languageDetection Boolean @default(true)
|
||||
noteHistory Boolean @default(false)
|
||||
noteHistoryMode String @default("manual")
|
||||
languageDetection Boolean @default(true)
|
||||
fontFamily String @default("inter")
|
||||
autoSave Boolean @default(true)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@ -300,9 +310,8 @@ model UserAISettings {
|
||||
model NoteEmbedding {
|
||||
id String @id @default(cuid())
|
||||
noteId String @unique
|
||||
embedding Unsupported("vector(1536)")
|
||||
embedding String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([noteId])
|
||||
@@ -321,9 +330,6 @@ model Agent {
|
||||
isEnabled Boolean @default(true)
|
||||
targetNotebookId String?
|
||||
sourceNotebookId String?
|
||||
sourceNoteIds String?
|
||||
slideTheme String?
|
||||
slideStyle String?
|
||||
tools String? @default("[]")
|
||||
maxSteps Int @default(10)
|
||||
notifyEmail Boolean @default(false)
|
||||
@@ -334,6 +340,9 @@ model Agent {
|
||||
scheduledTime String? @default("08:00")
|
||||
scheduledDay Int?
|
||||
timezone String?
|
||||
sourceNoteIds String?
|
||||
slideStyle String?
|
||||
slideTheme String?
|
||||
notebook Notebook? @relation(fields: [targetNotebookId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
actions AgentAction[]
|
||||
@@ -426,17 +435,198 @@ model WorkflowRun {
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String // "agent_success", "agent_failure", "share", "reminder", "system"
|
||||
title String
|
||||
message String?
|
||||
read Boolean @default(false)
|
||||
actionUrl String? // e.g. "/agents" or "/notes/xxx"
|
||||
relatedId String? // e.g. agentId or noteId
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
title String
|
||||
message String?
|
||||
read Boolean @default(false)
|
||||
actionUrl String?
|
||||
relatedId String?
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId, read])
|
||||
@@index([userId, createdAt])
|
||||
}
|
||||
|
||||
model BrainstormSession {
|
||||
id String @id @default(cuid())
|
||||
seedIdea String
|
||||
sourceNoteId String?
|
||||
contextNoteIds String?
|
||||
exportedNoteId String?
|
||||
userId String
|
||||
inviteToken String? @unique
|
||||
inviteExpiry DateTime?
|
||||
liveblocksRoomId String?
|
||||
isPublic Boolean @default(false)
|
||||
guestCanEdit Boolean @default(false)
|
||||
status String @default("active")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ideas BrainstormIdea[]
|
||||
participants BrainstormParticipant[]
|
||||
activities BrainstormActivity[]
|
||||
shares BrainstormShare[]
|
||||
snapshots BrainstormSnapshot[]
|
||||
sourceNote Note? @relation("SourceBrainstorm", fields: [sourceNoteId], references: [id])
|
||||
exportedNote Note? @relation("ExportedBrainstorm", fields: [exportedNoteId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@index([userId, createdAt])
|
||||
@@index([inviteToken])
|
||||
@@index([isPublic])
|
||||
}
|
||||
|
||||
model BrainstormIdea {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
waveNumber Int
|
||||
title String
|
||||
description String
|
||||
connectionToSeed String?
|
||||
noveltyScore Int?
|
||||
parentIdeaId String?
|
||||
convertedToNoteId String?
|
||||
relatedNoteIds String?
|
||||
status String @default("active")
|
||||
positionX Float?
|
||||
positionY Float?
|
||||
createdAt DateTime @default(now())
|
||||
createdBy String?
|
||||
createdByType String? @default("ai")
|
||||
convertedNote Note? @relation("ConvertedBrainstormIdea", fields: [convertedToNoteId], references: [id])
|
||||
parentIdea BrainstormIdea? @relation("IdeaTree", fields: [parentIdeaId], references: [id])
|
||||
children BrainstormIdea[] @relation("IdeaTree")
|
||||
session BrainstormSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
noteRefs BrainstormNoteRef[]
|
||||
|
||||
@@index([sessionId])
|
||||
@@index([waveNumber])
|
||||
@@index([status])
|
||||
@@index([parentIdeaId])
|
||||
@@index([sessionId, status])
|
||||
@@index([sessionId, waveNumber, createdAt])
|
||||
}
|
||||
|
||||
model BrainstormNoteRef {
|
||||
id String @id @default(cuid())
|
||||
ideaId String
|
||||
noteId String?
|
||||
relation String
|
||||
explanation String
|
||||
verdict String @default("unresolved")
|
||||
createdAt DateTime @default(now())
|
||||
visibility String @default("participants")
|
||||
idea BrainstormIdea @relation(fields: [ideaId], references: [id], onDelete: Cascade)
|
||||
note Note? @relation(fields: [noteId], references: [id])
|
||||
|
||||
@@index([ideaId])
|
||||
@@index([noteId])
|
||||
@@index([noteId, relation])
|
||||
@@index([visibility])
|
||||
}
|
||||
|
||||
model BrainstormParticipant {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
userId String
|
||||
role String @default("viewer")
|
||||
joinedAt DateTime @default(now())
|
||||
lastSeenAt DateTime @default(now())
|
||||
session BrainstormSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([sessionId, userId])
|
||||
@@index([sessionId])
|
||||
@@index([userId])
|
||||
@@index([sessionId, userId, role])
|
||||
}
|
||||
|
||||
model BrainstormActivity {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
userId String?
|
||||
action String
|
||||
details String?
|
||||
createdAt DateTime @default(now())
|
||||
session BrainstormSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([sessionId, createdAt], map: "BrainstormActivity_sessionId_createdAt_asc_idx")
|
||||
@@index([sessionId, createdAt(sort: Desc)], map: "BrainstormActivity_sessionId_createdAt_desc_idx")
|
||||
@@index([sessionId, createdAt])
|
||||
}
|
||||
|
||||
model BrainstormShare {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
userId String
|
||||
sharedBy String
|
||||
status String @default("pending")
|
||||
permission String @default("editor")
|
||||
notifiedAt DateTime?
|
||||
respondedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
session BrainstormSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
sharer User @relation("SentBrainstormShares", fields: [sharedBy], references: [id], onDelete: Cascade)
|
||||
user User @relation("ReceivedBrainstormShares", fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([sessionId, userId])
|
||||
@@index([userId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model BrainstormSnapshot {
|
||||
id String @id @default(cuid())
|
||||
sessionId String
|
||||
activityId String?
|
||||
step Int
|
||||
label String?
|
||||
ideaGraph String
|
||||
createdAt DateTime @default(now())
|
||||
session BrainstormSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([sessionId, step])
|
||||
@@index([sessionId, createdAt])
|
||||
@@index([activityId])
|
||||
}
|
||||
|
||||
model NoteAttachment {
|
||||
id String @id @default(cuid())
|
||||
noteId String
|
||||
fileName String
|
||||
fileType String
|
||||
fileSize Int
|
||||
filePath String
|
||||
mimeType String
|
||||
status String @default("pending")
|
||||
pageCount Int?
|
||||
error String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
||||
chunks DocumentChunk[]
|
||||
|
||||
@@index([noteId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model DocumentChunk {
|
||||
id String @id @default(cuid())
|
||||
attachmentId String
|
||||
content String
|
||||
chunkIndex Int
|
||||
pageNumber Int?
|
||||
startChar Int?
|
||||
endChar Int?
|
||||
metadata String?
|
||||
createdAt DateTime @default(now())
|
||||
attachment NoteAttachment @relation(fields: [attachmentId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([attachmentId])
|
||||
@@index([attachmentId, chunkIndex])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user