feat(dashboard): tableau de bord Second Brain configurable avec chargement progressif
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m3s
CI / Deploy production (on server) (push) Successful in 23s

Briefing granulaire, pistes rapides puis enrichissement async, layout persisté v5,
suggestions agents, intégration Gmail et navigation sidebar alignée sur /home.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Antigravity
2026-07-14 16:50:53 +00:00
parent d38a99586b
commit 30da592ba2
62 changed files with 7741 additions and 335 deletions

View File

@@ -0,0 +1,26 @@
-- CreateTable
CREATE TABLE "AgentSuggestion" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"topic" TEXT NOT NULL,
"reason" TEXT NOT NULL,
"suggestedRole" TEXT NOT NULL,
"suggestedType" TEXT NOT NULL DEFAULT 'researcher',
"suggestedFrequency" TEXT NOT NULL DEFAULT 'weekly',
"relatedNoteIds" TEXT NOT NULL,
"clusterId" INTEGER,
"status" TEXT NOT NULL DEFAULT 'pending',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "AgentSuggestion_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "AgentSuggestion_userId_status_idx" ON "AgentSuggestion"("userId", "status");
-- CreateIndex
CREATE UNIQUE INDEX "AgentSuggestion_userId_clusterId_key" ON "AgentSuggestion"("userId", "clusterId");
-- AddForeignKey
ALTER TABLE "AgentSuggestion" ADD CONSTRAINT "AgentSuggestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,21 @@
-- CreateTable
CREATE TABLE "GmailScanHistory" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"messageId" TEXT NOT NULL,
"category" TEXT NOT NULL,
"data" JSONB,
"noteId" TEXT,
"scannedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "GmailScanHistory_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "GmailScanHistory_userId_scannedAt_idx" ON "GmailScanHistory"("userId", "scannedAt");
-- CreateIndex
CREATE UNIQUE INDEX "GmailScanHistory_userId_messageId_key" ON "GmailScanHistory"("userId", "messageId");
-- AddForeignKey
ALTER TABLE "GmailScanHistory" ADD CONSTRAINT "GmailScanHistory_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "UserAISettings" ADD COLUMN IF NOT EXISTS "dashboardLayout" JSONB;

View File

@@ -30,6 +30,7 @@ model User {
onboardingStep Int @default(0)
accounts Account[]
agents Agent[]
agentSuggestions AgentSuggestion[]
aiFeedback AiFeedback[]
brainstormActivities BrainstormActivity[]
brainstormParticipant BrainstormParticipant[]
@@ -58,6 +59,7 @@ model User {
bridgeSuggestions BridgeSuggestion[]
flashcardDecks FlashcardDeck[]
errorLogs ErrorLog[]
gmailScanHistory GmailScanHistory[]
}
model Account {
@@ -370,6 +372,7 @@ model UserAISettings {
autoSave Boolean @default(true)
aiProcessingConsent Boolean @default(false)
svgComplexity String @default("simple")
dashboardLayout Json?
integrationTokens Json? // Stores third-party integration tokens (Readwise, Calendar, etc.)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@ -480,6 +483,39 @@ model AgentAction {
@@index([agentId])
}
model AgentSuggestion {
id String @id @default(cuid())
userId String
topic String
reason String
suggestedRole String @db.Text
suggestedType String @default("researcher")
suggestedFrequency String @default("weekly")
relatedNoteIds String // JSON string[]
clusterId Int?
status String @default("pending") // pending | accepted | dismissed
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, status])
@@unique([userId, clusterId])
}
model GmailScanHistory {
id String @id @default(cuid())
userId String
messageId String
category String // flight | package | subscription
data Json?
noteId String?
scannedAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, messageId])
@@index([userId, scannedAt])
}
model Conversation {
id String @id @default(cuid())
title String?