Files
dogfather-universe/server/crew-adresse.js
T
DogFatherGitandClaude Opus 5 7b21f247eb Der Treff: eine eigene Tür für die Community, und sie sieht nur, was dasteht
Filipe: "eine community rolle und community kategorie, wo die community
auch dann nur die sieht" · "wieso nur eine kachel — ich will mehrere,
mit mehreren optionen" · "egal welche rolle hinzugefügt wird soll immer
nur das sehen was ich erlaube".

DIE DRITTE ADRESSE. treff.dogfather-universe.com bekommt eine eigene
Weiche (treff-adresse.js), eine eigene Zugangswand, ein eigenes Manifest
und acht eigene Bühnenbilder. Ohne sie stünde dort die Wand der Agentur:
Spicy-Logo, "Creator Workspace", fünf Rollenkacheln mit den Namen Admin,
Manager, Scout, Creator — die komplette Struktur des Unternehmens, vor
der Anmeldung, für jeden mit der Adresse.

Welche Wand zu welcher Tür gehört, steht jetzt in EINER Tafel
(istFremdeWand) statt als Sonderfall im Code. Bei zwei Wänden war ein
Sonderfall richtig; bei drei wären es drei geworden, bei vier sechs.

SIEBEN BRETTER UND EIN ACHTES NUR FÜRS TEAM. Anschlagbrett, Was ansteht,
Der Treff, Wunschliste, Highlights, Regeln & Hilfe, Mitmachen — dazu
"Meldungen & Maßnahmen", das ausdrücklich NICHT in TREFF_BEREICHE steht:
dort wäre es lautlos bei der Community gelandet und hätte ausgesehen wie
die anderen sieben.

WAS AUF DEN BRETTERN PASSIERT: "Will ich auch" (eine Stimme je Person,
erzwungen durch den Schlüssel, nicht durch eine Prüfung) · Anheften,
höchstens drei, gezählt IN der Transaktion · Freigabe vor Sichtbarkeit
für Termine und Highlights, wobei Abwesenheit der Ruhezustand ist ·
Melden mit Pflicht-Grund (DSA Art. 16) · Entfernen mit Grund, der den
Beitrag ÜBERLEBT (DSA Art. 17) · drei Stufen, gerechnet statt
gespeichert · die Bannleiter: Modi bis 7 Tage, dauerhaft nur DogFather
(seine Entscheidung) · "Mitmachen" wird zum Talent, genau einmal.

Der Ausschluss wirkt in sitzungLesen() — also nicht nur beim Schreiben.
Wer ausgeschlossen ist, ist weg, nicht stumm.

ZWEI SEITEN MEHR. treff-regeln.html holt seine ZAHLEN vom Server
(Mindestalter 18, Fristen, Anschläge) — ein Regeltext, der eine andere
Zahl nennt als die Regel, ist schlimmer als keiner. rechte.html rechnet
"Wer sieht was" aus derselben Tafel aus, aus der die Schranke ihre
Entscheidung holt. Die Community steht dort bei 3 von 23.

SECHS BEFUNDE, KEINEN HAT DAS LESEN GEFUNDEN:
 · Ein Modi kam über den verborgenen Zugang in den Treff — die Bedingung
   war durch Ausschluss formuliert und nahm die neue Wand automatisch mit
 · /api/personen gab einem Mitglied Namen und Rolle von DogFather
 · Ein DELETE mit Körper wird von Nodes HTTP-Parser mit einem leeren 400
   abgewiesen, bevor Express ihn sieht (gemessen). Der Grund reist jetzt
   in der Adresse
 · Der Kommentar, der erklärt, warum die Zugangswand keine Rollennamen
   nennt, nannte selbst einen — in einer ausgelieferten Datei
 · Zwei Listen für "welche Seiten sind ohne Anmeldung offen". Sie
   stimmten, weil beide am selben Tag entstanden
 · Ein Portkonflikt, den ich selbst gebaut hatte (4391 gehört
   pruef-chat-aufloesen)

