Co-authored-by: cetinmustafa83 <30570791+cetinmustafa83@users.noreply.github.com>
179 lines
7.0 KiB
TypeScript
179 lines
7.0 KiB
TypeScript
/**
|
|
* Generate DATA_MODEL.md from Prisma schema and database config
|
|
* This document lists all data entities, their purposes, legal basis, and retention categories
|
|
*/
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
interface DataEntity {
|
|
name: string;
|
|
dataCategories: string[];
|
|
legalBasis: string;
|
|
purpose: string;
|
|
retentionCategory: string;
|
|
notes?: string;
|
|
}
|
|
|
|
// Core data model definition
|
|
const dataModel: DataEntity[] = [
|
|
{
|
|
name: "User",
|
|
dataCategories: ["firstName", "lastName", "email", "role", "createdAt"],
|
|
legalBasis: "GDPR Art. 6(1)(c) - Legal obligation (Schulgesetz)",
|
|
purpose: "User account management and authentication",
|
|
retentionCategory: "TEACHER_AUDIT_LOG",
|
|
notes: "Retained per employment contract or student enrollment period",
|
|
},
|
|
{
|
|
name: "Student",
|
|
dataCategories: [
|
|
"firstName",
|
|
"lastName",
|
|
"dateOfBirth",
|
|
"email",
|
|
"phone",
|
|
"address",
|
|
],
|
|
legalBasis: "GDPR Art. 6(1)(c) - Legal obligation (Schulgesetz)",
|
|
purpose: "Student record management and communication",
|
|
retentionCategory: "LEARNING_PROGRESS",
|
|
},
|
|
{
|
|
name: "ClassGroup",
|
|
dataCategories: ["name", "grade", "year", "studentCount"],
|
|
legalBasis: "GDPR Art. 6(1)(c) - Legal obligation (Schulgesetz)",
|
|
purpose: "Class organization and grouping",
|
|
retentionCategory: "LEARNING_PROGRESS",
|
|
},
|
|
{
|
|
name: "Assessment",
|
|
dataCategories: ["studentId", "subjectId", "score", "feedback", "date"],
|
|
legalBasis:
|
|
"GDPR Art. 6(1)(a) - Consent + Art. 8 (children) - Parental consent",
|
|
purpose: "Record student learning progress and performance",
|
|
retentionCategory: "ASSESSMENT_RESULT",
|
|
},
|
|
{
|
|
name: "Report (Final Grade Report)",
|
|
dataCategories: ["studentId", "finalGrades", "comments", "semester"],
|
|
legalBasis:
|
|
"GDPR Art. 6(1)(c) - Legal obligation (Schulgesetz - long-term retention requirement)",
|
|
purpose: "Permanent record of student academic achievement",
|
|
retentionCategory: "FINAL_REPORT",
|
|
notes: "Typically retained for student lifetime + 30 years (per Bundesland law)",
|
|
},
|
|
{
|
|
name: "BehaviorIncident",
|
|
dataCategories: ["studentId", "incidentType", "description", "resolution"],
|
|
legalBasis:
|
|
"GDPR Art. 6(1)(a) - Consent + Art. 9(2)(h) - Health/safety necessity",
|
|
purpose: "Track disciplinary actions and behavioral support",
|
|
retentionCategory: "DISCIPLINARY_RECORD",
|
|
notes: "Retention varies by Bundesland; typically 3-10 years",
|
|
},
|
|
{
|
|
name: "ExamIncidentEvent",
|
|
dataCategories: ["studentId", "eventType", "timestamp", "notes"],
|
|
legalBasis:
|
|
"GDPR Art. 6(1)(a) - Consent + Art. 9(2)(h) - Exam integrity necessity",
|
|
purpose: "Log exam-time incidents (distress, technical issues)",
|
|
retentionCategory: "EXAM_INCIDENT",
|
|
notes: "Shorter retention (6-12 months) unless escalated to disciplinary record",
|
|
},
|
|
{
|
|
name: "Message",
|
|
dataCategories: ["senderId", "recipientId", "content", "timestamp"],
|
|
legalBasis: "GDPR Art. 6(1)(a) - Consent (user opt-in for messaging)",
|
|
purpose: "Communication between teachers, parents, and students",
|
|
retentionCategory: "MESSAGE",
|
|
},
|
|
{
|
|
name: "AuditLog",
|
|
dataCategories: ["userId", "action", "entityType", "timestamp"],
|
|
legalBasis: "GDPR Art. 6(1)(c) - Legal obligation (data protection compliance)",
|
|
purpose: "Audit trail for regulatory compliance and breach investigation",
|
|
retentionCategory: "TEACHER_AUDIT_LOG",
|
|
},
|
|
{
|
|
name: "Notebook (Student Learning Notebooks)",
|
|
dataCategories: ["studentId", "content", "createdAt"],
|
|
legalBasis: "GDPR Art. 6(1)(a) - Consent (student/parent consent)",
|
|
purpose: "Student learning portfolio and reflection entries",
|
|
retentionCategory: "NOTEBOOK_PAGE",
|
|
},
|
|
{
|
|
name: "AITutorLog",
|
|
dataCategories: ["studentId", "interaction", "timestamp", "response"],
|
|
legalBasis: "GDPR Art. 6(1)(a) - Explicit consent + Art. 22 - Automated decisions",
|
|
purpose: "Track AI tutor interactions for learning analytics",
|
|
retentionCategory: "AI_TUTOR_LOG",
|
|
notes: "Subject to Art. 22 GDPR - no solely automated grading decisions",
|
|
},
|
|
];
|
|
|
|
export function generateDataModel(outputPath: string = "docs/legal"): void {
|
|
if (!fs.existsSync(outputPath)) {
|
|
fs.mkdirSync(outputPath, { recursive: true });
|
|
}
|
|
|
|
const lines: string[] = [
|
|
"# Data Model Documentation",
|
|
"",
|
|
"**Status**: Schema Reference for ExaMetra (Module L)",
|
|
"",
|
|
"This document outlines all personal data entities collected by ExaMetra, their legal basis, purpose, and retention category.",
|
|
"",
|
|
"## Core Entities",
|
|
"",
|
|
"| Entity | Data Categories | Legal Basis | Purpose | Retention Category | Notes |",
|
|
"|--------|-----------------|------------|---------|-------------------|-------|",
|
|
];
|
|
|
|
for (const entity of dataModel) {
|
|
const dataCategories = entity.dataCategories.join(", ");
|
|
const notes = entity.notes ? `${entity.notes}` : "—";
|
|
const row = `| **${entity.name}** | ${dataCategories} | ${entity.legalBasis} | ${entity.purpose} | **${entity.retentionCategory}** | ${notes} |`;
|
|
lines.push(row);
|
|
}
|
|
|
|
lines.push(
|
|
"",
|
|
"## Retention Categories",
|
|
"",
|
|
"| Category | Typical Retention | Legal Basis |",
|
|
"|----------|------------------|------------|",
|
|
"| LEARNING_PROGRESS | 1-2 years | Bundesland school law (Schulgesetz) |",
|
|
"| ASSESSMENT_RESULT | 1-2 years | Bundesland school law |",
|
|
"| FINAL_REPORT | 30+ years | Permanent record under Schulgesetz |",
|
|
"| DISCIPLINARY_RECORD | 3-10 years | Varies by Bundesland |",
|
|
"| EXAM_INCIDENT | 6-12 months | Exam integrity + school safety |",
|
|
"| MESSAGE | 1-2 years | Communication retention best practices |",
|
|
"| AI_TUTOR_LOG | 6-12 months | Pedagogical purpose + learning analytics |",
|
|
"| NOTEBOOK_PAGE | 1-2 years | Student portfolio / learning records |",
|
|
"| SIGNAGE_LOG | 3 months | Safety monitoring (emergency only) |",
|
|
"| TEACHER_AUDIT_LOG | 1-2 years | Compliance and audit trail |",
|
|
"",
|
|
"## Compliance Notes",
|
|
"",
|
|
"- **DPO Review**: Each retention period must be reviewed and approved by your school's Data Protection Officer (DPO)",
|
|
"- **Bundesland Variations**: Retention periods may vary by state (Bundesland). Consult your regional school authority.",
|
|
"- **Parental Consent**: For student data (especially minors), parental consent is required per Art. 8 GDPR",
|
|
"- **Automated Decisions**: No solely automated decisions (e.g., automatic grade lowering) without human review per Art. 22 GDPR",
|
|
"- **Data Subject Rights**: All entities are subject to GDPR rights: access, correction, erasure (where legally permitted), portability",
|
|
"",
|
|
"## Generated From",
|
|
"",
|
|
`Generated: ${new Date().toISOString()}`,
|
|
"Source: ExaMetra Prisma schema (Module L)",
|
|
];
|
|
|
|
const filePath = path.join(outputPath, "DATA_MODEL.md");
|
|
fs.writeFileSync(filePath, lines.join("\n"), "utf-8");
|
|
console.log(`[v0] Generated DATA_MODEL.md at ${filePath}`);
|
|
}
|
|
|
|
if (require.main === module) {
|
|
generateDataModel();
|
|
}
|