Files
Webklar-Kundenbereich/docs/superpowers/specs/2026-09-30-preview-runner-design.md
T
2026-09-30 21:53:41 +00:00

9.8 KiB
Raw Blame History

Preview 2.0 – Preview-Runner, Modi, Variablen – Design

Stand: 2026-09-30 · Status: vom Nutzer im Chat freigegeben (Abschnitte 1–3), Spec zur Durchsicht Teilprojekt 2 von 3 (1 Projektarten – live seit 2026-09-30; 3 Website-Analyse – eigene Spec). Regel des Nutzers: bauen → live → Nutzer testet live → erst dann das nächste Teilprojekt. Recherche: /root/reports/analyse-funktion-2026-09-30/projekttypen-preview.md.

Ziel

Previews starten automatisch, auch für vibe-gecodete Projekte, die man mit npm run dev startet. Builds laufen nicht mehr im Portal-Container (der Appwrite-, Gitea-, SMTP- und Stripe-Zugangsdaten hat), sondern in Wegwerf-Containern ohne Zugangsdaten. Projekte können Preview-Variablen bekommen, ohne dass eine .env im Repo liegt.

Entscheidungen (vom Nutzer)

# Entscheidung
V1 Modus pro Projekt: auto (Vorauswahl) · build · dev · off. auto = erst statisch/Build, Dev-Server nur als Ausweg.
V2 Neuer Dienst Preview-Runner als eigener Container (Variante A). Nur er darf Docker-Container starten.
V3 Preview-Variablen pro Projekt im WOMS, verschlüsselt gespeichert, nur an Build/Dev dieses Projekts.
V4 Build-Fehler ⇒ letzte funktionierende Version bleibt online (keine Platzhalterseite mehr).
V5 Dev-Server starten beim ersten Aufruf, stoppen nach 20 min ohne Aufruf, max. 3 gleichzeitig.
V6 Kundenportal unverändert (außer der Seite „Preview startet …“ bei schlafendem Dev-Server).

1. Aufbau

Gitea-Push ──▶ Portal (webhook) ──Auftrag──▶ Preview-Runner ──▶ Docker
                  │                            │                ├─ Build-Container (Wegwerf)
                  │                            │                └─ Dev-Container (bei Bedarf)
                  │                            ▼
                  │                  /var/www/previews/<sub>  (fertige Dateien)
                  ▼
     Traefik: <sub>.project.webklar.com ──preview-chain──▶ preview-nginx  (static/build)
                                                     └────▶ Runner-Proxy   (dev)

1.1 Portal (bleibt Chef)

  • Neue Attribute an websiteProjects (Schema-Skript scripts/preview-runner-setup.mjs, idempotent, Attributliste mit limit 200 lesen): previewMode (string 10: auto|build|dev|off; leer = auto), previewEnv (string 20000, verschlüsselt), previewState (string 20: online|building|failed|sleeping|starting|off), previewDetected (string 40, z. B. build:vite:npm, static, dev:npm), previewBuiltSha (string 40), previewBuiltAt (ISO), previewError (string 500).
  • Vorauswahl des Modus bei neuer Zuordnung aus dem Projektarten-Katalog (projectKinds.js): Art website/webapp ⇒ auto, alle anderen ⇒ off. Bestehende Projekte ohne Wert gelten als auto.
  • server/services/previewDeploy.js bekommt einen Schalter config.previewRunner.enabled (PREVIEW_RUNNER=on|off, Vorgabe off). off = bisheriger Weg unverändert. on = Aufträge an den Runner.
  • syncPreviewTls() schreibt für Projekte im Modus dev (oder auto mit Ergebnis dev) den Router auf den Service preview-runner@docker statt preview-nginx@docker; Middleware preview-chain bleibt gleich (öffentliche Subdomains wie heute ohne Middleware).
  • Verschlüsselung server/services/previewEnv.js: AES-256-GCM, Schlüssel PREVIEW_ENV_KEY (32 Byte base64) aus /home/webklar/apps/.env; Format v1:<iv>:<tag>:<ciphertext> (base64). Namen ^[A-Z_][A-Z0-9_]*$, max. 30 Variablen, Wert max. 4096 Byte. Ohne Schlüssel ⇒ Variablen-Funktion aus, Fehlermeldung im WOMS.
  • Protokolle: upload-data/preview-logs/<projektId>/<zeitstempel>.log, letzte 300 Zeilen je Lauf, die letzten 5 Läufe je Projekt, ältere löschen. Variablenwerte (≥ 4 Zeichen) werden vor dem Speichern durch ••• ersetzt.
  • Admin-API (requireAppwriteStaff): GET /api/admin/website-projects/:id/preview (Modus, Status, erkannt, Namen der Variablen, Protokoll-Liste), PATCH …/preview { mode }, PUT …/preview/env { set: {NAME: wert}, remove: [NAME] }, POST …/preview/rebuild, POST …/preview/dev/start|stop, GET …/preview/logs/:runId. Änderung von Variablen oder Modus ⇒ automatisch Neubau bzw. Dev-Neustart.

