9.8 KiB
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-Skriptscripts/preview-runner-setup.mjs, idempotent, Attributliste mitlimit 200lesen):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 alsauto. server/services/previewDeploy.jsbekommt einen Schalterconfig.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 (oderautomit Ergebnis dev) den Router auf den Servicepreview-runner@dockerstattpreview-nginx@docker; Middlewarepreview-chainbleibt gleich (öffentliche Subdomains wie heute ohne Middleware).- Verschlüsselung
server/services/previewEnv.js: AES-256-GCM, SchlüsselPREVIEW_ENV_KEY(32 Byte base64) aus/home/webklar/apps/.env; Formatv1:<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/(eigenespackage.json, Node 20, keine Abhängigkeit zum Portal-Code). Compose-Dienst in/home/webklar/apps/docker-compose.yml, Imagenode:20-alpine+ Docker-CLI, Mountbuild/runner(read-only),/var/run/docker.sock,/var/www/previews, Cache-Volume.deploy.shstartet den Runner neu, wenn sichrunner/geändert hat. - Netze:
webklar-network(für Portal und Traefik) undpreview-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.htmlim Wurzelverzeichnis (oderindexaus.webklar-preview.json) und keinbuild-Skript ⇒static; sonstbuild-Skript vorhanden ⇒ Build; Build fehlgeschlagen oder kein Build-Skript, aberdev-Skript ⇒dev; sonststaticmit Hinweis. Paketmanager aus Lock-Datei:pnpm-lock.yaml⇒ pnpm,yarn.lock⇒ yarn,bun.lockb/bun.lock⇒ bun, sonst npm (npm ci, ohne Locknpm 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 pergit clone --depth 1mit Deploy-Token in ein Arbeitsverzeichnis; Cachenode_modulesje Repo (Volume, max. 5 GB gesamt, Einträge > 14 Tage löschen). Erfolg ⇒ Ausgabe atomar nach/var/www/previews/<sub>(in<sub>.newkopieren, dann umbenennen). Fehler ⇒ vorhandener Ordner bleibt. - Dev-Container: gleiches Sicherheitsprofil,
--memory 512m, Namepreview-dev-<sub>, nur im Netzpreview-sandbox. Startnpm run dev -- --host 0.0.0.0 --port 5173(bzw. passender Paketmanager; Port aus.webklar-preview.jsondevPortü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): leitetHost: <sub>.project.webklar.cominkl. WebSocket (Hot-Reload) anpreview-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/meminfoMemAvailable des Hosts) < 1,5 GB ⇒ keine neuen Builds oder Dev-Starts; Antwort503 { 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:
- Modus: Automatisch · Build · Dev-Server · Aus; darunter „Automatisch → Build (Vite, npm)“ o. ä. aus
previewDetected. - 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.
- Protokoll: letzte 300 Zeilen, aufklappbar, letzte 5 Läufe wählbar.
- Preview-Variablen: Tabelle Name/Wert, Werte nach dem Speichern nur
•••; Hinweis „Alles mitVITE_/NEXT_PUBLIC_ist im Browser sichtbar“. - 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.