Dazu zwei feste Zahlen abgeschafft (die 20 in pruef-rechtetafel, die
Kachelzahl in pruef-treff) und zwei Werkzeuge, die jetzt SUCHEN statt
aufzuzählen: Der Versionsstempel findet seine Manifeste selbst — das
dritte hätte sonst keinen bekommen, und die neue App hätte bis zu vier
Stunden lang das falsche Zeichen getragen. Das Bildwerkzeug baut beide
Zugangswände aus einer Vorlage mit zwei Werten.

Zwei neue Kacheltöne, gemessen statt gewählt: #2f2f7f (Abstand 31,4 in
Lab) und #7c2771 (29,7). Das schwächste Paar der vorhandenen 34 liegt
bei 24,9.

Geprüft: treff 69 · treff-werkzeuge 60 · rollen 312 · start-ansicht 147 ·
crew-adresse 129 · sicht 84 · modi-verborgen 80 · haus-trennung 62 ·
bereiche-lesend 37 · css-klassen 30 · zwischenspeicher 21 · alle-wege 19 ·
rechtetafel 19 — alles grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 17:58:34 +02:00

425 lines
20 KiB
JavaScript

/* =====================================================================
Die eigene Adresse der Modi-App (10.09.2026)
crew.dogfather-universe.com
WARUM EINE EIGENE ADRESSE. Derselbe Grund, aus dem der Creator
Workspace am 06.09.2026 umgezogen ist (siehe workspace-umzug.js):
Auf einem Ursprung laesst sich genau EINE App installieren. Zwei
Manifeste mit verschachtelten Bereichen sind laut w3c/manifest
Nr. 1180 "strongly not recommended", und Chrome haelt sich daran --
der zweite Eintrag erscheint dann nur als Verknuepfung, nie als
eigene App. Filipe will fuer die Modis ausdruecklich eine eigene
App: "ich will dass es eine eigene app wird."
WAS SICH NICHT AENDERT: der Pfad /workspace/, der Dienst (4100), die
Datenbank, der Code. Getrennt wird ueber den HOSTNAMEN, nicht ueber
einen zweiten Prozess. Genau so machen es Hauptseite und Workspace
schon heute.
---------------------------------------------------------------------
DREI FALLEN, DIE MAN EINER BEDINGUNG NICHT ANSIEHT
---------------------------------------------------------------------
1. EIN MUSTER STATT EINER LISTE WAERE TOEDLICH.
/dogfather-universe\.com$/ passt auch auf
workspace.dogfather-universe.com -- und wuerde damit genau die
Adresse abschalten, die man schuetzen will. Deshalb hier zwei
feste Mengen und kein einziges Muster. (Dieselbe Ueberlegung
steht schon in workspace-umzug.js; sie hat dort einen Ausfall
verhindert und gilt hier unveraendert.)
2. "ALLES AUSSER crew." IST NICHT DASSELBE WIE "DIE ALTEN ADRESSEN".
Der naheliegende Satz waere: "Ein Modi darf ueberall rein, nur
nicht auf einer Adresse, die nicht crew heisst." Damit waeren
localhost, 127.0.0.1 und jede Pruefadresse eingeschlossen -- und
saemtliche Modi-Pruefungen wuerden ab sofort messen, dass ein
Modi nirgends hereinkommt, ohne dass irgendwo etwas rot wird.
Ein gruener Lauf, der nichts mehr prueft, ist schlimmer als ein
roter. Deshalb ist OHNE_MODI_HOSTS eine AUFZAEHLUNG der drei
echten Adressen. Wer eine vierte anlegt, traegt sie hier nach --
und pruef-crew-adresse.mjs sagt es ihm, wenn er es vergisst.
3. "FAENGT AN MIT /workspace" TRIFFT AUCH /workspaceXYZ.
Beim Workspace-Umzug waere das beinahe passiert. Hier gilt es
genauso, deshalb dieselbe Schreibweise: genau "/workspace" oder
alles unter "/workspace/", sonst nichts.
---------------------------------------------------------------------
WARUM DIE ALTE ADRESSE FUER MODIS ZUGEHT
---------------------------------------------------------------------
Ein Modi, der sich weiterhin auf workspace.dogfather-universe.com
anmelden koennte, haette zwei Anmeldungen, zwei Sitzungen und zwei
Apps auf dem Startbildschirm -- und der verborgene Zugang haette
damit eine zweite Spur genau dort, wo alle anderen arbeiten. Er
bekommt deshalb auf der alten Adresse KEINE Sitzung, sondern den
Hinweis auf die neue.
DASS DIESER HINWEIS DIE ADRESSE NENNT, IST KEIN LECK: Er erscheint
nur nach Eingabe eines gueltigen Modi-Codes. Wer den hat, ist Modi.
Fuer jeden anderen -- auch fuer jeden Manager mit gueltigem eigenen
Code -- veraendert sich an der alten Adresse ueberhaupt nichts.
---------------------------------------------------------------------
UND WARUM AUF DER NEUEN ADRESSE NUR MODIS HEREINKOMMEN
---------------------------------------------------------------------
Sonst waere crew. eine zweite, vollwertige Tuer in den Workspace --
und die erste Person, die sie zufaellig errät und ihren eigenen Code
eintippt, wuesste sofort, dass es hier noch etwas gibt. Ein fremder
Code bekommt dort deshalb dieselbe Antwort wie ein erfundener: die
Zugangswand sieht aus wie immer, und der Code stimmt nicht.
===================================================================== */
export const CREW_ADRESSE = "https://crew.dogfather-universe.com";
/* =====================================================================
DAS TEAM VON DOGI -- WELCHE ROLLEN DAZUGEHOEREN
Blueprint V3.0, Kapitel 1.1 und 3.1: DogFather (Owner), die "rechte
Hand" (Deputy, eine Person, austauschbar) und die Modis. Die beiden
letzten leben ausschliesslich auf dieser Adresse und sind fuer die
Workspace-Welt unsichtbar. DogFather steht in beiden Welten und
gehoert deshalb NICHT in diese Menge -- sie beantwortet die Frage
"wer ist hier verborgen", nicht "wer gehoert zum Team".
WARUM SIE HIER STEHT UND NICHT IN workspace.js, wo das uebrige
Rollenmodell liegt: workspace.js importiert diese Datei. Stuende die
Menge dort, muesste diese Datei zurueckimportieren -- ein Kreis, den
Node zwar aufloest, aber mit halb gefuellten Modulen, und das faellt
erst zur Laufzeit auf. Diese Datei hat bewusst KEINE eigenen
Importe; sie ist damit der einzige Ort, an dem so etwas gefahrlos
stehen kann. workspace.js gibt sie fuer die Fachmodule weiter. */
export const TEAM_DOGI_ROLLEN = new Set(["hand", "modi"]);
/* WER VON AUSSEN KOMMT (11.09.2026).
Die Community. Sie steht hier und nicht in workspace.js, weil diese
Datei von nichts abhaengt -- workspace.js importiert von hier, nicht
umgekehrt. Eine zweite Liste dort waere die, die auseinanderlaeuft.
Der Unterschied zu TEAM_DOGI_ROLLEN ist nicht die Verborgenheit,
sondern die Richtung: Das Team gehoert zum Haus und wird vor der
Agentur verborgen. Die Community gehoert NICHT zum Haus -- sie
bekommt nur, was ausdruecklich fuer sie da ist. */
export const AUSSEN_ROLLEN = new Set(["gast"]);
/* Die Adresse des Treffs. Eigene Wand, eigenes Haus -- und ausdruecklich
NICHT crew.: Diese Adresse ist absichtlich verborgen (kein Eintrag bei
Suchmaschinen, keine Rollennamen in ausgelieferten Dateien, Codes nur
persoenlich). Dutzende Zuschauer heben jede dieser Eigenschaften auf.
Nicht durch einen Fehler, sondern durch die Nutzung. */
const TREFF_HOSTS = new Set(["treff.dogfather-universe.com"]);
/** Die Adresse der Modi-App. Feste Menge, kein Muster -- Falle 1. */
const CREW_HOSTS = new Set(["crew.dogfather-universe.com"]);
/** Die echten Adressen, auf denen ein Modi nichts verloren hat.
* Aufzaehlung und ausdruecklich NICHT "alles ausser crew" -- Falle 2. */
const OHNE_MODI_HOSTS = new Set([
"dogfather-universe.com",
"www.dogfather-universe.com",
"workspace.dogfather-universe.com",
]);
/** Nur der Name, ohne Port und in Kleinschreibung.
* Hostnamen sind laut RFC 4343 gross/klein-unempfindlich; ein Browser
* darf "Workspace.Dogfather-Universe.com" schicken. */
function nurHost(hostKopfzeile) {
return String(hostKopfzeile || "").toLowerCase().split(":")[0];
}
/** Kommt die Anfrage ueber die Adresse der Modi-App? */
export function istCrewAdresse(hostKopfzeile) {
return CREW_HOSTS.has(nurHost(hostKopfzeile));
}
/** Ist das eine der Adressen, auf denen Modis nicht mehr arbeiten? */
export function istOhneModiAdresse(hostKopfzeile) {
return OHNE_MODI_HOSTS.has(nurHost(hostKopfzeile));
}
/** Eine Pruefadresse -- localhost und die Nummern, unter denen die
* Pruefungen ihren eigenen Server starten.
*
* Sie steht hier als EIGENE Funktion und nicht als "alles, was keine
* der echten Adressen ist". Genau diese Formulierung durch Ausschluss
* hat am 11.09.2026 dazu gefuehrt, dass der verborgene Zugang auf der
* neuen dritten Wand mitgalt, ohne dass es jemand entschieden haette.
* Wer eine vierte Adresse baut, muss sie hier NICHT eintragen -- und
* bekommt dadurch von selbst das sichere Verhalten. */
export function istPruefAdresse(hostKopfzeile) {
const h = nurHost(hostKopfzeile);
return h === "localhost" || h === "127.0.0.1" || h.startsWith("127.")
|| h === "::1" || h === "[::1]";
}
/** Ist das die Adresse des Treffs? */
export function istTreffAdresse(hostKopfzeile) {
return TREFF_HOSTS.has(nurHost(hostKopfzeile));
}
/** Gehoert dieser Pfad zum Workspace-Teil? Genau "/workspace" oder
* alles darunter -- aber NICHT /workspaceXYZ (Falle 3). */
export function istWorkspacePfad(pfad) {
const p = String(pfad || "");
return p === "/workspace" || p.startsWith("/workspace/");
}
/* =====================================================================
WELCHE WAND GEHOERT ZU WELCHER TUER (11.09.2026)
=====================================================================
Drei Zugangswaende liegen als drei Dateien im selben Ordner, und
express.static liefert jede aus, die man beim Namen nennt. Ohne eine
Regel kann also jeder jede aufrufen: die Community die Wand von Team
Dogi, das Team die Wand des Treffs, und beide auf der Agenturadresse.
DAS WAR SCHON EINMAL EIN LOCH, und gefunden hat es nicht das Lesen,
sondern der Wortleck-Test, der ALLE ausgelieferten Dateien durchsucht.
Damals stand die Regel als EIN Sonderfall im Code ("auf den alten
Adressen gibt es crew-index.html nicht"). Bei der dritten Wand waeren
daraus drei Sonderfaelle geworden, bei der vierten sechs. Deshalb
steht hier jetzt eine Tafel: Jede benannte Wand nennt die Adresse,
auf die sie gehoert, und die Frage wird einmal beantwortet.
404 UND KEINE WEITERLEITUNG: "Gibt es nicht" verraet nichts. Eine
Weiterleitung wuerde sagen, dass es die Datei gibt, nur woanders.
/workspace/index.html STEHT ABSICHTLICH NICHT IN DER TAFEL. Sie ist
keine benannte Wand, sondern die Vorgabe -- jede Adresse biegt sie
auf ihre eigene um, bevor daraus eine Datei wird. Stuende sie hier,
bekaeme man auf crew. und treff. ein 404 statt der eigenen Wand.
AUF PRUEFADRESSEN GILT DIE TAFEL NICHT, und das ist dieselbe
Ueberlegung wie bei OHNE_MODI_HOSTS: Sonst koennten die Pruefungen,
die jede Wand im Browser ansehen, keine mehr oeffnen -- sie blieben
gruen und wuerden nichts mehr messen. Ein gruener Lauf, der nichts
mehr prueft, ist schlimmer als ein roter. */
const BENANNTE_WAENDE = [
{ datei: "/workspace/crew-index.html", zuhause: istCrewAdresse },
{ datei: "/workspace/treff-index.html", zuhause: istTreffAdresse },
];
/** Wird hier eine Wand verlangt, die zu einer ANDEREN Tuer gehoert? */
export function istFremdeWand(hostKopfzeile, pfad) {
/* Mehrfache Schraegstriche zusammenziehen: express raeumt Punkt-
Segmente weg, doppelte Striche aber nicht -- und express.static
zieht sie danach selbst zusammen und liefert die Datei aus. Genau
daran ist am 04.09.2026 die Schranke des Workspace vorbeigelaufen. */
const p = String(pfad || "").toLowerCase().replace(/\/{2,}/g, "/");
const wand = BENANNTE_WAENDE.find((w) => w.datei === p);
if (!wand) return false;
if (istPruefAdresse(hostKopfzeile)) return false;
const benannt = istOhneModiAdresse(hostKopfzeile)
|| istCrewAdresse(hostKopfzeile) || istTreffAdresse(hostKopfzeile);
if (!benannt) return false;
return !wand.zuhause(hostKopfzeile);
}
/**
* Darf diese Person auf dieser Adresse angemeldet sein?
*
* Die eine Regel, aus der beide Richtungen folgen. Sie steht hier als
* eigene Funktion, damit sie ohne laufenden Server pruefbar ist -- und
* damit sie an GENAU EINER Stelle steht: sitzungLesen() in
* workspace.js. Jedes der 26 Fachmodule geht dort durch.
*
* @param {string} rolle Rolle der angemeldeten Person
* @param {string} hostKopfzeile Inhalt des Host-Kopffeldes
*/
export function sitzungPasstZurAdresse(rolle, hostKopfzeile) {
const team = TEAM_DOGI_ROLLEN.has(rolle);
/* AUSSENROLLEN GEHOEREN AUF GENAU EINE ADRESSE (11.09.2026).
Und die Bedingung steht in BEIDE Richtungen: Die Community kommt
nur auf treff. herein, und auf treff. kommt NUR sie herein. Das
Team sieht den Treff auf seiner eigenen Adresse -- es hat dort
nichts zu suchen, und ein Konto, das an zwei Waenden funktioniert,
ist eine Tuer, die man beim naechsten Umbau uebersieht. */
const aussen = AUSSEN_ROLLEN.has(rolle);
if (istTreffAdresse(hostKopfzeile)) return aussen;
if (aussen) return false;
/* crew.: das Team -- und DogFather, der in beiden Welten arbeitet. */
if (istCrewAdresse(hostKopfzeile)) return team || rolle === "admin";
/* Die echten alten Adressen: alle ausser dem Team. */
if (istOhneModiAdresse(hostKopfzeile)) return !team;
/* localhost, Pruefadressen: unberuehrt. */
return true;
}
/**
* Express-Zwischenschritt fuer die Adresse der Modi-App.
*
* Er macht zwei Dinge und ausdruecklich nichts mit Rechten -- die
* liegen in sitzungLesen():
*
* 1. NICHT INDIZIEREN. Die Adresse taucht heute in keinem oeffentlichen
* Zertifikatsprotokoll auf (nachgemessen am 10.09.2026: crt.sh
* kennt fuer dogfather-universe.com nur den Platzhalter-Eintrag).
* Eine Suchmaschine waere der zweite Weg, sie doch zu finden --
* der Kopf schliesst ihn. Er steht hier und nicht nur als
* <meta> im HTML, weil er dann auch fuer Bilder, Manifest und
* jede Antwort ohne HTML gilt.
*
* 2. NUR DER WORKSPACE. Auf crew. gibt es die Hauptseite nicht --
* sonst laege die komplette Dogfather-Website ein zweites Mal
* unter einer zweiten Adresse (doppelter Inhalt, und ein Weg,
* die Adresse ueber eine Suchmaschine zu finden). Alles ausserhalb
* von /workspace und /assets geht zur Zugangswand.
*
* Caddy tut Punkt 2 bereits mit derselben Weiche. Dass es hier ein
* zweites Mal steht, ist Absicht: Eine Schranke, die nur in einer
* Datei ausserhalb des Projekts existiert, faellt beim naechsten
* Serverumbau lautlos weg.
*/
export function crewWeiche(req, res, next) {
/* DIE FREMDE WAND -- fuer JEDE Adresse, auch fuer crew. selbst.
Sie steht vor der Weiche und nicht in ihrem Nein-Zweig. Dort stand
sie bis zum 11.09.2026, und das war richtig, solange es zwei Waende
gab: Die eigene kann man nicht "fremd" verlangen. Mit der dritten
stimmt das nicht mehr -- auf crew. ist die Wand des Treffs fremd,
und im Nein-Zweig waere diese Frage dort nie gestellt worden. */
if (istFremdeWand(req.get("host"), req.path)) {
return res.status(404).type("html").send("Nicht gefunden.");
}
if (!istCrewAdresse(req.get("host"))) return next();
res.setHeader("X-Robots-Tag", "noindex, nofollow");
/* DAS MANIFEST MACHT DIE APP (10.09.2026).
Beide Adressen liefern dieselben HTML-Dateien aus -- in jeder steht
<link rel="manifest" href="/workspace/app.webmanifest">. Auf der
Modi-Adresse soll dahinter aber ein anderes Manifest stehen: eigener
Name ("Team Dogi"), eigenes Symbol. Sonst hiesse die App auf dem
Startbildschirm eines Modis "Creator Workspace" und traege das
Zeichen mit der Chili -- die zu Spicy Media gehoert, nicht zu ihnen.
WARUM DIE ADRESSE UMGEBOGEN WIRD, STATT IN 30 HTML-DATEIEN EINE
ZWEITE ZEILE ZU SETZEN: Eine zweite Zeile muesste jemand bei jeder
neuen Seite mitschreiben, und wer sie vergisst, bekommt eine Seite,
die still zur falschen App gehoert. Hier steht es einmal.
ZWISCHENSPEICHER: Cloudflare nimmt den Hostnamen in den Schluessel
auf, die beiden Antworten koennen sich also nicht vermischen. Der
Browser ohnehin nicht -- fuer ihn sind es zwei Ursprunge. */
if (req.path === "/workspace/app.webmanifest") {
req.url = "/workspace/crew.webmanifest";
return next();
}
/* DIE ZUGANGSWAND GEHOERT DOGI UND DEN MODIS (10.09.2026).
Filipe: "alles soll auf dogfather und die modis perfektionniert
werden auf der neuen modi seite."
Bis dahin stand hier die gewohnte Wand: Spicy-Media-Logo, "Creator
Workspace", fuenf Rollenkacheln -- fuer einen Modi war davon nichts
richtig. Jetzt liefert crew. eine eigene Seite mit eigener Buehne,
eigenem Namen und ohne Kachelreihe.
DAS KEHRT EINE FRUEHERE ENTSCHEIDUNG UM, und das gehoert
hierhergeschrieben: Vorher war die Wand absichtlich identisch --
wer die Adresse errat, sollte etwas Vertrautes sehen und nichts
ueber Modis erfahren. Filipe hat anders entschieden. Der Tausch
ist damit bewusst: Ein Ratender liest jetzt "Team Dogi". Alles
andere bleibt, wie es war -- sein Code funktioniert dort nicht.
ZWEI ADRESSEN, EINE DATEI: `/workspace/` und
`/workspace/index.html` fuehren beide zur Wand, also muessen beide
umgebogen werden. Die zweite zu vergessen waere nicht aufgefallen,
denn im Alltag tippt sie niemand. */
if (req.path === "/workspace/" || req.path === "/workspace/index.html") {
req.url = "/workspace/crew-index.html";
return next();
}
/* DIE BUEHNEN INNEN GEHOEREN AUCH DER MODI-APP (10.09.2026).
Filipe: "auch die hintergrund bilder vom crew espace sollen anderes
aussehen, der community angepasst wie die zugangscode seite die ist
mega."
Die neun Buehnen hinter den Seiten zeigen nicht bloss rotes Licht,
sondern das Spicy-Media-Logo selbst -- in `halle` und `arena` sogar
vielfach nebeneinander. Umfaerben haette daraus ein blaues fremdes
Logo gemacht, also etwas Schlimmeres. Es gibt jetzt eigene Motive
aus den Community-Bildern der Dogfather-Seite (tools/crew-buehnen.mjs).
WARUM DIE ADRESSE UMGEBOGEN WIRD UND NICHT DAS CSS: `start.css`
nennt die neun Bilder in neun Zeilen und wird an alle
ausgeliefert. Eine zweite Zeile je Szene fuer die Modi-App waere
achtzehn Zeilen, die zusammenpassen muessen -- und der Name der
Szene stuende dann doppelt da. Hier steht eine Regel.
UND SIE HAT KEIN FLACKERN: Das Bild wird beim ERSTEN Abruf schon
als das richtige geliefert. Eine Umschaltung per JavaScript haette
erst die Spicy-Buehne gezeigt und dann getauscht -- sichtbar, und
ausgerechnet auf der Seite, die niemand sehen soll. */
const buehne = /^\/workspace\/assets\/img\/(buehne-[a-z]+-(?:uhd|breit|schmal)\.webp)$/
.exec(req.path);
if (buehne) {
req.url = `/workspace/assets/img/crew-${buehne[1]}`;
return next();
}
/* DAS ZEICHEN IN DER KOPFLEISTE (10.09.2026).
`start.css` setzt links neben den Namen eine Chili -- als
CSS-Hintergrund, nicht als Bild im HTML. Auf der Modi-Adresse stand
damit oben links das Zeichen von Spicy Media, auf jeder Seite, den
ganzen Tag. Im Bildschirmfoto der Startseite war es das Erste, was
auffiel.
UEBER DIE ADRESSE UND NICHT UEBER JAVASCRIPT: Eine Umschaltung im
Browser haette erst die Chili gezeigt und sie dann getauscht --
sichtbar, und ausgerechnet an der Stelle, die man zuerst ansieht.
So kommt beim ersten Abruf schon der Husky.
Er liegt laengst da (marke-husky.webp) und wird auf der Zugangswand
und im App-Symbol ohnehin benutzt. Ein neues Bild waere eine Datei
mehr fuer dasselbe Zeichen. */
if (req.path === "/workspace/assets/img/marke-spicy.webp") {
req.url = "/workspace/assets/img/marke-husky.webp";
return next();
}
/* DAS HAUS (10.09.2026).
Filipe: "die leiste da und alles andere was noch rot ist auf team
dogi seite soll lila werden. richtig geiles lila und babyblau
mischung ueberall." Und davor: "ich will doch dass der eingang
hier getrennt ist von der workspace seite … aber es soll trotzdem
so bleiben dass ich die daten hier und da sehe."
Getrennt wird also das AUSSEHEN, nicht der Bestand. Dieselbe
Datenbank, dieselben Seiten, dasselbe Programm -- und zwei
Haeuser, die man nicht verwechseln kann.
Jede Seite laedt als LETZTE Stilvorlage `haus.css`. Auf der
Agenturadresse ist die leer, hier steht dahinter das ganze andere
Farbhaus. Warum ueber den Dateinamen und nicht ueber ein Attribut
am <html>: Ein Attribut muesste entweder JavaScript setzen (dann
laedt die Seite erst im falschen Ton und faerbt sich um -- auf
jeder Seite, bei jedem Aufruf) oder der Server muesste jede
HTML-Antwort umschreiben statt sie als Datei auszuliefern.
Der Dateiname reist mit einer Fassungsnummer (`?v=…`); die
Bedingung sieht deshalb nur auf den PFAD, nicht auf die ganze
Adresse. Genau daran waere sie sonst gescheitert -- lautlos, denn
ein nicht umgebogener Pfad liefert weiterhin eine gueltige
Datei. */
if (req.path === "/workspace/assets/css/haus.css") {
req.url = "/workspace/assets/css/crew-haus.css"
+ (req.url.includes("?") ? req.url.slice(req.url.indexOf("?")) : "");
return next();
}
if (istWorkspacePfad(req.path) || req.path.startsWith("/assets/")) return next();
return res.redirect(302, "/workspace/");
}