diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..eff5089 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,226 @@ +# MathQuest Deployment Anleitung + +Diese Anleitung erklärt, wie du MathQuest auf deinem Server deployst. + +## Voraussetzungen + +- Server mit Ubuntu/Debian +- Node.js installiert (Version 14 oder höher) +- Nginx installiert +- SSL-Zertifikat für lydix.de (Let's Encrypt) +- Root-Zugriff oder sudo-Rechte + +## Schritt 1: Dateien auf den Server kopieren + +### Option A: Mit SCP (vom lokalen Rechner) + +```bash +# Vom lokalen Rechner aus: +scp -r /home/lukas/nerd/mathquest/* user@dein-server:/var/www/mathquest/ +``` + +### Option B: Mit Git (wenn du ein Repository hast) + +```bash +# Auf dem Server: +cd /var/www +git clone dein-repo-url mathquest +cd mathquest +``` + +## Schritt 2: Dependencies installieren + +```bash +cd /var/www/mathquest +npm install --production +``` + +## Schritt 3: Berechtigungen setzen + +```bash +chown -R www-data:www-data /var/www/mathquest +chmod +x /var/www/mathquest/server.js +``` + +## Schritt 4: systemd Service installieren + +```bash +# Service-Datei kopieren +sudo cp /var/www/mathquest/mathquest.service /etc/systemd/system/ + +# Service aktivieren und starten +sudo systemctl daemon-reload +sudo systemctl enable mathquest +sudo systemctl start mathquest + +# Status prüfen +sudo systemctl status mathquest +``` + +## Schritt 5: Nginx konfigurieren + +### SSL-Zertifikat prüfen + +Da du einen Wildcard DNS Eintrag hast, sollte ein Wildcard-Zertifikat für `*.lydix.de` existieren. + +Prüfe deine Zertifikate: +```bash +sudo certbot certificates +``` + +Finde den korrekten Pfad (oft `/etc/letsencrypt/live/lydix.de/` oder `/etc/letsencrypt/live/lydix.de-0001/`): +```bash +ls -la /etc/letsencrypt/live/ +``` + +Falls der Pfad anders ist, passe die SSL-Zertifikat-Pfade in `nginx-mathquest.conf` an. + +### Nginx-Konfiguration installieren + +```bash +# Konfiguration kopieren +sudo cp /var/www/mathquest/nginx-mathquest.conf /etc/nginx/sites-available/mathquest.conf + +# Symlink erstellen +sudo ln -s /etc/nginx/sites-available/mathquest.conf /etc/nginx/sites-enabled/ + +# Konfiguration testen +sudo nginx -t + +# Nginx neu laden +sudo systemctl reload nginx +``` + +## Schritt 6: DNS konfigurieren + +Da du einen Wildcard DNS Eintrag hast (`*.lydix.de`), ist kein separater A-Record für `mathquest.lydix.de` nötig. Die Subdomain sollte automatisch funktionieren. + +Falls der Wildcard-Eintrag noch nicht existiert, erstelle einen: +``` +*.lydix.de A deine-server-ip +``` + +## Schritt 7: Firewall prüfen + +Stelle sicher, dass Port 80 und 443 offen sind: + +```bash +# UFW +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Oder iptables +sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT +sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT +``` + +## Automatisches Deployment + +Du kannst auch das bereitgestellte Deployment-Script verwenden: + +```bash +cd /var/www/mathquest +chmod +x deploy.sh +sudo ./deploy.sh +``` + +## Nützliche Befehle + +### Service verwalten + +```bash +# Status prüfen +sudo systemctl status mathquest + +# Logs ansehen +sudo journalctl -u mathquest -f + +# Service neustarten +sudo systemctl restart mathquest + +# Service stoppen +sudo systemctl stop mathquest + +# Service starten +sudo systemctl start mathquest +``` + +### Nginx verwalten + +```bash +# Konfiguration testen +sudo nginx -t + +# Nginx neu laden +sudo systemctl reload nginx + +# Nginx neustarten +sudo systemctl restart nginx + +# Logs ansehen +sudo tail -f /var/log/nginx/mathquest-access.log +sudo tail -f /var/log/nginx/mathquest-error.log +``` + +## Troubleshooting + +### Service startet nicht + +```bash +# Prüfe die Logs +sudo journalctl -u mathquest -n 50 + +# Prüfe ob Port 3000 belegt ist +sudo netstat -tulpn | grep 3000 + +# Prüfe die Berechtigungen +ls -la /var/www/mathquest +``` + +### Nginx gibt 502 Bad Gateway + +```bash +# Prüfe ob der Service läuft +sudo systemctl status mathquest + +# Prüfe die Nginx-Logs +sudo tail -f /var/log/nginx/mathquest-error.log + +# Prüfe ob Node.js auf Port 3000 lauscht +sudo netstat -tulpn | grep 3000 +``` + +### SSL-Zertifikat Probleme + +```bash +# Prüfe Zertifikat +sudo certbot certificates + +# Erneuere Zertifikat falls nötig +sudo certbot renew + +# Prüfe Zertifikat-Pfade in Nginx-Konfiguration +sudo cat /etc/nginx/sites-available/mathquest.conf | grep ssl_certificate +``` + +## Updates durchführen + +1. Dateien auf dem Server aktualisieren +2. Dependencies aktualisieren (falls nötig): + ```bash + cd /var/www/mathquest + npm install --production + ``` +3. Service neustarten: + ```bash + sudo systemctl restart mathquest + ``` + +## Backup + +Wichtig: Backupe regelmäßig die `tasks.json` Datei, da dort alle Antworten gespeichert werden: + +```bash +# Backup erstellen +cp /var/www/mathquest/tasks.json /var/www/mathquest/tasks.json.backup +``` diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..7cba1fc --- /dev/null +++ b/deploy.sh @@ -0,0 +1,103 @@ +#!/bin/bash + +# MathQuest Deployment Script +# Führe dieses Script auf dem Server aus + +set -e + +echo "🚀 MathQuest Deployment Script" +echo "================================" +echo "" + +# Farben für Output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Variablen +APP_DIR="/var/www/mathquest" +SERVICE_NAME="mathquest" +NGINX_CONF="/etc/nginx/sites-available/mathquest.conf" +NGINX_ENABLED="/etc/nginx/sites-enabled/mathquest.conf" + +# Prüfe ob als root ausgeführt +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}❌ Bitte führe dieses Script als root aus (sudo ./deploy.sh)${NC}" + exit 1 +fi + +echo -e "${YELLOW}📦 Schritt 1: Erstelle Verzeichnis...${NC}" +mkdir -p $APP_DIR +echo -e "${GREEN}✅ Verzeichnis erstellt${NC}" + +echo "" +echo -e "${YELLOW}📝 Schritt 2: Kopiere Dateien...${NC}" +echo "Bitte kopiere die Dateien manuell nach $APP_DIR" +echo "Oder verwende: scp -r * user@server:$APP_DIR/" +echo "" +read -p "Drücke Enter, wenn die Dateien kopiert wurden..." + +echo "" +echo -e "${YELLOW}📦 Schritt 3: Installiere Dependencies...${NC}" +cd $APP_DIR +if [ -f "package.json" ]; then + npm install --production + echo -e "${GREEN}✅ Dependencies installiert${NC}" +else + echo -e "${RED}❌ package.json nicht gefunden!${NC}" + exit 1 +fi + +echo "" +echo -e "${YELLOW}🔧 Schritt 4: Setze Berechtigungen...${NC}" +chown -R www-data:www-data $APP_DIR +chmod +x $APP_DIR/server.js +echo -e "${GREEN}✅ Berechtigungen gesetzt${NC}" + +echo "" +echo -e "${YELLOW}⚙️ Schritt 5: Installiere systemd Service...${NC}" +if [ -f "$APP_DIR/mathquest.service" ]; then + cp $APP_DIR/mathquest.service /etc/systemd/system/$SERVICE_NAME.service + systemctl daemon-reload + systemctl enable $SERVICE_NAME + echo -e "${GREEN}✅ Service installiert und aktiviert${NC}" +else + echo -e "${RED}❌ mathquest.service nicht gefunden!${NC}" + exit 1 +fi + +echo "" +echo -e "${YELLOW}🌐 Schritt 6: Konfiguriere Nginx...${NC}" +if [ -f "$APP_DIR/nginx-mathquest.conf" ]; then + cp $APP_DIR/nginx-mathquest.conf $NGINX_CONF + ln -sf $NGINX_CONF $NGINX_ENABLED + nginx -t + if [ $? -eq 0 ]; then + systemctl reload nginx + echo -e "${GREEN}✅ Nginx konfiguriert${NC}" + else + echo -e "${RED}❌ Nginx Konfiguration fehlerhaft!${NC}" + exit 1 + fi +else + echo -e "${RED}❌ nginx-mathquest.conf nicht gefunden!${NC}" + exit 1 +fi + +echo "" +echo -e "${YELLOW}🚀 Schritt 7: Starte Service...${NC}" +systemctl start $SERVICE_NAME +sleep 2 +systemctl status $SERVICE_NAME --no-pager + +echo "" +echo -e "${GREEN}✅ Deployment abgeschlossen!${NC}" +echo "" +echo "Nützliche Befehle:" +echo " Status prüfen: systemctl status $SERVICE_NAME" +echo " Logs ansehen: journalctl -u $SERVICE_NAME -f" +echo " Neustarten: systemctl restart $SERVICE_NAME" +echo " Stoppen: systemctl stop $SERVICE_NAME" +echo "" +echo "Die App sollte jetzt unter https://mathquest.lydix.de erreichbar sein!" diff --git a/mathquest.service b/mathquest.service new file mode 100644 index 0000000..8b7cc8d --- /dev/null +++ b/mathquest.service @@ -0,0 +1,18 @@ +[Unit] +Description=MathQuest - Mathe-Lernseite für Kinder +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/var/www/mathquest +ExecStart=/usr/bin/node /var/www/mathquest/server.js +Restart=always +RestartSec=10 +StandardOutput=journal +StandardError=journal +Environment=NODE_ENV=production +Environment=PORT=3000 + +[Install] +WantedBy=multi-user.target diff --git a/nginx-mathquest.conf b/nginx-mathquest.conf new file mode 100644 index 0000000..3bd5ce0 --- /dev/null +++ b/nginx-mathquest.conf @@ -0,0 +1,22 @@ +server { + listen 80; + server_name mathquest.lydix.de; + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + server_name mathquest.lydix.de; + ssl_certificate /etc/letsencrypt/live/mathquest.lydix.de/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/mathquest.lydix.de/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + } +} diff --git a/public/app.js b/public/app.js index f387c43..683a453 100644 --- a/public/app.js +++ b/public/app.js @@ -4,11 +4,15 @@ const API_BASE = ''; // Globale Variablen let totalPoints = 0; let tasks = []; +let chapters = []; +let activeChapter = null; // Initialisiere die App async function init() { await loadTasks(); + extractChapters(); calculateTotalPoints(); + renderTabs(); renderTasks(); updateProgress(); } @@ -33,17 +37,79 @@ async function loadTasks() { } } +// Extrahiere alle Chapters aus den Tasks +function extractChapters() { + const chapterSet = new Set(); + tasks.forEach(task => { + if (task.chapter) { + chapterSet.add(task.chapter); + } + }); + chapters = Array.from(chapterSet).sort(); + + // Setze ersten Chapter als aktiv, falls vorhanden + if (chapters.length > 0 && !activeChapter) { + activeChapter = chapters[0]; + } else if (chapters.length === 0) { + // Wenn keine Chapters vorhanden, zeige alle Tasks + activeChapter = null; + } +} + +// Rendere Tabs für alle Chapters +function renderTabs() { + const tabsContainer = document.getElementById('tabsContainer'); + tabsContainer.innerHTML = ''; + + // Zeige Tabs nur an, wenn es Chapters gibt + if (chapters.length === 0) { + tabsContainer.style.display = 'none'; + return; + } + + tabsContainer.style.display = 'flex'; + + chapters.forEach(chapter => { + const tabButton = document.createElement('button'); + tabButton.className = `tab-button ${activeChapter === chapter ? 'active' : ''}`; + tabButton.textContent = chapter; + tabButton.onclick = () => switchChapter(chapter); + tabsContainer.appendChild(tabButton); + }); +} + +// Wechsle zu einem anderen Chapter +function switchChapter(chapter) { + activeChapter = chapter; + renderTabs(); + renderTasks(); +} + +// Hole Tasks für das aktive Chapter +function getTasksForActiveChapter() { + if (!activeChapter) { + return tasks; + } + return tasks.filter(task => task.chapter === activeChapter); +} + // Rendere Aufgaben function renderTasks() { const container = document.getElementById('taskContainer'); container.innerHTML = ''; - tasks.forEach(task => { + const tasksToShow = getTasksForActiveChapter(); + + tasksToShow.forEach(task => { + // Überspringe bereits richtig beantwortete Aufgaben (werden nicht mehr angezeigt) + if (task.isCorrect === true) { + return; + } + const taskCard = document.createElement('div'); taskCard.className = 'task-card'; taskCard.id = `task-${task.id}`; - const isCompleted = task.isCorrect === true; const hasAnswer = task.userAnswer !== undefined; taskCard.innerHTML = ` @@ -59,25 +125,20 @@ function renderTasks() { id="input-${task.id}" placeholder="?" value="${hasAnswer ? task.userAnswer : ''}" - ${isCompleted ? 'disabled' : ''} >