feat: Complete internationalization and code cleanup
## Translation Files - Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ missing translation keys across all 15 languages - New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels - Update nav section with workspace, quickAccess, myLibrary keys ## Component Updates - Update 15+ components to use translation keys instead of hardcoded text - Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc. - Replace 80+ hardcoded English/French strings with t() calls - Ensure consistent UI across all supported languages ## Code Quality - Remove 77+ console.log statements from codebase - Clean up API routes, components, hooks, and services - Keep only essential error handling (no debugging logs) ## UI/UX Improvements - Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500) - Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items) - Make "+" button permanently visible in notebooks section - Fix grammar and syntax errors in multiple components ## Bug Fixes - Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json - Fix syntax errors in notebook-suggestion-toast.tsx - Fix syntax errors in use-auto-tagging.ts - Fix syntax errors in paragraph-refactor.service.ts - Fix duplicate "fusion" section in nl.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Ou une version plus courte si vous préférez : feat(i18n): Add 15 languages, remove logs, update UI components - Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ translation keys: notebook, pagination, AI features - Update 15+ components to use translations (80+ strings) - Remove 77+ console.log statements from codebase - Fix JSON syntax errors in 4 translation files - Fix component syntax errors (toast, hooks, services) - Update logo to yellow post-it style - Change selection colors (#FEF3C6, #EFB162) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -164,10 +164,22 @@ exports.Prisma.VerificationTokenScalarFieldEnum = {
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.NotebookScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
icon: 'icon',
|
||||
color: 'color',
|
||||
order: 'order',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LabelScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
color: 'color',
|
||||
notebookId: 'notebookId',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
@@ -195,8 +207,15 @@ exports.Prisma.NoteScalarFieldEnum = {
|
||||
sharedWith: 'sharedWith',
|
||||
userId: 'userId',
|
||||
order: 'order',
|
||||
notebookId: 'notebookId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
updatedAt: 'updatedAt',
|
||||
autoGenerated: 'autoGenerated',
|
||||
aiProvider: 'aiProvider',
|
||||
aiConfidence: 'aiConfidence',
|
||||
language: 'language',
|
||||
languageConfidence: 'languageConfidence',
|
||||
lastAiAnalysis: 'lastAiAnalysis'
|
||||
};
|
||||
|
||||
exports.Prisma.NoteShareScalarFieldEnum = {
|
||||
@@ -217,6 +236,44 @@ exports.Prisma.SystemConfigScalarFieldEnum = {
|
||||
value: 'value'
|
||||
};
|
||||
|
||||
exports.Prisma.AiFeedbackScalarFieldEnum = {
|
||||
id: 'id',
|
||||
noteId: 'noteId',
|
||||
userId: 'userId',
|
||||
feedbackType: 'feedbackType',
|
||||
feature: 'feature',
|
||||
originalContent: 'originalContent',
|
||||
correctedContent: 'correctedContent',
|
||||
metadata: 'metadata',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.MemoryEchoInsightScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
note1Id: 'note1Id',
|
||||
note2Id: 'note2Id',
|
||||
similarityScore: 'similarityScore',
|
||||
insight: 'insight',
|
||||
insightDate: 'insightDate',
|
||||
viewed: 'viewed',
|
||||
feedback: 'feedback',
|
||||
dismissed: 'dismissed'
|
||||
};
|
||||
|
||||
exports.Prisma.UserAISettingsScalarFieldEnum = {
|
||||
userId: 'userId',
|
||||
titleSuggestions: 'titleSuggestions',
|
||||
semanticSearch: 'semanticSearch',
|
||||
paragraphRefactor: 'paragraphRefactor',
|
||||
memoryEcho: 'memoryEcho',
|
||||
memoryEchoFrequency: 'memoryEchoFrequency',
|
||||
aiProvider: 'aiProvider',
|
||||
preferredLanguage: 'preferredLanguage',
|
||||
fontSize: 'fontSize',
|
||||
demoMode: 'demoMode'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
@@ -233,10 +290,14 @@ exports.Prisma.ModelName = {
|
||||
Account: 'Account',
|
||||
Session: 'Session',
|
||||
VerificationToken: 'VerificationToken',
|
||||
Notebook: 'Notebook',
|
||||
Label: 'Label',
|
||||
Note: 'Note',
|
||||
NoteShare: 'NoteShare',
|
||||
SystemConfig: 'SystemConfig'
|
||||
SystemConfig: 'SystemConfig',
|
||||
AiFeedback: 'AiFeedback',
|
||||
MemoryEchoInsight: 'MemoryEchoInsight',
|
||||
UserAISettings: 'UserAISettings'
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
9444
keep-notes/prisma/client-generated/index.d.ts
vendored
9444
keep-notes/prisma/client-generated/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "prisma-client-0924f65183f5d4eff92dbcaaa75ea4e789cffdcbc361852cabe5beaded9c8358",
|
||||
"name": "prisma-client-093f8032ffdb503017a919cb283b2e9dc4eed6db9cd03676bdc7dbcbf826224c",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "index-browser.js",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
264
keep-notes/prisma/client-generated/schema.prisma
Normal file
264
keep-notes/prisma/client-generated/schema.prisma
Normal file
@@ -0,0 +1,264 @@
|
||||
// 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])
|
||||
}
|
||||
@@ -164,10 +164,22 @@ exports.Prisma.VerificationTokenScalarFieldEnum = {
|
||||
expires: 'expires'
|
||||
};
|
||||
|
||||
exports.Prisma.NotebookScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
icon: 'icon',
|
||||
color: 'color',
|
||||
order: 'order',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LabelScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
color: 'color',
|
||||
notebookId: 'notebookId',
|
||||
userId: 'userId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
@@ -195,8 +207,15 @@ exports.Prisma.NoteScalarFieldEnum = {
|
||||
sharedWith: 'sharedWith',
|
||||
userId: 'userId',
|
||||
order: 'order',
|
||||
notebookId: 'notebookId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
updatedAt: 'updatedAt',
|
||||
autoGenerated: 'autoGenerated',
|
||||
aiProvider: 'aiProvider',
|
||||
aiConfidence: 'aiConfidence',
|
||||
language: 'language',
|
||||
languageConfidence: 'languageConfidence',
|
||||
lastAiAnalysis: 'lastAiAnalysis'
|
||||
};
|
||||
|
||||
exports.Prisma.NoteShareScalarFieldEnum = {
|
||||
@@ -217,6 +236,44 @@ exports.Prisma.SystemConfigScalarFieldEnum = {
|
||||
value: 'value'
|
||||
};
|
||||
|
||||
exports.Prisma.AiFeedbackScalarFieldEnum = {
|
||||
id: 'id',
|
||||
noteId: 'noteId',
|
||||
userId: 'userId',
|
||||
feedbackType: 'feedbackType',
|
||||
feature: 'feature',
|
||||
originalContent: 'originalContent',
|
||||
correctedContent: 'correctedContent',
|
||||
metadata: 'metadata',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.MemoryEchoInsightScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
note1Id: 'note1Id',
|
||||
note2Id: 'note2Id',
|
||||
similarityScore: 'similarityScore',
|
||||
insight: 'insight',
|
||||
insightDate: 'insightDate',
|
||||
viewed: 'viewed',
|
||||
feedback: 'feedback',
|
||||
dismissed: 'dismissed'
|
||||
};
|
||||
|
||||
exports.Prisma.UserAISettingsScalarFieldEnum = {
|
||||
userId: 'userId',
|
||||
titleSuggestions: 'titleSuggestions',
|
||||
semanticSearch: 'semanticSearch',
|
||||
paragraphRefactor: 'paragraphRefactor',
|
||||
memoryEcho: 'memoryEcho',
|
||||
memoryEchoFrequency: 'memoryEchoFrequency',
|
||||
aiProvider: 'aiProvider',
|
||||
preferredLanguage: 'preferredLanguage',
|
||||
fontSize: 'fontSize',
|
||||
demoMode: 'demoMode'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
@@ -233,10 +290,14 @@ exports.Prisma.ModelName = {
|
||||
Account: 'Account',
|
||||
Session: 'Session',
|
||||
VerificationToken: 'VerificationToken',
|
||||
Notebook: 'Notebook',
|
||||
Label: 'Label',
|
||||
Note: 'Note',
|
||||
NoteShare: 'NoteShare',
|
||||
SystemConfig: 'SystemConfig'
|
||||
SystemConfig: 'SystemConfig',
|
||||
AiFeedback: 'AiFeedback',
|
||||
MemoryEchoInsight: 'MemoryEchoInsight',
|
||||
UserAISettings: 'UserAISettings'
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
BIN
keep-notes/prisma/dev.db.backup-20260111
Normal file
BIN
keep-notes/prisma/dev.db.backup-20260111
Normal file
Binary file not shown.
@@ -26,8 +26,15 @@ model User {
|
||||
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
|
||||
}
|
||||
@@ -71,17 +78,39 @@ model VerificationToken {
|
||||
@@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
|
||||
name String
|
||||
color String @default("gray")
|
||||
userId String? // Made optional for migration, but logic will enforce it
|
||||
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([name, userId]) // Labels are unique per user
|
||||
@@index([userId])
|
||||
@@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 {
|
||||
@@ -93,7 +122,7 @@ model Note {
|
||||
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
|
||||
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
|
||||
@@ -108,14 +137,36 @@ model 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 {
|
||||
@@ -142,4 +193,72 @@ model NoteShare {
|
||||
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])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user