Profilfotos im Chat, rechte Hand zuerst, Karten lesbar

---- SCREEN 9: DIE FOTOS -------------------------------------------

Filipe: "da soll man im chat auch die profilfotos von den leuten sehen
wenn die schon eins drin haben."

ZWEI Luecken, beide an Stellen, wo ein Feld weggeworfen wurde:

1. Die GESPRAECHSLISTE bekam kein Bild. `teilnehmerVon` liest es aus
   der Datenbank, die Detailansicht nimmt es mit -- die Zeile fuer die
   Liste warf es weg. Folge: im offenen Gespraech ein Gesicht, in der
   Liste daneben ein Buchstabe. Vom selben Menschen.

2. Eine FRISCH GESENDETE Nachricht trug kein Bild. Der Verlauf beim
   Laden schon. Folge: Wer gerade zusieht, bekommt einen Buchstaben;
   wer neu laedt, ein Gesicht -- der Unterschied haengt nur daran, wann
   man geschaut hat.

Der Buchstabe bleibt als Unterlage LIEGEN und wird nicht ersetzt: Laedt
das Bild nicht, steht dort weiterhin etwas Sinnvolles statt eines
kaputten Bildsymbols. Vier Stellen, ein Verhalten.

---- SCREEN 3: REIHENFOLGE UND AUSSEHEN ----------------------------

Filipe: "ich will dass hier wie ueberall die reihenfolge immer rechte
hand und dan erst die modis."

Die Abfrage sortierte nach `aktiv DESC, name` -- die ROLLE wurde nicht
einmal mitgelesen. Die Seite konnte gar nicht wissen, wer rechte Hand
ist; sie sortierte alphabetisch, und damit stand Diene vor Funny, weil
D vor F kommt. Jetzt mit ROLLEN_SORTIERUNG -- derselben Regel, die auch
Personenliste, Chat und Rechtetafel benutzen.

"die kiste von rechte hand soll auch noch vieeeeeel krasser und
spezieller aussehen ... der hintergrund von den kacheln soll auch viel
krasser und geiler sein und so dass man texte und so besser erkennt.
weil gerade ist es schwer lesbar."

ZUERST DAS LESEN: Der Grund fuer die schlechte Lesbarkeit war der
durchscheinende Untergrund -- die Karten lagen auf dem Buehnenbild, und
ein Foto wird stellenweise hell. Sie bekommen jetzt eine DECKENDE
Unterlage und erst darueber die Verlaeufe. Die Verlaeufe sieht man
weiterhin, nur nicht mehr das Bild dahinter.

DANN DAS BESONDERE: Die rechte Hand bekommt einen goldenen Ton, eine
deutlich hellere Kante und eine schmale Leiste an der linken Seite --
man sieht den Rang aus zwei Metern, ohne ein Wort zu lesen. KEIN
zweiter Bauplan: dieselbe Karte, dieselben Felder, nur ein Merkmal am
Element. Zwei Karten zu bauen hiesse, jede kuenftige Aenderung zweimal
zu machen.

---- EINE PRUEFUNG, DIE EINE POSITION FESTNAGELTE ------------------

`ok(leute[0]?.id === idMarina, "die Aktiven stehen oben")` wurde rot,
sobald die rechte Hand nach vorn sortierte. Richtig wurde sie dadurch
nicht: Die Aussage "die Aktiven stehen oben" hat mit Marinas Platz
nichts zu tun. Jetzt prueft sie die EIGENSCHAFT (keine Pause vor einer
Aktiven) -- eine Pruefung, die eine Position festnagelt, verbietet jede
Umsortierung, auch die gewollte.

