diff --git a/server/index.js b/server/index.js index 2df9b908..1d7391ad 100644 --- a/server/index.js +++ b/server/index.js @@ -11,6 +11,7 @@ import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { gateMiddleware } from "./gate.js"; +import { workspaceUmzug } from "./workspace-umzug.js"; import { webdesignGate } from "./webdesign-gate.js"; import { inhaltsrichtlinie } from "./inhaltsrichtlinie.js"; import { workspaceRouter, sichtSetzen } from "./workspace.js"; @@ -37,6 +38,7 @@ import { schulungRouter } from "./workspace-schulung.js"; import { ampelRouter } from "./workspace-ampel.js"; import { checklisteRouter } from "./workspace-checkliste.js"; import { pushRouter, pushStarten } from "./workspace-push.js"; +import { chatRouter } from "./workspace-chat.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); const SITE_DIR = join(__dirname, ".."); @@ -94,6 +96,13 @@ app.use((req, res, next) => { next(); }); +/* Umzug des Creator Workspace auf eine eigene Adresse (06.09.2026). + Begruendung und die beiden Fallstricke stehen in workspace-umzug.js — + sie sind dort als eigene Funktion pruefbar (pruef-workspace-umzug.mjs). + Steht bewusst FRUEH: vor jeder Schranke, damit auch die Anmeldeseite + und die 404-Seite unter der alten Adresse weiterleiten. */ +app.use(workspaceUmzug); + /* Inhaltsrichtlinie (26.08.2026). Steht bewusst HIER -- vor jeder Schranke und vor express.static: Auch die Zugangswand und die 404-Seite sollen sie bekommen, denn gerade dort werden Eingaben @@ -153,6 +162,7 @@ app.use(steckbriefRouter); oeffentlichen Schluessel, bevor irgendetwas anderes laeuft, und die Push-Wege bringen ihre eigene Schranke mit. */ app.use(pushRouter); +app.use(chatRouter); app.use(vorlagenRouter); app.use(schulungRouter); app.use(ampelRouter); diff --git a/server/pruef-workspace-umzug.mjs b/server/pruef-workspace-umzug.mjs new file mode 100644 index 00000000..395047c3 --- /dev/null +++ b/server/pruef-workspace-umzug.mjs @@ -0,0 +1,86 @@ +/* ===================================================================== + Prüft die Umzugs-Weiterleitung des Creator Workspace. + + Zwei Fehler waeren hier teuer, und beide sieht man einer Bedingung + nicht an: + + 1. ENDLOSSCHLEIFE. Derselbe Dienst bedient die alte UND die neue + Adresse. Wer nicht auf den Hostnamen prueft, leitet die neue + Adresse immer wieder auf sich selbst -- der Workspace waere fuer + alle unerreichbar, und zwar sofort nach dem Neustart. + + 2. PRAEFIX-IRRTUM. "faengt an mit /workspace" trifft auch + /workspaceXYZ oder /workspace-alt -- Pfade, die nicht zum + Workspace gehoeren. + + Geprueft wird die ECHTE Funktion aus workspace-umzug.js, nicht eine + Kopie der Bedingung -- eine Kopie wuerde beim naechsten Umbau + auseinanderlaufen und dann etwas anderes bestaetigen als das, was + wirklich laeuft. + + Aufruf: node server/pruef-workspace-umzug.mjs + ===================================================================== */ +import { sollUmgeleitetWerden, NEUE_ADRESSE } from "./workspace-umzug.js"; + +/* [Host, Pfad, erwartet, Begruendung] */ +const FAELLE = [ + // --- muss weiterleiten --- + ["dogfather-universe.com", "/workspace/", true, "alte Adresse, Startseite"], + ["dogfather-universe.com", "/workspace", true, "alte Adresse, ohne Schraegstrich"], + ["dogfather-universe.com", "/workspace/start.html", true, "alte Adresse, Unterseite"], + ["dogfather-universe.com", "/workspace/api/aufgaben", true, "alte Adresse, Schnittstelle"], + ["www.dogfather-universe.com", "/workspace/", true, "auch mit www"], + ["DOGFATHER-UNIVERSE.COM", "/workspace/", true, "Grossschreibung darf egal sein"], + ["dogfather-universe.com:443", "/workspace/", true, "Portangabe darf egal sein"], + + // --- darf NICHT weiterleiten: sonst Endlosschleife --- + ["workspace.dogfather-universe.com", "/workspace/", false, "NEUE Adresse -- sonst Endlosschleife"], + ["workspace.dogfather-universe.com", "/workspace/start.html", false, "NEUE Adresse, Unterseite"], + ["workspace.dogfather-universe.com", "/workspace/api/aufgaben", false, "NEUE Adresse, Schnittstelle"], + + // --- darf NICHT weiterleiten: gehoert nicht zum Workspace --- + ["dogfather-universe.com", "/", false, "Hauptseite"], + ["dogfather-universe.com", "/index.html", false, "Hauptseite"], + ["dogfather-universe.com", "/webdesign/", false, "anderer Bereich"], + ["dogfather-universe.com", "/workspaceXYZ", false, "PRAEFIX-IRRTUM: gehoert nicht dazu"], + ["dogfather-universe.com", "/workspace-alt/seite", false, "PRAEFIX-IRRTUM mit Bindestrich"], + ["dogfather-universe.com", "/assets/css/main.css", false, "gemeinsame Datei"], + + // --- darf NICHT weiterleiten: lokale Tests wuerden sonst scheitern --- + ["127.0.0.1:4100", "/workspace/", false, "lokaler Testserver"], + ["localhost:4100", "/workspace/start.html", false, "lokaler Testserver"], + + // --- Sonderfaelle --- + ["", "/workspace/", false, "kein Host-Feld"], + ["boese.example.com", "/workspace/", false, "fremder Host"], +]; + +let geprueft = 0; +const fehler = []; +for (const [host, pfad, erwartet, grund] of FAELLE) { + const ist = sollUmgeleitetWerden(host, pfad); + geprueft++; + if (ist !== erwartet) { + fehler.push(`${host || "(leer)"}${pfad} -> ${ist ? "leitet um" : "leitet NICHT um"}, erwartet ${erwartet ? "umleiten" : "nicht umleiten"} (${grund})`); + } +} + +/* Gegenprobe: Kann diese Pruefung ueberhaupt "nein" sagen? Ein Fall, von + dem wir wissen, dass er falsch ist, MUSS auffallen. */ +const gegenprobe = sollUmgeleitetWerden("dogfather-universe.com", "/workspace/") === true + && sollUmgeleitetWerden("workspace.dogfather-universe.com", "/workspace/") === false; + +/* Und das Ziel muss stimmen -- eine Weiterleitung auf die falsche Adresse + waere schlimmer als gar keine. */ +const zielStimmt = NEUE_ADRESSE === "https://workspace.dogfather-universe.com"; +geprueft++; +if (!zielStimmt) fehler.push(`Ziel ist "${NEUE_ADRESSE}", erwartet https://workspace.dogfather-universe.com`); + +const SOLL = FAELLE.length + 1; +console.log(`${geprueft} Faelle geprueft (erwartet ${SOLL}), ${fehler.length} Beanstandungen.`); +console.log(`Gegenprobe (alt leitet um, neu nicht): ${gegenprobe ? "ja" : "NEIN"}`); +for (const f of fehler) console.log(" FEHL " + f); + +if (geprueft !== SOLL) { console.log("FEHL: Anzahl stimmt nicht."); process.exit(1); } +if (!gegenprobe) { console.log("FEHL: Gegenprobe schlaegt nicht an -- die Pruefung waere wertlos."); process.exit(1); } +process.exit(fehler.length === 0 ? 0 : 1); diff --git a/server/workspace-umzug.js b/server/workspace-umzug.js new file mode 100644 index 00000000..d10ac069 --- /dev/null +++ b/server/workspace-umzug.js @@ -0,0 +1,69 @@ +/* ===================================================================== + Umzug des Creator Workspace auf eine eigene Adresse (06.09.2026) + + Der Workspace liegt seit diesem Tag auf + workspace.dogfather-universe.com + und ist unter der alten Adresse dogfather-universe.com/workspace/ nur + noch als Weiterleitung erreichbar. + + WARUM: Chrome laesst neben der Hauptseite, deren Bereich "/" die ganze + Domain umfasst, keine zweite App auf derselben Adresse zu. Unter dem + alten Pfad liess sich der Workspace deshalb nur als Verknuepfung + ablegen, nie als richtige App installieren -- im Menue stand "Oeffnen + in DOGFATHER UNIVERSE" statt "Seite als App installieren". Das ist kein + Fehler, sondern Absicht (w3c/manifest Nr. 1180: verschachtelte Bereiche + auf einem Ursprung sind "strongly not recommended"). Eine eigene + Adresse ist der einzige Weg. + + Der PFAD /workspace/ bleibt erhalten. An ihm haengen 150 Server-Routen, + 107 API-Aufrufe und 26 Server-Dateien -- ihn wegzuschneiden waere ein + grosser Umbau ohne Gewinn, denn der Konflikt entsteht durch die + gemeinsame ADRESSE, nicht durch den Pfad. + + WARUM DIESE ENTSCHEIDUNG IN EINER EIGENEN DATEI STEHT: Sie hat zwei + Stellen, an denen ein Denkfehler teuer waere, und beide sieht man einer + Bedingung nicht an: + + 1. Derselbe Dienst bedient BEIDE Adressen. Wer nicht auf den Host + prueft, baut eine Endlosschleife -- die neue Adresse wuerde sich + immer wieder auf sich selbst weiterleiten, und der Workspace waere + fuer alle unerreichbar. + + 2. "faengt an mit /workspace" trifft auch /workspaceXYZ. Ein solcher + Pfad gehoert nicht zum Workspace und darf nicht umgeleitet werden. + + Als eigene Funktion laesst sich beides pruefen, ohne den ganzen Server + zu starten -- siehe pruef-workspace-umzug.mjs. + ===================================================================== */ + +export const NEUE_ADRESSE = "https://workspace.dogfather-universe.com"; + +/** Die alten Adressen, von denen weitergeleitet wird. Bewusst eine feste + * Liste und kein Muster: Ein Muster wie /dogfather-universe\.com$/ wuerde + * auch auf workspace.dogfather-universe.com passen -- und damit genau die + * Endlosschleife bauen, die es zu vermeiden gilt. */ +const ALTE_HOSTS = new Set(["dogfather-universe.com", "www.dogfather-universe.com"]); + +/** + * Soll diese Anfrage auf die neue Adresse umgeleitet werden? + * @param {string} hostKopfzeile Inhalt des Host-Kopffeldes, ggf. mit Port + * @param {string} pfad req.path, also ohne Abfrageteil + */ +export function sollUmgeleitetWerden(hostKopfzeile, pfad) { + const host = String(hostKopfzeile || "").toLowerCase().split(":")[0]; + if (!ALTE_HOSTS.has(host)) return false; + /* Genau "/workspace" oder alles darunter -- aber NICHT /workspaceXYZ. */ + return pfad === "/workspace" || pfad.startsWith("/workspace/"); +} + +/** Express-Zwischenschritt. Bewusst 302 (voruebergehend) statt 301: + * Ein 301 wird vom Browser dauerhaft gemerkt und laesst sich praktisch + * nicht zurueckholen -- waere an der Umleitung etwas falsch, waere die + * alte Adresse fuer jeden, der sie einmal aufgerufen hat, dauerhaft + * unbrauchbar, auch nach einer Korrektur. */ +export function workspaceUmzug(req, res, next) { + if (sollUmgeleitetWerden(req.get("host"), req.path)) { + return res.redirect(302, NEUE_ADRESSE + req.originalUrl); + } + next(); +}