# DOGFATHER UNIVERSE — Go-Live-Anleitung ## ⚠️ ZUERST LESEN: Die echte Seite läuft auf dem NETCUP-SERVER, nicht auf Cloudflare Seit dem öffentlichen Start (21.08.2026) wird `dogfather-universe.com` vom **eigenen Netcup-Server** ausgeliefert. Der alte Cloudflare-Worker existiert zwar noch und lässt sich auch weiterhin deployen — **er erreicht die echte Domain aber nicht mehr.** Das ist die gefährlichste Stelle im ganzen Projekt: `npx wrangler deploy` läuft ohne Fehler durch und meldet „Deployed", die Änderung ist danach auf `…workers.dev` sichtbar — und auf `dogfather-universe.com` passiert **nichts**. Genau so ist es am 22.08.2026 beim Sprachfenster- Fix passiert (siehe unten). Wer nur die Erfolgsmeldung von Wrangler liest, meldet „ist live", obwohl Filipe auf dem Handy weiterhin den kaputten Stand sieht. | Adresse | Läuft wo | Wird von wo beliefert | |---|---|---| | **`dogfather-universe.com`** ← **die echte Seite** | **Netcup**, Caddy → `localhost:4100`, systemd-Dienst `dogiweb.service`, Verzeichnis `/home/dogiweb/dogfather-universe/` | Gitea `git.dogfather-universe.com/DogFatherGit/dogfather-universe`, Zweig `main` | | `www.dogfather-universe.com` | dasselbe (Caddy nimmt beide Namen) | dasselbe | | `dogfather-universe.dogfather1608.workers.dev` | Cloudflare Worker (Altbestand) | `npx wrangler deploy` | Erkennungsmerkmal im Zweifel: `curl -sI https://dogfather-universe.com/ | grep -i via` → zeigt `via: 1.1 Caddy`, also Netcup. Käme die Seite von Cloudflare, stünde da kein Caddy. ## So wird eine Änderung wirklich live (der einzige gültige Weg) ```bash cd ~/Documents/Obelix/DogiHompage # 1. Änderung committen git add && git commit # 2. In die Ablage schieben (Gitea ist die Quelle der Wahrheit) git push gitea master:main # 3. Auf dem Server holen ssh dogfather-server "cd /home/dogiweb/dogfather-universe && git pull --ff-only origin main" ``` Statische Dateien (HTML/CSS/JS/Bilder) sind damit **sofort** live — der Express-Dienst liefert das Verzeichnis direkt aus, ein Neustart ist dafür **nicht** nötig. ## ⚠️ ES GIBT ZWEI CHECKOUTS AUF DEM SERVER, NICHT EINEN Am 22.08.2026 beim Ausrollen des Webdesign-Bereichs gefunden — diese Datei beschrieb vorher nur den ersten und war damit unvollständig: | Dienst | Checkout | Liefert | |---|---|---| | `dogiweb.service` (Port 4100) | `/home/dogiweb/dogfather-universe/` | die öffentliche Website + `server/` | | `dogiintern.service` (Port 4200) | `/home/dogiintern/dogfather-universe/` | die API unter `postfach.dogfather-universe.com` + `server-internal/` | **Ein `git pull` in `/home/dogiweb` ändert an `server-internal/` also gar nichts.** Wer nur dort zieht und danach `dogiintern.service` neu startet, startet den Dienst mit unverändertem Code neu und wundert sich, warum nichts passiert. `claudian` hat auf `/home/dogiintern/` **keinen Zugriff** (weder lesend noch über den begrenzten sudo). Änderungen an `server-internal/` muss deshalb Filipe selbst ausrollen: ```bash sudo -u dogiintern git -C /home/dogiintern/dogfather-universe pull --ff-only origin main sudo systemctl restart dogiintern.service ``` ## Server-Code geändert? Dann ist ein Neustart PFLICHT Statische Dateien sind nach dem Pull sofort live. Server-Code **nicht** — der läuft weiter mit dem alten Stand, bis der Dienst neu startet. ```bash ssh dogfather-server "sudo systemctl restart dogiweb.service" # nach Änderungen in server/ ssh dogfather-server "sudo systemctl restart dogiintern.service" # nach Änderungen in server-internal/ ``` **Warum das hier besonders steht (Vorfall 22.08.2026):** Nach dem Pull des Webdesign-Bereichs war `/webdesign/` für einige Minuten **ohne Zugangsschutz öffentlich erreichbar** (HTTP 200 statt der Umleitung zur Zugangswand). Die HTML-Dateien waren durch den Pull sofort da — die Schranke in `server/webdesign-gate.js` lief aber erst nach dem Neustart von `dogiweb.service`. Bei einem Bereich, der ausdrücklich nicht öffentlich sein soll, ist genau dieses Zeitfenster der gefährliche Teil eines Deploys. Merksatz: **Erst neu starten, dann „ist live" melden** — und danach mit `curl -I` prüfen, dass die Schranke wirklich greift: ```bash curl -sI https://dogfather-universe.com/webdesign/ | grep -iE "^location|x-robots-tag" # erwartet: location: /webdesign/zugang.html?next=... und x-robots-tag: noindex, ... ``` **Achtung bei Zweig-Namen:** lokal heißt der Zweig `master`, auf dem Server und in Gitea `main`. Deshalb `master:main` beim Push. Ein blankes `git push` schiebt sonst nach `gitea/master` — einen alten, abgehängten Zweig, den niemand ausliefert. ## Abhängigkeiten: `npm ci`, nicht `npm install` Seit dem 26.08.2026 ist `package-lock.json` versioniert. Auf dem Server gilt deshalb: ```bash npm ci # richtig: installiert exakt das, was in der Lock-Datei steht npm install # falsch: darf neuere Fassungen ziehen und schreibt die Datei um ``` **Warum der Unterschied zählt.** In `package.json` steht `"express": "^4.21.2"` — das erlaubt alles unter 5.0. Vor dieser Umstellung lief auf dem Server deshalb express **4.22.2**, während hier 4.21.2 stand. Geprüft wurde also nie ganz das, was ausgeliefert wurde. Solche Unterschiede fallen nicht beim Deploy auf, sondern im Betrieb — und dann sucht man den Fehler im eigenen Code. `npm ci` löscht `node_modules` vorher vollständig und baut streng nach der Lock-Datei neu auf. Es schreibt sie nie um; passt sie nicht zur `package.json`, bricht es ab, statt still etwas anderes zu installieren. **Die Lock-Datei war früher ausgeschlossen** (`.gitignore`), weil ein `git pull` daran scheiterte: Git überschreibt keine unverfolgte Datei, auch wenn ihr Inhalt derselbe ist. Das war ein formaler Konflikt, kein inhaltlicher — nachgemessen waren beide Fassungen Byte für Byte identisch. Wenn dieser Fall irgendwo erneut auftritt, ist die Lösung, die Datei auf dem Server **einmal** zu entfernen und danach aus dem Repo zu holen: ```bash ssh dogfather-server "rm -f /home/dogiweb/dogfather-universe/server/package-lock.json" ssh dogfather-server "cd /home/dogiweb/dogfather-universe && git pull --ff-only origin main" ``` ## ⚠️ Am Webdesign-Bereich geändert? Dann ZWEI Zahlen hochzählen Die App speichert Dateien zwischen. Nach einer Änderung an `webdesign/` oder `assets/` müssen **beide** Stellen hoch, sonst bekommen Geräte, die die Seite schon einmal geöffnet haben, weiterhin den alten Stand: ``` webdesign/sw.js const CACHE_NAME = "dogfather-webdesign-vNN"; assets/js/wd-core.js .register("/webdesign/sw.js?v=NN", …) ``` **Warum zwei und nicht eine.** `CACHE_NAME` wirft den Zwischenspeicher weg, sobald der Service Worker startet. Die Nummer in der Adresse sorgt dafür, dass er überhaupt neu geladen wird — und das ist hier nicht selbstverständlich: Gemessen am 26.08.2026: Der Server liefert `sw.js` mit `Cache-Control: no-cache` aus. **Cloudflare ersetzt das durch `max-age=14400`** — vier Stunden, auch bei `cf-cache-status: MISS`. Ursache ist eine feste „Browser Cache TTL" in den Cloudflare-Einstellungen. Ohne die Nummer in der Adresse erreicht jede Änderung am Service Worker die Geräte also bis zu vier Stunden zu spät. Solange alles läuft, fällt das nie auf; ist der Stand fehlerhaft, sind es vier Stunden ohne Reparaturmöglichkeit. ## Was auf dem Server automatisch läuft Beides über `/etc/cron.d/`, beides als root. Die Skripte liegen im Repo und werden über den normalen `git pull` aktualisiert — ein eigener Deploy-Schritt ist nicht nötig. | Wann | Was | Skript | |---|---|---| | täglich 03:15 | Sicherung von Datenbank und Uploads | `server-internal/sicherung.sh` | | alle 5 Minuten | Wächter über 18 Punkte | `server-internal/waechter.mjs` | **Sicherung.** Nutzt SQLites eigenen `.backup`-Befehl, keine Dateikopie — die Datenbank ist 778 KB groß, ihr WAL 4,1 MB, eine Kopie der `.db` allein wäre also weitgehend leer. 14 tägliche Stände, sonntags zusätzlich ein Wochenstand (8 davon). Jeder Stand wird sofort nach dem Anlegen geprüft. Wiederherstellung: `server-internal/wiederherstellen.sh`, zeigt ohne Argument die verfügbaren Stände. **Wächter.** Prüft sechs Dienste, neun Adressen, Plattenplatz und zwei Zertifikatslaufzeiten. Meldet per Push, und zwar **nur bei Zustandswechsel** — nicht alle fünf Minuten dasselbe. Läuft als root und verschickt selbst; ein Wächter, der über den internen Dienst meldet, wäre ausgerechnet dann still, wenn dieser das Problem ist. Meldeweg prüfen, ohne auf eine Störung zu warten: ```bash sudo /usr/local/bin/node /home/dogiweb/dogfather-universe/server-internal/waechter.mjs --probe ``` ⚠️ **Grenze:** Ist der Server als Ganzes weg — Netz, Strom, Hardware —, meldet auch der Wächter nichts. Dagegen hilft nur eine Überwachung außerhalb der Maschine. ## Die Verwaltung ist eine eigene App Seit dem 26.08.2026 hat `webdesign/verwaltung.html` ein **eigenes** Manifest (`verwaltung.webmanifest`) mit eigener `id` und eigenem Symbol. Ohne die unterschiedliche `id` hielten Browser beide für dieselbe App, und die zweite Installation überschriebe die erste. Das Manifest steht in der Ausnahmeliste von `server/webdesign-gate.js` — ohne diesen Eintrag antwortet es mit 302 auf die Zugangswand, und der Browser bietet „App installieren" gar nicht erst an. ## Pflicht-Prüfung nach JEDEM Deploy Nicht auf die Erfolgsmeldung des Deploy-Befehls verlassen, sondern **die echte Domain fragen**: ```bash # Kommt meine Änderung wirklich auf der Seite an, die Filipe benutzt? curl -s https://dogfather-universe.com/assets/css/main.css | grep "" ``` Erst wenn das anschlägt, gilt eine Änderung als erledigt. Bei optischen Änderungen zusätzlich mit einem echten Browser im Handy-Format nachsehen (Playwright, Viewport 390×844) und einen Screenshot machen — Text im Quelltext beweist noch nicht, dass es auch richtig aussieht. ## Der Cloudflare-Worker (Altbestand) Bleibt vorerst bestehen, liefert aber nur noch `…workers.dev` aus. Ein Deploy dorthin ändert an der echten Seite nichts. Der Versuch, die Domain per `wrangler` wieder anzubinden, schlägt bewusst fehl: ``` Hostname 'dogfather-universe.com' already has externally managed DNS records ``` Das ist **kein Fehler, den man beheben sollte** — es ist die Schutzwirkung davon, dass die Domain jetzt auf Netcup zeigt. `routes` mit `custom_domain = true` steht deshalb nur noch aus historischen Gründen in `wrangler.toml`. Der Bewerbungs-Postfach-Worker ist davon unabhängig und läuft weiter auf Cloudflare: `https://dogfather-universe-postfach.dogfather1608.workers.dev` (`API_BASE_URL` in `assets/js/forms.js`, `index.html`, `postfach.html`). ## Git-Ablage - **Quelle der Wahrheit:** Gitea, `git.dogfather-universe.com/DogFatherGit/dogfather-universe`, Zweig `main` (auf dem eigenen Server, kostenlos, in eigener Hand). - Lokal heißt das Fernziel `gitea`, der Zweig `master`. - Auf dem Server heißt das Fernziel `origin`, der Zweig `main`. - `gitea/master` ist ein **alter, abgehängter Zweig** (Stand 44086b0) — nicht benutzen. - Sicherungszweig `server-stand-vor-abgleich-22-08-2026` auf dem Server: der Stand, bevor die beiden Fassungen am 22.08.2026 zusammengeführt wurden. Kann irgendwann weg, kostet nichts. **Nie direkt auf dem Server Dateien bearbeiten, ohne sie danach in Gitea nachzutragen.** Genau dadurch waren am 22.08.2026 zwei Reparaturen (Autofokus in `gate.html`, abgeschnittene Öffnen-Knöpfe in `verwaltung.html`) nur auf dem Server vorhanden und wären beim nächsten Deploy vom Rechner aus überschrieben worden. ## Offene Punkte - ~~Hintergrundbilder liegen nur auf dem Server~~ — **erledigt, nachgeprüft am 26.08.2026.** Alle genannten Dateien (`bg-bewerben-modi.jpg`, `bg-links-seite.jpg`, `bg-medien-casper.jpg`, `bg-supporter.jpg`, `bg-modis.jpg`) und der Ordner `assets/img/stimmen-avatare/` (8 Dateien) sind inzwischen versioniert. `git status --untracked-files=all -- assets/` auf dem Server meldet **null** unverfolgte Dateien. Der Eintrag bleibt hier stehen, statt gelöscht zu werden: Eine Liste offener Punkte, in der Erledigtes ungekennzeichnet steht, wird beim nächsten Mal gar nicht mehr gelesen. Wer prüft, will sehen, dass geprüft wurde. - **CORS steht auf `*`** — in `server-internal/index.js` (`app.use(cors())`) und im Altbestand `cloudflare-worker/src/lib/http.js`. **Eingeordnet am 26.08.2026, weniger dringend als der alte Hinweis klang:** Die Antwort enthält *kein* `Access-Control-Allow-Credentials`, und die Verwaltung weist sich über `Authorization: Bearer …` aus, nicht über ein Cookie. Ein Browser schickt bei einer fremden Seite deshalb weder Cookies noch das Token mit — eine fremde Seite erreicht damit nur die ohnehin öffentlichen Endpunkte (Team, Events, Stimmen). An Kundendaten kommt sie nicht. Sauberer wäre es trotzdem: eine feste Liste erlaubter Herkünfte (`dogfather-universe.com`, `vans-diy-bastelbedarf.com`) statt `*`. Das ist Härtung, keine Reparatur — und ein Eingriff in einen laufenden Dienst, der bei zu enger Einstellung die Seite lahmlegt. Also als eigener Vorgang, mit Live-Test danach. - **express 5 vorbereitet, nicht umgestellt.** `pruef-express5.mjs` (Bestand durchsuchen) und `server/test-express5.mjs` (echter Server gegen 5.2.1) sind grün — der Umstieg wäre ohne Codeänderung möglich. Nicht durchgeführt, weil express 4.22.2 gepflegt wird und `npm audit` null meldet. Ebenfalls offen: dotenv 16→17, better-sqlite3 11→13 (dort muss die ABI zur Node-Fassung passen; ein Fehlgriff legt den internen Dienst still). - **Datenschutz-Endpunkte warten auf einen Pull in `/home/dogiintern`.** Die Oberfläche ist live, die drei Endpunkte (`/webdesign/admin/datenschutz/{auskunft,vorschau,loeschen}`) antworten dort noch mit 404. Der Pull scheitert vermutlich an der unverfolgten `package-lock.json` — siehe den Abschnitt zu `npm ci` weiter oben. ## Alternative Hosting-Optionen (nur als Notfall-Plan) Die Seite ist reines statisches HTML/CSS/JS und läuft überall — `netlify.toml` und `.nojekyll` liegen bereit. Relevant nur, falls der Netcup-Server einmal ausfällt.