GEPRUEFT: pruef-team-stufen 28/0 (zwei Aussagen mehr),
pruef-erwaehnung 69/0 (zwei mehr: das Bild kommt in der Liste an, und
wer keines hat, bekommt auch keines vorgegaukelt), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-20 19:07:06 +02:00
co-authored by Claude Opus 5
parent c59517cb23
commit 586eb51504
44 changed files with 742 additions and 510 deletions
+30
View File
@@ -242,6 +242,36 @@ ok(Number.isInteger(raumId), `eine Gruppe mit drei Leuten steht (Raum ${raumId})
`die Raumliste bringt die Teilnehmer schon mit (${r?.teilnehmer?.length})`);
ok(r?.teilnehmer?.every((t) => t.id && t.name),
" mit Nummer und Namen — mehr braucht die Auswahl nicht");
/* ---- UND MIT DEM PROFILBILD (20.09.2026) ---------------------------
Filipe: "da soll man im chat auch die profilfotos von den leuten
sehen wenn die schon eins drin haben."
Es fehlte in GENAU DIESER Abbildung: `teilnehmerVon` liest das Bild
aus der Datenbank, und die Zeile in der Raumliste warf es weg. Die
Detailansicht nahm es mit. Folge: im offenen Gespraech ein Gesicht,
in der Liste daneben ein Buchstabe -- vom selben Menschen.
Geprueft wird mit einem eingetragenen Dateinamen; ob die Datei
existiert, ist eine andere Frage und gehoert zum Steckbrief. Hier
geht es darum, dass der WEG ueberhaupt ankommt. */
{
const d = new DatabaseSync(process.env.WORKSPACE_DB);
d.prepare("UPDATE personen SET bild = ? WHERE id = ?").run("probe.webp", idVan);
d.close();
const l2 = json(await ruf("/workspace/api/chat/raeume", aDogi.keks));
const r2 = (l2.raeume || []).find((x) => x.id === raumId);
const van = r2?.teilnehmer?.find((t) => t.id === idVan);
ok(typeof van?.bild === "string" && van.bild.includes("probe.webp"),
`das Profilbild kommt in der Gespraechsliste an (${van?.bild})`);
const ohne = r2?.teilnehmer?.find((t) => t.id === idFunny);
ok(ohne && !ohne.bild,
"Gegenprobe: wer keines hinterlegt hat, bekommt auch keines vorgegaukelt");
const d2 = new DatabaseSync(process.env.WORKSPACE_DB);
d2.prepare("UPDATE personen SET bild = NULL WHERE id = ?").run(idVan);
d2.close();
}
}
/* Jetzt die eigentliche Nachricht. */
+27 -2
View File
@@ -143,8 +143,33 @@ ok(!!marina && !!kim, "beide sind namentlich wiederzufinden");
ok(marina?.aktiv === true && kim?.aktiv === false,
`Status stimmt (Marina aktiv: ${marina?.aktiv}, Kim aktiv: ${kim?.aktiv})`);
/* AKTIVE ZUERST -- wer pausiert ist, steht unten und nicht mittendrin. */
ok(leute[0]?.id === idMarina, "die Aktiven stehen oben");
/* AKTIVE ZUERST -- wer pausiert ist, steht unten und nicht mittendrin.
GEPRUEFT WIRD DIE EIGENSCHAFT, NICHT DIE POSITION (berichtigt
20.09.2026). Hier stand `leute[0]?.id === idMarina` -- und das wurde
rot, sobald die rechte Hand nach vorn sortiert wurde. Richtig wurde
es dadurch nicht: Die Aussage "die Aktiven stehen oben" hat mit
Marinas Platz nichts zu tun. Eine Pruefung, die eine Position
festnagelt, verbietet jede Umsortierung -- auch die gewollte. */
const letzteAktive = leute.map((m) => m.aktiv).lastIndexOf(true);
const ersteInPause = leute.map((m) => m.aktiv).indexOf(false);
ok(ersteInPause === -1 || letzteAktive < ersteInPause,
`die Aktiven stehen oben (letzte aktive Stelle ${letzteAktive}, erste Pause ${ersteInPause})`);
/* ==== UND DIE RECHTE HAND VOR DEN MODIS (20.09.2026) ================
Filipe: "ich will dass hier wie ueberall die reihenfolge immer
rechte hand und dan erst die modis."
Vorher sortierte die Abfrage nur nach Namen -- die Rolle wurde nicht
einmal mitgelesen. Damit stand die Reihenfolge im Alphabet, und das
ist keine. */
const platzHand = leute.findIndex((m) => m.id === idHand);
const ersterModi = leute.findIndex((m) => m.id !== idHand && m.aktiv);
ok(platzHand >= 0 && (ersterModi === -1 || platzHand < ersterModi),
`die rechte Hand steht vor den Modis (Platz ${platzHand} vor ${ersterModi})`);
ok(leute.every((m) => typeof m.rolle === "string" && m.rolle),
"und jede Karte weiss, welche Rolle sie hat — sonst kann die Seite sie nicht unterscheiden");
ok(typeof marina?.seit === "string" && marina.seit.startsWith(vor40Tagen.slice(0, 10)),
`"dabei seit" kommt mit (${(marina?.seit || "").slice(0, 10)})`);
+33 -1
View File
@@ -160,6 +160,20 @@ function istDrin(raumId, person) {
wurde damit zu Programmtext, und die Datei liess sich nicht mehr
lesen. Ein Kommentar, der die Zeichenkette schliesst, in der er
steht. */
/** Der Weg zum Profilbild dieser Person -- oder null.
*
* ALS EIGENE FUNKTION, weil die Zeile
* `bild ? "/workspace/api/steckbrief/bild/" + bild : null`
* sonst an drei Stellen steht. Die dritte Abschrift ist die, die
* den Pfad falsch schreibt, und ein kaputter Bildpfad sieht aus wie
* "die Person hat halt kein Bild". */
function bildWegFuer(personId) {
try {
const z = db().prepare("SELECT bild FROM personen WHERE id = ?").get(personId);
return z?.bild ? `/workspace/api/steckbrief/bild/${z.bild}` : null;
} catch { return null; }
}
function teilnehmerVon(raumId) {
return db().prepare(`
SELECT t.person_id AS id, p.name, p.rolle, p.bild, t.leitung, t.gelesen_bis
@@ -545,7 +559,18 @@ chatRouter.get("/workspace/api/chat/raeume", (req, res) => {
Stellen steht; genau daran ist es beim ersten Anlauf
gescheitert. */
darf_aufloesen: darfAufloesen(r, req.person),
teilnehmer: leute.map((t) => ({ id: t.id, name: t.name, rolle: t.rolle })),
/* DAS BILD GEHOERT DAZU (20.09.2026).
Filipe: "da soll man im chat auch die profilfotos von den
leuten sehen wenn die schon eins drin haben."
Es fehlte genau hier: `teilnehmerVon` liest das Bild aus der
Datenbank, und diese Zeile warf es weg. Die Detailansicht
weiter unten nimmt es mit -- die LISTE nicht. Deshalb stand
im offenen Gespraech ein Gesicht und in der Liste daneben ein
Buchstabe, vom selben Menschen. */
teilnehmer: leute.map((t) => ({ id: t.id, name: t.name, rolle: t.rolle,
bild: t.bild })),
letzte: letzte ? {
/* Ein Anhang ohne Begleittext hätte hier eine leere Zeile
hinterlassen. "Foto"/"PDF" ist die Vorschau, die man in
@@ -1061,6 +1086,13 @@ chatRouter.post("/workspace/api/chat/raeume/:id/nachrichten", gleicheHerkunft,
const nachricht = {
id, raum_id: raumId, von_id: req.person.id, von: req.person.name,
/* DAS BILD MUSS MIT (20.09.2026). Der Verlauf beim Laden bringt
`von_bild` mit -- diese Nachricht hier nicht, und sie ist die,
die per Ereignisstrom bei allen anderen ankommt. Folge: Wer
gerade zusieht, bekommt einen Buchstaben; wer die Seite neu
laedt, ein Gesicht. Derselbe Mensch, zwei Darstellungen, und
der Unterschied haengt nur daran, wann man geschaut hat. */
von_bild: bildWegFuer(req.person.id),
rolle: req.person.rolle, text, erstellt: n, zurueckgenommen: false,
antwort: zitat ? {
id: antwortAuf, von: zitat.von || "Gelöscht",
+22 -2
View File
@@ -34,6 +34,7 @@
import express from "express";
import {
db, sitzungLesen, istDogFather, fuehrtTeamDogi, heuteLokal, protokolliere, echteIp,
ROLLEN_SORTIERUNG,
} from "./workspace.js";
import { MODI_PUNKTE } from "./workspace-modi-punkte.js";
import { checklistenTabellen } from "./workspace-checkliste.js";
@@ -171,10 +172,24 @@ teamlageRouter.get("/workspace/api/teamlage", (req, res) => {
verhindern soll. Der Riegel eine Zeile hoeher (`darfEingang`)
bleibt beim Angemeldeten: Das ist ein Recht, keine Anzeige. */
const zeigt = req.sicht || person;
/* ==== DIE RECHTE HAND STEHT ZUERST (20.09.2026) ==============
Filipe: "ich will dass hier wie ueberall die reihenfolge immer
rechte hand und dan erst die modis."
Hier stand `ORDER BY aktiv DESC, name` -- die Rolle wurde nicht
einmal MITGELESEN. Die Seite konnte also gar nicht wissen, wer
rechte Hand ist und wer Modi; sie sortierte alphabetisch, und
damit stand Diene vor Funny, weil D vor F kommt.
Sortiert wird jetzt mit ROLLEN_SORTIERUNG -- derselben Regel, die
auch die Personenliste, der Chat und die Rechtetafel benutzen.
Eine eigene Reihenfolge hier waere die zweite Wahrheit, und die
zweite ist die, die beim naechsten Rollenwechsel abweicht. */
const modis = db().prepare(
`SELECT id, name, bild, letzter_login, aktiv, erstellt, stufe FROM personen
`SELECT id, name, rolle, bild, letzter_login, aktiv, erstellt, stufe FROM personen
WHERE rolle IN ('hand','modi') AND id <> ?
ORDER BY aktiv DESC, name`).all(zeigt.id);
ORDER BY aktiv DESC, ` + ROLLEN_SORTIERUNG + `, name`).all(zeigt.id);
if (!modis.length) {
/* `eingang` auch hier -- die Oberflaeche darf nicht raten
@@ -374,6 +389,11 @@ teamlageRouter.get("/workspace/api/teamlage", (req, res) => {
return {
id: m.id,
name: m.name,
/* DIE ROLLE GEHT MIT (20.09.2026). Ohne sie kann die Seite
die rechte Hand nicht von einem Modi unterscheiden -- und
genau das soll sie: andere Reihenfolge, anderes Aussehen.
Sie stand bisher nicht einmal in der Abfrage. */
rolle: m.rolle,
bild: m.bild ? `/workspace/api/steckbrief/bild/${m.bild}` : null,
letzter_login: m.letzter_login,
/* Die drei Felder aus Kapitel 4: Status, "dabei seit", Stufe. */