spawner/docs/templates/DICTIONARY_TEMPLATE.md

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 Image
  • requirements.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/Definition
  • created_at - Erstellungsdatum
  • updated_at - Letztes Update

Constraints:

  • word ist 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:

  1. PostgreSQL verwenden statt SQLite (für Multi-User)
  2. Redis Caching für häufige Abfragen
  3. Elasticsearch für Full-Text Suche in Bedeutungen

🔒 Sicherheit & Authentifizierung

Das Dictionary-Template ist obligatorisch geschützt mit JWT-Token-Validierung:

  1. HttpOnly Cookie spawner_token wird vom Spawner gesetzt
  2. Vor jedem API-Request wird der Token validiert
  3. 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:

  1. Spawner erstellt Container mit Template user-template-dictionary:latest
  2. Mountet Volume: /volumes/{user-id}:/data
  3. Traefik routet Request zu Container unter https://coder.domain.com/{user-slug}
  4. Benutzer sieht Wörterbuch-Interface
  5. Datenbank wird in /volumes/{user-id}/app.db erstellt
  6. 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

  1. Kategorien - Wörter in Kategorien organisieren
  2. Export/Import - CSV/JSON Download
  3. Suche - Volltext-Suche in Wörtern/Bedeutungen
  4. Tags - Flexible Kategorisierung
  5. Statistiken - Graphen, Lernfortschritt
  6. Multi-Language - Übersetzungen hinzufügen
  7. Phonetik - Audio-Aussprache
  8. 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:

  1. Logs prüfen: docker logs container-id
  2. Health Check testen: curl http://localhost:8080/health
  3. Datenbank prüfen: sqlite3 /data/app.db ".tables"
  4. 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