Round 13: PWA Offline Mode, Rate Limiting, Behavior Analytics, Interventions, Audit Logging

This commit is contained in:
Mustafa Cetin committed 2026-07-29 10:23:50 +00:00
1 parent ceea8fb591
commit ff4dd670d4
33 files changed
+6327 -509

No files matched your search

+396
View File
@@ -1388,6 +1388,93 @@ const de: TranslationDict = {
'behavior.duplicate_category': 'Eine Kategorie mit diesem Namen existiert bereits',
'behavior.confirm_close': 'Möchten Sie den Dialog wirklich schließen? Nicht gespeicherte Änderungen gehen verloren.',
// Behavior Analytics
'behavior.tab_analytics': 'Analyse',
'behavior.tab_interventions': 'Massnahmen',
'behavior.analytics.trend': 'Verlauf',
'behavior.analytics.trend_desc': 'Positive vs. negative Vorfälle im Zeitverlauf',
'behavior.analytics.category_dist': 'Kategorienverteilung',
'behavior.analytics.category_dist_desc': 'Aufschlüsselung nach Verhaltenskategorie',
'behavior.analytics.risk_profile': 'Risikoprofil',
'behavior.analytics.risk_profile_desc': 'Schüler:innen mit häufigen negativen Vorfällen',
'behavior.analytics.class_comparison': 'Klassenvergleich',
'behavior.analytics.class_comparison_desc': 'Verhaltensmuster im Klassenvergleich',
'behavior.analytics.time_of_day': 'Tageszeit-Analyse',
'behavior.analytics.time_of_day_desc': 'Wann Vorfälle am häufigsten auftreten',
'behavior.analytics.positive_trend': 'Positive Entwicklung',
'behavior.analytics.positive_trend_desc': 'Schüler:innen mit positiver Verhaltensentwicklung',
'behavior.analytics.positive_change': 'Positive Veränderung',
'behavior.analytics.negative_change': 'Negative Veränderung',
'behavior.analytics.period': 'Zeitraum',
'behavior.analytics.last_30': 'Letzte 30 Tage',
'behavior.analytics.last_90': 'Letzte 90 Tage',
'behavior.analytics.this_year': 'Dieses Schuljahr',
'behavior.analytics.risk_high': 'Hohes Risiko',
'behavior.analytics.risk_medium': 'Mittleres Risiko',
'behavior.analytics.risk_low': 'Niedriges Risiko',
'behavior.analytics.incidents_count_short': 'Vorfälle',
// Behavior Interventions
'behavior.intervention.title': 'Verhaltensmassnahmen',
'behavior.intervention.subtitle': 'Massnahmen erfassen und deren Wirksamkeit verfolgen',
'behavior.intervention.add': 'Massnahme hinzufügen',
'behavior.intervention.edit': 'Massnahme bearbeiten',
'behavior.intervention.type': 'Typ',
'behavior.intervention.type.warning': 'Verwarnung',
'behavior.intervention.type.meeting': 'Gespräch',
'behavior.intervention.type.action_plan': 'Aktionsplan',
'behavior.intervention.type.support': 'Unterstützung',
'behavior.intervention.type.parent_contact': 'Elternkontakt',
'behavior.intervention.description': 'Beschreibung',
'behavior.intervention.description_placeholder': 'Beschreibung der Massnahme…',
'behavior.intervention.status': 'Status',
'behavior.intervention.status.planned': 'Geplant',
'behavior.intervention.status.in_progress': 'In Bearbeitung',
'behavior.intervention.status.completed': 'Abgeschlossen',
'behavior.intervention.status.cancelled': 'Abgebrochen',
'behavior.intervention.assigned_to': 'Zugewiesen an',
'behavior.intervention.assigned_to_placeholder': 'Lehrkraft auswählen',
'behavior.intervention.start_date': 'Startdatum',
'behavior.intervention.end_date': 'Enddatum',
'behavior.intervention.outcome': 'Ergebnis',
'behavior.intervention.outcome_placeholder': 'Ergebnis der Massnahme…',
'behavior.intervention.linked_incident': 'Verknüpfter Vorfall',
'behavior.intervention.no_incident': 'Kein Vorfall verknüpft',
'behavior.intervention.effectiveness': 'Wirksamkeit',
'behavior.intervention.progress': 'Fortschritt',
'behavior.intervention.no_interventions': 'Keine Massnahmen vorhanden',
'behavior.intervention.no_interventions_desc': 'Erstellen Sie eine Massnahme, um das Verhalten zu unterstützen.',
'behavior.intervention.saved': 'Massnahme gespeichert',
'behavior.intervention.deleted': 'Massnahme gelöscht',
'behavior.intervention.error_save': 'Fehler beim Speichern der Massnahme',
'behavior.intervention.error_delete': 'Fehler beim Löschen der Massnahme',
'behavior.intervention.required_type': 'Bitte wählen Sie einen Typ aus',
'behavior.intervention.required_description': 'Bitte geben Sie eine Beschreibung ein',
'behavior.intervention.filter_status': 'Status filtern',
'behavior.intervention.all_statuses': 'Alle Status',
'behavior.intervention.filter_type': 'Typ filtern',
'behavior.intervention.all_types': 'Alle Typen',
// Audit Log Enhancement
'audit.entity_type': 'Entitätstyp',
'audit.entity_type_filter': 'Nach Typ filtern',
'audit.all_entity_types': 'Alle Typen',
'audit.user_filter': 'Benutzer filtern',
'audit.all_users': 'Alle Benutzer',
'audit.changes': 'Änderungen',
'audit.before': 'Vorher',
'audit.after': 'Nachher',
'audit.detail': 'Detailansicht',
'audit.export_csv': 'Als CSV exportieren',
'audit.page': 'Seite',
'audit.of': 'von',
'audit.entries': 'Einträge',
'audit.previous': 'Zurück',
'audit.next': 'Weiter',
'audit.no_changes': 'Keine Änderungsdetails verfügbar',
'audit.ip_address': 'IP-Adresse',
'audit.user_agent': 'Benutzer-Agent',
// Curriculum Coverage — Kompetenzabdeckung
'nav.coverage': 'Abdeckung',
'coverage.title': 'Kompetenzabdeckung',
@@ -2327,6 +2414,117 @@ const de: TranslationDict = {
'performance.title': 'Leistung',
'performance.fps': 'Bilder pro Sekunde',
'mobile.optimized': 'Für mobile Geräte optimiert',
// ── Report Scheduling (Task 13) ──
'schedules.title': 'Berichtsplanung',
'schedules.frequency': 'Häufigkeit',
'schedules.weekly': 'Wöchentlich',
'schedules.monthly': 'Monatlich',
'schedules.quarterly': 'Vierteljährlich',
'schedules.end_of_term': 'Ende des Halbjahres',
'schedules.next_run': 'Nächste Ausführung',
'schedules.last_run': 'Letzte Ausführung',
'schedules.manual_run': 'Manuell ausführen',
'schedules.recipients': 'Empfänger',
'schedules.include_students': 'Schüler einbeziehen',
'schedules.include_grades': 'Noten einbeziehen',
'schedules.include_attendance': 'Anwesenheit einbeziehen',
'schedules.include_behavior': 'Verhalten einbeziehen',
'schedules.include_competencies': 'Kompetenzen einbeziehen',
'schedules.create_schedule': 'Planung erstellen',
'schedules.edit_schedule': 'Planung bearbeiten',
'schedules.delete_schedule': 'Planung löschen',
'schedules.active': 'Aktiv',
'schedules.inactive': 'Inaktiv',
'schedules.no_schedules': 'Keine Berichtsplanungen vorhanden',
'schedules.no_schedules_desc': 'Erstellen Sie Ihre erste Berichtsplanung.',
'schedules.running': 'Wird ausgeführt...',
'schedules.run_success': 'Bericht erfolgreich generiert',
'schedules.run_error': 'Fehler bei der Berichtsgenerierung',
'schedules.day_of_week': 'Wochentag',
'schedules.day_of_month': 'Tag des Monats',
'schedules.month_of_year': 'Monat',
'schedules.template': 'Vorlage',
'schedules.all_classes': 'Alle Klassen',
'schedules.timeline': 'Zeitplan',
'schedules.confirm_delete': 'Planung löschen?',
'schedules.confirm_delete_desc': 'Diese Berichtsplanung wird unwiderruflich gelöscht.',
'schedules.confirm_run': 'Manuell ausführen?',
'schedules.confirm_run_desc': 'Der Bericht wird sofort generiert und an die Empfänger gesendet.',
'schedules.toggle_active': 'Aktivieren/Deaktivieren',
// ── School District (Task 13) ──
'district.title': 'Schulbezirk',
'district.schools': 'Schulen',
'district.comparison': 'Schulvergleich',
'district.analytics': 'Bezirksanalyse',
'district.create': 'Bezirk erstellen',
'district.edit': 'Bezirk bearbeiten',
'district.delete': 'Bezirk löschen',
'district.assign_school': 'Schule zuordnen',
'district.unassign_school': 'Schule entfernen',
'district.name': 'Name',
'district.code': 'Bezirk-Code',
'district.region': 'Region',
'district.country': 'Land',
'district.admin_email': 'Administrator-E-Mail',
'district.no_districts': 'Keine Schulbezirke vorhanden',
'district.no_districts_desc': 'Erstellen Sie Ihren ersten Schulbezirk.',
'district.school_count': 'Anzahl Schulen',
'district.student_count': 'Anzahl Schüler',
'district.confirm_delete': 'Bezirk löschen?',
'district.confirm_delete_desc': 'Dieser Schulbezirk wird gelöscht. Die zugeordneten Schulen bleiben erhalten.',
'district.top_performing': 'Beste Schule',
'district.needs_attention': 'Schulung empfohlen',
'district.avg_attendance': 'Durchschnittliche Anwesenheit',
'district.competency_coverage': 'Kompetenzabdeckung',
'district.no_schools_assigned': 'Keine Schulen zugeordnet',
'district.select_school': 'Schule auswählen',
'district.cross_school_comparison': 'Schulvergleich',
'district.total_students': 'Gesamtschüler',
'district.total_classes': 'Gesamtklassen',
'district.total_teachers': 'Gesamtlehrer',
// PWA / Offline
'pwa.offline': 'Sie sind offline',
'pwa.offline_desc': 'Ihre Daten werden aus dem Cache geladen.',
'pwa.back_online': 'Wieder online',
'pwa.back_online_desc': 'Ihre Verbindung wurde wiederhergestellt.',
'pwa.cached_data': 'Cache-Daten',
'pwa.install_app': 'App installieren',
'pwa.install_app_desc': 'CompetenceTrack als App auf Ihrem Gerät installieren.',
'pwa.install': 'Installieren',
'pwa.installed': 'App installiert',
'pwa.installed_desc': 'CompetenceTrack wurde erfolgreich als App installiert.',
'pwa.install_accepted': 'Installation gestartet',
'pwa.update_available': 'Update verfügbar',
'pwa.update_available_desc': 'Eine neue Version ist verfügbar. Laden Sie die Seite neu.',
'pwa.reload': 'Neu laden',
'pwa.offline_mode': 'Offline-Modus',
'pwa.pending_sync': '{count} ausstehende Synchronisationen',
'pwa.sync_complete': 'Synchronisation abgeschlossen',
'pwa.sync_complete_desc': '{count} Änderungen wurden erfolgreich synchronisiert.',
'pwa.notebook_cached': 'Offline verfügbar',
'pwa.notebook_cached_desc': 'Dieses Notizbuch ist für die Offline-Nutzung gespeichert.',
'pwa.cache_notebook': 'Offline speichern',
'pwa.cache_notebook_desc': 'Notizbuch für Offline-Zugriff speichern.',
'pwa.cached_at': 'Gespeichert am',
'pwa.queued_edits': 'Ausstehende Änderungen',
'pwa.queued_edits_desc': '{count} Änderungen werden synchronisiert, wenn Sie wieder online sind.',
// Rate Limiting
'rate_limit.title': 'Zu viele Anfragen',
'rate_limit.description': 'Bitte warten Sie {retryAfter} bevor Sie es erneut versuchen.',
'rate_limit.status_title': 'Rate-Limit-Status',
'rate_limit.active_entries': 'Aktive Einträge',
'rate_limit.top_consumers': 'Top-Verbraucher',
'rate_limit.requests': 'Anfragen',
'rate_limit.no_active': 'Keine aktiven Rate-Limits',
'rate_limit.unavailable': 'Rate-Limit-Status nicht verfügbar',
'rate_limit.auth_limit': 'Auth-Limit: 5/Min',
'rate_limit.data_limit': 'Daten-Limit: 60/Min',
'rate_limit.write_limit': 'Schreib-Limit: 30/Min',
'rate_limit.heavy_limit': 'Schwer-Limit: 10/5Min',
};
const en: TranslationDict = {
@@ -3714,6 +3912,93 @@ const en: TranslationDict = {
'behavior.duplicate_category': 'A category with this name already exists',
'behavior.confirm_close': 'Are you sure you want to close? Unsaved changes will be lost.',
// Behavior Analytics
'behavior.tab_analytics': 'Analytics',
'behavior.tab_interventions': 'Interventions',
'behavior.analytics.trend': 'Trend',
'behavior.analytics.trend_desc': 'Positive vs. negative incidents over time',
'behavior.analytics.category_dist': 'Category Distribution',
'behavior.analytics.category_dist_desc': 'Breakdown by behavior category',
'behavior.analytics.risk_profile': 'Risk Profile',
'behavior.analytics.risk_profile_desc': 'Students with frequent negative incidents',
'behavior.analytics.class_comparison': 'Class Comparison',
'behavior.analytics.class_comparison_desc': 'Compare behavior patterns across classes',
'behavior.analytics.time_of_day': 'Time-of-Day Analysis',
'behavior.analytics.time_of_day_desc': 'When incidents most frequently occur',
'behavior.analytics.positive_trend': 'Positive Reinforcement',
'behavior.analytics.positive_trend_desc': 'Students with positive behavior trends',
'behavior.analytics.positive_change': 'Positive change',
'behavior.analytics.negative_change': 'Negative change',
'behavior.analytics.period': 'Period',
'behavior.analytics.last_30': 'Last 30 days',
'behavior.analytics.last_90': 'Last 90 days',
'behavior.analytics.this_year': 'This school year',
'behavior.analytics.risk_high': 'High risk',
'behavior.analytics.risk_medium': 'Medium risk',
'behavior.analytics.risk_low': 'Low risk',
'behavior.analytics.incidents_count_short': 'Incidents',
// Behavior Interventions
'behavior.intervention.title': 'Behavior Interventions',
'behavior.intervention.subtitle': 'Track interventions and their effectiveness',
'behavior.intervention.add': 'Add Intervention',
'behavior.intervention.edit': 'Edit Intervention',
'behavior.intervention.type': 'Type',
'behavior.intervention.type.warning': 'Warning',
'behavior.intervention.type.meeting': 'Meeting',
'behavior.intervention.type.action_plan': 'Action Plan',
'behavior.intervention.type.support': 'Support',
'behavior.intervention.type.parent_contact': 'Parent Contact',
'behavior.intervention.description': 'Description',
'behavior.intervention.description_placeholder': 'Describe the intervention…',
'behavior.intervention.status': 'Status',
'behavior.intervention.status.planned': 'Planned',
'behavior.intervention.status.in_progress': 'In Progress',
'behavior.intervention.status.completed': 'Completed',
'behavior.intervention.status.cancelled': 'Cancelled',
'behavior.intervention.assigned_to': 'Assigned To',
'behavior.intervention.assigned_to_placeholder': 'Select a teacher',
'behavior.intervention.start_date': 'Start Date',
'behavior.intervention.end_date': 'End Date',
'behavior.intervention.outcome': 'Outcome',
'behavior.intervention.outcome_placeholder': 'Outcome of the intervention…',
'behavior.intervention.linked_incident': 'Linked Incident',
'behavior.intervention.no_incident': 'No incident linked',
'behavior.intervention.effectiveness': 'Effectiveness',
'behavior.intervention.progress': 'Progress',
'behavior.intervention.no_interventions': 'No interventions yet',
'behavior.intervention.no_interventions_desc': 'Create an intervention to support behavior improvement.',
'behavior.intervention.saved': 'Intervention saved',
'behavior.intervention.deleted': 'Intervention deleted',
'behavior.intervention.error_save': 'Error saving intervention',
'behavior.intervention.error_delete': 'Error deleting intervention',
'behavior.intervention.required_type': 'Please select a type',
'behavior.intervention.required_description': 'Please enter a description',
'behavior.intervention.filter_status': 'Filter by status',
'behavior.intervention.all_statuses': 'All statuses',
'behavior.intervention.filter_type': 'Filter by type',
'behavior.intervention.all_types': 'All types',
// Audit Log Enhancement
'audit.entity_type': 'Entity Type',
'audit.entity_type_filter': 'Filter by type',
'audit.all_entity_types': 'All types',
'audit.user_filter': 'Filter by user',
'audit.all_users': 'All users',
'audit.changes': 'Changes',
'audit.before': 'Before',
'audit.after': 'After',
'audit.detail': 'Detail View',
'audit.export_csv': 'Export as CSV',
'audit.page': 'Page',
'audit.of': 'of',
'audit.entries': 'entries',
'audit.previous': 'Previous',
'audit.next': 'Next',
'audit.no_changes': 'No change details available',
'audit.ip_address': 'IP Address',
'audit.user_agent': 'User Agent',
// Curriculum Coverage
'nav.coverage': 'Coverage',
'coverage.title': 'Curriculum Coverage',
@@ -4653,6 +4938,117 @@ const en: TranslationDict = {
'performance.title': 'Leistung',
'performance.fps': 'Bilder pro Sekunde',
'mobile.optimized': 'Für mobile Geräte optimiert',
// ── Report Scheduling (Task 13) ──
'schedules.title': 'Report Scheduling',
'schedules.frequency': 'Frequency',
'schedules.weekly': 'Weekly',
'schedules.monthly': 'Monthly',
'schedules.quarterly': 'Quarterly',
'schedules.end_of_term': 'End of Term',
'schedules.next_run': 'Next Run',
'schedules.last_run': 'Last Run',
'schedules.manual_run': 'Run Manually',
'schedules.recipients': 'Recipients',
'schedules.include_students': 'Include Students',
'schedules.include_grades': 'Include Grades',
'schedules.include_attendance': 'Include Attendance',
'schedules.include_behavior': 'Include Behavior',
'schedules.include_competencies': 'Include Competencies',
'schedules.create_schedule': 'Create Schedule',
'schedules.edit_schedule': 'Edit Schedule',
'schedules.delete_schedule': 'Delete Schedule',
'schedules.active': 'Active',
'schedules.inactive': 'Inactive',
'schedules.no_schedules': 'No report schedules found',
'schedules.no_schedules_desc': 'Create your first report schedule.',
'schedules.running': 'Running...',
'schedules.run_success': 'Report generated successfully',
'schedules.run_error': 'Error generating report',
'schedules.day_of_week': 'Day of Week',
'schedules.day_of_month': 'Day of Month',
'schedules.month_of_year': 'Month',
'schedules.template': 'Template',
'schedules.all_classes': 'All Classes',
'schedules.timeline': 'Timeline',
'schedules.confirm_delete': 'Delete schedule?',
'schedules.confirm_delete_desc': 'This report schedule will be permanently deleted.',
'schedules.confirm_run': 'Run manually?',
'schedules.confirm_run_desc': 'The report will be generated immediately and sent to recipients.',
'schedules.toggle_active': 'Activate/Deactivate',
// ── School District (Task 13) ──
'district.title': 'School District',
'district.schools': 'Schools',
'district.comparison': 'School Comparison',
'district.analytics': 'District Analytics',
'district.create': 'Create District',
'district.edit': 'Edit District',
'district.delete': 'Delete District',
'district.assign_school': 'Assign School',
'district.unassign_school': 'Remove School',
'district.name': 'Name',
'district.code': 'District Code',
'district.region': 'Region',
'district.country': 'Country',
'district.admin_email': 'Admin Email',
'district.no_districts': 'No school districts found',
'district.no_districts_desc': 'Create your first school district.',
'district.school_count': 'School Count',
'district.student_count': 'Student Count',
'district.confirm_delete': 'Delete district?',
'district.confirm_delete_desc': 'This district will be deleted. Associated schools will remain.',
'district.top_performing': 'Top Performing',
'district.needs_attention': 'Needs Attention',
'district.avg_attendance': 'Average Attendance',
'district.competency_coverage': 'Competency Coverage',
'district.no_schools_assigned': 'No schools assigned',
'district.select_school': 'Select School',
'district.cross_school_comparison': 'Cross-School Comparison',
'district.total_students': 'Total Students',
'district.total_classes': 'Total Classes',
'district.total_teachers': 'Total Teachers',
// PWA / Offline
'pwa.offline': 'You are offline',
'pwa.offline_desc': 'Your data is being loaded from cache.',
'pwa.back_online': 'Back online',
'pwa.back_online_desc': 'Your connection has been restored.',
'pwa.cached_data': 'Cached data',
'pwa.install_app': 'Install App',
'pwa.install_app_desc': 'Install CompetenceTrack as an app on your device.',
'pwa.install': 'Install',
'pwa.installed': 'App installed',
'pwa.installed_desc': 'CompetenceTrack has been successfully installed as an app.',
'pwa.install_accepted': 'Installation started',
'pwa.update_available': 'Update available',
'pwa.update_available_desc': 'A new version is available. Reload the page to update.',
'pwa.reload': 'Reload',
'pwa.offline_mode': 'Offline Mode',
'pwa.pending_sync': '{count} pending synchronizations',
'pwa.sync_complete': 'Sync complete',
'pwa.sync_complete_desc': '{count} changes were successfully synchronized.',
'pwa.notebook_cached': 'Available offline',
'pwa.notebook_cached_desc': 'This notebook is saved for offline use.',
'pwa.cache_notebook': 'Save offline',
'pwa.cache_notebook_desc': 'Save notebook for offline access.',
'pwa.cached_at': 'Cached at',
'pwa.queued_edits': 'Pending changes',
'pwa.queued_edits_desc': '{count} changes will be synced when you are back online.',
// Rate Limiting
'rate_limit.title': 'Too many requests',
'rate_limit.description': 'Please wait {retryAfter} before trying again.',
'rate_limit.status_title': 'Rate Limit Status',
'rate_limit.active_entries': 'Active entries',
'rate_limit.top_consumers': 'Top consumers',
'rate_limit.requests': 'requests',
'rate_limit.no_active': 'No active rate limits',
'rate_limit.unavailable': 'Rate limit status unavailable',
'rate_limit.auth_limit': 'Auth limit: 5/min',
'rate_limit.data_limit': 'Data limit: 60/min',
'rate_limit.write_limit': 'Write limit: 30/min',
'rate_limit.heavy_limit': 'Heavy limit: 10/5min',
};
const translations: Record<string, TranslationDict> = { de, en };