diff --git a/server/pruef-verteilen.mjs b/server/pruef-verteilen.mjs
index 78ac2d48..628022a5 100644
--- a/server/pruef-verteilen.mjs
+++ b/server/pruef-verteilen.mjs
@@ -160,14 +160,36 @@ const vonDogi = await anlegenFuer(kDogi, idModi2, "Von DogFather an Ghost");
ok(vonDogi.code === 201 && vonDogi.verant === idModi2,
`DogFather ebenso (${vonDogi.code}, liegt bei ${vonDogi.verant})`);
-/* DIE ENTSCHEIDENDE GEGENPROBE: Ein Modi versucht dasselbe. Die
- Aufgabe wird NICHT abgelehnt -- sie landet bei ihm selbst. Das ist
- freundlicher als ein Fehler und genau das, was Filipe wollte:
- "jeder soll sich selber aufgabe vergeben koennen". */
+/* DIE ENTSCHEIDENDE GEGENPROBE: Ein Modi versucht dasselbe.
+ ---------------------------------------------------------------------
+ BIS ZUM 22.09.2026 stand hier, die Aufgabe lande bei ihm selbst --
+ "jeder soll sich selber aufgabe vergeben koennen" (20.09.). Filipe
+ hat das ausdruecklich umgedreht: "damit wir endlich den modis
+ aufgaben anstaendig verteilen koennen und sie sich nicht selber
+ aufgaben geben."
+
+ Im Team Dogi kommen Aufgaben jetzt von der Leitung. Ein Modi
+ bekommt 403 -- und das ist der Unterschied, auf den es ankommt: Er
+ kann sich keine geben, weder sich selbst noch jemand anderem. */
const vonModi = await anlegenFuer(kModi, idModi2, "Versuch eines Modi");
-ok(vonModi.code === 201 && vonModi.verant === idModi,
- `Gegenprobe: ein Modi kann es versuchen — die Aufgabe landet bei ihm selbst `
- + `(${vonModi.verant}, nicht ${idModi2})`);
+ok(vonModi.code === 403,
+ `Gegenprobe: ein Modi legt gar keine Aufgabe mehr an (${vonModi.code})`);
+
+/* UND IN DER AGENTUR BLEIBT ES, WIE ES WAR. Dort ist eine Aufgabe eine
+ Notiz an sich selbst, kein Auftrag von jemandem -- eine Regel, die
+ beide Haeuser ueber einen Kamm schert, waere falsch. */
+{
+ const w = await import("./workspace.js");
+ ok(w.darfAufgabenAnlegen({ rolle: "creator" }) === true
+ && w.darfAufgabenAnlegen({ rolle: "manager" }) === true,
+ "in der Agentur legt weiterhin jeder fuer sich selbst an");
+ ok(w.darfAufgabenAnlegen({ rolle: "modi" }) === false,
+ "ein Modi nicht");
+ ok(w.darfAufgabenAnlegen({ rolle: "hand" }) === true
+ && w.darfAufgabenAnlegen({ rolle: "linke" }) === true
+ && w.darfAufgabenAnlegen({ rolle: "admin" }) === true,
+ "die drei, die verteilen duerfen, schon");
+}
/* =======================================================================
DIE FELDER MUESSEN AUCH ZU SEHEN SEIN
diff --git a/server/pruef-zuteilung.mjs b/server/pruef-zuteilung.mjs
index 0f97748b..00ce4396 100644
--- a/server/pruef-zuteilung.mjs
+++ b/server/pruef-zuteilung.mjs
@@ -359,15 +359,21 @@ melde("\n=== Eine einzelne Person ===");
===================================================================== */
melde("\n=== Grenzen beim Verteilen ===");
{
+ /* EIN MODI LEGT GAR NICHTS MEHR AN (22.09.2026).
+ ------------------------------------------------------------------
+ Hier stand bis heute: "Anna darf sich selbst etwas notieren" --
+ ihre Zuteilung an Bea wurde stillschweigend auf sie selbst
+ umgebogen. Filipe hat das umgedreht: "sie sich nicht selber
+ aufgaben geben."
+
+ 403 ist hier die ehrlichere Antwort als ein stilles Umbiegen: Wer
+ etwas versucht, das nicht vorgesehen ist, soll es erfahren -- und
+ nicht ein Ergebnis bekommen, das er nicht gemeint hat. */
const a = await rufe("/workspace/api/aufgaben", { method: "POST", keks: anna,
body: { titel: "Bea soll das machen", zuteilung: [idBea] } });
- ok(a.code === 201, `Anna darf sich selbst etwas notieren (HTTP ${a.code})`);
- const beiBea = await aufgabeBei(bea, a.json?.id);
- ok(!beiBea?.meine_zuteilung,
- "aber Bea bekommt nichts davon zugeteilt");
- const beiAnna = await aufgabeBei(anna, a.json?.id);
- ok(beiAnna?.verantwortlich_name === "Anna",
- `die Aufgabe liegt bei Anna selbst (${beiAnna?.verantwortlich_name})`);
+ ok(a.code === 403, `ein Modi legt gar keine Aufgabe an (HTTP ${a.code})`);
+ ok(a.json?.fehler === "nur_leitung_legt_an",
+ `und bekommt einen Grund, der einen Satz hat (${a.json?.fehler})`);
}
diff --git a/server/workspace-aufgaben.js b/server/workspace-aufgaben.js
index baaa906d..5c68ee4a 100644
--- a/server/workspace-aufgaben.js
+++ b/server/workspace-aufgaben.js
@@ -10,7 +10,7 @@
import express from "express";
import {
- db, protokolliere, echteIp, sitzungLesen, betreutWo, istLeitung, darfAufgabenVerteilen, ohneDogFather, heuteLokal, ROLLEN_SORTIERUNG, ROLLEN_GRUPPE, betreuteIds,
+ db, protokolliere, echteIp, sitzungLesen, betreutWo, istLeitung, darfAufgabenVerteilen, darfAufgabenAnlegen, ohneDogFather, heuteLokal, ROLLEN_SORTIERUNG, ROLLEN_GRUPPE, betreuteIds,
externPruefen, externSql, sichtbarePersonenIds, sichtbareCreatorIds,
MODI_KATEGORIEN, kategorienFuer, kategoriePersonen,
KANAELE, kanaeleFuer,
@@ -209,10 +209,32 @@ function sichtbarRoh(person) {
`case` ohne `break` faellt in den naechsten -- genau das ist hier
gewollt und der kuerzeste ehrliche Weg, "diese beiden gleich" zu
sagen. */
+ /* =================================================================
+ EIN MODI SIEHT NUR SEINE EIGENEN (22.09.2026) -- und das dreht
+ die Entscheidung vom 09.09. ausdruecklich um.
+
+ Filipe, mehrfach und zuletzt unmissverstaendlich: "die modis
+ sollen immer nur ihre aufgaben auch sehen und nicht die von
+ anderen, so wie bei den daten ... damit wir endlich den modis
+ aufgaben anstaendig verteilen koennen und sie sich nicht selber
+ aufgaben geben."
+
+ Am 09.09. hatte er das Gegenteil entschieden ("ja, sie sind
+ untereinander ein team"), damit ein Schichttausch ohne Umweg
+ geht. Diese Zeile haelt beides fest, damit niemand spaeter die
+ aeltere Entscheidung findet und sie fuer die gueltige haelt: Die
+ neuere gilt.
+
+ WAS BLEIBT: Was ihm ueber `aufgaben_zuteilung` gegeben wurde,
+ sieht er weiterhin -- das haengt `mitZugeteilten()` an diese
+ Bedingung an. Ein Pool, in dem er steht, bleibt also sichtbar,
+ bis ihn jemand uebernimmt. */
+ case "modi":
+ return { wo: "a.verantwortlich_id = ?", werte: [person.id] };
+
case "hand":
/* Die linke Hand sieht dasselbe wie die rechte (21.09.2026). */
- case "linke":
- case "modi": {
+ case "linke": {
const liste = [...TEAM_DOGI_ROLLEN].map((r) => `'${r}'`).join(", ");
const modis = db().prepare(
`SELECT id FROM personen WHERE rolle IN (${liste})`).all().map((z) => z.id);
@@ -777,6 +799,13 @@ aufgabenRouter.delete("/workspace/api/notizen/:id", gleicheHerkunft, (req, res)
aufgabenRouter.post("/workspace/api/aufgaben", gleicheHerkunft, (req, res) => {
try {
+ /* IM TEAM DOGI LEGT NUR DIE LEITUNG AN (22.09.2026). Ein Modi
+ bekommt Aufgaben; er gibt sich keine. Die Schranke steht VOR der
+ Feldpruefung, damit die Antwort nicht erst ueber Feldfehler
+ redet, wenn der Weg ohnehin zu ist. */
+ if (!darfAufgabenAnlegen(req.person)) {
+ return res.status(403).json({ fehler: "nur_leitung_legt_an" });
+ }
const { aus, fehler } = pruefeFelder(req.body || {}, { neu: true, person: req.person });
if (fehler.length) return res.status(400).json({ fehler: fehler.join(" ") });
diff --git a/server/workspace.js b/server/workspace.js
index c9aec03b..bad63857 100644
--- a/server/workspace.js
+++ b/server/workspace.js
@@ -269,6 +269,23 @@ export const istDogFather = (person) => !!person && person.rolle === "admin";
spicy und manager bleiben drin: Auf der Agenturseite verteilen sie
seit jeher Aufgaben, und daran soll sich nichts aendern. */
+/** Wer eine Aufgabe ANLEGEN darf.
+ *
+ * IM TEAM DOGI KOMMEN AUFGABEN VON DER LEITUNG (22.09.2026). Filipe:
+ * "sie sich nicht selber aufgaben geben" und "die modis sollen nur
+ * diese aufgaben wo sie von den drauf markiert werden annehmen
+ * koennen".
+ *
+ * Das gilt AUSDRUECKLICH NUR im Team Dogi. In der Agentur legt
+ * weiterhin jeder fuer sich selbst an -- dort ist eine Aufgabe eine
+ * Notiz an sich selbst, kein Auftrag von jemandem. Eine Regel, die
+ * beide Haeuser ueber einen Kamm schert, waere hier falsch. */
+export const darfAufgabenAnlegen = (person) => {
+ if (!person) return false;
+ if (TEAM_DOGI_ROLLEN.has(person.rolle)) return darfAufgabenVerteilen(person);
+ return true;
+};
+
export const darfAufgabenVerteilen = (person) =>
istLeitung(person) || istHand(person);
@@ -1469,12 +1486,50 @@ const MEINE_ENTWICKLUNG_KACHEL = {
name: "Deine Entwicklung", unter: "Was sich bei dir bewegt hat – ohne Note",
};
+/* DER MODI BEKOMMT DENSELBEN BEREICH WIE DIE LEITUNG (22.09.2026).
+
+ Filipe zum Bildschirmfoto der Gruppe "Entwicklung & Nachwuchs":
+ "die modis sollen diesen bereich und diese zwei kacheln auch sehen,
+ die sollen aber nur ihre aufgaben und daten sehen."
+
+ DIESELBEN ZWEI KACHELN, NICHT EIGENE MIT ANDEREM NAMEN. Bis heute
+ standen hier MEINE_AUFGABEN_KACHEL und MEINE_ENTWICKLUNG_KACHEL --
+ zwei Kacheln mit denselben Zielen und anderen Namen. Zwei Namen fuer
+ dieselbe Sache ist genau der Fehler, der am 19.09. schon einmal zwei
+ Kacheln "Chat" ergeben hat: Man klickt den falschen und sucht den
+ Unterschied.
+
+ "TALENTE" BLEIBT DRAUSSEN. Dort stehen Notizen ueber Zuschauer, die
+ nichts davon wissen -- das ist etwas anderes als die eigene
+ Entwicklung. Der Riegel dafuer sitzt ohnehin in rechte.js; diese
+ Zeile sorgt nur dafuer, dass gar nicht erst eine Kachel dorthin
+ zeigt.
+
+ DASS ER DORT NUR SICH SELBST SIEHT, entscheiden die Seiten: In
+ workspace-werdegang.js steht `leitung ? alle : []`, in
+ workspace-entwicklungs-punkte.js dasselbe. Die Kachel oeffnet die
+ Seite -- was darauf steht, entscheidet der Server. */
const MODI_MIT_TREFF = [...MODI_BEREICHE, BEFINDEN_KACHEL,
- MEINE_AUFGABEN_KACHEL, MEINE_ENTWICKLUNG_KACHEL, ...TREFF_BEREICHE,
+ ENTWICKLUNG_KACHEL, WERDEGANG_KACHEL, ...TREFF_BEREICHE,
TREFF_MODERATION_KACHEL];
const HAND_MIT_TREFF = [...HAND_BEREICHE, ...TREFF_BEREICHE,
TREFF_MODERATION_KACHEL, HILFE_KACHEL];
+/* DIE LINKE HAND SIEHT "DEIN TEAM" NICHT (22.09.2026).
+
+ Filipe: "die rolle linke hand soll die kachel dein team auch nicht
+ sehen bitte danke."
+
+ ABGELEITET, NICHT NACHGEBAUT: Ihre Liste ist die der rechten Hand
+ MINUS dieser einen Kachel. Eine zweite, eigene Liste waere die, die
+ beim naechsten neuen Bereich auseinanderlaeuft -- dann haette sie
+ ihn, und die linke Hand nicht, und niemand wuesste warum.
+
+ Erkannt wird die Kachel an ihrem ZIEL, nicht an ihrem Namen: Der
+ Name ist am 17.09. schon einmal gewandert ("Eingang" -> "Dein
+ Team"), das Ziel nicht. */
+const LINKE_MIT_TREFF = HAND_MIT_TREFF.filter((k) => k.ziel !== EINGANG_KACHEL.ziel);
+
/* AUSSEN_ROLLEN kommt aus crew-adresse.js und wird hier nur
weitergereicht -- die Adressregel braucht sie zuerst, und diese Datei
importiert von dort. Eine zweite Menge waere die, die auseinanderlaeuft. */
@@ -1559,6 +1614,9 @@ const TREFF_MIT_EIGENEM = [...TREFF_BEREICHE, HILFE_KACHEL, STECKBRIEF_KACHEL_TR
export function bereicheFuer(person) {
if (person?.rolle === "modi") return MODI_MIT_TREFF;
+ /* Die linke Hand vor der allgemeinen Hand-Regel -- sonst faenge
+ `istHand()` sie ab, und der Filter darunter liefe nie. */
+ if (person?.rolle === "linke") return LINKE_MIT_TREFF;
if (istHand(person)) return HAND_MIT_TREFF;
/* DIE COMMUNITY SIEHT DEN TREFF UND SONST NICHTS (11.09.2026) --
seit dem 19.09. plus den eigenen Steckbrief. */
@@ -5616,6 +5674,9 @@ workspaceRouter.get("/workspace/api/ich", (req, res) => {
Aus DERSELBEN Funktion, die auch die Route benutzt. */
darf_verteilen: darfAufgabenVerteilen(person),
+ /* Damit die Oberflaeche den Knopf gar nicht erst anbietet -- ein
+ Knopf, der mit 403 antwortet, ist schlimmer als keiner. */
+ darf_aufgaben_anlegen: darfAufgabenAnlegen(person),
/* DIE KACHELN, WENN SIE NICHT IM BROWSER STEHEN DUERFEN.
Fuer die fuenf bekannten Rollen steht hier `null`, und die
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 71c05259..9c14d79f 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,15 +16,15 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+