Der Treff zieht in Team Dogi ein — die dritte Adresse ist wieder weg

Filipe, nachdem er die dritte Wand gesehen hatte: "das soll keine app
für sich sein, dass soll in der crew seite adaptiert werden, da rein
perfektionniert."

WAS VERSCHWINDET: treff.dogfather-universe.com samt Weiche
(treff-adresse.js), Zugangswand, Manifest und acht Bühnenbildern. Kein
DNS-Eintrag, kein zweiter Caddy-Block, kein zweites App-Symbol.

Die Gründe, die DAFÜR sprachen, stehen jetzt als Kommentar in
crew-adresse.js statt als Code -- sie gelten weiter, und beim nächsten
Mal wird jemand dieselbe Idee haben: eine App je Ursprung, und ein
Schloss mehr zwischen der Community und den Daten der Agentur.

WAS DER VERZICHT KOSTET, benannt statt übersehen:
 · Die Community steht vor derselben Wand wie das Team und liest dort
   die Namen der drei Team-Rollen. Filipes Entscheidung auf die Frage:
   vierte Kachel "Community" statt gar keiner Kacheln.
 · Ein Schloss weniger. Was vorher die Adresse getrennt hat, muss jetzt
   jede einzelne Regel halten -- deshalb prüft pruef-treff-werkzeuge
   seit heute zehn Dinge mehr (70 statt 60).

EINE LÜCKE, DIE DABEI AUFGEFALLEN IST -- und die es schon vorher gab:
Ein Mitglied der Community stand in der Auswahl, wen man zu einem
Termin einlädt, wem man eine Aufgabe gibt und mit wem man einen Chat
anfängt. Für DogFather bedeutet fast jede Liste "alle". Jetzt zu, über
eine Hülle (ohneAussen) um die fünf Listen, die von Zusammenarbeit
handeln -- damit sie auch für die Listen gilt, die es noch nicht gibt.
Die Verwaltungsliste in "Personen & Zugänge" zeigt sie weiterhin, sonst
legt er einen Zugang an und der verschwindet im selben Moment.

DREI BEFUNDE AUS DEN PRÜFUNGEN, wieder keiner vom Lesen:
 · Mein eigener Kommentar auf der Wand nannte eine Rolle der Agentur --
   in einer Datei, die jedes Community-Mitglied im Quelltext liest.
   Zum zweiten Mal an einem Tag, und zum zweiten Mal ausgerechnet in
   einem Kommentar, der erklärt, warum man das nicht tut.
 · Die Prüfung "der Satz nennt die Modis" durchsuchte den QUELLTEXT und
   wäre grün geblieben, obwohl der Satz auf dem Bildschirm längst ein
   anderer ist -- sie fand ihn in einem Kommentar. Sie misst jetzt die
   sichtbare Unterzeile.
 · Der erste Entwurf der Adressregel sperrte die Community auch auf
   localhost aus -- eine Bedingung durch AUSSCHLUSS, zum dritten Mal an
   einem Tag. Jede Zeile nennt jetzt die Adresse, FÜR DIE sie gilt.

Und zwei feste Zahlen weniger: Die Kachelreihe wird nicht mehr gezählt,
sondern beim Namen genannt (admin, hand, modi, gast) -- eine Zahl war
dort schon zweimal rot, ohne dass etwas kaputt war. Der App-Name wird
nicht nur geprüft, sondern der UNTERSCHIED zur Agenturadresse.

Die App heißt auf crew. jetzt "DogFather Universe" statt "Team Dogi" --
sie gehört ab heute beiden (Entscheidung Filipe).

Geprüft: rollen 312 · crew-adresse 132 · kalender 104 · sicht 84 ·
modi-verborgen 80 · chat-kanaele 79 · treff-werkzeuge 70 · haus-trennung
62 · treff 58 · chat 48 · treff-seiten 42 · bereiche-lesend 37 ·
start-ansicht 147 · css-klassen 30 · zwischenspeicher 21 · alle-wege 19 ·
rechtetafel 19 -- alles grün.

