feat: add new legal document and database schema for module L compliance

Co-authored-by: cetinmustafa83 <30570791+cetinmustafa83@users.noreply.github.com>
This commit is contained in:
v0andcetinmustafa83 committed 2026-07-31 13:34:58 +00:00
1 parent e6d82083d7
commit 927aae8580
24 files changed
+6565 -1

No files matched your search

Executable → Regular
+108 -1
View File
@@ -116,6 +116,12 @@ model School {
substituteTeachers SubstituteTeacher[]
teacherAbsences TeacherAbsence[]
substitutionAssignments SubstitutionAssignment[]
// Module L compliance relations
dataRetentionPolicies DataRetentionPolicy[]
dpiaRecords DpiaRecord[]
complianceConsultations ComplianceConsultation[]
complianceStatus SchoolComplianceStatus?
deletionFlags DeletionFlag[]
}
model User {
@@ -125,10 +131,11 @@ model User {
passwordHash String
firstName String
lastName String
role String @default("TEACHER") // TEACHER, SCHOOL_ADMIN, SUPER_ADMIN, STUDENT, PARENT, VICE_PRINCIPAL
role String @default("TEACHER") // TEACHER, SCHOOL_ADMIN, SUPER_ADMIN, STUDENT, PARENT, VICE_PRINCIPAL, DPO
locale String @default("de")
twoFactorSecret String?
isDemo Boolean @default(false)
isTeacher Boolean @default(false) // civil-servant status for Personalrat rights
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@ -207,6 +214,11 @@ model User {
careerAppointments CareerAppointment[]
substituteTeacher SubstituteTeacher?
teacherAbsences TeacherAbsence[]
// Module L compliance relations
retentionPoliciesReviewed DataRetentionPolicy[] @relation("DataRetentionPolicyReviewer")
dpiaRecordsApproved DpiaRecord[] @relation("DpiaRecordApprover")
complianceConsultationsAcknowledged ComplianceConsultation[] @relation("ComplianceConsultationAcknowledger")
deletionFlagsApproved DeletionFlag[] @relation("DeletionFlagApprover")
}
model SchoolYear {
@@ -651,9 +663,13 @@ model AuditLog {
userAgent String?
timestamp DateTime @default(now())
metadata String? // JSON
dataSubject String? // track which student (if applicable) for GDPR export scope
user User? @relation(fields: [userId], references: [id])
school School? @relation(fields: [schoolId], references: [id])
@@index([dataSubject])
@@index([timestamp])
}
model DataExportRequest {
@@ -3216,3 +3232,94 @@ model GradeReport {
@@index([schoolId])
@@index([generatedBy])
}
// ─── Module L: Legal & Data Protection Compliance ──────────────────
model DataRetentionPolicy {
id String @id @default(cuid())
schoolId String
dataCategory String // LEARNING_PROGRESS, ASSESSMENT_RESULT, FINAL_REPORT, DISCIPLINARY_RECORD, EXAM_INCIDENT, MESSAGE, AI_TUTOR_LOG, NOTEBOOK_PAGE, SIGNAGE_LOG, TEACHER_AUDIT_LOG
retentionPeriodMonths Int? // nullable to force DPO to fill in legally-mandated categories
legalBasisNote String? // DPO notes on state-specific retention rule
isDefault Boolean @default(false) // false = legally mandated; true = optional product data
reviewedByUserId String? // DPO approval
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
school School @relation(fields: [schoolId], references: [id])
reviewedByUser User? @relation("DataRetentionPolicyReviewer", fields: [reviewedByUserId], references: [id])
@@index([schoolId])
@@index([dataCategory])
}
model DpiaRecord {
id String @id @default(cuid())
schoolId String
moduleScope String // AI_TUTOR, EXAM_MODE, WELLNESS_CHECKS, SIGNAGE_EMERGENCY, MESSAGING, LEARNING_ANALYTICS
dataProcessingSummary String // what's processed, for how long, who sees it
completedAt DateTime
approvedByUserId String? // DPO approval
documentUrl String? // uploaded DPIA PDF
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
school School @relation(fields: [schoolId], references: [id])
approvedByUser User? @relation("DpiaRecordApprover", fields: [approvedByUserId], references: [id])
@@index([schoolId])
@@index([moduleScope])
@@unique([schoolId, moduleScope])
}
model ComplianceConsultation {
id String @id @default(cuid())
schoolId String
consultationType String // ELTERNBEIRAT, SCHULKONFERENZ, PERSONALRAT
moduleScope String? // specific module if Personalrat for monitoring-capable features
acknowledgedByUserId String
acknowledgedAt DateTime
notes String? // what was consulted/approved
createdAt DateTime @default(now())
school School @relation(fields: [schoolId], references: [id])
acknowledgedByUser User @relation("ComplianceConsultationAcknowledger", fields: [acknowledgedByUserId], references: [id])
@@index([schoolId])
@@index([consultationType])
}
model SchoolComplianceStatus {
id String @id @default(cuid())
schoolId String @unique
bundesland String? // BERLIN, BREMEN, HAMBURG, etc. (16 states)
onboardingCompleted Boolean @default(false)
dpoDpoContactEmail String?
schultragerContactEmail String?
moduleGates String? // JSON: { "AI_TUTOR": { isApprovedForUse: bool, diaCompleted: bool }, ... }
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
school School @relation(fields: [schoolId], references: [id])
}
model DeletionFlag {
id String @id @default(cuid())
schoolId String
entityType String // Student, Message, Notebook, etc.
entityId String
dataCategory String // retention category reference
flaggedAt DateTime @default(now())
approvedByUserId String?
approvedAt DateTime?
deletedAt DateTime?
reason String // "retention period expired", "erasure request", etc.
school School @relation(fields: [schoolId], references: [id])
approvedByUser User? @relation("DeletionFlagApprover", fields: [approvedByUserId], references: [id])
@@index([schoolId])
@@index([entityType])
@@index([flaggedAt])
}