Diagnoseseite: findet und behebt haengende Zwischenspeicher
Rueckmeldung: "garnichts laedt in der verwaltungsseite". Geprueft statt geraten -- die Serverseite ist in Ordnung: Dienst aktiv, keine Fehler im Protokoll CORS-Vorabanfrage 204 mit allow-origin echte Anfrage 401 (korrekt ohne Anmeldung), Antwortzeit unauffaellig ausgelieferte Seite enthaelt den neuen Code Damit bleibt fast nur der Browser: ein alter Service Worker, der veraltete Dateien ausliefert. Er ueberlebt ein normales Neuladen, und niemand kann ihn ohne Entwicklerwerkzeuge sehen. webdesign/diagnose.html prueft sechs Dinge und sagt im Klartext, welches davon klemmt: Service Worker aktiv? Zwischenspeicher gefuellt? Server erreichbar und wie schnell? Kennt der Server die neuen Adressen (404 = Server veraltet)? Liegt eine Anmeldung vor? Und wird die AKTUELLE Gestaltungsdatei ausgeliefert -- erkennbar an einem Merkmal, das es erst seit heute gibt. Ein Knopf meldet den Service Worker ab, loescht die Zwischenspeicher und laedt die Verwaltung mit Zeitstempel neu. Der Text sagt ausdruecklich, dass Anmeldung und Daten unberuehrt bleiben -- sonst traut sich niemand zu klicken. ZWEI ENTSCHEIDUNGEN Die Seite laedt KEINE externen Dateien, alles steht inline. Sie muss funktionieren, wenn genau das kaputt ist, was sie untersucht -- eine Diagnoseseite, die an derselben veralteten CSS-Datei scheitert, ist wertlos. Sie ist von der Zugangswand ausgenommen, wie Widerruf und Rechtstexte. Gebraucht wird sie genau dann, wenn etwas klemmt; dann darf nicht ausgerechnet die Zugangswand davorstehen. Sie enthaelt keine Kunden- oder Projektdaten, sondern prueft nur den eigenen Browser und meldet Statusnummern. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -445,6 +445,11 @@ export function webdesignGate(req, res, next) {
|
||||
pfad === "/webdesign/zugang.html" ||
|
||||
pfad === "/webdesign/widerruf.html" ||
|
||||
pfad === "/webdesign/rechtliches.html" ||
|
||||
/* Die Diagnoseseite bleibt ebenfalls offen. Sie wird genau dann
|
||||
gebraucht, wenn etwas klemmt -- und dann darf nicht ausgerechnet
|
||||
die Zugangswand dazwischenstehen. Sie enthaelt keine Daten,
|
||||
sondern prueft nur den eigenen Browser und meldet Statusnummern. */
|
||||
pfad === "/webdesign/diagnose.html" ||
|
||||
pfad === "/webdesign/sw.js" ||
|
||||
pfad === "/webdesign/app.webmanifest"
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Diagnose — Dogfather Webdesign</title>
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<meta name="theme-color" content="#05070b" />
|
||||
<style>
|
||||
/* ---------------------------------------------------------------------
|
||||
BEWUSST OHNE EXTERNE DATEIEN.
|
||||
|
||||
Diese Seite muss auch dann funktionieren, wenn genau das kaputt ist,
|
||||
was sie untersuchen soll: veraltete CSS- und JS-Dateien aus dem
|
||||
Zwischenspeicher. Würde sie webdesign.css oder wd-core.js laden,
|
||||
könnte sie am selben Problem scheitern und wäre nutzlos.
|
||||
|
||||
Deshalb steht hier alles inline und es gibt keinen Service Worker.
|
||||
--------------------------------------------------------------------- */
|
||||
:root { color-scheme: dark; }
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0; padding: 1.5rem 1rem 3rem;
|
||||
background: #05070b; color: #eef4fb;
|
||||
font: 16px/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
}
|
||||
.hu { max-width: 720px; margin: 0 auto; }
|
||||
h1 { font-size: 1.5rem; margin: 0 0 .3rem; }
|
||||
p.lead { color: #8f9fb4; margin: 0 0 1.6rem; }
|
||||
h2 { font-size: 1.05rem; margin: 1.8rem 0 .6rem; color: #7fd0e8; }
|
||||
.zeile {
|
||||
display: flex; gap: .8rem; align-items: flex-start;
|
||||
padding: .8rem .9rem; margin-bottom: .5rem;
|
||||
border: 1px solid rgba(127,208,232,.16); border-radius: 10px;
|
||||
background: rgba(16,26,41,.5);
|
||||
}
|
||||
.zeile b { display: block; margin-bottom: .1rem; }
|
||||
.zeile span { color: #8f9fb4; font-size: .9rem; word-break: break-word; }
|
||||
.mark { flex: none; width: 26px; height: 26px; border-radius: 50%;
|
||||
display: grid; place-items: center; font-size: .95rem; line-height: 1; }
|
||||
.gut { background: rgba(111,214,163,.15); color: #6fd6a3; }
|
||||
.warn { background: rgba(232,200,119,.18); color: #e8c877; }
|
||||
.bad { background: rgba(255,157,157,.15); color: #ff9d9d; }
|
||||
.wart { background: rgba(143,159,180,.15); color: #8f9fb4; }
|
||||
button {
|
||||
font: inherit; font-weight: 700; cursor: pointer;
|
||||
padding: .85rem 1.3rem; border-radius: 10px; border: 0;
|
||||
background: linear-gradient(135deg, #a9e2f2, #7fd0e8); color: #04060a;
|
||||
min-height: 48px;
|
||||
}
|
||||
button.zweit { background: transparent; color: #7fd0e8; border: 1px solid rgba(127,208,232,.34); }
|
||||
.knoepfe { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1rem; }
|
||||
.hinweis {
|
||||
margin-top: 1.6rem; padding: 1rem 1.1rem; border-radius: 12px;
|
||||
background: rgba(232,200,119,.08); border: 1px solid rgba(232,200,119,.32);
|
||||
}
|
||||
.hinweis b { color: #e8c877; }
|
||||
code { background: rgba(127,208,232,.1); padding: .1rem .35rem; border-radius: 5px; font-size: .88em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="hu">
|
||||
<h1>Diagnose</h1>
|
||||
<p class="lead">
|
||||
Diese Seite prüft, warum der Verwaltungs- oder Portalbereich nicht lädt.
|
||||
Sie lädt selbst keine externen Dateien — sie funktioniert also auch dann,
|
||||
wenn genau die das Problem sind.
|
||||
</p>
|
||||
|
||||
<h2>Prüfungen</h2>
|
||||
<div id="ergebnis">
|
||||
<div class="zeile"><span class="mark wart">…</span><div><b>Läuft</b><span>Einen Moment.</span></div></div>
|
||||
</div>
|
||||
|
||||
<div class="knoepfe">
|
||||
<button type="button" id="reparieren">Zwischenspeicher leeren und neu laden</button>
|
||||
<button type="button" class="zweit" id="nochmal">Nochmal prüfen</button>
|
||||
</div>
|
||||
|
||||
<div class="hinweis">
|
||||
<p style="margin:0 0 .4rem"><b>Was der grosse Knopf macht</b></p>
|
||||
<p style="margin:0;font-size:.92rem">
|
||||
Er meldet den Service Worker ab und löscht alle zwischengespeicherten
|
||||
Dateien dieser Seite. Danach holt der Browser alles frisch vom Server.
|
||||
<strong>Deine Anmeldung und deine Daten bleiben unberührt</strong> —
|
||||
gelöscht werden nur Kopien von Dateien, die ohnehin jederzeit neu
|
||||
geladen werden können.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* Alles inline und ohne Abhängigkeiten — siehe Begründung im CSS-Kopf. */
|
||||
(function () {
|
||||
"use strict";
|
||||
var API = "https://postfach.dogfather-universe.com";
|
||||
var ziel = document.getElementById("ergebnis");
|
||||
|
||||
function zeile(art, titel, text) {
|
||||
var z = { gut: "✓", warn: "!", bad: "✕", wart: "…" };
|
||||
var d = document.createElement("div");
|
||||
d.className = "zeile";
|
||||
d.innerHTML = '<span class="mark ' + art + '">' + z[art] + "</span><div><b></b><span></span></div>";
|
||||
d.querySelector("b").textContent = titel;
|
||||
d.querySelector("span").textContent = text;
|
||||
ziel.appendChild(d);
|
||||
}
|
||||
|
||||
async function pruefen() {
|
||||
ziel.innerHTML = "";
|
||||
|
||||
/* 1. Service Worker — der häufigste Grund für "es lädt die alte
|
||||
Fassung". Er überlebt ein normales Neuladen. */
|
||||
if ("serviceWorker" in navigator) {
|
||||
try {
|
||||
var regs = await navigator.serviceWorker.getRegistrations();
|
||||
var meine = regs.filter(function (r) {
|
||||
return (r.scope || "").indexOf("/webdesign") >= 0;
|
||||
});
|
||||
if (!meine.length) {
|
||||
zeile("gut", "Service Worker", "Keiner aktiv — Dateien kommen direkt vom Server.");
|
||||
} else {
|
||||
zeile("warn", "Service Worker aktiv",
|
||||
meine.length + " registriert. Er kann alte Dateien ausliefern. "
|
||||
+ "Der Knopf unten meldet ihn ab.");
|
||||
}
|
||||
} catch (e) {
|
||||
zeile("warn", "Service Worker", "Konnte nicht geprüft werden: " + e.message);
|
||||
}
|
||||
} else {
|
||||
zeile("gut", "Service Worker", "Von diesem Browser nicht unterstützt — kein Problem.");
|
||||
}
|
||||
|
||||
/* 2. Zwischenspeicher */
|
||||
if ("caches" in window) {
|
||||
try {
|
||||
var namen = await caches.keys();
|
||||
var meineC = namen.filter(function (n) { return n.indexOf("webdesign") >= 0; });
|
||||
if (!meineC.length) zeile("gut", "Zwischenspeicher", "Leer.");
|
||||
else zeile("warn", "Zwischenspeicher", "Enthält: " + meineC.join(", "));
|
||||
} catch (e) {
|
||||
zeile("warn", "Zwischenspeicher", "Nicht prüfbar: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. Ist der Server erreichbar? Ein Endpunkt, der ohne Anmeldung
|
||||
antwortet -- 401 ist hier die RICHTIGE Antwort und beweist,
|
||||
dass alles bis dorthin funktioniert. */
|
||||
try {
|
||||
var t0 = Date.now();
|
||||
var a = await fetch(API + "/webdesign/admin/anfragen", { cache: "no-store" });
|
||||
var ms = Date.now() - t0;
|
||||
if (a.status === 401) {
|
||||
zeile("gut", "Server erreichbar", "Antwortet in " + ms + " ms (Status 401 = erwartet ohne Anmeldung).");
|
||||
} else if (a.status === 404) {
|
||||
zeile("bad", "Server veraltet", "Status 404 — der interne Dienst kennt diese Adresse noch nicht.");
|
||||
} else {
|
||||
zeile("warn", "Server antwortet", "Status " + a.status + " nach " + ms + " ms.");
|
||||
}
|
||||
} catch (e) {
|
||||
zeile("bad", "Server NICHT erreichbar",
|
||||
"Der Browser kommt nicht an " + API + " heran. " + (e.message || ""));
|
||||
}
|
||||
|
||||
/* 4. Die neuen Adressen */
|
||||
try {
|
||||
var b = await fetch(API + "/webdesign/admin/einstellungen", { cache: "no-store" });
|
||||
if (b.status === 401) zeile("gut", "Zahlungen-Bereich", "Vorhanden und geschützt.");
|
||||
else if (b.status === 404) zeile("bad", "Zahlungen-Bereich fehlt",
|
||||
"Der Server muss noch aktualisiert werden (git pull + Neustart).");
|
||||
else zeile("warn", "Zahlungen-Bereich", "Status " + b.status + ".");
|
||||
} catch (e) {
|
||||
zeile("bad", "Zahlungen-Bereich", "Nicht erreichbar: " + (e.message || ""));
|
||||
}
|
||||
|
||||
/* 5. Anmeldung im Browser vorhanden? */
|
||||
try {
|
||||
var tok = sessionStorage.getItem("wd-vw-token");
|
||||
if (tok) zeile("gut", "Anmeldung Verwaltung", "Ein Sitzungsschlüssel liegt vor.");
|
||||
else zeile("warn", "Anmeldung Verwaltung",
|
||||
"Keiner vorhanden — die Verwaltung fragt nach dem Zugangscode. Das ist normal, "
|
||||
+ "wenn die Seite zwischendurch geschlossen war.");
|
||||
} catch (e) {
|
||||
zeile("warn", "Anmeldung", "Speicher nicht lesbar: " + e.message);
|
||||
}
|
||||
|
||||
/* 6. Welche Fassung liegt im Browser? */
|
||||
try {
|
||||
var c = await fetch("/assets/css/webdesign.css?diagnose=" + Date.now(), { cache: "no-store" });
|
||||
var txt = await c.text();
|
||||
var hatNeu = txt.indexOf("--wd-blau-rgb") >= 0;
|
||||
zeile(hatNeu ? "gut" : "bad", "Gestaltungsdatei",
|
||||
hatNeu ? "Aktuelle Fassung wird ausgeliefert."
|
||||
: "VERALTETE Fassung. Der Knopf unten hilft.");
|
||||
} catch (e) {
|
||||
zeile("warn", "Gestaltungsdatei", "Nicht prüfbar: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("nochmal").addEventListener("click", pruefen);
|
||||
|
||||
document.getElementById("reparieren").addEventListener("click", async function () {
|
||||
var k = this;
|
||||
k.disabled = true;
|
||||
k.textContent = "Wird bereinigt …";
|
||||
try {
|
||||
if ("serviceWorker" in navigator) {
|
||||
var regs = await navigator.serviceWorker.getRegistrations();
|
||||
for (var i = 0; i < regs.length; i++) await regs[i].unregister();
|
||||
}
|
||||
if ("caches" in window) {
|
||||
var namen = await caches.keys();
|
||||
for (var j = 0; j < namen.length; j++) await caches.delete(namen[j]);
|
||||
}
|
||||
} catch (e) { /* weiter -- neu laden hilft meistens trotzdem */ }
|
||||
k.textContent = "Fertig — wird neu geladen …";
|
||||
/* Mit Zeitstempel, damit auch der Browser-eigene Zwischenspeicher
|
||||
umgangen wird. */
|
||||
setTimeout(function () {
|
||||
location.href = "/webdesign/verwaltung.html?frisch=" + Date.now();
|
||||
}, 700);
|
||||
});
|
||||
|
||||
pruefen();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user