larpaso-website/DEPLOYMENT_ADMIN.md
Pascal Scholz cf8d6a65ea Document correct order when content and admin code change together
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 22:58:32 +02:00

13 KiB
Raw Blame History

DEPLOYMENT_ADMIN.md – Login-Editor für larpaso.de

Ergänzt DEPLOYMENT.md um einen eigenen, öffentlich erreichbaren, aber login-geschützten Editor unter https://admin.larpaso.de. Dort können Texte, Bilder, Links, Impressum, Datenschutz sowie Schriftarten/-größen und alle Farben der Seite geändert werden. „Speichern & veröffentlichen" baut die Seite neu und die Änderung ist sofort auf larpaso.de sichtbar – ohne weiteren Server-Zugriff nötig.

Wie in DEPLOYMENT.md: Teil A ist bereits im Repo erledigt (Claude Code) und lokal getestet. Teil B unten führst du selbst per SSH auf dem Server aus – das ist eine vollständige Schritt-für-Schritt-Anleitung zum Copy-Pasten. Claude Code hat zu keinem Zeitpunkt Zugriff auf Benutzername/Passwort/Secrets oder den Server selbst.


Was der Editor kann

  • Texte: alle Überschriften, Absätze, Listen, FAQ, Preis-Punkte, Mappe-Einträge usw. der Startseite – inklusive Impressum und Datenschutzerklärung. Längere Texte haben einen Rich-Text-Editor mit Knöpfen für Fett/Kursiv/Unterstrichen sowie eine Schriftart-Auswahl, mit der einzelne markierte Wörter/Sätze eine eigene Schriftart bekommen können (aus der gleichen kuratierten Liste wie im Design-Tab) – unabhängig von den zwei Grundschriften.
  • Bilder: Logo, Mappe-Screenshots, Team-Foto, plus optional eigene Bilder anstelle der eingebauten Google-Vorschau und des PDF/Tabellen-Vergleichs.
  • Links: Menüpunkte, E-Mail-Adresse, Kontakt-Angaben.
  • Design: Schriftart für Überschriften/Fließtext (Auswahl aus gängigen Google Fonts oder Systemschrift), Schriftgrößen (7 Stufen, per Schieberegler), und alle Farben der Seite einzeln über Hex-Feld, RGB-Schieberegler und Transparenz-Regler.
  • Übersicht: die Oberfläche ist in Reiter/Tabs gegliedert (linke Seitenleiste, gruppiert in „Inhalte" und „Design") statt einer langen durchgehenden Seite.

Was sich technisch ändert

  • Neuer Dienst admin (Node/Express, admin/) mit Login, Bearbeitungsoberfläche und einem „Veröffentlichen"-Knopf, der intern npm run build ausführt.
  • Der bestehende website-Dienst (nginx) serviert nicht mehr aus dem Image gebackene Dateien, sondern aus einem gemeinsamen Volume (site-dist), das der admin-Dienst nach jedem „Veröffentlichen" neu befüllt. Kein Neustart von website nötig.
  • Bearbeitete Inhalte (content/site.json, content/theme.json) und hochgeladene Bilder (public/uploads/) liegen auf eigenen Volumes, damit sie ein Image-Update überleben.
  • Login: ein oder mehrere feste Benutzername/Passwort-Paare (bcrypt-Hash), Session-Cookie (12h, httpOnly, Secure, SameSite=Strict), Rate-Limit (5 Fehlversuche → 15 Min. Sperre pro IP).

TEIL A – im Repo (bereits erledigt)

  • admin/ – Editor-Backend + -Oberfläche (Login, Formulare, Bild-Upload, Farb-/Font-/ Größen-Editor, Build-Trigger).
  • content/site.json, content/theme.json – alle editierbaren Inhalte bzw. Design-Werte.
  • Dockerfile.admin – Image für den admin-Dienst.
  • Dockerfile (angepasst) – website seedet ein leeres site-dist-Volume beim ersten Start aus dem gebackenen Build, statt Dateien fest einzubacken.
  • docker-entrypoint-seed.sh, docker-entrypoint-admin-seed.sh – Seed-Skripte für die Volumes.
  • Lokal geprüft: npm run build läuft fehlerfrei; Login, Rate-Limit-Sperre, Speichern (Texte, Bilder, Impressum/Datenschutz, Farben, Schriftarten, Schriftgrößen), Bild-Upload und Veröffentlichen wurden lokal gegen den Admin-Server End-to-End getestet.

TEIL B – Schritt für Schritt per SSH (machst du)

Alles unten in dieser Reihenfolge ausführen. Wo <...> steht, durch echte Werte ersetzen.

B0. Voraussetzung: Code muss auf dem Server ankommen können

Damit git pull in B1 etwas findet, muss dieser Stand vorher nach git.larpaso.de/pascal/larpaso-website gepusht sein. Frag im Chat nach, ob das schon passiert ist, falls du direkt startest.

B1. Repo aktualisieren

ssh deploy@<server>
cd ~/sites/larpaso-website
git pull

