// 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" previewFeatures = ["fullTextIndex"] } datasource db { provider = "mysql" url = env("DATABASE_URL") } // ============================================= // 基础审计字段模型 // ============================================= model ApplicationUser { id String @id @default(uuid()) @db.VarChar(36) realName String @map("real_name") @db.VarChar(50) studentId String? @map("student_id") @db.VarChar(20) avatarUrl String? @map("avatar_url") @db.VarChar(500) gender Gender @default(Male) currentSchoolId String? @map("current_school_id") @db.VarChar(36) accountStatus AccountStatus @map("account_status") @default(Active) email String? @db.VarChar(100) phone String? @db.VarChar(20) bio String? @db.Text passwordHash String @map("password_hash") @db.VarChar(255) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") // Relations classMemberships ClassMember[] createdQuestions Question[] @relation("CreatedQuestions") createdExams Exam[] @relation("CreatedExams") submissions StudentSubmission[] messages Message[] @@index([studentId]) @@index([email]) @@index([phone]) @@index([currentSchoolId]) @@map("application_users") } enum Gender { Male Female } enum AccountStatus { Active Suspended Graduated } // ============================================= // 组织架构模块 // ============================================= model School { id String @id @default(uuid()) @db.VarChar(36) name String @db.VarChar(100) regionCode String @map("region_code") @db.VarChar(20) address String? @db.VarChar(200) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") grades Grade[] @@index([regionCode]) @@map("schools") } model Grade { id String @id @default(uuid()) @db.VarChar(36) schoolId String @map("school_id") @db.VarChar(36) name String @db.VarChar(50) sortOrder Int @map("sort_order") enrollmentYear Int @map("enrollment_year") createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") school School @relation(fields: [schoolId], references: [id]) classes Class[] @@index([schoolId]) @@index([enrollmentYear]) @@map("grades") } model Class { id String @id @default(uuid()) @db.VarChar(36) gradeId String @map("grade_id") @db.VarChar(36) name String @db.VarChar(50) inviteCode String @unique @map("invite_code") @db.VarChar(10) headTeacherId String? @map("head_teacher_id") @db.VarChar(36) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") grade Grade @relation(fields: [gradeId], references: [id]) members ClassMember[] assignments Assignment[] schedules Schedule[] @@index([gradeId]) @@map("classes") } model ClassMember { id String @id @default(uuid()) @db.VarChar(36) classId String @map("class_id") @db.VarChar(36) userId String @map("user_id") @db.VarChar(36) roleInClass ClassRole @map("role_in_class") @default(Student) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") class Class @relation(fields: [classId], references: [id], onDelete: Cascade) user ApplicationUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([classId, userId]) @@index([userId]) @@map("class_members") } enum ClassRole { Student Monitor Committee Teacher } // ============================================= // 教材与知识图谱模块 // ============================================= model Subject { id String @id @default(uuid()) @db.VarChar(36) name String @db.VarChar(50) code String @unique @db.VarChar(20) icon String? @db.VarChar(50) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") textbooks Textbook[] questions Question[] exams Exam[] @@map("subjects") } model Textbook { id String @id @default(uuid()) @db.VarChar(36) subjectId String @map("subject_id") @db.VarChar(36) name String @db.VarChar(100) publisher String @db.VarChar(100) versionYear String @map("version_year") @db.VarChar(20) coverUrl String? @map("cover_url") @db.VarChar(500) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") subject Subject @relation(fields: [subjectId], references: [id]) units TextbookUnit[] @@index([subjectId]) @@map("textbooks") } model TextbookUnit { id String @id @default(uuid()) @db.VarChar(36) textbookId String @map("textbook_id") @db.VarChar(36) name String @db.VarChar(100) sortOrder Int @map("sort_order") createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") textbook Textbook @relation(fields: [textbookId], references: [id], onDelete: Cascade) lessons TextbookLesson[] @@index([textbookId]) @@index([sortOrder]) @@map("textbook_units") } model TextbookLesson { id String @id @default(uuid()) @db.VarChar(36) unitId String @map("unit_id") @db.VarChar(36) name String @db.VarChar(100) sortOrder Int @map("sort_order") createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") unit TextbookUnit @relation(fields: [unitId], references: [id], onDelete: Cascade) knowledgePoints KnowledgePoint[] @@index([unitId]) @@index([sortOrder]) @@map("textbook_lessons") } model KnowledgePoint { id String @id @default(uuid()) @db.VarChar(36) lessonId String @map("lesson_id") @db.VarChar(36) parentKnowledgePointId String? @map("parent_knowledge_point_id") @db.VarChar(36) name String @db.VarChar(200) difficulty Int description String? @db.Text createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") lesson TextbookLesson @relation(fields: [lessonId], references: [id], onDelete: Cascade) parentKnowledgePoint KnowledgePoint? @relation("KnowledgePointHierarchy", fields: [parentKnowledgePointId], references: [id], onDelete: Cascade) childKnowledgePoints KnowledgePoint[] @relation("KnowledgePointHierarchy") questionAssociations QuestionKnowledge[] @@index([lessonId]) @@index([parentKnowledgePointId]) @@index([difficulty]) @@map("knowledge_points") } // ============================================= // 题库资源模块 // ============================================= model Question { id String @id @default(uuid()) @db.VarChar(36) subjectId String @map("subject_id") @db.VarChar(36) content String @db.Text optionsConfig Json? @map("options_config") questionType QuestionType @map("question_type") answer String @db.Text explanation String? @db.Text difficulty Int @default(3) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") subject Subject @relation(fields: [subjectId], references: [id]) creator ApplicationUser @relation("CreatedQuestions", fields: [createdBy], references: [id]) knowledgePoints QuestionKnowledge[] examNodes ExamNode[] @@index([subjectId]) @@index([questionType]) @@index([difficulty]) @@fulltext([content]) @@map("questions") } model QuestionKnowledge { id String @id @default(uuid()) @db.VarChar(36) questionId String @map("question_id") @db.VarChar(36) knowledgePointId String @map("knowledge_point_id") @db.VarChar(36) weight Int @default(100) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") question Question @relation(fields: [questionId], references: [id], onDelete: Cascade) knowledgePoint KnowledgePoint @relation(fields: [knowledgePointId], references: [id], onDelete: Cascade) @@unique([questionId, knowledgePointId]) @@index([knowledgePointId]) @@map("question_knowledge") } enum QuestionType { SingleChoice MultipleChoice TrueFalse FillBlank Subjective } // ============================================= // 试卷工程模块 // ============================================= model Exam { id String @id @default(uuid()) @db.VarChar(36) subjectId String @map("subject_id") @db.VarChar(36) title String @db.VarChar(200) examType String @default("Uncategorized") @map("exam_type") @db.VarChar(50) // e.g. Midterm, Final, Unit, Weekly totalScore Decimal @map("total_score") @default(0) @db.Decimal(5, 1) suggestedDuration Int @map("suggested_duration") status ExamStatus @default(Draft) description String? @db.Text createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") subject Subject @relation(fields: [subjectId], references: [id]) creator ApplicationUser @relation("CreatedExams", fields: [createdBy], references: [id]) nodes ExamNode[] assignments Assignment[] @@index([subjectId]) @@index([status]) @@index([createdBy]) @@map("exams") } model ExamNode { id String @id @default(uuid()) @db.VarChar(36) examId String @map("exam_id") @db.VarChar(36) parentNodeId String? @map("parent_node_id") @db.VarChar(36) nodeType NodeType @map("node_type") questionId String? @map("question_id") @db.VarChar(36) title String? @db.VarChar(200) description String? @db.Text score Decimal @db.Decimal(5, 1) sortOrder Int @map("sort_order") createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") exam Exam @relation(fields: [examId], references: [id], onDelete: Cascade) parentNode ExamNode? @relation("ExamNodeHierarchy", fields: [parentNodeId], references: [id], onDelete: Cascade) childNodes ExamNode[] @relation("ExamNodeHierarchy") question Question? @relation(fields: [questionId], references: [id]) submissionDetails SubmissionDetail[] @@index([examId]) @@index([parentNodeId]) @@index([sortOrder]) @@index([questionId]) @@map("exam_nodes") } enum ExamStatus { Draft Published } enum NodeType { Group Question } // ============================================= // 教学执行模块 // ============================================= model Assignment { id String @id @default(uuid()) @db.VarChar(36) examId String @map("exam_id") @db.VarChar(36) classId String @map("class_id") @db.VarChar(36) title String @db.VarChar(200) startTime DateTime @map("start_time") endTime DateTime @map("end_time") allowLateSubmission Boolean @map("allow_late_submission") @default(false) autoScoreEnabled Boolean @map("auto_score_enabled") @default(true) status AssignmentStatus @default(Active) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") exam Exam @relation(fields: [examId], references: [id]) class Class @relation(fields: [classId], references: [id]) submissions StudentSubmission[] @@index([examId]) @@index([classId]) @@index([startTime]) @@index([endTime]) @@map("assignments") } model StudentSubmission { id String @id @default(uuid()) @db.VarChar(36) assignmentId String @map("assignment_id") @db.VarChar(36) studentId String @map("student_id") @db.VarChar(36) submissionStatus SubmissionStatus @map("submission_status") @default(Pending) startedAt DateTime? @map("started_at") submitTime DateTime? @map("submit_time") timeSpentSeconds Int? @map("time_spent_seconds") totalScore Decimal? @map("total_score") @db.Decimal(5, 1) createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade) student ApplicationUser @relation(fields: [studentId], references: [id], onDelete: Cascade) details SubmissionDetail[] @@unique([assignmentId, studentId]) @@index([studentId]) @@index([submitTime]) @@index([submissionStatus]) @@map("student_submissions") } model SubmissionDetail { id String @id @default(uuid()) @db.VarChar(36) submissionId String @map("submission_id") @db.VarChar(36) examNodeId String @map("exam_node_id") @db.VarChar(36) studentAnswer String? @map("student_answer") @db.Text gradingData Json? @map("grading_data") score Decimal? @db.Decimal(5, 1) judgement JudgementResult? teacherComment String? @map("teacher_comment") @db.Text createdAt DateTime @default(now()) @map("created_at") createdBy String @map("created_by") @db.VarChar(36) updatedAt DateTime @updatedAt @map("updated_at") updatedBy String @map("updated_by") @db.VarChar(36) isDeleted Boolean @default(false) @map("is_deleted") submission StudentSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade) examNode ExamNode @relation(fields: [examNodeId], references: [id]) @@unique([submissionId, examNodeId]) @@index([examNodeId]) @@index([judgement]) @@map("submission_details") } enum SubmissionStatus { Pending Submitted Grading Graded } enum AssignmentStatus { Active Archived } enum JudgementResult { Correct Incorrect Partial } // ============================================= // 辅助功能模块 // ============================================= model Message { id String @id @default(uuid()) @db.VarChar(36) userId String @map("user_id") @db.VarChar(36) title String @db.VarChar(200) content String @db.Text type String @db.VarChar(20) // Announcement, Notification, Alert senderName String @map("sender_name") @db.VarChar(50) isRead Boolean @default(false) @map("is_read") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user ApplicationUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@map("messages") } model Schedule { id String @id @default(uuid()) @db.VarChar(36) classId String @map("class_id") @db.VarChar(36) subject String @db.VarChar(50) room String? @db.VarChar(50) dayOfWeek Int @map("day_of_week") // 1-7 period Int // 1-8 startTime String @map("start_time") @db.VarChar(10) // HH:mm endTime String @map("end_time") @db.VarChar(10) // HH:mm createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") class Class @relation(fields: [classId], references: [id], onDelete: Cascade) @@index([classId]) @@map("schedules") }