Die goldene Regel: was nicht in der Tafel steht, ist verboten

Filipe: "egal welche rolle oder person hinzugefuegt wird soll immer nur
das sehen wass ich erlaube. mehr nicht. soll nichts so sein dass wenn
mann eine rolle oder jemanden hinzufuegt dass er dan alles sieht."

DER BEFUND -- GEZAEHLT, NICHT GESCHAETZT

NEUN von zwanzig Seiten standen auf `null`, und `null` hiess "jede
angemeldete Rolle": Start, Uebersicht, Aufgaben, Chat, Kalender,
Dateien, Calls, Start-Check, Wissen. Eine neue Rolle erbte sie alle,
ohne dass jemand etwas erlaubt haette.

UND EIN ZWEITES LOCH, das ich vorher nicht gemessen hatte: Die Schranke
las `const erlaubt = GESCHUETZT[pfad]` und prueffte `if (erlaubt && ...)`.
Eine Seite, die GAR NICHT in der Tabelle stand, ergab `undefined`, fiel
durch dieselbe Bedingung und war damit ebenfalls fuer jede angemeldete
Rolle offen. Am 11.09.2026 betraf das keine einzige Seite (nachgezaehlt:
22 Dateien = 20 Eintraege + 2 Zugangswaende) -- aber jede NEUE waere so
entstanden.

Die Rolle wird im Haus an 74 Stellen in 20 Modulen abgefragt, und die
Endzweige widersprechen einander: Aufgaben enden mit `default: 0=1`
(sieht nichts), Bereiche und Dateien fallen in "eigene plus betreute".
Drei Module, drei Antworten auf dieselbe Frage.

WARUM NICHT "DIE LISTE DURCHGEHEN"

Das waere die naheliegende Antwort und die falsche. Im Code stand seit
dem 10.09. genau dieser Satz -- "Wer eine Rolle hinzufuegt, muss diese
Liste durchgehen" -- und einen Tag spaeter standen immer noch neun
Seiten auf `null`. Ein Satz, der sich auf ein Gedaechtnis verlaesst, ist
keine Sicherung. Dazu: eine vergessene Erlaubnis MELDET SICH NIE. Die
Seite laedt ja. In der anderen Richtung ist es schlimmer -- eine Seite,
die zu viel zeigt, sieht aus wie eine Seite, die funktioniert.

WAS JETZT GILT

server/rechte.js traegt die Tafel, `darfSeite()` liest sie, und sie
kennt zwei Antworten: Seite in der Tafel UND Rolle darin -> ja. Alles
andere -> nein. Kein `null`, kein `undefined`, kein Zweig, der etwas
durchlaesst.