B2. Platzhalter für ~/stack/admin.env anlegen (NICHT ins Git-Repo!)

Erstmal nur eine leere Datei, damit Docker Compose in B3/B5 nicht meckert, dass sie fehlt. Die echten Werte kommen in B6 rein.

touch ~/stack/admin.env
chmod 600 ~/stack/admin.env

B3. Dienste in ~/stack/docker-compose.yml ergänzen

nano ~/stack/docker-compose.yml

Beim bestehenden website-Dienst ein volumes: ergänzen:

  website:
    build:
      context: /home/deploy/sites/larpaso-website
    restart: unless-stopped
    networks: [web]
    volumes:
      - site-dist:/usr/share/nginx/html

Neuen admin-Dienst unter services: ergänzen:

  admin:
    build:
      context: /home/deploy/sites/larpaso-website
      dockerfile: Dockerfile.admin
    restart: unless-stopped
    networks: [web]
    env_file:
      - /home/deploy/stack/admin.env
    volumes:
      - site-dist:/site-dist
      - admin-content:/app/content
      - admin-uploads:/app/public/uploads

(Kein ports: bei beiden Diensten – Caddy erreicht sie intern über den Container-Namen.)

Im bestehenden obersten volumes:-Block der Datei ergänzen (nicht neu anlegen):

volumes:
  site-dist:
  admin-content:
  admin-uploads:

B4. Caddy-Block ergänzen

nano ~/stack/caddy/Caddyfile

Hinzufügen:

admin.larpaso.de {
    reverse_proxy admin:4321
}

B5. Admin-Image bauen

cd ~/stack
docker compose build admin

Das baut das Image für den Login-Editor – inklusive eines sauberen npm ci für die Admin-Abhängigkeiten (bcryptjs, Express usw.), im selben zuverlässigen Schritt, der auch gleich für den Live-Betrieb verwendet wird.

B6. Login-Zugangsdaten erzeugen

Jetzt mit dem gerade gebauten Image statt einem Wegwerf-Container – robuster als ein Ad-hoc-npm install (das kann mit dem bekannten npm-Fehler „Tracker 'idealTree' already exists" fehlschlagen):

docker compose run --rm admin node admin/hash-password.js "dein-neues-passwort" | sed 's/\$/$$/g'

Gibt einen bcrypt-Hash aus, bei dem jedes $ bereits verdoppelt ist ($$2a$$12$$...) – genau so, mit den doppelten $, in B7 einfügen. Docker Compose interpretiert einzelne $ in env_file-Werten nämlich selbst als Variablen (siehe Warnung weiter unten, falls das schiefgeht) – $$ ist Compose' eigene Escape-Regel dafür, kein Tippfehler.

Zufälliges Session-Secret erzeugen (rein hexadezimal, kein $ enthalten, keine Verdopplung nötig):

docker compose run --rm admin node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Auch kopieren.

Optional – zweiten Benutzer anlegen (z. B. für Lara): denselben Hash-Befehl nochmal mit ihrem Passwort ausführen und den (verdoppelten) Hash ebenfalls kopieren. Ein Session-Secret reicht für alle Benutzer, das muss nicht nochmal erzeugt werden.

docker compose run --rm admin node admin/hash-password.js "ihr-neues-passwort" | sed 's/\$/$$/g'

B7. ~/stack/admin.env mit echten Werten befüllen

Am einfachsten mit nano (kein Heredoc nötig):

nano ~/stack/admin.env

Inhalt (Beispiel – deine Werte aus B6 einsetzen, die Hashes mit den doppelten $ genau so wie von sed ausgegeben, nicht die ursprüngliche, unverdoppelte Variante):

NODE_ENV=production
ADMIN_USERNAME=pascal
ADMIN_PASSWORD_HASH=$$2a$$12$$dein.eigentlicher.hash.hier
SESSION_SECRET=dein-hex-string-hier

Nur falls du einen zweiten Benutzer angelegt hast, zwei weitere Zeilen ergänzen (Muster lässt sich mit _3, _4, ... beliebig fortsetzen):

ADMIN_USERNAME_2=lara
ADMIN_PASSWORD_HASH_2=$$2a$$12$$laras.hash.hier

Speichern: Strg+O, Enter, Strg+X. Danach:

chmod 600 ~/stack/admin.env

Kontrolle (jeder Hash muss inklusive der verdoppelten $ 63 Zeichen lang sein – 60 für den eigentlichen bcrypt-Hash + 3 zusätzliche $):

grep HASH ~/stack/admin.env | awk -F= '{print $1": "length($2)" Zeichen"}'

B8. DNS bei IONOS

  • Neuer A-Eintrag: Hostname admin → Server-IPv4 (gleiche IP wie @).
  • Kurz warten/prüfen: nslookup admin.larpaso.de muss die Server-IP liefern, bevor B9 läuft (sonst bekommt Caddy kein Zertifikat).

B9. Bauen & starten

cd ~/stack
docker compose build website
docker compose up -d website admin
docker compose restart caddy
docker compose logs -f caddy   # auf "certificate obtained successfully" für admin.larpaso.de warten, dann Strg+C

(admin wurde schon in B5 gebaut – falls du seitdem nochmal git pull gemacht hast, einmal docker compose build admin vorweg wiederholen.)

B10. Prüfen

  1. https://admin.larpaso.de/admin/login öffnen, mit den Zugangsdaten aus B6/B7 anmelden.
  2. Eine Kleinigkeit ändern (z. B. Telefonnummer im Abschnitt „Kontakt" oder eine Farbe im Abschnitt „Design – Farben"), Speichern & veröffentlichen klicken.
  3. Build-Ausgabe sollte mit „Complete!" enden.
  4. https://larpaso.de neu laden (ggf. Hard-Reload / Cache leeren) – Änderung sollte sofort da sein.

Fertig. Ab jetzt kannst du alle Texte, Bilder, Links und das Design selbst über admin.larpaso.de pflegen, ohne mich oder SSH zu brauchen.


Künftige Updates am Code (Admin-Backend selbst)

Ändert sich admin/ oder das Editor-Frontend am Code (nicht über die Editor-Oberfläche, sondern durch mich im Chat), reicht danach:

cd ~/sites/larpaso-website && git pull
cd ~/stack && docker compose build admin && docker compose up -d admin

content/site.json, content/theme.json und hochgeladene Bilder bleiben unangetastet (liegen auf eigenen Volumes, nicht im Image).

Content-Updates über Git/Claude Code, ohne den Editor zu überschreiben

Seit es den Editor gibt, liegt der echte Live-Inhalt (content/site.json, content/theme.json) auf eigenen Volumes auf dem Server, nicht mehr im Git-Image – ein einfaches git pull + docker compose build website ändert an den Live-Inhalten deshalb nichts mehr (das Seed-Skript befüllt die Volumes nur einmalig, wenn sie leer sind).

Damit Claude Code trotzdem Content-Änderungen pushen kann, ohne Änderungen zu überschreiben, die zwischenzeitlich über den Editor gemacht wurden, gibt es zwei Skripte im Repo (auf dem Server, aus ~/stack ausführen):

  1. Vor einer Content-Änderung durch Claude Code: aktuellen Live-Stand nach Git holen (nur nötig, falls seit dem letzten Mal über den Editor was geändert wurde – bei keiner Änderung passiert nichts):
    cd ~/stack
    ~/sites/larpaso-website/sync-content-from-live.sh
    
  2. Im Chat mit Claude Code die gewünschte Änderung beschreiben – Claude Code ändert content/site.json/theme.json lokal auf Basis des gerade synchronisierten Stands, testet den Build und pusht nach main.
  3. Nach dem Push: Git-Stand auf den Server holen und live veröffentlichen (baut über denselben Weg wie „Speichern & veröffentlichen" im Editor, ohne den website- oder admin-Dienst neu zu bauen):
    cd ~/sites/larpaso-website && git pull
    cd ~/stack
    ./sync-content-from-live.sh   # kann man sich sparen, falls Schritt 1 schon frisch war
    ~/sites/larpaso-website/publish-content-to-live.sh
    

Wichtig: Das gilt nur für content/site.json/theme.json (Texte, Bilder-Referenzen, Design-Werte). Änderungen am Code selbst (admin/, src/) laufen weiterhin über den normalen Weg (docker compose build website/admin + up -d, siehe oben).

Ändert sich in einem Push beides gleichzeitig (Content und Code, z. B. neue Felder in content/site.json plus die passende Template-Änderung in src/) – unbedingt in dieser Reihenfolge, sonst baut publish-content-to-live.sh mit dem alten Template und die Content-Änderung scheint wirkungslos:

cd ~/sites/larpaso-website && git pull
cd ~/stack
docker compose build admin && docker compose up -d admin   # zuerst: neuer Code im Container
~/sites/larpaso-website/publish-content-to-live.sh          # danach erst: baut/veröffentlicht mit dem neuen Code

Bekannte Grenzen

  • Mehrere feste Logins möglich (ADMIN_USERNAME/ADMIN_PASSWORD_HASH, _2, _3, ...), aber kein echtes Mehrbenutzer-System – alle Logins haben dieselben Rechte, es gibt keine Rollen und keine Passwort-Reset-Funktion in der Oberfläche. Neues/geändertes Passwort: docker compose run --rm admin node admin/hash-password.js "..." ausführen (wie B6), Hash in admin.env eintragen, dann docker compose up -d admin.
  • Sessions sind In-Memory: Ein Neustart des admin-Containers meldet alle ab.
  • Es gibt keine Versionshistorie der Inhalte oder des Designs – beides liegt aber auf dem Server und kann bei Bedarf manuell gesichert werden (z. B. regelmäßiges Backup der Volumes admin-content und admin-uploads einplanen, wie für die anderen Volumes auch).
  • Schriftarten sind auf eine kuratierte Liste gängiger Google Fonts + Systemschrift begrenzt (keine eigenen Font-Dateien hochladbar) – bei Bedarf im Chat erweiterbar.