# Deployment — SLC-Workshop Companion (App) **Auftrag für die Server-Claude / Ops:** Diese App **statisch** ausliefern. Kein Build-Schritt, keine Secrets, keine Datenbank. > **Neu (v0.10): kleiner Feedback-Endpoint.** Die App sammelt jetzt Workshop-Feedback > (Phasen + Prüfschritte) und **speichert es auf dem Server** zur späteren Auswertung. > Dafür braucht es **einen** schlanken POST-Sammelpunkt (Flat-File, **keine Datenbank**). > Referenz liegt bei: [`feedback.php`](feedback.php). Ist der Endpoint (noch) nicht > aktiv, geht **nichts verloren**: die App hält das Feedback lokal vor (Retry-Queue) > und der Header-Button **„⇩ Feedback"** exportiert es als Backup-Datei. ## Was das ist - Eine **statische Single-Page-PWA**. Alle Inhalte (Stationen, Quiz, Use-Cases) sind in `index.html` eingebettet — keine Laufzeit-API nötig. - Dateien im Ordner `04_Tablet-Quiz/app/`: - `index.html` — die App - `manifest.webmanifest` — PWA-Manifest - `sw.js` — Service Worker (Offline-Cache der App-Shell) - `icon.svg` — App-Icon - `feedback.php` — **optionaler** Feedback-Sammelpunkt (Flat-File, JSON Lines) ## Ziel Den Ordner `04_Tablet-Quiz/app/` als **statisches Web-Root** über den vorhandenen Webserver bereitstellen, erreichbar per **HTTPS** (oder localhost). > **Wichtig:** Der Service Worker (Offline/Installierbar) läuft **nur über HTTPS > oder localhost**. Über reines `http://` ohne TLS registriert er sich nicht — > die App funktioniert dann trotzdem, nur ohne Offline-Cache. ## Schritte 1. Repo auf dem Server bereitstellen/aktualisieren: `git clone https://git.1789.cloud/patrick/SLC_Game.git` (bzw. `git pull`). 2. Den Ordner `SLC_Game/04_Tablet-Quiz/app/` als statisches Root einbinden. ### Beispiel nginx ```nginx server { listen 443 ssl; server_name slc.example.intern; # anpassen # ssl_certificate ... ; ssl_certificate_key ... ; root /srv/SLC_Game/04_Tablet-Quiz/app; # Pfad anpassen index index.html; location = /sw.js { add_header Cache-Control "no-cache"; } # SW immer frisch location / { try_files $uri $uri/ /index.html; } } ``` ### Beispiel Caddy (TLS automatisch) ```caddy slc.example.intern { root * /srv/SLC_Game/04_Tablet-Quiz/app file_server header /sw.js Cache-Control "no-cache" } ``` ## Feedback-Endpoint (empfohlen — für die Auswertung) Die App schickt jedes gespeicherte Feedback per `POST` als JSON an den im `` hinterlegten Pfad (Default: `feedback.php`, gleiche Domain). Der Service Worker fasst POSTs nicht an — der Offline-Cache stört also nicht. **Variante A — PHP (Referenz, einfachste Option).** `feedback.php` liegt im App-Ordner. Voraussetzung: `php-fpm` aktiv und das App-Verzeichnis für PHP freigegeben; das Datenverzeichnis `feedback-data/` muss vom Webserver-User beschreibbar sein. ```nginx # innerhalb des server{}-Blocks von oben: location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php-fpm.sock; # Pfad anpassen fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } ``` Daten landen in `feedback-data/feedback.jsonl` (eine JSON-Zeile pro Feedback) → später für die Auswertung einlesen/zu CSV konvertieren. **Variante B — kein PHP verfügbar.** Endpoint auf einen beliebigen JSON-POST-Empfänger zeigen lassen (z. B. ein kleines Node-/Worker-Skript, das den Body an eine Datei anhängt) und im `` dessen URL eintragen. **Variante C — gar kein Server-Save.** Auch ohne Endpoint funktioniert alles: das Feedback bleibt in der Retry-Queue und kann über den Header-Button **„⇩ Feedback"** als JSON-Datei exportiert werden. ## Verifikation nach dem Deploy 1. URL öffnen → Startbildschirm „SLC Companion". 2. DevTools → Application → **Service Workers**: `sw.js` ist *activated*. 3. Flugmodus/Offline → Seite neu laden → App lädt weiterhin (Offline-Cache). 4. Einen Major-Durchlauf spielen, an einem Gate Feedback eintragen → **„💾 Feedback speichern"**. Bei aktivem Endpoint erscheint kein Fehler in der Konsole; in `feedback-data/feedback.jsonl` taucht eine neue Zeile auf. Ohne Endpoint: Header **„⇩ Feedback"** lädt die Backup-Datei. ## Updates - Bei neuem Stand: `git pull`. Wenn sich App-Assets geändert haben, in `sw.js` die Konstante `CACHE` hochzählen (z. B. `slc-companion-v1` → `-v2`), damit der Service Worker den Cache erneuert. ## Noch offen (nicht Teil dieses Deploys) - **YAML→Inhaltspipeline:** Inhalte sind aktuell in `index.html` eingebettet. Später aus den Blueprint-`service-lifecycle_*.yaml` generieren (braucht Zugriff aufs Blueprint-Repo). Bis dahin werden Inhalte direkt in `index.html` gepflegt. - **Companion-Chatbot** (optionaler Nachschlage-Bot) — siehe `../README.md` §8; *braucht* ein LLM-Backend und ist daher **nicht** Teil der statischen App.