1.2 Preview-Runner (neuer Container webklar-preview-runner)

  • Code im Portal-Repo unter runner/ (eigenes package.json, Node 20, keine Abhängigkeit zum Portal-Code). Compose-Dienst in /home/webklar/apps/docker-compose.yml, Image node:20-alpine + Docker-CLI, Mount build/runner (read-only), /var/run/docker.sock, /var/www/previews, Cache-Volume. deploy.sh startet den Runner neu, wenn sich runner/ geändert hat.
  • Netze: webklar-network (für Portal und Traefik) und preview-sandbox (Dev-Container). Kein veröffentlichter Port.
  • Umgebung: nur PREVIEW_RUNNER_TOKEN, GITEA_DEPLOY_TOKEN (read:repository), Gitea-URL, Limits. Keine Appwrite-/SMTP-/Stripe-Zugangsdaten.
  • HTTP-API (Bearer PREVIEW_RUNNER_TOKEN, Port 8080 nur intern): POST /jobs/build { projectId, repoFullName, branch, sha, subdomain, mode, env, index } ⇒ { runId }; GET /jobs/:runId ⇒ { state, detected, sha, log, error }; POST /dev/:subdomain/start|stop; GET /status (laufende Dev-Server, Warteschlange, freier Speicher). Nur diese festen Aufträge – keine freien Docker-Befehle.
  • Erkennung (auto): index.html im Wurzelverzeichnis (oder index aus .webklar-preview.json) und kein build-Skript ⇒ static; sonst build-Skript vorhanden ⇒ Build; Build fehlgeschlagen oder kein Build-Skript, aber dev-Skript ⇒ dev; sonst static mit Hinweis. Paketmanager aus Lock-Datei: pnpm-lock.yaml ⇒ pnpm, yarn.lock ⇒ yarn, bun.lockb/bun.lock ⇒ bun, sonst npm (npm ci, ohne Lock npm install). Ausgabeordner: dist, build, out, web-build (wie heute) bzw. aus .webklar-preview.json (output).
  • Build-Container: node:20 (bun: oven/bun), --memory 1g --cpus 1 --pids-limit 512 --cap-drop ALL --security-opt no-new-privileges --user 1000:1000 --network preview-sandbox, Zeitlimit 15 min, genau einer gleichzeitig (Warteschlange). Quelle per git clone --depth 1 mit Deploy-Token in ein Arbeitsverzeichnis; Cache node_modules je Repo (Volume, max. 5 GB gesamt, Einträge > 14 Tage löschen). Erfolg ⇒ Ausgabe atomar nach /var/www/previews/<sub> (in <sub>.new kopieren, dann umbenennen). Fehler ⇒ vorhandener Ordner bleibt.
  • Dev-Container: gleiches Sicherheitsprofil, --memory 512m, Name preview-dev-<sub>, nur im Netz preview-sandbox. Start npm run dev -- --host 0.0.0.0 --port 5173 (bzw. passender Paketmanager; Port aus .webklar-preview.json devPort überschreibbar); Vite bekommt __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=.project.webklar.com. Bereit, sobald der Port antwortet (max. 180 s). Leerlauf 20 min ⇒ stoppen (Container entfernen, Cache bleibt). Max. 3; beim 4. weicht der am längsten ungenutzte. Neuer Push ⇒ Code aktualisieren und neu starten.
  • Runner-Proxy (Port 8081, Traefik-Service preview-runner): leitet Host: <sub>.project.webklar.com inkl. WebSocket (Hot-Reload) an preview-dev-<sub>:<port> weiter; läuft keiner ⇒ Start anstoßen und Seite „Preview startet …“ (deutsch, Neuladen alle 3 s, nach 180 s Fehlermeldung „Preview konnte nicht starten“).
  • Schutzschalter: freier Speicher (/proc/meminfo MemAvailable des Hosts) < 1,5 GB ⇒ keine neuen Builds oder Dev-Starts; Antwort 503 { error: 'Server ausgelastet' }, Build bleibt in der Warteschlange.

