first commit
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"username" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL DEFAULT 'Student',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Subject" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"abbreviation" TEXT,
|
||||
"color" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Subject_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Room" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"building" TEXT,
|
||||
"capacity" INTEGER,
|
||||
"equipment" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Room_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TimetableEntry" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"dayOfWeek" INTEGER NOT NULL,
|
||||
"startTime" TEXT NOT NULL,
|
||||
"endTime" TEXT NOT NULL,
|
||||
"subjectId" INTEGER NOT NULL,
|
||||
"teacherId" INTEGER,
|
||||
"roomId" INTEGER,
|
||||
"weekNumber" INTEGER,
|
||||
"year" INTEGER,
|
||||
"isRecurring" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "TimetableEntry_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Feedback" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"studentId" INTEGER NOT NULL,
|
||||
"teacherId" INTEGER NOT NULL,
|
||||
"lessonId" INTEGER NOT NULL,
|
||||
"lessonDate" TIMESTAMP(3) NOT NULL,
|
||||
"overallRating" INTEGER NOT NULL,
|
||||
"categories" JSONB,
|
||||
"whatWasGood" TEXT,
|
||||
"whatCanImprove" TEXT,
|
||||
"additionalComments" TEXT,
|
||||
"isAnonymous" BOOLEAN NOT NULL DEFAULT false,
|
||||
"allowTeacherResponse" BOOLEAN NOT NULL DEFAULT true,
|
||||
"teacherResponse" TEXT,
|
||||
"teacherRespondedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Feedback_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Grade" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"studentId" INTEGER NOT NULL,
|
||||
"timetableEntryId" INTEGER NOT NULL,
|
||||
"weekNumber" INTEGER NOT NULL,
|
||||
"year" INTEGER NOT NULL,
|
||||
"grade" DOUBLE PRECISION NOT NULL,
|
||||
"gradeType" TEXT NOT NULL,
|
||||
"weight" DOUBLE PRECISION DEFAULT 1.0,
|
||||
"teacherId" INTEGER NOT NULL,
|
||||
"title" TEXT,
|
||||
"description" TEXT,
|
||||
"maxPoints" DOUBLE PRECISION,
|
||||
"achievedPoints" DOUBLE PRECISION,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Grade_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ChatGroup" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"createdById" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ChatGroup_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ChatGroupMember" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
"groupId" INTEGER NOT NULL,
|
||||
"joinedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ChatGroupMember_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ChatMessage" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
"groupId" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ChatMessage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Subject_name_key" ON "Subject"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Subject_name_idx" ON "Subject"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Room_number_key" ON "Room"("number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Room_number_idx" ON "Room"("number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimetableEntry_dayOfWeek_idx" ON "TimetableEntry"("dayOfWeek");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimetableEntry_weekNumber_year_idx" ON "TimetableEntry"("weekNumber", "year");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimetableEntry_subjectId_idx" ON "TimetableEntry"("subjectId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimetableEntry_teacherId_idx" ON "TimetableEntry"("teacherId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TimetableEntry_roomId_idx" ON "TimetableEntry"("roomId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Feedback_studentId_idx" ON "Feedback"("studentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Feedback_teacherId_idx" ON "Feedback"("teacherId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Feedback_lessonId_idx" ON "Feedback"("lessonId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Feedback_studentId_lessonId_key" ON "Feedback"("studentId", "lessonId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Grade_studentId_idx" ON "Grade"("studentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Grade_timetableEntryId_idx" ON "Grade"("timetableEntryId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Grade_teacherId_idx" ON "Grade"("teacherId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Grade_weekNumber_year_idx" ON "Grade"("weekNumber", "year");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Grade_studentId_timetableEntryId_weekNumber_year_gradeType_key" ON "Grade"("studentId", "timetableEntryId", "weekNumber", "year", "gradeType");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatGroup_createdById_idx" ON "ChatGroup"("createdById");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatGroupMember_userId_idx" ON "ChatGroupMember"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatGroupMember_groupId_idx" ON "ChatGroupMember"("groupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ChatGroupMember_userId_groupId_key" ON "ChatGroupMember"("userId", "groupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatMessage_groupId_idx" ON "ChatMessage"("groupId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatMessage_userId_idx" ON "ChatMessage"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ChatMessage_createdAt_idx" ON "ChatMessage"("createdAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TimetableEntry" ADD CONSTRAINT "TimetableEntry_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "Subject"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TimetableEntry" ADD CONSTRAINT "TimetableEntry_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TimetableEntry" ADD CONSTRAINT "TimetableEntry_roomId_fkey" FOREIGN KEY ("roomId") REFERENCES "Room"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Feedback" ADD CONSTRAINT "Feedback_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Feedback" ADD CONSTRAINT "Feedback_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Feedback" ADD CONSTRAINT "Feedback_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "TimetableEntry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Grade" ADD CONSTRAINT "Grade_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Grade" ADD CONSTRAINT "Grade_timetableEntryId_fkey" FOREIGN KEY ("timetableEntryId") REFERENCES "TimetableEntry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Grade" ADD CONSTRAINT "Grade_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatGroup" ADD CONSTRAINT "ChatGroup_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatGroupMember" ADD CONSTRAINT "ChatGroupMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatGroupMember" ADD CONSTRAINT "ChatGroupMember_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "ChatGroup"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ChatMessage" ADD CONSTRAINT "ChatMessage_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "ChatGroup"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "passwordResetExpires" TIMESTAMP(3),
|
||||
ADD COLUMN "passwordResetToken" TEXT;
|
||||
@@ -0,0 +1,28 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "TimetableEntry" ADD COLUMN "allowStudentUploads" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "File" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"filename" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"mimetype" TEXT NOT NULL,
|
||||
"size" INTEGER NOT NULL,
|
||||
"uploadedById" INTEGER NOT NULL,
|
||||
"timetableEntryId" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "File_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "File_uploadedById_idx" ON "File"("uploadedById");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "File_timetableEntryId_idx" ON "File"("timetableEntryId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "File" ADD CONSTRAINT "File_uploadedById_fkey" FOREIGN KEY ("uploadedById") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "File" ADD CONSTRAINT "File_timetableEntryId_fkey" FOREIGN KEY ("timetableEntryId") REFERENCES "TimetableEntry"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,32 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "students" (
|
||||
"student_id" SERIAL NOT NULL,
|
||||
"student_first_name" TEXT NOT NULL,
|
||||
"student_last_name" TEXT NOT NULL,
|
||||
"student_class_name" TEXT,
|
||||
"student_rfid_card_uid" TEXT NOT NULL,
|
||||
"student_card_is_active" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "students_pkey" PRIMARY KEY ("student_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "attendance_logs" (
|
||||
"attendance_log_id" SERIAL NOT NULL,
|
||||
"student_id" INTEGER NOT NULL,
|
||||
"attendance_scanned_at" TIMESTAMP(3) NOT NULL,
|
||||
"attendance_event_type" TEXT NOT NULL,
|
||||
"was_manual_entry" BOOLEAN NOT NULL DEFAULT false,
|
||||
"manual_entry_reason" TEXT,
|
||||
|
||||
CONSTRAINT "attendance_logs_pkey" PRIMARY KEY ("attendance_log_id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "students_student_rfid_card_uid_key" ON "students"("student_rfid_card_uid");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "attendance_logs_student_id_attendance_scanned_at_idx" ON "attendance_logs"("student_id", "attendance_scanned_at");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "attendance_logs" ADD CONSTRAINT "attendance_logs_student_id_fkey" FOREIGN KEY ("student_id") REFERENCES "students"("student_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
279
Smartes-Klassenzimmer-Backend/prisma/schema.prisma
Normal file
279
Smartes-Klassenzimmer-Backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,279 @@
|
||||
// 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")
|
||||
}
|
||||
236
Smartes-Klassenzimmer-Backend/prisma/seed.ts
Normal file
236
Smartes-Klassenzimmer-Backend/prisma/seed.ts
Normal file
@@ -0,0 +1,236 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Datenbank wird mit Testdaten befüllt...\n');
|
||||
|
||||
// 1. Benutzer erstellen (Lehrer und Schüler)
|
||||
console.log('📝 Erstelle Benutzer...');
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'admin@smartesklassenzimmer.de' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'admin@smartesklassenzimmer.de',
|
||||
username: 'admin',
|
||||
password: '$2b$10$8I9F3DPBvqzm.tBz7yMgfur4z1gMyaHsPyhmL4VAGJ2OvnmTTn5KW', // admin123
|
||||
role: 'Lehrer',
|
||||
},
|
||||
});
|
||||
|
||||
const teacher1 = await prisma.user.upsert({
|
||||
where: { email: 'mueller@schule.de' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'mueller@schule.de',
|
||||
username: 'Frau Müller',
|
||||
password: '$2b$10$8I9F3DPBvqzm.tBz7yMgfur4z1gMyaHsPyhmL4VAGJ2OvnmTTn5KW', // admin123
|
||||
role: 'Lehrer',
|
||||
},
|
||||
});
|
||||
|
||||
const teacher2 = await prisma.user.upsert({
|
||||
where: { email: 'schmidt@schule.de' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'schmidt@schule.de',
|
||||
username: 'Herr Schmidt',
|
||||
password: '$2b$10$8I9F3DPBvqzm.tBz7yMgfur4z1gMyaHsPyhmL4VAGJ2OvnmTTn5KW', // admin123
|
||||
role: 'Lehrer',
|
||||
},
|
||||
});
|
||||
|
||||
const student1 = await prisma.user.upsert({
|
||||
where: { email: 'max@student.de' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'max@student.de',
|
||||
username: 'Max Mustermann',
|
||||
password: '$2b$10$8I9F3DPBvqzm.tBz7yMgfur4z1gMyaHsPyhmL4VAGJ2OvnmTTn5KW', // admin123
|
||||
role: 'Student',
|
||||
},
|
||||
});
|
||||
|
||||
const student2 = await prisma.user.upsert({
|
||||
where: { email: 'anna@student.de' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'anna@student.de',
|
||||
username: 'Anna Schmidt',
|
||||
password: '$2b$10$8I9F3DPBvqzm.tBz7yMgfur4z1gMyaHsPyhmL4VAGJ2OvnmTTn5KW', // admin123
|
||||
role: 'Student',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Benutzer erstellt\n');
|
||||
|
||||
// 2. Fächer erstellen
|
||||
console.log('📚 Erstelle Fächer...');
|
||||
const mathSubject = await prisma.subject.upsert({
|
||||
where: { name: 'Mathematik' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Mathematik',
|
||||
abbreviation: 'Mathe',
|
||||
color: '#FF5733',
|
||||
},
|
||||
});
|
||||
|
||||
const germanSubject = await prisma.subject.upsert({
|
||||
where: { name: 'Deutsch' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Deutsch',
|
||||
abbreviation: 'DE',
|
||||
color: '#33FF57',
|
||||
},
|
||||
});
|
||||
|
||||
const englishSubject = await prisma.subject.upsert({
|
||||
where: { name: 'Englisch' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Englisch',
|
||||
abbreviation: 'EN',
|
||||
color: '#3357FF',
|
||||
},
|
||||
});
|
||||
|
||||
const physicsSubject = await prisma.subject.upsert({
|
||||
where: { name: 'Physik' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Physik',
|
||||
abbreviation: 'Phy',
|
||||
color: '#FF33F5',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Fächer erstellt\n');
|
||||
|
||||
// 3. Räume erstellen
|
||||
console.log('🏫 Erstelle Räume...');
|
||||
const roomA101 = await prisma.room.upsert({
|
||||
where: { number: 'A101' },
|
||||
update: {},
|
||||
create: {
|
||||
number: 'A101',
|
||||
building: 'Hauptgebäude',
|
||||
capacity: 30,
|
||||
equipment: 'Beamer, Whiteboard',
|
||||
},
|
||||
});
|
||||
|
||||
const roomB203 = await prisma.room.upsert({
|
||||
where: { number: 'B203' },
|
||||
update: {},
|
||||
create: {
|
||||
number: 'B203',
|
||||
building: 'Neubau',
|
||||
capacity: 25,
|
||||
equipment: 'Smartboard, Laptop',
|
||||
},
|
||||
});
|
||||
|
||||
const roomC105 = await prisma.room.upsert({
|
||||
where: { number: 'C105' },
|
||||
update: {},
|
||||
create: {
|
||||
number: 'C105',
|
||||
building: 'Hauptgebäude',
|
||||
capacity: 20,
|
||||
equipment: 'Beamer',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Räume erstellt\n');
|
||||
|
||||
// 4. Stundenplan-Einträge erstellen
|
||||
console.log('📅 Erstelle Stundenplan-Einträge...');
|
||||
|
||||
// Montag
|
||||
await prisma.timetableEntry.create({
|
||||
data: {
|
||||
dayOfWeek: 1,
|
||||
startTime: '08:00',
|
||||
endTime: '09:30',
|
||||
subjectId: mathSubject.id,
|
||||
teacherId: teacher1.id,
|
||||
roomId: roomA101.id,
|
||||
isRecurring: true,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.timetableEntry.create({
|
||||
data: {
|
||||
dayOfWeek: 1,
|
||||
startTime: '10:00',
|
||||
endTime: '11:30',
|
||||
subjectId: germanSubject.id,
|
||||
teacherId: teacher2.id,
|
||||
roomId: roomB203.id,
|
||||
isRecurring: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Dienstag
|
||||
await prisma.timetableEntry.create({
|
||||
data: {
|
||||
dayOfWeek: 2,
|
||||
startTime: '08:00',
|
||||
endTime: '09:30',
|
||||
subjectId: englishSubject.id,
|
||||
teacherId: teacher1.id,
|
||||
roomId: roomC105.id,
|
||||
isRecurring: true,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.timetableEntry.create({
|
||||
data: {
|
||||
dayOfWeek: 2,
|
||||
startTime: '10:00',
|
||||
endTime: '11:30',
|
||||
subjectId: physicsSubject.id,
|
||||
teacherId: teacher2.id,
|
||||
roomId: roomA101.id,
|
||||
isRecurring: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Mittwoch
|
||||
await prisma.timetableEntry.create({
|
||||
data: {
|
||||
dayOfWeek: 3,
|
||||
startTime: '08:00',
|
||||
endTime: '09:30',
|
||||
subjectId: mathSubject.id,
|
||||
teacherId: teacher1.id,
|
||||
roomId: roomA101.id,
|
||||
isRecurring: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Stundenplan-Einträge erstellt\n');
|
||||
|
||||
console.log('\n=== LOGIN-DATEN ===');
|
||||
console.log('👨🏫 Lehrer:');
|
||||
console.log(' - Benutzername: admin, Passwort: admin123');
|
||||
console.log(' - Benutzername: Frau Müller, Passwort: admin123');
|
||||
console.log(' - Benutzername: Herr Schmidt, Passwort: admin123');
|
||||
console.log('\n👨🎓 Schüler:');
|
||||
console.log(' - Benutzername: Max Mustermann, Passwort: admin123');
|
||||
console.log(' - Benutzername: Anna Schmidt, Passwort: admin123');
|
||||
console.log('==================\n');
|
||||
|
||||
console.log('🎉 Datenbank erfolgreich mit Testdaten befüllt!\n');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user