Spec: Preview 2.0 mit Preview-Runner, Modi und Variablen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
edef85c7b3
commit
651745eccc
1 file changed
+135
@@ -0,0 +1,135 @@
|
||||
# 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 <sha7>)“ · 🟡 „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.
|
||||
Reference in new issue
Block a user