From 88a8d302b95b21bf266b63022d56ba825e680b40 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Tue, 6 Oct 2026 17:49:18 +0200 Subject: [PATCH] Kapitel 11 auf der Crew-Adresse: die Community gehoert nicht in die Pflegeliste ZWEITER BEFUND DES ABENDS, und wieder einer, den es im Agenturhaus gar nicht geben konnte. Bauplan Kapitel 11, woertlich: "Stand der Ersten Schritte: nur fuer Team-Rollen, 'fertig / offen' mit Datum. Fuer die Community wird nichts je Person angezeigt." Gemessen: Auf der Crew-Adresse nahm die Liste schlicht alle Fassungen des Hauses -- und seit die Community seit heute frueh eine eigene Fassung hat, stand jedes Mitglied mit Namen, Fortschritt und Datum darin. Im Agenturhaus konnte das nie auffallen, dort ist jede Fassung eine Teamrolle. Das ist kein Schoenheitsfehler: Ein Mitglied hat sich zum Mitlesen angemeldet, nicht zu einer Fortschrittsakte. Jetzt siebt `standRollen()` ueber AUSSEN_ROLLEN -- abgeleitet und nicht als zweite Liste, damit die naechste Rolle von aussen automatisch heraus ist. Gegenprobe gefahren: Sieb ausgebaut -> die Zeile wird rot und nennt "1 von 4". DAZU GEPRUEFT, was Kapitel 11 sonst verlangt (pruef-anleitung 173 -> 181): DogFather bekommt auf der Crew-Adresse die Pflege statt einer Fassung, mit den VIER Fassungen dieses Hauses (nicht denen der Agentur); ein Modi kommt an die Liste gar nicht heran (403); und die "Vorschau in der Sicht dieser Rolle" liefert ihm die 29 Karten des Modi, mit `darf_pflegen: true` und `darf_abhaken: false` -- er soll pflegen koennen, aber nicht in fremdem Namen abhaken. Nachgestellt wird dabei genau die Anfrage, die kopf.js stellt (`sicht=` an jede lesende Anfrage), nicht eine nachgebaute. AUSSERDEM: ZWEI DINGE HIESSEN `an-stufe` Der Kasten einer EINORDNUNG ("Das brauchst du sofort") und der Kasten "Deine Stufe" mit Neu, Dabei, Stamm trugen dieselbe Klasse. Der Bauplan warnt in Kapitel 14 ausdruecklich davor, die beiden zu verwechseln -- im Quelltext taten sie es. Aufgefallen beim Messen des Filters "Muss": Er musste seine Suche von Hand auf `#stufen` eingrenzen, sonst haette er die Karte "Deine Stufe" mit weggeblendet. Eine Regel wie `.an-stufe { display: none }` haette denselben Schaden angerichtet, und man haette sie nicht kommen sehen. Die Mitglieder-Stufe heisst jetzt `an-rang`; in der Oberflaeche aendert sich kein Wort. IM BROWSER NACHGEMESSEN (390 px, echte Anmeldung) Filter "Muss" -> Community 5 Karten, rechte Hand 8. Genau die Zahlen der Abnahme-Checkliste, und nach dem Umbenennen blendet er nur noch den einen Abschnitt aus statt zwei. "Deine Stufe" -> Community ja ("Du bist gerade: Neu"), rechte Hand nein. Steht und faellt mit dem neuen Namen. Keine Browsermeldungen, kein Querscrollen. pruef-css-klassen und pruef-anleitung (181) gruen. Co-Authored-By: Claude Opus 5 --- server/mess-anleitung-crew.mjs | 22 ++++++++++ server/pruef-anleitung.mjs | 69 ++++++++++++++++++++++++++++++ server/workspace-anleitung.js | 32 +++++++++++++- workspace/anleitung.html | 34 +++++++-------- workspace/anruf-probe.html | 10 ++--- workspace/app.webmanifest | 8 ++-- workspace/assets/css/anleitung.css | 38 +++++++++++----- workspace/assets/js/anleitung.js | 10 ++--- workspace/aufgaben.html | 38 ++++++++-------- workspace/automation.html | 32 +++++++------- workspace/befinden.html | 34 +++++++-------- workspace/bereich.html | 44 +++++++++---------- workspace/bewerben.html | 38 ++++++++-------- workspace/bewerbungen.html | 36 ++++++++-------- workspace/buehne.html | 6 +-- workspace/calls.html | 34 +++++++-------- workspace/chat.html | 40 ++++++++--------- workspace/content.html | 34 +++++++-------- workspace/crew-index.html | 12 +++--- workspace/crew.webmanifest | 8 ++-- workspace/dateien.html | 34 +++++++-------- workspace/entwicklung.html | 36 ++++++++-------- workspace/hilfe.html | 30 ++++++------- workspace/index.html | 10 ++--- workspace/kalender.html | 34 +++++++-------- workspace/leistung.html | 32 +++++++------- workspace/manager-ziele.html | 28 ++++++------ workspace/material.html | 32 +++++++------- workspace/notizen.html | 28 ++++++------ workspace/personen.html | 32 +++++++------- workspace/profil.html | 36 ++++++++-------- workspace/reaktion.html | 38 ++++++++-------- workspace/rechte.html | 34 +++++++-------- workspace/report.html | 36 ++++++++-------- workspace/scouting.html | 32 +++++++------- workspace/start.html | 38 ++++++++-------- workspace/startcheck.html | 34 +++++++-------- workspace/steckbrief.html | 36 ++++++++-------- workspace/support.html | 28 ++++++------ workspace/tafel.html | 6 +-- workspace/talente.html | 36 ++++++++-------- workspace/team.html | 32 +++++++------- workspace/teamlage.html | 34 +++++++-------- workspace/teilen.html | 30 ++++++------- workspace/treff-moderation.html | 32 +++++++------- workspace/treff-regeln.html | 32 +++++++------- workspace/uebersicht.html | 32 +++++++------- workspace/unsere-seiten.html | 30 ++++++------- workspace/unterstuetzen.html | 32 +++++++------- workspace/werdegang.html | 32 +++++++------- workspace/wissen.html | 34 +++++++-------- 51 files changed, 842 insertions(+), 707 deletions(-) diff --git a/server/mess-anleitung-crew.mjs b/server/mess-anleitung-crew.mjs index 17df9dec..a4e089e0 100644 --- a/server/mess-anleitung-crew.mjs +++ b/server/mess-anleitung-crew.mjs @@ -242,6 +242,28 @@ for (const [rolle, wie] of ROLLEN) { console.log(` Querscrollen : ${lage.quer ? "JA -- Befund" : "nein"}`); console.log(` Tippziele unter 44 : ${lage.klein}`); console.log(` Stufen-Marken : ${lage.marken.join(" | ") || "keine"}`); + + /* ==== DER FILTER „MUSS" (Abnahme Kapitel 13) ===================== + „Filter ‚Muss' zeigt nur die Muss-Karten." Gemessen wird, was + nach dem Tippen SICHTBAR ist -- nicht, was im Baum steht. Ein + Kasten mit `hidden` enthaelt seine Karten weiterhin; wer sie + zaehlt, zaehlt auch die verborgenen und bekommt immer dieselbe + Zahl heraus. */ + const filter = await seite.evaluate(async () => { + const knopf = [...document.querySelectorAll(".an-filter__knopf")] + .find((k) => k.dataset.wert === "muss"); + if (!knopf) return { da: false }; + knopf.click(); + await new Promise((r) => setTimeout(r, 200)); + const sichtbar = [...document.querySelectorAll(".an-karte")] + .filter((k) => k.getBoundingClientRect().height > 0).length; + const offeneStufen = [...document.querySelectorAll(".an-stufe")] + .filter((b) => !b.hidden).map((b) => b.dataset.stufe); + return { da: true, sichtbar, stufen: offeneStufen.join(", ") }; + }); + console.log(` Filter „Muss“ : ${filter.da + ? `${filter.sichtbar} Karten sichtbar, Abschnitt(e): ${filter.stufen}` + : "KEIN FILTERKNOPF -- Befund"}`); console.log(` Browsermeldungen : ${klagen.length ? klagen.join(" | ") : "keine"}`); console.log(` Fehlgeschlagen : ${schlecht.length ? schlecht.slice(0, 6).join(" | ") : "nichts"}`); diff --git a/server/pruef-anleitung.mjs b/server/pruef-anleitung.mjs index e40cf475..2a41291f 100644 --- a/server/pruef-anleitung.mjs +++ b/server/pruef-anleitung.mjs @@ -1290,6 +1290,75 @@ melde("\n=== Seite sperren, Karte weg (Abnahme Kapitel 13) ==="); + `${vorher.length})`); } +/* ===================================================================== + DIE PFLEGE AUF DER CREW-ADRESSE (Bauplan Kapitel 11) + --------------------------------------------------------------------- + „Fuer DogFather gibt es keine Fassung und keinen Rundgang. Bei ihm + oeffnet die Kachel die Pflege-Ansicht: Rolle waehlen und Vorschau, + Einordnung aendern, Texte bearbeiten, Lueckenwarnung, Stand der + Ersten Schritte — nur fuer Team-Rollen, fuer die Community wird + nichts je Person angezeigt." + + DER LETZTE HALBSATZ IST DER, DER HIER GEMESSEN WIRD. Im Agenturhaus + konnte er nie falsch sein (dort ist jede Fassung eine Teamrolle); + auf der Crew-Adresse schon, seit die Community eine eigene Fassung + hat. Ein Mitglied hat sich zum Mitlesen angemeldet, nicht zu einer + Fortschrittsakte mit Namen und Datum. */ +melde("\n=== Die Pflege auf der Crew-Adresse (Kapitel 11) ==="); +{ + const dogiCrew = await holen("admin", CREW_HOST); + ok(dogiCrew.code === 200 && dogiCrew.j?.hat_fassung === false + && dogiCrew.j?.darf_pflegen === true, + `DogFather bekommt auf der Crew-Adresse die Pflege, keine Fassung ` + + `(HTTP ${dogiCrew.code}, Fassung ${dogiCrew.j?.hat_fassung}, ` + + `pflegen ${dogiCrew.j?.darf_pflegen})`); + /* Und zwar die VIER des Hauses, nicht die der Agentur. */ + const angeboten = (dogiCrew.j?.fassungen || []).join(","); + ok(angeboten === "gast,modi,linke,hand", + `…mit den vier Fassungen dieses Hauses (${angeboten || "keine"})`); + + const st = await roh("/workspace/api/anleitung/stand", CREW_HOST, null, kekse.admin); + let leute = []; + try { leute = JSON.parse(st.text)?.leute || []; } catch { /* bleibt leer */ } + ok(st.code === 200 && leute.length > 0, + `der Stand der Ersten Schritte oeffnet sich (HTTP ${st.code}, ` + + `${leute.length} Leute)`); + ok(!leute.some((p) => p.rolle === "gast"), + `…und kein einziges Mitglied steht darin (${ + leute.filter((p) => p.rolle === "gast").length} von ${leute.length})`); + /* GEGENPROBE: Es steht ueberhaupt jemand drin, und zwar aus dem + Team. Ohne diese Zeile waere die darueber auch dann gruen, wenn + die Liste aus einem ganz anderen Grund leer bliebe. */ + ok(leute.some((p) => ["modi", "linke", "hand"].includes(p.rolle)), + `Gegenprobe: die Teamrollen stehen sehr wohl darin (${ + leute.map((p) => p.rolle).join(", ") || "niemand"})`); + /* Und ein Modi kommt gar nicht erst an die Liste. */ + const stModi = await roh("/workspace/api/anleitung/stand", CREW_HOST, null, kekse.modi); + ok(stModi.code === 403, `ein Modi sieht den Stand nicht (${stModi.code})`); + + /* ---- „Rolle waehlen und Vorschau in der Sicht dieser Rolle" ------- + Gebaut ist das nicht als zweite Rollenauswahl, sondern ueber den + Sicht-Umschalter, den es im Haus schon gibt: kopf.js haengt jeder + LESENDEN Anfrage `sicht=` an. Genau das wird hier + nachgestellt -- nicht nachgebaut, sondern dieselbe Anfrage + gestellt, die der Browser stellt. */ + const modiId = (() => { + const d = new DatabaseSync(process.env.WORKSPACE_DB); + const z = d.prepare("SELECT id FROM personen WHERE rolle = 'modi'").get(); + d.close(); return z?.id || 0; + })(); + braucht(!!modiId, "kein Modi in der Probe-Datenbank"); + const vorschau = await roh(`/workspace/api/anleitung?sicht=${modiId}`, + CREW_HOST, null, kekse.admin); + let vj = null; try { vj = JSON.parse(vorschau.text); } catch { /* bleibt null */ } + ok(vj?.rolle === "modi" && (vj?.karten?.length ?? 0) === 29, + `in der Sicht auf einen Modi sieht er dessen Anleitung ` + + `(${vj?.rolle}, ${vj?.karten?.length ?? 0} Karten)`); + ok(vj?.darf_pflegen === true && vj?.darf_abhaken === false, + `…darf sie pflegen, aber nicht in fremdem Namen abhaken ` + + `(pflegen ${vj?.darf_pflegen}, abhaken ${vj?.darf_abhaken})`); +} + /* ---------- Abschluss ------------------------------------------------ */ try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } console.log(`\n${fehler ? "FEHLER: " + fehler : "Alles in Ordnung"} — ${geprueft} Prüfungen`); diff --git a/server/workspace-anleitung.js b/server/workspace-anleitung.js index 8ecd5fce..1f0b4693 100644 --- a/server/workspace-anleitung.js +++ b/server/workspace-anleitung.js @@ -615,8 +615,36 @@ anleitungRouter.put("/workspace/api/anleitung/rolle/:rolle", nurPflege, (req, re * Unterscheidung wie bei der Team-Lage. Hier steht, wer seine * Einweisung noch offen hat, damit jemand nachfragen kann. Nicht, * was er gelesen hat oder wie lange er gebraucht hat. */ +/** Welche Rollen stehen im „Stand der Ersten Schritte"? + * + * NUR TEAMROLLEN -- Bauplan Kapitel 11, woertlich: „Stand der Ersten + * Schritte: nur fuer Team-Rollen, ‚fertig / offen' mit Datum. Fuer die + * Community wird nichts je Person angezeigt." + * + * GEMESSEN AM 06.10.2026, UND ES STIMMTE NICHT: Auf der Crew-Adresse + * nahm die Liste schlicht alle Fassungen des Hauses -- und seit die + * Community eine eigene Fassung hat, stand jedes Mitglied mit Namen + * und Fortschritt darin. Das ist kein Schoenheitsfehler: Ein Mitglied + * hat sich zum Mitlesen angemeldet, nicht zu einer Fortschrittsakte. + * Im Agenturhaus fiel es nicht auf, weil dort jede Fassung eine + * Teamrolle ist. + * + * ABGELEITET AUS AUSSEN_ROLLEN und nicht aus einer zweiten Liste: + * Kommt eines Tages eine weitere Rolle von aussen dazu, ist sie damit + * automatisch heraus. Eine Liste hier waere die, die man beim + * Anlegen der neuen Rolle nicht anfasst. */ +function standRollen(haus) { + return fassungenFuer(haus).filter((r) => !AUSSEN_ROLLEN.has(r)); +} + anleitungRouter.get("/workspace/api/anleitung/stand", nurPflege, (req, res) => { try { + const rollen = standRollen(hausVon(req.person)); + /* Keine Teamrolle in diesem Haus? Dann eine leere Liste und kein + SQL mit leerem IN () -- das waere ein Syntaxfehler und damit ein + 500 an einer Stelle, an der „es gibt niemanden" die richtige + Antwort ist. */ + if (!rollen.length) return res.json({ leute: [] }); const leute = db().prepare( `SELECT p.id, p.name, p.rolle, (SELECT COUNT(*) FROM anl_zeile z @@ -625,8 +653,8 @@ anleitungRouter.get("/workspace/api/anleitung/stand", nurPflege, (req, res) => { WHERE s.person_id = p.id AND z2.art = 'schritt') AS erledigt, (SELECT MAX(s2.erledigt_am) FROM anl_stand s2 WHERE s2.person_id = p.id) AS zuletzt FROM personen p - WHERE p.aktiv = 1 AND p.rolle IN (${fassungenFuer(hausVon(req.person)).map(() => "?").join(",")}) - ORDER BY p.rolle, p.name`).all(hausVon(req.person), ...fassungenFuer(hausVon(req.person))); + WHERE p.aktiv = 1 AND p.rolle IN (${rollen.map(() => "?").join(",")}) + ORDER BY p.rolle, p.name`).all(hausVon(req.person), ...rollen); res.json({ leute: leute.map((p) => ({ name: p.name, rolle: p.rolle, diff --git a/workspace/anleitung.html b/workspace/anleitung.html index 635e85ae..0fa581e5 100644 --- a/workspace/anleitung.html +++ b/workspace/anleitung.html @@ -7,17 +7,17 @@ - - - - - + + + + + - - + + @@ -146,10 +146,10 @@ Bedarf sagen, was WICHTIG ist; Neu, Dabei und Stamm sagen, was jemand DARF. Deshalb heißt die Einordnung auf dieser Seite nirgends „Stufe". --> -