// 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 = "../node_modules/.prisma/client" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id Int @id @default(autoincrement()) email String @unique username String @unique password String role String @default("Student") // Password Reset passwordResetToken String? passwordResetExpires DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt receivedGrades Grade[] @relation("ReceivedGrades") // Noten, die Schüler erhalten haben assignedGrades Grade[] @relation("AssignedGrades") // Noten, die Lehrer vergeben haben chatMessages ChatMessage[] chatGroups ChatGroupMember[] studentFeedbacks Feedback[] @relation("StudentFeedbacks") teacherFeedbacks Feedback[] @relation("TeacherFeedbacks") taughtTimetableEntries TimetableEntry[] @relation("TeacherTimetableEntries") createdChatGroups ChatGroup[] @relation("ChatGroupCreator") uploadedFiles File[] } // Neue Tabelle: File (Dateien) model File { id Int @id @default(autoincrement()) filename String path String mimetype String size Int uploadedById Int uploadedBy User @relation(fields: [uploadedById], references: [id], onDelete: Cascade) timetableEntryId Int? timetableEntry TimetableEntry? @relation(fields: [timetableEntryId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @@index([uploadedById]) @@index([timetableEntryId]) } // Neue Tabelle: Subject (Fächer) model Subject { id Int @id @default(autoincrement()) name String @unique // z.B. "Mathematik", "Deutsch", "Englisch" abbreviation String? // z.B. "Mathe", "DE", "EN" color String? // Farbe für UI (z.B. "#FF5733") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt timetableEntries TimetableEntry[] @@index([name]) } // Neue Tabelle: Room (Räume) model Room { id Int @id @default(autoincrement()) number String @unique // z.B. "A101", "B203" building String? // z.B. "Hauptgebäude", "Neubau" capacity Int? // Anzahl Sitzplätze equipment String? // z.B. "Beamer, Whiteboard" createdAt DateTime @default(now()) updatedAt DateTime @updatedAt timetableEntries TimetableEntry[] @@index([number]) } model TimetableEntry { id Int @id @default(autoincrement()) dayOfWeek Int // 1 = Montag, 2 = Dienstag, ..., 5 = Freitag startTime String // Format: "08:00" endTime String // Format: "09:30" // Normalisierte Relationen subjectId Int subject Subject @relation(fields: [subjectId], references: [id], onDelete: Restrict) teacherId Int? teacher User? @relation("TeacherTimetableEntries", fields: [teacherId], references: [id], onDelete: SetNull) roomId Int? room Room? @relation(fields: [roomId], references: [id], onDelete: SetNull) // Wochenbasierte Planung weekNumber Int? // Kalenderwoche (1-53), null = alle Wochen year Int? // Jahr (z.B. 2025), null = alle Jahre isRecurring Boolean @default(true) // true = wiederholt sich jede Woche, false = nur für spezifische Woche allowStudentUploads Boolean @default(false) files File[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt feedbacks Feedback[] grades Grade[] @@index([dayOfWeek]) @@index([weekNumber, year]) @@index([subjectId]) @@index([teacherId]) @@index([roomId]) } model Feedback { id Int @id @default(autoincrement()) // Foreign Key Relations zu User-Tabelle studentId Int student User @relation("StudentFeedbacks", fields: [studentId], references: [id], onDelete: Cascade) teacherId Int teacher User @relation("TeacherFeedbacks", fields: [teacherId], references: [id], onDelete: Cascade) // Foreign Key Relation zu TimetableEntry lessonId Int timetableEntry TimetableEntry @relation(fields: [lessonId], references: [id], onDelete: Cascade) lessonDate DateTime overallRating Int // Prisma Json-Typ für Kategorien categories Json? whatWasGood String? whatCanImprove String? additionalComments String? isAnonymous Boolean @default(false) allowTeacherResponse Boolean @default(true) teacherResponse String? teacherRespondedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Unique Constraint: Ein Schüler kann nur einmal pro Stunde Feedback geben @@unique([studentId, lessonId]) @@index([studentId]) @@index([teacherId]) @@index([lessonId]) } model Grade { id Int @id @default(autoincrement()) // Schüler-Information (erhält die Note) studentId Int student User @relation("ReceivedGrades", fields: [studentId], references: [id], onDelete: Cascade) // Stundenplan-Bezug timetableEntryId Int timetableEntry TimetableEntry @relation(fields: [timetableEntryId], references: [id], onDelete: Cascade) // Wochenbezug (Note gilt für eine spezifische Woche) weekNumber Int // Kalenderwoche (1-53) year Int // Jahr (z.B. 2025) // Noten-Details grade Float // z.B. 1.0, 2.5, 3.0 (deutsches Notensystem) gradeType String // z.B. "Klausur", "Mitarbeit", "Hausaufgabe", "Mündlich" weight Float? @default(1.0) // Gewichtung der Note (z.B. Klausur = 2.0, Mitarbeit = 1.0) // Lehrer-Information (vergibt die Note) teacherId Int teacher User @relation("AssignedGrades", fields: [teacherId], references: [id], onDelete: Restrict) // Optional: Detailbeschreibung title String? // z.B. "Mathearbeit Kapitel 3" description String? // Zusätzliche Informationen maxPoints Float? // Maximale Punktzahl achievedPoints Float? // Erreichte Punktzahl // Datum date DateTime // Datum der Leistung createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([studentId, timetableEntryId, weekNumber, year, gradeType]) @@index([studentId]) @@index([timetableEntryId]) @@index([teacherId]) @@index([weekNumber, year]) } model ChatGroup { id Int @id @default(autoincrement()) name String description String? createdById Int // Lehrer, der die Gruppe erstellt hat createdBy User @relation("ChatGroupCreator", fields: [createdById], references: [id], onDelete: Restrict) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt members ChatGroupMember[] messages ChatMessage[] @@index([createdById]) } model ChatGroupMember { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id], onDelete: Cascade) groupId Int group ChatGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) joinedAt DateTime @default(now()) @@unique([userId, groupId]) @@index([userId]) @@index([groupId]) } model ChatMessage { id Int @id @default(autoincrement()) content String userId Int user User @relation(fields: [userId], references: [id], onDelete: Cascade) groupId Int group ChatGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @@index([groupId]) @@index([userId]) @@index([createdAt]) } model Student { studentId Int @id @default(autoincrement()) @map("student_id") studentFirstName String @map("student_first_name") studentLastName String @map("student_last_name") studentClassName String? @map("student_class_name") studentRfidCardUid String @unique @map("student_rfid_card_uid") studentCardIsActive Boolean @default(true) @map("student_card_is_active") attendanceLogs AttendanceLog[] @@map("students") } model AttendanceLog { attendanceLogId Int @id @default(autoincrement()) @map("attendance_log_id") studentId Int @map("student_id") student Student @relation(fields: [studentId], references: [studentId], onDelete: Cascade) attendanceScannedAt DateTime @map("attendance_scanned_at") attendanceEventType String @map("attendance_event_type") wasManualEntry Boolean @default(false) @map("was_manual_entry") manualEntryReason String? @map("manual_entry_reason") @@index([studentId, attendanceScannedAt]) @@map("attendance_logs") }