2. WOMS

Block „Preview“ auf der Projektkarte im Ticket (TicketProjects/AssignedProjectCard) und im „Bearbeiten“-Dialog unter Projekte:

  1. Modus: Automatisch · Build · Dev-Server · Aus; darunter „Automatisch → Build (Vite, npm)“ o. ä. aus previewDetected.
  2. Status: 🟢 „Online seit TT.MM. HH:MM (Build )“ · 🟡 „Baut gerade …“ / „Dev-Server schläft, startet beim nächsten Aufruf“ · 🔴 „Build fehlgeschlagen – letzte funktionierende Version ist online“. Knöpfe: Neu bauen · Protokoll ansehen · bei Dev: Jetzt starten / Stoppen.
  3. Protokoll: letzte 300 Zeilen, aufklappbar, letzte 5 Läufe wählbar.
  4. Preview-Variablen: Tabelle Name/Wert, Werte nach dem Speichern nur •••; Hinweis „Alles mit VITE_ / NEXT_PUBLIC_ ist im Browser sichtbar“.
  5. Services-Seite: Preview-Punkt (grün/gelb/rot/grau) je Projektzeile.

3. Sicherheit, Speicher, Tests, Livegang

Sicherheit und Grenzen wie in Abschnitt 1.2. Zusätzlich: Runner-Eingaben streng prüfen (Subdomain ^[a-z0-9-]{1,63}$, Repo ^[\w.-]+/[\w.-]+$, sha ^[0-9a-f]{7,40}$), Pfade nur unterhalb der festen Wurzeln.

Tests: Runner-Unit-Tests mit Schein-Docker (Auftragsprüfung, Warteschlange, Erkennung, Leerlauf-Stopp, Verdrängung, Schutzschalter, Proxy inkl. Startseite); Portal (Verschlüsselung, Maskierung, Modus-Vorgaben, TLS-Router für dev, Schalter off = altes Verhalten); WOMS (Preview-Block-Logik, Playwright gegen Fixtures); echter Durchlauf auf dem Server mit drei Beispiel-Repos (HTML, Vite-Build, nur dev).

Livegang (jeder Schritt mit OK des Nutzers): L1 Netz preview-sandbox, Schlüssel PREVIEW_RUNNER_TOKEN + PREVIEW_ENV_KEY in .env, Runner-Dienst in Compose, Schema-Skript · L2 Portal pushen mit PREVIEW_RUNNER=off · L3 Schalter on, 12 Previews einzeln neu bauen und vorher/nachher vergleichen · L4 WOMS pushen · L5 Live-Test des Nutzers mit Dev-Modus. Rückweg jederzeit: PREVIEW_RUNNER=off + Portal neu starten.

Nicht Teil dieser Spec

Datenbanken/Backends als Beiwagen-Container, Next.js-SSR mit eigenem Start-Modus (start), gemeinsame Standard-Variablen (Variante C), Previews für Handy-Apps (Expo-Web), Website-Analyse (Teilprojekt 3), „Art ändern“ aus Teilprojekt 1.