DIE TABELLE IST UMGEZOGEN, NICHT NEU GESCHRIEBEN. In ihren Kommentaren
steckt das Gedaechtnis des Hauses -- jede Zeile traegt ein Datum und
einen Satz von Filipe ("nimm die kategorie zahlen bei jedem weg", "die
manager sollen diese kategorien garnicht sehen", "ich will dass die
rechte Hand auch alle sieht"). Die wegzurefactoren waere der teuerste
Fehler dieses Umbaus gewesen.

VERHALTENSGLEICH FUER DIE SIEBEN VORHANDENEN ROLLEN. Die neun
`null`-Seiten tragen jetzt alle sieben Namen. Eine Umkehrung, die
nebenbei Rechte entzieht, waeren zwei Aenderungen in einer -- und man
wuesste hinterher nicht, welche etwas kaputtgemacht hat. Enger stellen
ist ein eigener Schritt.

pruef-rechtetafel.mjs (NEU, 19 Pruefungen, Port 4397) macht daraus eine
Garantie statt einer Absicht:

  * Jede Rolle braucht einen Eintrag -- sonst rot. Man kann eine Rolle
    nicht mehr hinzufuegen, ohne zu entscheiden, was sie sieht.
  * Jede Seite braucht einen Eintrag -- verglichen gegen das
    DATEISYSTEM, nicht gegen eine zweite Liste. Eine neue Seite ist
    damit erst einmal fuer NIEMANDEN offen statt fuer alle.
  * Eine Phantomrolle kommt auf keine der zwanzig Seiten.
  * Gegenprobe: jede ECHTE Rolle kommt irgendwo hin (spicy 18, admin 20,
    manager 17, scout 16, creator 15, hand 13, modi 11) -- sonst waere
    die Zeile darueber auch gruen, wenn schlicht alles zu waere.
  * Am Server: eine Seite ohne Eintrag wird abgewiesen statt
    ausgeliefert, und alle 20 Seiten der DogFather-Rolle liefern wirklich.
  * Zerstoerende Probe ganz am Ende (die Lektion vom 09.09.: in der
    Mitte verbiegt sie alles danach).

ZWEI EIGENE FEHLER UNTERWEGS. `node --check` meldete "Syntax in
Ordnung", das Modul lud aber nicht -- beim Umzug war eine Konstante
verlorengegangen. Syntax ist kein Beweis. Und ein Kommentar behauptete
danach noch das Alte ("eine neue Seite ist mindestens nur fuer
Angemeldete"); der Rueckfall ist jetzt "fuer niemanden", und das steht
da auch so.

Gruen: pruef-rechtetafel 19 (neu), pruef-rollen 287, pruef-sicht 84,
pruef-crew-adresse 129, pruef-modi-verborgen 80, pruef-haus-trennung 62.
Stempel 202609111617.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-11 16:18:09 +02:00
co-authored by Claude Opus 5
parent 4219ac3f9d
commit 47a91e9708
27 changed files with 906 additions and 451 deletions
+280
View File
@@ -0,0 +1,280 @@
/* =====================================================================
DIE RECHTETAFEL — die Pruefung, die aus einer Absicht eine Garantie
macht (11.09.2026)
Filipe:
"egal welche rolle oder person hinzugefuegt wird soll immer nur das
sehen wass ich erlaube. mehr nicht. soll nichts so sein dass wenn
mann eine rolle oder jemanden hinzufuegt dass er dan alles sieht."
---------------------------------------------------------------------
WARUM DIESE DATEI UND NICHT EIN KOMMENTAR
In `rechte.js` stand bis heute ein Satz, der genau das Richtige
verlangte: *"Wer eine Rolle hinzufuegt, muss diese Liste durchgehen."*
Er stand seit dem 10.09. da, und am Tag darauf standen immer noch neun
Seiten auf `null`. Ein Satz, der sich auf ein Gedaechtnis verlaesst,
ist keine Sicherung.
Diese Datei verlaesst sich auf nichts. Sie wird rot, wenn
* eine Rolle keinen Eintrag hat,
* eine Seite keinen Eintrag hat,
* eine unbekannte Rolle irgendwo hineinkaeme,
* oder eine unbekannte Seite sich fuer irgendwen oeffnet.
Man KANN es damit nicht mehr vergessen -- der Prueflauf laesst es
nicht zu.
---------------------------------------------------------------------
DREI EBENEN, UND JEDE BEANTWORTET ETWAS ANDERES
1. DIE TAFEL SELBST, ohne Server. Vollstaendig, schnell, und sie
vergleicht gegen das DATEISYSTEM statt gegen eine zweite Liste --
eine zweite Liste waere die Stelle, an der beide auseinanderlaufen.
2. DER SERVER. Dass die Tafel richtig ist, heisst nicht, dass sie
auch gefragt wird. Genau dieser Unterschied hat am 10.09. drei
Stunden gekostet: Kachel und Schnittstelle stimmten, die Seite
warf trotzdem zurueck. Hier wird deshalb wirklich angeklopft.
3. DIE GEGENPROBE. Eine Pruefung, die immer bestaetigt, bestaetigt
nichts. Am Ende bekommt sie absichtlich eine kaputte Tafel und
MUSS sie als kaputt melden.
===================================================================== */
import { mkdtempSync, rmSync, readdirSync, existsSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { portMussFreiSein } from "./helfer-port.mjs";
const PORT = await portMussFreiSein(4397, "pruef-rechtetafel");
const ordner = mkdtempSync(join(tmpdir(), "ws-rechte-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
const express = (await import("express")).default;
const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
import { notbremse } from "./helfer-notbremse.mjs";
await import("./index.js");
notbremse(180_000, "pruef-rechtetafel");
await new Promise((r) => setTimeout(r, 700));
const BASIS = `http://127.0.0.1:${PORT}`;
/* EIGENE ZUHOERER. index.js haengt fuer den Betrieb Auffangnetze an
`uncaughtException` -- eine Pruefung, die dieselbe Datei in denselben
Prozess laedt, erbt sie und wuerde nach einem Absturz weiterhaengen,
statt rot zu werden. */
process.on("uncaughtException", (f) => { console.error("ABSTURZ:", f); process.exit(7); });
process.on("unhandledRejection", (f) => { console.error("ABSTURZ (Versprechen):", f); process.exit(7); });
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 rechte = await import("./rechte.js");
const w = await import("./workspace.js");
/* =======================================================================
1. DIE TAFEL IST VOLLSTAENDIG
======================================================================= */
melde("");
melde("=== 1. Jede Rolle und jede Seite hat einen Eintrag ===");
/* DIE ROLLENLISTE DARF NICHT ZWEIMAL EXISTIEREN.
rechte.js kennt ALLE_ROLLEN, workspace.js kennt ROLLEN. Zwei Listen
derselben Sache laufen auseinander -- die Frage ist nur wann. Hier
werden sie gegeneinandergehalten, damit das Wann "beim naechsten
Prueflauf" ist und nicht "wenn jemand hineinfaellt". */
{
const ausWorkspace = [...(w.ROLLEN_NAME ? Object.keys(w.ROLLEN_NAME) : [])].sort();
const ausTafel = [...rechte.ALLE_ROLLEN].sort();
ok(ausWorkspace.length > 0, `workspace.js kennt ${ausWorkspace.length} Rollen`);
ok(JSON.stringify(ausWorkspace) === JSON.stringify(ausTafel),
`beide Listen sind identisch (${ausTafel.join(", ")})`);
}
/* JEDE DATEI AUF DER PLATTE BRAUCHT EINEN EINTRAG.
Verglichen wird gegen das Dateisystem, nicht gegen eine Liste im Code.
Eine neue Seite entsteht als DATEI -- wer sie anlegt und den Eintrag
vergisst, faellt genau hier auf. */
const SEITEN_ORDNER = new URL("../workspace/", import.meta.url).pathname
.replace(/^\/([A-Za-z]:)/, "$1");
{
const dateien = readdirSync(SEITEN_ORDNER)
.filter((f) => f.endsWith(".html"))
.map((f) => "/workspace/" + f).sort();
const inTafel = new Set([...rechte.alleSeiten(), ...rechte.OHNE_ANMELDUNG]);
const fehlend = dateien.filter((p) => !inTafel.has(p));
const ueberzaehlig = rechte.alleSeiten().filter((p) => !dateien.includes(p));
ok(dateien.length >= 20, `${dateien.length} Seiten liegen im Ordner`);
ok(fehlend.length === 0,
`jede davon steht in der Tafel${fehlend.length ? " -- FEHLT: " + fehlend.join(", ") : ""}`);
ok(ueberzaehlig.length === 0,
`und jeder Eintrag hat eine Datei${ueberzaehlig.length ? " -- OHNE DATEI: " + ueberzaehlig.join(", ") : ""}`);
}
/* KEIN EINTRAG DARF UNSCHARF SEIN. `null` war der alte Fehler; eine
Rolle, die es gar nicht gibt, waere der naechste. */
{
const bekannt = new Set(rechte.ALLE_ROLLEN);
const kaputt = [];
for (const [pfad, rollen] of Object.entries(rechte.SEITEN)) {
if (!Array.isArray(rollen)) { kaputt.push(`${pfad}: kein Feld`); continue; }
for (const r of rollen) if (!bekannt.has(r)) kaputt.push(`${pfad}: unbekannte Rolle "${r}"`);
}
ok(kaputt.length === 0, `alle Eintraege sind Listen bekannter Rollen${kaputt.length ? " -- " + kaputt.join(" | ") : ""}`);
}
/* =======================================================================
2. WAS NICHT IN DER TAFEL STEHT, IST VERBOTEN
======================================================================= */
melde("");
melde("=== 2. Die Regel selbst ===");
const PHANTOM = "xx-gibt-es-nicht";
{
const alle = rechte.alleSeiten();
const durchgelassen = alle.filter((p) => rechte.darfSeite({ rolle: PHANTOM }, p));
ok(alle.length === 20, `${alle.length} Seiten in der Tafel`);
ok(durchgelassen.length === 0,
`eine unbekannte Rolle kommt auf KEINE davon${durchgelassen.length ? " -- durchgelassen: " + durchgelassen.join(", ") : ""}`);
/* DIE GEGENPROBE ZUR OBIGEN ZEILE. Ohne sie waere sie auch dann
gruen, wenn darfSeite() schlicht immer nein sagt -- und dann waere
das ganze Haus zu, ohne dass diese Datei es meldet. */
const echteWege = rechte.ALLE_ROLLEN
.map((r) => [r, alle.filter((p) => rechte.darfSeite({ rolle: r }, p)).length]);
const ohneSeite = echteWege.filter(([, n]) => n === 0).map(([r]) => r);
ok(ohneSeite.length === 0,
`und jede ECHTE Rolle kommt irgendwo hin (${echteWege.map(([r, n]) => r + ":" + n).join(" ")})`);
}
{
/* EINE SEITE, DIE ES NICHT GIBT. Das war das zweite Loch: `undefined`
fiel durch dieselbe Bedingung wie `null`. */
const erfunden = rechte.ALLE_ROLLEN
.filter((r) => rechte.darfSeite({ rolle: r }, "/workspace/gibt-es-nicht.html"));
ok(erfunden.length === 0,
`eine Seite ohne Eintrag oeffnet sich fuer niemanden -- auch nicht fuer DogFather`);
ok(rechte.darfSeite(null, "/workspace/start.html") === false,
"und ohne Anmeldung erst recht nicht");
}
/* =======================================================================
3. DIE TAFEL WIRD AUCH WIRKLICH GEFRAGT
======================================================================= */
melde("");
melde("=== 3. Der Server haelt sich daran ===");
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
const d = new DatabaseSync(process.env.WORKSPACE_DB);
const jetzt = new Date().toISOString();
const schluessel = randomBytes(32).toString("hex");
d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)"
+ " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING")
.run("code_kennung_schluessel", schluessel, jetzt);
function anlegen(name, rolle, code) {
const salt = randomBytes(16).toString("hex");
const hash = scryptSync(code, salt, 64, { N: 32768, r: 8, p: 1, maxmem: 96 * 1024 * 1024 }).toString("hex");
d.prepare("INSERT INTO personen (name, rolle, code_hash, code_salt, code_n, code_kennung, aktiv, erstellt)"
+ " VALUES (?,?,?,?,?,?,1,?)")
.run(name, rolle, hash, salt, 32768, createHmac("sha256", schluessel).update(code).digest("hex"), jetzt);
}
anlegen("Filipe", "admin", "CODE-DOGI-0001");
anlegen("Mara", "manager", "CODE-MANA-0001");
d.close();
async function anmelden(rolle, code) {
const a = await fetch(`${BASIS}/workspace/api/anmelden`, {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ rolle, code }),
});
return a.headers.getSetCookie().map((c) => c.split(";")[0]).join("; ");
}
const kDogi = await anmelden("admin", "CODE-DOGI-0001");
const kMana = await anmelden("manager", "CODE-MANA-0001");
async function hole(pfad, keks) {
const a = await fetch(BASIS + pfad, { headers: { cookie: keks }, redirect: "manual" });
return { status: a.status, ziel: a.headers.get("location") || "" };
}
ok(kDogi.length > 0 && kMana.length > 0, "beide Anmeldungen haben eine Sitzung");
{
const a = await hole("/workspace/automation.html", kDogi);
ok(a.status === 200, `DogFather kommt auf automation.html (${a.status})`);
const b = await hole("/workspace/automation.html", kMana);
ok(b.status === 302 && b.ziel.endsWith("start.html"),
`eine Managerin nicht -- sie landet auf der Startseite (${b.status} ${b.ziel})`);
}
{
/* DER EIGENTLICHE NEUE FALL: eine Seite, die es in der Tafel nicht
gibt. Vorher fiel sie durch die Schranke und traf danach auf
express.static -- also 404, was von aussen aussieht wie "gibt es
nicht", obwohl sie in Wahrheit einfach nicht geschuetzt war. Jetzt
greift die Schranke davor. */
const a = await hole("/workspace/gibt-es-nicht.html", kDogi);
ok(a.status === 302 && a.ziel.endsWith("start.html"),
`eine Seite ohne Eintrag wird abgewiesen, nicht ausgeliefert (${a.status} ${a.ziel})`);
}
{
/* Und die Gegenprobe: Die geoeffneten Seiten oeffnen sich wirklich.
Sonst waere "alles abgewiesen" ebenfalls gruen. */
let auf = 0;
for (const p of rechte.seitenFuer("admin")) {
const a = await hole(p, kDogi);
if (a.status === 200) auf++;
}
ok(auf === rechte.seitenFuer("admin").length,
`alle ${auf} Seiten der DogFather-Rolle liefern wirklich aus`);
}
/* =======================================================================
4. DIE GEGENPROBE: KANN DIESE PRUEFUNG UEBERHAUPT ROT WERDEN?
======================================================================= */
melde("");
melde("=== 4. Gegenprobe -- eine kaputte Tafel MUSS auffallen ===");
/* Dieselbe Vergleichslogik wie in Abschnitt 1, aber mit absichtlich
beschaedigten Daten. Steht ganz am Ende, damit ihr Schaden nichts
verfaelscht, was davor gemessen wurde -- die Lektion vom 09.09., als
eine zerstoerende Probe in der Mitte stand und alles danach verbog. */
{
const dateien = readdirSync(SEITEN_ORDNER).filter((f) => f.endsWith(".html"))
.map((f) => "/workspace/" + f);
const luecke = new Set([...rechte.alleSeiten(), ...rechte.OHNE_ANMELDUNG]);
luecke.delete("/workspace/start.html");
ok(dateien.some((p) => !luecke.has(p)),
"eine entfernte Seite wird als Luecke erkannt");
const falscheRolle = { "/workspace/x.html": ["gibt-es-nicht"] };
const bekannt = new Set(rechte.ALLE_ROLLEN);
const gefunden = Object.values(falscheRolle)[0].some((r) => !bekannt.has(r));
ok(gefunden, "eine unbekannte Rolle in einem Eintrag wird erkannt");
const alsNull = { "/workspace/x.html": null };
ok(!Array.isArray(Object.values(alsNull)[0]),
"und ein `null`-Eintrag wird als kein Feld erkannt");
}
/* Der Server haelt die Datenbankdatei offen -- unter Windows laesst
sie sich dann nicht loeschen. Das ist ein Aufraeumrest im
Temp-Ordner, kein Befund, und darf die Pruefung nicht rot machen. */
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
console.log("");
console.log(`${geprueft} Pruefungen, ${fehler} Fehler`);
console.log(fehler === 0 ? "ALLES IN ORDNUNG" : "NICHT IN ORDNUNG");
process.exit(fehler === 0 ? 0 : 1);
+307
View File
@@ -0,0 +1,307 @@
/* =====================================================================
DIE RECHTETAFEL — was jede Rolle sehen darf, an einer Stelle
=====================================================================
Filipe, 11.09.2026:
"egal welche rolle oder person hinzugefuegt wird soll immer nur
das sehen wass ich erlaube. mehr nicht. soll nichts so sein dass
wenn mann eine rolle oder jemanden hinzufuegt dass er dan alles
sieht, soll jede rolle immer nur das sehen was sie sehen sollen."
---------------------------------------------------------------------
DAS IST EINE UMKEHRUNG DER BAUWEISE, KEINE EINSTELLUNG
Vorher galt: erlauben, ausser es steht etwas dagegen. Die Tabelle
der geschuetzten Seiten hiess sogar so -- "GESCHUETZT ist die
Ausnahme, nicht die Regel" -- und sie kannte zwei Wege, auf denen
etwas durchfiel:
1. `null` als Wert hiess "jede angemeldete Rolle". NEUN von zwanzig
Seiten standen darauf: Start, Uebersicht, Aufgaben, Chat,
Kalender, Dateien, Calls, Start-Check, Wissen. Eine neue Rolle
erbte sie alle, ohne dass jemand etwas erlaubt haette.
2. Eine Seite, die GAR NICHT in der Tabelle stand, fiel durch
dieselbe Bedingung (`if (erlaubt && ...)`) und war damit
ebenfalls fuer jeden offen. Das betraf am 11.09.2026 keine
einzige Seite -- gemessen, nicht gehofft --, aber jede neue
waere so entstanden.
Ab hier gilt das Gegenteil: WAS NICHT IN DIESER TAFEL STEHT, IST
VERBOTEN. Kein `null`, kein `undefined`, kein Zweig, der etwas
durchlaesst. `darfSeite()` kennt genau zwei Antworten.
---------------------------------------------------------------------
WARUM DAS NICHT "DIE LISTE EINMAL DURCHGEHEN" IST
Das waere die naheliegende Antwort und die falsche. Die Rolle wird
im Haus an 74 Stellen in 20 Modulen abgefragt (gezaehlt, nicht
geschaetzt). Drei Gruende, und alle drei sind hier schon eingetreten:
* Eine Liste ALTERT. Am 09.09. war `content.html` fuer eine neue
Rolle offen -- nicht aus Nachlaessigkeit, sondern weil die Seite
spaeter dazukam als die Ueberlegung.
* Eine vergessene Erlaubnis SCHWEIGT. Sie faellt nur dem auf, der
hindurchgeht, und der merkt nichts: Die Seite laedt ja. In der
anderen Richtung ist es schlimmer -- eine Seite, die zu viel
zeigt, sieht aus wie eine Seite, die funktioniert.
* Bei 74 Stellen ist "ich gehe sie alle durch" kein Verfahren,
sondern ein Vorsatz.
Deshalb steht die Antwort nicht in einem Kommentar, sondern in
`pruef-rechtetafel.mjs`: Eine Rolle ohne Eintrag macht den Prueflauf
rot. Eine Seite ohne Eintrag macht den Prueflauf rot. Man KANN es
nicht mehr vergessen.
---------------------------------------------------------------------
DIESE DATEI HAENGT VON NICHTS AB
Kein Import aus workspace.js -- sonst gaebe es einen Ring, und die
Tafel muesste warten, bis das grosse Modul geladen ist. Sie ist
damit auch ohne laufenden Server pruefbar, genau wie crew-adresse.js.
===================================================================== */
/** Alle Rollen, die es gibt. Muss zu ROLLEN in workspace.js passen --
* pruef-rechtetafel vergleicht die beiden und wird rot, wenn eine
* Rolle nur in einer der beiden Listen steht. */
export const ALLE_ROLLEN = [
"spicy", "admin", "manager", "scout", "creator", "hand", "modi",
];
/* Kurzform fuer die Tafel unten. `ALLE` heisst hier ausdruecklich
"alle Rollen, die es GIBT" -- nicht "alle, die es geben wird".
Genau darin liegt der Unterschied zum alten `null`. */
const ALLE = ALLE_ROLLEN;
/* Schutz der angemeldeten Seiten. Serverseitig, nicht nur im Browser --
sonst könnte man die Seite einfach direkt aufrufen. */
/* Pfad -> erlaubte Rollen. `null` heisst: jede angemeldete Rolle.
Die Rolle wird hier mitgeprueft und nicht nur in der Schnittstelle.
Sonst bekommt z. B. ein Creator die Verwaltungsseite zwar ausgeliefert
(HTTP 200) und sieht ihr Geruest, auch wenn sie danach leer bleibt und
das Skript ihn wegschickt. Sichtbar sein soll sie gar nicht. */
export const SEITEN = {
/* AUS `null` WURDE EINE LISTE (11.09.2026).
Filipe: "egal welche rolle oder person hinzugefuegt wird soll
immer nur das sehen wass ich erlaube."
Diese neun Seiten standen auf `null` -- das hiess "jede
angemeldete Rolle", also auch jede Rolle, die es noch gar nicht
gibt. Jetzt stehen die sieben, die es wirklich gibt.
FUER DIE VORHANDENEN ROLLEN AENDERT SICH DAMIT NICHTS. Das ist
Absicht: Eine Umkehrung, die nebenbei Rechte entzieht, waere
zwei Aenderungen in einer -- und man wuesste hinterher nicht,
welche der beiden etwas kaputtgemacht hat. Wer hier enger
stellen will, macht das als eigenen Schritt. */
"/workspace/start.html": [...ALLE],
"/workspace/uebersicht.html": [...ALLE],
/* AUSDRUECKLICH OHNE 'modi' (10.09.2026). Vorher stand hier `null`
("jede angemeldete Rolle") -- und mit der neuen Rolle hiess das
auch: sie. Die Seite laedt dann zwar, ihre Schnittstelle antwortet
ihm aber mit 404, weil `content` nicht zu seinen Bereichen gehoert.
Eine Seite, die man oeffnen kann und die dann leer bleibt, sieht
aus wie ein Fehler -- und ist einer.
Das ist die Kehrseite von "geschuetzt ist die Regel, nicht die
Ausnahme": Eine NEUE ROLLE erbt jedes `null` automatisch. Wer eine
Rolle hinzufuegt, muss diese Liste durchgehen -- der Kachel-Durchgang
in pruef-rollen findet die Faelle, die dabei auffallen. */
"/workspace/content.html": ["spicy", "admin", "manager", "scout", "creator"],
"/workspace/aufgaben.html": [...ALLE],
/* Chat (06.09.2026): jede Rolle. WEN man erreicht, entscheidet
schreibbareIds() -- nicht der Zugang zur Seite. Ein Creator, der
die Seite nicht öffnen dürfte, könnte auch nicht antworten, und
genau das Antworten ist der Zweck. */
"/workspace/chat.html": [...ALLE],
/* NUR DogFather (07.09.2026). Wunsch Filipe: "nimm die kategorie
zahlen bei jedem weg, nur die rolle dogfather soll die sehen."
Bis heute stand hier `null` -- jede Rolle durfte die Seite oeffnen,
und WESSEN Zahlen jemand sah, entschied sichtbareCreatorIds().
Die Begruendung dafuer war gut (es sind SEINE Zahlen), sie ist
jetzt aber nicht mehr meine Entscheidung.
WICHTIG: Die Kachel wegzunehmen haette NICHT gereicht. Eine Kachel
ist ein Weg, keine Schranke -- wer die Adresse kennt oder ein altes
Lesezeichen hat, waere weiterhin hineingekommen. Beides gehoert
zusammen: bereiche.js zeigt sie nur noch DogFather, diese Zeile
laesst nur ihn hinein. */
/* JETZT WIEDER FUER ALLE (11.09.2026). Filipe, mit der Kachel im
Bild: "jetzt soll jede rolle diese kachel sehen. spicy, dogfather,
manager, scout und creator. aber die creator kriegen dan quasi nur
ihre daten zu sehen und der manager scout dogfather oder spicy
koennen eintragen."
Die Zeile stand seit dem 07.09.2026 auf ["admin"] -- erst "nimm
die kategorie zahlen bei jedem weg", dann die Praezisierung, dass
auch Spicy Media sie nicht sieht. Beides ist damit aufgehoben.
AUSDRUECKLICH ALS LISTE, NICHT ALS `null`. `null` hiesse "jede
angemeldete Rolle" -- und damit automatisch auch jede Rolle, die
es noch gar nicht gibt. Genau das ist am 10.09. bei content.html
schiefgegangen. Hier stehen die fuenf, die Filipe genannt hat.
WER WAS DARF, steht NICHT hier. Diese Zeile oeffnet nur die Tuer.
Dahinter gilt weiterhin: sichtbareCreatorIds() entscheidet, WESSEN
Zahlen jemand sieht (ein Creator sieht genau sich selbst), und
darfEintragen() entscheidet, wer schreiben darf (Leitung + Scout,
also NICHT der Creator). Beides war schon vorher so gebaut und
bleibt unangetastet -- es war nur niemand da, der es benutzen
konnte. */
"/workspace/leistung.html": ["spicy", "admin", "manager", "scout", "creator"],
/* NUR DogFather (02.09.2026). Die Rollenauswahl verspricht das seit
jeher ("Manager -- dieselben Rechte, ausser der
Personenverwaltung"), die Schranke hielt sich nur nicht daran.
Wunsch: "die manager sollen diese kategorien garnicht sehen". */
/* PERSONEN & ZUGAENGE: jetzt auch fuer Manager und Spicy Media
(07.09.2026).
Filipe: "die manager sehen immer noch nicht die kachel personen &
zugangscode, wo sie dan die neuen creator hinzufuegen koennen ...
und die sollen in der kategorie wo die jetzt sehen werden auch noch
das mit den hinzufuegen sehen, alles andere auf der seite sollen die
weiterhin nicht sehen."
DIE SEITE OEFFNET SICH, DIE SCHNITTSTELLEN NICHT. Das ist der ganze
Trick und der Grund, warum das hier ungefaehrlich ist: Alles unter
/workspace/api/verwaltung haengt weiterhin an `nurAdmin` -- Rollen
aendern, Codes neu setzen, sperren, loeschen, Protokoll lesen
bleiben zu und antworten mit 404. Wer die Seite oeffnet, bekommt
also genau die Teile zu sehen, fuer die es auch einen Weg gibt.
Eine Seite ist kein Schutz, sie ist ein Weg. Der Schutz steht in den
Schnittstellen, und der ist unveraendert. */
/* 'hand' kam am 10.09.2026 dazu. Filipe: "ich will dass die rechte
Hand auch alle sieht."
ES WAR DIE DRITTE SCHICHT, DIE ZUSTIMMEN MUSSTE. Die Kachel stand
da, die Schnittstelle liess sie lesen -- und die Seite selbst warf
sie auf die Startseite zurueck. Gefunden hat das nicht das Auge,
sondern pruef-rollen: Sie geht jede Kachel jeder Rolle ab und
schaut, wo man landet ("Rechte Hand Kachel personen.html LANDET
AUF start.html").
Dass die Seite aufgeht, gibt ihr nichts, was die Schnittstellen ihr
nicht ohnehin geben: Alles unter /workspace/api/verwaltung ausser
der Liste antwortet ihr weiterhin mit 404. Eine Seite ist kein
Schutz, sie ist ein Weg. */
"/workspace/personen.html": ["spicy", "admin", "manager", "hand"],
"/workspace/profil.html": ["spicy", "admin", "manager", "scout", "creator"],
/* Der eigene Steckbrief -- jede Rolle hat einen. Ein Creator wird
dort nicht hingeschickt (er sieht seinen auf profil.html), darf die
Seite aber aufrufen: Sie zeigt ihm dasselbe, nur ohne die Akte. */
/* 'modi' kam am 10.09.2026 dazu. Der Steckbrief ist die EIGENE Seite
("Dein Bild und deine Kanäle"); profil.html daneben ist der
Entwicklungsplan eines Creators und fuer ihn sinnlos. Der erste
Anlauf hatte genau das verwechselt -- die Kachel hiess "Mein
Profil" und fuehrte auf eine Seite, deren Schnittstelle mit 404
antwortet, weil sie ausdruecklich nur Creator kennt. Gefunden vom
neuen Kachel-Durchgang in pruef-rollen. */
"/workspace/steckbrief.html": ["spicy", "admin", "manager", "scout", "creator", "hand", "modi"],
"/workspace/kalender.html": [...ALLE],
"/workspace/dateien.html": [...ALLE],
/* 'modi' kam am 10.09.2026 dazu -- und es war ein echter Fund: Ohne
diese Zeile leiteten VIER seiner Kacheln (Live-Ablauf, Community,
Technik, Ideen-Board) wortlos auf die Startseite zurueck. Der
Rollen-Rundgang meldete sie trotzdem als "ok": Eine Umleitung ist
kein Fehler, die Seite laedt ja -- nur eben eine andere. Seither
prueft pruef-rollen fuer JEDE Rolle, dass jede Kachel, die sie
bekommt, auch wirklich dort ankommt.
WELCHE Bereiche ein Modi oeffnen darf, entscheidet die Liste
seiner Kacheln (MODI_BEREICHE_ERLAUBT) -- sonst kaeme er ueber die
Adresszeile auch in die Agentur-Ablage. */
"/workspace/bereich.html": ["spicy", "admin", "manager", "scout", "creator", "hand", "modi"],
"/workspace/report.html": ["spicy", "admin", "manager", "scout", "creator"],
"/workspace/scouting.html": ["spicy", "admin", "manager", "scout"],
/* DIE ARBEITSLAGE DES TEAMS (09.09.2026).
Filipe: "so eine kategorie wie ueber die creator will ich dass nur
fuer die spicy und dogfather rolle auch ueber manager und scouts
gibt."
Nur diese beiden Rollen. Ein Manager sieht seine eigene Zeile hier
ausdruecklich NICHT -- das ist kein Versehen: Eine Uebersicht ueber
die Arbeit der Kollegen gehoert der Leitung, nicht der Reihe. Der
Schutz steht ohnehin in der Schnittstelle (workspace-team.js);
diese Zeile sorgt nur dafuer, dass niemand vor einer leeren Seite
steht. */
"/workspace/team.html": ["spicy", "admin"],
"/workspace/calls.html": [...ALLE],
"/workspace/startcheck.html": [...ALLE],
"/workspace/wissen.html": [...ALLE],
/* Ebenfalls nur DogFather: Was von allein passiert, bestimmt, was
allen anderen zugeschoben wird. */
/* AUTOMATIONEN BLEIBEN BEI DogFather (07.09.2026). Ausdruecklich:
"bei automationen sollen die nicht sehen." Dahinter liegen
Sicherungen, die KI und der Zustand des Servers -- das ist Betrieb,
nicht Betreuung. */
"/workspace/automation.html": ["admin"],
/* Die gemeinsame Lage des Teams -- nur die DogFather-Rolle, also
Filipe und VanVan (10.09.2026). Fuer alle anderen leitet die
Schranke auf die Startseite; die Schnittstelle dahinter antwortet
zusaetzlich mit 404. Zwei Schloesser, absichtlich: Faellt eines
weg, haelt das andere. */
/* Der Eingang: DogFather und seine rechte Hand. Blueprint 3.1 --
"Kann im Alltag vertretend Entscheidungen treffen." Genau das
passiert auf dieser Seite. */
"/workspace/teamlage.html": ["admin", "hand"],
};
/* Die Zugangswaende. Sie haben keine Rolle, weil sich dort noch
niemand angemeldet hat -- sie sind der Ort, an dem das passiert.
Sie stehen hier nur, damit die Pruefung "jede Datei hat einen
Eintrag" sie nicht als Luecke meldet. */
export const OHNE_ANMELDUNG = [
"/workspace/index.html",
"/workspace/crew-index.html",
];
/* =====================================================================
DIE EINE FRAGE, DIE ALLES BEANTWORTET
===================================================================== */
/**
* Darf diese Person diese Seite oeffnen?
*
* Zwei Antworten, keine dritte:
* - Die Seite steht in der Tafel UND die Rolle steht darin -> ja.
* - Alles andere -> nein. Auch eine Seite, die es in der Tafel gar
* nicht gibt. Das ist die eigentliche Aenderung.
*
* @param {{rolle?: string}|null} person
* @param {string} pfad z. B. "/workspace/start.html"
*/
export function darfSeite(person, pfad) {
const rolle = person?.rolle;
if (!rolle) return false;
const erlaubt = SEITEN[String(pfad || "")];
/* Kein Eintrag heisst NEIN. Vorher hiess es ja -- und genau darin
lag das Loch, das man einer neuen Seite nicht ansieht. */
if (!Array.isArray(erlaubt)) return false;
return erlaubt.includes(rolle);
}
/**
* Die Tafel aus der anderen Richtung: Rolle -> Seiten.
*
* Fuer die Uebersichtsseite ("Wer sieht was") und fuer Pruefungen.
* ABGELEITET, nicht zweitgeschrieben -- eine zweite Liste waere die
* Stelle, an der die beiden auseinanderlaufen.
*/
export function seitenFuer(rolle) {
return Object.entries(SEITEN)
.filter(([, r]) => r.includes(rolle))
.map(([p]) => p)
.sort();
}
/** Alle Seiten der Tafel -- fuer die Pruefung gegen die Platte. */
export function alleSeiten() {
return Object.keys(SEITEN).sort();
}
+34 -166
View File
@@ -27,6 +27,7 @@ import { dirname, join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { mkdirSync } from "node:fs";
import { createRequire } from "node:module";
import { darfSeite } from "./rechte.js";
import { sitzungPasstZurAdresse, istOhneModiAdresse, istCrewAdresse,
TEAM_DOGI_ROLLEN } from "./crew-adresse.js";
/* Weitergereicht, damit die Fachmodule sie wie alles andere aus
@@ -3104,169 +3105,20 @@ function sitzungSetzen(res, person, req) {
export const workspaceRouter = express.Router();
/* Schutz der angemeldeten Seiten. Serverseitig, nicht nur im Browser --
sonst könnte man die Seite einfach direkt aufrufen. */
/* Pfad -> erlaubte Rollen. `null` heisst: jede angemeldete Rolle.
/* DIE ZUGANGSTABELLE STEHT SEIT DEM 11.09.2026 IN rechte.js.
Die Rolle wird hier mitgeprueft und nicht nur in der Schnittstelle.
Sonst bekommt z. B. ein Creator die Verwaltungsseite zwar ausgeliefert
(HTTP 200) und sieht ihr Geruest, auch wenn sie danach leer bleibt und
das Skript ihn wegschickt. Sichtbar sein soll sie gar nicht. */
const GESCHUETZT = {
"/workspace/start.html": null,
"/workspace/uebersicht.html": null,
/* AUSDRUECKLICH OHNE 'modi' (10.09.2026). Vorher stand hier `null`
("jede angemeldete Rolle") -- und mit der neuen Rolle hiess das
auch: sie. Die Seite laedt dann zwar, ihre Schnittstelle antwortet
ihm aber mit 404, weil `content` nicht zu seinen Bereichen gehoert.
Eine Seite, die man oeffnen kann und die dann leer bleibt, sieht
aus wie ein Fehler -- und ist einer.
Sie ist dorthin UMGEZOGEN, nicht kopiert -- samt jeder
Begruendung, die hier ueber den Jahren entstanden ist. Zwei
Tabellen waeren zwei Wahrheiten, und die zweite haette niemand
gepflegt.
Das ist die Kehrseite von "geschuetzt ist die Regel, nicht die
Ausnahme": Eine NEUE ROLLE erbt jedes `null` automatisch. Wer eine
Rolle hinzufuegt, muss diese Liste durchgehen -- der Kachel-Durchgang
in pruef-rollen findet die Faelle, die dabei auffallen. */
"/workspace/content.html": ["spicy", "admin", "manager", "scout", "creator"],
"/workspace/aufgaben.html": null,
/* Chat (06.09.2026): jede Rolle. WEN man erreicht, entscheidet
schreibbareIds() -- nicht der Zugang zur Seite. Ein Creator, der
die Seite nicht öffnen dürfte, könnte auch nicht antworten, und
genau das Antworten ist der Zweck. */
"/workspace/chat.html": null,
/* NUR DogFather (07.09.2026). Wunsch Filipe: "nimm die kategorie
zahlen bei jedem weg, nur die rolle dogfather soll die sehen."
Der Grund fuer den Umzug: `null` hiess "jede angemeldete Rolle",
und ein FEHLENDER Eintrag hiess dasselbe. Beides ist jetzt
"niemand". Was nicht in der Tafel steht, ist verboten.
pruef-rechtetafel.mjs macht daraus eine Garantie: eine Rolle
ohne Eintrag und eine Seite ohne Eintrag machen den Prueflauf
rot. */
Bis heute stand hier `null` -- jede Rolle durfte die Seite oeffnen,
und WESSEN Zahlen jemand sah, entschied sichtbareCreatorIds().
Die Begruendung dafuer war gut (es sind SEINE Zahlen), sie ist
jetzt aber nicht mehr meine Entscheidung.
WICHTIG: Die Kachel wegzunehmen haette NICHT gereicht. Eine Kachel
ist ein Weg, keine Schranke -- wer die Adresse kennt oder ein altes
Lesezeichen hat, waere weiterhin hineingekommen. Beides gehoert
zusammen: bereiche.js zeigt sie nur noch DogFather, diese Zeile
laesst nur ihn hinein. */
/* JETZT WIEDER FUER ALLE (11.09.2026). Filipe, mit der Kachel im
Bild: "jetzt soll jede rolle diese kachel sehen. spicy, dogfather,
manager, scout und creator. aber die creator kriegen dan quasi nur
ihre daten zu sehen und der manager scout dogfather oder spicy
koennen eintragen."
Die Zeile stand seit dem 07.09.2026 auf ["admin"] -- erst "nimm
die kategorie zahlen bei jedem weg", dann die Praezisierung, dass
auch Spicy Media sie nicht sieht. Beides ist damit aufgehoben.
AUSDRUECKLICH ALS LISTE, NICHT ALS `null`. `null` hiesse "jede
angemeldete Rolle" -- und damit automatisch auch jede Rolle, die
es noch gar nicht gibt. Genau das ist am 10.09. bei content.html
schiefgegangen. Hier stehen die fuenf, die Filipe genannt hat.
WER WAS DARF, steht NICHT hier. Diese Zeile oeffnet nur die Tuer.
Dahinter gilt weiterhin: sichtbareCreatorIds() entscheidet, WESSEN
Zahlen jemand sieht (ein Creator sieht genau sich selbst), und
darfEintragen() entscheidet, wer schreiben darf (Leitung + Scout,
also NICHT der Creator). Beides war schon vorher so gebaut und
bleibt unangetastet -- es war nur niemand da, der es benutzen
konnte. */
"/workspace/leistung.html": ["spicy", "admin", "manager", "scout", "creator"],
/* NUR DogFather (02.09.2026). Die Rollenauswahl verspricht das seit
jeher ("Manager -- dieselben Rechte, ausser der
Personenverwaltung"), die Schranke hielt sich nur nicht daran.
Wunsch: "die manager sollen diese kategorien garnicht sehen". */
/* PERSONEN & ZUGAENGE: jetzt auch fuer Manager und Spicy Media
(07.09.2026).
Filipe: "die manager sehen immer noch nicht die kachel personen &
zugangscode, wo sie dan die neuen creator hinzufuegen koennen ...
und die sollen in der kategorie wo die jetzt sehen werden auch noch
das mit den hinzufuegen sehen, alles andere auf der seite sollen die
weiterhin nicht sehen."
DIE SEITE OEFFNET SICH, DIE SCHNITTSTELLEN NICHT. Das ist der ganze
Trick und der Grund, warum das hier ungefaehrlich ist: Alles unter
/workspace/api/verwaltung haengt weiterhin an `nurAdmin` -- Rollen
aendern, Codes neu setzen, sperren, loeschen, Protokoll lesen
bleiben zu und antworten mit 404. Wer die Seite oeffnet, bekommt
also genau die Teile zu sehen, fuer die es auch einen Weg gibt.
Eine Seite ist kein Schutz, sie ist ein Weg. Der Schutz steht in den
Schnittstellen, und der ist unveraendert. */
/* 'hand' kam am 10.09.2026 dazu. Filipe: "ich will dass die rechte
Hand auch alle sieht."
ES WAR DIE DRITTE SCHICHT, DIE ZUSTIMMEN MUSSTE. Die Kachel stand
da, die Schnittstelle liess sie lesen -- und die Seite selbst warf
sie auf die Startseite zurueck. Gefunden hat das nicht das Auge,
sondern pruef-rollen: Sie geht jede Kachel jeder Rolle ab und
schaut, wo man landet ("Rechte Hand Kachel personen.html LANDET
AUF start.html").
Dass die Seite aufgeht, gibt ihr nichts, was die Schnittstellen ihr
nicht ohnehin geben: Alles unter /workspace/api/verwaltung ausser
der Liste antwortet ihr weiterhin mit 404. Eine Seite ist kein
Schutz, sie ist ein Weg. */
"/workspace/personen.html": ["spicy", "admin", "manager", "hand"],
"/workspace/profil.html": ["spicy", "admin", "manager", "scout", "creator"],
/* Der eigene Steckbrief -- jede Rolle hat einen. Ein Creator wird
dort nicht hingeschickt (er sieht seinen auf profil.html), darf die
Seite aber aufrufen: Sie zeigt ihm dasselbe, nur ohne die Akte. */
/* 'modi' kam am 10.09.2026 dazu. Der Steckbrief ist die EIGENE Seite
("Dein Bild und deine Kanäle"); profil.html daneben ist der
Entwicklungsplan eines Creators und fuer ihn sinnlos. Der erste
Anlauf hatte genau das verwechselt -- die Kachel hiess "Mein
Profil" und fuehrte auf eine Seite, deren Schnittstelle mit 404
antwortet, weil sie ausdruecklich nur Creator kennt. Gefunden vom
neuen Kachel-Durchgang in pruef-rollen. */
"/workspace/steckbrief.html": ["spicy", "admin", "manager", "scout", "creator", "hand", "modi"],
"/workspace/kalender.html": null,
"/workspace/dateien.html": null,
/* 'modi' kam am 10.09.2026 dazu -- und es war ein echter Fund: Ohne
diese Zeile leiteten VIER seiner Kacheln (Live-Ablauf, Community,
Technik, Ideen-Board) wortlos auf die Startseite zurueck. Der
Rollen-Rundgang meldete sie trotzdem als "ok": Eine Umleitung ist
kein Fehler, die Seite laedt ja -- nur eben eine andere. Seither
prueft pruef-rollen fuer JEDE Rolle, dass jede Kachel, die sie
bekommt, auch wirklich dort ankommt.
WELCHE Bereiche ein Modi oeffnen darf, entscheidet die Liste
seiner Kacheln (MODI_BEREICHE_ERLAUBT) -- sonst kaeme er ueber die
Adresszeile auch in die Agentur-Ablage. */
"/workspace/bereich.html": ["spicy", "admin", "manager", "scout", "creator", "hand", "modi"],
"/workspace/report.html": ["spicy", "admin", "manager", "scout", "creator"],
"/workspace/scouting.html": ["spicy", "admin", "manager", "scout"],
/* DIE ARBEITSLAGE DES TEAMS (09.09.2026).
Filipe: "so eine kategorie wie ueber die creator will ich dass nur
fuer die spicy und dogfather rolle auch ueber manager und scouts
gibt."
Nur diese beiden Rollen. Ein Manager sieht seine eigene Zeile hier
ausdruecklich NICHT -- das ist kein Versehen: Eine Uebersicht ueber
die Arbeit der Kollegen gehoert der Leitung, nicht der Reihe. Der
Schutz steht ohnehin in der Schnittstelle (workspace-team.js);
diese Zeile sorgt nur dafuer, dass niemand vor einer leeren Seite
steht. */
"/workspace/team.html": ["spicy", "admin"],
"/workspace/calls.html": null,
"/workspace/startcheck.html": null,
"/workspace/wissen.html": null,
/* Ebenfalls nur DogFather: Was von allein passiert, bestimmt, was
allen anderen zugeschoben wird. */
/* AUTOMATIONEN BLEIBEN BEI DogFather (07.09.2026). Ausdruecklich:
"bei automationen sollen die nicht sehen." Dahinter liegen
Sicherungen, die KI und der Zustand des Servers -- das ist Betrieb,
nicht Betreuung. */
"/workspace/automation.html": ["admin"],
/* Die gemeinsame Lage des Teams -- nur die DogFather-Rolle, also
Filipe und VanVan (10.09.2026). Fuer alle anderen leitet die
Schranke auf die Startseite; die Schnittstelle dahinter antwortet
zusaetzlich mit 404. Zwei Schloesser, absichtlich: Faellt eines
weg, haelt das andere. */
/* Der Eingang: DogFather und seine rechte Hand. Blueprint 3.1 --
"Kann im Alltag vertretend Entscheidungen treffen." Genau das
passiert auf dieser Seite. */
"/workspace/teamlage.html": ["admin", "hand"],
};
/* Die einzige Seite unter /workspace, die offen sein MUSS -- man kann
sich schlecht anmelden, wenn die Anmeldeseite eine Anmeldung verlangt. */
@@ -3327,10 +3179,19 @@ function schrankenPfad(roh) {
damit offen ins Netz, ohne dass irgendwo etwas rot wird. Genau diese
Sorte Fehler faellt erst auf, wenn jemand danach sucht.
Jetzt gilt: JEDE .html unter /workspace ist geschuetzt, ausser den
ausdruecklich offenen. Die Liste oben sagt nur noch, WELCHE ROLLEN
zusaetzlich eingeschraenkt sind. Eine neue Seite ist dadurch von
selbst mindestens "nur fuer Angemeldete" -- der sichere Rueckfall. */
Seit dem 06.09.2026 gilt: JEDE .html unter /workspace ist
geschuetzt, ausser den ausdruecklich offenen.
UND SEIT DEM 11.09.2026 AUCH FUER DIE ROLLE. Bis dahin sagte die
Liste nur, welche Rollen ZUSAETZLICH eingeschraenkt sind -- eine
neue Seite war damit "nur fuer Angemeldete", also fuer JEDE Rolle.
Das war der sichere Rueckfall gegen Fremde, aber keiner gegen eine
Rolle, die man gerade erst angelegt hat.
Jetzt ist der Rueckfall "fuer niemanden". Eine neue Seite ohne
Eintrag in rechte.js oeffnet sich fuer keine Rolle, auch nicht fuer
DogFather -- und pruef-rechtetafel meldet sie, statt dass man es
beim Ausprobieren merkt. */
workspaceRouter.use((req, res, next) => {
const pfad = schrankenPfad(req.path);
if (!pfad.startsWith("/workspace/") || !pfad.endsWith(".html")) return next();
@@ -3338,8 +3199,15 @@ workspaceRouter.use((req, res, next) => {
const person = sitzungLesen(req);
if (!person) return res.redirect(302, "/workspace/");
const erlaubt = GESCHUETZT[pfad];
if (erlaubt && !erlaubt.includes(person.rolle)) {
/* EIN FEHLENDER EINTRAG HEISST JETZT NEIN.
Vorher stand hier `if (erlaubt && ...)` -- und `erlaubt` war
`undefined`, sobald eine Seite gar nicht in der Tabelle stand.
Die Bedingung fiel dann durch, und die Seite war fuer jede
angemeldete Rolle offen. Am 11.09.2026 betraf das keine einzige
Seite (nachgemessen: 20 in der Tabelle, 2 Zugangswaende, 22
Dateien) -- aber jede NEUE waere so entstanden. */
if (!darfSeite(person, pfad)) {
return res.redirect(302, "/workspace/start.html");
}
return next();
+4 -4
View File
@@ -13,25 +13,25 @@
"theme_color": "#06090f",
"icons": [
{
"src": "/assets/img/app-symbole/workspace-192.png?v=202609111554",
"src": "/assets/img/app-symbole/workspace-192.png?v=202609111617",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-512.png?v=202609111554",
"src": "/assets/img/app-symbole/workspace-512.png?v=202609111617",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609111554",
"src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609111617",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609111554",
"src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609111617",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
+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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -252,10 +252,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/aufgaben.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/aufgaben.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/automation.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -147,10 +147,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/automation.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/automation.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/bereich.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -181,14 +181,14 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/checkliste.js?v=202609111554" defer></script>
<script src="assets/js/ampel.js?v=202609111554" defer></script>
<script src="assets/js/schulung.js?v=202609111554" defer></script>
<script src="assets/js/vorlagen.js?v=202609111554" defer></script>
<script src="assets/js/bereich.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/checkliste.js?v=202609111617" defer></script>
<script src="assets/js/ampel.js?v=202609111617" defer></script>
<script src="assets/js/schulung.js?v=202609111617" defer></script>
<script src="assets/js/vorlagen.js?v=202609111617" defer></script>
<script src="assets/js/bereich.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/calls.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -89,11 +89,11 @@
</main>
<script src="assets/js/ki.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/calls.js?v=202609111554" defer></script>
<script src="assets/js/ki.js?v=202609111617" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/calls.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/chat.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -341,10 +341,10 @@
</form>
</dialog>
<script src="assets/js/bereiche.js?v=202609111554"></script>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554"></script>
<script src="assets/js/glocke.js?v=202609111554"></script>
<script src="assets/js/chat.js?v=202609111554"></script>
<script src="assets/js/bereiche.js?v=202609111617"></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617"></script>
<script src="assets/js/glocke.js?v=202609111617"></script>
<script src="assets/js/chat.js?v=202609111617"></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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/content.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/content.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -179,12 +179,12 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/checkliste.js?v=202609111554" defer></script>
<script src="assets/js/vorlagen.js?v=202609111554" defer></script>
<script src="assets/js/content.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/checkliste.js?v=202609111617" defer></script>
<script src="assets/js/vorlagen.js?v=202609111617" defer></script>
<script src="assets/js/content.js?v=202609111617" defer></script>
</body>
</html>
+5 -5
View File
@@ -30,15 +30,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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/crew-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/crew-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/crew-haus.css?v=202609111617" />
</head>
<body class="gate gate--crew">
@@ -252,6 +252,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609111554" defer></script>
<script src="assets/js/gate.js?v=202609111617" defer></script>
</body>
</html>
+4 -4
View File
@@ -13,25 +13,25 @@
"theme_color": "#06090f",
"icons": [
{
"src": "/assets/img/app-symbole/crew-192.png?v=202609111554",
"src": "/assets/img/app-symbole/crew-192.png?v=202609111617",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-512.png?v=202609111554",
"src": "/assets/img/app-symbole/crew-512.png?v=202609111617",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609111554",
"src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609111617",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609111554",
"src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609111617",
"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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/dateien.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -108,10 +108,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/dateien.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/dateien.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
</head>
<body class="gate">
@@ -401,6 +401,6 @@
</main>
</div>
<script src="assets/js/gate.js?v=202609111554" defer></script>
<script src="assets/js/gate.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/kalender.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -377,11 +377,11 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/kalender.js?v=202609111554" defer></script>
<script src="assets/js/kalender-abo.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/kalender.js?v=202609111617" defer></script>
<script src="assets/js/kalender-abo.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/leistung.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -382,10 +382,10 @@
</form>
</dialog>
<script src="assets/js/wahl.js?v=202609111554"></script>
<script src="assets/js/bereiche.js?v=202609111554"></script>
<script src="assets/js/kopf.js?v=202609111554"></script>
<script src="assets/js/glocke.js?v=202609111554"></script>
<script src="assets/js/leistung.js?v=202609111554"></script>
<script src="assets/js/wahl.js?v=202609111617"></script>
<script src="assets/js/bereiche.js?v=202609111617"></script>
<script src="assets/js/kopf.js?v=202609111617"></script>
<script src="assets/js/glocke.js?v=202609111617"></script>
<script src="assets/js/leistung.js?v=202609111617"></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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/personen.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -396,10 +396,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/personen.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/personen.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -214,11 +214,11 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/steckbrief.js?v=202609111554" defer></script>
<script src="assets/js/profil.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/steckbrief.js?v=202609111617" defer></script>
<script src="assets/js/profil.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/report.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/report.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -106,11 +106,11 @@
</main>
<script src="assets/js/ki.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/report.js?v=202609111554" defer></script>
<script src="assets/js/ki.js?v=202609111617" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/report.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/scouting.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -173,10 +173,10 @@
</div>
</div>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/scouting.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/scouting.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/heim.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -674,10 +674,10 @@
</p>
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/start.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/start.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/startcheck.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -85,11 +85,11 @@
</main>
<script src="assets/js/ki.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/startcheck.js?v=202609111554" defer></script>
<script src="assets/js/ki.js?v=202609111617" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/startcheck.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/profil.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -126,10 +126,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/steckbrief.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/steckbrief.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -110,10 +110,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/team.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/team.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/team.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</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=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/teamlage.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/teamlage.js?v=202609111617" defer></script>
</body>
</html>
+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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<!-- Formular- und Dialogstile: seit dem 07.09.2026 steht hier der
Dialog "Creator anlegen". -->
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/uebersicht.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -149,11 +149,11 @@
</main>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/uebersicht.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/uebersicht.js?v=202609111617" 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=202609111554" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111554" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609111554" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111554" />
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609111617" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609111617" />
<link rel="stylesheet" href="assets/css/gate.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/start.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/wissen.css?v=202609111617" />
<link rel="stylesheet" href="assets/css/module.css?v=202609111617" />
<!-- 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=202609111554" />
<link rel="stylesheet" href="assets/css/haus.css?v=202609111617" />
</head>
<body class="start">
@@ -190,10 +190,10 @@
</main>
<script src="assets/js/wahl.js?v=202609111554" defer></script>
<script src="assets/js/bereiche.js?v=202609111554" defer></script>
<script src="assets/js/kopf.js?v=202609111554" defer></script>
<script src="assets/js/glocke.js?v=202609111554" defer></script>
<script src="assets/js/wissen.js?v=202609111554" defer></script>
<script src="assets/js/wahl.js?v=202609111617" defer></script>
<script src="assets/js/bereiche.js?v=202609111617" defer></script>
<script src="assets/js/kopf.js?v=202609111617" defer></script>
<script src="assets/js/glocke.js?v=202609111617" defer></script>
<script src="assets/js/wissen.js?v=202609111617" defer></script>
</body>
</html>