generator client { provider = "prisma-client-js" binaryTargets = ["native", "linux-musl-openssl-3.0.x"] } datasource db { provider = "mysql" url = env("DATABASE_URL") } model User { id BigInt @id @default(autoincrement()) email String? @db.VarChar(255) nickname String? @db.VarChar(100) avatarUrl String? @db.VarChar(500) status String @default("active") @db.VarChar(32) onboardingCompleted Boolean @default(false) lastLoginAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? authAccounts AuthAccount[] refreshTokens RefreshToken[] profile UserProfile? preferences UserPreference? consents UserConsent[] knowledgeBases KnowledgeBase[] knowledgeItems KnowledgeItem[] knowledgeItemRelations KnowledgeItemRelation[] tags Tag[] uploadedFiles UploadedFile[] documentImports DocumentImport[] learningSessions LearningSession[] learningRecords LearningRecord[] activeRecallQuestions ActiveRecallQuestion[] activeRecallAnswers ActiveRecallAnswer[] aiAnalysisJobs AiAnalysisJob[] aiAnalysisResults AiAnalysisResult[] focusItems FocusItem[] reviewCards ReviewCard[] reviewLogs ReviewLog[] reviewPlans ReviewPlan[] dailyLearningActivities DailyLearningActivity[] notifications Notification[] feedbacks Feedback[] @@index([email]) @@index([status]) } model AuthAccount { id BigInt @id @default(autoincrement()) userId BigInt provider String @db.VarChar(32) providerUserId String @db.VarChar(255) email String? @db.VarChar(255) rawProfileJson Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@unique([provider, providerUserId]) @@index([userId]) } model RefreshToken { id BigInt @id @default(autoincrement()) userId BigInt tokenHash String @db.VarChar(255) deviceId String? @db.VarChar(255) deviceName String? @db.VarChar(255) expiresAt DateTime revokedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([tokenHash]) } model UserProfile { id BigInt @id @default(autoincrement()) userId BigInt @unique learningIdentity String? @db.VarChar(100) learningDirection String? @db.VarChar(255) bio String? @db.Text currentGoal String? @db.VarChar(255) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) } model UserPreference { id BigInt @id @default(autoincrement()) userId BigInt @unique preferredMethods Json? defaultFocusMinutes Int @default(25) aiSuggestionLevel String @default("normal") @db.VarChar(32) language String @default("zh-CN") @db.VarChar(32) appearance String @default("system") @db.VarChar(32) notificationEnabled Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) } model UserConsent { id BigInt @id @default(autoincrement()) userId BigInt consentType String @db.VarChar(32) version String @db.VarChar(50) acceptedAt DateTime ipAddress String? @db.VarChar(100) userAgent String? @db.VarChar(500) createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([consentType]) } model KnowledgeBase { id BigInt @id @default(autoincrement()) userId BigInt title String @db.VarChar(255) description String? @db.Text coverKey String? @db.VarChar(100) status String @default("active") @db.VarChar(32) itemCount Int @default(0) lastStudiedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? user User @relation(fields: [userId], references: [id]) items KnowledgeItem[] focusItems FocusItem[] @@index([userId]) @@index([status]) } model KnowledgeItem { id BigInt @id @default(autoincrement()) userId BigInt knowledgeBaseId BigInt parentId BigInt? itemType String @db.VarChar(32) title String @db.VarChar(255) content String? @db.LongText summary String? @db.Text sourceType String? @db.VarChar(32) sourceRef String? @db.VarChar(500) orderIndex Int @default(0) status String @default("active") @db.VarChar(32) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? user User @relation(fields: [userId], references: [id]) knowledgeBase KnowledgeBase @relation(fields: [knowledgeBaseId], references: [id]) parent KnowledgeItem? @relation("KnowledgeItemRelations", fields: [parentId], references: [id]) children KnowledgeItem[] @relation("KnowledgeItemRelations") tags KnowledgeItemTag[] @@index([userId]) @@index([knowledgeBaseId]) @@index([parentId]) @@index([itemType]) } model KnowledgeItemRelation { id BigInt @id @default(autoincrement()) userId BigInt sourceItemId BigInt targetItemId BigInt relationType String @db.VarChar(32) confidence Decimal? @db.Decimal(5, 2) reason String? @db.Text createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([sourceItemId]) @@index([targetItemId]) } model Tag { id BigInt @id @default(autoincrement()) userId BigInt name String @db.VarChar(100) color String? @db.VarChar(32) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) items KnowledgeItemTag[] @@unique([userId, name]) } model KnowledgeItemTag { id BigInt @id @default(autoincrement()) knowledgeItemId BigInt tagId BigInt createdAt DateTime @default(now()) knowledgeItem KnowledgeItem @relation(fields: [knowledgeItemId], references: [id]) tag Tag @relation(fields: [tagId], references: [id]) @@unique([knowledgeItemId, tagId]) } model UploadedFile { id BigInt @id @default(autoincrement()) userId BigInt filename String @db.VarChar(255) mimeType String? @db.VarChar(100) storagePath String @db.VarChar(500) sizeBytes BigInt @default(0) checksum String? @db.VarChar(255) createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) @@index([userId]) } model DocumentImport { id BigInt @id @default(autoincrement()) userId BigInt knowledgeBaseId BigInt? fileId BigInt? sourceType String @db.VarChar(32) sourceName String? @db.VarChar(255) sourceUrl String? @db.VarChar(500) rawText String? @db.LongText status String @default("pending") @db.VarChar(32) progress Int @default(0) errorMessage String? @db.Text resultJson Json? startedAt DateTime? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([status]) } model LearningSession { id BigInt @id @default(autoincrement()) userId BigInt knowledgeBaseId BigInt? knowledgeItemId BigInt? mode String @db.VarChar(32) status String @default("active") @db.VarChar(32) startedAt DateTime endedAt DateTime? durationSeconds Int @default(0) focusMinutes Int? metadata Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([knowledgeItemId]) @@index([startedAt]) } model LearningRecord { id BigInt @id @default(autoincrement()) userId BigInt sessionId BigInt? recordType String @db.VarChar(32) title String @db.VarChar(255) description String? @db.Text durationSeconds Int @default(0) occurredAt DateTime metadata Json? createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([occurredAt]) } model ActiveRecallQuestion { id BigInt @id @default(autoincrement()) userId BigInt knowledgeItemId BigInt? questionText String @db.Text difficulty String? @db.VarChar(32) createdBy String @default("ai") @db.VarChar(32) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) answers ActiveRecallAnswer[] @@index([userId]) @@index([knowledgeItemId]) } model ActiveRecallAnswer { id BigInt @id @default(autoincrement()) userId BigInt questionId BigInt? sessionId BigInt? answerType String @default("text") @db.VarChar(32) answerText String? @db.LongText audioFileId BigInt? submittedAt DateTime createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) question ActiveRecallQuestion? @relation(fields: [questionId], references: [id]) @@index([userId]) @@index([questionId]) @@index([sessionId]) } model AiAnalysisJob { id BigInt @id @default(autoincrement()) userId BigInt sessionId BigInt? answerId BigInt? jobType String @db.VarChar(32) status String @default("pending") @db.VarChar(32) progress Int @default(0) errorMessage String? @db.Text queuedAt DateTime? startedAt DateTime? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) results AiAnalysisResult[] @@index([userId]) @@index([status]) @@index([sessionId]) } model AiAnalysisResult { id BigInt @id @default(autoincrement()) userId BigInt jobId BigInt sessionId BigInt? answerId BigInt? summary String? @db.Text masteryScore Int? strengths Json? weaknesses Json? suggestions Json? nextActions Json? rawResult Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) job AiAnalysisJob @relation(fields: [jobId], references: [id]) @@index([userId]) @@index([jobId]) @@index([sessionId]) } model FocusItem { id BigInt @id @default(autoincrement()) userId BigInt knowledgeBaseId BigInt? knowledgeItemId BigInt? analysisResultId BigInt? title String @db.VarChar(255) reason String? @db.Text suggestion String? @db.Text priority String @default("normal") @db.VarChar(32) status String @default("open") @db.VarChar(32) masteryScore Int? dueAt DateTime? completedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? user User @relation(fields: [userId], references: [id]) knowledgeBase KnowledgeBase? @relation(fields: [knowledgeBaseId], references: [id]) @@index([userId]) @@index([status]) @@index([dueAt]) } model ReviewCard { id BigInt @id @default(autoincrement()) userId BigInt knowledgeItemId BigInt? focusItemId BigInt? frontText String @db.Text backText String? @db.Text difficulty String? @db.VarChar(32) status String @default("active") @db.VarChar(32) nextReviewAt DateTime? intervalDays Int @default(1) easeFactor Decimal @default(2.50) @db.Decimal(4, 2) repetitionCount Int @default(0) lapseCount Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? user User @relation(fields: [userId], references: [id]) logs ReviewLog[] @@index([userId]) @@index([nextReviewAt]) @@index([focusItemId]) } model ReviewLog { id BigInt @id @default(autoincrement()) userId BigInt reviewCardId BigInt sessionId BigInt? rating String @db.VarChar(32) responseText String? @db.Text reviewedAt DateTime nextReviewAt DateTime? createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) reviewCard ReviewCard @relation(fields: [reviewCardId], references: [id]) @@index([userId]) @@index([reviewCardId]) @@index([reviewedAt]) } model ReviewPlan { id BigInt @id @default(autoincrement()) userId BigInt title String @db.VarChar(255) status String @default("active") @db.VarChar(32) scheduledAt DateTime? completedAt DateTime? cardCount Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([scheduledAt]) } model DailyLearningActivity { id BigInt @id @default(autoincrement()) userId BigInt activityDate DateTime @db.Date durationSeconds Int @default(0) sessionsCount Int @default(0) activeRecallCount Int @default(0) reviewCount Int @default(0) aiAnalysisCount Int @default(0) completedLoopCount Int @default(0) activityLevel Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@unique([userId, activityDate]) @@index([userId]) } model Notification { id BigInt @id @default(autoincrement()) userId BigInt type String @db.VarChar(32) title String @db.VarChar(255) content String? @db.Text data Json? readAt DateTime? createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) @@index([userId]) @@index([readAt]) @@index([type]) } model Feedback { id BigInt @id @default(autoincrement()) userId BigInt? email String? @db.VarChar(255) category String @db.VarChar(64) content String @db.Text deviceInfo Json? status String @default("open") @db.VarChar(32) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User? @relation(fields: [userId], references: [id]) @@index([userId]) @@index([status]) } model AppChangelog { id BigInt @id @default(autoincrement()) version String @db.VarChar(50) title String @db.VarChar(255) content String @db.Text platform String @default("ios") @db.VarChar(32) publishedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }