/* ===================================================================== workspace-anleitung.js — die Einweisung je Rolle (Etappe 1) Bauplan: „Kachel Anleitung", Stand 06.10.2026, geprueft in `02 Projekte/Anleitung-Kachel – Bauplan.md`. --------------------------------------------------------------------- WAS DIESE SCHNITTSTELLE LIEFERT UND WAS NICHT Sie liefert die TEXTE und die STUFE je Kachel. Sie liefert NICHT den Namen, das Symbol, die Farbe oder die Adresse einer Kachel — die stehen in `workspace/assets/js/bereiche.js`, und nur dort. Die Seite verbindet beides ueber den Kachel-Schluessel (`window.Bereiche.schluesselVonZiel`). Das ist Absicht und der Grund, warum diese Datei so kurz ist: Der Server kennt die Kacheln des Agenturhauses gar nicht. `bereicheFuer` gibt dort `null` zurueck — „nimm die Liste aus dem Browser". Haette ich sie hier noch einmal hingeschrieben, um „alles an einer Stelle" zu haben, waere genau das die zweite Liste, die beim naechsten Umbau veraltet und dann eine Kachel erklaert, die es nicht mehr gibt. --------------------------------------------------------------------- DREI SCHRANKEN, NICHT EINE 1. `rechte.js` sperrt die Seite fuer die Crew. 2. Diese Datei prueft Haus und Rolle noch einmal selbst. 3. Die Hinweise (ab Etappe 2) pruefen es ein drittes Mal. Am 15.09.2026 ist ein Weg fuer die Community genau durch Luecke 3 gerutscht, obwohl Tafel und Seite sauber gesperrt waren. Die Hinweise sind eine eigene Tuer. ===================================================================== */ import express from "express"; import { db, sitzungLesen } from "./workspace.js"; import { STUFEN, FASSUNGEN, PFLEGE_ROLLEN, } from "./anleitung-tabellen.js"; export const anleitungRouter = express.Router(); const HAUS = "agentur"; function angemeldet(req, res, next) { const person = sitzungLesen(req); if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" }); req.person = person; next(); } anleitungRouter.use("/workspace/api/anleitung", angemeldet); /** Wessen Fassung wird gezeigt? * * `req.sicht` ist der HAUSEIGENE Umschalter: DogFather kann die Sicht * eines anderen einnehmen, und dann zeigt jede Seite das, was dieser * andere sieht. Hier gilt dasselbe — und genau deshalb braucht die * Anleitung keine eigene „Vorschau": Die gibt es schon, sie heisst * „Meine Sicht" und steht in der Kopfleiste. * * Ohne gewaehlte Sicht ist DogFather `admin`, und fuer `admin` gibt es * keine Fassung (Bauplan, Kapitel 11). Dann sagt die Seite das, statt * ihm irgendeine fremde Rolle unterzuschieben. */ function fassungFuer(req) { const person = req.sicht || req.person; return { person, rolle: String(person?.rolle || "") }; } anleitungRouter.get("/workspace/api/anleitung", (req, res) => { try { const { person, rolle } = fassungFuer(req); /* DIE CREW HAT HIER NICHTS ZU SUCHEN. 404 und nicht 403: Auf der Crew-Adresse gibt es diese Seite nicht, und „gibt es nicht" ist die richtige Auskunft — 403 waere der Hinweis, dass es sie woanders doch gibt. */ if (person?.haus === "crew") return res.status(404).json({ fehler: "nicht_hier" }); const d = db(); const darfPflegen = PFLEGE_ROLLEN.includes(String(req.person?.rolle || "")); if (!FASSUNGEN.includes(rolle)) { /* DogFather ohne gewaehlte Sicht. Kein Fehler, sondern eine Auskunft: Er bekommt keine Einweisung, kann aber jede ansehen. Die Rollen stehen MIT Namen dabei, damit die Seite keine zweite Rollenliste braucht. */ return res.json({ rolle, hat_fassung: false, darf_pflegen: darfPflegen, fassungen: FASSUNGEN, satz: "Für dich gibt es keine Einweisung – du kennst den Laden. " + "Wähle oben unter „Meine Sicht“ eine Rolle, dann siehst du genau das, " + "was diese Person zu lesen bekommt.", }); } const kopf = d.prepare( "SELECT leitgedanke FROM anl_rolle WHERE haus = ? AND rolle = ?").get(HAUS, rolle); const karten = d.prepare( `SELECT kachel, stufe, wozu, tust, merke, reihe, geaendert FROM anl_karte WHERE haus = ? AND rolle = ? ORDER BY reihe, id`).all(HAUS, rolle); const zeilen = d.prepare( `SELECT art, titel, text, ziel, reihe FROM anl_zeile WHERE haus = ? AND rolle = ? ORDER BY art, reihe, id`).all(HAUS, rolle); const nachArt = (art) => zeilen.filter((z) => z.art === art); /* DIE ZAHL GEHOERT IN DIE ANTWORT, nicht nur in die Liste. Die Seite kann damit sagen „18 Karten" — und eine Pruefung kann nachrechnen, ohne die Liste selbst zu zaehlen. */ res.json({ rolle, hat_fassung: true, darf_pflegen: darfPflegen, leitgedanke: kopf?.leitgedanke || "", stufen: STUFEN, saetze: nachArt("satz").map((z) => z.text), schritte: nachArt("schritt").map((z) => ({ titel: z.titel, text: z.text, ziel: z.ziel })), karten, nicht: nachArt("nicht").map((z) => ({ titel: z.titel, text: z.text })), takt: nachArt("takt").map((z) => ({ titel: z.titel, text: z.text })), fragen: nachArt("frage").map((z) => ({ titel: z.titel, text: z.text })), anzahl: karten.length, }); } catch (fehler) { console.error("[workspace] Anleitung:", fehler?.message); res.status(500).json({ fehler: "serverfehler" }); } });