Willkommen: eine Seite, die erklaert, was es hier gibt
Auftrag vom 21.09.2026, Abschnitte 7 und 8. Aus der Kachel "Der Treff" wird die Willkommensseite. WARUM DAS NICHTS VERLIERT, gemessen am echten Bestand: Das Brett "treff" hatte NULL Eintraege, der Treff-Chat daneben 29 Nachrichten. Geredet wird im Chat; das Brett war eine Kachel ohne Inhalt. DIE SEITE ERKLAERT NICHT "DIE WEBSITE", SONDERN DEINE. Sie baut sich aus derselben Kachelliste wie die Startseite, durch denselben Filter (darfSeite). Wer morgen eine Kachel bekommt, bekommt automatisch auch ihre Erklaerung -- und wer eine nicht hat, liest nicht davon. Eine Liste von Dingen, die man nicht darf, ist keine Orientierung. Gemessen: DogFather 30 Kacheln, Modi 25, Community 11 -- und keine einzige davon ist fuer den Betreffenden gesperrt. DREI FEHLER, DIE ERST DAS BILDSCHIRMFOTO GEZEIGT HAT: body class="gate" ist die ANMELDEWAND (display:flex, zentriert). Kopfleiste und Inhalt standen dadurch NEBENEINANDER -- am Handy blieben dem Text 260 von 390 Pixeln. .huelle gibt es im Haus gar nicht. Der Inhalt stand linksbuendig statt mittig, ohne Sicherheitsrand an randlosen Geraeten. Jetzt .inhalt wie jede andere Seite. Der Text stand direkt auf dem Buehnenbild: Kontrast 1.68:1 am Rechner, 2.23:1 am Handy (noetig 4.5). Die Hausregel stand daneben in start.css -- "der Text steht auf eigenen Flaechen" -- und diese Seite hielt sich als einzige nicht daran. Jetzt 5.19 und 7.73. UND EIN LECK, ZUM DRITTEN MAL DIESELBE URSACHE: Die Kachel umzuleiten nahm dem Brett "treff" die Zugehoerigkeit -- TREFF_BRETTER wird aus Kachelzielen abgeleitet. Die Schranke laesst eine AGENTURROLLE unbesehen durch, wenn ein Brett in keiner Liste steht: Eine Creatorin konnte das Brett des Treffs lesen. Behoben, und diesmal dauerhaft laut gemacht: Nachgemessen ist die Trennung exakt und in beide Richtungen deckungsgleich -- die Bretter mit `fuerAlle` sind genau die des Treffs plus die Agenturablage. Das ist eine Eigenschaft des BRETTS und wandert nicht, wenn jemand eine Kachel umleitet. pruef-treff prueft das jetzt. Mein erster Entwurf der Regel war zu breit und meldete `content` und `schutz` -- beides Agenturbretter, die eine Agenturrolle zu Recht liest. Eine Pruefung, die zu viel meldet, wird abgeschaltet. AUSSERDEM: 16 Kennungen aus workspace-zuteilung.js hatten keinen deutschen Satz -- auf dem Bildschirm haette woertlich "nicht_zugeteilt" gestanden. Gefunden von pruef-meldungen am selben Tag. Und zwei Erwartungen in pruef-treff abgeleitet statt gezaehlt: die Zahl der Rollenkacheln auf der Wand (die Anmeldung sucht WHERE rolle=?, eine Rolle ohne Kachel ist unerreichbar) und "die breite Kachel steht vorne" ueber die Eigenschaft statt ueber den Namen. Geprueft: pruef-willkommen 66/0 (neu), pruef-treff 80/0 (war 59 ok / 13 FEHL), pruef-buehne fuer die neue Seite 10/0, pruef-meldungen 8/0, pruef-css-klassen 30/0, pruef-rechtetafel 19/0.
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
/* =====================================================================
|
||||
WILLKOMMEN — die Seite, die erklärt, was es hier gibt
|
||||
=====================================================================
|
||||
|
||||
Auftrag vom 21.09.2026, Abschnitte 7 und 8:
|
||||
|
||||
*"Beim Öffnen soll die Person persönlich begrüßt werden ...
|
||||
Willkommen, [Name]! – danach folgt eine verständliche Einführung
|
||||
in die Website ... Die Willkommensseite darf nicht für alle Nutzer
|
||||
identisch sein. Sie muss vollständig rollenbasiert und individuell
|
||||
aufgebaut werden ... Die Erklärung soll sich automatisch an die
|
||||
tatsächlich vorhandenen Rechte des jeweiligen Nutzers anpassen."*
|
||||
|
||||
DAS LETZTE IST DER GANZE BAU. Eine Erklärung, die aufzählt, was es
|
||||
gibt, ist am Tag danach falsch — jemand baut eine Kachel dazu, und
|
||||
die Seite verschweigt sie. Deshalb erklärt sie GENAU DIE KACHELN,
|
||||
die diese Person wirklich hat: dieselbe Liste, aus der die
|
||||
Startseite gebaut wird (`bereicheFuer`), durch denselben Filter
|
||||
(`darfSeite`). Wer morgen eine Kachel bekommt, bekommt automatisch
|
||||
auch ihre Erklärung.
|
||||
|
||||
DREI EBENEN, und jede hat einen Grund:
|
||||
|
||||
Der Untertitel steht schon an der Kachel. Er ist die kürzeste
|
||||
wahre Auskunft und wird deshalb nicht neu
|
||||
erfunden.
|
||||
Der lange Satz nur bei den Seiten, wo eine Zeile zu wenig ist.
|
||||
NACH ZIEL abgelegt, nicht nach Name: Namen
|
||||
ändern sich (am 21.09. gleich zweimal), das
|
||||
Ziel bleibt.
|
||||
Die Einleitung je Rolle ein eigener Absatz. Das ist die eine
|
||||
Stelle, an der wirklich nach Rolle unterschieden
|
||||
wird — und es sind vier Sätze, keine vier
|
||||
Seitenlisten.
|
||||
|
||||
WAS NICHT ERKLÄRT WIRD, STEHT AUCH NICHT DA. Der Auftrag lässt die
|
||||
Wahl zwischen "gar nicht erklären" und "deutlich als nicht relevant
|
||||
behandeln". Gar nicht ist richtig: Eine Liste von Dingen, die man
|
||||
nicht darf, ist keine Orientierung, sondern eine Kränkung.
|
||||
===================================================================== */
|
||||
|
||||
import express from "express";
|
||||
import {
|
||||
sitzungLesen, bereicheFuer, zusatzBereicheFuer, rollentextFuer,
|
||||
ROLLEN_NAME, istDogFather, darfAufgabenVerteilen,
|
||||
} from "./workspace.js";
|
||||
import { darfSeite } from "./rechte.js";
|
||||
|
||||
export const willkommenRouter = express.Router();
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
DIE EINLEITUNG JE ROLLE
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Sie sagt in zwei, drei Sätzen, WOZU jemand hier ist. Die Kacheln
|
||||
darunter sagen, WOMIT. Beides zu mischen ergäbe einen Text, den
|
||||
niemand liest.
|
||||
|
||||
Der Ton ist bewusst derselbe wie im ganzen Haus: auf Augenhöhe,
|
||||
ohne jemanden über jemanden zu stellen. */
|
||||
const EINLEITUNG = {
|
||||
admin: {
|
||||
was: "Das hier ist deine Seite — von hier aus läuft alles.",
|
||||
dazu: "Du siehst jede Kachel, die es gibt, und entscheidest am Ende, "
|
||||
+ "was passiert. Wenn dir etwas Vorgeschlagenes nicht passt, lehnst "
|
||||
+ "du es ab; nichts geschieht ohne dich.",
|
||||
},
|
||||
hand: {
|
||||
was: "Du vertrittst DogFather im Alltag und hältst das Team zusammen.",
|
||||
dazu: "Du siehst dieselben Aufgaben, Ideen und Auswertungen wie er und "
|
||||
+ "kannst Aufgaben an die Modis verteilen. Private Bereiche von "
|
||||
+ "DogFather bleiben seine.",
|
||||
},
|
||||
linke: {
|
||||
was: "Du führst das Team durch den Tag — mit denselben Werkzeugen wie "
|
||||
+ "die rechte Hand.",
|
||||
dazu: "Aufgaben verteilen, Stände verfolgen, Rückmeldung geben: alles "
|
||||
+ "wie sie. Was du NICHT hast: Personen anlegen, Rollen ändern und "
|
||||
+ "den vertraulichen Meldeweg. Das ist kein Versehen, sondern so "
|
||||
+ "eingerichtet.",
|
||||
},
|
||||
modi: {
|
||||
was: "Schön, dass du da bist. Hier findest du alles für deinen Tag.",
|
||||
dazu: "Unter „Aufgaben\" steht, was gerade für dich dran ist — du "
|
||||
+ "nimmst an, was du schaffst, und sagst ab, was nicht geht. Eine "
|
||||
+ "Absage ist völlig in Ordnung, schreib einfach kurz warum.",
|
||||
},
|
||||
gast: {
|
||||
was: "Schön, dass du da bist.",
|
||||
dazu: "Hier triffst du die anderen aus der Community. Schau dich um, "
|
||||
+ "schreib etwas, oder lies erst mal mit — beides ist richtig.",
|
||||
},
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
DIE LANGEN SÄTZE — nach ZIEL, nicht nach Name
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Nur dort, wo eine Zeile zu wenig ist. Wer zu jeder Kachel einen
|
||||
Absatz schreibt, schreibt eine Seite, die niemand zu Ende liest.
|
||||
|
||||
Der Schlüssel ist der Dateiname ohne Parameter. Am 21.09. sind in
|
||||
diesem Haus zwei Kachelnamen gewandert; ein Text, der am Namen
|
||||
hängt, wäre dabei stumm geworden, ohne dass es jemand merkt. */
|
||||
const LANG = {
|
||||
"aufgaben.html":
|
||||
"Oben steht, wie es bei dir gerade aussieht — was offen ist, was läuft, "
|
||||
+ "was erledigt ist. Darunter die Karten. Bekommst du eine Aufgabe, "
|
||||
+ "kannst du sie annehmen oder ablehnen; wenn du ablehnst, schreib "
|
||||
+ "kurz warum, dann muss niemand nachfragen.",
|
||||
"chat.html":
|
||||
"Einzelgespräche und Gruppen. Mit @ und dem Namen sprichst du jemanden "
|
||||
+ "direkt an — er bekommt dann eine eigene Meldung, auch wenn er den "
|
||||
+ "Chat gerade nicht offen hat.",
|
||||
"kalender.html":
|
||||
"Alles mit Datum an einer Stelle. Termine über mehrere Tage sind "
|
||||
+ "durchgehend markiert, am Handy tippst du einen Tag an und siehst, "
|
||||
+ "was dort ansteht.",
|
||||
"bereich.html":
|
||||
"Ein Brett zum Sammeln. Schreib hinein, was dir einfällt — es geht "
|
||||
+ "nichts verloren, und niemand muss es sofort beantworten.",
|
||||
"befinden.html":
|
||||
"Ein paar Fragen über dich, nur für dich. Niemand aus dem Team sieht "
|
||||
+ "deine Antworten — am Ende bekommst du eine kurze Zusammenfassung.",
|
||||
"steckbrief.html":
|
||||
"Deine Seite: Foto, ein paar Worte über dich. Du entscheidest, was "
|
||||
+ "darauf steht.",
|
||||
"hilfe.html":
|
||||
"Wenn etwas vorgefallen ist, das niemand mitlesen soll. Nur DogFather "
|
||||
+ "und die rechte Hand sehen diese Meldungen.",
|
||||
"treff-regeln.html":
|
||||
"Wie wir hier miteinander umgehen. Kurz, und es lohnt sich einmal.",
|
||||
"unsere-seiten.html":
|
||||
"Ob gerade gestreamt wird, wann es losgeht, und wo du die Kanäle "
|
||||
+ "findest.",
|
||||
"personen.html":
|
||||
"Zugänge anlegen, sperren und Rollen ändern. Der Code wird genau "
|
||||
+ "einmal angezeigt — danach nie wieder.",
|
||||
"teamlage.html":
|
||||
"Wer gerade wie unterwegs ist. Gedacht zum Hinsehen, nicht zum "
|
||||
+ "Vergleichen.",
|
||||
"werdegang.html":
|
||||
"Wie sich jemand über die Zeit entwickelt hat. Keine Note, kein "
|
||||
+ "Ranking — nur die Bewegung.",
|
||||
"willkommen.html": null, /* sich selbst erklärt sie nicht */
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
DIE ROUTE
|
||||
--------------------------------------------------------------------- */
|
||||
willkommenRouter.get("/workspace/api/willkommen", (req, res) => {
|
||||
try {
|
||||
const person = sitzungLesen(req);
|
||||
if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" });
|
||||
|
||||
/* DIESELBE LISTE WIE DIE STARTSEITE, durch denselben Filter. Eine
|
||||
eigene Aufzählung wäre die, die beim nächsten Umbau veraltet. */
|
||||
const roh = [
|
||||
...(bereicheFuer(person) || []),
|
||||
...(zusatzBereicheFuer(person) || []),
|
||||
];
|
||||
const offen = roh.filter((k) => {
|
||||
if (k?.aussen) return true;
|
||||
const ziel = String(k?.ziel || "");
|
||||
if (!ziel) return false;
|
||||
return darfSeite(person, "/workspace/" + ziel.split("?")[0]);
|
||||
});
|
||||
|
||||
/* NACH GRUPPEN, in der Reihenfolge, in der sie auf der Startseite
|
||||
stehen -- wer dort von oben liest, findet hier dasselbe wieder. */
|
||||
const gruppen = [];
|
||||
for (const k of offen) {
|
||||
const name = k.gruppe || "Sonst";
|
||||
let g = gruppen.find((x) => x.name === name);
|
||||
if (!g) { g = { name, kacheln: [] }; gruppen.push(g); }
|
||||
const datei = String(k.ziel || "").split("?")[0];
|
||||
g.kacheln.push({
|
||||
name: k.name,
|
||||
unter: k.unter || "",
|
||||
ziel: k.ziel,
|
||||
zeichen: k.zeichen || null,
|
||||
/* Der lange Satz nur, wenn es einen gibt -- `null` heißt
|
||||
ausdrücklich "hier reicht die Zeile". */
|
||||
lang: Object.prototype.hasOwnProperty.call(LANG, datei) ? LANG[datei] : null,
|
||||
});
|
||||
}
|
||||
|
||||
const ein = EINLEITUNG[person.rolle] || {
|
||||
was: "Schön, dass du da bist.",
|
||||
dazu: "Hier findest du alles, was für dich freigeschaltet ist.",
|
||||
};
|
||||
|
||||
res.json({
|
||||
name: person.name,
|
||||
rolle: person.rolle,
|
||||
rollenname: ROLLEN_NAME[person.rolle] || null,
|
||||
rollentext: rollentextFuer(person),
|
||||
gruss: `Willkommen, ${person.name}!`,
|
||||
einleitung: ein,
|
||||
gruppen,
|
||||
/* Ein paar Sätze, die nur für bestimmte Rollen gelten und zu
|
||||
keiner einzelnen Kachel gehören. */
|
||||
hinweise: hinweiseFuer(person),
|
||||
/* Damit die Seite die Zahl nennen kann, ohne sie zu zählen. */
|
||||
kachelzahl: offen.length,
|
||||
});
|
||||
} catch (f) {
|
||||
console.error("[willkommen]:", f?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/** Sätze, die zu keiner Kachel gehören, aber zur Rolle. */
|
||||
function hinweiseFuer(person) {
|
||||
const aus = [];
|
||||
if (darfAufgabenVerteilen(person)) {
|
||||
aus.push({
|
||||
titel: "Aufgaben verteilen",
|
||||
text: "Beim Anlegen einer Aufgabe kannst du eine Person aussuchen — "
|
||||
+ "oder mehrere. Bei mehreren fragst du noch, ob jede ihren Teil "
|
||||
+ "macht oder ob die Erste, die Zeit hat, übernimmt. Ist jemand "
|
||||
+ "fertig, kannst du kurz Rückmeldung geben.",
|
||||
});
|
||||
}
|
||||
if (person.rolle === "modi") {
|
||||
aus.push({
|
||||
titel: "Du musst nicht alles annehmen",
|
||||
text: "Wenn eine Aufgabe gerade nicht geht, lehn sie ab und schreib "
|
||||
+ "einen Satz dazu. Das ist ausdrücklich vorgesehen und niemandem "
|
||||
+ "unangenehm.",
|
||||
});
|
||||
}
|
||||
if (person.rolle === "linke") {
|
||||
aus.push({
|
||||
titel: "Was du nicht siehst",
|
||||
text: "Personen anlegen, Rollen ändern, Bewerbungen und der "
|
||||
+ "vertrauliche Meldeweg sind nicht für dich freigeschaltet. "
|
||||
+ "Alles, was mit Aufgaben und dem Team zu tun hat, schon.",
|
||||
});
|
||||
}
|
||||
if (istDogFather(person)) {
|
||||
aus.push({
|
||||
titel: "Du entscheidest am Ende",
|
||||
text: "Überall, wo dir etwas vorgeschlagen wird, kannst du annehmen "
|
||||
+ "oder ablehnen. Ein Vorschlag ist ein Vorschlag.",
|
||||
});
|
||||
}
|
||||
if (person.rolle === "gast") {
|
||||
aus.push({
|
||||
titel: "Nachts ist Ruhe",
|
||||
text: "Zwischen 0 und 6 Uhr schläft der Chat — gelesen werden kann "
|
||||
+ "weiter, geschrieben ab 6 Uhr wieder. Das gilt für alle, auch "
|
||||
+ "für DogFather.",
|
||||
});
|
||||
}
|
||||
return aus;
|
||||
}
|
||||
Reference in New Issue
Block a user