- Python 49.3%
- HTML 23.2%
- JavaScript 21.4%
- CSS 3.5%
- Shell 2.4%
- Other 0.2%
Versionsnummer von v0.5.0 auf v0.6.0 angehoben (VERSION, README, PROJECT_STRUCTURE, HILFE, helpers.get_version-Fallback). Changelog- Eintrag 0.6.0 ergänzt (Auto-Save, LAN-Zugriff, Test-Isolation-Fix, create_app-Factory, app.config['LESSONS'], Route-Tests + ruff). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .githooks | ||
| alembic | ||
| data | ||
| routes | ||
| services | ||
| static | ||
| templates | ||
| tests | ||
| .coveragerc | ||
| .gitignore | ||
| .stylelintrc.json | ||
| alembic.ini | ||
| app.py | ||
| cleanup.sh | ||
| convert_txt_files_to_lessons_json.py | ||
| HILFE.md | ||
| JAVASCRIPT_MODULES.md | ||
| MIGRATIONS.md | ||
| models.py | ||
| PROJECT_STRUCTURE.md | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| ruff.toml | ||
| run_coverage.sh | ||
| setup.sh | ||
| setup_database.py | ||
| start.sh | ||
| VERSION | ||
Typewriter Tutor - Adaptiver Tipptrainer
Version: v0.6.0 (siehe VERSION Datei)
Ein moderner, webbasierter Tipptrainer mit adaptivem Metronom und umfangreichen Statistiken. Das Programm passt sich automatisch Ihrer Tippgeschwindigkeit an und hilft Ihnen, das Zehnfingerschreiben systematisch zu erlernen.
💡 Hinweis: Dieses Projekt dient auch als Übungsprojekt für das KI-Programmiertool Aider.
✨ Hauptfunktionen
🎯 Adaptives Metronom
- Automatische Geschwindigkeitsanpassung: Das Metronom passt sich dynamisch Ihrer Tippgeschwindigkeit an
- 5 intelligente Anpassungsregeln: Beschleunigt bei hoher Genauigkeit, bremst bei Fehlern
- Zielgenauigkeit: Hält Sie im optimalen Bereich von 91-95% Genauigkeit
- Konfigurierbare Obergrenze: Maximale Geschwindigkeit einstellbar (Standard: 100 BPM)
- Präzises Timing: Läuft unabhängig von Tastatureingaben mit Web Audio API
- Zwei Modi:
- Automatisch: Adaptives Metronom (empfohlen)
- Explizit: Feste Geschwindigkeit (40-200 BPM)
- Streak-Bonus: Belohnt fehlerfreies Tippen mit höherer Geschwindigkeit
📊 Umfangreiche Statistiken
- Echtzeit-Metriken: ZPM (Zeichen/Minute), WPM (Wörter/Minute), Präzision in %
- Positive Darstellung: Präzisions-Anzeige statt Fehlerrate für motivierendes Feedback
- Detaillierte Diagramme: Visualisierung Ihrer Fortschritte mit Chart.js
- Lektionsbasierte Auswertung: Separate Statistiken für jede Lektion
- Historische Daten: Verfolgen Sie Ihre Entwicklung über die Zeit
- Datenexport: CSV und JSON-Export Ihrer Statistiken
🎨 Moderne Benutzeroberfläche
- Direct Input: Tippen Sie direkt im Vorlagenfeld - kein separates Eingabefeld
- Visuelles Feedback:
- ✅ Grün für korrekte Zeichen
- ❌ Rot für Fehler mit orangefarbener Anzeige des falsch eingegebenen Zeichens
- 📍 Blinkender Cursor zeigt Ihre Position
- Dezentes Design: Schlichte, ablenkungsfreie Statistik-Anzeige ohne bunte Badges
- Versionsnummer: Im Header sichtbar für bessere Nachvollziehbarkeit
- Dark/Light Mode: Komfortable Arbeit bei Tag und Nacht
- Responsive Design: Funktioniert auf Desktop und mobilen Geräten
- Hilfe-System: Integrierte Hilfe mit detaillierten Erklärungen
🔧 Erweiterte Features
- ErrorLock: Optional müssen Fehler korrigiert werden, bevor weitergeschrieben werden kann
- Pause-Funktion: Unterbrechen und Fortsetzen jederzeit möglich
- Flexible Lektionsauswahl: 43+ Lektionen von Grundlagen bis Programmierung
- Fortschrittsverfolgung: Automatisches Speichern Ihres Fortschritts
- Anti-Cheat: Verhindert Copy-Paste und unerlaubte Hilfen
🚀 Installation
Voraussetzungen
- Python 3.8 oder höher
- pip (Python Package Manager)
Schnellstart
- Repository klonen oder Download:
git clone https://kitux.de/forgejo/dschlueter/typewriter_tutor.git
cd typewriter_tutor
Alternativ: Neuestes Release herunterladen
- Virtuelle Umgebung erstellen (empfohlen):
python -m venv venv
source venv/bin/activate # Linux/Mac
# oder
venv\Scripts\activate # Windows
- Abhängigkeiten installieren:
pip install -r requirements.txt
- Datenbank initialisieren (optional, wird automatisch beim Start erstellt):
# Bei erster Installation oder für Updates:
alembic upgrade head
- Anwendung starten:
python app.py
- Im Browser öffnen:
http://localhost:5000
📁 Projektstruktur
typewriter/
├── app.py # Flask-Hauptanwendung
├── models.py # SQLAlchemy Datenbankmodelle
├── convert_txt_files_to_lessons_json.py # Tool: TXT → lessons.json
├── requirements.txt # Python-Dependencies
├── .env # Secret Key (automatisch generiert)
├── .gitignore # Git-Ignore-Konfiguration
│
├── data/
│ └── lessons.json # 43 Lektionen (JSON)
│
├── static/
│ ├── css/
│ │ └── style.css # Styling (Dark/Light Mode)
│ ├── js/ # Modulare JavaScript-Architektur (ES6)
│ │ ├── main.js # Hauptorchestration
│ │ ├── keyboard.js # Keyboard-Event-Handling
│ │ ├── metronome.js # Adaptives Metronom
│ │ ├── session.js # Session Management
│ │ ├── statistics.js # Statistik-Berechnungen
│ │ ├── textDisplay.js # Text-Rendering
│ │ ├── theme.js # Theme Management
│ │ └── ui.js # UI-Interaktionen
│ └── favicon.svg # Schreibmaschinen-Icon
│
├── templates/
│ ├── index.html # Hauptseite (Training)
│ ├── statistics.html # Statistik-Diagramme
│ └── settings.html # Einstellungen (Metronom, Anzeige)
│
├── alembic/ # Datenbank-Migrationen
│ ├── env.py
│ ├── versions/
│ │ └── 09de7cfb8b74_initial_migration.py
│ └── alembic.ini
│
├── instance/
│ └── typewriter.db # SQLite-Datenbank (automatisch erstellt)
│
├── README.md # Diese Datei
├── CLAUDE.md # Projektdokumentation für KI
└── MIGRATIONS.md # Alembic-Anleitung
🎮 Verwendung
Grundlegende Bedienung
- Training starten: Öffnen Sie die Anwendung im Browser
- Lektion wählen: Klicken Sie auf eine Lektionsnummer in der Lektionsleiste
- Tippen: Beginnen Sie direkt zu tippen - der Cursor zeigt Ihre Position
- Statistiken: Werden in Echtzeit angezeigt (optional über "Leistung" einblendbar)
- Navigation:
- Weiter: Nächste Lektion
- Leistung: Detaillierte Statistiken ein-/ausblenden
- Statistik: Zur Statistik-Seite mit Diagrammen
- Beenden: Sitzung beenden
Steuerung
| Taste/Aktion | Funktion |
|---|---|
| Buchstaben/Zahlen | Zeichen eingeben |
| Leertaste | Leerzeichen |
| Enter | Zeilenumbruch (falls im Text vorhanden) |
| Pfeiltaste ←/→ | Cursor bewegen |
| Backspace | Zeichen löschen |
| Lautsprecher-Icon | Metronom ein/aus |
| Schloss-Icon | ErrorLock ein/aus |
| Play/Pause-Icon | Training pausieren/fortsetzen |
| Mond/Sonne-Icon | Dark/Light Mode wechseln |
| Zahnrad-Icon | Einstellungen öffnen |
Einstellungen
Über das Zahnrad-Icon (⚙️) gelangen Sie zu den Einstellungen:
Metronom-Einstellungen:
- Modus: Automatisch (adaptiv) oder Explizit (feste Geschwindigkeit)
- Geschwindigkeit: 40-200 ZPM (nur im Explizit-Modus)
- Ziel-Fehlerrate: 1-20% (nur im Automatik-Modus)
- Maximale Geschwindigkeit: 40-200 BPM (Standard: 100) - verhindert Überforderung bei fehlerfreiem Tippen
Statistik-Anzeige:
- ZPM (Zeichen pro Minute) oder WPM (Wörter pro Minute)
📈 Statistiken und Metriken
Berechnungsformeln
Zeichen pro Minute (ZPM) = (Korrekte Zeichen / Zeit in Sekunden) × 60
Wörter pro Minute (WPM) = (Korrekte Zeichen / 5) / (Zeit in Minuten)
Fehlerrate (%) = (Falsche Tastenanschläge / Gesamte Tastenanschläge) × 100
Präzision (%) = 100 - Fehlerrate
Statistik-Seite
Die Statistik-Seite (/statistics) bietet:
- Interaktive Diagramme: ZPM/WPM und Fehlerrate über die Zeit
- Lektionsauswahl: Separate Statistiken für jede Lektion
- Datenexport: CSV und JSON-Download Ihrer Statistiken
- Verlaufsanalyse: Sehen Sie Ihre Fortschritte über mehrere Sitzungen
🧪 Tests
Das Projekt enthält eine umfassende Test-Suite mit 97 Tests (100% Erfolgsrate) und lokaler Validierung per Pre-commit-Hook (ruff + Tests).
Test-Übersicht
| Kategorie | Anzahl | Status |
|---|---|---|
| Gesamt | 97 Tests | ✅ 100% |
| Unit Tests | 54 Tests | ✅ Bestanden |
| Integration Tests | 31 Tests | ✅ Bestanden |
| Route Tests | 12 Tests | ✅ Bestanden |
Test-Ausführung
# Alle Tests
python -m unittest discover -s tests -p "test_*.py" -v
# Nur Unit Tests (schnell, ohne DB)
python -m unittest tests.test_lesson_service tests.test_statistics_service tests.test_settings_service -v
# Nur Integration Tests (mit DB)
python -m unittest tests.test_integration_progress tests.test_integration_statistics -v
# Nur Route-Tests (Flask-Testclient)
python -m unittest tests.test_routes -v
# Coverage Report generieren
./run_coverage.sh
Was wird getestet?
Service Layer (Unit + Integration):
- ✅ LessonService: Navigation, Validierung, Edge Cases
- ✅ StatisticsService: Berechnungen (ZPM/WPM), DB-Operationen, 30-Tage-Daten
- ✅ SettingsService: Validierungen, Boundary Values
- ✅ ProgressService: CRUD, State Management, Multi-Lesson Independence, Lektions-Auflösung
Routes (test_routes.py):
- ✅ Seiten (
/,/train,/statistics,/settings) und zentrale API-Endpoints inkl. CSV-Export
Lokale Validierung
Die Validierung läuft lokal über einen Git-Pre-commit-Hook (aktuell ist keine serverseitige CI eingerichtet).
- ✅ Pre-commit Hook führt Unit- und Integrationstests vor jedem Commit aus und blockiert bei Fehlern
- ✅ Coverage Reports mit HTML-Visualisierung (lokal via
./run_coverage.sh)
Pre-commit Hook Installation:
# Hook ist bereits installiert, oder kopiere Template:
cp .githooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Weitere Informationen:
- 📖 Service Tests:
tests/README.md
🔧 Entwicklung
Lektionen aus TXT-Dateien erstellen
Das Projekt enthält ein Kommandozeilen-Tool zum Konvertieren von TXT-Dateien in das lessons.json Format:
# Konvertiere TXT-Dateien zu lessons.json
python3 convert_txt_files_to_lessons_json.py 01.1_*.txt 01.2_*.txt 01.3_*.txt
# Mit custom Output-Datei
python3 convert_txt_files_to_lessons_json.py -o data/lessons.json *.txt
# Hilfe anzeigen
python3 convert_txt_files_to_lessons_json.py --help
TXT-Datei Format:
Titel: 01.1 Erarbeitung der Grundstellung
Untertitel: Die erste Lektion (optional, wird ignoriert)
Anweisung: Sprechen Sie laut und deutlich jeden Buchstaben mit.
ffff jjjj ffff jjjj ffff jjjj
ffjj ffjj ffjj ffjj ffjj ffjj
...
Dateinamen-Format: XX.Y_Beschreibung.txt (z.B. 01.1_Grundstellung.txt)
- Die Nummer wird zur
lesson(z.B.01.1→"1.1") - Die Reihenfolge der Parameter bestimmt die Reihenfolge in der JSON-Datei
- Kommentarzeilen (beginnend mit
#) werden ignoriert
Datenbank-Migrationen
Das Projekt verwendet Alembic für Datenbank-Schema-Änderungen:
# Neue Migration erstellen
alembic revision --autogenerate -m "Beschreibung"
# Migrationen anwenden
alembic upgrade head
# Migration rückgängig machen
alembic downgrade -1
Siehe MIGRATIONS.md für vollständige Anleitung.
API-Endpoints
Öffentliche Endpoints:
GET /- Hauptseite (Training)GET /statistics- Statistik-Seite mit DiagrammenGET /settings- EinstellungsseiteGET /export/statistics/csv- CSV-ExportGET /export/statistics/json- JSON-Export
API-Endpoints (AJAX):
POST /update_progress- Fortschritt aktualisierenPOST /next_text- Nächste Lektion ladenPOST /set_lesson- Lektion wechselnPOST /save_lesson_statistics- Lektionsstatistiken speichernGET /get_lesson_statistics/<int:lesson_index>- Statistiken abrufenPOST /save_settings- Einstellungen speichernPOST /set_metronome- Metronom-EinstellungenPOST /end_session- Sitzung beenden
Debug-Endpoints (nur im Debug-Modus):
GET /debug- Debug-InformationenPOST /repair_json- JSON-ReparaturPOST /recreate_lessons- Lektionen neu erstellen
Sicherheitsfeatures
- ✅ CSRF-Protection: Flask-WTF schützt vor Cross-Site Request Forgery
- ✅ Input-Validierung: Alle POST-Endpoints validieren Eingaben
- ✅ Secret Key: Automatisch generiert und sicher in
.envgespeichert (0o600) - ✅ XSS-Prevention: HTML-Escaping bei DOM-Manipulation
- ✅ SQL-Injection-Schutz: SQLAlchemy ORM mit Parameterisierung
- ✅ Anti-Cheat: Copy-Paste im Vorlagenfeld deaktiviert
🎯 Adaptives Metronom - Details
Das adaptive Metronom ist das Herzstück des Trainers:
Anpassungsregeln
| Regel | Bedingung | Aktion | Änderung |
|---|---|---|---|
| #1 | 15+ fehlerfreie Zeichen (Streak) | Belohnung | +3% |
| #2 | Genauigkeit > 95% | Zu leicht | +2% |
| #3 | Genauigkeit < 85% | Zu schwer | -8% |
| #4 | Genauigkeit 85-91% | Leicht unter Ziel | -3% |
| #5 | Genauigkeit 91-95% | Im Zielbereich | +1% |
Funktionsweise
- Sliding Window: Speichert die letzten 50 Tasteneingaben
- Genauigkeitsberechnung: Prozentsatz korrekter Eingaben
- Regelauswahl: Hierarchische Prüfung der 5 Regeln
- Geschwindigkeitsanpassung: Multiplikation mit Faktor
- Grenzen: Minimum 40 BPM, Maximum 200 BPM
Beispiel: Anfänger mit 70% Genauigkeit
- Start: 60 BPM
- Nach 50 Eingaben: ~40 BPM (Minimum erreicht)
- System bremst ab für weniger Fehler
Beispiel: Experte mit 98% Genauigkeit
- Start: 60 BPM
- Nach 100 Eingaben: ~200 BPM (Maximum erreicht)
- Plus Streak-Boni bei 15+ korrekten Zeichen
Die Implementierung findet sich in static/js/metronome.js.
📊 Datenbank-Schema
Tabellen
Progress - Aktueller Fortschritt
id INTEGER PRIMARY KEY
current_text_index INTEGER DEFAULT 0 -- Aktuelle Lektion
current_position INTEGER DEFAULT 0 -- Cursor-Position
last_text TEXT DEFAULT '' -- Letzte Eingabe
Statistic - Allgemeine Statistiken (Legacy)
id INTEGER PRIMARY KEY
total_chars INTEGER DEFAULT 0
correct_chars INTEGER DEFAULT 0
incorrect_chars INTEGER DEFAULT 0
error_rate FLOAT DEFAULT 0.0
typing_speed FLOAT DEFAULT 0.0
duration_per_char FLOAT DEFAULT 0.0
accuracy FLOAT DEFAULT 0.0
wpm FLOAT DEFAULT 0.0
LessonStatistic - Lektionsstatistiken (mit Indexes)
id INTEGER PRIMARY KEY
lesson_index INTEGER NOT NULL -- Index: idx_lesson_created
chars_per_minute FLOAT DEFAULT 0.0
error_rate FLOAT DEFAULT 0.0
wpm FLOAT DEFAULT 0.0
created_at DATETIME DEFAULT NOW() -- Index: idx_lesson_created
🤝 Beitragen
Contributions sind willkommen! Bitte:
- Fork das Repository
- Erstelle einen Feature-Branch (
git checkout -b feature/AmazingFeature) - Führe Tests aus (
python -m unittest discover -s tests -p "test_*.py" -v) - Commit deine Änderungen (
git commit -m 'Add AmazingFeature') - Push zum Branch (
git push origin feature/AmazingFeature) - Öffne einen Pull Request
Code-Qualität
- ✅ Alle Tests müssen bestehen
- ✅ Neue Features sollten Tests haben
- ✅ Code sollte dokumentiert sein (Docstrings)
- ✅ Befolge die bestehende Code-Struktur
📝 Changelog
Hinweis: Die aktuelle Versionsnummer wird zentral in der VERSION Datei verwaltet.
Version 0.6.0 (Aktuell)
- ✅ Auto-Save: Periodisches Speichern des Fortschritts (Standard alle 10s, im Code einstellbar) sowie beim Pausieren – schützt vor Datenverlust bei abruptem Abbruch
- ✅ LAN-Zugriff: Erreichbar von allen Geräten im Netzwerk; die LAN-URL wird beim Start ausgegeben (
Tipp-Training im LAN: http://<ip>:5000) - ✅ Fix: Integrationstests isoliert: Tests zerstörten zuvor die echte Datenbank – nun via
create_app()-Factory mit In-Memory-DB sauber getrennt - ✅ Application-Factory:
create_app(config)ermöglicht isolierte Test-Apps und nebenwirkungsfreien Import - ✅ Robustere Architektur: Lektionen zentral über
app.config['LESSONS'](behebt stale-state-Fehler u.a. auf der Statistik-Seite) - ✅ Mehr Tests & Linting: Route-Level-Tests (Flask-Testclient), ruff im Pre-commit-Hook (97 Tests gesamt)
- ✅ Fix: doppelte Statistik-Einträge, CSRF gezielt nur für
/shutdown, defensiveres Laden vonlessons.json
Version 0.5.0
- ✅ Lektionsspezifische Datenpersistenz: Jede Lektion speichert ihren Fortschritt unabhängig
- ✅ Automatisches Pausieren: Beim Wechsel zur Statistikseite wird automatisch pausiert und gespeichert
- ✅ Korrekte Datenwiederherstellung: Alle Daten (Cursor-Position, Eingabe, Trainingszeit) werden beim Zurückkehren korrekt geladen
- ✅ Reset-Funktionalität: Reset-Buttons (refresh-ccw) für Lektions-Fortschritt und Statistiken
- ✅ CTRL-P Tastenkombination: Pausieren/Fortsetzen mit Tastatur
- ✅ LessonProgress-Tabelle: Neue Datenbank-Tabelle für lektionsspezifische Daten
- ✅ Automatische Statistik-Speicherung: Bei Lektion-Abschluss werden Statistiken automatisch gespeichert
- ✅ Fix: ZPM-Berechnung: Mindestzeit von 1 Sekunde verhindert unrealistische Werte
Version 0.4.5
- ✅ Tooltips: Alle Symbole zeigen beim Hover hilfreiche Tooltips (Einstellungen, Theme wechseln, Fehler blockiert an/aus, etc.)
- ✅ Whitespace-Farbkodierung: Leerzeichen, Tabs und Newlines werden grau-grün (korrekt) oder rot (falsch) eingefärbt
- ✅ Fehler-Overlay für Whitespace: Falsch eingegebene Zeichen werden auch bei Leerzeichen, Tabs und Newlines in Orange angezeigt
- ✅ Live-Trainingszeit: Zeitanzeige aktualisiert sich sekündlich während des Trainings (pausiert automatisch bei Pause)
- ✅ Landing Page Bild: Piano-Emoji durch professionelles typing_hands.jpg Bild ersetzt
Version 0.4.0
- ✅ Landing Page: Begrüßungsseite mit Übersicht über Funktionen und direktem Zugang zum Training
- ✅ Theme-Integration: Dark/Light Mode Toggle auch auf der Landing Page
- ✅ Verbesserte Navigation: Zentrale Einstiegsseite für neue Nutzer
Version 0.3.0
- ✅ Maximale Metronom-Geschwindigkeit: Konfigurierbar (Standard: 100 BPM) zur Vermeidung von Überforderung
- ✅ Präzisions-Anzeige: Positive Darstellung (Präzision statt Fehlerrate) für motivierendes Feedback
- ✅ Persistente Settings: Einstellungen werden in Datenbank gespeichert (nicht nur Session)
- ✅ Metronom-Timing: Web Audio API für präzises, unterbrechungsfreies Timing
- ✅ UI-Verbesserungen: Dezente Statistik-Anzeige ohne bunte Badges, einheitliches Button-Design
- ✅ Versionsnummer: Im Header sichtbar
- ✅ Alembic-Migration:
max_bpm_speedzur UserSettings-Tabelle hinzugefügt
Version 0.2.0
- ✅ Streak-Statistik: 30-Tage Balkendiagramm mit täglicher Übungszeit
- ✅ Persistente Einstellungen: Alle Einstellungen und Lektion werden gespeichert
- ✅ Session-Ende: Übersichtsseite mit Statistiken beim Beenden
- ✅ Auto-Restore: Beim Neustart werden gespeicherte Einstellungen wiederhergestellt
- ✅ Shutdown-Funktion: Programm kann sich selbst beenden
- ✅ Metronom-Fix: Läuft jetzt rhythmisch präzise ohne Unterbrechungen
- ✅ Adaptives Metronom mit 5 Anpassungsregeln
- ✅ Einstellungsseite für Metronom und Anzeige
- ✅ CSV/JSON-Export der Statistiken
- ✅ CSRF-Protection mit Flask-WTF
- ✅ Umfassende Input-Validierung
- ✅ Secret Key Management mit .env
- ✅ Alembic für Datenbank-Migrationen
- ✅ 40 Unit-Tests (18 App + 22 Metronom)
- ✅ Accessibility-Verbesserungen (ARIA-Labels)
- ✅ Performance-Optimierung (DOM-Rendering)
- ✅ Custom Favicon (Schreibmaschine)
- ✅ Strukturiertes Logging
- ✅ Type Hints in Python-Code
Version 0.1.x
- ✅ Grundlegende Tipptrainer-Funktionalität
- ✅ 43 Lektionen von Grundlagen bis Programmierung
- ✅ Echtzeit-Statistiken
- ✅ Diagramme mit Chart.js
- ✅ Dark/Light Mode
- ✅ Direct Input im Vorlagenfeld
🐛 Bekannte Einschränkungen
- Metronom-Difficulty: Parameter
current_difficultywird aktuell nicht genutzt (immer 1.0) - Type Hints: Nicht alle Funktionen haben vollständige Type Hints
Diese können bei Bedarf in zukünftigen Versionen verbessert werden.
📄 Lizenz
MIT License - siehe LICENSE Datei für Details.
👨💻 Autor
Dieter Schlüter 📧 dieter.schlueter@linix.de 🌐 Forgejo: @dschlueter
🙏 Danksagungen
- Flask - Web-Framework
- Bootstrap 5 - UI-Framework
- Chart.js - Diagramme
- Lucide Icons - Icon-Set
- Aider - KI-Programmiertool für Entwicklung
Viel Erfolg beim Training! 🚀