14 KiB
📚 Wörterbuch Template - Vollständige Dokumentation
Übersicht
Das Wörterbuch Template (user-template-dictionary) ist eine Flask-basierte Web-Anwendung, die es Benutzern ermöglicht, persönliche Wörterbuch-Einträge zu speichern und zu verwalten. Jeder Eintrag besteht aus einem Wort und seiner Bedeutung, die in einer SQLite-Datenbank persistiert werden.
Features
- ✅ Persönliche Wörterbuch-Datenbank pro Benutzer
- ✅ SQLite-Persistierung - Daten bleiben erhalten nach Container-Neustart
- ✅ REST API für Verwaltung (GET, POST, PUT, DELETE)
- ✅ Moderne HTML/CSS/JS Frontend mit Fehlerbehandlung
- ✅ Health Checks für Monitoring
- ✅ Vollständige Fehlerbehandlung und Logging
- ✅ Docker Volume Support für Datenpersistierung
Architektur
High-Level Diagramm
Browser Request
↓
Flask Backend (Port 8080)
↓
SQLite Database (/data/app.db)
↓
Docker Volume (/volumes/{user-id})
↓
Persistente Speicherung
Komponenten
Frontend (HTML/CSS/JavaScript):
templates/index.html- Single Page Application mit React-ähnlichem State Management- Responsive Design (Mobile-freundlich)
- Real-time UI Updates
- Benutzerfreundliche Fehlerbehandlung
Backend (Flask + SQLite):
app.py- Python Flask Anwendung- SQLite Datenbank in
/data/app.db - REST API Endpoints
- Logging und Health Checks
Containerisierung:
Dockerfile- Python 3.11 slim Imagerequirements.txt- Python Dependencies (Flask, Werkzeug)- Unprivileged User (Port 8080)
- Health Check Endpoint
Installation & Setup
Schritt 1: Template in .env registrieren
Bearbeite .env und füge das Dictionary Template hinzu:
# .env
USER_TEMPLATE_IMAGES="user-template-01:latest;user-template-02:latest;user-template-next:latest;user-template-dictionary:latest"
Wichtig: Nur hier definierte Templates werden von bash install.sh gebaut!
Schritt 2: Metadaten in templates.json aktualisieren
Das Template ist bereits in templates.json registriert:
{
"type": "dictionary",
"image": "user-template-dictionary:latest",
"display_name": "📚 Wörterbuch",
"description": "Persönliches Wörterbuch mit Datenbank - Speichern Sie Wörter und Bedeutungen"
}
Schritt 3: Build & Deploy
# Alle Templates bauen (inkl. dictionary)
bash install.sh
# Docker Compose neu starten
docker-compose up -d --build
REST API Referenz
Base URL
http://localhost:8080
Endpoints
1. Frontend abrufen
GET /
Response: HTML-Seite mit Interface
2. Alle Wörter abrufen
GET /api/words
Response (200 OK):
{
"words": [
{
"id": 1,
"word": "Serendipität",
"meaning": "Das glückliche Finden von etwas Ungesucht",
"created_at": "2026-03-18T10:30:45"
},
{
"id": 2,
"word": "Wanderlust",
"meaning": "Starkes Verlangen zu reisen und die Welt zu erkunden",
"created_at": "2026-03-18T11:15:20"
}
],
"count": 2
}
3. Neues Wort hinzufügen
POST /api/words
Content-Type: application/json
{
"word": "Schadenfreude",
"meaning": "Freude über das Unglück anderer"
}
Response (201 Created):
{
"id": 3,
"word": "Schadenfreude",
"meaning": "Freude über das Unglück anderer",
"created_at": "2026-03-18T12:00:00"
}
Error Response (409 Conflict):
{
"error": "Das Wort \"Schadenfreude\" existiert bereits"
}
4. Wort aktualisieren
PUT /api/words/{id}
Content-Type: application/json
{
"word": "Schadenfreude",
"meaning": "Böse Freude über Missgeschick eines anderen"
}
Response (200 OK):
{
"id": 3,
"word": "Schadenfreude",
"meaning": "Böse Freude über Missgeschick eines anderen",
"created_at": "2026-03-18T12:00:00"
}
5. Wort löschen
DELETE /api/words/{id}
Response (204 No Content): (Leerer Body, nur Status 204)
6. Statistiken abrufen
GET /api/stats
Response (200 OK):
{
"total_words": 2,
"last_added": "2026-03-18T11:15:20",
"database": "sqlite3",
"storage": "/data/app.db"
}
7. Health Check
GET /health
Response (200 OK):
{
"status": "ok",
"database": "connected"
}
Error Response (500):
{
"status": "error",
"message": "database connection failed"
}
Datapersistierung
Docker Volumes
Die Datenbank wird in einem Docker Volume gespeichert, damit Daten bei Container-Neustarts erhalten bleiben.
Automatische Konfiguration (via container_manager.py)
Das Spawner Backend sollte automatisch Volumes mounten:
volumes = {
f"/volumes/{user_id}": {
"bind": "/data",
"mode": "rw"
}
}
Ergebnis:
- Jeder User erhält ein eigenes Verzeichnis
/volumes/{user_id} - Die SQLite DB wird gespeichert in
/volumes/{user_id}/app.db - Der Container sieht dies als
/data/app.db - Beim Container-Restart bleiben Daten erhalten
Manuelles Testen
# Container starten
docker run -v /volumes/user-123:/data -p 8080:8080 user-template-dictionary:latest
# Datenbank inspizieren
sqlite3 /volumes/user-123/app.db "SELECT * FROM words;"
# Container stoppen und neustart
docker stop <container-id>
docker start <container-id>
# Daten sollten noch da sein!
sqlite3 /volumes/user-123/app.db "SELECT * FROM words;"
Datenbankschema
Tabelle: words
CREATE TABLE words (
id INTEGER PRIMARY KEY AUTOINCREMENT,
word TEXT NOT NULL UNIQUE,
meaning TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
Spalten:
id- Eindeutige ID (Auto-Increment)word- Das Wort (UNIQUE - keine Duplikate!)meaning- Bedeutung/Definitioncreated_at- Erstellungsdatumupdated_at- Letztes Update
Constraints:
wordist UNIQUE - kann nicht doppelt vorkommen- Maximale Länge: 255 Zeichen für Wort, 2000 für Bedeutung
Sicherheit
Input Validation
- ✅ Wort und Bedeutung sind erforderlich
- ✅ Maximale Längen: 255 Zeichen (Wort), 2000 Zeichen (Bedeutung)
- ✅ HTML-Escaping in Frontend (XSS-Schutz)
- ✅ SQL-Injection-Schutz via Prepared Statements
Error Handling
- ✅ Konsistente JSON-Error-Responses
- ✅ Aussagekräftige Error-Messages
- ✅ HTTP Status Codes korrekt gesetzt
- ✅ Logging aller Fehler
Docker Security
- ✅ Unprivileged User (nicht Root)
- ✅ Port 8080 (nicht privilegierter Port)
- ✅ SQLite für Single-User (keine Multi-Client Issues)
Monitoring & Debugging
Logs anschauen
# Live Logs des Containers
docker logs -f user-dictionary-abc123
# Beispiel Log Output:
# [DICTIONARY] Database path: /data/app.db
# [DICTIONARY] Table 'words' already exists
# [DICTIONARY] Retrieved 2 words
# [DICTIONARY] Word added: 'Serendipität'
Health Check
# In Chrome DevTools oder terminal:
curl http://localhost:8080/health
# Antwort:
# {"status": "ok", "database": "connected"}
Database Debugging
# Mit der Python Shell in den Container gehen
docker exec -it <container-id> python
# Dann:
import sqlite3
conn = sqlite3.connect('/data/app.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM words')
print(cursor.fetchall())
Statistiken
curl http://localhost:8080/api/stats
# Antwort:
# {"total_words": 5, "last_added": "2026-03-18T...", "database": "sqlite3", "storage": "/data/app.db"}
Performance & Limits
Empfehlungen
- SQLite Limit: ~1 Million Zeilen problemlos
- Typical Use: Bis zu 10.000 Wörter problemlos
- Query Time: < 10ms für typische Abfragen
- Database Size: ~1KB pro Wort
Resource Limits (via .env)
# In .env definieren:
DEFAULT_MEMORY_LIMIT=512m # RAM pro Container
DEFAULT_CPU_QUOTA=50000 # 0.5 CPU
Skalierung
Falls die Anwendung wächst:
- PostgreSQL verwenden statt SQLite (für Multi-User)
- Redis Caching für häufige Abfragen
- Elasticsearch für Full-Text Suche in Bedeutungen
🔒 Sicherheit & Authentifizierung
JWT-Cookie Validierung
Das Dictionary-Template ist obligatorisch geschützt mit JWT-Token-Validierung:
- HttpOnly Cookie
spawner_tokenwird vom Spawner gesetzt - Vor jedem API-Request wird der Token validiert
- Ohne gültigen Token: 403 Forbidden
How It Works
User Login
↓
Spawner setzt HttpOnly Cookie: spawner_token=<JWT>
↓
Browser sendet Cookie automatisch bei jedem Request
↓
Dictionary-Template validiert JWT in: app.before_request()
↓
Gültig? → Erlauben API-Zugriff
Ungültig? → 403 Forbidden (Authentifizierung erforderlich)
Implementation Details
Token-Validierung in app.py:
@app.before_request
def validate_jwt_token():
# Öffentliche Endpoints (GET / und /health)
if request.path == '/' or request.path == '/health':
return
# Alle API-Calls brauchen gültigen JWT
token = request.cookies.get('spawner_token')
if not token:
return jsonify({'error': 'Authentifizierung erforderlich'}), 401
# Dekodiere und validiere JWT
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
g.user_id = payload.get('sub')
Sicherheits-Features
- ✅ HttpOnly Cookies - JavaScript kann Token nicht auslesen
- ✅ Secure Flag - Nur über HTTPS übertragen
- ✅ SameSite=Lax - CSRF-Schutz
- ✅ Token Expiration - Standard: 1 Stunde (konfigurierbar)
- ✅ JWT_SECRET - Wird vom Spawner übergeben
- ✅ Logout - Cookie wird beim Logout gelöscht
Testing der Sicherheit
# 1. Versuche direkten Zugriff OHNE Login
curl https://spawner.wieland.org/e220dd278a12-template-dictionary/api/words
# → Sollte 401 Unauthorized zurückgeben
# 2. Nach erfolgreichem Login
curl -b "spawner_token=<JWT>" https://spawner.wieland.org/e220dd278a12-template-dictionary/api/words
# → Sollte Wörter-Liste zurückgeben
# 3. Überprüfe Cookie im Browser
# Browser DevTools → Application → Cookies
# → spawner_token sollte HttpOnly markiert sein
Troubleshooting
Problem: "Datenbankfehler beim Abrufen"
Mögliche Ursachen:
1. Volume nicht gemountet
2. /data Verzeichnis nicht vorhanden
3. Datenbank-Datei korrupt
4. Permissionen falsch
Lösung:
docker exec container-id ls -la /data
docker exec container-id sqlite3 /data/app.db "SELECT 1"
Problem: "Wort existiert bereits" beim Hinzufügen
Das ist normal! Die Anwendung verhindert Duplikate.
Wörter sind eindeutig (UNIQUE Constraint).
Wenn das Problem ist: Bearbeiten statt Hinzufügen nutzen.
Oder: Wort löschen und neu hinzufügen.
Problem: Daten nach Restart weg
Ursache: Volume nicht korrekt gemountet.
Prüfen:
docker inspect <container-id> | grep -A10 Mounts
Sollte zeigen:
"Mounts": [
{
"Type": "bind",
"Source": "/volumes/user-123",
"Destination": "/data"
}
]
Problem: Container startet nicht
# Logs prüfen
docker logs <container-id> 2>&1 | tail -50
# Python Syntax prüfen
docker build -t test . --no-cache
# Dockerfile validieren
docker run --rm -it user-template-dictionary:latest python app.py
Wartung & Updates
Backup der Datenbank
# Einzelnen User-Backup
tar -czf backup-user-123.tar.gz /volumes/user-123/
# Alle User-Datenbanken
tar -czf backup-all-users.tar.gz /volumes/
Datenbank Upgrade
Falls die Tabelle erweitert werden soll:
# In app.py - init_db() Methode:
cursor.execute('''
ALTER TABLE words ADD COLUMN
category TEXT DEFAULT 'general'
''')
Logs archivieren
# Logs rotieren
docker logs --timestamps user-dictionary-abc > logs.txt
Integration mit Spawner
Automatischer Container-Spawn
Wenn ein Benutzer dieses Template wählt:
- Spawner erstellt Container mit Template
user-template-dictionary:latest - Mountet Volume:
/volumes/{user-id}:/data - Traefik routet Request zu Container unter
https://coder.domain.com/{user-slug} - Benutzer sieht Wörterbuch-Interface
- Datenbank wird in
/volumes/{user-id}/app.dberstellt - Bei nächstem Login: Gleicher Container + Gleiche Datenbank = Gleiche Wörter!
Admin-Dashboard Integration
Im Admin-Dashboard können Admins:
- ✅ Container starten/stoppen
- ✅ Container löschen (löscht auch Datenbank!)
- ✅ Logs ansehen
- ✅ Container-Status prüfen
Weitere Verbesserungen (Optional)
Mögliche Features für Zukunft
- Kategorien - Wörter in Kategorien organisieren
- Export/Import - CSV/JSON Download
- Suche - Volltext-Suche in Wörtern/Bedeutungen
- Tags - Flexible Kategorisierung
- Statistiken - Graphen, Lernfortschritt
- Multi-Language - Übersetzungen hinzufügen
- Phonetik - Audio-Aussprache
- Spaced Repetition - Lern-Algorithmus
Datenschutz & DSGVO
- ✅ Daten werden lokal in Containern gespeichert
- ✅ Keine Daten an Dritte übertragen
- ✅ Benutzer hat vollständige Kontrolle
- ✅ Einfaches Löschen möglich (Container löschen)
Support & Issues
Bei Problemen:
- Logs prüfen:
docker logs container-id - Health Check testen:
curl http://localhost:8080/health - Datenbank prüfen:
sqlite3 /data/app.db ".tables" - API testen:
curl http://localhost:8080/api/words
Version & Changelog
Version: 1.0.0 (2026-03-18)
Features
- ✅ Wort hinzufügen/löschen/bearbeiten
- ✅ SQLite Persistierung
- ✅ REST API
- ✅ Modern HTML/CSS/JS Frontend
- ✅ Health Checks
- ✅ Fehlerbehandlung
Lizenz & Attribution
Template: Container Spawner Autor: Rainer Wieland Lizenz: MIT oder ähnlich
Letzte Aktualisierung
- Datum: 2026-03-18
- Version: 1.0.0
- Status: Production Ready ✅