Die 58 bei pruef-treff sind elf weniger als gestern: Mit der dritten
Adresse fallen ihre 26 Weichen-Prüfungen weg, ersetzt durch 10 für die
eine Wand plus die neuen in 7b.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-11 18:38:05 +02:00
co-authored by Claude Opus 5
parent 1ebaf8a864
commit 39dd666b17
47 changed files with 856 additions and 987 deletions
+64 -26
View File
@@ -105,14 +105,36 @@ export const TEAM_DOGI_ROLLEN = new Set(["hand", "modi"]);
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"]);
/* DER TREFF HAT KEINE EIGENE ADRESSE (Entscheidung Filipe, 11.09.2026:
"das soll keine app fuer sich sein, das soll in der crew seite
adaptiert werden").
/** Die Adresse der Modi-App. Feste Menge, kein Muster -- Falle 1. */
Am Vormittag stand hier treff.dogfather-universe.com -- eine dritte
Tuer mit eigener Wand, eigenem Manifest, eigenen Buehnenbildern. Sie
ist wieder weg, und das gehoert aufgeschrieben, weil die Gruende
dafuer weiterhin gelten und beim naechsten Mal jemand dieselbe Idee
haben wird:
WAS DAFUER SPRACH: Auf einem Ursprung laesst sich genau EINE App
installieren. Und zwischen einem Mitglied der Community und den
Daten der Agentur stand damit ein Schloss mehr.
WAS DAGEGEN ENTSCHIEDEN HAT: Es waere ein drittes Haus gewesen --
mit eigener Wand, eigenem Namen, eigener App neben Team Dogi. Der
Treff ist aber kein drittes Haus, sondern ein Raum in Dogis.
WAS DER VERZICHT KOSTET, ehrlich benannt: Die Community steht jetzt
vor derselben Wand wie das Team und liest dort die Namen der drei
Team-Rollen (Filipes Entscheidung: vierte Kachel "Community" statt
gar keiner Kacheln). Und sie ist auf demselben Ursprung angemeldet
wie die Modis -- die Trennung haengt damit allein an der
Rechtetafel und an sitzungLesen(), nicht mehr zusaetzlich an der
Adresse. Das ist der Grund, warum pruef-treff seit heute NICHT
weniger prueft, sondern mehr: Was vorher die Adresse erledigt hat,
muss jetzt jede einzelne Regel halten. */
/** Die Adresse von Team Dogi -- und seit 11.09.2026 auch die des
* Treffs. 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.
@@ -155,11 +177,6 @@ export function istPruefAdresse(hostKopfzeile) {
|| 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) {
@@ -197,9 +214,12 @@ export function istWorkspacePfad(pfad) {
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. */
/* EINE benannte Wand, seit der Treff keine eigene mehr hat. Die Tafel
bleibt trotzdem eine Tafel und wird nicht wieder zum Sonderfall: Sie
ist der Ort, an dem die naechste Wand eingetragen wird, ohne dass
jemand drei Bedingungen umbauen muss. */
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? */
@@ -212,8 +232,7 @@ export function istFremdeWand(hostKopfzeile, pfad) {
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);
const benannt = istOhneModiAdresse(hostKopfzeile) || istCrewAdresse(hostKopfzeile);
if (!benannt) return false;
return !wand.zuhause(hostKopfzeile);
}
@@ -234,18 +253,37 @@ export function sitzungPasstZurAdresse(rolle, hostKopfzeile) {
/* 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. */
NUR auf crew. herein (dort liegt der Treff), und auf den alten
Adressen kommt sie gar nicht herein. Ein Konto, das an zwei
Waenden funktioniert, ist eine Tuer, die man beim naechsten Umbau
uebersieht.
SEIT DEM 11.09.2026 IST DIESE ADRESSE crew. UND NICHT treff.
(Filipe: "das soll keine app fuer sich sein"). Die Richtung der
Regel hat sich dadurch umgedreht, die Regel selbst nicht: Es gibt
genau eine Adresse, auf der die Community angemeldet sein darf. */
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. */
/* crew.: das Team, die Community -- und DogFather, der in beiden
Welten arbeitet. */
if (istCrewAdresse(hostKopfzeile)) return team || aussen || rolle === "admin";
/* Die echten alten Adressen: alle ausser dem Team und der Community. */
if (istOhneModiAdresse(hostKopfzeile)) return !team && !aussen;
/* localhost, Pruefadressen: unberuehrt.
UND DAS GILT AUCH FUER DIE COMMUNITY (gemessen 11.09.2026). Der
erste Entwurf hatte hier ein "wer von aussen ist, kommt sonst
nirgends herein" stehen -- eine Bedingung durch AUSSCHLUSS, und sie
traf damit auch localhost. Ergebnis: Jede Pruefung des Treffs haette
ab sofort gemessen, dass ein Mitglied nirgends hereinkommt, und
waere gruen geblieben, ohne noch irgendetwas zu pruefen. Genau die
Falle, vor der oben in diesem Kopf Nummer 2 warnt -- und ich bin
am selben Tag zum dritten Mal hineingelaufen.
Jetzt nennt jede Zeile die Adresse, FUER DIE sie gilt. Wer eine
vierte baut, faellt hier unten heraus und bekommt "erlaubt" --
das ist auf einer Pruefadresse richtig und auf einer echten faellt
es sofort auf, weil pruef-crew-adresse jede echte Adresse
einzeln aufzaehlt. */
return true;
}
-16
View File
@@ -13,7 +13,6 @@ import { fileURLToPath } from "node:url";
import { gateMiddleware } from "./gate.js";
import { workspaceUmzug } from "./workspace-umzug.js";
import { crewWeiche } from "./crew-adresse.js";
import { treffWeiche } from "./treff-adresse.js";
import { webdesignGate } from "./webdesign-gate.js";
import { inhaltsrichtlinie } from "./inhaltsrichtlinie.js";
import { workspaceRouter, sichtSetzen } from "./workspace.js";
@@ -129,21 +128,6 @@ app.use(workspaceUmzug);
gehen. Zwei Orte fuer dieselbe Regel waeren einer zu viel. */
app.use(crewWeiche);
/* Die eigene Adresse des Treffs (11.09.2026): treff.dogfather-universe.com.
Begruendung in treff-adresse.js, geprueft in pruef-treff-adresse.mjs.
DIREKT HINTER crewWeiche UND NICHT DAVOR. Die Reihenfolge ist keine
Geschmacksfrage: crewWeiche beantwortet ueber die Wandtafel fuer JEDE
Adresse die Frage "wird hier eine fremde Zugangswand verlangt?" --
auch fuer treff. Stuende treffWeiche davor, wuerde sie
/workspace/crew-index.html erst auf die Treff-Wand umbiegen und die
Tafel kaeme nie zum Zug. Ein Mitglied der Community saehe dann keine
404, sondern seine eigene Wand -- und niemandem waere aufgefallen,
dass die Sperre nicht mehr greift.
Auch sie vergibt KEINE Rechte. Wer auf welcher Adresse angemeldet
sein darf, entscheidet sitzungLesen() in workspace.js. */
app.use(treffWeiche);
/* Inhaltsrichtlinie (26.08.2026). Steht bewusst HIER -- vor jeder
Schranke und vor express.static: Auch die Zugangswand und die
+50 -5
View File
@@ -320,7 +320,22 @@ try { mc = JSON.parse(manifestCrew.text); } catch { /* bleibt leer */ }
try { mw = JSON.parse(manifestWs.text); } catch { /* bleibt leer */ }
ok(manifestCrew.status === 200 && manifestWs.status === 200,
"beide Adressen liefern ein Manifest");
ok(mc.name === "Team Dogi", `crew.: die App heisst "Team Dogi" (gelesen: ${mc.name || "?"})`);
/* DER NAME GILT SEIT DEM 11.09.2026 FUER BEIDE (Entscheidung Filipe).
Er hiess "Team Dogi". Seit der Treff hier wohnt, wuerde ein Mitglied
der Community diesen Namen auf seinem Startbildschirm haben -- den
Namen eines Bereichs, zu dem es nicht gehoert. Das Manifest gilt je
ADRESSE und kann sich nicht nach der Rolle richten; also einer, der
fuer beide stimmt.
GEPRUEFT WIRD NICHT NUR DER NAME, SONDERN DER UNTERSCHIED. Ein
fester Name allein waere beim naechsten Umbenennen wieder rot, ohne
dass etwas kaputt ist. Dass die beiden Adressen sich UNTERSCHEIDEN,
ist die Eigenschaft, um die es geht -- sonst waere es eine App. */
ok(mc.name === "DogFather Universe",
`crew.: die App heisst "DogFather Universe" (gelesen: ${mc.name || "?"})`);
ok(mc.name && mw.name && mc.name !== mw.name,
`und anders als auf der Agenturadresse ("${mw.name}")`);
ok(mw.name === "Creator Workspace — Spicy & Dogi",
`workspace.: dort heisst sie unveraendert (gelesen: ${mw.name || "?"})`);
ok(Array.isArray(mc.icons) && mc.icons.length > 0
@@ -367,13 +382,43 @@ ok(/Team&nbsp;Dogi|Team Dogi/.test(wandCrew.text), "crew.: dort steht Team Dogi"
ok(/DogFather/.test(wandCrew.text), "crew.: und DogFather daneben");
ok(!/Spicy/i.test(wandCrew.text), "crew.: von Spicy Media steht dort nichts mehr");
ok(!/Creator/i.test(wandCrew.text), "crew.: und vom Creator Workspace auch nicht");
ok(/die Modis/.test(wandCrew.text), "crew.: der Satz nennt DogFather und die Modis");
/* DER SATZ AUF DER WAND MUSS FUER BEIDE STIMMEN (11.09.2026).
/* Die Kachelreihe ist weg -- auf einer Adresse mit genau einer Sorte
Zugang waere sie eine Bedienhuerde, keine Auswahl. */
Hier stand `/die Modis/` -- und der Satz lautete "Privater Bereich
fuer DogFather und die Modis". Seit die Community durch dieselbe Wand
kommt, liest sie ihn auch, und fuer sie ist er schlicht falsch.
UND DIE ALTE PRUEFUNG WAERE TROTZDEM GRUEN GEBLIEBEN: Sie durchsuchte
den QUELLTEXT, und dort steht "die Modis" weiterhin in einem
Kommentar. Sie haette also bestaetigt, dass ein Satz dasteht, den es
auf dem Bildschirm gar nicht mehr gibt. Gemessen wird deshalb die
sichtbare Unterzeile, nicht die Datei. */
{
const unter = /<p class="unterzeile">([^<]*)<\/p>/.exec(wandCrew.text)?.[1] || "";
ok(/Team\s*Dogi/.test(unter) && /Treff/.test(unter),
`crew.: die Unterzeile nennt Team Dogi und den Treff ("${unter.trim()}")`);
ok(!/Arbeitsbereich/.test(unter),
"und behauptet nicht mehr, das hier sei nur zum Arbeiten");
}
/* DIE KACHELREIHE HAT SEIT DEM 11.09.2026 VIER EINTRAEGE.
Die Geschichte dieser Zeile ist lehrreich und steht deshalb hier:
Erst gab es keine Kachelreihe (eine Sorte Zugang, eine Reihe waere
eine Huerde gewesen). Dann drei ("3 rollen. dogfather. rechte hand
und modis"). Jetzt vier, weil der Treff hier eingezogen ist.
GEPRUEFT WIRD NICHT DIE ZAHL, SONDERN WELCHE. Eine Zahl war schon
zweimal rot, ohne dass etwas kaputt war. Die NAMEN dagegen sagen
etwas: Steht dort eines Tages "manager", ist das ein Befund und kein
Umbau. */
const rollenAufWand = [...wandCrew.text.matchAll(/data-rolle="([a-z]+)"/g)].map((m) => m[1]);
ok(JSON.stringify(rollenAufWand) === JSON.stringify(["admin", "hand", "modi", "gast"]),
`crew.: die vier Kacheln in dieser Reihenfolge (${rollenAufWand.join(", ")})`);
const kachelnCrew = (wandCrew.text.match(/class="rolle"/g) || []).length;
const kachelnWs = (wandWs.text.match(/class="rolle"/g) || []).length;
ok(kachelnCrew === 3, `crew.: drei Rollenkacheln (gezaehlt: ${kachelnCrew})`);
ok(kachelnCrew === rollenAufWand.length,
`crew.: ${kachelnCrew} Rollenkacheln -- so viele, wie es Rollen auf der Wand gibt`);
for (const [rolle, name] of [["admin", "DogFather"], ["hand", "Rechte Hand"], ["modi", "Modi"]]) {
ok(wandCrew.text.includes(`data-rolle="${rolle}"`) && wandCrew.text.includes(`>${name}<`),
`crew.: die Kachel "${name}" steht da`);
+95 -23
View File
@@ -64,9 +64,9 @@ let fehler = 0, geprueft = 0;
const melde = (t) => console.log(t);
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
const TREFF = "treff.dogfather-universe.com";
const CREW = "crew.dogfather-universe.com";
const HAUS = "workspace.dogfather-universe.com";
const HAUPT = "dogfather-universe.com";
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
@@ -153,8 +153,8 @@ async function anmelden(rolle, code, host) {
const kDogi = await anmelden("admin", "CODE-DOGI-0001", HAUS);
const kModi = await anmelden("modi", "CODE-MODI-0001", CREW);
const kKessi = await anmelden("gast", "CODE-GAST-0001", TREFF);
const kBo = await anmelden("gast", "CODE-GAST-0002", TREFF);
const kKessi = await anmelden("gast", "CODE-GAST-0001", CREW);
const kBo = await anmelden("gast", "CODE-GAST-0002", CREW);
ok(!!kDogi && !!kModi && !!kKessi && !!kBo, "alle vier sind angemeldet");
/* =======================================================================
@@ -164,24 +164,24 @@ melde("");
melde("=== 1. Will ich auch ===");
{
const weg = `/workspace/api/treff/eintrag/${wunsch1}/willich`;
const a = await roh(weg, TREFF, { cookie: kKessi }, {}, "PUT");
const a = await roh(weg, CREW, { cookie: kKessi }, {}, "PUT");
ok(a.code === 200 && json(a).stimmen === 1, `Kessi stimmt ab (${json(a).stimmen})`);
/* ZWEIMAL DRUECKEN IST EINMAL. Das ist die eigentliche Regel: Der
zusammengesetzte Schluessel laesst gar keine zweite Zeile zu. */
const b = await roh(weg, TREFF, { cookie: kKessi }, {}, "PUT");
const b = await roh(weg, CREW, { cookie: kKessi }, {}, "PUT");
ok(b.code === 200 && json(b).stimmen === 1, `zweimal druecken aendert nichts (${json(b).stimmen})`);
const c = await roh(weg, TREFF, { cookie: kBo }, {}, "PUT");
const c = await roh(weg, CREW, { cookie: kBo }, {}, "PUT");
ok(c.code === 200 && json(c).stimmen === 2, `Bo auch (${json(c).stimmen})`);
const e = await roh(weg, TREFF, { cookie: kKessi }, {}, "DELETE");
const e = await roh(weg, CREW, { cookie: kKessi }, {}, "DELETE");
ok(e.code === 200 && json(e).stimmen === 1 && json(e).meine === false,
`Kessi nimmt sie zurueck (${json(e).stimmen})`);
/* Und die Zahl kommt am Brett an -- sonst waere sie eine Zahl, die
nur die Route kennt. */
const brett = await roh("/workspace/api/bereich/wunsch", TREFF, { cookie: kBo });
const brett = await roh("/workspace/api/bereich/wunsch", CREW, { cookie: kBo });
const zeile = (json(brett).eintraege || []).find((x) => x.id === wunsch1);
ok(zeile?.stimmen === 1 && zeile?.meine_stimme === 1,
`am Brett steht sie auch (${zeile?.stimmen}, meine ${zeile?.meine_stimme})`);
@@ -190,7 +190,7 @@ melde("=== 1. Will ich auch ===");
diese Zeile waere "es geht" auch dann gruen, wenn es ueberall
ginge -- und dann waere die Wunschliste keine Abstimmung mehr,
sondern ein Nebeneffekt. */
const f = await roh(`/workspace/api/treff/eintrag/${bosBeitrag}/willich`, TREFF,
const f = await roh(`/workspace/api/treff/eintrag/${bosBeitrag}/willich`, CREW,
{ cookie: kKessi }, {}, "PUT");
ok(f.code === 400, `im Gespraech gibt es kein "Will ich auch" (${f.code})`);
}
@@ -225,7 +225,7 @@ melde("=== 2. Anheften ===");
ok(nochmal.code === 200, `nach dem Abnehmen geht die vierte (${nochmal.code})`);
/* Und die Community heftet nichts an. */
const gast = await roh(`/workspace/api/treff/eintrag/${anschlag[1]}/anheften`, TREFF,
const gast = await roh(`/workspace/api/treff/eintrag/${anschlag[1]}/anheften`, CREW,
{ cookie: kKessi }, {}, "PUT");
ok(gast.code === 404, `ein Mitglied kann nichts anheften (${gast.code})`);
@@ -241,13 +241,13 @@ melde("");
melde("=== 3. Melden ===");
{
const weg = `/workspace/api/treff/eintrag/${bosBeitrag}/melden`;
const ohne = await roh(weg, TREFF, { cookie: kKessi }, { grund: "" });
const ohne = await roh(weg, CREW, { cookie: kKessi }, { grund: "" });
ok(ohne.code === 400, `ohne Grund geht es nicht (${ohne.code})`);
const kurz = await roh(weg, TREFF, { cookie: kKessi }, { grund: "doof" });
const kurz = await roh(weg, CREW, { cookie: kKessi }, { grund: "doof" });
ok(kurz.code === 400, `"doof" ist kein Grund (${kurz.code})`);
const mit = await roh(weg, TREFF, { cookie: kKessi },
const mit = await roh(weg, CREW, { cookie: kKessi },
{ grund: "Da steht die Handynummer von jemandem drin." });
ok(mit.code === 200, `mit Grund geht es (${mit.code})`);
@@ -260,7 +260,7 @@ melde("=== 3. Melden ===");
/* Die Community sieht die Meldungen NICHT -- sonst waere ablesbar,
wer wen gemeldet hat. */
const gast = await roh("/workspace/api/treff/meldungen", TREFF, { cookie: kBo });
const gast = await roh("/workspace/api/treff/meldungen", CREW, { cookie: kBo });
ok(gast.code === 404, `ein Mitglied sieht die Liste nicht (${gast.code})`);
/* Entscheiden braucht ebenfalls einen Satz. */
@@ -366,7 +366,7 @@ melde("=== 6. Ausschluss ===");
/* "dabei" und nicht "stamm": Kessi ist 40 Tage dabei, hat aber
keinen eigenen Beitrag geschrieben. Beide Bedingungen muessen
erfuellt sein -- genau das misst diese Zeile nebenbei mit. */
const vorher = await roh("/workspace/api/treff/lage", TREFF, { cookie: kKessi });
const vorher = await roh("/workspace/api/treff/lage", CREW, { cookie: kKessi });
ok(vorher.code === 200 && json(vorher).stufe === "dabei",
`Kessi ist drin, Stufe ${json(vorher).stufe}`);
@@ -378,24 +378,24 @@ melde("=== 6. Ausschluss ===");
/* DIE SITZUNG IST WEG, nicht nur das Schreiben. Ein
Ausgeschlossener, der weiter mitlesen kann, ist bei Belaestigung
genau der Teil, der weh tut. */
const lage = await roh("/workspace/api/treff/lage", TREFF, { cookie: kKessi });
const lage = await roh("/workspace/api/treff/lage", CREW, { cookie: kKessi });
ok(lage.code === 401, `ihre Sitzung gilt nicht mehr (${lage.code})`);
const brett = await roh("/workspace/api/bereich/treff", TREFF, { cookie: kKessi });
const brett = await roh("/workspace/api/bereich/treff", CREW, { cookie: kKessi });
ok(brett.code === 401, `und sie liest auch nichts mehr (${brett.code})`);
/* Und sie kommt auch nicht wieder herein -- gar nicht erst. Ohne
diese Zeile waere die Anmeldung gelungen, das Plaetzchen gesetzt,
und dahinter eine Seite, auf der nichts geht. Das sieht aus wie
ein kaputtes Programm, nicht wie eine Entscheidung. */
const neu = await anmelden("gast", "CODE-GAST-0001", TREFF);
const neu = await anmelden("gast", "CODE-GAST-0001", CREW);
ok(!neu, "und sie kann sich nicht neu anmelden");
/* GEGENPROBE: Bo hat nur eine PAUSE -- kein Ausschluss. Er darf
weiter lesen, aber nicht schreiben. Ohne diese Zeile waeren die
vier darueber auch dann gruen, wenn jede Massnahme jeden
aussperrt. */
const boLage = await roh("/workspace/api/treff/lage", TREFF, { cookie: kBo });
const boLage = await roh("/workspace/api/treff/lage", CREW, { cookie: kBo });
ok(boLage.code === 200, `Bo liest weiter (${boLage.code})`);
ok(json(boLage).sperre?.art === "pause" && !!json(boLage).sperre?.bis,
`und sieht seine Pause mit Enddatum (${json(boLage).sperre?.bis?.slice(0, 10)})`);
@@ -403,10 +403,10 @@ melde("=== 6. Ausschluss ===");
/* Und Pim, sieben Tage ausgeschlossen, kommt gar nicht mehr herein
-- ein befristeter Ausschluss ist ein Ausschluss, keine Pause. */
const pim = await anmelden("gast", "CODE-GAST-0003", TREFF);
const pim = await anmelden("gast", "CODE-GAST-0003", CREW);
ok(!pim, "ein befristeter Ausschluss sperrt ebenfalls aus");
const versuch = await roh("/workspace/api/bereich/treff", TREFF, { cookie: kBo },
const versuch = await roh("/workspace/api/bereich/treff", CREW, { cookie: kBo },
{ art: ersteArt("treff"), titel: "BO-TROTZDEM", text: "Hallo?", datum: heute });
ok(versuch.code === 403, `und es geht auch wirklich nicht (${versuch.code})`);
}
@@ -431,17 +431,89 @@ melde("=== 7. Die Bruecke zu den Talenten ===");
/* Die Community kommt an die Talente nicht heran -- sonst waere die
Bruecke ein Fenster. */
const gast = await roh("/workspace/api/bereich/talente", TREFF, { cookie: kBo });
const gast = await roh("/workspace/api/bereich/talente", CREW, { cookie: kBo });
ok(gast.code === 404, `ein Mitglied sieht die Talente nicht (${gast.code})`);
}
/* =======================================================================
7b. DIE COMMUNITY STEHT IN KEINER ARBEITSLISTE — aber in der Verwaltung
Seit der Treff in Team Dogi eingezogen ist, sind Mitglieder und Team
auf derselben Adresse. Was vorher die Adresse getrennt hat, muss
jetzt jede einzelne Liste halten.
DREI LISTEN, ZWEI ANTWORTEN. Einladen und Chatten: nein, und zwar
auch für DogFather, der sonst überall "alle" bekommt. Verwaltung: ja
— sonst legt er einen Zugang an und der verschwindet im selben
Moment aus der Liste.
MIT GEGENPROBE IN BEIDE RICHTUNGEN: Jede "steht nicht drin"-Zeile
steht neben einer, die beweist, dass die Liste überhaupt jemanden
enthält. Eine leere Liste erfüllt sonst jede Nein-Bedingung.
======================================================================= */
melde("");
melde("=== 7b. Keine Arbeitsliste, aber die Verwaltung ===");
{
const namen = (a) => {
try {
const j = JSON.parse(a.text);
const feld = Object.values(j).find(Array.isArray) || [];
return feld.map((x) => x?.name).filter(Boolean);
} catch { return []; }
};
for (const [was, weg] of [
["die Einladungsliste", "/workspace/api/einladbar"],
["die Chat-Partner", "/workspace/api/chat/partner"],
]) {
const a = await roh(weg, HAUS, { cookie: kDogi });
const liste = namen(a);
/* DIE ZAHL GEHÖRT IN DIE BEDINGUNG: Wäre die Liste leer, wäre
"Kessi steht nicht drin" trivial wahr. */
ok(a.code === 200 && liste.length > 0,
`${was} hat überhaupt Einträge (${liste.length})`);
ok(!liste.includes("Kessi") && !liste.includes("Bo"),
`${was} enthält niemanden aus der Community${
liste.filter((n) => n === "Kessi" || n === "Bo").join(", ")}`);
ok(liste.includes("Frida"),
`aber den Modi — ${was} filtert nicht einfach alles weg`);
}
/* UND DIE VERWALTUNG ZEIGT SIE. Auf der Team-Adresse, denn dort
wohnt der Treff jetzt. */
const verwaltung = await roh("/workspace/api/personen", CREW, { cookie: kDogi });
const inVerwaltung = namen(verwaltung);
ok(verwaltung.code === 200 && inVerwaltung.includes("Kessi"),
`in "Personen & Zugänge" auf crew. steht die Community (${inVerwaltung.length} Personen)`);
ok(inVerwaltung.includes("Frida"),
"und das Team ebenfalls — eine Liste, nicht zwei");
/* Die Rolle lässt sich dort auch VERGEBEN. Ein Knopf, den es nicht
gibt, macht die Liste nutzlos: Ohne ihn kann DogFather nirgends
einen Zugang zum Treff anlegen. */
const ich = await roh("/workspace/api/ich", CREW, { cookie: kDogi });
let darf = [];
try { darf = JSON.parse(ich.text).darf_anlegen || []; } catch { /* bleibt leer */ }
ok(darf.includes("gast"),
`und DogFather darf dort Community-Zugänge anlegen (${darf.join(", ")})`);
/* GEGENPROBE: Ein Modi darf das nicht — Zugänge vergibt DogFather.
Ohne diese Zeile wäre die darüber auch dann grün, wenn es jeder
dürfte. */
const ichModi = await roh("/workspace/api/ich", CREW, { cookie: kModi });
let darfModi = [];
try { darfModi = JSON.parse(ichModi.text).darf_anlegen || []; } catch { /* leer */ }
ok(!darfModi.includes("gast"),
`ein Modi nicht (${darfModi.length ? darfModi.join(", ") : "gar nichts"})`);
}
/* =======================================================================
8. DIE REGELN NENNEN DIE ZAHLEN, DIE WIRKLICH GELTEN
======================================================================= */
melde("");
melde("=== 8. Der Regeltext ===");
{
const a = await roh("/workspace/api/treff/regeln", TREFF, { cookie: kBo });
const a = await roh("/workspace/api/treff/regeln", CREW, { cookie: kBo });
const r = json(a);
ok(a.code === 200 && r.mindestalter === treffModul.MINDESTALTER,
`Mindestalter ${r.mindestalter} -- dieselbe Zahl wie im Code`);
+143 -131
View File
@@ -1,5 +1,5 @@
/* =====================================================================
DER TREFF — die Community und ihre sieben Bretter (11.09.2026)
DER CREW — die Community und ihre sieben Bretter (11.09.2026)
Filipe:
@@ -66,9 +66,9 @@ let fehler = 0, geprueft = 0;
const melde = (t) => console.log(t);
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
const TREFF = "treff.dogfather-universe.com";
const CREW = "crew.dogfather-universe.com";
const HAUS = "workspace.dogfather-universe.com";
const HAUPT = "dogfather-universe.com";
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
@@ -103,7 +103,7 @@ const rein = d.prepare(
+ " VALUES (?,?,?,?,?,?,?)");
const BRETTER = ["anschlag", "ansteht", "treff", "wunsch", "highlight", "regeln", "mitmachen"];
for (const b of BRETTER) rein.run(b, Object.keys((await import("./workspace-bereiche.js")).BEREICHE[b].arten)[0],
`TREFF-PROBE-${b.toUpperCase()}`, "", jetzt.slice(0, 10), jetzt, idDogi);
`CREW-PROBE-${b.toUpperCase()}`, "", jetzt.slice(0, 10), jetzt, idDogi);
/* Und einer im Haus, den die Community NICHT sehen darf. */
rein.run("ideen", "content", "HAUS-GEHEIM-4711", "", jetzt.slice(0, 10), jetzt, idDogi);
d.close();
@@ -140,23 +140,47 @@ async function anmelden(rolle, code, host) {
======================================================================= */
melde("");
melde("=== 1. Eine Rolle, eine Wand ===");
const gast = await anmelden("gast", "CODE-GAST-0001", TREFF);
ok(gast.code === 200 && gast.keks.length > 0, `die Community kommt auf treff. herein (${gast.code})`);
const gast = await anmelden("gast", "CODE-GAST-0001", CREW);
ok(gast.code === 200 && gast.keks.length > 0,
`die Community kommt auf crew. herein (${gast.code})`);
for (const [name, host] of [["crew.", CREW], ["workspace.", HAUS]]) {
/* AUF DEN ALTEN ADRESSEN NICHT -- und zwar mit derselben Antwort wie
ein erfundener Code. Ein anderer Fehlercode waere die Auskunft
"diesen Zugang gibt es, nur nicht hier", und wer das liest, sucht
weiter. */
for (const [name, host] of [["workspace.", HAUS], ["der Hauptseite", HAUPT]]) {
const a = await anmelden("gast", "CODE-GAST-0001", host);
const b = await anmelden("gast", "VOELLIG-ERFUNDEN-XYZ", host);
ok(a.code === 401 && a.keks === "", `auf ${name} nicht (${a.code})`);
/* NICHT AUF EINEN BESTIMMTEN CODE FESTLEGEN (gemessen 11.09.2026).
Hier stand `=== 401`. Auf workspace. stimmt das; auf der
Hauptseite antwortet der Server 410 -- der Workspace ist von dort
weggezogen, und "Gone" ist die richtige Antwort fuer JEDEN, der es
dort noch versucht. Die Pruefung war rot, obwohl genau das Richtige
passierte.
Gemessen wird jetzt, was die Zeile eigentlich behaupten will: Er
kommt nicht herein, und er kann an der Antwort nicht ablesen, dass
es seinen Zugang gibt. */
ok(a.code !== 200 && a.keks === "", `auf ${name} nicht (${a.code})`);
ok(a.code === b.code, `und zwar mit derselben Antwort wie ein erfundener Code (${a.code}/${b.code})`);
}
{
/* UND DIE GEGENRICHTUNG: Auf der Wand des Treffs kommt sonst niemand
herein -- auch DogFather nicht. Er hat dort nichts zu suchen; er
sieht den Treff auf seiner eigenen Adresse. */
const a = await anmelden("admin", "CODE-DOGI-0001", TREFF);
const b = await anmelden("modi", "CODE-MODI-0001", TREFF);
ok(a.code !== 200 && b.code !== 200,
`auf treff. kommt sonst niemand herein -- auch DogFather nicht (${a.code}/${b.code})`);
/* DIE GEGENPROBE: Auf derselben Wand kommt auch das Team herein --
sonst waere "die Community kommt auf crew. herein" auch dann
gruen, wenn dort ueberhaupt niemand mehr durchkaeme. */
const a = await anmelden("admin", "CODE-DOGI-0001", CREW);
const b = await anmelden("modi", "CODE-MODI-0001", CREW);
ok(a.code === 200 && b.code === 200,
`und das Team ebenfalls -- eine Wand fuer beide (${a.code}/${b.code})`);
/* UND DIE AGENTUR WEITERHIN NICHT. Dass der Treff hier eingezogen
ist, hat daran nichts geaendert -- und genau das ist die Stelle,
an der ein Umbau so etwas versehentlich aufmacht. */
const c = await anmelden("manager", "CODE-MANA-0001", CREW);
const d = await anmelden("creator", "CODE-CREA-0001", CREW);
ok(c.code !== 200 && d.code !== 200,
`eine Managerin und eine Creatorin aber nicht (${c.code}/${d.code})`);
}
const kDogi = (await anmelden("admin", "CODE-DOGI-0001", HAUS)).keks;
@@ -166,108 +190,96 @@ const kMana = (await anmelden("manager", "CODE-MANA-0001", HAUS)).keks;
ok([kDogi, kModi, kCrea, kMana].every((k) => k.length > 0), "die vier Vergleichsrollen sind angemeldet");
/* =======================================================================
1b. DIE WEICHE: drei Adressen, drei Türen, keine Verwechslung
1b. EINE WAND FÜR BEIDE — und keine dritte mehr
Bis zum Mittag des 11.09.2026 hatte der Treff eine eigene Adresse,
eine eigene Wand und ein eigenes Manifest. Filipe hat das verworfen:
*"das soll keine app für sich sein, das soll in der crew seite
adaptiert werden."*
Was dieser Abschnitt jetzt misst, ist deshalb das Gegenteil von
vorher — und er misst es, weil ein halber Rückbau die gefährlichste
Lage wäre: eine Wand, die es nicht mehr geben soll, die aber noch
als Datei herumliegt und von express.static ausgeliefert wird.
======================================================================= */
melde("");
melde("=== 1b. Die Weiche des Treffs ===");
melde("=== 1b. Eine Wand für beide ===");
{
/* DIE WAND. Ohne die Weiche stünde auf der Adresse der Community die
Wand der Agentur: Spicy-Media-Logo, "Creator Workspace", fünf
Rollenkacheln mit den Namen Admin, Manager, Scout, Creator -- die
komplette Struktur des Unternehmens, VOR der Anmeldung, für jeden,
der die Adresse hat. Das ist das eigentliche Leck, gegen das
treffWeiche gebaut ist. */
for (const pfad of ["/workspace/", "/workspace/index.html"]) {
const a = await roh(pfad, TREFF);
const ist = a.code === 200 && /Der&nbsp;Treff|Der Treff/.test(a.text);
ok(ist, `${pfad} zeigt die Wand des Treffs (${a.code})`);
ok(!/Creator\s*Workspace|Spicy/i.test(a.text),
`und nennt weder Workspace noch Spicy (${pfad})`);
}
/* DIE DATEIEN DER DRITTEN ADRESSE SIND WEG. Nicht "nicht mehr
verlinkt" -- weg. Eine Zugangswand, die niemand mehr meint, die
aber unter ihrem Dateinamen weiterhin herumliegt, ist genau die
Sorte Rest, die man ein halbes Jahr spaeter findet.
/* KEINE ROLLENNAMEN DES HAUSES in der ausgelieferten Datei. Die
beiden anderen Wände nennen ihre Rollen offen -- dort ist das
richtig, denn dort steht nur, wer ohnehin dazugehört. Hier steht
ein Mensch, der NICHT zum Team gehört. */
GEFRAGT WIRD DIE PLATTE, NICHT DER SERVER (gemessen 11.09.2026).
Ueber HTTP antwortet eine geloeschte Seite mit 302 auf die
Startseite -- weil die Schranke davor greift, bevor express.static
ueberhaupt nachsieht. Das ist im Betrieb genau richtig (eine Seite,
die es nicht gibt, verhaelt sich wie eine, die man nicht darf),
macht die Frage "gibt es die Datei noch?" per HTTP aber
unbeantwortbar: 302 kommt in beiden Faellen. Wer hier 404 erwartet,
prueft die Schranke und nennt es Dateipruefung. */
{
const a = await roh("/workspace/treff-index.html", TREFF);
const verraten = ["manager", "scout", "creator", "modi", "rechte hand"]
.filter((w) => new RegExp(w, "i").test(a.text));
ok(verraten.length === 0,
`die Wand nennt keine Rolle des Hauses${verraten.length ? " -- FUND: " + verraten.join(", ") : ""}`);
const { existsSync } = await import("node:fs");
const { fileURLToPath } = await import("node:url");
/* fileURLToPath statt .pathname mit Handarbeit: Unter Windows
liefert .pathname "/C:/..." -- mit einem fuehrenden Schraegstrich,
den existsSync nicht mag. Wer den mit einem Muster wegschneidet,
hat eine Zeile, die auf Linux nichts tut und auf Windows alles
entscheidet. Der eingebaute Weg kennt beide Faelle. */
const ordner = fileURLToPath(new URL("../workspace/", import.meta.url));
const reste = ["treff-index.html", "treff.webmanifest",
"assets/img/buehne/treff-gate-1280.webp"]
.filter((f) => existsSync(ordner + f));
ok(reste.length === 0,
`von der dritten Adresse liegt nichts mehr herum${reste.length ? " -- REST: " + reste.join(", ") : ""}`);
/* GEGENPROBE: Die Pruefung sieht ueberhaupt an der richtigen
Stelle nach. Ohne sie waere die Zeile darueber auch bei einem
falschen Pfad gruen -- der gruene Haken ueber der Null. */
ok(existsSync(ordner + "crew-index.html"),
"und die Wand von Team Dogi liegt dort, wo gesucht wurde");
}
/* DAS MANIFEST MACHT DIE APP. Drei Adressen, drei Namen -- sonst
hieße die App auf dem Startbildschirm eines Mitglieds "Team Dogi",
der Name eines Bereichs, zu dem es nicht gehört. */
const namen = {};
for (const [was, host] of [["treff", TREFF], ["crew", CREW], ["haus", HAUS]]) {
const a = await roh("/workspace/app.webmanifest", host);
try { namen[was] = JSON.parse(a.text).name; } catch { namen[was] = `(kein JSON: ${a.code})`; }
}
ok(namen.treff === "Der Treff", `das Manifest heißt "${namen.treff}"`);
ok(namen.crew === "Team Dogi" && namen.treff !== namen.crew,
`und auf crew. weiterhin "${namen.crew}"`);
ok(new Set(Object.values(namen)).size === 3,
`drei Adressen, drei Namen (${Object.values(namen).join(" · ")})`);
/* DIE WAND ZEIGT VIER KACHELN. Die Zahl steht nicht als Zahl da,
sondern kommt aus der Rollenliste des Servers -- wer eine fünfte
Rolle auf diese Wand lässt, ohne eine Kachel zu bauen, bekommt
hier eine rote Zeile statt eines stummen Lochs. */
const wand = await roh("/workspace/", CREW);
ok(wand.code === 200 && /Team&nbsp;Dogi|Team Dogi/.test(wand.text),
`die Wand von Team Dogi steht (${wand.code})`);
const kacheln = [...wand.text.matchAll(/data-rolle="([a-z]+)"/g)].map((m) => m[1]);
ok(kacheln.length === 4 && kacheln.includes("gast"),
`vier Kacheln, eine davon die Community: ${kacheln.join(", ")}`);
ok(kacheln[kacheln.length - 1] === "gast",
"und sie steht zuletzt -- wer täglich kommt, findet oben, was er täglich braucht");
/* JEDE WAND GEHÖRT ZU GENAU EINER TÜR. Beide Richtungen, sonst
beweist es nichts: Die eigene Wand MUSS erreichbar sein. */
const waende = [
["/workspace/crew-index.html", CREW, TREFF],
["/workspace/treff-index.html", TREFF, CREW],
["/workspace/treff-index.html", TREFF, HAUS],
];
for (const [datei, zuhause, fremd] of waende) {
const a = await roh(datei, zuhause);
const b = await roh(datei, fremd);
ok(a.code === 200, `${datei} gibt es zu Hause (${a.code})`);
ok(b.code === 404, `und auf der fremden Adresse nicht (${b.code})`);
}
/* Auch mit doppeltem Schrägstrich -- express.static zieht sie später
selbst zusammen und liefert die Datei aus. Genau daran ist am
04.09.2026 die Schranke des Workspace vorbeigelaufen. */
const schraeg = await roh("/workspace//treff-index.html", CREW);
ok(schraeg.code === 404, `auch mit doppeltem Schrägstrich nicht (${schraeg.code})`);
/* DER TEXT AUF DER WAND MUSS FÜR BEIDE STIMMEN. Er stand auf
"Privater Arbeitsbereich für DogFather und die Modis" -- das liest
ab heute auch die Community, und für sie ist es schlicht falsch. */
ok(!/Arbeitsbereich für DogFather und die Modis/.test(wand.text),
"und der Untertitel behauptet nicht mehr, das hier sei nur für das Team");
/* DAS MANIFEST GILT JE ADRESSE und kann sich nicht nach der Rolle
richten. Filipes Entscheidung: ein Name, der für beide passt. */
const man = await roh("/workspace/app.webmanifest", CREW);
let name = "(kein JSON)";
try { name = JSON.parse(man.text).name; } catch { /* bleibt stehen */ }
ok(name === "DogFather Universe", `die App heißt "${name}" -- für Team und Community`);
const manHaus = await roh("/workspace/app.webmanifest", HAUS);
let nameHaus = "(kein JSON)";
try { nameHaus = JSON.parse(manHaus.text).name; } catch { /* bleibt stehen */ }
ok(nameHaus !== name, `und auf der Agenturadresse weiterhin etwas anderes ("${nameHaus}")`);
/* DIE WAND VON TEAM DOGI BLEIBT AUF DEN ALTEN ADRESSEN UNSICHTBAR.
404 und keine Weiterleitung: "Gibt es nicht" verrät nichts. */
const fremd = await roh("/workspace/crew-index.html", HAUS);
const schraeg = await roh("/workspace//crew-index.html", HAUS);
ok(fremd.code === 404 && schraeg.code === 404,
`die Wand gibt es auf workspace. nicht -- auch mit doppeltem Schrägstrich (${fremd.code}/${schraeg.code})`);
/* NICHT INDIZIEREN -- als Kopf und nicht nur als <meta>, damit er
auch für Manifest, Bilder und jede Antwort ohne HTML gilt. */
const kopf = await roh("/workspace/", TREFF);
ok(/noindex/i.test(kopf.kopf?.["x-robots-tag"] || ""),
`der Kopf sagt noindex (${kopf.kopf?.["x-robots-tag"]})`);
/* NUR DER WORKSPACE. Sonst läge die komplette Dogfather-Website ein
zweites Mal unter einer zweiten Adresse. */
const haupt = await roh("/", TREFF);
ok(haupt.code === 302 && haupt.kopf?.location === "/workspace/",
`die Hauptseite gibt es hier nicht (${haupt.code} → ${haupt.kopf?.location})`);
/* DAS HAUS. haus.css ist auf der Agenturadresse leer; auf treff.
muss dahinter das Farbhaus von Team Dogi stehen -- sonst käme die
Seite grau an und färbte sich erst im Browser um. */
const haus = await roh("/workspace/assets/css/haus.css?v=1", TREFF);
ok(haus.code === 200 && /--sternenfeld/.test(haus.text),
`haus.css bringt das Farbhaus mit (${haus.text.length} Zeichen)`);
/* DIE BÜHNEN INNEN. Die Motive der Agentur zeigen das
Spicy-Media-Logo selbst -- teils vielfach nebeneinander. */
const a1 = await roh("/workspace/assets/img/buehne-lounge-breit.webp", TREFF);
const a2 = await roh("/workspace/assets/img/crew-buehne-lounge-breit.webp", TREFF);
const a3 = await roh("/workspace/assets/img/buehne-lounge-breit.webp", HAUS);
ok(a1.code === 200 && a1.text.length === a2.text.length,
`die Bühne kommt von Team Dogi (${a1.text.length} = ${a2.text.length})`);
ok(a1.text.length !== a3.text.length,
`und ist eine andere als die der Agentur (${a1.text.length} ≠ ${a3.text.length})`);
/* DAS ZEICHEN IN DER KOPFLEISTE. start.css setzt dort eine Chili --
als CSS-Hintergrund, auf jeder Seite, den ganzen Tag. */
const m1 = await roh("/workspace/assets/img/marke-spicy.webp", TREFF);
const m2 = await roh("/workspace/assets/img/marke-husky.webp", TREFF);
const m3 = await roh("/workspace/assets/img/marke-spicy.webp", HAUS);
ok(m1.code === 200 && m1.text.length === m2.text.length,
`in der Kopfleiste steht der Husky (${m1.text.length})`);
ok(m1.text.length !== m3.text.length,
`und nicht die Chili (${m1.text.length} ≠ ${m3.text.length})`);
ok(/noindex/i.test(wand.kopf?.["x-robots-tag"] || ""),
`der Kopf sagt noindex (${wand.kopf?.["x-robots-tag"]})`);
}
/* =======================================================================
@@ -277,7 +289,7 @@ melde("");
melde("=== 2. Sieben Kacheln — und keine achte ===");
let namen = [];
{
const a = await roh("/workspace/api/ich", TREFF, { cookie: gast.keks });
const a = await roh("/workspace/api/ich", CREW, { cookie: gast.keks });
const j = JSON.parse(a.text);
ok(Array.isArray(j.bereiche) && j.bereiche.length === 7,
`die Community bekommt sieben Kacheln (${j.bereiche?.length})`);
@@ -330,7 +342,7 @@ let namen = [];
/* UND DIE MODERATIONSKACHEL IST BEI DER COMMUNITY WIRKLICH NICHT DA
-- nicht nur "nicht in dieser Liste". Die Kachel ist ein Weg; wenn
der Weg zu ist, muss auch die Tuer zu sein. */
const d = JSON.parse((await roh("/workspace/api/ich", TREFF, { cookie: gast.keks })).text);
const d = JSON.parse((await roh("/workspace/api/ich", CREW, { cookie: gast.keks })).text);
const alleNamen = [...(d.bereiche || []), ...(d.bereiche_zusatz || [])].map((k) => k.name);
ok(!alleNamen.includes(MOD), `die Community hat keine Moderationskachel (${alleNamen.length} Kacheln)`);
}
@@ -349,8 +361,8 @@ async function brett(b, host, keks) {
{
let gefunden = 0;
for (const b of BRETTER) {
const r = await brett(b, TREFF, gast.keks);
if (r.code === 200 && r.titel.includes(`TREFF-PROBE-${b.toUpperCase()}`)) gefunden++;
const r = await brett(b, CREW, gast.keks);
if (r.code === 200 && r.titel.includes(`CREW-PROBE-${b.toUpperCase()}`)) gefunden++;
}
/* FUENF VON SIEBEN, UND DAS IST DAS ERGEBNIS -- kein Mangel.
@@ -368,8 +380,8 @@ async function brett(b, host, keks) {
Bretter aus einem anderen Grund leer sind. */
let vorher = 0;
for (const b of treffModul.TREFF_FREIGABE_BRETTER) {
const r = await brett(b, TREFF, gast.keks);
if (r.titel.includes(`TREFF-PROBE-${b.toUpperCase()}`)) vorher++;
const r = await brett(b, CREW, gast.keks);
if (r.titel.includes(`CREW-PROBE-${b.toUpperCase()}`)) vorher++;
}
ok(vorher === 0, `ohne Freigabe sieht die Community Termine und Highlights nicht (${vorher})`);
@@ -378,7 +390,7 @@ async function brett(b, host, keks) {
for (const b of treffModul.TREFF_FREIGABE_BRETTER) {
const beiDogi2 = await roh(`/workspace/api/bereich/${b}`, HAUS, { cookie: kDogi });
const eintrag = (JSON.parse(beiDogi2.text).eintraege || [])
.find((e) => e.titel === `TREFF-PROBE-${b.toUpperCase()}`);
.find((e) => e.titel === `CREW-PROBE-${b.toUpperCase()}`);
if (!eintrag) continue;
const a = await roh(`/workspace/api/treff/eintrag/${eintrag.id}/freigeben`, HAUS,
{ cookie: kDogi }, {}, "PUT");
@@ -389,8 +401,8 @@ async function brett(b, host, keks) {
let nachher = 0;
for (const b of treffModul.TREFF_FREIGABE_BRETTER) {
const r = await brett(b, TREFF, gast.keks);
if (r.titel.includes(`TREFF-PROBE-${b.toUpperCase()}`)) nachher++;
const r = await brett(b, CREW, gast.keks);
if (r.titel.includes(`CREW-PROBE-${b.toUpperCase()}`)) nachher++;
}
ok(nachher === treffModul.TREFF_FREIGABE_BRETTER.length,
`nach der Freigabe sieht sie beide (${nachher})`);
@@ -409,7 +421,7 @@ async function brett(b, host, keks) {
const fremde = ["ideen", "angebote", "rueckmeldung", "entwicklung", "talente", "agentur", "live", "content"];
const durch = [];
for (const b of fremde) {
const r = await brett(b, TREFF, gast.keks);
const r = await brett(b, CREW, gast.keks);
if (r.code === 200) durch.push(b);
}
ok(durch.length === 0, `und kein einziges des Hauses${durch.length ? " -- DURCH: " + durch.join(", ") : ""}`);
@@ -420,25 +432,25 @@ async function brett(b, host, keks) {
bin ich am 10.09. schon einmal hereingefallen und haette fast ein
Loch repariert, das keines war. Gezaehlt wird, was die Suche
WIRKLICH gefunden hat. */
const suche = await roh("/workspace/api/suche?q=HAUS-GEHEIM-4711", TREFF, { cookie: gast.keks });
const suche = await roh("/workspace/api/suche?q=HAUS-GEHEIM-4711", CREW, { cookie: gast.keks });
let treffer = -1;
try { treffer = JSON.parse(suche.text).gesamt; } catch { treffer = -1; }
ok(treffer === 0, `auch die Suche findet nichts aus dem Haus (${treffer} Treffer)`);
}
{
/* UND DIE AGENTUR SIEHT DEN TREFF NICHT. Beide Richtungen, beide
/* UND DIE AGENTUR SIEHT DEN CREW NICHT. Beide Richtungen, beide
ueber die Adresszeile. */
const durch = [];
for (const b of BRETTER) {
const r = await brett(b, HAUS, kCrea);
if (r.code === 200 && r.titel.some((t) => t.startsWith("TREFF-PROBE"))) durch.push(b);
if (r.code === 200 && r.titel.some((t) => t.startsWith("CREW-PROBE"))) durch.push(b);
}
ok(durch.length === 0, `eine Creatorin sieht kein Brett des Treffs${durch.length ? " -- DURCH: " + durch.join(", ") : ""}`);
const durchM = [];
for (const b of BRETTER) {
const r = await brett(b, HAUS, kMana);
if (r.code === 200 && r.titel.some((t) => t.startsWith("TREFF-PROBE"))) durchM.push(b);
if (r.code === 200 && r.titel.some((t) => t.startsWith("CREW-PROBE"))) durchM.push(b);
}
ok(durchM.length === 0, `eine Managerin auch nicht${durchM.length ? " -- DURCH: " + durchM.join(", ") : ""}`);
@@ -448,7 +460,7 @@ async function brett(b, host, keks) {
let sieht = 0;
for (const b of BRETTER) {
const r = await brett(b, CREW, kModi);
if (r.code === 200 && r.titel.includes(`TREFF-PROBE-${b.toUpperCase()}`)) sieht++;
if (r.code === 200 && r.titel.includes(`CREW-PROBE-${b.toUpperCase()}`)) sieht++;
}
ok(sieht === 7, `ein Modi sieht alle sieben (${sieht}/7)`);
}
@@ -488,7 +500,7 @@ melde("=== 4. Nur die Seiten aus der Tafel ===");
const zu = [];
for (const p of erlaubt) {
const a = await roh(p, TREFF, { cookie: gast.keks });
const a = await roh(p, CREW, { cookie: gast.keks });
if (a.code !== 200) zu.push(`${p.split("/").pop()} (${a.code})`);
}
ok(zu.length === 0,
@@ -496,7 +508,7 @@ melde("=== 4. Nur die Seiten aus der Tafel ===");
const durch = [];
for (const p of verboten) {
const a = await roh(p, TREFF, { cookie: gast.keks });
const a = await roh(p, CREW, { cookie: gast.keks });
if (a.code === 200) durch.push(p.split("/").pop());
}
ok(durch.length === 0,
@@ -507,9 +519,9 @@ melde("=== 4. Nur die Seiten aus der Tafel ===");
wirklich weh täte: Dort stehen die Namen derer, die gemeldet
haben. Eine eigene Zeile dafür, damit der Befund einen Namen hat
und nicht in "eine von 20" untergeht. */
const mod = await roh("/workspace/treff-moderation.html", TREFF, { cookie: gast.keks });
const mod = await roh("/workspace/treff-moderation.html", CREW, { cookie: gast.keks });
ok(mod.code !== 200, `die Moderationsseite bleibt zu (${mod.code})`);
const modApi = await roh("/workspace/api/treff/meldungen", TREFF, { cookie: gast.keks });
const modApi = await roh("/workspace/api/treff/meldungen", CREW, { cookie: gast.keks });
ok(modApi.code === 404, `und die Meldungen dahinter auch (${modApi.code})`);
}
@@ -525,7 +537,7 @@ for (const [name, pfad] of [
["Personen", "/workspace/api/personen"],
["Gespräche", "/workspace/api/chat/raeume"],
]) {
const a = await roh(pfad, TREFF, { cookie: gast.keks });
const a = await roh(pfad, CREW, { cookie: gast.keks });
let leer = a.code !== 200;
if (a.code === 200) {
try {
@@ -551,11 +563,11 @@ melde("=== 6. Schreiben ===");
ist, liest und stimmt ab -- mehr nicht. Das wird von BEIDEN
Seiten der Grenze gemessen, sonst beweist es nichts: Eine
Schreibsperre, die immer sperrt, ist keine Stufe. */
const neu = await roh("/workspace/api/bereich/treff", TREFF, { cookie: gast.keks },
const neu = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
{ art: "hallo", titel: "GAST-ZU-FRUEH-0001", text: "Hallo zusammen.", datum: jetzt.slice(0, 10) });
ok(neu.code === 403, `wer neu ist, schreibt noch nicht (${neu.code})`);
const lage0 = JSON.parse((await roh("/workspace/api/treff/lage", TREFF, { cookie: gast.keks })).text);
const lage0 = JSON.parse((await roh("/workspace/api/treff/lage", CREW, { cookie: gast.keks })).text);
ok(lage0.stufe === "neu", `und die Lage sagt es ihm auch: ${lage0.stufe}`);
ok(lage0.schreiben?.treff === false, "der Knopf waere aus");
@@ -567,7 +579,7 @@ melde("=== 6. Schreiben ===");
.run(new Date(Date.now() - 8 * 86400000).toISOString(), idGast);
dd.close();
const a = await roh("/workspace/api/bereich/treff", TREFF, { cookie: gast.keks },
const a = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
{ art: "hallo", titel: "GAST-SCHREIBT-8899", text: "Hallo zusammen.", datum: jetzt.slice(0, 10) });
ok(a.code === 200 || a.code === 201, `nach acht Tagen schon (${a.code})`);
@@ -578,7 +590,7 @@ melde("=== 6. Schreiben ===");
dd2.prepare("UPDATE personen SET erstellt = ? WHERE id = ?")
.run(new Date(Date.now() - 6 * 86400000).toISOString(), idGast);
dd2.close();
const knapp = await roh("/workspace/api/bereich/treff", TREFF, { cookie: gast.keks },
const knapp = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
{ art: "hallo", titel: "GAST-ZU-FRUEH-0002", text: "Und?", datum: jetzt.slice(0, 10) });
ok(knapp.code === 403, `sechs Tage reichen nicht (${knapp.code})`);
const dd3 = new DatabaseSync(process.env.WORKSPACE_DB);
@@ -587,7 +599,7 @@ melde("=== 6. Schreiben ===");
dd3.close();
/* Und auf ein Brett des Teams kommt er auch als "Dabei" nicht. */
const brettDesTeams = await roh("/workspace/api/bereich/anschlag", TREFF, { cookie: gast.keks },
const brettDesTeams = await roh("/workspace/api/bereich/anschlag", CREW, { cookie: gast.keks },
{ art: Object.keys(BEREICHE.anschlag.arten)[0], titel: "GAST-AM-ANSCHLAG-0001",
text: "Ansage", datum: jetzt.slice(0, 10) });
ok(brettDesTeams.code === 403, `aufs Anschlagbrett schreibt nur das Team (${brettDesTeams.code})`);
@@ -601,7 +613,7 @@ melde("=== 6. Schreiben ===");
}
{
/* UND NICHT IN EIN BRETT DES HAUSES. */
const a = await roh("/workspace/api/bereich/ideen", TREFF, { cookie: gast.keks },
const a = await roh("/workspace/api/bereich/ideen", CREW, { cookie: gast.keks },
{ art: "content", titel: "GAST-IM-HAUS-0000", text: "", datum: jetzt.slice(0, 10) });
ok(a.code !== 200 && a.code !== 201, `aber nicht in ein Brett des Hauses (${a.code})`);
}
-3
View File
@@ -300,9 +300,6 @@ export const SEITEN = {
export const OHNE_ANMELDUNG = [
"/workspace/index.html",
"/workspace/crew-index.html",
/* Die Wand des Treffs (11.09.2026). Dritte Adresse, dritte Wand --
und die erste, vor der jemand steht, der NICHT zum Team gehoert. */
"/workspace/treff-index.html",
];
/* =====================================================================
-171
View File
@@ -1,171 +0,0 @@
/* =====================================================================
Die eigene Adresse des Treffs (11.09.2026)
treff.dogfather-universe.com
Auftrag (Filipe, 11.09.2026): *"eine community rolle und community
kategorie, wo die community auch dann nur die sieht."*
---------------------------------------------------------------------
WARUM EINE DRITTE ADRESSE UND NICHT EINE DRITTE KACHEL
Drei Gruende, und jeder allein wuerde schon reichen:
1. EINE APP JE URSPRUNG. Auf einem Ursprung laesst sich genau EINE
App installieren (w3c/manifest Nr. 1180: verschachtelte Bereiche
sind "strongly not recommended", Chrome haelt sich daran). Team
Dogi hat seine App, der Workspace hat seine. Ohne eigene Adresse
haette die Community gar keine.
2. EINE FALSCHE ANMELDUNG DARF NICHT REICHEN. Waere der Treff eine
Kachel auf der Wand des Workspace, traefe jeder Tippfehler in
der Rechteprueung sofort echte Zuschauer. So steht zwischen
einem Mitglied der Community und den Daten der Agentur nicht nur
eine Rollenabfrage, sondern eine Adresse, ein Zwischenschritt
und die Adressregel in sitzungLesen(). Drei Schloesser -- faellt
eines, halten zwei.
3. DIE COMMUNITY IST DER ERSTE KREIS VON AUSSEN. Bisher hatte jede
Rolle in diesem Haus einen Vertrag, eine Rechnung oder eine
Absprache. Ein Mitglied des Treffs hat nur einen Code. Was diese
Menschen sehen, ist damit die einzige Stelle, an der ein Fehler
wirklich nach draussen geht.
---------------------------------------------------------------------
WAS SICH NICHT AENDERT: der Pfad /workspace/, der Dienst (4100), die
Datenbank, der Code. Getrennt wird ueber den HOSTNAMEN, so wie bei
Workspace und Team Dogi auch.
---------------------------------------------------------------------
WAS DIESE DATEI AUSDRUECKLICH NICHT TUT: Rechte vergeben.
Wer auf welcher Adresse angemeldet sein darf, entscheidet
sitzungPasstZurAdresse() -- aufgerufen in sitzungLesen(), durch das
alle 26 Fachmodule gehen. Was eine Rolle sehen darf, entscheidet die
Rechtetafel in rechte.js. Zwei Orte fuer dieselbe Regel waeren einer
zu viel; der zweite waere der, den beim naechsten Umbau niemand
anfasst.
---------------------------------------------------------------------
DASS DER TREFF WIE TEAM DOGI AUSSIEHT, IST ENTSCHIEDEN
Er benutzt crew-haus.css, die Buehnen von Team Dogi und deren
App-Symbol. Gemessen gaebe es durchaus einen eigenen Farbton
(Tannengruen liegt 60 Lab-Einheiten vom Marineblau entfernt, also
klar unterscheidbar). Er wuerde den Treff aber zu einem DRITTEN Haus
machen, neben Spicy Media und Team Dogi. Er ist kein drittes Haus,
sondern ein zweiter Raum in demselben -- "lila und babyblau ueberall"
(Filipe, 10.09.2026).
Unterschieden werden die Tueren durch das WORT darauf: Die Buehne der
Zugangswand traegt "DER TREFF" statt "TEAM DOGI" (tools/crew-buehne.mjs,
zwei Werte, ein Werkzeug), und die App heisst "Der Treff".
===================================================================== */
import {
istTreffAdresse, istWorkspacePfad,
} from "./crew-adresse.js";
/**
* Express-Zwischenschritt fuer die Adresse des Treffs.
*
* Er laeuft NACH crewWeiche und tut dort dasselbe wie diese auf ihrer
* Adresse -- mit drei Unterschieden: eigenes Manifest, eigene Wand,
* und die Buehnen kommen von Team Dogi statt von der Agentur.
*
* DIE FREMDEN WAENDE SPERRT ER NICHT SELBST. Das macht bereits
* crewWeiche fuer jede Adresse ueber die Wandtafel (istFremdeWand).
* Eine zweite Sperre hier waere dieselbe Regel an zwei Orten.
*/
export function treffWeiche(req, res, next) {
if (!istTreffAdresse(req.get("host"))) return next();
/* NICHT INDIZIEREN. Der Kopf steht hier und nicht nur als <meta> im
HTML, weil er dann auch fuer Manifest, Symbole, Bilder und jede
Antwort ohne HTML gilt. Bei dieser Adresse wiegt das schwerer als
bei den anderen beiden: Sie wird an Dutzende Menschen
weitergegeben, die nichts unterschrieben haben. Ein Eintrag bei
einer Suchmaschine waere nicht rueckholbar. */
res.setHeader("X-Robots-Tag", "noindex, nofollow");
/* DAS MANIFEST MACHT DIE APP. Alle drei Adressen liefern dieselben
HTML-Dateien aus, in jeder steht dieselbe Manifest-Zeile. Hier
liegt dahinter ein anderes: Name "Der Treff". Sonst hiesse die App
auf dem Startbildschirm eines Mitglieds "Team Dogi" -- der Name
eines Bereichs, zu dem es nicht gehoert.
Ueber die Adresse und nicht ueber eine zweite Zeile in 30
HTML-Dateien: Eine zweite Zeile muesste jemand bei jeder neuen
Seite mitschreiben, und wer sie vergisst, bekommt eine Seite, die
still zur falschen App gehoert. */
if (req.path === "/workspace/app.webmanifest") {
req.url = "/workspace/treff.webmanifest";
return next();
}
/* DIE ZUGANGSWAND. Ohne diese Zeile stuende auf der Adresse der
Community die Wand der Agentur: Spicy-Media-Logo, "Creator
Workspace", fuenf Rollenkacheln mit den Namen Admin, Manager,
Scout, Creator -- die komplette Struktur des Unternehmens, vor der
Anmeldung, fuer jeden, der die Adresse hat.
ZWEI PFADE, EINE DATEI: "/workspace/" und "/workspace/index.html"
fuehren beide zur Wand, also muessen beide umgebogen werden. Den
zweiten zu vergessen faellt im Alltag nicht auf -- ihn tippt
niemand -- und waere trotzdem genau das Leck von oben. */
if (req.path === "/workspace/" || req.path === "/workspace/index.html") {
req.url = "/workspace/treff-index.html";
return next();
}
/* DIE BUEHNEN INNEN. Die neun Motive der Agentur zeigen nicht bloss
rotes Licht, sondern das Spicy-Media-Logo selbst -- in `halle` und
`arena` sogar vielfach nebeneinander. Die Fassungen von Team Dogi
liegen laengst da und sind genau dafuer gebaut worden.
UND ES FLACKERT NICHT: Das Bild wird beim ERSTEN Abruf schon als
das richtige geliefert. Eine Umschaltung per JavaScript haette
erst die Spicy-Buehne gezeigt und dann getauscht. */
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. start.css setzt links neben den
Namen eine Chili -- als CSS-Hintergrund, nicht als Bild im HTML.
Ohne diese Zeile stuende oben links auf jeder Seite des Treffs das
Zeichen von Spicy Media. */
if (req.path === "/workspace/assets/img/marke-spicy.webp") {
req.url = "/workspace/assets/img/marke-husky.webp";
return next();
}
/* DAS HAUS. Jede Seite laedt als LETZTE Stilvorlage haus.css; auf der
Agenturadresse ist die leer, hier steht dahinter das Farbhaus von
Team Dogi.
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();
}
/* NUR DER WORKSPACE. Auf treff. 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 dasselbe bereits mit seiner eigenen 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. */
if (istWorkspacePfad(req.path) || req.path.startsWith("/assets/")) return next();
return res.redirect(302, "/workspace/");
}
+96 -14
View File
@@ -32,7 +32,7 @@ import { darfSeite, OHNE_ANMELDUNG, SEITEN, ALLE_ROLLEN } from "./rechte.js";
obwohl workspace-treff.js seinerseits aus dieser Datei importiert.
Begruendung im Kopf von treff-tabellen.js. */
import { treffTabellen, treffSperreLesen } from "./treff-tabellen.js";
import { sitzungPasstZurAdresse, istOhneModiAdresse, istCrewAdresse, istTreffAdresse, istPruefAdresse, AUSSEN_ROLLEN,
import { sitzungPasstZurAdresse, istOhneModiAdresse, istCrewAdresse, istPruefAdresse, AUSSEN_ROLLEN,
TEAM_DOGI_ROLLEN } from "./crew-adresse.js";
/* Weitergereicht, damit die Fachmodule sie wie alles andere aus
workspace.js beziehen und nicht wissen muessen, wo sie wohnt. */
@@ -100,8 +100,22 @@ const ROLLEN_KACHEL = new Set(["spicy", "admin", "manager", "scout", "creator"])
*
* DogFather steht auf BEIDEN Waenden. Er ist die einzige Person, die
* in beiden Welten arbeitet; das ist keine Ausnahme von der Trennung,
* sondern ihr Sinn. */
const CREW_KACHEL = new Set(["admin", "hand", "modi"]);
* sondern ihr Sinn.
*
* VIER, SEIT DER TREFF HIER WOHNT (Entscheidung Filipe, 11.09.2026:
* "das soll keine app fuer sich sein, das soll in der crew seite
* adaptiert werden" -- und auf die Frage, wie die Community durch
* diese Wand kommt: "vierte Kachel Community").
*
* WAS DAS KOSTET, und es gehoert hierhin und nicht in eine Fussnote:
* Ein Mitglied der Community liest vor seiner Anmeldung die Namen der
* drei Team-Rollen. Die Alternative waere gewesen, die Kachelreihe
* ganz abzuschaffen und allein den Code entscheiden zu lassen -- dann
* haette niemand eine Rolle gesehen, aber Filipes Entscheidung vom
* 10.09. waere wieder umgeworfen worden. Er hat sich fuer die vierte
* Kachel entschieden; der Preis ist damit bewusst bezahlt und nicht
* uebersehen. */
const CREW_KACHEL = new Set(["admin", "hand", "modi", "gast"]);
/** Die Rollen mit einer Kachel auf der Zugangswand von treff.
*
@@ -114,7 +128,7 @@ const CREW_KACHEL = new Set(["admin", "hand", "modi"]);
* Die Menge steht trotzdem hier: Die Anmeldung prueft gegen sie, und
* eine Wand ohne Kacheln darf nicht heissen, dass jede Rolle
* durchkommt. */
const TREFF_KACHEL = new Set(["gast"]);
/* Als SQL-Ausdruck fuer ORDER BY. "ORDER BY rolle" waere alphabetisch
(admin, creator, manager, scout, spicy) -- also fast genau falsch
@@ -3288,7 +3302,7 @@ export function sitzungLesen(req) {
(sichtPerson) das auch nicht tut. Wer hier etwas anderes einbaut,
macht aus einer Anzeigefrage eine Rechtefrage. */
const haus = istCrewAdresse(req.get?.("host")) ? "crew"
: istTreffAdresse(req.get?.("host")) ? "treff" : "agentur";
: "agentur";
/* DER AUSSCHLUSS WIRKT HIER -- an derselben Stelle wie alles andere
(11.09.2026).
@@ -3676,9 +3690,7 @@ workspaceRouter.post("/workspace/api/anmelden", (req, res) => {
Wand gerade dran ist. Ein Manager, der crew. erraet und seinen
Code eintippt, faellt dadurch in genau dieselbe Antwort wie
jemand mit einer erfundenen Rolle. */
const kachelSatz = istTreffAdresse(req.get("host")) ? TREFF_KACHEL
: istCrewAdresse(req.get("host")) ? CREW_KACHEL
: ROLLEN_KACHEL;
const kachelSatz = istCrewAdresse(req.get("host")) ? CREW_KACHEL : ROLLEN_KACHEL;
if (!kachelSatz.has(rolle) || !codeBrauchbar) {
db().prepare("INSERT INTO versuche (ip, zeitpunkt) VALUES (?,?)").run(ip, jetzt());
@@ -4865,7 +4877,21 @@ export function protokollLesen(anzahl = 20) {
Die Reihenfolge ist egal (beide verkleinern nur), die Trennung nicht.
===================================================================== */
const HAUS_TEAM_ROLLEN = new Set(["admin", "hand", "modi"]);
/* WER AUF DER TEAM-ADRESSE UEBERHAUPT VORKOMMT.
*
* Die Community steht seit dem 11.09.2026 mit drin (Filipe: "das soll
* keine app fuer sich sein, das soll in der crew seite adaptiert
* werden"). Der Treff wohnt jetzt hier, also muessen seine Mitglieder
* hier auch verwaltet werden koennen -- sonst legt DogFather einen
* Zugang an und er verschwindet im selben Moment aus der Liste.
*
* DAS MACHT SIE NICHT ZU KOLLEGEN. Diese Menge beantwortet nur "wer
* kommt auf dieser Adresse vor". Ob jemand in eine Einladung, eine
* Aufgabe oder einen Chat darf, beantwortet ohneAussen() weiter unten
* -- und das sagt bei der Community ueberall Nein. Zwei verschiedene
* Fragen, zwei verschiedene Funktionen; wer sie in eine legt, kann
* spaeter nicht mehr sagen, welche gerade zugeschlagen hat. */
const HAUS_TEAM_ROLLEN = new Set(["admin", "hand", "modi", "gast"]);
function nurHaus(ids, person) {
if (person?.haus !== "crew") return ids;
@@ -4971,10 +4997,66 @@ function nurEigene(ids, person) {
return person?.id ? [person.id] : [];
}
export const sichtbareCreatorIds = (person) => nurEigene(nurCreatorIds(nurHaus(ohneVerborgene(sichtbareCreatorIdsRoh(person), person), person)), person);
/* =====================================================================
WER VON AUSSEN IST, STEHT IN KEINER ARBEITSLISTE (11.09.2026)
=====================================================================
nurEigene() beantwortet "was sieht ein Mitglied der Community?".
Diese Huelle beantwortet die andere Richtung: "steht ein Mitglied der
Community in der Liste, die jemand ANDERS bekommt?"
DER ANLASS: Seit es die Rolle gibt, taucht sie in jeder Liste auf,
die "alle" bedeutet -- und fuer DogFather bedeutet fast jede Liste
"alle" (siehtAlles). Ein Mitglied der Community stand damit in der
Auswahl, wen man zu einem Termin einlaedt, wem man eine Aufgabe gibt
und mit wem man einen Chat anfaengt. Nichts davon ist vorgesehen, es
gab dafuer nie eine Entscheidung, und aufgefallen waere es zum ersten
Mal, wenn jemand versehentlich einen Zuschauer zu einer internen
Besprechung einlaedt.
WARUM ALS HUELLE UND NICHT IN DEN VIER FUNKTIONEN: Weil sie dann auch
fuer die Listen gilt, die es noch nicht gibt. Dieselbe Ueberlegung
steht schon bei nurHaus() und bei der Modi-Huelle in
workspace-bereiche.js -- und beide Male war der erste Anlauf ein
einzelner geflickter Fall, der den naechsten offen liess.
NULL HEISST "ALLE" -- und sobald hier etwas herausfaellt, darf es das
nicht mehr heissen. Die Liste wird deshalb AUSGESCHRIEBEN, so wie
ohneVerborgene() und nurHaus() es auch tun.
EIN FEHLSCHLAG SCHLIESST. Bei einer Datenbankstoerung eine
ungefilterte Liste zurueckzugeben hiesse, die Community genau dann in
die Einladungsauswahl zu setzen, wenn ohnehin gerade etwas nicht
stimmt. Eine leere Liste ist sichtbar falsch, eine zu volle nicht.
AUSDRUECKLICH NICHT ANGEWENDET auf sichtbarePersonenIds(): Das ist
die Verwaltungsliste, in der DogFather Zugaenge anlegt und Codes neu
setzt. Dort MUSS die Community stehen. Die Einladungsliste leitet
sich zwar davon ab -- aber sie bekommt diese Huelle aussen herum,
und damit ist die Verwaltung offen und die Zusammenarbeit zu. */
function ohneAussen(ids) {
const rollen = [...AUSSEN_ROLLEN];
if (!rollen.length) return ids;
try {
const platz = rollen.map(() => "?").join(", ");
const aussen = db().prepare(
`SELECT id FROM personen WHERE rolle IN (${platz})`).all(...rollen).map((z) => z.id);
if (!aussen.length) return ids;
if (ids === null) {
return db().prepare(
`SELECT id FROM personen WHERE rolle NOT IN (${platz})`).all(...rollen).map((z) => z.id);
}
const menge = new Set(aussen);
return ids.filter((i) => !menge.has(i));
} catch {
return [];
}
}
export const sichtbareCreatorIds = (person) => ohneAussen(nurEigene(nurCreatorIds(nurHaus(ohneVerborgene(sichtbareCreatorIdsRoh(person), person), person)), person));
export const sichtbarePersonenIds = (person) => nurEigene(nurHaus(ohneVerborgene(sichtbarePersonenIdsRoh(person), person), person), person);
export const betreuerIds = (person) => nurEigene(nurHaus(ohneVerborgene(betreuerIdsRoh(person), person), person), person);
export const einladbareIds = (person) => nurEigene(nurHaus(ohneVerborgene(einladbareIdsRoh(person), person), person), person);
export const betreuerIds = (person) => ohneAussen(nurEigene(nurHaus(ohneVerborgene(betreuerIdsRoh(person), person), person), person));
export const einladbareIds = (person) => ohneAussen(nurEigene(nurHaus(ohneVerborgene(einladbareIdsRoh(person), person), person), person));
/* SICH SELBST NICHT -- UND ZWAR AUCH DANN NICHT, WENN DIE LISTE
AUSGESCHRIEBEN WIRD (10.09.2026).
@@ -4996,7 +5078,7 @@ export const einladbareIds = (person) => nurEigene(nurHaus(ohneVerborgene(einlad
seit es ueberhaupt jemanden zu verbergen gibt; vorher konnte es ihn
nicht geben. */
export const schreibbareIds = (person) => {
const ids = nurHaus(ohneVerborgene(schreibbareIdsRoh(person), person), person);
const ids = ohneAussen(nurHaus(ohneVerborgene(schreibbareIdsRoh(person), person), person));
return ids === null ? null : ids.filter((i) => i !== person?.id);
};
export const pipelineIds = (person) => nurHaus(ohneVerborgene(pipelineIdsRoh(person), person), person);
export const pipelineIds = (person) => ohneAussen(nurHaus(ohneVerborgene(pipelineIdsRoh(person), person), person));
+13 -42
View File
@@ -61,35 +61,6 @@ const SZENE = join(QUELLE, "gate-spicy-dogfather.jpeg");
const DOGI = join(QUELLE, "dogfather-husky.png");
const ZIEL = process.env.BUEHNE_ZIEL || join(WURZEL, "workspace", "assets", "img", "buehne");
/* ZWEI TUEREN, EIN WERKZEUG (11.09.2026).
Der Treff bekommt seine eigene Zugangswand, und sie braucht ihr
eigenes Motiv -- nicht weil sie anders aussehen soll, sondern weil
in diesem Bild "TEAM DOGI" EINGEBRANNT ist. Die Community traegt
diesen Namen nicht; auf ihrer Tuer stuende sonst der Name eines
Bereichs, zu dem sie nicht gehoert.
WARUM KEINE ZWEITE DATEI: Eine Kopie dieser 520 Zeilen haette die
drei Gegenproben mitkopiert -- und beim naechsten Nachbessern waere
genau eine der beiden verbessert worden. Hier aendern sich zwei
Dinge, also sind es zwei Werte und kein zweites Werkzeug.
DIE FARBE BLEIBT DIESELBE, und das ist eine Entscheidung, keine
Bequemlichkeit: Gemessen liegt der naechstbeste eigene Farbton
(Tannengruen) 60 Lab-Einheiten vom Marineblau entfernt -- er waere
also klar unterscheidbar gewesen. Nur haette der Treff damit wie ein
DRITTES Haus ausgesehen, neben Spicy Media und Team Dogi. Er ist
aber kein drittes Haus, sondern eine zweite Tuer in demselben:
"lila und babyblau ueberall" (Filipe, 10.09.2026). Unterschieden
werden die Tueren durch das WORT darauf, nicht durch die Farbe --
so, wie man es in einem Gebaeude auch macht.
node tools/crew-buehne.mjs
WAND_TEXT="DER TREFF" WAND_PRAEFIX=treff-gate node tools/crew-buehne.mjs
*/
const WAND_TEXT = process.env.WAND_TEXT || "TEAM DOGI";
const WAND_PRAEFIX = process.env.WAND_PRAEFIX || "crew-gate";
for (const q of [SZENE, DOGI]) {
if (!existsSync(q)) { console.error(`Fehlt: ${q}`); process.exit(1); }
}
@@ -324,14 +295,14 @@ async function bauen({ breite, ausschnitt = null, guete = 0.92, dunkel = 0.08,
g.restore();
}
/* ---- 5. Der Name auf der Tuer --------------------------------- */
/* ---- 5. "TEAM DOGI" ------------------------------------------- */
const schriftHoehe = Math.round(zh * 0.072);
g.save();
g.textAlign = "center";
g.textBaseline = "alphabetic";
g.font = `800 ${schriftHoehe}px "Segoe UI", system-ui, sans-serif`;
/* 0,955 lag halb unter dem Bildrand -- im Bildschirmfoto war von
dem Namen die untere Haelfte abgeschnitten. Jetzt so weit
"TEAM DOGI" die untere Haelfte abgeschnitten. Jetzt so weit
herauf, dass die Unterlaengen noch auf dem Wasser stehen. */
const ty = zh * 0.915;
/* Erst ein kalter Schein darunter, dann die Schrift in Metall --
@@ -339,7 +310,7 @@ async function bauen({ breite, ausschnitt = null, guete = 0.92, dunkel = 0.08,
g.shadowColor = "rgba(70,150,220,0.85)";
g.shadowBlur = schriftHoehe * 0.9;
g.fillStyle = "rgba(10,25,45,0.9)";
g.fillText(a.text, mx, ty);
g.fillText("TEAM DOGI", mx, ty);
g.shadowBlur = 0;
const metall = g.createLinearGradient(0, ty - schriftHoehe, 0, ty);
metall.addColorStop(0, "#ffffff");
@@ -347,7 +318,7 @@ async function bauen({ breite, ausschnitt = null, guete = 0.92, dunkel = 0.08,
metall.addColorStop(0.55, "#7ea6c6");
metall.addColorStop(1, "#e8f2fa");
g.fillStyle = metall;
g.fillText(a.text, mx, ty);
g.fillText("TEAM DOGI", mx, ty);
g.restore();
/* ---- 6. Vignette und ein Hauch Dunkel ------------------------- */
@@ -393,7 +364,7 @@ async function bauen({ breite, ausschnitt = null, guete = 0.92, dunkel = 0.08,
dogiKasten,
};
}, { szene: szeneDaten, dogi: dogiDaten, breite, ausschnitt, guete, dunkel, vignette,
ohneDogi, tafel: TAFEL, text: WAND_TEXT });
ohneDogi, tafel: TAFEL });
return { ...roh, puffer: Buffer.from(roh.bild.split(",")[1], "base64") };
}
@@ -468,17 +439,17 @@ let gebaut = 0;
console.log("\n--- Quer ---");
for (const b of [960, 1280, 1600, 1920, 2560]) {
const r = await bauen({ breite: b, guete: 0.93, dunkel: 0.08, vignette: 0.26 });
writeFileSync(join(ZIEL, `${WAND_PRAEFIX}-${b}.webp`), r.puffer);
writeFileSync(join(ZIEL, `crew-gate-${b}.webp`), r.puffer);
gebaut++;
if (r.rotAnteil > 0.01) maengel.push(
`${WAND_PRAEFIX}-${b}: noch ${(r.rotAnteil * 100).toFixed(1)} % rote Bildpunkte -- Umfaerbung hat nicht gegriffen`);
`crew-gate-${b}: noch ${(r.rotAnteil * 100).toFixed(1)} % rote Bildpunkte -- Umfaerbung hat nicht gegriffen`);
if (r.tafelMittel > 46) maengel.push(
`${WAND_PRAEFIX}-${b}: die Tafel ist zu hell (${r.tafelMittel.toFixed(1)}) -- die Karte braucht einen ruhigen Grund`);
`crew-gate-${b}: die Tafel ist zu hell (${r.tafelMittel.toFixed(1)}) -- die Karte braucht einen ruhigen Grund`);
if (r.tafelStreuung > 34) maengel.push(
`${WAND_PRAEFIX}-${b}: in der Tafel ist zu viel Muster (Streuung ${r.tafelStreuung.toFixed(1)})`);
`crew-gate-${b}: in der Tafel ist zu viel Muster (Streuung ${r.tafelStreuung.toFixed(1)})`);
console.log(` ${WAND_PRAEFIX}-${b}.webp`.padEnd(30)
console.log(` crew-gate-${b}.webp`.padEnd(30)
+ `${(r.puffer.length / 1024).toFixed(0)} KB · ${r.breite}x${r.hoehe}`
+ ` · Rot ${(r.rotAnteil * 100).toFixed(2)} %`
+ ` · Tafel ${r.tafelMittel.toFixed(1)}/${r.tafelStreuung.toFixed(1)}`);
@@ -500,11 +471,11 @@ for (const b of [440, 580, 900]) {
ausschnitt: [0.13, 0.02, 0.32, 0.98], guete: 0.88,
dunkel: 0.22, vignette: 0.30,
});
writeFileSync(join(ZIEL, `${WAND_PRAEFIX}-hoch-${b}.webp`), r.puffer);
writeFileSync(join(ZIEL, `crew-gate-hoch-${b}.webp`), r.puffer);
gebaut++;
if (r.rotAnteil > 0.01) maengel.push(
`${WAND_PRAEFIX}-hoch-${b}: noch ${(r.rotAnteil * 100).toFixed(1)} % rote Bildpunkte`);
console.log(` ${WAND_PRAEFIX}-hoch-${b}.webp`.padEnd(30)
`crew-gate-hoch-${b}: noch ${(r.rotAnteil * 100).toFixed(1)} % rote Bildpunkte`);
console.log(` crew-gate-hoch-${b}.webp`.padEnd(30)
+ `${(r.puffer.length / 1024).toFixed(0)} KB · ${r.breite}x${r.hoehe}`
+ ` · Rot ${(r.rotAnteil * 100).toFixed(2)} %`);
}
+4 -4
View File
@@ -13,25 +13,25 @@
"theme_color": "#06090f",
"icons": [
{
"src": "/assets/img/app-symbole/workspace-192.png?v=202609111804",
"src": "/assets/img/app-symbole/workspace-192.png?v=202609111836",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-512.png?v=202609111804",
"src": "/assets/img/app-symbole/workspace-512.png?v=202609111836",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609111804",
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609111836",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609111804",
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609111836",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

+1 -26
View File
@@ -76,31 +76,6 @@
und zwar ohne Fehlermeldung im Protokoll. */
const ohneKacheln = rollen.length === 0;
/* UND SEIT DEM 11.09.2026 GIBT ES SIE WIEDER -- die Wand des Treffs.
Dort ist nur EINE Sorte Zugang vorgesehen, und eine Kachelreihe
mit genau einem Eintrag waere keine Auswahl, sondern eine Huerde:
ein Knopf, den man druecken muss, damit der naechste Knopf
funktioniert.
DER SERVER BRAUCHT DIE ROLLE TROTZDEM. Er vergleicht sie gegen den
Kachelsatz seiner Adresse; kaeme "" an, waere die Antwort dieselbe
wie bei einem falschen Code -- 401, ohne dass irgendwo etwas
kaputt ist. Genau so eine Stelle sucht man lange, denn sie sieht
aus wie ein Tippfehler des Nutzers.
WARUM DAS AM <body> STEHT UND NICHT IM SKRIPT: gate.js wird an
ALLE drei Waende ausgeliefert. Eine Fallunterscheidung hier
("wenn Treff, dann gast") waere eine vierte Stelle, an der die
Adressen aufgezaehlt werden -- und die erste, die beim naechsten
Umbau vergessen wird. Die Wand sagt selbst, wofuer sie da ist.
EIN LECK IST DAS NICHT: Auf dieser Wand gibt es genau diese eine
Rolle. Der Name verraet nichts, was der Seitenkopf nicht ohnehin
sagt -- die beiden anderen Waende nennen ihre Rollen seit jeher
offen im Quelltext. */
const VORGABE = document.body.dataset.rolle || "";
/* ---------- Rolle wählen ------------------------------------------ */
function waehle(rolle, fokus = false) {
@@ -186,7 +161,7 @@
braucht ihn dort nicht: Er prueft den verborgenen Zugang
VOR dem gewohnten Weg, und ein leerer Name faellt danach in
dieselbe Antwort wie ein erfundener. */
body: JSON.stringify({ rolle: gewaehlt || VORGABE, code: wert }),
body: JSON.stringify({ rolle: gewaehlt || '', code: wert }),
credentials: 'same-origin',
});
+12 -12
View File
@@ -12,19 +12,19 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -252,10 +252,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/aufgaben.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/aufgaben.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -147,10 +147,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/automation.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/automation.js?v=202609111836" defer></script>
</body>
</html>
+17 -17
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -181,14 +181,14 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/checkliste.js?v=202609111804" defer></script>
<script src="assets/js/ampel.js?v=202609111804" defer></script>
<script src="assets/js/schulung.js?v=202609111804" defer></script>
<script src="assets/js/vorlagen.js?v=202609111804" defer></script>
<script src="assets/js/bereich.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/checkliste.js?v=202609111836" defer></script>
<script src="assets/js/ampel.js?v=202609111836" defer></script>
<script src="assets/js/schulung.js?v=202609111836" defer></script>
<script src="assets/js/vorlagen.js?v=202609111836" defer></script>
<script src="assets/js/bereich.js?v=202609111836" defer></script>
</body>
</html>
+14 -14
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -89,11 +89,11 @@
</main>
<script src="assets/js/ki.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/calls.js?v=202609111804" defer></script>
<script src="assets/js/ki.js?v=202609111836" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/calls.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,26 +12,26 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<!-- aufgaben.css bringt die Dialog- und Formularstile mit (.dialog,
.neu__zeile, .dialog__knoepfe). Sie stehen dort seit dem
Aufgabenbrett; sie hierher zu kopieren hiesse, sie an zwei Stellen
zu pflegen. Dieselbe Lösung nutzen kalender.html und content.html.
Gemeldet von pruef-css-klassen.mjs, bevor jemand einen ungestylten
Dialog zu sehen bekam. -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -341,10 +341,10 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609111804"></script>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804"></script>
<script src="assets/js/glocke.js?v=202609111804"></script>
<script src="assets/js/chat.js?v=202609111804"></script>
<script src="assets/js/bereiche.js?v=202609111836"></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836"></script>
<script src="assets/js/glocke.js?v=202609111836"></script>
<script src="assets/js/chat.js?v=202609111836"></script>
</body>
</html>
+15 -15
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/content.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/content.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -179,12 +179,12 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/checkliste.js?v=202609111804" defer></script>
<script src="assets/js/vorlagen.js?v=202609111804" defer></script>
<script src="assets/js/content.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/checkliste.js?v=202609111836" defer></script>
<script src="assets/js/vorlagen.js?v=202609111836" defer></script>
<script src="assets/js/content.js?v=202609111836" defer></script>
</body>
</html>
+75 -8
View File
@@ -3,8 +3,14 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>Anmeldung · Team Dogi</title>
<meta name="description" content="Privater Arbeitsbereich für DogFather und die Modis." />
<title>Anmeldung · DogFather Universe</title>
<!-- WEDER "Arbeitsbereich" NOCH "die Modis" (11.09.2026).
Seit die Community durch diese Wand kommt, liest sie auch diesen
Satz. "Privater Arbeitsbereich fuer DogFather und die Modis" waere
fuer sie schlicht falsch -- und das Erste, was sie ueber das Haus
erfaehrt. -->
<meta name="description" content="Privater Bereich rund um DogFather. Zugang nur mit persönlichem Code." />
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<!-- Die Farbe der Fensterleiste, wenn der Workspace als App laeuft.
@@ -30,15 +36,15 @@
<link rel="preload" as="image" href="assets/img/buehne/crew-gate-hoch-580.webp"
type="image/webp" media="(max-width: 899px)" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<!-- Diese Wand steht NUR auf der Adresse von Team Dogi (ueberall sonst
404, siehe crewWeiche). Sie darf das Haus deshalb direkt nennen
statt ueber den Platzhalter haus.css zu gehen -- und sie MUSS es:
Eine Zugangswand, die sich erst nach dem Umbiegen faerbt, waere
die eine Seite, auf der man das Umfaerben sieht. -->
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609111836" />
</head>
<body class="gate gate--crew">
@@ -111,6 +117,42 @@
<path fill="rgba(255,255,255,.32)"
d="M8.4 13.6c1-1.3 2.6-2 4.2-1.9-1.7.5-3 1.6-3.6 2.9z"/>
</g>
<!-- DIE COMMUNITY (11.09.2026).
Zwei Figuren, keine einzelne. Das Zeichen EINER Person ist im
Haus schon vergeben; zwei Rollen mit demselben Zeichen heisst,
dass das Zeichen nichts mehr sagt.
(Und ja: Hier stand zuerst der Name jener anderen Rolle. Diese
Datei wird an jedes Mitglied der Community ausgeliefert, samt
Kommentaren -- eine Rolle der Agentur hat darin nichts verloren.
Gefunden hat das nicht das Auge, sondern pruef-crew-adresse, die
seit dem 10.09. genau danach sucht. Zum zweiten Mal an einem Tag,
und zum zweiten Mal in einem Kommentar, der erklaert, warum man
so etwas nicht schreibt.)
Die hintere Figur ist leiser gesetzt und teilweise verdeckt -- das
ist keine Zierde: Bei 22 px verschmelzen zwei gleich helle Formen
zu einem Klecks. Erst der Helligkeitsunterschied macht daraus zwei
Menschen.
DERSELBE VERLAUF WIE DIE PFOTE, nicht der Husky-Filter: Die Pfote
steht bei denen, die taeglich unterwegs sind, der Husky bei denen
mit dem Ueberblick. Die Community ist weder das eine noch das
andere -- sie bekommt die Farbe der Pfote und eine eigene Form.
Ein drittes Farbsystem auf einer Wand mit vier Kacheln waere
Unruhe ohne Aussage. -->
<g id="r-leute">
<circle fill="url(#rs-pfote)" opacity=".55" cx="15.9" cy="8.1" r="2.9"/>
<path fill="url(#rs-pfote)" opacity=".55"
d="M10.6 20.4v-2.2c0-2.6 2.4-4.3 5.3-4.3s5.3 1.7 5.3 4.3v2.2z"/>
<circle fill="url(#rs-pfote)" cx="9.2" cy="7.4" r="3.4"/>
<path fill="url(#rs-pfote)"
d="M2.8 20.4v-2.5c0-3 2.9-5 6.4-5s6.4 2 6.4 5v2.5z"/>
<path fill="rgba(255,255,255,.3)"
d="M6.6 5.6a3.4 3.4 0 0 1 3.6-1.4c-1.4.3-2.5 1.2-3 2.4z"/>
</g>
</defs></svg>
@@ -180,7 +222,7 @@
<span class="marke__crew">Team&nbsp;Dogi</span>
</p>
<h1 class="titel">Team&nbsp;Dogi</h1>
<p class="unterzeile">Privater Bereich für DogFather und die Modis.</p>
<p class="unterzeile">Team Dogi und der Treff. Zugang nur mit persönlichem Code.</p>
</header>
<div class="rollen" role="radiogroup" aria-labelledby="rollen-schild">
@@ -214,6 +256,31 @@
<span class="rolle__zusatz">Chat, Live und eigene Aufgaben</span>
</span>
</button>
<!-- DIE VIERTE KACHEL (Entscheidung Filipe, 11.09.2026).
Der Treff ist kein eigenes Haus mehr, sondern ein Raum in
diesem. Damit kommt die Community durch DIESE Wand, und sie
braucht etwas zum Drauftippen.
SIE STEHT GANZ UNTEN, und das ist nicht Rangfolge, sondern
Haeufigkeit: Die drei darueber melden sich taeglich an, die
Community-Kachel wird von jedem Einzelnen genau einmal
gedrueckt und danach merkt sich der Browser die Wahl
(localStorage, siehe gate.js). Wer taeglich kommt, soll oben
finden, was er taeglich braucht.
DER UNTERTITEL BESCHREIBT EINEN ORT, KEINE RECHTE -- dieselbe
Ueberlegung wie bei den drei anderen: Wer vor der Auswahl
steht, fragt sich nicht, was er duerfte, sondern wo er
hinwill. -->
<button type="button" class="rolle" data-rolle="gast" role="radio" aria-checked="false">
<svg class="rolle__zeichen" viewBox="0 0 24 24" aria-hidden="true"><use href="#r-leute"/></svg>
<span class="rolle__text">
<span class="rolle__name">Community</span>
<span class="rolle__zusatz">Der Treff</span>
</span>
</button>
</div>
@@ -252,6 +319,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609111804" defer></script>
<script src="assets/js/gate.js?v=202609111836" defer></script>
</body>
</html>
+7 -7
View File
@@ -1,7 +1,7 @@
{
"name": "Team Dogi",
"short_name": "Team Dogi",
"description": "Aufgaben, Termine, Ideen und Angebote an einem Ort. Nur mit persönlichem Zugangscode.",
"name": "DogFather Universe",
"short_name": "DogFather",
"description": "Team Dogi und der Treff an einem Ort. Nur mit persoenlichem Zugangscode.",
"start_url": "/workspace/start.html",
"id": "/workspace/start.html",
"scope": "/workspace/",
@@ -13,25 +13,25 @@
"theme_color": "#06090f",
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609111804",
"src": "/assets/img/app-symbole/crew-192.png?v=202609111836",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609111804",
"src": "/assets/img/app-symbole/crew-512.png?v=202609111836",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609111804",
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609111836",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609111804",
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609111836",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -108,10 +108,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/dateien.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/dateien.js?v=202609111836" defer></script>
</body>
</html>
+4 -4
View File
@@ -30,9 +30,9 @@
<link rel="preload" as="image" href="assets/img/buehne/gate-hoch-580.webp"
type="image/webp" media="(max-width: 899px)" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
</head>
<body class="gate">
@@ -401,6 +401,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609111804" defer></script>
<script src="assets/js/gate.js?v=202609111836" defer></script>
</body>
</html>
+14 -14
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -377,11 +377,11 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/kalender.js?v=202609111804" defer></script>
<script src="assets/js/kalender-abo.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/kalender.js?v=202609111836" defer></script>
<script src="assets/js/kalender-abo.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -382,10 +382,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609111804"></script>
<script src="assets/js/bereiche.js?v=202609111804"></script>
<script src="assets/js/kopf.js?v=202609111804"></script>
<script src="assets/js/glocke.js?v=202609111804"></script>
<script src="assets/js/leistung.js?v=202609111804"></script>
<script src="assets/js/wahl.js?v=202609111836"></script>
<script src="assets/js/bereiche.js?v=202609111836"></script>
<script src="assets/js/kopf.js?v=202609111836"></script>
<script src="assets/js/glocke.js?v=202609111836"></script>
<script src="assets/js/leistung.js?v=202609111836"></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -423,10 +423,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/personen.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/personen.js?v=202609111836" defer></script>
</body>
</html>
+14 -14
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -214,11 +214,11 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/steckbrief.js?v=202609111804" defer></script>
<script src="assets/js/profil.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/steckbrief.js?v=202609111836" defer></script>
<script src="assets/js/profil.js?v=202609111836" defer></script>
</body>
</html>
+12 -12
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -117,9 +117,9 @@
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
die seit dem 07.09. jede Seite danach absucht. -->
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/rechte.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/rechte.js?v=202609111836" defer></script>
</body>
</html>
+14 -14
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/report.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/report.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -106,11 +106,11 @@
</main>
<script src="assets/js/ki.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/report.js?v=202609111804" defer></script>
<script src="assets/js/ki.js?v=202609111836" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/report.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -173,10 +173,10 @@
</div>
</div>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/scouting.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/scouting.js?v=202609111836" defer></script>
</body>
</html>
+12 -12
View File
@@ -12,21 +12,21 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<!-- Nur die Startseite: Begrüßungskachel, Uhr, Glockenmulde. Siehe
den Hinweis in start.css -- dort stand es bis zum 07.09.2026. -->
<link rel="stylesheet" href="assets/css/heim.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -674,10 +674,10 @@
</p>
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/start.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/start.js?v=202609111836" defer></script>
</body>
</html>
+14 -14
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -85,11 +85,11 @@
</main>
<script src="assets/js/ki.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/startcheck.js?v=202609111804" defer></script>
<script src="assets/js/ki.js?v=202609111836" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/startcheck.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -126,10 +126,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/steckbrief.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/steckbrief.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -7,20 +7,20 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -110,10 +110,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/team.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/team.js?v=202609111836" defer></script>
</body>
</html>
+12 -12
View File
@@ -7,20 +7,20 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<!-- `data-buehne` steht hier fest und nicht im Skript: Die Kachel zu
@@ -84,9 +84,9 @@
Kaputt ist dabei nichts -- er funktioniert. Genau deshalb faellt
es niemandem auf, und deshalb prueft pruef-css-klassen die
ABHAENGIGKEIT statt der Optik. Hier hat sie angeschlagen. -->
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/teamlage.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/teamlage.js?v=202609111836" defer></script>
</body>
</html>
-163
View File
@@ -1,163 +0,0 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>Anmeldung · Der Treff</title>
<!-- Die Beschreibung nennt WEDER Rollen NOCH Bereiche des Teams.
Auf den beiden anderen Waenden steht dort, wofuer sie da sind, und
das ist dort richtig: Wer sie liest, gehoert ohnehin dazu. Hier
steht ein Mensch, der NICHT zum Team gehoert. Was er auf der
Anmeldeseite liest, ist das Einzige, was er ueber das Haus
erfaehrt, solange er den Code nicht hat.
UND DIESER KOMMENTAR HAT SICH SELBST ERWISCHT (11.09.2026): Er
zaehlte urspruenglich als Beispiel auf, was auf der anderen Wand
steht -- und nannte dabei eine Rolle des Hauses, in einer Datei,
die jeder Besucher des Treffs im Quelltext lesen kann. Gefunden
hat das nicht das Auge, sondern eine Zeile in pruef-treff, die
genau danach sucht. Ein Kommentar in einer ausgelieferten Datei
ist kein Notizzettel. -->
<meta name="description" content="Der Treffpunkt rund um DogFather. Zugang nur mit persönlichem Code." />
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<!-- Derselbe Ton wie die Kopfleiste dahinter, damit Fensterleiste und
Seite eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<!-- Quer- und Hochformat getrennt vorgeladen, damit das Handy nicht die
grosse Fassung zieht. WebP und nicht AVIF: Der ausliefernde Express 4
bringt eine MIME-Tabelle ohne AVIF mit, die Dateien kaemen als
application/octet-stream an und wuerden wegen nosniff verweigert --
die Buehne bliebe leer. (Ausfuehrlich in crew-index.html.) -->
<link rel="preload" as="image" href="assets/img/buehne/treff-gate-1920.webp"
type="image/webp" media="(min-width: 900px)" />
<link rel="preload" as="image" href="assets/img/buehne/treff-gate-hoch-580.webp"
type="image/webp" media="(max-width: 899px)" />
<!-- DASSELBE APP-SYMBOL WIE TEAM DOGI, und das ist kein Sparen.
Es zeigt den Husky -- das Zeichen des HAUSES, nicht das einer
Rolle. Wer den Treff auf seinen Startbildschirm legt, legt sich
Dogis Zeichen dorthin, und genau das ist gemeint. Unterschieden
werden die beiden Apps durch den NAMEN darunter ("Der Treff" gegen
"Team Dogi"), und niemand hat beide: Ein Konto der Community kommt
auf crew. nicht herein, ein Konto des Teams hier nicht. -->
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<!-- Diese Wand steht NUR auf der Adresse des Treffs (ueberall sonst 404,
siehe treffWeiche). Sie darf das Haus deshalb direkt nennen statt
ueber den Platzhalter haus.css zu gehen -- und sie MUSS es: Eine
Zugangswand, die sich erst nach dem Umbiegen faerbt, waere die eine
Seite, auf der man das Umfaerben sieht. -->
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609111804" />
</head>
<!-- ====================================================================
`gate--crew` IST HIER KEIN VERSEHEN (11.09.2026).
Darin stehen die Abweichungen, die aus der UMGEFAERBTEN Buehne
folgen: Der Anmeldeknopf laeuft von Lila nach Babyblau statt von
Rot nach Blau, und die Karte nimmt die Farben des gemalten Rahmens
auf -- ringsum blau. Die Buehne des Treffs ist dieselbe Szene in
derselben Farbe; jede dieser Abweichungen gilt hier wortgleich.
Eine eigene Klasse `gate--treff` waere eine Kopie derselben Werte
gewesen. Beim naechsten Nachbessern des Knopfes haette jemand eine
der beiden verbessert -- und das ist genau der Fehler, gegen den
in diesem Haus die halbe Dokumentation geschrieben ist.
`data-rolle` sagt dem Anmeldeskript, wofuer diese Wand da ist.
Ohne Kachelreihe kaeme sonst eine leere Rolle beim Server an, und
der antwortet darauf wie auf einen falschen Code: 401, ohne dass
irgendwo etwas kaputt ist.
================================================================= -->
<body class="gate gate--crew gate--treff" data-rolle="gast">
<!-- ---------- Bühne: Bild + Schleier ---------------------------------- -->
<div class="buehne" aria-hidden="true">
<picture>
<source media="(min-width: 900px)" type="image/webp"
srcset="assets/img/buehne/treff-gate-960.webp 960w,
assets/img/buehne/treff-gate-1280.webp 1280w,
assets/img/buehne/treff-gate-1600.webp 1600w,
assets/img/buehne/treff-gate-1920.webp 1920w,
assets/img/buehne/treff-gate-2560.webp 2560w" sizes="100vw" />
<source type="image/webp"
srcset="assets/img/buehne/treff-gate-hoch-440.webp 440w,
assets/img/buehne/treff-gate-hoch-580.webp 580w,
assets/img/buehne/treff-gate-hoch-900.webp 900w" sizes="100vw" />
<img class="buehne__bild" src="assets/img/buehne/treff-gate-1280.webp" alt=""
width="1647" height="955" fetchpriority="high" decoding="async" />
</picture>
<div class="buehne__schleier"></div>
</div>
<!-- ---------- Tafel ----------------------------------------------------
Der Anker rechnet die Cover-Geometrie des Bildes nach, damit die
Karte in der GEMALTEN Tafel sitzt und nicht ungefaehr dort. Er
faengt keine Klicks ab; nur die Karte darin ist bedienbar.
(Herleitung in crew-index.html und gate.css.) -->
<div class="tafel-anker">
<main class="tafel" id="tafel">
<div class="tafel__kante" aria-hidden="true"></div>
<!-- EIN NAME, KEIN PAAR.
Die Wand von Team Dogi setzt oben "DogFather × Team Dogi" -- zwei,
die das zusammen machen. Hier waere dasselbe falsch: Der Treff
gehoert nicht DogFather und der Community gemeinsam, er ist der
Ort, an dem sie sich treffen. Deshalb steht oben nur das Haus und
darunter der Raum. -->
<header class="kopf">
<p class="marke marke--paar">
<span class="marke__crew">DogFather&nbsp;Universe</span>
</p>
<h1 class="titel">Der&nbsp;Treff</h1>
<p class="unterzeile">Schön, dass du da bist. Gib deinen Code ein.</p>
</header>
<form class="formular" id="formular" novalidate>
<label class="feldschild" for="code">
Persönlicher Zugangscode <span class="fuer" id="fuer" hidden></span>
</label>
<div class="feld">
<input type="password" id="code" name="code" inputmode="text"
autocomplete="current-password" spellcheck="false"
placeholder="Code eingeben" aria-describedby="hinweis fehler" />
<button type="button" class="feld__auge" id="auge"
aria-label="Code anzeigen" aria-pressed="false">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path class="strich" d="M2.5 12S6 5.8 12 5.8 21.5 12 21.5 12 18 18.2 12 18.2 2.5 12 2.5 12Z"/>
<circle class="strich" cx="12" cy="12" r="2.9"/>
<path class="strich durch" d="m4 20 16-16"/>
</svg>
</button>
</div>
<p class="hinweis" id="hinweis" hidden>Feststelltaste ist aktiv.</p>
<p class="fehler" id="fehler" role="alert" aria-live="polite"></p>
<button type="submit" class="knopf" id="knopf">
<span class="knopf__text">Anmelden</span>
<span class="knopf__laden" aria-hidden="true"></span>
</button>
</form>
<!-- KEIN "NOCH KEINEN CODE? HIER ANFRAGEN".
Das waere die naheliegende Zeile und genau die falsche: Sie macht
aus einer verborgenen Adresse eine oeffentliche Anmeldestelle,
und jeder, der die Adresse errät, haette einen Weg, Aufmerksamkeit
zu verlangen. Codes werden persoenlich vergeben -- wer keinen hat,
hat hier auch nichts zu klaeren. -->
<p class="fuss">
Verschlüsselte Verbindung · Zugriffe werden protokolliert
</p>
</main>
</div>
<script src="assets/js/gate.js?v=202609111804" defer></script>
</body>
</html>
+12 -12
View File
@@ -7,14 +7,14 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -110,9 +110,9 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/treff-moderation.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/treff-moderation.js?v=202609111836" defer></script>
</body>
</html>
+12 -12
View File
@@ -7,18 +7,18 @@
<meta name="robots" content="noindex, nofollow" />
<link rel="manifest" href="/workspace/app.webmanifest" />
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/treff.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein. Auf der Adresse des
Treffs biegt der Server genau diesen Dateinamen auf crew-haus.css
um, und die Seite kommt schon beim ERSTEN Abruf in Lila und
Babyblau an -- ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -190,9 +190,9 @@
Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen
Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen,
die seit dem 07.09. jede Seite danach absucht. -->
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/treff-regeln.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/treff-regeln.js?v=202609111836" defer></script>
</body>
</html>
-40
View File
@@ -1,40 +0,0 @@
{
"name": "Der Treff",
"short_name": "Der Treff",
"description": "Der Treffpunkt rund um DogFather: Ansagen, Termine, Wuensche und das Gespraech. Nur mit persoenlichem Zugangscode.",
"start_url": "/workspace/start.html",
"id": "/workspace/start.html",
"scope": "/workspace/",
"display": "standalone",
"orientation": "any",
"lang": "de",
"dir": "ltr",
"background_color": "#0a121e",
"theme_color": "#06090f",
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609111804",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609111804",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609111804",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609111804",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
+13 -13
View File
@@ -12,22 +12,22 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -149,11 +149,11 @@
</main>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/uebersicht.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/uebersicht.js?v=202609111836" defer></script>
</body>
</html>
+13 -13
View File
@@ -12,20 +12,20 @@
Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite
eine Flaeche sind statt zweier. -->
<meta name="theme-color" content="#06090f" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111804" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111804" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111804" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111836" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111836" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609111836" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111836" />
<!-- haus.css MUSS die letzte Stilvorlage sein (10.09.2026).
Auf der Agenturadresse ist sie leer -- das Haus hier IST der
Grundzustand. Auf der Adresse von Team Dogi biegt der Server
genau diesen Dateinamen auf crew-haus.css um, und die Seite
kommt schon beim ERSTEN Abruf in Lila und Babyblau an --
ohne Umfaerben im Browser, ohne Flackern. -->
<link rel="stylesheet" href="assets/css/haus.css?v=202609111804" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111836" />
</head>
<body class="start">
@@ -190,10 +190,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111804" defer></script>
<script src="assets/js/bereiche.js?v=202609111804" defer></script>
<script src="assets/js/kopf.js?v=202609111804" defer></script>
<script src="assets/js/glocke.js?v=202609111804" defer></script>
<script src="assets/js/wissen.js?v=202609111804" defer></script>
<script src="assets/js/wahl.js?v=202609111836" defer></script>
<script src="assets/js/bereiche.js?v=202609111836" defer></script>
<script src="assets/js/kopf.js?v=202609111836" defer></script>
<script src="assets/js/glocke.js?v=202609111836" defer></script>
<script src="assets/js/wissen.js?v=202609111836" defer></script>
</body>
</html>