Wunsch Filipe (10.09.2026): *"diese kategorien mussen auf dieser seite auch noch auf die modis perfektionniert werden, da mussen lauter sachen sein die vanvan und ich danach verteilen können und da anpassen können ob gut oder nicht."* Und: *"da soll es eine kategorie geben für uns beide nur sonst keinen wo wir dass alles sehen und behandeln können."* === TEIL 1: SEIN EIGENER PUNKTESATZ === 101 Punkte in workspace-modi-punkte.js -- Live-Ablauf 40, Community 36, Technik 25. Die vorhandenen sagen "Upload messen", "Sendeplan festlegen", "Verweildauer vergleichen": Ein Modi sendet nicht, er moderiert. Ihm dieselbe Liste vorzulegen hiesse, ihn an Dingen zu messen, die nicht seine Arbeit sind. DIESELBE EINTEILUNG (Vor/Waehrend/Nach usw.), nur andere Punkte darin. Zwei verschiedene Einteilungen waeren zwei Dinge zum Lernen statt einem, und die Oberflaeche kaeme ohne Umbau nicht damit zurecht. DIE SCHLUESSEL BEGINNEN MIT "m-". Der Stand haengt an (bereich, schluessel, person) -- ohne Praefix koennte ein Modi-Punkt eines Tages denselben Namen tragen wie ein Creator-Punkt und dessen Bewertung erben. BEIDE SAETZE STEHEN IN GUELTIG. Stuenden dort nur die Creator-Punkte, kaeme die Liste an und jeder Klick darauf brachte einen 404 -- die Sorte Fehler, die man erst beim Benutzen merkt. Ein Modi sieht SEINE Liste, ohne jemanden auszuwaehlen (wie ein Creator), und bewertet sich nicht selbst. Ohne diese Zeile waere er in den Betreuer-Zweig gefallen, haette eine Auswahl fremder Creator vorgesetzt bekommen und seine eigene Liste gar nicht gesehen. DER HEIKELSTE PUNKT WAR EIN ANDERER: `darfCreator` sagt bei siehtAlles() pauschal ja -- und darin steckt auch Spicy Media. Wer die Modi-Auswahl daran haengt, oeffnet sie ihr nebenbei mit, ohne dass an der Stelle etwas davon steht. Deshalb eine eigene Regel (darfPerson), und die Pruefung versucht es ueber die Liste, ueber die Adresse UND ueber das Bewerten. Die Auswahl heisst bei der DogFather-Rolle jetzt "Person" statt "Creator" -- ein Feld namens "Creator", in dem ein Modi steht, ist falsch beschriftet. Das Wort kommt vom Server; ein Rollenvergleich im Browser waere die Stelle, an der der Name in einer ausgelieferten Datei landet. === TEIL 2: DIE GEMEINSAME SEITE === teamlage.html, nur fuer die DogFather-Rolle -- also Filipe und VanVan. Fuer alle anderen gibt es weder die Kachel noch die Seite noch die Schnittstelle (404, wie bei einer Adresse, die es nicht gibt). Zwei Schloesser, absichtlich: die Schranke und die Abfrage. Faellt eines weg, haelt das andere. Je Person: offene und ueberfaellige Aufgaben, beigetragene Ideen, Rueckmeldungen, und je Bereich gut/verbessern/offen. Jede Zeile fuehrt in den Bereich -- MIT DER PERSON VORAUSGEWAEHLT. Dafuer liest die Checkliste jetzt `creator_id` aus der Adresse; ohne das landet man auf der erstbesten Person und weiss beim zweiten Suchen nicht mehr, warum man hier war. SIE ZAEHLT, SIE BEWERTET NICHT. Bewertet wird dort, wo die Punkte stehen. Eine zweite Stelle dafuer waere eine zweite Stelle, an der es auseinanderlaeuft. UND SIE IST KEINE UEBERWACHUNG. Ueber team.html steht schon, dass eine Seite mit Zahlen ueber Kollegen als Kontrolle gelesen wird -- und dann arbeitet niemand mehr offen damit. "Offen" heisst hier deshalb ausdruecklich: darueber habt ihr noch nicht geredet. Eine Merkliste fuer euch beide, keine Note. ALLES IN VIER ABFRAGEN, nicht vier je Person -- bei zehn Modis waeren das vierzig. Denselben Fehler hat das Haus bei den Terminen schon gemacht und ihn dort vermerkt. KEINE NEUEN CSS-KLASSEN: Fuer genau diese Karten gibt es sie schon (tperson, tz, schritt -- aus team.html). Elf neue haetten gepflegt werden muessen fuer ein Aussehen, das bereits da ist. ZUSATZKACHELN sind ein neuer, kleiner Mechanismus: `bereiche` ERSETZT die Liste im Browser (fuer Rollen, die dort nicht vorkommen), `bereiche_zusatz` HAENGT an. Gebraucht fuer Kacheln, die nur eine einzige Rolle bekommt -- in bereiche.js duerften sie nicht stehen, weil eine Kachel, die nur bei einem erscheint, die Frage aufwirft, fuer wen sie ist. Findet sich die genannte Gruppe nicht, wird eine eigene angelegt: Sonst faellt die Kachel lautlos weg, sobald jemand eine Gruppe umbenennt. EHRLICH ZUM UMFANG: Technik ist mit 25 Punkten der duennste Bereich. Das ist Absicht -- der technische Spielraum eines Moderators ist kleiner als der eines Streamers. Auffuellen haette Fuellmaterial in eine Liste gebracht, die Filipe und VanVan durchgehen muessen. GEPRUEFT: pruef-modi-checkliste (39, neu), pruef-rollen (244 statt 243 -- die neue Kachel wird angeklickt und muss ankommen), pruef-modi-verborgen (75), pruef-workspace-seiten. Co-Authored-By: Claude Opus 5 <[email protected]>
128 lines
5.3 KiB
JavaScript
128 lines
5.3 KiB
JavaScript
/* =====================================================================
|
|
DIE LAGE DES MODI-TEAMS -- an einer Stelle (10.09.2026)
|
|
|
|
Wunsch Filipe: *"dan will ich auch dass vanvan und ich diese sachen
|
|
von den modis auch in der dogfather rolle sehen. da soll es eine
|
|
kategorie geben für uns beide nur sonst keinen wo wir dass alles
|
|
sehen und behandeln können. so wie mit dem ideen-board."*
|
|
|
|
NUR DIE DOGFATHER-ROLLE. Das sind Filipe und VanVan -- sie tragen
|
|
beide `admin`. Fuer alle anderen gibt es diese Seite nicht: 404 wie
|
|
bei einer Adresse, die niemand kennt. Ein "kein Zugriff" waere die
|
|
Auskunft, dass es sie gibt.
|
|
|
|
SEHEN UND BEHANDELN, in dieser Reihenfolge: Die Seite zaehlt nur --
|
|
bewertet wird dort, wo die Punkte stehen. Jede Zahl ist deshalb ein
|
|
Verweis in den jeweiligen Bereich, mit der Person schon
|
|
vorausgewaehlt. Eine zweite Stelle zum Bewerten waere eine zweite
|
|
Stelle, an der es auseinanderlaeuft.
|
|
|
|
UND SIE IST KEINE UEBERWACHUNG. Dieselbe Ueberlegung steht schon
|
|
ueber team.html: Eine Seite mit Zahlen ueber Kollegen wird als
|
|
Kontrolle gelesen, und dann arbeitet niemand mehr offen damit.
|
|
Deshalb zaehlt sie, was NOCH NICHT BESPROCHEN ist -- nicht, wer wie
|
|
fleissig war. "Offen" heisst hier: Darueber habt ihr noch nicht
|
|
geredet. Es ist eine Liste fuer euch, keine Note fuer ihn.
|
|
===================================================================== */
|
|
import express from "express";
|
|
import {
|
|
db, sitzungLesen, istDogFather, heuteLokal,
|
|
} from "./workspace.js";
|
|
import { MODI_PUNKTE } from "./workspace-modi-punkte.js";
|
|
|
|
export const teamlageRouter = express.Router();
|
|
|
|
/* Wie viele Punkte es je Bereich ueberhaupt gibt. Einmal gerechnet --
|
|
die Saetze aendern sich nicht zur Laufzeit. */
|
|
const GESAMT = Object.fromEntries(
|
|
Object.entries(MODI_PUNKTE).map(([b, g]) => [b, Object.values(g).flat().length]));
|
|
|
|
teamlageRouter.get("/workspace/api/teamlage", (req, res) => {
|
|
try {
|
|
const person = sitzungLesen(req);
|
|
if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" });
|
|
/* 404 und nicht 403 -- siehe Kopf. */
|
|
if (!istDogFather(person)) return res.status(404).json({ fehler: "nicht_gefunden" });
|
|
|
|
const modis = db().prepare(
|
|
`SELECT id, name, bild, letzter_login FROM personen
|
|
WHERE rolle = 'modi' AND aktiv = 1 ORDER BY name`).all();
|
|
|
|
if (!modis.length) {
|
|
return res.json({ modis: [], bereiche: GESAMT, heute: heuteLokal() });
|
|
}
|
|
const platz = modis.map(() => "?").join(",");
|
|
const nummern = modis.map((m) => m.id);
|
|
const heute = heuteLokal();
|
|
|
|
/* ALLES IN VIER ABFRAGEN, nicht vier je Person. Bei zehn Modis
|
|
waeren das vierzig -- den Fehler hat das Haus bei den Terminen
|
|
schon einmal gemacht und ihn dort ausdruecklich vermerkt. */
|
|
const stand = new Map(); // person -> bereich -> {gut, verbessern}
|
|
for (const z of db().prepare(
|
|
`SELECT creator_id, bereich, stufe, COUNT(*) AS n FROM punkt_stand
|
|
WHERE creator_id IN (${platz}) GROUP BY creator_id, bereich, stufe`).all(...nummern)) {
|
|
if (!stand.has(z.creator_id)) stand.set(z.creator_id, {});
|
|
const b = stand.get(z.creator_id);
|
|
b[z.bereich] = b[z.bereich] || { gut: 0, verbessern: 0 };
|
|
if (z.stufe === "gut" || z.stufe === "verbessern") b[z.bereich][z.stufe] = z.n;
|
|
}
|
|
|
|
const aufgaben = new Map();
|
|
for (const z of db().prepare(
|
|
`SELECT verantwortlich_id AS p,
|
|
COUNT(*) AS offen,
|
|
SUM(CASE WHEN frist IS NOT NULL AND frist < ? THEN 1 ELSE 0 END) AS ueberfaellig
|
|
FROM aufgaben
|
|
WHERE verantwortlich_id IN (${platz})
|
|
AND status NOT IN ('erledigt', 'abgebrochen')
|
|
GROUP BY verantwortlich_id`).all(heute, ...nummern)) {
|
|
aufgaben.set(z.p, { offen: z.offen, ueberfaellig: z.ueberfaellig || 0 });
|
|
}
|
|
|
|
const ideen = new Map();
|
|
for (const z of db().prepare(
|
|
`SELECT erstellt_von AS p, COUNT(*) AS n FROM eintraege
|
|
WHERE bereich = 'ideen' AND erstellt_von IN (${platz}) GROUP BY erstellt_von`)
|
|
.all(...nummern)) {
|
|
ideen.set(z.p, z.n);
|
|
}
|
|
|
|
/* Wie viele Rueckmeldungen an seinen Punkten haengen -- das ist
|
|
das Gespraech, nicht die Note. */
|
|
const nachrichten = new Map();
|
|
for (const z of db().prepare(
|
|
`SELECT creator_id AS p, COUNT(*) AS n FROM punkt_nachricht
|
|
WHERE creator_id IN (${platz}) GROUP BY creator_id`).all(...nummern)) {
|
|
nachrichten.set(z.p, z.n);
|
|
}
|
|
|
|
res.json({
|
|
heute,
|
|
bereiche: GESAMT,
|
|
modis: modis.map((m) => {
|
|
const s = stand.get(m.id) || {};
|
|
const je = {};
|
|
for (const [b, gesamt] of Object.entries(GESAMT)) {
|
|
const gut = s[b]?.gut || 0;
|
|
const verbessern = s[b]?.verbessern || 0;
|
|
je[b] = { gesamt, gut, verbessern, offen: Math.max(gesamt - gut - verbessern, 0) };
|
|
}
|
|
return {
|
|
id: m.id,
|
|
name: m.name,
|
|
bild: m.bild ? `/workspace/api/steckbrief/bild/${m.bild}` : null,
|
|
letzter_login: m.letzter_login,
|
|
aufgaben: aufgaben.get(m.id) || { offen: 0, ueberfaellig: 0 },
|
|
ideen: ideen.get(m.id) || 0,
|
|
nachrichten: nachrichten.get(m.id) || 0,
|
|
bereiche: je,
|
|
};
|
|
}),
|
|
});
|
|
} catch (fehler) {
|
|
console.error("[workspace] Team-Lage:", fehler?.message);
|
|
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
|
}
|
|
});
|