[dyad] SchulOS markalama kabul kriterlerini doğrulama

This commit is contained in:
[dyad] committed 2026-08-02 01:55:22 +02:00
1 parent 0b0481a4d0
commit 5e66bae15b
57 files changed
+195 -191

No files matched your search

+3 -3
View File
@@ -975,7 +975,7 @@ export default function AppLayout() {
</div>
)}
<div className="group-data-[collapsible=icon]:hidden">
<h2 className="text-lg font-bold text-gray-900 dark:text-gray-100 leading-tight">{schoolBranding?.name || 'CompetenceTrack'}</h2>
<h2 className="text-lg font-bold text-gray-900 dark:text-gray-100 leading-tight">{schoolBranding?.name || 'SchulOS'}</h2>
<p className="text-[10px] text-emerald-600/70 dark:text-emerald-400/50 leading-tight">{t('app.subtitle')}</p>
</div>
</motion.div>
@@ -1409,7 +1409,7 @@ export default function AppLayout() {
<div className="flex items-center justify-between text-xs text-emerald-600/60 dark:text-emerald-400/40">
<span className="flex items-center gap-1">
<Leaf className="h-3 w-3 text-emerald-500" />
CompetenceTrack — {t('footer.copyright')}
SchulOS — {t('footer.copyright')}
</span>
<span className="flex items-center gap-2">
<span className="hidden sm:inline">{t('footer.version')} · {t('footer.oss')}</span>
@@ -1609,7 +1609,7 @@ export default function AppLayout() {
{t('polish.help')}
</DialogTitle>
<DialogDescription className="text-xs text-gray-500 dark:text-gray-400">
CompetenceTrack · {t('footer.version')}
SchulOS · {t('footer.version')}
</DialogDescription>
</DialogHeader>
<div className="space-y-2 text-sm">
+1 -1
View File
@@ -3295,7 +3295,7 @@ export default function DashboardView() {
<div className="hidden sm:flex flex-col items-end gap-1 shrink-0">
<Badge className="bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300 text-xs">
<GraduationCap className="h-3 w-3 mr-1" />
{currentUser?.schoolId ? t('nav.classes') : 'CompetenceTrack'}
{currentUser?.schoolId ? t('nav.classes') : 'SchulOS'}
</Badge>
<span className="text-[10px] text-gray-400 dark:text-gray-500">
{t('dashboard.total_students')}: {data.stats.totalStudents} · {t('dashboard.total_classes')}: {data.stats.totalClasses}
+1 -1
View File
@@ -244,7 +244,7 @@ export default function OnboardingTour({ open, onClose }: OnboardingTourProps) {
{/* Hidden title for accessibility */}
<DialogHeader className="sr-only">
<VisuallyHidden>
<DialogTitle>CompetenceTrack Onboarding Tour</DialogTitle>
<DialogTitle>SchulOS Onboarding Tour</DialogTitle>
</VisuallyHidden>
</DialogHeader>
{/* Close button */}
+1 -1
View File
@@ -1762,7 +1762,7 @@ function generatePrintHTML(
return `
<div class="report-card-page">
<div class="header">
<h1>${school?.name ?? 'CompetenceTrack'}</h1>
<h1>${school?.name ?? 'SchulOS'}</h1>
${school?.motto ? `<p class="motto">${school.motto}</p>` : ''}
<h2>Zeugnis / Report Card</h2>
<p>Schuljahr: ${report.schoolYear.label}</p>
+1 -1
View File
@@ -534,7 +534,7 @@ export default function SchoolLibraryView() {
<p><strong>${t('library.due_date')}:</strong> ${new Date(checkout.dueDate).toLocaleDateString()}</p>
<p><strong>${t('library.condition')}:</strong> ${checkout.condition}</p>
<hr/>
<p style="text-align:center; font-size: 12px;">CompetenceTrack - ${t('library.title')}</p>
<p style="text-align:center; font-size: 12px;">SchulOS - ${t('library.title')}</p>
</body></html>
`);
printWindow.document.close();
+7 -7
View File
@@ -732,7 +732,7 @@ function PrivacyTab({ currentUser }: { currentUser: { id: string; role: string;
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `competencetrack-data-export-${new Date().toISOString().split('T')[0]}.json`;
a.download = `schulos-data-export-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
@@ -866,7 +866,7 @@ function PrivacyTab({ currentUser }: { currentUser: { id: string; role: string;
<Mail className="h-4 w-4 text-gray-600 dark:text-gray-400" />
<h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300">{t('dsgvo.contact_dpo')}</h4>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400">datenschutz@competencetrack.org</p>
<p className="text-sm text-gray-600 dark:text-gray-400">datenschutz@schulos.org</p>
</div>
</CardContent>
</Card>
@@ -1070,12 +1070,12 @@ function PrivacyTab({ currentUser }: { currentUser: { id: string; role: string;
className="min-h-[44px] rounded-xl border-violet-200 dark:border-violet-900/30 text-violet-700 dark:text-violet-300 hover:bg-violet-50 dark:hover:bg-violet-900/20 font-semibold"
onClick={() => {
// Generate a simple DPA template as a downloadable text file
const dpaTemplate = `Auftragsverarbeitungsvertrag (AVV)\ngemäß Art. 28 DSGVO\n\nVerantwortliche Stelle (Schule):\n[Name der Schule]\n[Adresse]\n\nAuftragsverarbeiter:\nCompetenceTrack\n[Adresse]\n\n1. Gegenstand und Dauer der Verarbeitung\nDer Auftragsverarbeiter verarbeitet personenbezogene Daten im Auftrag der verantwortlichen Stelle gemäß den Bestimmungen dieses Vertrages.\n\n2. Art und Zweck der Verarbeitung\n- Bereitstellung und Betrieb der CompetenceTrack-Plattform\n- Verwaltung von Schüler- und Klassendaten\n- Dokumentation von Lernfortschritten\n- Erstellung von Zeugnissen und Berichten\n\n3. Art der personenbezogenen Daten\n- Name, E-Mail-Adresse\n- Schülereinschreibungsdaten\n- Lernfortschrittsdaten\n- Bewertungsdaten\n- Anwesenheitsdaten\n\n4. Betroffene Personenkreise\n- Schülerinnen und Schüler\n- Lehrkräfte\n- Eltern / Erziehungsberechtigte\n\n5. Technisch-organisatorische Maßnahmen\nDer Auftragsverarbeiter implementiert angemessene technisch-organisatorische Maßnahmen gemäß Art. 32 DSGVO.\n\n6. Löschung und Rückgabe von Daten\nNach Beendigung des Auftragsverhältnisses werden alle personenbezogenen Daten gelöscht.\n\n7. Kontrolle durch die verantwortliche Stelle\nDie verantwortliche Stelle hat das Recht, die Einhaltung der Maßnahmen zu kontrollieren.\n\n8. Unterauftragsverhältnisse\nEine Weitergabe an Unterauftragnehmer bedarf der vorherigen Zustimmung der verantwortlichen Stelle.\n\nOrt, Datum: _______________\n\nUnterschrift Verantwortliche Stelle: _______________\nUnterschrift Auftragsverarbeiter: _______________`;
const dpaTemplate = `Auftragsverarbeitungsvertrag (AVV)\ngemäß Art. 28 DSGVO\n\nVerantwortliche Stelle (Schule):\n[Name der Schule]\n[Adresse]\n\nAuftragsverarbeiter:\nSchulOS\n[Adresse]\n\n1. Gegenstand und Dauer der Verarbeitung\nDer Auftragsverarbeiter verarbeitet personenbezogene Daten im Auftrag der verantwortlichen Stelle gemäß den Bestimmungen dieses Vertrages.\n\n2. Art und Zweck der Verarbeitung\n- Bereitstellung und Betrieb der SchulOS-Plattform\n- Verwaltung von Schüler- und Klassendaten\n- Dokumentation von Lernfortschritten\n- Erstellung von Zeugnissen und Berichten\n\n3. Art der personenbezogenen Daten\n- Name, E-Mail-Adresse\n- Schülereinschreibungsdaten\n- Lernfortschrittsdaten\n- Bewertungsdaten\n- Anwesenheitsdaten\n\n4. Betroffene Personenkreise\n- Schülerinnen und Schüler\n- Lehrkräfte\n- Eltern / Erziehungsberechtigte\n\n5. Technisch-organisatorische Maßnahmen\nDer Auftragsverarbeiter implementiert angemessene technisch-organisatorische Maßnahmen gemäß Art. 32 DSGVO.\n\n6. Löschung und Rückgabe von Daten\nNach Beendigung des Auftragsverhältnisses werden alle personenbezogenen Daten gelöscht.\n\n7. Kontrolle durch die verantwortliche Stelle\nDie verantwortliche Stelle hat das Recht, die Einhaltung der Maßnahmen zu kontrollieren.\n\n8. Unterauftragsverhältnisse\nEine Weitergabe an Unterauftragnehmer bedarf der vorherigen Zustimmung der verantwortlichen Stelle.\n\nOrt, Datum: _______________\n\nUnterschrift Verantwortliche Stelle: _______________\nUnterschrift Auftragsverarbeiter: _______________`;
const blob = new Blob([dpaTemplate], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'AVV_CompetenceTrack_Vorlage.txt';
a.download = 'AVV_SchulOS_Vorlage.txt';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
@@ -1102,7 +1102,7 @@ function PrivacyTab({ currentUser }: { currentUser: { id: string; role: string;
title: 'Verzeichnis von Verarbeitungstätigkeiten',
legalBasis: 'Art. 30 DSGVO',
controller: '[Name der Schule]',
processor: 'CompetenceTrack',
processor: 'SchulOS',
processingActivities: [
{ name: 'Benutzerverwaltung', purpose: 'Bereitstellung der Plattform', dataCategories: 'Name, E-Mail, Rolle', retention: 'Dauer der Nutzung + 30 Tage', legalBasis: 'Art. 6 Abs. 1 lit. b DSGVO' },
{ name: 'Schülerverwaltung', purpose: 'Verwaltung von Klassen und Schülern', dataCategories: 'Name, Geburtsdatum, Geschlecht', retention: 'Dauer der Nutzung + 30 Tage', legalBasis: 'Art. 6 Abs. 1 lit. b DSGVO' },
@@ -5085,7 +5085,7 @@ export default function SettingsView() {
</div>
)}
<div>
<p className="font-bold text-gray-900 dark:text-gray-100" style={{ color: brandingForm.primaryColor }}>{selectedSchool?.name || 'CompetenceTrack'}</p>
<p className="font-bold text-gray-900 dark:text-gray-100" style={{ color: brandingForm.primaryColor }}>{selectedSchool?.name || 'SchulOS'}</p>
<p className="text-xs text-gray-500 dark:text-gray-400">{brandingForm.motto || t('app.subtitle')}</p>
</div>
</div>
@@ -5444,7 +5444,7 @@ export default function SettingsView() {
<div className="p-4 rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900">
<p className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-1">{t('email.template_subject')}: {emailPreviewTemplate.subject}</p>
<div className="mt-3 p-3 rounded-xl bg-gray-50 dark:bg-gray-800/50 text-sm max-h-64 overflow-y-auto scrollbar-education">
{emailPreviewTemplate.body.replace(/\{\{studentName\}\}/g, 'Max Mustermann').replace(/\{\{className\}\}/g, 'Klasse 5a').replace(/\{\{teacherName\}\}/g, 'Frau Muster').replace(/\{\{date\}\}/g, new Date().toLocaleDateString()).replace(/\{\{schoolName\}\}/g, 'CompetenceTrack Schule').replace(/\{\{subjectName\}\}/g, 'Mathematik').replace(/\{\{score\}\}/g, '85%')}
{emailPreviewTemplate.body.replace(/\{\{studentName\}\}/g, 'Max Mustermann').replace(/\{\{className\}\}/g, 'Klasse 5a').replace(/\{\{teacherName\}\}/g, 'Frau Muster').replace(/\{\{date\}\}/g, new Date().toLocaleDateString()).replace(/\{\{schoolName\}\}/g, 'SchulOS Schule').replace(/\{\{subjectName\}\}/g, 'Mathematik').replace(/\{\{score\}\}/g, '85%')}
</div>
</div>
<div className="space-y-2">
+1 -1
View File
@@ -378,7 +378,7 @@ function exportStudentCsv(data: StudentDetailData) {
const rows: string[] = [];
// Header section
rows.push('CompetenceTrack - Student Export');
rows.push('SchulOS - Student Export');
rows.push(`Student,${studentName}`);
rows.push(`Class,${primaryClass}`);
rows.push(`School,${schoolName}`);