Files
dogfather-universe/server/workspace-teamlage.js
T
DogFatherGitandClaude Opus 5 6122ea6972 Eigene Checklisten fuer die Modis -- und eine Seite fuer euch beide
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]>
2026-09-10 03:10:04 +02:00

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" });
}
});