diff --git a/server/anleitung-inhalte-crew.js b/server/anleitung-inhalte-crew.js new file mode 100644 index 00000000..3ff9765f --- /dev/null +++ b/server/anleitung-inhalte-crew.js @@ -0,0 +1,724 @@ +/* ===================================================================== + Die Einweisung für Team Dogi — Inhalte der vier Crew-Fassungen. + + Quelle: Bauplan „Willkommen & Anleitung — Einweisung je Rolle", + Stand 06.10.2026, Kapitel 06 bis 09. Gelesen mit `tools/pdf-text.mjs` + (auf diesem Rechner liegt kein PDF-Werkzeug; der Auszug übersetzt + die Teilschriften über ihre ToUnicode-Tabellen zurück). + + --------------------------------------------------------------------- + WARUM EINE EIGENE DATEI + + `anleitung-tabellen.js` trägt die Agenturfassungen und ist dabei + schon 856 Zeilen lang. Die Crew bringt noch einmal so viel mit. + Beides in einer Datei wäre eine Datei, in der man nichts mehr + findet — und bei der jede Änderung an einem Haus das andere + mitberührt. Getrennte Dateien sind hier dasselbe Prinzip wie + getrennte Häuser. + + --------------------------------------------------------------------- + DIE SCHLÜSSEL SIND GEMESSEN, NICHT GERATEN + + Jeder `kachel`-Schlüssel stammt aus `bereicheFuer()` für die + jeweilige Rolle, durch dieselbe Regel geschickt, die auch der + Browser benutzt (`schluesselVonZiel`). Zwei Namen sind dabei + überraschend, und beide hätte man beim Abschreiben falsch geraten: + + entwicklung.html heißt „Eure Aufgaben" + werdegang.html heißt „Entwicklung" + + Und `chat.html` trägt ZWEI Kacheln: „Chat" (das Team) und + „Rudel-Chat" (`?raum=treff`). Sie werden seit dem 06.10. als `chat` + und `chat:treff` unterschieden — vorher ergaben beide denselben + Schlüssel, und der Bauplan gibt ihnen verschiedene Einordnungen. + + --------------------------------------------------------------------- + DIE ZAHLEN DES BAUPLANS GEHEN AUF + + Nachgezählt gegen die echten Kachellisten (Kapitel 13): + + Community 14 Karten + Willkommen = 15 Kacheln + Modi 29 Karten + Willkommen = 30 + Linke Hand 29 Karten + Willkommen = 30 + Rechte Hand 34 Karten + Willkommen = 35 + + Die linke Hand stimmte zuerst nicht (34 statt 30). Gemessen: Vier + ihrer Kacheln führten auf Seiten, die sie nicht öffnen darf. Das + lag an der Kachelliste, nicht am Bauplan — behoben am 06.10.2026. + + Für die Kachel „Willkommen & Anleitung" selbst gibt es bewusst + KEINE Karte: Eine Seite, die sich selbst erklärt, ist eine Schleife. + ===================================================================== */ + +export const INHALTE_CREW = { + + /* =================================================================== + COMMUNITY (Rolle `gast`) — Kapitel 06 + =================================================================== */ + gast: { + leitgedanke: + "Dein Platz im Rudel. Schau dich um, schreib etwas oder lies erst mal mit. " + + "Beides ist richtig.", + saetze: [ + "Fünf Kacheln reichen für den Anfang. Den Rest entdeckst du nebenbei.", + "Du musst nichts schreiben und nichts geben. Mitlesen ist völlig in Ordnung.", + "Manches geht erst nach ein paar Tagen. Das kommt von selbst.", + ], + schritte: [ + { titel: "Regeln & Hilfe", ziel: "treff-regeln.html", + text: "Fünf Regeln, einmal lesen." }, + { titel: "Mein Steckbrief", ziel: "steckbrief.html", + text: "Bild wählen, ein Satz über dich." }, + { titel: "Draußen", ziel: "unsere-seiten.html", + text: "Dort siehst du, ob Dogi gerade live ist." }, + { titel: "Wunschliste", ziel: "bereich.html?b=wunsch", + text: "Bei einem Wunsch „Will ich auch“ drücken." }, + /* KEIN ZIEL. „Installieren" ist keine Kachel, sondern der Knopf + in der Kopfleiste -- ein Sprung ginge ins Leere. */ + { titel: "Installieren", ziel: null, + text: "Oben antippen, dann hast du das Rudel als App." }, + ], + karten: [ + { kachel: "treff-regeln", stufe: "muss", + wozu: "Wie es hier läuft.", + tust: "Einmal lesen: fünf Regeln, die Stufen und die Folgen.", + merke: "Reihenfolge bei Verstößen: Hinweis, Pause, Ende." }, + { kachel: "steckbrief", stufe: "muss", + wozu: "Deine Seite.", + tust: "Einmal ausfüllen: Bild, ein Satz, deine Kanäle.", + merke: "Unten kannst du herunterladen, was über dich gespeichert ist." }, + { kachel: "chat:treff", stufe: "muss", + wozu: "Miteinander reden.", + tust: "Im Kanal „Das Rudel“ schreiben, antworten, reagieren.", + merke: "Schreiben ab Stufe Dabei. Mit @ und Namen sprichst du jemanden direkt an." }, + { kachel: "bereich:ansteht", stufe: "muss", + wozu: "Streams, Events, Turniere.", + tust: "Nachsehen, was kommt, mit Countdown.", + merke: "Steht hier nichts, steht noch kein Termin fest." }, + { kachel: "bereich:anschlag", stufe: "muss", + wozu: "Was gerade gilt.", + tust: "Lesen: Ansagen, neue Regeln, Hinweise, Danke.", + merke: "Hier schreibt nur das Team. Abgehängtes gilt nicht mehr." }, + + { kachel: "bereich:wunsch", stufe: "regelmaessig", + wozu: "Was ihr euch wünscht.", + tust: "„Will ich auch“ drücken. Ab Stufe Dabei eigene Wünsche einstellen.", + merke: "Sortiert nach dem, was die meisten wollen. DogFather entscheidet." }, + { kachel: "bereich:highlight", stufe: "regelmaessig", + wozu: "Clips, Bilder, Fanart.", + tust: "Ansehen und auf TikTok liken. Ab Stufe Stamm selbst einstellen.", + merke: "Der Knopf führt zu TikTok. Dort zählt das Liken wirklich." }, + { kachel: "unsere-seiten", stufe: "regelmaessig", + wozu: "Wo es Dogi sonst gibt.", + tust: "Live-Status, Kanäle, Website und Shop öffnen.", + merke: "Im Shop gibt es 10 % für die Community. Der Code steht dort zum Kopieren." }, + { kachel: "reaktion", stufe: "regelmaessig", + wozu: "Zusammen schauen.", + tust: "In den Saal gehen, wenn er offen ist, und im Live-Chat mitschreiben.", + merke: "Ob der Saal offen ist, siehst du schon an der Kachel." }, + + { kachel: "material", stufe: "bedarf", + wozu: "Bilder und Videos zum Posten.", + tust: "„Nehmen und laden“ antippen.", + merke: "Jedes Stück gibt es nur einmal. Wer es nimmt, hat es." }, + { kachel: "unterstuetzen", stufe: "bedarf", + wozu: "Etwas zurückgeben.", + tust: "Aussuchen, was passt: da sein, weitersagen, schenken oder direkt geben.", + merke: "Nichts ist Pflicht, und niemand sieht, wer etwas gegeben hat." }, + { kachel: "bereich:mitmachen", stufe: "bedarf", + wozu: "Wie du dazugehören kannst.", + tust: "Lesen, was gesucht wird. Über „Anfrage stellen“ Modi werden wollen.", + merke: "Ab Stufe Dabei. Die Anfrage lesen nur DogFather und die rechte Hand." }, + { kachel: "support", stufe: "bedarf", + wozu: "Etwas ist kaputt.", + tust: "Einen Satz schreiben, Bildschirmfoto anhängen.", + merke: "Für Fehler an der Seite, nicht für Streit." }, + { kachel: "hilfe", stufe: "bedarf", + wozu: "Wenn etwas vorgefallen ist.", + tust: "„Neue Meldung“ schreiben.", + merke: "Nur DogFather und die rechte Hand lesen mit. Sie sehen deinen Namen." }, + ], + nicht: [ + { titel: "Geld geben.", text: "Wer nur zuschaut, gehört genauso dazu." }, + { titel: "Jeden Tag schreiben.", text: "Mitlesen reicht." }, + { titel: "In den ersten 7 Tagen schreiben.", + text: "Geht noch nicht und kommt von selbst." }, + { titel: "Alle Kacheln kennen.", text: "Fang mit den fünf Muss-Kacheln an." }, + { titel: "Streit selbst klären.", text: "An jedem fremden Beitrag steht „melden“." }, + ], + takt: [ + { titel: "Wenn du reinschaust", + text: "Startseite, Rudel-Chat, Was ansteht, Anschlagbrett." }, + { titel: "Wenn Dogi live ist", text: "Draußen, Reaction." }, + { titel: "Ab und zu", text: "Wunschliste, Highlights." }, + ], + fragen: [ + { titel: "Muss ich alles kennen?", + text: "Nein. Fünf Kacheln reichen. Der Rest kommt, wenn du ihn brauchst." }, + { titel: "Warum kann ich noch nicht schreiben?", + text: "In den ersten 7 Tagen kannst du lesen und mitstimmen. " + + "Das schützt vor Wegwerf-Zugängen." }, + { titel: "Mir gefällt ein Beitrag nicht. Was tun?", + text: "An jedem fremden Beitrag steht „melden“. " + + "Schreib in einem Satz, was nicht in Ordnung ist." }, + { titel: "Muss ich Geld geben, um dazuzugehören?", + text: "Nein. Wer nur zuschaut, gehört genauso dazu." }, + { titel: "Mein Code geht nicht mehr.", + text: "Frag im Live nach. Team Dogi gibt dir einen neuen." }, + ], + /* NUR FUER DIE COMMUNITY (Bauplan, Kapitel 04). Drei Saetze, die + VOR allem anderen stehen -- sie regeln nichts, sie sagen nur, + woran sich alle halten. */ + vorweg: [ + { titel: "Dein Code gehört dir.", + text: "Gib ihn nicht weiter. Was damit geschrieben wird, steht unter deinem Namen." }, + { titel: "Nachts ist Ruhe.", + text: "Zwischen 0 und 6 Uhr kannst du lesen, schreiben geht ab 6 Uhr wieder. " + + "Das gilt für alle, auch für DogFather." }, + { titel: "Was hier passiert, bleibt hier.", + text: "Keine Bildschirmfotos nach draußen." }, + ], + }, + + /* =================================================================== + MODI — Kapitel 07 + =================================================================== */ + modi: { + leitgedanke: + "Dein Bereich im Team. Du nimmst an, was du schaffst, und sagst ab, was nicht geht. " + + "Eine Absage ist in Ordnung, schreib kurz warum.", + saetze: [ + "Dein Alltag sind drei Dinge: Aufgaben, Meldungen aus dem Rudel und das Live.", + "Aus 15 Kacheln sind 30 geworden. Sieben davon brauchst du wirklich.", + "Die Kacheln der Community kennst du schon. Jetzt befüllst du einige davon.", + ], + schritte: [ + { titel: "Aufgaben", ziel: "aufgaben.html", + text: "So nimmst du eine Aufgabe an oder lehnst sie mit einem Satz ab." }, + { titel: "Meldungen & Maßnahmen", ziel: "treff-moderation.html", + text: "Hier landet, was aus dem Rudel gemeldet wird." }, + { titel: "Live-Ablauf", ziel: "bereich.html?b=live", + text: "Die Checkliste für vor, während und nach der Sendung." }, + { titel: "Kalender", ziel: "kalender.html", + text: "Live-Zeiten in deinen eigenen Kalender holen." }, + { titel: "Mein Steckbrief", ziel: "steckbrief.html", text: "Ausfüllen." }, + ], + karten: [ + { kachel: "aufgaben", stufe: "muss", + wozu: "Was für dich dran ist.", + tust: "Annehmen oder ablehnen, bearbeiten, zur Freigabe geben.", + merke: "Wer ablehnt, schreibt einen Satz dazu. Dann muss niemand nachfragen." }, + { kachel: "treff-moderation", stufe: "muss", + wozu: "Die Arbeit am Rudel.", + tust: "Offene Meldungen prüfen, Beitrag entfernen, Hinweis oder Pause geben.", + merke: "Du kannst bis zu 7 Tage Pause geben. Jeder Eingriff braucht einen Grund, " + + "die Person erfährt ihn." }, + { kachel: "bereich:live", stufe: "muss", + wozu: "Checkliste fürs Live.", + tust: "Vor, während und nach der Sendung die Punkte durchgehen: passt so, zu verbessern.", + merke: "40 feste Punkte in drei Phasen." }, + { kachel: "chat", stufe: "muss", + wozu: "Nachrichten mit dem Team.", + tust: "Einzelgespräche, Gruppen, Kanäle.", + merke: "Mit @ und Namen bekommt die Person eine eigene Meldung." }, + { kachel: "kalender", stufe: "muss", + wozu: "Live-Zeiten und Termine.", + tust: "Termine ansehen und anlegen, Live-Zeiten in deinen eigenen Kalender holen.", + merke: "Am Handy einen Tag antippen." }, + { kachel: "chat:treff", stufe: "muss", + wozu: "Der Chat der Community.", + tust: "Mitlesen und mitreden.", + merke: "Zwischen 0 und 6 Uhr nur lesen. Das gilt für alle." }, + { kachel: "steckbrief", stufe: "muss", + wozu: "So sehen dich die anderen.", + tust: "Einmal ausfüllen: Bild, Satz, Kanäle.", + merke: "Jeder pflegt nur seinen eigenen." }, + + { kachel: "bereich:ideen", stufe: "regelmaessig", + wozu: "Ideen sammeln.", + tust: "Idee eintragen, fertige Vorschläge übernehmen.", + merke: "Sortiert nach Dringlichkeit." }, + { kachel: "bereich:rueckmeldung", stufe: "regelmaessig", + wozu: "Was gut läuft, was hakt.", + tust: "Eine Zeile reicht.", + merke: "Geht in beide Richtungen." }, + { kachel: "entwicklung", stufe: "regelmaessig", + wozu: "Was im Team über deine Arbeit notiert ist.", + tust: "Deine Karte ansehen und selbst etwas dazu sagen.", + merke: "Keine Noten. Eine Einschätzung erscheint erst, wenn beide Hände sie " + + "gesetzt haben." }, + { kachel: "befinden", stufe: "regelmaessig", + wozu: "Ein paar Fragen über dich.", + tust: "Antworten und Runde abschließen.", + merke: "Niemand im Team sieht deine Antworten." }, + { kachel: "bereich:anschlag", stufe: "regelmaessig", + wozu: "Was gerade gilt.", + tust: "Ansagen, neue Regeln, Hinweise einstellen.", + merke: "Hier schreibt nur das Team. Abgehängtes gilt nicht mehr." }, + { kachel: "bereich:ansteht", stufe: "regelmaessig", + wozu: "Streams, Events, Turniere.", + tust: "Termine eintragen.", + merke: "Steht hier nichts, sieht die Community keinen Termin." }, + { kachel: "bereich:highlight", stufe: "regelmaessig", + wozu: "Clips, Bilder, Fanart.", + tust: "Eingestellte Beiträge freigeben.", + merke: "Beiträge der Community erscheinen erst nach Freigabe durch das Team." }, + + { kachel: "calls", stufe: "bedarf", + wozu: "Gespräche mit To-dos.", + tust: "Protokolle lesen und schreiben.", + merke: "To-dos werden zu Aufgaben." }, + { kachel: "dateien", stufe: "bedarf", + wozu: "Ablage und Freigaben.", + tust: "Dateien hochladen (bis 25 MB) und öffnen.", + merke: "Entwurf, Zur Freigabe, Freigegeben." }, + { kachel: "bereich:angebote", stufe: "bedarf", + wozu: "Vorschläge für DogFather.", + tust: "Aktion oder Format vorschlagen.", + merke: "DogFather nimmt an oder lehnt ab." }, + { kachel: "werdegang", stufe: "bedarf", + wozu: "Wie du dich bewegst.", + tust: "Verlauf ansehen.", + merke: "Am Anfang leer. Das ist normal." }, + { kachel: "bereich:community", stufe: "bedarf", + wozu: "Begrüßen, vermitteln, wiedererkennen.", + tust: "Festhalten, was vorbereitet ist und was geholfen hat.", + merke: "36 feste Punkte." }, + { kachel: "bereich:technik", stufe: "bedarf", + wozu: "Ton, Bild, Verbindung.", + tust: "Probleme und Lösungen notieren.", + merke: "25 feste Punkte." }, + { kachel: "bereich:wunsch", stufe: "bedarf", + wozu: "Was sich das Rudel wünscht.", + tust: "Mitlesen, was die meisten wollen.", + merke: "DogFather entscheidet." }, + { kachel: "material", stufe: "bedarf", + wozu: "Bilder und Videos zum Posten.", + tust: "Neue Stücke einstellen.", + merke: "Jedes Stück gibt es nur einmal." }, + { kachel: "reaktion", stufe: "bedarf", + wozu: "Zusammen schauen.", + tust: "Dabei sein, wenn der Saal offen ist.", + merke: "Ob er offen ist, steht an der Kachel." }, + { kachel: "unsere-seiten", stufe: "bedarf", + wozu: "Live-Status, Kanäle, Website, Shop.", + tust: "Nachsehen.", + merke: "Du siehst, was die Community sieht." }, + { kachel: "unterstuetzen", stufe: "bedarf", + wozu: "Wie man Dogi etwas zurückgeben kann.", + tust: "Nachsehen.", + merke: "Nichts ist Pflicht." }, + { kachel: "bereich:mitmachen", stufe: "bedarf", + wozu: "Wie man dazugehören kann.", + tust: "Lesen, was gesucht wird.", + merke: "Anfragen lesen nur DogFather und die rechte Hand." }, + { kachel: "treff-regeln", stufe: "bedarf", + wozu: "Regeln, Stufen und Folgen.", + tust: "Nachschlagen, bevor du eingreifst.", + merke: "Reihenfolge bei Verstößen: Hinweis, Pause, Ende." }, + { kachel: "notizen", stufe: "bedarf", + wozu: "Dein Block.", + tust: "Aufschreiben, was dir einfällt.", + merke: "Nur du siehst ihn. Auch DogFather nicht." }, + { kachel: "support", stufe: "bedarf", + wozu: "Etwas ist kaputt.", + tust: "Beschreiben, Bild anhängen.", + merke: "Geht an DogFather und die rechte Hand." }, + ], + nicht: [ + { titel: "Jede Aufgabe annehmen.", text: "Ablehnen ist ausdrücklich vorgesehen." }, + { titel: "Aufgaben verteilen.", text: "Das machen die Linke und die Rechte Hand." }, + { titel: "Pausen über 7 Tage und Ausschlüsse.", text: "Das entscheidet DogFather." }, + { titel: "Leute anlegen und Codes vergeben.", + text: "Das machen die Rechte Hand und DogFather." }, + { titel: "Vertrauliche Meldungen.", + text: "Die lesen nur die Rechte Hand und DogFather." }, + ], + takt: [ + { titel: "Vor dem Live", text: "Live-Ablauf, Kalender, Chat." }, + { titel: "Täglich", + text: "Startseite, Aufgaben, Meldungen & Maßnahmen, Rudel-Chat." }, + { titel: "Wöchentlich", + text: "Ideen-Board, Rückmeldung, Eure Aufgaben, Wie geht's dir?" }, + ], + fragen: [ + { titel: "Darf ich eine Aufgabe ablehnen?", + text: "Ja. Das ist ausdrücklich vorgesehen. Schreib einen Satz dazu." }, + { titel: "Wie lange darf ich jemanden pausieren?", + text: "Bis zu 7 Tage. Längere Pausen und Ausschlüsse sind DogFathers Entscheidung." }, + { titel: "Wer liest meine Notizen?", text: "Niemand außer dir." }, + { titel: "Muss ich begründen, wenn ich etwas entferne?", + text: "Ja. Der Grund wird festgehalten, und die Person erfährt ihn." }, + ], + }, + + /* =================================================================== + LINKE HAND — Kapitel 08 + =================================================================== */ + linke: { + leitgedanke: + "Du führst das Team durch den Tag, mit denselben Werkzeugen wie die Rechte Hand. " + + "Du siehst dieselben 30 Kacheln wie ein Modi, arbeitest aber anders darin.", + saetze: [ + "Du verteilst Aufgaben und behältst das Team im Blick.", + "Neu für dich gegenüber dem Modi: Aufgaben anlegen, Eure Aufgaben für alle, " + + "Entwicklung für alle.", + "Bei Meldungen springst du ein, wenn niemand reagiert.", + ], + schritte: [ + { titel: "Mein Steckbrief", ziel: "steckbrief.html", text: "Ausfüllen." }, + { titel: "Aufgaben", ziel: "aufgaben.html", + text: "Mit „Neue Aufgabe“ eine anlegen: für eine Person oder mehrere." }, + { titel: "Eure Aufgaben", ziel: "entwicklung.html", + text: "Unter „Wen gehst du durch?“ steht das ganze Team." }, + { titel: "Entwicklung", ziel: "werdegang.html", + text: "Alle Karten, nach Rolle geordnet." }, + { titel: "Rückmeldung", ziel: "bereich.html?b=rueckmeldung", + text: "Jemandem kurz Rückmeldung geben." }, + ], + karten: [ + { kachel: "aufgaben", stufe: "muss", + wozu: "Wer macht was.", + tust: "Aufgaben anlegen und verteilen, Stände verfolgen, Rückmeldung geben.", + merke: "Bei mehreren Personen wählen: Jede macht ihren Teil, " + + "oder die Erste mit Zeit übernimmt." }, + { kachel: "entwicklung", stufe: "muss", + wozu: "Das Team im Blick.", + tust: "Jede Person durchgehen, Beobachtungen setzen, Aufgaben aus der Vorlage übernehmen.", + merke: "101 fertige Aufgaben in 14 Kategorien. Eine Einschätzung zählt erst, " + + "wenn beide Hände sie gesetzt haben." }, + { kachel: "treff-moderation", stufe: "muss", + wozu: "Die Arbeit am Rudel.", + tust: "Wie die Modis, und du springst ein, wenn niemand reagiert.", + merke: "Längere Pausen und Ausschlüsse bleiben bei DogFather." }, + { kachel: "bereich:live", stufe: "muss", + wozu: "Checkliste fürs Live.", + tust: "Vor, während und nach der Sendung die Punkte durchgehen: passt so, zu verbessern.", + merke: "40 feste Punkte in drei Phasen." }, + { kachel: "chat", stufe: "muss", + wozu: "Nachrichten mit dem Team.", + tust: "Einzelgespräche, Gruppen, Kanäle.", + merke: "Mit @ und Namen bekommt die Person eine eigene Meldung." }, + { kachel: "kalender", stufe: "muss", + wozu: "Live-Zeiten und Termine.", + tust: "Termine ansehen und anlegen, Live-Zeiten in deinen eigenen Kalender holen.", + merke: "Am Handy einen Tag antippen." }, + { kachel: "steckbrief", stufe: "muss", + wozu: "So sehen dich die anderen.", + tust: "Einmal ausfüllen: Bild, Satz, Kanäle.", + merke: "Jeder pflegt nur seinen eigenen." }, + + { kachel: "werdegang", stufe: "regelmaessig", + wozu: "Bewegung über die Zeit.", + tust: "Karten aller Teammitglieder ansehen.", + merke: "Keine Note, kein Ranking. Nachfragen statt behaupten." }, + { kachel: "bereich:rueckmeldung", stufe: "regelmaessig", + wozu: "Was gut läuft, was hakt.", + tust: "Eine Zeile reicht.", + merke: "Geht in beide Richtungen." }, + { kachel: "chat:treff", stufe: "regelmaessig", + wozu: "Der Chat der Community.", + tust: "Mitlesen und mitreden.", + merke: "Zwischen 0 und 6 Uhr nur lesen. Das gilt für alle." }, + { kachel: "bereich:ideen", stufe: "regelmaessig", + wozu: "Ideen sammeln.", + tust: "Idee eintragen, fertige Vorschläge übernehmen.", + merke: "Sortiert nach Dringlichkeit." }, + { kachel: "befinden", stufe: "regelmaessig", + wozu: "Deine Runde und die Stimmung im Team.", + tust: "Selbst antworten. Im Teamhinweis siehst du, wie viele geantwortet haben " + + "und ob mehrere gerade viel haben.", + merke: "Namen und Antworten siehst du nicht." }, + { kachel: "bereich:anschlag", stufe: "regelmaessig", + wozu: "Was gerade gilt.", + tust: "Ansagen, neue Regeln, Hinweise einstellen.", + merke: "Hier schreibt nur das Team. Abgehängtes gilt nicht mehr." }, + { kachel: "bereich:ansteht", stufe: "regelmaessig", + wozu: "Streams, Events, Turniere.", + tust: "Termine eintragen.", + merke: "Steht hier nichts, sieht die Community keinen Termin." }, + + { kachel: "calls", stufe: "bedarf", + wozu: "Gespräche mit To-dos.", + tust: "Protokolle lesen und schreiben.", + merke: "To-dos werden zu Aufgaben." }, + { kachel: "dateien", stufe: "bedarf", + wozu: "Ablage und Freigaben.", + tust: "Dateien hochladen (bis 25 MB) und öffnen.", + merke: "Entwurf, Zur Freigabe, Freigegeben." }, + { kachel: "bereich:angebote", stufe: "bedarf", + wozu: "Vorschläge für DogFather.", + tust: "Aktion oder Format vorschlagen.", + merke: "DogFather nimmt an oder lehnt ab." }, + { kachel: "bereich:community", stufe: "bedarf", + wozu: "Begrüßen, vermitteln, wiedererkennen.", + tust: "Festhalten, was vorbereitet ist und was geholfen hat.", + merke: "36 feste Punkte." }, + { kachel: "bereich:technik", stufe: "bedarf", + wozu: "Ton, Bild, Verbindung.", + tust: "Probleme und Lösungen notieren.", + merke: "25 feste Punkte." }, + { kachel: "bereich:highlight", stufe: "bedarf", + wozu: "Clips, Bilder, Fanart.", + tust: "Eingestellte Beiträge freigeben.", + merke: "Beiträge der Community erscheinen erst nach Freigabe durch das Team." }, + { kachel: "bereich:wunsch", stufe: "bedarf", + wozu: "Was sich das Rudel wünscht.", + tust: "Mitlesen, was die meisten wollen.", + merke: "DogFather entscheidet." }, + { kachel: "material", stufe: "bedarf", + wozu: "Bilder und Videos zum Posten.", + tust: "Neue Stücke einstellen.", + merke: "Jedes Stück gibt es nur einmal." }, + { kachel: "reaktion", stufe: "bedarf", + wozu: "Zusammen schauen.", + tust: "Dabei sein, wenn der Saal offen ist.", + merke: "Ob er offen ist, steht an der Kachel." }, + { kachel: "unsere-seiten", stufe: "bedarf", + wozu: "Live-Status, Kanäle, Website, Shop.", + tust: "Nachsehen.", + merke: "Du siehst, was die Community sieht." }, + { kachel: "unterstuetzen", stufe: "bedarf", + wozu: "Wie man Dogi etwas zurückgeben kann.", + tust: "Nachsehen.", + merke: "Nichts ist Pflicht." }, + { kachel: "bereich:mitmachen", stufe: "bedarf", + wozu: "Wie man dazugehören kann.", + tust: "Lesen, was gesucht wird.", + merke: "Anfragen lesen nur DogFather und die rechte Hand." }, + { kachel: "treff-regeln", stufe: "bedarf", + wozu: "Regeln, Stufen und Folgen.", + tust: "Nachschlagen, bevor du eingreifst.", + merke: "Reihenfolge bei Verstößen: Hinweis, Pause, Ende." }, + { kachel: "notizen", stufe: "bedarf", + wozu: "Dein Block.", + tust: "Aufschreiben, was dir einfällt.", + merke: "Nur du siehst ihn. Auch DogFather nicht." }, + { kachel: "support", stufe: "bedarf", + wozu: "Etwas ist kaputt.", + tust: "Beschreiben, Bild anhängen.", + merke: "Geht an DogFather und die rechte Hand." }, + ], + nicht: [ + { titel: "Leute anlegen und Codes vergeben.", + text: "Das können nur die Rechte Hand und DogFather." }, + { titel: "Die Rechte-Tafel „Wer sieht was“.", text: "Liegt bei der Rechten Hand." }, + { titel: "Vertrauliche Meldungen.", + text: "Die lesen nur die Rechte Hand und DogFather." }, + { titel: "Längere Pausen und Ausschlüsse.", text: "Bleiben bei DogFather." }, + { titel: "Jede Aufgabe selbst erledigen.", text: "Du verteilst." }, + ], + takt: [ + { titel: "Vor dem Live", text: "Live-Ablauf, Kalender, Aufgaben verteilen." }, + { titel: "Täglich", + text: "Startseite, Aufgaben („Wer hat gerade was“), Meldungen & Maßnahmen." }, + { titel: "Wöchentlich", + text: "Eure Aufgaben (Einschätzungen setzen), Entwicklung, Rückmeldung." }, + ], + fragen: [ + { titel: "Was unterscheidet mich von der Rechten Hand?", + text: "Die Rechte Hand hat zusätzlich Dein Team, Talente, Personen & Zugänge, " + + "Wer sieht was und liest vertrauliche Meldungen." }, + { titel: "Wann zählt eine Einschätzung?", + text: "Erst, wenn beide Hände sie gesetzt haben." }, + { titel: "Sehe ich, was jemand bei „Wie geht's dir?“ antwortet?", + text: "Nein. Du siehst nur, wie viele geantwortet haben." }, + ], + }, + + /* =================================================================== + RECHTE HAND — Kapitel 09 + =================================================================== */ + hand: { + leitgedanke: + "Du hast alles im Blick und entscheidest mit. Du vertrittst DogFather im Alltag, " + + "verteilst Aufgaben und legst neue Leute an.", + saetze: [ + "Bei dir kommt an, was sonst niemand sieht: vertrauliche Meldungen und Support.", + "Dein Team zeigt dir jeden Tag, wer da ist und was auf dich wartet.", + "Von 35 Kacheln brauchst du acht täglich. Die Community-Kacheln befüllen die Modis.", + ], + schritte: [ + { titel: "Dein Team", ziel: "teamlage.html", + text: "Wer da ist, wer was offen hat, was auf dich wartet." }, + { titel: "Personen & Zugänge", ziel: "personen.html", + text: "So legst du jemanden an und gibst den Code weiter." }, + { titel: "Vertraulich melden", ziel: "hilfe.html", + text: "Hier liest du, was niemand sonst sieht." }, + { titel: "Talente", ziel: "talente.html", + text: "Zuschauer, die ins Team passen könnten." }, + { titel: "Wer sieht was", ziel: "rechte.html", + text: "Die Rechte-Tafel. Erst lesen, dann umstellen." }, + ], + karten: [ + { kachel: "teamlage", stufe: "muss", + wozu: "Die Lage des Teams.", + tust: "Sehen, wer da ist und wer was offen hat. „Was auf dich wartet“ abarbeiten.", + merke: "Geordnet nach Linke Hand und Modis." }, + { kachel: "hilfe", stufe: "muss", + wozu: "Vertrauliche Meldungen.", + tust: "Alle Meldungen lesen und bearbeiten.", + merke: "Nur du und DogFather. Kein Modi, kein Mitglied." }, + { kachel: "treff-moderation", stufe: "muss", + wozu: "Die Arbeit am Rudel.", + tust: "Wie die Modis, und du springst ein, wenn niemand reagiert.", + merke: "Längere Pausen und Ausschlüsse bleiben bei DogFather." }, + { kachel: "support", stufe: "muss", + wozu: "Fehler an der Seite.", + tust: "Eingänge ansehen und zurückmelden, wenn erledigt.", + merke: "Kommt bei dir und DogFather an." }, + { kachel: "aufgaben", stufe: "muss", + wozu: "Wer macht was.", + tust: "Aufgaben anlegen und verteilen, Stände verfolgen, Rückmeldung geben.", + merke: "Bei mehreren Personen wählen: Jede macht ihren Teil, " + + "oder die Erste mit Zeit übernimmt." }, + { kachel: "chat", stufe: "muss", + wozu: "Nachrichten mit dem Team.", + tust: "Einzelgespräche, Gruppen, Kanäle.", + merke: "Mit @ und Namen bekommt die Person eine eigene Meldung." }, + { kachel: "personen", stufe: "muss", + wozu: "Wer dabei ist.", + tust: "Person anlegen, Rolle wählen, Code weitergeben.", + merke: "Den Code persönlich oder über einen sicheren Weg weitergeben." }, + { kachel: "steckbrief", stufe: "muss", + wozu: "So sehen dich die anderen.", + tust: "Einmal ausfüllen: Bild, Satz, Kanäle.", + merke: "Jeder pflegt nur seinen eigenen." }, + + { kachel: "talente", stufe: "regelmaessig", + wozu: "Nachwuchs fürs Team.", + tust: "Zuschauer vormerken, die passen könnten. „Wonach du suchst“ lesen.", + merke: "Anfragen aus „Mitmachen“ liest nur du und DogFather." }, + { kachel: "entwicklung", stufe: "regelmaessig", + wozu: "Das Team im Blick.", + tust: "Jede Person durchgehen, Beobachtungen setzen, Aufgaben aus der Vorlage übernehmen.", + merke: "101 fertige Aufgaben in 14 Kategorien. Eine Einschätzung zählt erst, " + + "wenn beide Hände sie gesetzt haben." }, + { kachel: "bereich:mitmachen", stufe: "regelmaessig", + wozu: "Wie man dazugehören kann.", + tust: "Anfragen lesen und beantworten.", + merke: "Die Anfragen lesen nur du und DogFather." }, + { kachel: "werdegang", stufe: "regelmaessig", + wozu: "Bewegung über die Zeit.", + tust: "Karten aller Teammitglieder ansehen.", + merke: "Keine Note, kein Ranking. Nachfragen statt behaupten." }, + { kachel: "bereich:rueckmeldung", stufe: "regelmaessig", + wozu: "Was gut läuft, was hakt.", + tust: "Eine Zeile reicht.", + merke: "Geht in beide Richtungen." }, + { kachel: "bereich:live", stufe: "regelmaessig", + wozu: "Checkliste fürs Live.", + tust: "Vor, während und nach der Sendung die Punkte durchgehen: passt so, zu verbessern.", + merke: "40 feste Punkte in drei Phasen." }, + { kachel: "kalender", stufe: "regelmaessig", + wozu: "Live-Zeiten und Termine.", + tust: "Termine ansehen und anlegen, Live-Zeiten in deinen eigenen Kalender holen.", + merke: "Am Handy einen Tag antippen." }, + + { kachel: "rechte", stufe: "bedarf", + wozu: "Die Rechte-Tafel.", + tust: "Sehen, welche Rolle welche Seite öffnen darf. Ein Klick stellt um.", + merke: "Erst lesen, dann umstellen. Jeder Klick wird sofort gespeichert." }, + { kachel: "calls", stufe: "bedarf", + wozu: "Gespräche mit To-dos.", + tust: "Protokolle lesen und schreiben.", + merke: "To-dos werden zu Aufgaben." }, + { kachel: "dateien", stufe: "bedarf", + wozu: "Ablage und Freigaben.", + tust: "Dateien hochladen (bis 25 MB) und öffnen.", + merke: "Entwurf, Zur Freigabe, Freigegeben." }, + { kachel: "bereich:ideen", stufe: "bedarf", + wozu: "Ideen sammeln.", + tust: "Idee eintragen, fertige Vorschläge übernehmen.", + merke: "Sortiert nach Dringlichkeit." }, + { kachel: "bereich:angebote", stufe: "bedarf", + wozu: "Vorschläge für DogFather.", + tust: "Aktion oder Format vorschlagen.", + merke: "DogFather nimmt an oder lehnt ab." }, + { kachel: "bereich:community", stufe: "bedarf", + wozu: "Begrüßen, vermitteln, wiedererkennen.", + tust: "Festhalten, was vorbereitet ist und was geholfen hat.", + merke: "36 feste Punkte." }, + { kachel: "bereich:technik", stufe: "bedarf", + wozu: "Ton, Bild, Verbindung.", + tust: "Probleme und Lösungen notieren.", + merke: "25 feste Punkte." }, + { kachel: "chat:treff", stufe: "bedarf", + wozu: "Der Chat der Community.", + tust: "Mitlesen und mitreden.", + merke: "Zwischen 0 und 6 Uhr nur lesen. Das gilt für alle." }, + { kachel: "bereich:highlight", stufe: "bedarf", + wozu: "Clips, Bilder, Fanart.", + tust: "Eingestellte Beiträge freigeben.", + merke: "Beiträge der Community erscheinen erst nach Freigabe durch das Team." }, + { kachel: "bereich:anschlag", stufe: "bedarf", + wozu: "Was gerade gilt.", + tust: "Ansagen, neue Regeln, Hinweise einstellen.", + merke: "Hier schreibt nur das Team. Abgehängtes gilt nicht mehr." }, + { kachel: "bereich:ansteht", stufe: "bedarf", + wozu: "Streams, Events, Turniere.", + tust: "Termine eintragen.", + merke: "Steht hier nichts, sieht die Community keinen Termin." }, + { kachel: "bereich:wunsch", stufe: "bedarf", + wozu: "Was sich das Rudel wünscht.", + tust: "Mitlesen, was die meisten wollen.", + merke: "DogFather entscheidet." }, + { kachel: "material", stufe: "bedarf", + wozu: "Bilder und Videos zum Posten.", + tust: "Neue Stücke einstellen.", + merke: "Jedes Stück gibt es nur einmal." }, + { kachel: "reaktion", stufe: "bedarf", + wozu: "Zusammen schauen.", + tust: "Dabei sein, wenn der Saal offen ist.", + merke: "Ob er offen ist, steht an der Kachel." }, + { kachel: "unsere-seiten", stufe: "bedarf", + wozu: "Live-Status, Kanäle, Website, Shop.", + tust: "Nachsehen.", + merke: "Du siehst, was die Community sieht." }, + { kachel: "unterstuetzen", stufe: "bedarf", + wozu: "Wie man Dogi etwas zurückgeben kann.", + tust: "Nachsehen.", + merke: "Nichts ist Pflicht." }, + { kachel: "treff-regeln", stufe: "bedarf", + wozu: "Regeln, Stufen und Folgen.", + tust: "Nachschlagen, bevor du eingreifst.", + merke: "Reihenfolge bei Verstößen: Hinweis, Pause, Ende." }, + { kachel: "notizen", stufe: "bedarf", + wozu: "Dein Block.", + tust: "Aufschreiben, was dir einfällt.", + merke: "Nur du siehst ihn. Auch DogFather nicht." }, + { kachel: "befinden", stufe: "bedarf", + wozu: "Deine Runde und die Stimmung im Team.", + tust: "Selbst antworten. Im Teamhinweis siehst du, wie viele geantwortet haben " + + "und ob mehrere gerade viel haben.", + merke: "Namen und Antworten siehst du nicht." }, + ], + nicht: [ + { titel: "Endgültige Ausschlüsse.", text: "Jeder ist DogFathers Entscheidung." }, + { titel: "Die Rechte-Tafel regelmäßig anfassen.", + text: "Nur bei Änderungen, und dann erst lesen." }, + { titel: "Jede Aufgabe selbst erledigen.", text: "Du verteilst." }, + { titel: "Die Community-Kacheln täglich befüllen.", text: "Das machen die Modis." }, + ], + takt: [ + { titel: "Täglich", + text: "Dein Team, Vertraulich melden, Support-Eingänge, Meldungen & Maßnahmen." }, + { titel: "Wöchentlich", + text: "Talente, Eure Aufgaben, Mitmachen (Anfragen), Personen & Zugänge." }, + { titel: "Bei Änderungen", + text: "Wer sieht was, danach die Anleitung der betroffenen Rolle prüfen." }, + ], + fragen: [ + { titel: "Darf ich jemanden endgültig ausschließen?", + text: "Nein. Jeder endgültige Ausschluss ist DogFathers Entscheidung." }, + { titel: "Wer liest vertrauliche Meldungen?", + text: "Nur du und DogFather. Kein Modi, kein Mitglied." }, + { titel: "Was passiert, wenn ich in „Wer sieht was“ klicke?", + text: "Der Klick wird sofort gespeichert. Drei Felder sind fest, " + + "damit du dich nicht aussperrst." }, + ], + }, +}; + +/** Die Fassungen des Crew-Hauses, in der Reihenfolge des Bauplans. */ +export const FASSUNGEN_CREW = ["gast", "modi", "linke", "hand"]; diff --git a/server/anleitung-tabellen.js b/server/anleitung-tabellen.js index eed899e8..36576883 100644 --- a/server/anleitung-tabellen.js +++ b/server/anleitung-tabellen.js @@ -46,6 +46,8 @@ ===================================================================== */ /** Die drei Stufen. Reihenfolge ist die Anzeigereihenfolge. */ +import { INHALTE_CREW, FASSUNGEN_CREW } from "./anleitung-inhalte-crew.js"; + export const STUFEN = [ { schluessel: "muss", name: "Muss", titel: "Das brauchst du sofort", @@ -70,6 +72,19 @@ export const STUFEN_SCHLUESSEL = STUFEN.map((s) => s.schluessel); * Pflege-Ansicht. */ export const FASSUNGEN = ["creator", "scout", "manager", "spicy"]; +/** Welche Fassungen gibt es in DIESEM Haus? + * + * DAS HAUS ENTSCHEIDET, NICHT DIE ROLLE (06.10.2026). Die Agentur + * hat vier Fassungen, die Crew hat vier andere -- und keine Rolle + * kommt in beiden vor. Vorher stand `FASSUNGEN` an zehn Stellen + * fest; jede davon haette die Crew stillschweigend abgewiesen. + * + * EINE FUNKTION STATT ZWEIER LISTEN AN ZEHN STELLEN: Wer eine + * Fassung ergaenzt, traegt sie an einer Stelle ein. */ +export function fassungenFuer(haus) { + return haus === "crew" ? FASSUNGEN_CREW : FASSUNGEN; +} + /** Wer die Texte aendern darf. * * DogFather UND Spicy — Entscheidung Filipe am 06.10.2026, und zwar @@ -99,6 +114,11 @@ export const ZEILEN_ARTEN = { takt: { titel: true, ziel: false }, /* "Haeufige Fragen" — `titel` die Frage, `text` die Antwort. */ frage: { titel: true, ziel: false }, + /* "Drei Dinge vorweg" — NUR die Community (Bauplan, Kapitel 04). + `titel` die Regel in drei Worten, `text` was sie bedeutet. + Sie steht VOR allem anderen, weil sie nichts erklaert, sondern + sagt, woran sich alle halten. */ + vorweg: { titel: true, ziel: false }, }; export const ARTEN_SCHLUESSEL = Object.keys(ZEILEN_ARTEN); @@ -821,6 +841,9 @@ function rolleEinspielen(d, haus, rolle, inhalt, jetzt) { ["nicht", inhalt.nicht], ["takt", inhalt.takt], ["frage", inhalt.fragen], + /* Nur die Community bringt "Drei Dinge vorweg" mit. Fehlt die + Liste, wird nichts eingetragen -- kein Sonderfall noetig. */ + ["vorweg", inhalt.vorweg || []], ]; for (const [art, liste] of listen) { liste.forEach((z, i) => { @@ -840,15 +863,20 @@ export function anleitungTabellen(d) { const jetzt = new Date().toISOString(); let gesamt = 0; const neu = []; - for (const rolle of FASSUNGEN) { - const inhalt = INHALTE[rolle]; + for (const [haus, rollen, quelle] of [ + ["agentur", FASSUNGEN, INHALTE], + ["crew", FASSUNGEN_CREW, INHALTE_CREW], + ]) { + for (const rolle of rollen) { + const inhalt = quelle[rolle]; /* Eine Rolle ohne Inhalte ist kein Fehler, sondern der Stand der Arbeit: Etappe 1 bringt nur den Creator, die drei anderen kommen in Etappe 3. Still uebergehen — aber die Zuordnungspruefung weiss davon und meldet es als offen, nicht als in Ordnung. */ if (!inhalt) continue; - const n = rolleEinspielen(d, "agentur", rolle, inhalt, jetzt); - if (n) { gesamt += n; neu.push(`${rolle} ${n}`); } + const n = rolleEinspielen(d, haus, rolle, inhalt, jetzt); + if (n) { gesamt += n; neu.push(`${haus}/${rolle} ${n}`); } + } } if (gesamt) { console.log(`[workspace] Anleitung: ${gesamt} Zeilen erstbefuellt (${neu.join(", ")}).`); diff --git a/server/mess-anleitung-crew.mjs b/server/mess-anleitung-crew.mjs index d2e34e28..161e9a6c 100644 --- a/server/mess-anleitung-crew.mjs +++ b/server/mess-anleitung-crew.mjs @@ -85,8 +85,13 @@ const ROLLEN = [["gast", "Community"], ["modi", "Modi"], ["linke", "Linke Hand"] console.log("\n=== Was die Crew-Rollen heute auf willkommen.html bekommen ==="); for (const [rolle, wie] of ROLLEN) { + /* DIE ALTERSBESTAETIGUNG IST EIN EIGENER SCHRITT -- nur fuer den + Gast. Ohne sie antwortet der Server mit 400, und die Messung + haette "Community kommt nicht herein" gemeldet, ohne dass etwas + kaputt waere. */ const an = await ruf("/workspace/api/anmelden", { - methode: "POST", rumpf: JSON.stringify({ rolle, code: `CODE-${rolle.toUpperCase()}-0001` }), + methode: "POST", + rumpf: JSON.stringify({ rolle, code: `CODE-${rolle.toUpperCase()}-0001`, alter_ok: true }), }); if (an.status !== 200) { console.log(` ${wie.padEnd(12)} kommt nicht herein (${an.status})`); continue; } const seite = await ruf("/workspace/willkommen.html", { keks: an.keks }); diff --git a/server/pruef-anleitung.mjs b/server/pruef-anleitung.mjs index c2234f9d..f1b2b439 100644 --- a/server/pruef-anleitung.mjs +++ b/server/pruef-anleitung.mjs @@ -96,7 +96,15 @@ const SCHLUESSEL_PROBEN = [ ["bereich.html?b=live", "bereich:live"], ["bereich.html?b=agentur", "bereich:agentur"], ["profil.html", "profil"], - ["chat.html?raum=treff", "chat"], + /* ZWEI KACHELN AUF EINER SEITE (06.10.2026). Hier stand "chat" -- + und damit bekamen "Chat" (das Team) und "Rudel-Chat" (die + Community) denselben Schluessel. Auf der Agenturadresse fiel das + nie auf, dort gibt es nur eine Chat-Kachel. Die Crew hat beide, + und der Bauplan gibt ihnen verschiedene Einordnungen -- fuer die + rechte Hand ist der Team-Chat Muss, der Rudel-Chat nur bei + Bedarf. Ohne eigenen Schluessel waere das nicht abbildbar. */ + ["chat.html?raum=treff", "chat:treff"], + ["chat.html", "chat"], ["", ""], ]; for (const [ziel, erwartet] of SCHLUESSEL_PROBEN) { @@ -325,12 +333,29 @@ melde(` -- Scout, Manager und Spicy Media haben noch keine Inhalte ` const creatorPflege = creator.j.darf_pflegen; ok(creatorPflege === false, "ein Creator darf NICHT pflegen"); +/* ==== DIE CREW HAT JETZT IHRE EIGENE ANLEITUNG (06.10.2026) ======== + + Hier stand das Gegenteil: "ein Modi bekommt die Anleitung nicht + (erwartet 404)". Das war bis heute richtig -- die Anleitung gab es + nur im Agenturhaus. Mit dem Bauplan "Einweisung je Rolle" hat auch + Team Dogi vier Fassungen bekommen, und die Zeilen sind mitgewandert + statt stehenzubleiben. + + DIE TRENNUNG BLEIBT TROTZDEM, und sie wird hier gemessen: Auf der + Crew-Adresse kommen CREW-Inhalte, nicht die der Agentur. Eine + Anleitung, die auf beiden Adressen dasselbe zeigt, waere der + Rueckschritt hinter die Haustrennung vom 24.09. */ const modi = await holen("modi", CREW_HOST); -ok(modi.code === 404, - `ein Modi bekommt die Anleitung nicht (HTTP ${modi.code}, erwartet 404)`); +ok(modi.code === 200 && (modi.j?.karten?.length ?? 0) === 29, + `ein Modi bekommt seine Anleitung (HTTP ${modi.code}, ${modi.j?.karten?.length ?? 0} Karten)`); const hand = await holen("hand", CREW_HOST); -ok(hand.code === 404, - `die rechte Hand bekommt sie auf der Crew-Adresse nicht (HTTP ${hand.code}, erwartet 404)`); +ok(hand.code === 200 && (hand.j?.karten?.length ?? 0) === 34, + `die rechte Hand auf der Crew-Adresse ebenso (HTTP ${hand.code}, ` + + `${hand.j?.karten?.length ?? 0} Karten)`); +/* GEGENPROBE ZUR HAUSTRENNUNG: Die Crew-Fassung darf keine + Agenturkachel enthalten. "leistung" gibt es nur dort. */ +ok(!(modi.j?.karten || []).some((k) => k.kachel === "leistung"), + "und keine einzige Agenturkachel ist dabei"); /* Die Seite selbst, nicht nur die Schnittstelle. ===================================================================== @@ -631,7 +656,9 @@ const pScout = await pput("scout", `/workspace/api/anleitung/karte/${eineKarte.i ok(pScout.code === 403, `ein Scout auch nicht (HTTP ${pScout.code}, erwartet 403)`); const pModi = await pput("modi", `/workspace/api/anleitung/karte/${eineKarte.id}`, { stufe: "bedarf", wozu: "x", tust: "y", merke: "z" }, CREW_HOST); -ok(pModi.code === 404, `ein Modi bekommt die Pflege gar nicht (HTTP ${pModi.code}, erwartet 404)`); +/* 403 STATT 404 (seit 06.10.2026): Die Seite gibt es auf der + Crew-Adresse jetzt -- pflegen darf ein Modi sie trotzdem nicht. */ +ok(pModi.code === 403, `ein Modi darf nicht pflegen (HTTP ${pModi.code}, erwartet 403)`); melde("\n=== Pflege: Spicy aendert eine Stufe, und sie gilt sofort ==="); const vorher = eineKarte.stufe; @@ -779,9 +806,12 @@ ok(e2.j?.zeigen === false, "beim zweiten Mal nicht mehr"); /* DIE CREW BEKOMMT 200 UND NICHT 404. Das Skript laeuft auf JEDER Startseite; ein Fehlschlag waere eine rote Zeile in der Konsole bei jedem Aufruf -- und die verdeckt die naechste, die echt ist. */ +/* Seit dem 06.10. hat der Modi eine Fassung -- also soll die + Einweisung bei ihm auch ANGEBOTEN werden. Vorher war die ruhige + Absage richtig, weil es nichts einzuweisen gab. */ const eModi = await einweisung("modi", CREW_HOST); -ok(eModi.code === 200 && eModi.j?.zeigen === false, - `ein Modi bekommt eine ruhige Absage (HTTP ${eModi.code}, zeigen ${eModi.j?.zeigen})`); +ok(eModi.code === 200 && eModi.j?.zeigen === true, + `ein Modi bekommt seine Einweisung angeboten (HTTP ${eModi.code}, zeigen ${eModi.j?.zeigen})`); const eDogi = await einweisung("admin"); ok(eDogi.code === 200 && eDogi.j?.zeigen === false, `DogFather auch -- er braucht keine Einweisung (zeigen ${eDogi.j?.zeigen})`); diff --git a/server/workspace-anleitung.js b/server/workspace-anleitung.js index c9cf5f22..39cd3f1b 100644 --- a/server/workspace-anleitung.js +++ b/server/workspace-anleitung.js @@ -35,12 +35,25 @@ import express from "express"; import { db, sitzungLesen } from "./workspace.js"; import { - STUFEN, FASSUNGEN, PFLEGE_ROLLEN, + STUFEN, PFLEGE_ROLLEN, fassungenFuer, } from "./anleitung-tabellen.js"; export const anleitungRouter = express.Router(); -const HAUS = "agentur"; +/** In welchem Haus sind wir? + * + * DIE ADRESSE ENTSCHEIDET, NICHT DIE ANGESEHENE ROLLE (06.10.2026). + * Hier stand `const HAUS = "agentur"` -- die Anleitung gab es nur + * im Agenturhaus, und die Crew bekam an fuenf Stellen ein 404 + * ("nicht_hier"). Seit heute hat auch Team Dogi ihre vier + * Fassungen; das Haus kommt deshalb aus der Anmeldung. + * + * GEFRAGT WIRD IMMER `req.person`, NIE `req.sicht`: Nimmt DogFather + * die Sicht einer anderen Rolle ein, wechselt er damit die ROLLE, + * nicht die ADRESSE. Wer hier die angesehene Person naehme, bekaeme + * auf der Crew-Adresse Agenturinhalte, sobald eine Sicht gesetzt + * ist -- und genau das ist die Trennung, die seit dem 24.09. gilt. */ +const hausVon = (p) => (p?.haus === "crew" ? "crew" : "agentur"); function angemeldet(req, res, next) { const person = sitzungLesen(req); @@ -87,19 +100,18 @@ anleitungRouter.get("/workspace/api/anleitung", (req, res) => { 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)) { + if (!fassungenFuer(hausVon(req.person)).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, + fassungen: fassungenFuer(hausVon(req.person)), 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.", @@ -107,12 +119,12 @@ anleitungRouter.get("/workspace/api/anleitung", (req, res) => { } const kopf = d.prepare( - "SELECT leitgedanke FROM anl_rolle WHERE haus = ? AND rolle = ?").get(HAUS, rolle); + "SELECT leitgedanke FROM anl_rolle WHERE haus = ? AND rolle = ?").get(hausVon(req.person), rolle); const karten = d.prepare( `SELECT id, kachel, stufe, wozu, tust, merke, reihe, geaendert FROM anl_karte WHERE haus = ? AND rolle = ? - ORDER BY reihe, id`).all(HAUS, rolle); + ORDER BY reihe, id`).all(hausVon(req.person), rolle); /* `erledigt` kommt aus derselben Abfrage und nicht aus einer zweiten: Zwei Abfragen koennten zwischen den Zeilen @@ -124,7 +136,7 @@ anleitungRouter.get("/workspace/api/anleitung", (req, res) => { FROM anl_zeile z LEFT JOIN anl_stand s ON s.zeile_id = z.id AND s.person_id = ? WHERE z.haus = ? AND z.rolle = ? - ORDER BY z.art, z.reihe, z.id`).all(wessenStand(req), HAUS, rolle); + ORDER BY z.art, z.reihe, z.id`).all(wessenStand(req), hausVon(req.person), rolle); const nachArt = (art) => zeilen.filter((z) => z.art === art); const schritte = nachArt("schritt"); @@ -217,7 +229,6 @@ anleitungRouter.get("/workspace/api/anleitung", (req, res) => { anleitungRouter.put("/workspace/api/anleitung/schritt/:id", (req, res) => { try { const person = req.person; - if (person?.haus === "crew") return res.status(404).json({ fehler: "nicht_hier" }); const id = Number(req.params.id); if (!Number.isInteger(id) || id <= 0) { @@ -233,7 +244,7 @@ anleitungRouter.put("/workspace/api/anleitung/schritt/:id", (req, res) => { const zeile = d.prepare( `SELECT id FROM anl_zeile WHERE id = ? AND art = 'schritt' AND haus = ? AND rolle = ?`) - .get(id, HAUS, String(person?.rolle || "")); + .get(id, hausVon(req.person), String(person?.rolle || "")); if (!zeile) return res.status(404).json({ fehler: "kein_schritt" }); if (erledigt) { @@ -255,7 +266,7 @@ anleitungRouter.put("/workspace/api/anleitung/schritt/:id", (req, res) => { FROM anl_zeile z LEFT JOIN anl_stand s ON s.zeile_id = z.id AND s.person_id = ? WHERE z.haus = ? AND z.rolle = ? AND z.art = 'schritt'`) - .get(person.id, HAUS, String(person.rolle)); + .get(person.id, hausVon(req.person), String(person.rolle)); res.json({ erledigt, @@ -287,9 +298,9 @@ anleitungRouter.put("/workspace/api/anleitung/schritt/:id", (req, res) => { ===================================================================== */ export function offeneHinweise(person) { try { - if (!person || person.haus === "crew") return []; + if (!person) return []; const rolle = String(person.rolle || ""); - if (!FASSUNGEN.includes(rolle)) return []; + if (!fassungenFuer(hausVon(person)).includes(rolle)) return []; const stand = db().prepare( `SELECT COUNT(*) AS gesamt, @@ -297,7 +308,7 @@ export function offeneHinweise(person) { FROM anl_zeile z LEFT JOIN anl_stand s ON s.zeile_id = z.id AND s.person_id = ? WHERE z.haus = ? AND z.rolle = ? AND z.art = 'schritt'`) - .get(person.id, HAUS, rolle); + .get(person.id, hausVon(person), rolle); const gesamt = Number(stand?.gesamt || 0); const offen = gesamt - Number(stand?.erledigt || 0); @@ -337,7 +348,6 @@ export function offeneHinweise(person) { ===================================================================== */ function nurPflege(req, res, next) { - if (req.person?.haus === "crew") return res.status(404).json({ fehler: "nicht_hier" }); if (!PFLEGE_ROLLEN.includes(String(req.person?.rolle || ""))) { return res.status(403).json({ fehler: "nicht_erlaubt" }); } @@ -361,7 +371,7 @@ anleitungRouter.put("/workspace/api/anleitung/karte/:id", nurPflege, (req, res) geaendert = ?, geaendert_von = ? WHERE id = ? AND haus = ?`) .run(stufe, text(req.body?.wozu, 300), text(req.body?.tust, 400), - text(req.body?.merke, 400), new Date().toISOString(), req.person.id, id, HAUS); + text(req.body?.merke, 400), new Date().toISOString(), req.person.id, id, hausVon(req.person)); if (!n.changes) return res.status(404).json({ fehler: "keine_karte" }); res.json({ ok: true }); } catch (fehler) { @@ -381,7 +391,7 @@ anleitungRouter.post("/workspace/api/anleitung/karte", nurPflege, (req, res) => const rolle = String(req.body?.rolle ?? ""); const kachel = text(req.body?.kachel, 80); const stufe = String(req.body?.stufe ?? "bedarf"); - if (!FASSUNGEN.includes(rolle)) return res.status(400).json({ fehler: "unbekannte_rolle" }); + if (!fassungenFuer(hausVon(req.person)).includes(rolle)) return res.status(400).json({ fehler: "unbekannte_rolle" }); if (!kachel) return res.status(400).json({ fehler: "keine_kachel" }); if (!STUFEN.some((s) => s.schluessel === stufe)) { return res.status(400).json({ fehler: "unbekannte_stufe" }); @@ -389,13 +399,13 @@ anleitungRouter.post("/workspace/api/anleitung/karte", nurPflege, (req, res) => const d = db(); const platz = d.prepare( "SELECT COALESCE(MAX(reihe), -1) + 1 AS n FROM anl_karte WHERE haus = ? AND rolle = ?") - .get(HAUS, rolle).n; + .get(hausVon(req.person), rolle).n; try { d.prepare( `INSERT INTO anl_karte (haus, rolle, kachel, stufe, wozu, tust, merke, reihe, geaendert, geaendert_von) VALUES (?,?,?,?,?,?,?,?,?,?)`) - .run(HAUS, rolle, kachel, stufe, text(req.body?.wozu, 300), + .run(hausVon(req.person), rolle, kachel, stufe, text(req.body?.wozu, 300), text(req.body?.tust, 400), text(req.body?.merke, 400), platz, new Date().toISOString(), req.person.id); } catch { @@ -416,7 +426,7 @@ anleitungRouter.delete("/workspace/api/anleitung/karte/:id", nurPflege, (req, re try { const id = Number(req.params.id); if (!Number.isInteger(id) || id <= 0) return res.status(400).json({ fehler: "keine_nummer" }); - const n = db().prepare("DELETE FROM anl_karte WHERE id = ? AND haus = ?").run(id, HAUS); + const n = db().prepare("DELETE FROM anl_karte WHERE id = ? AND haus = ?").run(id, hausVon(req.person)); if (!n.changes) return res.status(404).json({ fehler: "keine_karte" }); res.json({ ok: true }); } catch (fehler) { @@ -431,7 +441,7 @@ anleitungRouter.put("/workspace/api/anleitung/zeile/:id", nurPflege, (req, res) const id = Number(req.params.id); if (!Number.isInteger(id) || id <= 0) return res.status(400).json({ fehler: "keine_nummer" }); const d = db(); - const alt = d.prepare("SELECT art FROM anl_zeile WHERE id = ? AND haus = ?").get(id, HAUS); + const alt = d.prepare("SELECT art FROM anl_zeile WHERE id = ? AND haus = ?").get(id, hausVon(req.person)); if (!alt) return res.status(404).json({ fehler: "keine_zeile" }); /* Ein Ziel gibt es nur beim Schritt. Bei einer Frage waere es ein Feld, das nirgends angezeigt wird -- und beim naechsten Umbau @@ -441,7 +451,7 @@ anleitungRouter.put("/workspace/api/anleitung/zeile/:id", nurPflege, (req, res) `UPDATE anl_zeile SET titel = ?, text = ?, ziel = ?, geaendert = ?, geaendert_von = ? WHERE id = ? AND haus = ?`) .run(text(req.body?.titel, 200), text(req.body?.text, 600), ziel, - new Date().toISOString(), req.person.id, id, HAUS); + new Date().toISOString(), req.person.id, id, hausVon(req.person)); res.json({ ok: true }); } catch (fehler) { console.error("[workspace] Anleitung Zeile:", fehler?.message); @@ -453,13 +463,13 @@ anleitungRouter.put("/workspace/api/anleitung/zeile/:id", nurPflege, (req, res) anleitungRouter.put("/workspace/api/anleitung/rolle/:rolle", nurPflege, (req, res) => { try { const rolle = String(req.params.rolle || ""); - if (!FASSUNGEN.includes(rolle)) return res.status(404).json({ fehler: "unbekannte_rolle" }); + if (!fassungenFuer(hausVon(req.person)).includes(rolle)) return res.status(404).json({ fehler: "unbekannte_rolle" }); db().prepare( `INSERT INTO anl_rolle (haus, rolle, leitgedanke, geaendert, geaendert_von) VALUES (?,?,?,?,?) ON CONFLICT(haus, rolle) DO UPDATE SET leitgedanke = excluded.leitgedanke, geaendert = excluded.geaendert, geaendert_von = excluded.geaendert_von`) - .run(HAUS, rolle, text(req.body?.leitgedanke, 600), + .run(hausVon(req.person), rolle, text(req.body?.leitgedanke, 600), new Date().toISOString(), req.person.id); res.json({ ok: true }); } catch (fehler) { @@ -484,8 +494,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 (${FASSUNGEN.map(() => "?").join(",")}) - ORDER BY p.rolle, p.name`).all(HAUS, ...FASSUNGEN); + 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))); res.json({ leute: leute.map((p) => ({ name: p.name, rolle: p.rolle, @@ -525,7 +535,7 @@ anleitungRouter.get("/workspace/api/anleitung/einweisung", (req, res) => { recht nicht fuer ihn abhaken, dass sie gezeigt wurde. */ const person = req.person; const rolle = String(person?.rolle || ""); - if (person?.haus === "crew" || !FASSUNGEN.includes(rolle)) { + if (!fassungenFuer(hausVon(person)).includes(rolle)) { return res.json({ zeigen: false, rolle }); } const d = db(); @@ -539,7 +549,7 @@ anleitungRouter.get("/workspace/api/anleitung/einweisung", (req, res) => { const muss = d.prepare( `SELECT kachel FROM anl_karte WHERE haus = ? AND rolle = ? AND stufe = 'muss' ORDER BY reihe`) - .all(HAUS, rolle).map((z) => z.kachel); + .all(hausVon(req.person), rolle).map((z) => z.kachel); res.json({ zeigen: !schon, @@ -567,7 +577,7 @@ anleitungRouter.post("/workspace/api/anleitung/einweisung/gesehen", (req, res) = try { const person = req.person; const rolle = String(person?.rolle || ""); - if (person?.haus === "crew" || !FASSUNGEN.includes(rolle)) { + if (!fassungenFuer(hausVon(person)).includes(rolle)) { return res.json({ ok: true }); } db().prepare( diff --git a/workspace/anleitung.html b/workspace/anleitung.html index 89150019..ac1c1222 100644 --- a/workspace/anleitung.html +++ b/workspace/anleitung.html @@ -7,17 +7,17 @@ - - - - - + + + + + - - + +
@@ -261,16 +261,16 @@ Und anleitung.js braucht es doppelt: Symbol, Farbe, Name und Adresse jeder Karte kommen von dort, nicht vom Server. --> - + - - - - - - + + + + + +