Files
Nexus_Edu/backend/prisma/schema.prisma

536 lines
20 KiB
Plaintext

// 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")
}