937 Commits
Author SHA1 Message Date
DogFatherGitandClaude Opus 5 c5e3ab1c44 Zwei Meldungen aus dem Support: Auswahlmenues und die Stelle im Chat
DIENE: "Beim Kalender laesst sich die Art noch nicht einstellen, das
Menue ploppt nur ganz kurz auf und verschwindet direkt wieder. Das
selbe bei den Wiederholungen."

In wahl.js stand `addEventListener('resize', schliessen)`. Auf dem
Rechner ist das harmlos -- dort aendert sich die Fenstergroesse nur,
wenn jemand sie aendert. Auf einem Handy aendert sie sich BEIM
BEDIENEN: Die Adressleiste faehrt beim kleinsten Scrollen ein und
aus, die Tastatur kommt und geht, und jedes Mal feuert `resize`. Die
Liste ging auf, der Browser meldete eine neue Hoehe, und sie war
wieder zu.

Es ist derselbe Fehler wie am 04.09. beim Scrollen ("wenn ich da
scollen will geht das immer zu"), nur eine Zeile tiefer: Ein
Ereignis, das beim BEDIENEN entsteht, wird als Grund zum Abbrechen
genommen. Jetzt wird die Liste neu ausgerichtet statt geschlossen --
`stelle()` kann das ohnehin, und nach einer Groessenaenderung muss
sie es sowieso.

pruef-suchfeld 8 -> 15, an Dienes genauem Fall: Kalenderformular,
beide Felder, echte Groessenaenderung dazwischen. Gemessen wird nicht
nur "offen", sondern auch "sitzt noch am Knopf" (6 px) -- offen, aber
verrutscht waere nur die halbe Antwort. Gegenprobe: mit der alten
Zeile 4 Fehler.

----------------------------------------------------------------------

MISS: "Wenn ich auf den Chat gehen, komme ich zuerst auf die erste
neue Nachricht, aber kurze Zeit spaeter springt er auf die zuletzt
geschrieben Nachricht."

In chat.js stand `unten = true; neuUnten = 0;` AUSSERHALB von
`if (!sanft)` -- es lief also bei jedem Nachladen, auch beim sanften,
das staendig passiert (Strom verbindet, jemand heftet etwas an, eine
Nachricht kommt).

Solange die Neu-Linie steht, faellt das nicht auf: Der Zweig darueber
springt dorthin und kehrt zurueck, bevor `unten` gelesen wird. Die
zweite Haelfte ist `wache` -- sie loescht den Sprung-Merker beim
ersten FINGERTIPP auf den Verlauf, und das ist richtig so. Ab da ist
der Weg frei, und das naechste sanfte Nachladen findet `unten ===
true` vor und reisst die Ansicht ans Ende. Genau ihre "kurze Zeit
spaeter".

Ein sanftes Nachladen ist kein Oeffnen. Wo jemand steht, weiss ab
jetzt allein der Scroll-Horcher -- und der misst es, statt es
anzunehmen.

DREI FEHLVERSUCHE BIS ZUR MESSUNG, und sie gehoeren ins Protokoll:
Erst sechs Sekunden Nichtstun, dann ein Fingertipp auf Koordinaten,
dann ein Verbindungsabriss -- alle drei waren mit dem ALTEN Code
gruen. Eine Pruefung, die den Fehler nicht herstellt, misst nichts,
und ich haette sie beinahe als Beweis genommen. Was fehlte: Der Griff
muss den Verlauf WIRKLICH treffen (Koordinaten gehen daneben), und es
braucht einen echten sanften Nachlauf -- hier das Anheften, das ein
`pin`-Ereignis an alle im Raum schickt.

Erst damit flippt die Gegenprobe: ohne Korrektur 500 -> 7054 px und
`amEnde: true`, mit Korrektur bleibt es bei 500.

pruef-chat-neu-stelle 62 -> 69.

Unterwegs wieder entfernt: ein Merker `schonGesprungen`, den ich
zuerst eingebaut hatte. Nach der echten Korrektur ist er
unerreichbar, und ich konnte ihn mit keiner Messung zum Greifen
bringen. Ein Zweig, den nichts erreicht, sieht beim Lesen aus wie ein
Fall, den es gibt.

Gegengemessen: pruef-chat 80, pruef-chat-optik 84, pruef-freie-namen
32 -- 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 22:41:18 +02:00
DogFatherGitandClaude Opus 5 4e67f8a6c2 Der schwarze Bildschirm: der Dialog stand ausserhalb des Fensters
Patrick ueber den Support: „Sophie kann Abschnitt 3 und 4 nicht
bestaetigen, beim druecken kommt ein schwarzer Bildschirm."

DER DIALOG WAR DIE GANZE ZEIT DA -- nur nicht im Bild. Nachgebaut auf
einer KOPIE der echten Datenbank, mit einem echten Browser, und dann
gemessen statt vermutet:

    position         absolute    statt fixed
    oben im Fenster   -143 px    also oberhalb des Sichtbaren

`module.css` setzte `.dialog { position: relative }`. Damit war die
Zentrierung des Browsers ueberschrieben: Ein Dialog aus `showModal()`
gehoert mit `position: fixed` in die Mitte des SICHTBAREN FENSTERS,
mit `relative` landet er im Dokumentfluss nahe dem SEITENANFANG. Wer
nach unten gescrollt hatte, sah nur noch den abdunkelnden Schleier --
einen schwarzen Bildschirm.

WARUM AUSGERECHNET „ABSCHNITT 3 UND 4"

Gar nicht wegen dieser beiden. Sophie hatte 1 und 2 schon bestaetigt,
dort gibt es keinen Knopf mehr -- 3 und 4 waren die einzigen, die sie
ueberhaupt noch druecken konnte, und sie stehen am weitesten unten.
Der Fehler hing nie an den Abschnitten, sondern an der Scrollhoehe.
Haette ich die Meldung woertlich genommen und in den Unterweisungen
gesucht, haette ich an der falschen Stelle gegraben.

ES BETRAF JEDEN DIALOG IM HAUS

22 Aufrufe von `showModal()` in 10 Dateien -- vom Loeschen einer Datei
ueber das Bearbeiten einer Aufgabe bis zum Eintragen eines
Monatsziels. Auf kurzen Seiten fiel es nie auf, weil dort niemand
scrollt. Keine einzige Pruefung im Haus hatte je einen Dialog
geoeffnet, NACHDEM sie gescrollt hat.

`relative` stand dort fuer die beiden Pseudo-Elemente (Leuchtschiene
und Lichtsaum) -- die brauchen einen positionierten Vorfahren, und
`fixed` ist ebenfalls einer. `inset: 0` und `margin: auto` schreiben
die Zentrierung jetzt ausdruecklich hin, statt sich auf eine Vorgabe
zu verlassen, die diese Datei selbst ueberschreibt.

WAS ICH FAST KAPUTT GEMACHT HAETTE

Mein erster Entwurf setzte zusaetzlich `max-height` und
`overflow: auto` auf den Dialog. Das waere ein Rueckschritt gewesen:
Das Rollen ist eine Ebene tiefer laengst geloest (`.dialog > form`),
gemessen am 25.09.2026 ueber vier Bildschirmgroessen, nachdem Miss
gemeldet hatte, dass sie aus einem Fenster nicht mehr herauskam. Dort
haengen auch die festen Kopf- und Fusszeilen -- und `position: sticky`
gilt immer zum naechsten rollenden Vorfahren. Ein zweiter Rollbereich
darueber haette genau die wieder geloest. Wieder entfernt;
`mess-dialog-ausgang` meldet unveraendert auf allen vier Groessen
„Kommt man heraus? JA".

NEU: pruef-dialog-sichtbar.mjs (18 Pruefungen, 0 Fehler)

Drei Ebenen, und die unterste allein waere zu wenig:

  * Im Quelltext: keine Regel darf `.dialog` wieder aus dem Fenster
    nehmen -- in ALLEN Stilvorlagen, nicht nur in module.css.
  * Am echten Bildschirm: zwei verschiedene Dialoge auf zwei
    verschiedenen Seiten, je auf Computer und Handy, jedes Mal ganz
    nach unten gescrollt (663 bis 1216 px).
  * Die Gegenprobe: Ein aus dem Fenster geschobener Dialog MUSS
    auffallen. Ohne sie waere „er steht im Bild" womoeglich eine
    Zeile, die immer wahr ist.

DREI MEINER EIGENEN MESSUNGEN WAREN ZUERST FALSCH, nicht der Code:
Die Textsuche fand Kommentare und `.dialog > *` (die Kinder DUERFEN
relativ sein); die Schulungstabellen entstehen erst beim ersten
Zugriff; und die Auswahl fuer den zweiten Dialog war seit dem
Schnell-Eintrag veraltet -- der erste Knopf oeffnet dort gar keinen
Dialog mehr. Alle drei berichtigt, bevor sie als Befund durchgingen.

NICHT VON MIR, aber beim Nachmessen aufgefallen: pruef-css-klassen
meldet 44 statt 42 Schriftgroessen unter 11,5 px (uebersicht.css,
wissen.css). Meine Aenderung fasst keine einzige Schriftgroesse an --
module.css hat vorher wie nachher denselben Wert. Der Befund ist
aelter und gehoert nicht hierher.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 19:32:53 +02:00
DogFatherGitandClaude Opus 5 25cf6a0163 Fotoposts von TikTok kommen jetzt an -- das war die Ursache
GEFUNDEN HAT ES DAS PROTOKOLL, das eine halbe Stunde vorher dazukam.
Filipes Versuche standen Minuten spaeter als `video_gescheitert`
da, mit Grund:

  highlight .../@dogfather0804/photo/7693113561568136470 -- 400
  highlight https://vm.tiktok.com/ZN8kdxP9N/             -- 400

Am echten Konto nachgemessen:

  .../photo/7693113561568136470   -> 400 "Something went wrong"
  .../video/7693113561568136470   -> 200, mit Titel
  vm.tiktok.com/ZN8kdxP9N/        -> leitet auf die /photo/-Adresse

TikToks Auskunft kennt FOTOPOSTS (Slideshows) nicht -- dieselbe
Nummer unter /video/ aber schon. Filipe postet seit kurzem solche
Beitraege. Deshalb "es ging doch immer bis jetzt": Es lag weder an
einer Auslieferung noch am Haus, sondern an der Art des Posts. Der
Server war die ganze Zeit unveraendert (ein Neustart seit 04.10.),
und genau das hat die Suche in die falsche Richtung geschickt.

Jetzt wird bei einem Fehlschlag ein zweites Mal gefragt: erst den
Kurzlink aufloesen -- er verraet von aussen nicht, was dahinter
steckt --, dann /photo/ auf /video/ drehen. Aufgeloest wird nur ueber
den Ort-Kopf (`redirect: "manual"`), die Seite selbst wird nie
geholt; sie ist ein Megabyte gross und enthaelt nichts, was wir
brauchen.

NUR BEIM FEHLSCHLAG: Ein gewoehnliches Video kostet keine einzige
zusaetzliche Anfrage. Gemessen: Video 204 ms wie bisher, Fotopost
676 ms, Kurzlink auf Fotopost 827 ms -- alle drei mit Titel und
Vorschaubild.

Gegengemessen an genau den zwei Adressen, die bei ihm gescheitert
sind: beide liefern jetzt Titel und Bild. pruef-video 74,
pruef-teilen 27 -- 0 Fehler.

WAS ICH DARAUS MITNEHME: Ich habe heute stundenlang von aussen
ausgeschlossen, was es NICHT ist -- Adresse, Haus, Sitzung,
Manifest, Service Worker, Zwischenspeicher. Beantwortet hat die
Frage am Ende eine einzige Protokollzeile. Die haette am Anfang
stehen muessen, nicht nach der halben Suche. Dieselbe Lehre wie am
06.09. im Shop, und ich habe sie heute zweimal gebraucht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 12:47:42 +02:00
DogFatherGitandClaude Opus 5 b42bbb1d88 Video einlesen: die Frist galt nur fuer den Anfang -- und kein Fehlschlag stand im Protokoll
Filipe: "ES GING DOCH IMMER BIS JETZT." Das war der nuetzlichste Satz
des Tages, denn er stimmt: Zwischen seinem letzten Erfolg (04.10.
13:44) und der Meldung wurde NICHTS ausgeliefert -- gemessen am
Server: ein einziger Neustart seit dem 04.10. 13:00, meiner von
heute 12:19. Am Haus hat sich nichts geaendert.

Ein Fehler, der ohne Aenderung anfaengt, haengt an etwas von
draussen. Und genau dafuer war die Frist zu kurz gebaut:

  holeMitFrist() gab die Antwort zurueck, sobald die KOPFZEILEN da
  waren, und raeumte im finally die Uhr weg. Was danach kam --
  a.json() fuer die Videodaten, a.arrayBuffer() fuer das
  Vorschaubild -- lief OHNE jede Frist.

Bleibt TikToks Bildserver mitten im Koerper stehen, wartet unsere
Anfrage fuer immer. Von aussen sieht das genau so aus, wie Filipe es
beschrieben hat: "der Knopf bleibt auf `wird geholt ...` stehen" --
keine Meldung, kein Eintrag, kein Protokolleintrag, weil der Vorgang
nie endet. Das Vorschaubild ist dabei kein Nebending: das letzte war
1,29 MB.

Der Koerper wird jetzt gelesen, SOLANGE die Uhr laeuft. Acht
Sekunden gelten fuer alles zusammen.

NACHGEMESSEN, nicht vermutet: oembed antwortet dem Server in 0,2 s,
das Bild laedt in 0,1 s -- heute haengt es also nicht. Der Fehler
ist trotzdem echt und erklaert genau dieses Bild; er kommt und geht
mit dem fremden Netz.

UND DER ZWEITE TEIL, der die Suche so teuer gemacht hat: Im
Protokoll stand nur der ERFOLG (video_eingelesen). Blieb TikTok eine
Antwort schuldig, gab es hinterher nichts zum Nachsehen -- auf die
Frage "ist der Versuch ueberhaupt angekommen?" liess sich nichts
sagen. Dieselbe Reihenfolge wie am 06.09. im Shop ("erst fragen, OB
gesendet wurde") und wie heute frueh beim Push.

Jetzt steht jeder Fehlschlag als `video_gescheitert` im Protokoll,
mit Grund: keine TikTok-Adresse, TikTok antwortet nicht, oder
Abbruch mit Meldung.

Gegengemessen: mess-teilen weiterhin 201 mit Eintrag und
Vorschaubild, pruef-video 74, pruef-teilen 27, pruef-kanalzeile 14 --
alle 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 12:39:49 +02:00
DogFatherGitandClaude Opus 5 48689e28ac Teilen-Seite kann nicht mehr stumm haengen bleiben
Filipe: "ich lade video hoch und es erscheint immer noch nicht" --
auf Nachfrage: die Seite bleibt haengen, es kommt KEINE Meldung.

WAS GEMESSEN WURDE, bevor etwas angefasst wurde:

  Server zwischen 08:41 und der Meldung   unveraendert, ein Neustart
  Seine Sitzungen                          gueltig, Android-App
  TikTok-Abruf vom Server                  200, auch fuer Kurzlinks
  Seite, Skript, alle 14 Elemente          live auf beiden Adressen
  Service Worker                           speichert nichts zwischen
  Manifeste (beide)                        gueltig, share_target da
  Protokoll heute                          kein video_eingelesen
  Teilen-Weg nachgespielt (mess-teilen)    201, Eintrag, Erfolgssatz

Aus den Caddy-Protokollen ausserdem: Die Handy-Apps laufen auf crew.
(85 Android, 18 iPhone), auf der Agenturadresse fast nur Windows.
Der Riegel von heute Mittag trifft ihn also nicht.

DIE URSACHE IST DAMIT NICHT GEFUNDEN -- aber ein eigener Mangel
schon, und der ist der Grund, warum die Suche so lange gedauert hat:
`los()` baut die Seite auf und macht dabei keine einzige Netzanfrage.
Es kann also nur stolpern, nicht warten. Und wenn es stolpert, wird
`ladezeile.hidden = true` nie erreicht -- die Seite steht fuer immer
auf "wird geladen". Kein Fehler, kein Hinweis, nichts zum
Weitermelden, und von aussen nicht zu unterscheiden von "der Server
antwortet nicht".

Eine Seite, die nicht sagen kann, dass sie kaputt ist, kostet jeden
Fehler doppelt: einmal den Fehler und einmal die Suche danach.

Jetzt nennt sie den Grund im Klartext, oeffnet das Feld zum
Einfuegen von Hand und haengt den Knopf daran -- eine Meldung ohne
Ausweg waere nur ein Trost. Beim naechsten Versuch steht also da,
woran es liegt.

GEGENPROBE GEFAHREN, und sie hat zuerst mich korrigiert: Der erste
Versuch tauschte die Kennung im HTML unterwegs aus und kam nie an --
die Seite lud normal, der Browser meldete nichts, und die Messung
schloss daraus "die Sicherung greift nicht". Eine Gegenprobe, die
ihren eigenen Schaden nicht anrichtet, misst gar nichts. Jetzt wird
`document.getElementById` vor jedem Skript ersetzt, genau das, was
`$` benutzt. Ergebnis: Ladezeile weg, Meldung "Probe: Element fehlt",
Einfuegefeld offen.

mess-teilen.mjs neu: spielt den Teilen-Weg einmal heil und einmal
zerstoert durch.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 12:34:51 +02:00
DogFatherGitandClaude Opus 5 adb265e603 Highlights: auf der Agenturadresse gibt es die Rudel-Bretter nicht mehr
Filipe, dringend: "ich kann gerade bei highlights keine videos
hochladen."

DAS HOCHLADEN WAR NICHT KAPUTT. Gemessen an der laufenden Datenbank:
49 Highlights, ALLE mit haus = crew -- so legt hausFuerNeuenEintrag
sie an, ausdruecklich "egal, von welcher Adresse aus jemand
hineinschreibt". Der Adressriegel vom 03.10. zeigt auf der
Agenturadresse aber nur haus = agentur:

    crew.     -> 49 Highlights
    workspace -> 0

Das Brett stand dort leer, und ein eingefuegtes Video verschwand in
derselben Sekunde: angelegt und sofort ausgeblendet. Von aussen sieht
das aus wie "geht nicht hoch". Beleg: Eintrag #77 wurde heute um
08:41 erfolgreich angelegt, #76 gestern von Filipe selbst.

Im Serverlog stand seit Stunden keine Fehlerzeile, und TikTok
antwortet dem Server normal (HTTP 200 in 0,2 s) -- beides geprueft,
bevor im Code gesucht wurde.

ZWEI REGELN WIDERSPRACHEN SICH, und jede fuer sich war richtig:
"diese Bretter sind immer crew" gegen "diese Adresse zeigt nur
agentur". Keine Pruefung konnte das merken, weil keine den
Zwischenraum ansah.

Aufgeloest in Filipes Richtung (Rueckfrage 05.10.): Auf der
Agenturadresse gibt es diese Bretter gar nicht -- 404 statt leerem
Brett. Das ist die Regel vom 24.09. beim Wort genommen: "auf jeder
Adresse nur deren Bestand."

EINE Regel (brettAufDieserAdresse), zwei Tore: die Middleware in
workspace-bereiche.js und die Video-Route, die NICHT an ihr haengt.
Ohne das zweite liesse sich weiterhin etwas anlegen, das danach
niemand sieht -- derselbe Zustand, nur still.

Ohne Adresse (Pruefungen, 127.0.0.1) bleibt alles offen, dieselbe
vorsichtige Richtung wie in nurDiesesHaus.

ZWEIMAL VON DER MESSUNG KORRIGIERT WORDEN:

1. Ich hatte zusaetzlich einen Kachelfilter gebaut. Er war toter
   Code: Auf der Agenturadresse liefert bereicheRoh `null` ("der
   Browser nimmt seine eigene Liste"), und in dieser stehen die
   Rudel-Bretter gar nicht -- weder in start.html noch in
   bereiche.js. Es gab nichts zu filtern. Wieder entfernt: Ein
   Filter, den nichts erreicht, sieht beim Lesen aus wie der Schutz,
   und man sucht den echten nicht mehr.

2. Meine erste Pruefzeile erwartete auf der Agenturadresse
   Serverkacheln und wurde rot -- zu Recht, ich hatte eine Liste
   vermutet, wo keine ist.

pruef-haus-trennung 100 -> 107, beide Richtungen und alle drei Wege
(Kachel, Brett, Video). Die Gegenprobe auf crew. schickt bewusst
KEINE echte TikTok-Adresse: Der Riegel sitzt vor der Adresspruefung,
also beweist 400 ebenso gut, dass er nicht gesprungen ist -- und der
Lauf geht dafuer nicht ins Netz. Mit einer echten Adresse riss der
Server beim Beenden in einen libuv-Absturz (107 Pruefungen, 1 Fehler,
Rueckgabewert 127).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-05 12:19:10 +02:00
DogFatherGitandClaude Opus 5 b625d901a5 Jeder darf seine eigene Chat-Nachricht bearbeiten
Filipe: "die nachrichten die man in den chat reinschreibt. jeder soll
seine eigene nachricht bearbeiten koennen. diese option soll jeder
fuer seine eigene nachrichten haben die er selber verfasst hat."

NUR DIE EIGENE -- OHNE AUSNAHME, auch nicht fuer DogFather und die
rechte Hand. Beim LOESCHEN gibt es diese Ausnahme seit dem 22.09.
(fuer den Notfall), und es waere naheliegend gewesen, sie
mitzunehmen. Das waere falsch: Eine fremde Nachricht zu entfernen
heisst "das soll hier nicht stehen". Eine fremde zu AENDERN heisst,
jemandem Worte in den Mund zu legen, die unter seinem Namen und
seinem Bild stehen bleiben. Nicht dieselbe Befugnis in groesser,
sondern eine andere. Genau das ist die wichtigste Pruefzeile:
DogFather darf loeschen und bekommt beim Bearbeiten 403/404.

AN DER NACHRICHT STEHT "BEARBEITET". Ein Text, der sich still
aendert, nachdem andere darauf geantwortet haben, ist ein
Vertrauensproblem und kein Komfort. Der Vermerk traegt die Zeit im
Titel. Derselbe Text setzt ihn NICHT -- sonst stuende er irgendwann
ueberall und waere nichts mehr wert.

ERWAEHNUNGEN BLEIBEN, WIE SIE BEIM SENDEN WAREN. Wer beim Bearbeiten
"@Anna" ergaenzt, spricht Anna damit nicht an. Sonst gaebe es nur
schlechte Wege: nachtraeglich benachrichtigen laesst sich beliebig
oft wiederholen, und still eintragen setzt jemanden auf eine Liste,
von der er nie erfaehrt. Ansprechen tut man mit einer neuen
Nachricht. (Falls das anders gewuenscht ist, ist es eine eigene
Entscheidung -- nicht etwas, das hier nebenbei mitpassiert.)

DER RAUM RUECKT NICHT NACH OBEN und niemand bekommt die Nachricht
als ungelesen: Eine Tippfehlerkorrektur ist keine Wortmeldung.
`letzte_am` wird deshalb nicht angefasst.

Leer geht nicht -- dafuer steht "loeschen" daneben, mit Rueckfrage.
Grenzen (4000 Zeichen) sind dieselben wie beim Senden; eine zweite
Rechnung waere die, die auseinanderlaeuft.

Das Feld sitzt AN der Nachricht, nicht im Schreibfeld unten: Wer
seinen Text zum Bearbeiten unten wiederfindet, schickt ihn beim
naechsten Enter als NEUE Nachricht ab und hat ihn zweimal im Raum.
Enter speichert, Shift+Enter macht eine Zeile, Escape bricht ab --
dieselben Tasten wie beim Schreiben. 16 px Schrift, sonst zoomt iOS
beim Hineintippen die ganze Seite heran.

Der Stift traegt sich in die Familie der Handgriffe ein, wie es der
Hinweis in chat.css ausdruecklich verlangt ("wer einen sechsten
Handgriff baut, traegt ihn hier ein und bekommt sein Zeichen").

EIN FEHLER, DEN NUR DAS BILD GEZEIGT HAT. Ich hatte im Code
behauptet, die Gespraechsliste aendere sich beim Bearbeiten nicht,
und darum auf das Nachladen verzichtet. Auf dem Bildschirmfoto stand
rechts "Treffen um 15 Uhr" und links in der Liste weiter "Du:
Treffen um 15 Urh" -- derselbe Satz, zweimal verschieden, auf einem
Schirm. Richtig ist: Die REIHENFOLGE aendert sich nicht, die
VORSCHAU sehr wohl. Beide Haelften waren fuer sich gemessen und
gruen; keine Zahl hat es gemerkt.

pruef-chat 17 neue Pruefungen: eigene geht, fremde nicht, DogFather
nicht, Vermerk kommt mit nach draussen (auch im SELECT -- genau das
hat am 03.10. bei den Anhaengen einen halben Tag gekostet), Raum
rueckt nicht, Vorschau zieht nach, leer/zu lang abgelehnt,
unveraendert ohne Vermerk, geloeschte nicht bearbeitbar, wer nicht
im Raum ist bekommt 404 statt 403.

pruef-chat-optik 71 -> 84: im echten Browser, mit zwei Sitzungen.
Darunter die Zeile, auf die es ankommt -- der neue Text steht bei
Patrick, OHNE Neuladen. Ein Bearbeiten, das nur der Schreibende
sieht, waere schlimmer als keins.

Dabei zwei eigene Messfehler behoben: Die Sitzungen von oben waren
laengst geschlossen (Playwright meldet nur "Target page has been
closed"), und beide klickten "das oberste Gespraech" statt
denselben Raum -- wodurch die Pruefung "an ihr steht KEIN
bearbeiten" gruen war, weil die Nachricht gar nicht da war. Sie
haengt jetzt daran, dass er sie wirklich sieht.

Datenbank vorher gesichert und zurueckgelesen (integrity_check,
324 Nachrichten, 20 Personen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-04 00:06:29 +02:00
DogFatherGitandClaude Opus 5 5d9c8cd377 Haustrennung: kein Eintrag mehr aus dem anderen Haus
Filipe, 24.09.2026: "wenn ich bei der einen was mache soll nichts bei
der anderen passieren." -- und heute: "ja los".

GEMESSEN, BEVOR ETWAS ANGEFASST WURDE (jedes Brett x beide Adressen x
vier Rollen):

  AGENTUR-Adresse   DogFather  18 Bretter
                    Manager     6 Bretter
                    Creator     6 Bretter
                    Modi        kommt nicht rein (401)
  CREW-Adresse      DogFather  18 Bretter
                    Modi       13 Bretter
                    Manager     kommt nicht rein (401)
                    Creator     kommt nicht rein (401)

Die Anmeldung war also dicht. Durch griff genau EINE Rolle: DogFather.
Er wohnt in beiden Haeusern, und die Riegel in sichtbarEintrag()
fragten nach der ROLLE, nicht nach der Adresse. Auf der Crew-Adresse
stand damit das Brett der Agentur samt Inhalt.

Nachgemessen ist der Durchgriff AELTER als der gestrige Eventkarten-
Umbau -- zweimal gemessen, mit und ohne ihn, gleiches Ergebnis.

RIEGEL 0 in sichtbarEintrag(): Wer auf einer Adresse angemeldet ist,
sieht nur Eintraege dieses Hauses. Er haengt den uebrigen Riegeln
UM, statt in jeden Ausgang geschrieben zu werden -- die Funktion hat
drei Rueckgabepunkte, und der naechste waere sonst wieder offen.

Nachher, dieselbe Messung: DogFather sieht auf der Agenturadresse nur
Agentur-Eintraege, auf der Crew-Adresse nur die des Rudels. Manager,
Creator und Modi unveraendert.

WAS DABEI SCHIEFGING UND WIE ES AUFFIEL

1. Die erste Fassung liess bei `haus IS NULL` den BEREICH entscheiden.
   pruef-haus-trennung.mjs wurde sofort rot: "Lunas Live vom Montag"
   verschwand von der Agenturadresse. `live`, `technik` und
   `community` tragen BEIDES -- die Kacheln von Team Dogi und die
   Creator-Akten. Eine Regel, die jedem Brett genau ein Haus zuweist,
   kann das nicht. Jetzt bleibt ein Eintrag ohne Haus sichtbar: ein
   Eintrag zu viel faellt auf, ein fehlender nicht.

2. Damit NULL kein Dauerloch ist: FUENF von ACHT Stellen, die
   Eintraege anlegen, setzten `haus` gar nicht (workspace-video.js,
   -content.js, -bewerbung.js, -treff.js, -vorlagen.js). Nachgetragen.

3. Und `person.haus` war dafuer der falsche Massstab: Legt DogFather
   ueber die Agenturadresse ein Highlight an, gehoert es trotzdem dem
   Rudel -- sonst sieht die Community es nie. pruef-treff.mjs hat das
   gefunden (2 Fehler). Neu: hausFuerNeuenEintrag() -- bei den sieben
   Brettern des Rudels entscheidet das BRETT, sonst die Adresse.

NEU: pruef-haus-luecke.mjs (12 Pruefungen). Sie sucht die
Einfuege-Stellen im Quelltext und wird rot, sobald eine neunte
dazukommt, die `haus` vergisst -- mit Gegenprobe, dass das Suchmuster
eine solche Stelle auch wirklich erkennt. Ein Kommentar daneben haette
es nicht verhindert; das steht so schon im Projektgedaechtnis.

NEBENBEI: In bereich.js stand seit gestern `|| "Agentur-Events"` als
Rueckfall fuer das Etikett der Vorschau. pruef-treff.mjs verbietet
das zu Recht -- wie ein Brett heisst, haengt am Haus, und der Server
sagt es. Der Rueckfall ist weg; fehlt die Angabe, steht lieber kein
Etikett da als ein falsches.

pruef-treff.mjs nachgezogen (85 -> 86 Pruefungen, nicht weniger): Die
Zusage "DogFather sieht den Beitrag" wird jetzt auf der Crew-Adresse
geprueft, mit Gegenprobe fuer die Agenturadresse.

GEPRUEFT, alle gruen:
  pruef-haus-luecke     12    pruef-haus-trennung  100
  pruef-crew-adresse   169    pruef-treff           86
  pruef-eventkarte      77    pruef-agentur         62
  pruef-haus-seiten     38    pruef-eintrag-bild    24
  pruef-vorlagen        24    pruef-video, -content, -bewerbung,
                              -bereiche-lesend: in Ordnung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 23:33:03 +02:00
DogFatherGitandClaude Opus 5 3e1e0810ba Agentur-Events: die Karte als Aushang, Aufgaben zum Abhaken
Filipe, mit einem Bildschirmfoto des Oktober-Events: "ich will das viel
geiler viel perfekter. und auch wenn man die eintraegt und so soll viel
mehr perfektioniert und uebersichtlicher sein."

VORHER GEMESSEN (1280 px, eine einzige Eventkarte):

  Kartenhoehe            1196 px   -- das Fenster ist 900 px
  davon Banner            638 px   -- 53 %, ohne einen Buchstaben
  Titel steht bei        1482 px   -- zweimal scrollen bis zum Namen
  Titelgroesse          15,36 px   -- 1,4 px mehr als der Fliesstext
  Etikett               10,88 px   -- unter der eigenen Grenze (11,5)
  Datum                     3 x    -- in drei Zeilen untereinander
  Knoepfe              4 x gleich  -- "loeschen" wie "zur Aufgabe"

NACHHER, dieselbe Messung: Karte 618 px, Buehne 203 px, Titel 75 px
unter der Kartenkante und 24,8 px gross, Etikett 12 px, das Datum
einmal, "loeschen" abgesetzt.

DIE KARTE
Das Banner ist nicht mehr ein Anhang ueber dem Titel, sondern die
Buehne dahinter -- Hoehe gedeckelt, Titel darauf. Dazu die Frage, die
bei einem Wettbewerb wirklich zaehlt und bisher nirgends beantwortet
wurde: "noch 12 Tage", mit Zeitbalken. Ein Knopf "Banner ganz" holt das
vollstaendige Bild zurueck, das beim Umbau sonst verloren gegangen
waere -- bei Filipes Banner steht die Ansage IM Bild.

DIE AUFGABEN
Aus Fliesstext wird eine Liste, und jeder hakt fuer sich ab (neue
Tabelle event_punkte, Schluessel aus dem Zeilentext). Umsortieren
laesst den Haken, wo er ist; wird die Bedingung selbst umgeschrieben,
faellt er -- beides nachgemessen. Die Leitung sieht, wer wie weit ist,
eine Creatorin sieht diese Liste gar nicht erst.

DAS FORMULAR
Ein Feld je Zeile statt eines leeren Textfeldes. Im echten Event stand
".Jeden Tag Live gehen" neben ". 33k Diamanten erreichen" -- einmal mit
Leerzeichen, einmal ohne. Das ist die zwangslaeufige Folge davon, dass
die Aufzaehlungszeichen von Hand getippt werden; jetzt setzt sie das
Formular. Dazu "Laeuft 14 Tage.", eine Warnung bei verdrehtem Zeitraum
und eine Vorschau, die dieselbe Funktion benutzt wie die echte Karte.

NEBENBEI GEFUNDEN UND BEHOBEN
* Das Banner kam bei Creatorn mit 404 zurueck -- also an genau der
  Karte, die fuer sie gemacht ist. Die Regel "wer das Brett sieht,
  sieht das Bild" galt nur fuer die sieben Community-Bretter. Jetzt
  fragt der Bildweg dieselbe Regel wie das Brett (darfEintragSehen);
  die Gegenprobe zeigt, dass ein fremder Eintrag weiterhin 404 gibt.
* Zwei Stellen setzten das Formular zurueck, die kuerzere liess
  Vorschau und Zeilen-Editor stehen -- beim naechsten "Neuer Eintrag"
  standen die Aufgaben des vorigen Events noch da.
* Der Schriftgrund ragte auf dem Handy 6 px ueber die Karte (feste
  -20 px gegen 14 px Polsterung); jetzt an die Polsterung gekoppelt.

GEPRUEFT
pruef-eventkarte.mjs (neu): 77 Pruefungen, 0 Fehler -- mit Gegenproben
zu jeder Zusage und einer Kontrastmessung am Bildpunkt auf einem
weissen Banner (14,7:1; ohne den Schriftgrund 1,05:1).
pruef-agentur.mjs auf die neuen Bausteine nachgezogen, Zahl unveraendert
bei 62. pruef-eintrag-bild.mjs 24/0.

OFFEN, NICHT AUS DIESEM UMBAU: Das Brett `agentur` ist auf der
Crew-Adresse erreichbar. Zweimal gemessen, mit und ohne diese
Aenderung -- gleiches Ergebnis. Gehoert zur Trennungsregel vom
24.09.2026 und wird getrennt entschieden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 19:02:05 +02:00
DogFatherGitandClaude Opus 5 ae2f12c67d "Fuer wen"-Reihe weg -- aber nur bei Team Dogi
Filipe, mit Bildschirmfoto der Leiste "FUER WEN · Alle 3 2 ·
Marina 1 · Diene 0": "brauchen wir nicht auf der aufgaben seite."

GETRENNT GEFUEHRT, wie seit dem 24.09. fuer jeden Umbau. Es ist
DIESELBE Reihe in beiden Haeusern, aber nicht dieselbe Aufgabe:

  Team Dogi    -> "Fuer wen", darin drei, vier Modis, die ohnehin
                  alle auf einem Schirm stehen. Ein Filter fuer eine
                  Liste, die kuerzer ist als er. WEG.
  Spicy Media  -> "Alle Creator" / "Deine Creator". Scouts und
                  Manager filtern damit durch ihre Creator, und das
                  sind deutlich mehr. BLEIBT.

Die Trennung ist eine einzige Zeile an `ich.haus` -- das kommt vom
Server. Eine Rollenliste im Browser waere die zweite Wahrheit und fuer
DogFather, der in beiden Haeusern arbeitet, sogar falsch.

Der Zweig fuer die dritte Beschriftung ist mit entfernt, nicht
stehengelassen: "Fuer wen" ist von nirgends mehr erreichbar, und ein
Zweig, den niemand erreicht, sieht beim Lesen aus wie ein Fall, den
es gibt -- beim naechsten Umbau pflegt ihn jemand mit.

BEWIESEN IN BEIDE RICHTUNGEN, sonst waere die Trennung eine
Behauptung:

  * pruef-handy-teamdogi (neu, 3 Pruefungen, 244 -> 247): auf crew.
    im echten Browser ist die Reihe weg -- MIT der Gegenprobe, dass
    die Seite ueberhaupt steht (4 Knoepfe in der Schwester-Reihe).
    "Reihe nicht da" waere sonst auch auf einer kaputten Seite wahr.
  * pruef-aufgabenbrett (49, unveraendert): bei Spicy Media steht sie
    weiterhin da, mit "Alle, Tili, Luna" und der Beschriftung "Alle
    Creator".

ZWEI DINGE AM PRUEFWERKZEUG, die mich heute Zeit gekostet haben:

1. `probleme` wurde seit jeher gefuellt und NIE ausgegeben. Am Ende
   stand "1 Befund" und sonst nichts -- wer das liest, weiss DASS
   etwas ist, nicht WAS, und muss den ganzen Lauf noch einmal
   anstossen. Die Befunde stehen jetzt unter der Zahl.

2. Der Anmeldeweg stand in der Schleife, und fuer die neue Messung
   habe ich ihn abgeschrieben -- dabei eine aeltere Fassung erwischt,
   ohne `isVisible()` und mit `click()` statt `check()`. Ergebnis:
   30 Sekunden Zeitablauf an der Altersfrage, die es fuer DogFather
   gar nicht gibt. Jetzt ein Helfer, den beide Aufrufer benutzen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 15:25:26 +02:00
DogFatherGitandClaude Opus 5 7d56837049 Fuenfte Etappe: "abgebrochen" fehlte in der Pruefung
Die Live-Datenbank hat mir den Fehler gezeigt, nicht der Quelltext.
Nach dem Ausliefern ein Blick auf die echten Staende: erledigt 6,
offen 4 -- und abgebrochen 2. Die zwei standen in meiner Pruefung
nicht.

GRUND: Ich hatte die Etappen aus STATUS in workspace-aufgaben.js
abgeleitet, und dort stehen nur vier. "abgebrochen" fehlt dort
ABSICHTLICH, damit der normale Weg es nicht setzen kann -- es kommt
ueber eine eigene Route mit Pflichtbegruendung. Wer die Liste aus
STATUS ableitet, uebersieht also ausgerechnet den Endzustand, in dem
Aufgaben am laengsten liegen bleiben. Dieselbe Luecke hat in dieser
Datei schon einmal zwei Bedingungen erwischt, die nur gegen
'erledigt' prueften.

"In jeder etape" waere damit eine Zusage ueber vier von fuenf
Etappen gewesen.

Zwei Dinge dafuer nachgezogen:

  * Die Etappe wird jetzt aus der DATENBANK gelesen, nicht aus der
    Liste. Abgebrochene Aufgaben werden an mehreren Stellen bewusst
    ausgeblendet -- "Etappe steht wirklich" waere ueber die Liste
    gar nicht messbar gewesen.
  * Die Auskunft an die Oberflaeche wird nur verlangt, WENN die
    Aufgabe in ihrer Liste steht. Blendet das Haus eine Etappe aus,
    gibt es dort keinen Knopf zu zeigen; dann zaehlt allein der
    Server, und den misst der DELETE. Gemessen: Sie steht drin, und
    der Knopf wird auch dort angeboten.

pruef-verteilen 42 -> 44, jetzt 5/5 in allen Zaehlungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 15:01:44 +02:00
DogFatherGitandClaude Opus 5 95d68fd392 Rechte Hand und DogFather duerfen Aufgaben immer loeschen, in jeder Etappe
Filipe: "ich will noch dass die rechte hand und dogfather bei den
aufgaben immer die option haben aufgaben zu loeschen. die soll es
immer geben in jeder etape."

NACHGEMESSEN STATT ANGENOMMEN, was vorher galt (darfAufgabenVerteilen
&& darfAendern):

  DogFather (admin)  -> Leitung, konnte schon immer ueberall loeschen.
  rechte Hand (hand) -> NUR an Aufgaben, bei denen sie selbst
                        Erstellerin, Verantwortliche oder Zielperson
                        war. An allen anderen fehlte der Knopf.

Die Luecke war also allein die rechte Hand -- und sie hing nicht an
der Etappe, sondern an der Zugehoerigkeit. Genau das faellt weg.

ZUR ETAPPE: Der Loeschweg hat auch vorher keinen Status geprueft, und
die Oberflaeche zeigt den Stift an JEDER Karte. Es gab hier nichts
freizuschalten -- die Zusage "in jeder etape" ist jetzt aber
festgenagelt, damit sie niemand mit einer gut gemeinten
Statusbedingung wieder aufhebt.

`istRechteHand` NEU, UND NICHT `istHand`: Letzteres umfasst auch die
LINKE Hand. Haette ich das genommen, haette sie das Recht lautlos
mitbekommen -- im ganzen Haus hat sie durchgaengig das kleinere
Recht, und es waren zwei Rollen genannt, nicht drei. Der Vergleich
`rolle === "hand"` stand bisher VIERMAL verstreut im Haus
(workspace-chat zweimal, workspace-material, workspace-rechte); eine
fuenfte Abschrift waere die naechste, die irgendwann abweicht. Die
vier alten bleiben vorerst unberuehrt -- nebenbei umgebaut waeren sie
vier ungepruefte Rechteaenderungen.

pruef-verteilen 30 -> 42. Darin steht jetzt das GEGENTEIL einer
bisherigen Zeile: "Gegenprobe: eine fremde Aufgabe loescht sie nicht
(403)" war am 25.09. richtig, als der Auftrag "ihre eigenen" hiess.
Sie ist mitgewandert statt stehenzubleiben -- eine Pruefung, die eine
zurueckgenommene Regel weiter verteidigt, haelt die Aenderung auf und
sieht dabei aus wie Sorgfalt.

Alle vier Etappen einzeln (offen, arbeit, review, erledigt), jeweils
mit der Kontrolle, dass die Etappe wirklich steht -- sonst waeren es
in Wahrheit viermal "offen" und die Pruefung gruen, ohne je etwas
anderes gesehen zu haben. Dazu je Etappe die Auskunft an die
Oberflaeche (darf_loeschen), der echte DELETE und ein Blick in die
Datenbank.

GEGENPROBE GEFAHREN: Mit `istHand` statt `istRechteHand` meldet die
Pruefung "die LINKE Hand darf es in keiner (0/4 mal abgelehnt)",
2 Fehler. Sie faengt also genau den Fehler, der am teuersten gewesen
waere.

Gegengemessen: pruef-haerte 20, pruef-aufgabenbrett 49,
pruef-rechtetafel 19, pruef-zuteilung 98, pruef-haus-trennung 100 --
alle 0 Fehler. Das andere Haus ist unberuehrt; "hand" gibt es dort
nicht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 15:00:03 +02:00
DogFatherGitandClaude Opus 5 e00a905ce8 Dopplung weg: "Bei dir klingelt nichts" stand zweimal auf einem Schirm
Der neue Kasten von heute Mittag hat die alte Tagesblick-Zeile nicht
ersetzt, sondern sich darueber gesetzt. Beide sagten dasselbe,
untereinander, auf derselben Seite.

GEFUNDEN HAT DAS NUR EIN BILDSCHIRMFOTO. Beide Teile waren fuer sich
gruen: pruef-glocke verlangte die Zeile, pruef-push-hinweis den
Kasten, und keine der beiden konnte sehen, dass die andere existiert.
Zahlen zeigen so etwas nie. Deshalb macht pruef-push-hinweis jetzt
bei jedem Lauf ein Foto -- und scrollt vorher hin, weil der erste
Versuch brav die Begruessungskachel zeigte und den Kasten gar nicht
im Bild hatte. Ein Beweisbild ohne das, was es beweisen soll, ist
schlimmer als keins: Man glaubt ja, hingesehen zu haben.

Entfernt wurde die aeltere der beiden (19.09.2026). Sie war gut
gebaut, server-seitig und nicht wegklickbar -- aber sie hat das
Problem nicht geloest: Am 03.10. nachgemessen hatten immer noch
12 von 20 kein Geraet, darunter die linke Hand und ein Modi. Sie SAGT
es und man kann nichts tun; sie fuehrt nur auf eine andere Seite. Der
neue Kasten hat einen Knopf und erklaert den iPhone-Fall, in dem
Web-Push ohne Home-Bildschirm gar nicht geht.

Entscheidung von Filipe am 03.10. Offen gesagt, was damit aufgegeben
ist: Wer "Nicht jetzt" tippt, bekommt keine zweite Erinnerung mehr.
Gegensicherung ist die Personenliste -- dort steht seit heute bei
jeder Person, die nichts bekommt, genau das.

pruef-glocke 36 -> 33, und die Zahl ist erklaert: 5 Pruefungen zur
alten Zeile entfernt, 2 neue dafuer. Die neuen pruefen das
GEGENTEIL von vorher -- dass die Zeile nicht unbemerkt
zurueckkommt -- mit der Zahl der geprueften Hinweise in der
Bedingung, damit eine leere Antwort der Schnittstelle nicht als
"steht nicht drin" durchgeht.

Die alte Gegenprobe ("mit angemeldetem Geraet ist der Hinweis weg")
ist ersatzlos entfallen, nicht aus Bequemlichkeit: Sie waere ab jetzt
IMMER gruen, egal was das Haus tut. Eine Pruefung, die nichts mehr
widerlegen kann, taeuscht nur Deckung vor. Was sie geprueft hat,
prueft pruef-push-hinweis am neuen Kasten, mit einer echten
Anmeldung.

OHNE_ZAHL in start.js bleibt als leere Liste stehen -- der naechste
Zustandshinweis braucht sie wieder, und als Liste ist sie die eine
Stelle dafuer.

Gegengemessen: pruef-tagesblick 23, pruef-start-ansicht 160,
pruef-push-hinweis 16 -- alle 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 13:47:50 +02:00
DogFatherGitandClaude Opus 5 cc716a9c1c Startseite sagt einmalig Bescheid, wenn jemand nichts bekommt
Am 03.10.2026 nachgemessen: 20 aktive Personen, 8 mit einer
Anmeldung. Zwoelf bekamen keine einzige Benachrichtigung -- darunter
die linke Hand und ein Modi. Die heute frueh behobene Dringlichkeit
hilft diesen zwoelf nichts: Ohne Anmeldung geht gar nichts hinaus.

Belegt im neuen Sendeprotokoll, seit dem Deploy heute Mittag:
10 Chat-Meldungen zugestellt, 26 Versuche an "keine_geraete"
gescheitert. Genau diese 26 sind der Grund.

Keiner der zwoelf wusste es. Die Glocke sagt es nur dem, der sie
anschaut -- und genau das hatten sie nie getan. Jetzt steht auf der
Startseite eine ruhige Zeile mit zwei Knoepfen: Anschalten oder
nicht jetzt.

ABGELEITET AUS `lage()`, der Stelle, die es ohnehin weiss. Eine
zweite Ableitung daneben waere die, die beim naechsten Umbau etwas
anderes behauptet als die Glocke zwei Zentimeter weiter oben.

NUR DORT, WO ES ETWAS ZU AENDERN GIBT. Bei "verboten" hilft kein
Knopf (das muss man im Browser zuruecknehmen), bei "geht-nicht"
erst recht nicht. Auf dem iPhone erklaert er stattdessen den Weg
ueber den Home-Bildschirm -- ohne den gibt es dort gar kein
Web-Push, und das weiss sonst niemand.

NUR AUF DER STARTSEITE, obwohl glocke.js auf 39 Seiten laeuft: Die
Seite stellt den Platz, das Skript fuellt ihn -- dasselbe Muster wie
`#glocke-platz`. Auf jeder Seite waere er nach dem zweiten Mal
Tapete.

Ruhig, nicht alarmierend: Es ist kein Fehler, sondern eine
Einstellung, die noch niemand getroffen hat. Rot waere hier falsch.

pruef-push-hinweis.mjs (neu, 16 Pruefungen). Sie misst VIER
Abwesenheiten und nur eine Anwesenheit, weil die Gefahr auf der
anderen Seite liegt: weg nach "Nicht jetzt", weg geblieben nach dem
Neuladen, nicht da auf anderen Seiten (mit der Gegenprobe, dass die
Glocke dort sehr wohl steht -- sonst waere nur gemessen, dass das
Skript gar nicht laeuft), und nicht da, wenn die Benachrichtigungen
AN sind. Die letzte mit echter Anmeldung, die nachweislich in der
Datenbank landet.

Dabei gelernt, und es stand nicht im Code: `browser.newContext()`
gibt ein Inkognito-Fenster, und Chrome unterstuetzt dort die Push-API
nicht -- "deliberately no way to feature-detect this". Die Pruefung
meldete zuerst den dritten Ausgang statt gruen, und weil sie die
Browsermeldungen mitschreibt, stand die Ursache sofort da. Jetzt
laeuft sie mit einem echten Profil.

Gegengemessen, dass die zusaetzliche Zeile nichts verschiebt:
pruef-glocke 36, pruef-start-ansicht 160, pruef-tagesblick 23,
pruef-kachelraster 24, pruef-handy 189, pruef-breiten 23,
pruef-lesbarkeit 14, pruef-ueberlappung (20 Breitenpaare) -- alle
0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 13:36:51 +02:00
DogFatherGitandClaude Opus 5 628b99943e Personenliste zeigt, wen eine Benachrichtigung ueberhaupt erreicht
Am 03.10.2026 am laufenden System nachgemessen: 20 aktive Personen,
aber nur 8 mit einer Push-Anmeldung. Zwoelf bekommen keine einzige
Benachrichtigung -- darunter ein Modi und die linke Hand.

Das war fuer niemanden sichtbar. Die Glocke sagt es nur dem, der sie
anschaut, und wer etwas Wichtiges schreibt, konnte nicht wissen, wen
es erreicht. Die Dringlichkeit, die heute frueh behoben wurde, hilft
diesen zwoelf gar nichts: Ohne Anmeldung geht nichts hinaus.

Der Hinweis steht jetzt auf der Personenseite, also dort, wo ohnehin
ueber Personen entschieden wird -- nicht auf einer eigenen Seite, die
niemand aufruft. Aus DERSELBEN Abfrage wie alles andere; eine zweite
waere eine zweite Gelegenheit, dass die Liste etwas anderes sagt als
die Wirklichkeit.

NUR BEIM FEHLEN, UND DAS IST ABSICHT. Stuende bei jeder Person eine
Zeile, stuenden bei zwanzig Personen zwanzig Zeilen da, und die, auf
die es ankommt, gingen darin unter -- eine Angabe, die immer kommt,
wird nicht mehr gelesen. Schweigen heisst hier: erreichbar. Die
Zeilen verschwinden eine nach der anderen, sobald jemand die Glocke
anschaltet.

Nicht bei gesperrten Personen: Dort ist es keine Luecke, sondern
richtig so.

pruef-personen-liste 33 -> 37, mit der Gegenprobe in beide
Richtungen: Eine Person bekommt im Testbestand ein angemeldetes
Geraet, und bei genau ihr darf der Hinweis NICHT stehen. Stuende er
ueberall, waere "er steht da" wertlos.

Gegengemessen, dass die zusaetzliche Zeile nichts verschiebt:
pruef-personen-kachel 45, pruef-hand-personen 49,
pruef-modi-verborgen 94, pruef-betreuung 18, pruef-scout-zuteilung
(liest dieselbe Klasse .person__bezug) -- alle ohne Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 13:09:51 +02:00
DogFatherGitandClaude Opus 5 e349de0040 Sendeprotokoll fuer Benachrichtigungen: "ich bekomme nichts" ist jetzt beantwortbar
Beim Nachsehen zu Dienes Meldung ist aufgefallen, dass ueber den
Versand selbst nichts festgehalten wird. Im Protokoll standen nur
push_angemeldet und push_abgemeldet -- kein Wort darueber, ob je
etwas verschickt wurde, an wie viele Geraete, und warum nicht.

Von neun Aufrufstellen wertete genau eine den Rueckgabewert aus; die
anderen acht warfen ihn weg. Sagt jemand "ich bekomme nichts", liess
sich also nicht nachsehen, OB gesendet wurde -- dieselbe Falle wie am
06.09. in VanVans Shop, wo zwei Stunden in die Zustellung ermittelt
wurden, bevor jemand fragte, ob die Mails abgeschickt waren. Sie
waren es, alle, nachweisbar in einer Abfrage.

zuletzt_ok reicht dafuer nicht: Es sagt, wann zuletzt irgendetwas
ankam -- nicht was, nicht an wen sonst, und nichts ueber die Faelle,
in denen gar nicht erst gesendet wurde. Genau die (abgeschaltet,
Ruhezeit, kein Geraet) sind die haeufigste Antwort auf die Frage.

Neue Tabelle push_versand: Zeit, Person, Art, Grund, Geraete,
zugestellt. Festgehalten wird JEDER Ausgang, auch der, bei dem nichts
hinausging -- ein Protokoll, das nur Erfolge kennt, kann die Frage
nicht beantworten, fuer die es angelegt wurde.

Das Protokoll sitzt als Huelle um den Versand, nicht in ihm: Sieben
Ausgaenge einzeln zu protokollieren waere eine Liste zum Pflegen, und
der achte, den jemand naechstes Jahr einbaut, umginge sie still --
so sind am 11.09. die Spalten beim Tabellenumbau verschwunden. So
steht ein neuer Ausgang ohne Zutun mit drin.

Aufraeumen nach 30 Tagen, neben dem bestehenden Aufraeumen von
push_verschickt. Gemessen statt geschaetzt: rund 16 Chat-Nachrichten
am Tag an bis zu acht angemeldete Geraete -- ein paar tausend Zeilen
im Monat.

Das Schreiben kann den Versand nicht aufhalten (try), meldet sich
aber, wenn es scheitert: ein Protokoll, das heimlich nichts
schreibt, ist schlimmer als keins.

pruef-push-eilig 13 -> 20. Darunter die Gegenprobe, dass auch das
NICHT-Senden protokolliert wird, und dass ein Fehlschlag nicht als
zugestellt gilt.

Datenbank vorher gesichert und die Sicherung geprueft (integrity_check,
20 Personen, 10 Anmeldungen lesbar).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 13:03:29 +02:00
DogFatherGitandClaude Opus 5 73f9b24793 Benachrichtigungen wecken das Telefon wieder: Urgency je Art
Diene hat gemeldet: "Die Benachrichtigungen werden nicht angezeigt,
wenn neue Nachrichten reinkommen. Erst, wenn man die App oeffnet."

Alles Messbare war gruen: Der Service Worker zeigt die Meldung bei
geschlossener App (pruef-push-zu, 13 Pruefungen), jede Anmeldung im
Haus stand auf fehler = 0, der Push-Dienst quittierte mit 201. Nur
den Kopf auf der Leitung hat nie jemand gemessen:

    Urgency: normal

Beide Dienste behandeln das ausdruecklich als "darf warten".
Android/FCM haelt solche Meldungen zurueck, solange das Telefon
doest, und stellt sie zu, wenn es aufwacht -- typischerweise beim
Entsperren oder Oeffnen der App. Apple/APNs nennt es "verzoegert,
gebuendelt oder gedrosselt". Das ist Dienes Satz, Wort fuer Wort,
und es stand als Vorgabe im eigenen Quelltext.

zuletzt_ok konnte das nie zeigen: Es beweist, dass der DIENST
angenommen hat, nicht dass das GERAET etwas angezeigt hat.

Bis hierher hing die Dringlichkeit an der Ruheregel (dringend =
regel === "nie"), mit der Begruendung, "darf das nachts stoeren?"
und "darf das warten?" haetten dieselbe Antwort. Haben sie nicht:
Ein Chat um 3 Uhr soll schweigen, um 14 Uhr aber nicht vierzig
Minuten liegen bleiben. Jetzt zwei Felder -- in DERSELBEN Zeile
derselben Artenliste, damit sie nicht auseinanderlaufen koennen.

10 von 19 Arten sind eilig (Anruf, Chat, Erwaehnung, Support, Hilfe,
Termin, Wecker, zweimal Live, Probe). Die anderen neun duerfen
warten -- waere alles eilig, waere nichts mehr eilig.

DIE FALLE BEIM BEHEBEN: dringend steuerte auch die Haltbarkeit
(TTL 150). Ein einfach auf "dringend" gestellter Chat waere nach
150 s verfallen -- wer sein Telefon drei Minuten aus hat, haette die
Nachricht GAR nicht mehr bekommen. Aus "zu spaet" waere "nie"
geworden. Deshalb sind eilig und kurzlebig getrennt; kurzlebig
bleibt genau beim Anruf und der Probe.

Der alte Name kracht jetzt, statt still "normal" zu liefern.

pruef-push-eilig.mjs (neu, 13 Pruefungen): die Entscheidung je Art
unabhaengig notiert statt aus der Artenliste abgelesen, jede Art
muss eine Entscheidung haben, und der Kopf wird durch
benachrichtige() hindurch an einem nachgebauten Push-Dienst
gemessen. Gegenprobe gelaufen: ohne das Feld meldet sie
"chat_nachricht geht mit Urgency: normal hinaus", 4 Fehler.
Die Uhr ist dort eine Eingabe, keine Annahme -- die Zeitzone wird so
gewaehlt, dass der Lauf immer auf 12 Uhr faellt, sonst waere die
Pruefung nachts rot ohne Befund.

pruef-anruf-klingelt 25 -> 26. Dabei aufgefallen: Eine ihrer
Pruefungen war gruen, obwohl die Zeile aus dem Code verschwunden war
-- sie stand nur noch in einem Kommentar, der die alte Fassung
zitiert. Quelltextpruefungen lesen dort jetzt ohne Kommentare.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 12:58:01 +02:00
DogFatherGitandClaude Opus 5 db8dd2fbea 147 Zeichen je Zeile -- am Kontrast lag es nicht
Filipe: „nur die kacheln noch viel geiler. so dass ich die texte auch
besser erkenne."

NAHELIEGEND WAERE GEWESEN, die Farben aufzuhellen. Erst gemessen,
dann gebaut -- und die Vermutung war falsch:

    Kontrast .s-karte__text        15,7 : 1   (noetig 4,5)
    Kontrast aller zehn Textarten   7,5 bis 15,7 : 1
    ZEICHEN JE ZEILE                        147   (angenehm 45-75)

Am Kontrast lag es nicht; der ist ueberall ueppig. Es lag an der
ZEILENLAENGE. Auf 1280 px lief der Meldungstext ueber die ganze
Kartenbreite: 1120 px, knapp 150 Zeichen. Beim Zeilenwechsel findet
das Auge die naechste Zeile nicht mehr sicher -- man liest dieselbe
zweimal oder ueberspringt eine. Das ist der groesste Hebel beim
Lesen, und er kostet nichts.

GEAENDERT

    Meldungstext   15,2 -> 17 px,  max-width 72ch,  Zeilenhoehe 1.6
    Verlaufstext   14,4 -> 15,2 px, max-width 70ch
    Kartenrand     16/18/15/22 -> 18/20/16/24 px
    Trennlinie     zwischen Meldung und Verlauf

    147 -> 78 Zeichen je Zeile (PC), 39 auf dem Handy

`ch` UND NICHT PIXEL: `ch` ist die Breite der Null und waechst mit
der Schrift mit. Eine Angabe in Pixeln waere bei der naechsten
Schriftgroesse wieder falsch -- dieselbe Falle wie jede feste Zahl.

MEHR RAND, WEIL DIE SCHRIFT GEWACHSEN IST. Bei unveraendertem Rand
haette sie die Kante beruehrt, und die Karte waere voller gewirkt
statt lesbarer. Links bleibt es breiter: dort laeuft die
Leuchtschiene in der Farbe des Stands.

DIE TRENNLINIE kostet einen Pixel und beantwortet „wo hoert die
Meldung auf und wo faengt die Vorgeschichte an?". Vorher lief beides
ohne Zaesur ineinander.

EIN FEHLER IN MEINER EIGENEN MESSUNG -- und er haette Schaden
angerichtet

Die erste Fassung der Kontrastrechnung meldete fuer drei gut lesbare
Texte einen Kontrast von 1,04. Ich war nah dran, Farben zu
„reparieren", die in Ordnung sind.

Der Grund: `rgb()` zaehlt 0..255, `color(srgb …)` zaehlt 0..1 -- und
genau das liefert Chrome fuer jedes `color-mix()`. 0,77 als 0,77/255
gelesen ist fast Schwarz. Aufgefallen ist es nur, weil die Zahl
nicht zum Bildschirmfoto passte: Dort waren die Texte deutlich
lesbar.

DESHALB STEHT IN DER PRUEFUNG EINE GEGENPROBE IM BROWSER: Ein
absichtlich zu blasser Absatz wird eingehaengt und MUSS auffallen
(gemessen 1,23 : 1). Ohne sie waere „alle ueber 4,5" auch dann
gruen, wenn die Rechnung kaputt ist -- und genau das war sie.

GEPRUEFT -- pruef-support-bilder 56 -> 64 ok

    9 Textarten in der Karte gemessen
    der Meldungstext ist 16.96 px gross (mindestens 16)
    und bricht nach etwa 78 Zeichen um (hoechstens 85, vorher 147)
    der Verlaufstext: 15.2 px, etwa 75 Zeichen
    jeder Text haelt die Kontrastschwelle (0 darunter)
      — schwaechster 7.55 : 1
    Gegenprobe: ein absichtlich blasser Text faellt auf (1.23 : 1)
    auf 390 px ragt mit der groesseren Schrift nichts heraus (0 px)
    und die Zeile bleibt lesbar lang (etwa 39 Zeichen)

Dazu gruen: pruef-css-klassen · pruef-fingermass.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 12:37:05 +02:00
DogFatherGitandClaude Opus 5 a1c2d49260 Drei Bilder konnte man schon -- nur sagte es niemand
Filipes Frage: „koennen die leute auch schon mehrere fotos schicken
wenn die im support was melden wollen?"

Technisch seit dem 02.10. (VanVans Meldung #11), und heute mehrfach
am laufenden Server nachgemessen. Beim Nachsehen auf der SEITE stand
aber:

    Knopf:       „Bild anhängen"          -- Einzahl
    Unterzeile:  „häng ein Bild dran"     -- Einzahl
    daneben:     (nichts)

Wer nicht zufaellig ein zweites Mal auf den Knopf tippt, schickt
eines. Aus seiner Sicht waere VanVans Meldung ungeloest -- und er
haette recht.

EINE MOEGLICHKEIT, VON DER MAN NICHTS WEISS, GIBT ES NICHT. Das ist
dieselbe Sorte wie ein Knopf, der eine Absage holt, nur andersherum:
Dort verspricht die Oberflaeche zu viel, hier zu wenig. Beides
kostet denselben Menschen dieselbe Zeit.

GEAENDERT

    Knopf:       „Bilder anhängen"
    Unterzeile:  „häng Bilder dran"
    daneben:     „bis zu 3 Bilder"        -- bevor man etwas waehlt
    nach einem:  „eins.png · 24 KB · noch 2 möglich"

Die letzte Zeile ist die wichtigere von beiden: „eins.png · 24 KB"
allein sagt nicht, dass ein zweites geht -- und genau an dieser
Stelle hoert jemand auf.

DIE ZAHL KOMMT VOM SERVER (`bilder_max`) und wird neu geschrieben,
sobald sie da ist. Ohne das stuende beim ersten Laden der
Vorgabewert dort -- heute zufaellig derselbe, morgen vielleicht
nicht. Eine Zahl, die zufaellig stimmt, ist keine Auskunft.

GEPRUEFT -- pruef-support-bilder 52 -> 56 ok

    der Knopf steht in der Mehrzahl („Bilder anhängen")
    und daneben steht, wie viele gehen („bis zu 3 Bilder")
    auch die Unterzeile sagt nicht mehr „ein Bild"
    und daneben steht, dass noch Platz ist
      („eins.png · 0 KB · noch 2 möglich")

Dazu gruen: pruef-zeichen 7 · pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 12:24:50 +02:00
DogFatherGitandClaude Opus 5 ae5b467e9a Der Supportverlauf: eine Zeitachse, eine Farbe je Runde
Filipe: „ich will diese komplette seite vom support viel
uebersichtlicher, profissioneller, jede runde soll auch immer eine
spezielle farbe haben und anders aufgestellt aufgeteilt sein damit
man einen viel besseren und krasseren ueberblick hat."

WAS VORHER DASTAND -- an einem Bild mit zwei Runden nachgesehen,
bevor eine Zeile angefasst wurde: vier Textzeilen untereinander,
alle in derselben Farbe. „RUNDE 1", Antwort, „Ging noch nicht · …",
„RUNDE 2". Bei fuenf Runden muss man die Runden ZAEHLEN, statt sie
zu sehen -- und wer spricht, stand nur als kleiner Name daneben.

VIER TEILE SIND NEU

 1. EINE LEISTE OBEN. Ein Punkt je Runde, in ihrer Farbe, mit ihrer
    Nummer -- und der Rand sagt, wie sie ausgegangen ist. Damit ist
    „wie oft ging es schon hin und her?" eine Frage des Hinsehens.
    Erst ab zwei Runden: bei einer waere sie ein Punkt neben nichts.

 2. EINE ZEITACHSE statt einer Liste. Jede Runde haengt mit einem
    Punkt an einer Linie in IHRER Farbe. Die Linie ist ein Rand an
    der Runde selbst, nicht am Behaelter -- so traegt jede ihr
    eigenes Stueck Achse.

 3. ZWEI SPRECHRICHTUNGEN je Runde, als getrennte Kaesten:
    „GEANTWORTET" in der Rundenfarbe, darunter „GING NOCH NICHT"
    (Bernstein) oder „GEHT WIEDER" (gruen) oder „WARTET AUF
    ANTWORT". Vorher standen beide Saetze als Absaetze untereinander
    und sahen gleich aus; man musste lesen, um zu wissen, von wem
    sie sind. Jetzt sagt es die Form.

 4. DIE LETZTEN ZWEI OFFEN, aeltere hinter „3 fruehere Runden
    zeigen". Die Leiste sagt ohnehin, wie viele es gab; im Wortlaut
    braucht es nicht alle. Zwei und nicht eine: Die letzte sagt, wo
    es steht, die vorletzte, woran es davor lag.

DIE FARBE WIRD GERECHNET, NICHT GEPFLEGT

`rundenTon(nr)` gibt 200 + ((nr-1) mod 4) * 32 Grad. Eine Liste mit
fuenf Farben waere die naheliegende Loesung und die falsche: Runde
sechs bekaeme keine. Diese Sorte Liste hat im Haus schon dreimal
etwas gekostet.

DER BEREICH IST ENG UND ABSICHTLICH: 200 bis 296 Grad, Blau ueber
Indigo nach Violett -- die Palette der Seite (babyblau mit lila) und
der Bereich, in dem KEINE Farbe nach „gut" oder „schlecht" aussieht.
Gruen und Bernstein sind fuer den AUSGANG reserviert; waere eine
Rundenfarbe rot, stuenden zwei Aussagen in einer Farbe.

AUGENSCHONEND: 52 % Saettigung, 64 % Helligkeit -- fuer alle Toene
gleich, und nur im CSS. Sonst waere Runde drei blasser als Runde
eins, und augenschonend ist das Gegenteil von zufaellig. Kein Neon,
kein Gluehen. Die Farbe ordnet Zeilen zu; sie schreit nicht.

UND DIE FARBE ALLEIN TRAEGT NICHTS: Die Nummer steht daneben, der
Ausgang in Worten. Fuer Vorleseprogramme gibt es statt elf Punkten
einen Satz.

EIN FUND UNTERWEGS: DIE MESSUNG MASS SEIT ZWEI TAGEN NICHTS

`mess-support-runde.mjs` schickte die Rueckmeldung noch als JSON.
Am 02.10. ist die Route auf den Kopf-Weg umgestellt worden
(`x-geht`, `x-text`); seither antwortete sie mit 400. Gemerkt hat es
niemand, weil diese Datei Bilder macht und keine Rueckgabewerte
prueft: Auf dem Bild stand danach EINE Runde statt vier, und das
sieht aus wie ein Ergebnis. Aufgefallen ist es erst, als die Bilder
vier Rundenfarben zeigen sollten.

Eine Messung, die nach einem Umbau stillschweigend etwas anderes
misst, ist schlimmer als keine -- man glaubt ihr. Sie meldet den
Fehlschlag jetzt mit Code und Text.

GEPRUEFT -- pruef-support-bilder 39 -> 52 ok

    die Leiste zeigt jede Runde (5 Punkte) · mit ihrer Nummer
    die ersten vier Runden haben vier verschiedene Farben (4)
    und die fuenfte faengt die Reihe wieder von vorn an
    Gegenprobe: sie sind nicht alle gleich (4 Farben)
    auch die Rundennummern tragen ihre Farbe (2 von 2)
    offen stehen die letzten zwei Runden (2)
    und die aelteren sind einen Griff entfernt
    jede Runde zeigt beide Seiten
    aufgeklappt stehen alle da (5) · und wieder zu
    auf 390 px ragt nichts heraus (0 px)
    bei einer einzigen Runde gibt es keine Leiste (0)

Die Gegenprobe „sie sind nicht alle gleich" ist die wichtigste:
Waere `--ton` nicht angekommen, waeren alle Punkte grau -- und „vier
Punkte" waere gruen gewesen, ohne dass eine Farbe zu sehen ist.
Gemessen wird die ANGEZEIGTE Farbe, nicht die Zahl im Attribut.

Dazu gruen: pruef-support 104 · pruef-css-klassen · pruef-zeichen 7 ·
pruef-fingermass 5.

Eine Schriftgroesse musste nachgebessert werden: .7rem sind 11,2 px,
und unter 11,5 px faengt im Haus die Grenze an, ab der man
zusammenkneift.

NUR DAS AGENTURHAUS: Die Supportseite liegt unter `/workspace`.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 11:54:46 +02:00
DogFatherGitandClaude Opus 5 ad5e758721 922 px auf einem 844-px-Bildschirm -- die halbe Antwort war zu wenig
VanVan im Support, Meldung #15: „Die Modis koennen die Antworten auf
die Bewerbungen im Bereich eure Aufgaben noch nicht einklappen. Das
wird mit der Zeit unuebersichtlich."

Heute Nacht habe ich dazu „Verstanden" gebaut: Gelesenes rutscht
hinter eine zugeklappte Zeile. Das ist richtig und war trotzdem nur
die halbe Antwort -- denn UNGELESENE stehen absichtlich offen da,
und davon hat ein Modi im Haus gerade neun.

GEMESSEN STATT GESCHAETZT, an seinem echten Bestand nachgebaut, auf
dem Handy (390 x 844 px):

    Band:            922 px   -- hoeher als das ganze Fenster
    Anteil der Seite: 49 %

Das IST ihr Satz. Mein Umbau loeste es erst NACH einem Griff auf
„Alle verstanden"; bis dahin stand die Wand unveraendert da.

GEAENDERT: Hoechstens drei stehen offen, der Rest ist einen Griff
entfernt („und 6 weitere"). Danach:

    Band:            566 px   -- passt in den Bildschirm
    nach einem Griff: 46 px   (zugeklappte Zeile)

WARUM NICHT NULL: Eine Absage, die man aufklappen muss, ist keine
Nachricht mehr -- das war die Begruendung vom 30.09., und sie gilt.
WARUM NICHT ALLE: siehe oben. Drei ist die Zahl, bei der Kopf,
Zeilen und Sammelknopf unter einem Bildschirm bleiben.

DIE NEUESTEN ZUERST -- der Server sortiert nach `entschieden_am
DESC`. Wer nicht aufklappt, hat die juengsten gesehen.

GEPRUEFT -- pruef-bewerbung-aufgaben 178 -> 184 ok

    mit fuenf Ungelesenen stehen drei offen (3)
      und der Rest ist einen Griff entfernt („und 3 weitere")
      das Band passt in den Bildschirm (436 px bei 1000 px)
    aufgeklappt stehen alle da (6, „Weniger zeigen")
    und wieder zu — der Knopf geht in beide Richtungen
    und die Probezeilen sind wieder weg — der Stand ist wie vorher

Die dritte Zeile ist die eigentliche Aussage: „drei Zeilen" waere
eine Zahl, „passt in den Bildschirm" ist der Zweck. Die letzte raeumt
die vier Probezeilen wieder weg -- ohne sie zaehlten die Pruefungen
darunter („1 aeltere Antwort", „2 aeltere Antworten") sechs statt
zwei und wuerden rot, ohne dass etwas kaputt ist.

Der Knopf geht in BEIDE Richtungen, und auch das steht da: Sonst
waere er ein Einwegschalter, und das faellt erst auf, wenn jemand
zurueckklappen will.

AUSSERDEM AN CASPERLINOS ECHTEN NEUN GEMESSEN (Kopie der Datenbank,
eigener Port, nichts im Live-System): neun Antworten, alle
ungelesen; „Verstanden" nimmt genau eine; „Alle verstanden" den
Rest; nachlesbar bleiben alle neun; ein zweiter Druck zaehlt null;
eine fremde Nummer gibt 404.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 11:45:03 +02:00
DogFatherGitandClaude Opus 5 63211252d2 VanVans Satz hatte zwei Haelften -- gemessen war eine
Meldung #11, Runde 2, woertlich:

    „man kann nicht mehrere Bilder zum hinzufuegen AUSWAEHLEN.
     Und wenn man es NACHEINANDER versucht hinzuzufuegen wird das
     Bild immer nur ersetzt"

Das NACHEINANDER stand seit gestern in der Pruefung -- es war die
Haelfte, die ich kaputt gebaut hatte und die mir deshalb im Kopf
war. Das AUSWAEHLEN nicht: drei Dateien in EINEM Griff, so wie der
Dateidialog sie uebergibt, wenn man sie mit gedrueckter Taste
markiert. Das haengt am `multiple` im Feld, und ohne Messung war es
eine Behauptung im HTML.

Aufgefallen beim Durchgehen ihres Satzes Wort fuer Wort, nachdem
Filipe auf den Screenshot gezeigt hat. Kaputt war nichts -- aber
unbewiesen, und das ist derselbe Zustand wie ungeprueft, nur mit
besserem Gefuehl.

NEU GEPRUEFT

    drei auf einen Griff ausgewaehlt ergeben drei (3)
      und zwar in der Reihenfolge des Dialogs
      das Feld laesst Mehrfachauswahl ausdruecklich zu (multiple)

Die letzte Zeile ist die Gegenprobe zur ersten: Ohne `multiple`
gaebe der Browser nur EINE Datei weiter, egal wie viele man
markiert -- und die Drei darueber koennte auch aus drei einzelnen
Griffen stammen. Gemessen wird deshalb das Merkmal selbst.

Davor wird ausdruecklich alles geleert („Alle weg"), sonst misst die
Zeile, was vorher schon dastand.

GEPRUEFT -- pruef-support-bilder 36 -> 39 ok

AUSSERDEM HEUTE AM LAUFENDEN SERVER NACHGEMESSEN (Meldung #11, auf
einer Kopie der echten Datenbank, eigener Port, nichts im
Live-System):

    er nennt die Grenze: 3
    die Meldung geht durch (201) · alle drei haengen dran (3)
    jedes kommt in SEINER Reihenfolge und mit SEINEM Typ zurueck (3/3)
    vier werden abgelehnt, mit einem Satz
    der alte Einzelbild-Weg ist weg (404) — es gibt nur noch einen

Und: Die Dateien, die VanVans Browser laedt, sind Byte fuer Byte die
geprueften -- support.js und support.css haben live dieselbe
Pruefsumme wie hier.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 11:35:32 +02:00
DogFatherGitandClaude Opus 5 ef911691b7 Der zweite Weg ist weg -- nicht nur sein Knopf
VanVan im Support, Meldung #8: „Wenn man auf ich fange an drueckt
steht dort in Bearbeitung und wenn man auf fertig drueckt dann wird
es zu erledigt. DIE AUFGABE BLEIBT ABER IM STATUS OFFEN STEHEN."

GESTERN HABE ICH DIE HALBE ARBEIT GEMACHT und daneben eine Ausrede
geschrieben. Die zwei Knoepfe kamen weg, und in den Kommentar kam:

    „Der Weg `/mein-stand` bleibt bestehen -- er ist die Schranke,
     falls ihn jemand direkt anspricht."

Eine Route ist keine Schranke gegen sich selbst. Sie setzte
weiterhin NUR `aufgaben_zuteilung.zustand` und liess
`aufgaben.status` stehen -- also genau den Widerspruch, den VanVan
beschrieben hat. Ich hatte ihn unsichtbar gemacht, nicht
abgeschafft: kein Knopf mehr, das Verhalten unveraendert im System.

GEFUNDEN BEIM NACHMESSEN AM LAUFENDEN SERVER, nicht beim Schreiben.
Filipe hat auf den Screenshot gezeigt und gesagt, es sei noch nicht
in Ordnung. Statt meine Pruefungen zu zitieren habe ich die Route
gelesen -- und dort stand es.

NACHGEMESSEN, BEVOR SIE WEGKAM: Kein einziger Aufruf mehr im
ausgelieferten Browsercode (grep ueber alle JS- und HTML-Dateien des
Workspace). Nur zwei Pruefungen benutzten sie.

UND EINE DAVON NICKTE DEN FEHLER AB. In pruef-zuteilung stand:

    Bea setzt "in Bearbeitung" (HTTP 200)
    und danach "erledigt" (HTTP 200)

Zwei gruene Haken ueber genau dem Verhalten, das gemeldet wurde --
weil sie nur den Rueckgabewert ansahen und nie den Aufgabenstatus
daneben. Eine Pruefung, die nur eine Haelfte misst, kann den
Widerspruch gar nicht finden. Jetzt steht dort:

    Bea setzt "in Bearbeitung" (HTTP 200)
      und BEIDES steht auf "in Arbeit" (Aufgabe arbeit,
      Zuteilung arbeit) — das war VanVans Befund
    und danach "erledigt" (HTTP 200)
      und wieder beides (Aufgabe erledigt, Zuteilung erledigt)

WAS JETZT GILT: `PATCH /workspace/api/aufgaben/:id` mit `{ status }`.
Er setzt den Status UND zieht die Zuteilung mit
(`zuteilungenNachStatus`), kennt dieselbe Sperre fuer dauerhafte
Aufgaben und dieselbe Rechtepruefung. Eine Frage, eine Antwort.

ENTFERNT STATT AUSKOMMENTIERT -- dieselbe Entscheidung wie bei
`/vorlagen/hilfe` am 01.09.: Eine Route, die niemand mehr aufruft,
wird beim naechsten Mal fuer lebenden Code gehalten und mitgepflegt.

EIN SCHRECKMOMENT UNTERWEGS, der sich als Messfehler herausstellte:
Nach der Umstellung meldete pruef-bewerbung-aufgaben eine 404 beim
Abhaken -- also der Verdacht, dass eine ZUGETEILTE Aufgabe ueber den
Statusweg gar nicht erreichbar ist und ich gerade etwas kaputt
gemacht haette. Nachgemessen statt geglaubt: Die Aufgabe steht in
ihrer Liste, der PATCH antwortet 200. Die rote Zeile war eine
DRITTE Stelle, die ich beim Umstellen uebersehen hatte und die noch
auf die alte Route zeigte. Zwei Minuten Messung statt einer Stunde
Suche an der falschen Stelle.

GEPRUEFT

  pruef-zuteilung             ok, mit zwei neuen Zeilen, die BEIDE
                              Zustaende messen
    den zweiten Weg (mein-stand) gibt es nicht mehr (404)
  pruef-bewerbung-aufgaben    178 ok
  pruef-struktur              102 ok, 414 -> 413 Routen
  pruef-aufgabenbrett · pruef-modi-katalog 159 ·
  pruef-aufgaben-vorlagen 60

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 11:31:18 +02:00
DogFatherGitandClaude Opus 5 2270f0de91 Der „Anpassen"-Knopf war nur an EINEM der beiden Bretter geprueft
Beim Nachsehen zu VanVans Meldung #6 aufgefallen, nicht beim Bauen:
Der Knopf haengt an ZWEI Kartenarten -- an den Creator-Vorlagen
(vorlagenbrett.js:459) und am Team-Katalog (:1220). Im Browser
gemessen war nur die erste.

UND DIE ZWEITE IST DIE, DIE VANVAN BENUTZT. Die Creator-Vorlagen
stehen auf „Aufgaben" und richten sich an Betreuer; der Katalog
steht auf „Eure Aufgaben", und dort verteilt die rechte Hand an die
Modis. Genau das war ihre Meldung.

Dass man diese beiden Bretter verwechselt, ist in diesem Haus schon
passiert: In pruef-bewerbung-aufgaben steht es seit dem 30.09. als
Messfehler notiert, „der wie ein Befund aussieht". Diesmal waere es
andersherum gewesen -- ein gruener Haken ueber einem Weg, den
niemand geprueft hat.

GEMESSEN HAT ES NICHTS KAPUTTES GEFUNDEN: Der Katalogzweig
funktioniert. Aber er war unbewiesen, und das ist derselbe Zustand
wie „ungeprueft" -- nur mit besserem Gefuehl.

DIE GEGENPROBE ZUM ANDEREN BRETT STECKT JETZT DRIN. Ein Creator
bekommt den „dauerhaft"-Haken NICHT (geprueft in
pruef-aufgaben-vorlagen), die Leitung MUSS ihn bekommen (geprueft
hier). Zwei Pruefungen, die denselben Unterschied von beiden Seiten
messen -- erst dann ist es eine Regel und nicht ein Zufall.

GEPRUEFT -- pruef-modi-katalog 150 -> 159 ok

  jede Katalogkarte hat einen „Anpassen …"-Knopf (12 von 12)
  das Fenster hat Frist und Anmerkung
  und die Leitung bekommt den „dauerhaft"-Haken
  die Frist der Vorlage steht als Vorgabe drin (2026-10-05,
    fruehestens 2026-10-03)
  mit Haken wird die Frist gesperrt
  die angepasste Aufgabe liegt in ihrer Liste (3 -> 4)
  sie ist wirklich dauerhaft · und hat keine Frist
  die Anmerkung steht als Notiz dabei

  Die letzten drei fragen die DATENBANK, nicht den Bildschirm. Was
  auf dem Brett steht, ist eine Darstellung; was in der Aufgabe
  steht, gilt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 11:04:03 +02:00
DogFatherGitandClaude Opus 5 3d859cbed5 Eine untaugliche Zweitfassung erkennt der Server selbst
NACHGEMESSEN AN DEN SECHS, DIE HEUTE NACHT LIVE ENTSTANDEN SIND --
vier tragen das Loch am Anfang, weil sie gebaut wurden, bevor es
bekannt war:

    387,6 s Zeitachse fuer wenige Sekunden Ton
    164,2 s
    134,1 s
     63,8 s
      9,7 s  (in Ordnung)
      3,3 s  (in Ordnung)

Sie gehoeren dem Dienstbenutzer; von aussen sind sie nicht
wegzuraeumen. Und mit „gibt es schon, dann weiter" waeren sie fuer
immer so geblieben.

EIN SCHALTER „alles neu ab Fassung 2" WAERE DIE BEQUEME LOESUNG und
die falsche: eine Zahl, die jemand hochzaehlen muss, wird beim
naechsten Mal vergessen. Gefragt wird deshalb die DATEI SELBST --
nach dem, was schiefgehen kann: Passt ihre Zeitachse zu der
Tonmenge, die sie traegt? AAC packt 1024 Abtastwerte in einen
Rahmen; Rahmenzahl mal 1024 durch die Abtastrate ist die echte
Laenge. Mehr als anderthalb Sekunden darueber heisst: Loch.

Was nicht passt, wird beim naechsten Nachruestlauf weggeraeumt und
neu gebaut -- einmal, denn danach passt es.

ZWEI FEHLER IN DIESER FUNKTION, BEIDE VON DER GEGENPROBE GEFUNDEN

Und beide waeren still geblieben:

 1. ffprobe GIBT DIE WERTE IN SEINER REIHENFOLGE AUS, nicht in
    meiner: erst `sample_rate`, dann `nb_frames`. Ich hatte
    `[rahmen, rate, dauer]` destrukturiert und damit 48000 Rahmen
    bei 95 Hz gerechnet -- eine „echte Laenge" von einer halben
    Million Sekunden. Die Funktion haette JEDE Datei fuer tauglich
    erklaert, immer. Gelesen wird jetzt mit Namen.

 2. DER DATEINAME FEHLTE IM AUFRUF. ffprobe antwortete „You have to
    specify one input file", der `catch` machte daraus ein
    freundliches „taugt" -- und wieder sagte die Funktion zu allem
    ja.

Das ist zweimal dieselbe Sorte: gruen und wertlos. Gefunden hat es
nicht das Lesen, sondern die Frage „kann sie ueberhaupt NEIN
sagen?". Genau dafuer gibt es die Gegenprobe.

WIE MAN EINE DATEI MIT LOCH NACHSTELLT -- UND WIE NICHT

`-itsoffset 40` war der naheliegende Weg und ergab 2,5 s: Der
MP4-Baukasten rechnet einen reinen Anfangsversatz wieder heraus.
Dasselbe mit `-copyts`, `-output_ts_offset` und `-muxdelay`. Was
bleibt, ist eine Zeitachse, die laenger ist als ihr Ton -- und das
stellt eine stumme Bildspur von 40 Sekunden her. Der Weg dorthin
ist ein anderer als bei `MediaRecorder`; die ZAHLEN, die die
Funktion liest, sind dieselben.

GEPRUEFT -- pruef-chat-anhaenge 164 -> 168 ok

  eine Fassung mit zu langer Zeitachse nachgestellt (40,0 s)
  und sie wird als untauglich erkannt
  der Nachruestlauf ersetzt sie (40,0 s → 2,5 s)
  und die neue gilt als tauglich — er wandelt sie nicht ewig weiter

Die letzte Zeile ist die zweite Gegenprobe: Ein Lauf, der bei jedem
Durchgang alles neu wandelt, waere eine Warnung, die immer kommt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 02:04:23 +02:00
DogFatherGitandClaude Opus 5 ff48a0a6ef Das Loch am Anfang der Sprachnachrichten -- und ein halb fertiges Stueck
NACHGEMESSEN AN EINER ECHTEN NACHRICHT AUS DEM HAUS, nachdem die
Zweitfassungen heute Nacht live entstanden waren. `mumqbw6v….webm`
vom 29.09., 46 Pakete:

    Paket 1 bei   0,000 s
    Paket 2 bei  61,116 s
    ...
    Paket 46 bei 63,756 s

2,76 Sekunden Ton, verteilt ueber eine Zeitachse von 63,8 Sekunden.
Dazwischen ein Loch von einer Minute. `MediaRecorder` setzt diesen
Versatz selbst; die Datenbank kennt ihn nicht (dort steht die Angabe
des Absenders: 2910 ms).

WAS DAS FUER DEN HOERER HEISST: Das Abspielgeraet zeigt 1:03,
springt beim Antippen in eine Minute Stille und faengt erst danach
an. Auf einem Handy ueber Mobilfunk sieht genau das aus wie „laedt
die ganze Zeit" -- Miss' Satz aus Runde 5, woertlich.

Das war also nicht nur der Behaelter. Die Umwandlung von heute Nacht
hat das Loch brav mituebernommen: 63,8 s Zeitachse, 32 KB Inhalt.

GEAENDERT: `-af asetpts=N/SR/TB` vergibt die Zeitstempel neu,
fortlaufend ab null. An der echten Datei nachgemessen -- der
Toninhalt bleibt unveraendert (260 KiB dekodiert vorher wie
nachher), nur die Laenge geht von 63,8 s auf 2,76 s. Es wird nichts
abgeschnitten, sondern ein Loch geschlossen.

UND EIN ZWEITER FUND, von der Pruefung und nicht vom Nachdenken

Sie holte die zweite Fassung ab und bekam 44 BYTES. ffmpeg legt die
Zieldatei sofort an und fuellt sie danach -- bei `+faststart`
schreibt es sie am Ende noch einmal um. Die Stelle, die fragt „gibt
es die zweite Fassung?", sah in dieser Zeit eine Datei, die es gibt
und die nichts enthaelt. Wer dann zuhoert, bekommt ein Bruchstueck.

Jetzt entsteht sie unter `….m4a.teil` und wird erst am Ende
umbenannt. Umbenennen im selben Ordner ist EIN Schritt: entweder
vollstaendig da oder gar nicht. Der Bruchstuecknamen endet
ausdruecklich NICHT auf `.m4a`, sonst waere die Luecke nur
umbenannt -- und deshalb muss `-f mp4` dabeistehen, weil ffmpeg das
Format sonst an der Endung waehlt und `.teil` nicht kennt. Auch das
hat die Pruefung gefunden: Der erste Versuch mit Umbenennen erzeugte
gar keine Datei mehr.

WAS DIE PRUEFUNG JETZT MISST -- UND WAS NICHT

Sie vergleicht NICHT mehr die Zeitachsen beider Dateien. Genau das
war mein erster Anlauf, und er haette das Loch durchgewunken: Wenn
es mitwandert, sind beide Zeitachsen gleich lang und alles ist
gruen. Gefragt wird jetzt nach dem TON -- wie viele Bytes
herauskommen, wenn man beide dekodiert (231 KiB zu 231 KiB) -- und
danach, ob die Zeitachse zu dieser Tonmenge passt (2,46 s fuer
2,46 s Ton).

Ein dritter kleiner: `tonBytes` las die Rueckgabe von
`execFileSync`. ffmpeg schreibt seine Zusammenfassung aber auf
stderr -- die Messung meldete fuer beide Dateien 0 KiB. Rot, und zu
Recht: Sie hat nichts gemessen.

WAS BEWUSST OFFEN BLEIBT: Eine Aufnahme, die schon als MP4
hereinkommt (seit dem 02.10. der Normalfall), wird nicht
umgewandelt -- und traegt ein solches Loch, falls sie eines hat,
weiter. Dass sie eines haette, ist nicht gemessen: Seit der
Umstellung gibt es keine einzige neue Aufnahme. AAC noch einmal nach
AAC zu wandeln kostet Qualitaet fuer ein Problem, das ich nicht
beobachtet habe. Faellt es auf, ist die Stelle bekannt.

GEPRUEFT -- pruef-chat-anhaenge 163 -> 164 ok

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 01:55:46 +02:00
DogFatherGitandClaude Opus 5 d70d00cedc Jede Sprachnachricht in einer Fassung, die JEDES Geraet abspielt
Miss im Support, Meldung #12 -- fuenf Runden seit dem 23.09.: „Bei
mir laesst sich die Nachricht nicht abspielen." Zuletzt: „Jetzt laedt
es die ganze Zeit." Bei allen anderen ging es.

GEMESSEN, BEVOR GEBAUT WURDE

  · Alle sechs Sprachnachrichten im Haus sind audio/webm (Opus).
  · Miss' Geraet: iPhone, iOS 18.7, WebKit.
  · Seit der Umstellung am 02.10. (neue Aufnahmen bevorzugen MP4)
    wurde KEINE EINZIGE neue aufgenommen. Ihr Problem betrifft also
    ausschliesslich die sechs alten Dateien -- und jede kuenftige aus
    einem Firefox, der nichts anderes kann.

WAS ICH NICHT MESSEN KONNTE, und das gehoert dazu: Ob WebKit
WebM/Opus abspielen kann, laesst sich auf diesem Rechner nicht
nachsehen -- Playwrights WebKit startet hier nicht (libegl.dll
fehlt). Die Vermutung „iPhones koennen kein WebM" ist begruendet,
aber von mir nicht gemessen.

GENAU DESHALB STELLT DIE LOESUNG DIE FRAGE NICHT. Statt zu raten,
welches Geraet welchen Behaelter kann, legt der Server neben jede
Sprachnachricht eine zweite Fassung in dem Format, bei dem sich seit
zwanzig Jahren alle einig sind: AAC in MP4. Gibt es sie, wird sie
abgespielt -- bei jedem, nicht nur auf iPhones. Kein Geraetename im
Code, keine Liste, die altert.

  helfer-ffmpeg.mjs     ffmpeg finden, umwandeln, drei Ausgaenge
  beim Hochladen        nebenher, nicht davor: Die Nachricht wartet
                        nicht auf ffmpeg
  toeneNachruesten()    das Netz darunter -- fuer die sechs von
                        frueher und fuer den Fall, dass eine
                        Umwandlung einmal nicht geklappt hat
  ?form=mp4             dieselbe Route, dieselben Rechte; eine
                        zweite haette dieselbe Sichtbarkeitspruefung
                        ein zweites Mal gebraucht

ffmpeg IST ABGESPROCHEN INSTALLIERT (Debian 7.1.5, auf Nachfrage
freigegeben). Fehlt es, passiert nichts Schlimmes: Die
Sprachnachricht geht wie bisher im Originalformat hinaus, und es
steht EINMAL eine Zeile im Protokoll -- nicht bei jedem Hochladen.

DREI ENTSCHEIDUNGEN, DIE NICHT NAHELIEGEND WAREN

 1. `-movflags +faststart` IST NICHT KOSMETIK. Ohne es steht die
    Inhaltsuebersicht einer MP4 am ENDE. Das Abspielgeraet muss dann
    erst bis ans Ende lesen, bevor es anfangen kann -- genau das
    „laedt die ganze Zeit" aus Miss' Runde 5. Geprueft wird die
    Reihenfolge der Kaesten in der Datei, nicht die Zeile im Aufruf.

 2. DAS ORIGINAL BLEIBT LIEGEN. Ohne `?form=mp4` kommt weiter die
    WebM. Sie ist das, was aufgenommen wurde; sie durch eine
    Umrechnung zu ersetzen hiesse, das Original wegzuwerfen.

 3. EIN GEMEINSAMER LOESCHER. Zwei Stellen entfernen Anhaenge
    (Gespraech wegraeumen, Nachricht zuruecknehmen). Beide nahmen
    genau eine Datei -- ab heute waere bei jeder geloeschten
    Sprachnachricht eine m4a liegengeblieben, ohne Zeile, die auf
    sie zeigt. Dieselbe Luecke hatte ich gestern bei den
    Supportbildern gefunden; hier steht sie von Anfang an an EINER
    Stelle.

ZWEI FUNDE DER PRUEFUNG, BEIDE MEINE EIGENEN

 · `anhang_datei` STAND NICHT IN DER ABFRAGE der Nachrichtenliste.
   Die Funktion, die auf der Platte nachsieht, bekam deshalb nichts
   und sagte brav „gibt es keine zweite Fassung" -- fuer JEDE
   Nachricht. Alles war gebaut, nichts kam an. Gefunden hat das die
   Pruefung, nicht das Lesen.
 · Mein erster Anlauf mass die Aufnahme ueber den Knopf -- und die
   ist seit dem 02.10. schon MP4, braucht also gar keine zweite
   Fassung. Die Pruefung wurde rot und hatte recht: Gemessen werden
   muss der Fall, den es bei Miss gibt. Jetzt nimmt sie ausdruecklich
   eine WebM auf.

Dazu zweimal derselbe alte Tritt: ein Gegen-Apostroph in einem
Kommentar INNERHALB eines Template-Literals. Der Server startet dann
gar nicht. Steht jetzt als Warnung an beiden Stellen.

GEPRUEFT -- pruef-chat-anhaenge 146 -> 163 ok

  Eine echte WebM/Opus-Aufnahme (31 972 Bytes) wird hochgeladen; die
  zweite Fassung entsteht von selbst und kommt als audio/mp4 heraus,
  mit „ftyp"-Marke, mit Accept-Ranges. ffprobe sagt: Original Opus,
  Zweitfassung AAC, 2,40 s gegen 2,46 s. Die Inhaltsuebersicht steht
  bei Byte 32, die Tondaten ab 1270 -- also vorne. Beim Loeschen
  gehen beide Dateien. Gegenproben: ein Bild bekommt keine zweite
  Fassung; eine halbierte Laenge waere aufgefallen; das Original
  bleibt unter seiner eigenen Adresse abrufbar.

  Der dritte Ausgang hat einen eigenen Zaehler: Fehlt ffmpeg, steht
  „KONNTE NICHT NACHSEHEN" mit Anleitung da -- nicht gruen und nicht
  rot. Und der Block raeumt hinter sich auf: Mein Probebild liess
  eine spaetere Pruefung rot werden, weil es die Gespraechsliste
  veraendert hatte. Eine Pruefung, die den Stand fuer die naechste
  verschiebt, ist schlimmer als keine.

  Dazu gruen: pruef-struktur 102 (92 Module) · pruef-ports 10 ·
  pruef-gifs 17 · pruef-treffchat 114 · pruef-chat-optik ·
  pruef-aufbewahrung 45.

NUR DAS AGENTURHAUS? NEIN -- der Chat gehoert beiden Haeusern, und
die Aenderung gilt fuer beide gleich. Sie aendert nichts an
Sichtbarkeit oder Rechten: Wer eine Nachricht hoeren darf, hoert sie
jetzt in einem Format, das sein Geraet kann.

OFFEN BLEIBT DIE ANTWORT VON MISS. Ob es bei ihr jetzt laeuft, weiss
nur sie -- deshalb steht ihre Meldung weiter offen und nicht auf
erledigt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 01:41:34 +02:00
DogFatherGitandClaude Opus 5 1ce2c3785e Der Hinweis an der Anmeldung sagte seit dem 01.10. das Gegenteil
VanVan im Support, Meldung #5, zweite Runde: „Man kann sich jetzt nur
noch über die richtige Schaltfläche anmelden. Das funktioniert jetzt.
Aber wenn man sich 2x versucht über den falschen Button anzumelden,
dann kommt ein irreführender Text wo steht, dass die Auswahl oben
nicht schuld ist."

SIE HAT RECHT -- UND DER GRUND IST MEINE EIGENE AENDERUNG

Auf der Crew-Wand stand ab dem zweiten Fehlversuch: „Zugangscode
stimmt nicht. Achte auf die Bindestriche -- die Auswahl oben ist
nicht schuld."

Das war am 20.09.2026 richtig. Dort gab es den STILLEN ZUGANG: Die
rechte Hand und die Modis kamen ueber die Codekennung herein, egal
welche Kachel sie antippten. Der Satz „Stimmt die Auswahl oben?"
haette sie in eine Schleife geschickt -- alle Kacheln durchprobieren,
acht Fehlversuche, Adresse gesperrt. Ein Hinweis, der die Sperre
herbeifuehrt, gegen die er helfen soll.

Mit VanVans ERSTER Runde derselben Meldung ist der stille Zugang
weggefallen („es soll fest sein"). Nachgemessen in workspace.js: Die
Kandidaten kommen seither aus `WHERE rolle = ?`, auf beiden Waenden.
Die Kachel entscheidet ueberall -- und der Satz sagte ab diesem Tag
das Gegenteil der Wahrheit, genau an der Stelle, an der jemand
feststeckt.

DAS IST DIE SORTE FEHLER, DIE EIN UMBAU HINTERLAESST: Nicht der neue
Code war falsch, sondern ein Satz drei Dateien weiter, dessen
Voraussetzung er entfernt hat. Er stand sogar ausfuehrlich begruendet
da -- und die Begruendung las sich beim Umbau wie eine Bestaetigung,
weil sie von einem Zustand sprach, den es nicht mehr gab. Gefunden
hat ihn kein Prueflauf, sondern VanVan beim Benutzen.

GEAENDERT: Ein Satz fuer beide Waende. Die Fallunterscheidung nach
Wand ist weg -- es gibt nur noch eine Regel, also auch nur noch eine
Auskunft. Der Hinweis auf die Bindestriche bleibt; er galt nie nur
fuer eine Wand.

  „Zugangscode stimmt nicht. Stimmt die Auswahl oben? Ein Code
   gehört immer zu genau einer davon – und achte auf die
   Bindestriche."

GEPRUEFT -- pruef-modi-verborgen 87 -> 94 ok

  Im echten Browser, beide Waende (crew-index.html und index.html),
  je zweimal mit einem falschen Code:
    · die Waende sind wirklich verschieden (gate--crew true/false)
    · „nicht schuld" steht nirgends mehr
    · stattdessen die Frage nach der Auswahl -- die dort seit dem
      01.10. wirklich gilt (Abschnitt 1 derselben Datei misst das)
    · derselbe Satz auf beiden Waenden
    · Gegenprobe: nach dem ERSTEN Versuch steht er noch nicht da,
      dort steht die kurze Absage. Ein Hinweis, der immer kommt,
      waere keiner.

  DIE VERSUCHSSPERRE WIRD VOR DER MESSUNG GELEERT. Acht Fehlversuche
  je Adresse in zehn Minuten -- die Abschnitte davor verbrauchen
  welche, und ab dem neunten stuende „Zu viele Versuche" statt des
  Satzes. Das waere ein roter Haken ueber die Messumgebung gewesen,
  nicht ueber das Programm.

  Dazu: pruef-struktur 102 ok.

BEIDE HAEUSER BETROFFEN, und das ist hier richtig: Es ist dieselbe
Anmeldung mit derselben Regel. Nachgewiesen wird genau das -- der
Satz ist auf beiden Waenden derselbe, und er stimmt auf beiden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 00:16:05 +02:00
DogFatherGitandClaude Opus 5 f2f11e8091 Gelesene Antworten rutschen zur Seite -- statt sich zu stapeln
VanVan im Support, Meldung #15: „Die Modis können die Antworten auf
die Bewerbungen im Bereich eure Aufgaben noch nicht einklappen. Das
wird mit der Zeit unübersichtlich."

WARUM ES NICHT EINFACH EIN SCHALTER GEWORDEN IST

Am 30.09. habe ich diesen Kasten absichtlich NICHT einklappbar
gebaut, und die Begruendung steht woertlich im Quelltext: „Eine
Antwort, die man erst aufklappen muss, ist wieder keine." Sie ist
richtig -- fuer eine Antwort, die man noch nicht gelesen hat. Danach
ist sie falsch herum, und genau das meldet VanVan.

Ein Schalter, der alles wegklappt, haette die naechste Absage
mitversteckt: die Zeile, derentwegen der Kasten ueberhaupt
entstanden ist. Deshalb nicht „einklappbar", sondern GELESEN:

  · Was noch niemand quittiert hat, steht offen da -- wie bisher.
  · „Verstanden" schiebt eine Zeile hinter „N ältere Antworten",
    zugeklappt, jederzeit wieder aufzumachen. Nichts wird geloescht;
    eine Absage samt Begruendung wegzuwerfen, weil jemand sie einmal
    gelesen hat, waere das Gegenteil des Umbaus vom 30.09.
  · Ab zwei offenen Antworten gibt es „Alle N verstanden" -- wer nach
    dem Urlaub sieben vorfindet, soll nicht siebenmal tippen, und
    sieben Anfragen waeren sieben Gelegenheiten, dass eine verloren
    geht.

AM MENSCHEN, NICHT AM GERAET

`gesehen_am` steht in `vorlagen_bewerbungen`, nicht im
Browserspeicher. „Habe ich das gelesen?" ist eine Frage ueber die
Person: Sonst waere dieselbe Antwort auf dem Handy wieder neu,
nachdem man sie am Rechner gelesen hat -- und das waere genau die
Unuebersichtlichkeit, die gemeldet wurde, nur eine Tuer weiter.

Das AUFKLAPPEN der aelteren bleibt dagegen im Augenblick: kein
Zustand, den man mitschleppt. Nach dem Neuladen ist wieder zu.

GEGEN FREMDE ZEILEN GESCHUETZT: Nur die eigenen, nur die
beantworteten, 404 statt 403 -- wie ueberall im Haus. Ein zweites
„Verstanden" zaehlt nicht noch einmal, sonst wanderte die Zeile bei
jedem Klick ans Ende und man saehe nicht mehr, wann man sie wirklich
gelesen hat.

WAS ICH FALSCH ERWARTET HATTE: Meine erste Pruefung verlangte, dass
nach einem „Verstanden" OBEN NICHTS mehr steht. Sie wurde rot --
Frida hatte zwei Antworten, und der Knopf gilt je Zeile. Die
Pruefung hatte recht; dass er nur seine eigene Zeile nimmt, ist das
gewollte Verhalten und steht jetzt als Aussage dort.

NEBENBEI: Ein 11,2-px-Pfeil (gemeldet von pruef-css-klassen). Unter
11,5 px faengt im Haus die Grenze an, ab der man zusammenkneift --
dass es „nur ein Zeichen" ist, aendert daran nichts.

GEPRUEFT

  pruef-bewerbung-aufgaben  164 -> 178 ok
    Im echten Browser, am Handy (390 px): die ungelesene Antwort
    steht offen mit „Verstanden", danach ist genau diese eine Zeile
    weg (2 -> 1), sie liegt hinter „1 ältere Antwort", zugeklappt
    wird sie gar nicht erst gebaut, aufgeklappt steht sie samt
    Begruendung wieder da, „Alle verstanden" raeumt den Rest, nach
    dem Neuladen gilt beides weiter als gelesen und ist wieder zu.
    Am Server: fremde Antwort 404, erfundene Nummer 404, zweites
    „Verstanden" zaehlt 0.
  pruef-struktur 102 ok, 414 Routen (eine neue) ·
  pruef-css-klassen · pruef-zeichen 7 · pruef-modi-katalog 150 ·
  pruef-vorlagen 24 · pruef-aufgaben-vorlagen 60

NUR DAS AGENTURHAUS. „Eure Aufgaben" liegt unter `/workspace`; am
Crew-Haus aendert sich keine Zeile.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-03 00:10:15 +02:00
DogFatherGitandClaude Opus 5 018d02c3b8 Vorlagen anpassen: Frist, dauerhaft und eine Anmerkung
VanVan im Support, Meldung #6, zweite Haelfte -- der Rest, der heute
frueh ausdruecklich offen stehen blieb: „Bei den Vorlagen laesst sich
weder die Frist anpassen noch ‚dauerhaft' einstellen, und eine
Anmerkung fehlt auch."

EIN ZWEITER KNOPF, NICHT EIN FENSTER FUER ALLE

„An alle" verteilt zwoelf Aufgaben mit einem Druck. Haette jedes
Uebernehmen jetzt ein Fenster geoeffnet, waere der haeufige Weg
langsamer geworden, um den seltenen moeglich zu machen. Neben
„Uebernehmen" steht deshalb „Anpassen …" -- an den Creator-Vorlagen
und am Katalog, aus derselben Funktion.

DAS FENSTER IST DAS DES HAUSES

`frageNach` kann seit heute ein DATUM und einen HAKEN, die Anmerkung
konnte es als `grund` schon. Ein eigener kleiner Dialog in
vorlagenbrett.js waere der zweite im Haus gewesen -- und der, in dem
beim naechsten Mal Esc, Fokusfalle oder der Abbruch fehlen. Beide
Felder sind standardmaessig aus; fuer die dreissig anderen Aufrufe
aendert sich nichts.

DREI ENTSCHEIDUNGEN, DIE NICHT NAHELIEGEND WAREN

 1. DIE ANMERKUNG WIRD EINE NOTIZ (`aufgaben_notizen`), kein Anhang
    an der Beschreibung. Sie traegt damit, von wem sie stammt, und
    die Aufgabe zeigt sie ohnehin an. In die Beschreibung geschrieben
    waere sie von der Vorlage nicht mehr zu unterscheiden -- und
    dieselbe Vorlage haette beim naechsten Mal einen anderen Text.

 2. EINE DAUERHAFTE AUFGABE BEKOMMT KEINE FRIST, auch wenn eine
    mitgeschickt wird. Sie waere ab dem naechsten Tag fuer immer
    ueberfaellig, und eine Warnung, die immer kommt, ist keine mehr.
    Dieselbe Regel steht seit Langem im Aenderungsweg; haette sie
    hier gefehlt, gaebe es zwei Antworten auf dieselbe Frage.
    Im Fenster wird das Datum deshalb GRAU, sobald der Haken sitzt --
    ein Datum, das dasteht und nicht gilt, ist schlimmer als keins.

 3. „DAUERHAFT" DARF NUR, WER VERTEILEN DARF. Eine dauerhafte Aufgabe
    laesst sich nicht abhaken (Commit von heute frueh); wer sie sich
    selbst anlegen koennte, haette etwas, das er nie wieder loswird.
    Der Haken fehlt deshalb im Fenster eines Creators -- und
    abgelehnt wird trotzdem am Server, nicht nur ausgeblendet.

EIN FUND, DEN DIE PRUEFUNG GEMACHT HAT

`Number(tage) || 7` -- die Untergrenze des Datumsfeldes lag dadurch
sieben Tage in der Zukunft statt heute, weil Null in JavaScript
unwahr ist. Die VORGABE („in 1 Tag") lag damit UNTER der erlaubten
Grenze: Wer das Fenster oeffnete und einfach „Uebernehmen" drueckte,
bekam eine Absage. `Number.isFinite` fragt, ob eine Zahl da ist, und
nicht, ob sie wahr ist -- derselbe Unterschied wie bei `kill -0`.

NEBENBEI BEHOBEN: Ein gerades Anfuehrungszeichen in einem deutschen
Fehlersatz (gemeldet von pruef-struktur).

GEPRUEFT

  pruef-aufgaben-vorlagen   46 -> 60 ok
    eigene Frist kommt an (und die Vorlage saehe 5 Tage vor -- die
    Angabe hat also wirklich gewirkt), Anmerkung wird woertlich zur
    Notiz mit Namen, ohne Angabe bleibt alles wie bisher, Scout 403
    und es entsteht auch nichts, DogFather 200 und KEINE Frist,
    „morgen" 400, der 45.13. 400, Vergangenheit 400, und als
    Gegenprobe dieselbe Vorlage ohne Frist 200.
    Im Browser: der Knopf, das Fenster, die Vorgabe, kein Haken fuer
    einen Creator, die Aufgabe traegt danach genau die eingetragene
    Frist samt Notiz -- und Abbrechen legt nichts an.
  pruef-nachfrage           74 -> 89 ok
    Datum mit Vorgabe und Untergrenze, Haken 44 px hoch mit 22-px-
    Kaestchen (nicht ueber die ganze Zeile), Sperre und Gegenprobe,
    beide Schranken fuer ein zu fruehes Datum einzeln.
  pruef-struktur 102 · pruef-css-klassen · pruef-modi-katalog 150 ·
  pruef-aufgabenbrett · pruef-vorlagen 24 ·
  pruef-bewerbung-aufgaben 164 · pruef-zuteilung

NUR DAS AGENTURHAUS. Vorlagenbrett und Aufgaben liegen unter
`/workspace`; am Crew-Haus aendert sich keine Zeile.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 23:57:41 +02:00
DogFatherGitandClaude Opus 5 b31bd9b515 Zwei bis drei Bilder je Supportmeldung -- und zwei Funde unterwegs
VanVan im Support, Meldung #11, VIERMAL gemeldet: „Hier im
Supportbereich kann man immer nur ein Bild hinzufuegen bei einer
Meldung. 2-3 waeren besser." Und in der zweiten Runde der Satz, auf
den es ankommt: „wenn man es nacheinander versucht hinzuzufuegen wird
das Bild immer nur ersetzt."

EINE TABELLE STATT NEUER SPALTEN

`support_bilder` haelt ab jetzt JEDES Supportbild -- das der Meldung
(`runde_nr` NULL) und das einer Antwort (`runde_nr` = Runde). Die
Alternative waere `bild2_datei`, `bild3_datei` gewesen, und beim
vierten Bild wieder. Eine Zeile je Bild kennt keine Obergrenze im
Schema; die Grenze steht an EINER Stelle im Code (`BILDER_MAX = 3`)
und kommt von dort in die Oberflaeche, statt dort ein zweites Mal
zu stehen.

DIE ACHT VORHANDENEN BILDER WANDERN MIT. Ohne diesen Schritt haette
die neue Tabelle ab heute recht und die alten Bilder waeren
unsichtbar -- ohne Fehler, ohne rote Zeile, nur acht leere Karten.
Der Umzug steht NACH der Spaltennachruestung: Er liest
`urteil_bild_datei`, und die gibt es in einer bestehenden Datenbank
erst, nachdem sie ergaenzt wurde. Stuende er davor, scheiterte er
genau dort, wo es darauf ankommt -- live, waehrend lokal alles gruen
bliebe, weil jede Pruefung ihre Datenbank frisch anlegt.

DREI BILDER IN EINER ANFRAGE

`x-bilder: 20481,15320` sagt, wo zu schneiden ist, der Rumpf ist die
Aneinanderreihung. `multipart/form-data` haette einen Zerleger
gebraucht, den dieses Haus nicht hat; drei Anfragen nacheinander
haetten den Zustand „Meldung da, Bild zwei laedt noch" erzeugt --
genau den, gegen den die Kommentare an dieser Route schon vorher
argumentieren. Die Summe muss auf das Byte stimmen, und jedes Stueck
wird einzeln an seinen ersten Bytes erkannt: Wer falsch schneidet,
bekommt eine Absage, kein verfaelschtes Bild. Ohne den Kopf gilt der
ganze Rumpf als ein Bild -- derselbe Satz mit einer Laenge, damit
eine Seite aus dem Zwischenspeicher weiterlaeuft.

EINE ROUTE STATT DREI. `/:id/bild` und `/:id/runde/:nr/bild` sind
weg; es gibt `/:id/bild/:bid`. Wohin ein Bild gehoert, steht in
seiner Zeile -- der Weg muss es nicht wiederholen. Die
Meldungsnummer bleibt trotzdem im Pfad: Sie ist die
Sichtbarkeitsfrage, und beides muss zusammenpassen (gemessen).

ZWEI FUNDE, DIE DIE PRUEFUNG GEMACHT HAT UND NICHT ICH

 1. UEBER DIE SEITE KAM GAR KEIN BILD MEHR AN. Beim Melden stand
    kein `Content-Type`. Das ging gut, solange der Rumpf eine
    einzelne Datei war -- ein `File` bringt seinen Typ mit. Ein
    `Blob` aus mehreren hat keinen, `fetch` schickt die Zeile dann
    gar nicht, `express.raw` fuehlt sich nicht zustaendig, und der
    Server bekam einen leeren Rumpf. Die Meldung waere durchgegangen,
    der Text angekommen, die Bilder weg -- ohne Fehlermeldung. Alle
    Pruefungen am Server waren dabei gruen; gefunden hat es erst der
    echte Browser.

 2. DAS KREUZ DES DRITTEN BILDES LAG AUF DEM ZWEITEN. Der
    Entfernen-Knopf ist 44 px breit und absolut gesetzt, der Kasten
    aber nur so breit wie sein Bild. Bei einem schmalen Bild ragt er
    darueber hinaus -- wer „das zweite weg" antippt, loescht das
    dritte. `min-width`/`min-height` loesen das an der Ursache: Ein
    Kasten ist nie schmaler als der Knopf in ihm.

WAS ICH FALSCH ANGENOMMEN HATTE: Ich hatte eingebaut, dass ein
Nachtrag in derselben Runde die Bilder ersetzt. Die Pruefung dazu
wurde rot -- zu Recht: Eine zweite Antwort in derselben Runde kann
es nicht geben, die erste verlaesst den Stand „wartet". Der Code
waere nie gelaufen und damit nie pruefbar gewesen. Er ist weg; an
seiner Stelle steht der Beweis, dass er nicht fehlt.

DREI WEITERE ROTE ZEILEN, DIE NICHT ZU DIESEM UMBAU GEHOERTEN

 * `manager-ziele.js` hatte einen ZWEITEN Notnagel
   (`frageNach ? … : confirm(…)`). `nachfrage.js` hat denselben
   laengst, und zwar mit dem vollstaendigen Text; der hiesige war
   der kuerzere und haette gewonnen. Zwei Antworten auf dieselbe
   Frage -- gemeldet von `pruef-nachfrage`.
 * Zwei Mittelpunkte in `reaktion.css` standen woertlich im
   `content`. Sie liegen im Latin-1-Block, wo `pruef-zeichen` die
   Truemmer einer verunglueckten Kodierung sucht. Jetzt als Escape
   -- im Browser nachgemessen, es steht Zeichen fuer Zeichen
   dasselbe da.
 * Das Aufraeumen nach 90 Tagen loeschte nur das EINE Bild der
   Meldung; die Bilder aus den Antwortrunden blieben ohne Zeile auf
   der Platte liegen. Die Liste kommt jetzt aus einer Abfrage statt
   aus einer Spalte und kann deshalb nicht wieder unvollstaendig
   sein.

GEPRUEFT

  pruef-support            78 -> 104 ok
    darunter: der Umzug der alten Bilder auf einer eigenen
    Wegwerf-Datenbank -- zweimal und dreimal gestartet, nichts
    verdoppelt, Datum von damals erhalten
  pruef-support-bilder     NEU, 36 ok (echter Browser)
    dreimal nacheinander waehlen ergibt drei, das vierte wird mit
    einem Satz abgelehnt, dasselbe zaehlt nicht doppelt, einzeln
    entfernen laesst die anderen stehen, alle drei laden wirklich
    (naturalWidth), Kreuze 44x44 und keines verdeckt (mit Gegenprobe
    per Deckel), nichts ragt auf 390 px heraus
  pruef-nachfrage          69 -> 74 ok
  pruef-struktur          102 ok, 413 Routen (vorher 414: zwei weg,
                          eine neu)
  pruef-zeichen             7 ok (vorher 1 Fehler)
  pruef-aufbewahrung       45 ok
  pruef-manager-ziele     216 ok
  pruef-ports              10 ok · pruef-portnummern 41 ok
    (die neue Pruefdatei verschiebt die abgeleiteten Nummern)

NUR DAS AGENTURHAUS IST BETROFFEN. Die Supportseite liegt unter
`/workspace`; am Crew-Haus aendert sich keine Zeile.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 23:38:03 +02:00
DogFatherGitandClaude Opus 5 3ab69d36a5 Eine dauerhafte Aufgabe wird nicht abgehakt -- auch nicht ueber den Status
VanVan im Support, Meldung #6: „Der Modi kann die dauerhafte Aufgabe
immer noch auf erledigt setzen."

DIE SPERRE GAB ES SEIT DEM 30.09. -- ABER NUR AN EINER TUER.

`/mein-stand` lehnt „erledigt" bei einer dauerhaften Aufgabe seither
ab. Der STATUSWEG (`PATCH /workspace/api/aufgaben/:id`) kannte
`dauerhaft` ueberhaupt nicht. Wer die Aufgabe ohnehin aendern durfte --
etwa weil das Uebernehmen aus dem Pool ihn verantwortlich macht --
hakte sie damit einfach ab. Zwei Tueren, eine Regel, und die Regel
hing nur an einer.

UND ICH HABE DAS LOCH HEUTE FRUEH VERBREITERT. Mit dem Commit davor
darf eine Modi den Status ihrer Aufgabe setzen (damit VanVans Satz
„es gibt darüber ja den button starten" fuer sie ueberhaupt stimmt).
Damit stand ihr genau der Weg offen, der ihr an der anderen Tuer
ausdruecklich verwehrt ist. Gefunden habe ich es nicht beim Bauen,
sondern beim Lesen der offenen Supportmeldungen -- ihr Satz stand seit
dem 28.09. da und passte ploetzlich auf meine eigene Aenderung.

GEAENDERT

 1. Der Statusweg lehnt „erledigt" bei einer dauerhaften Aufgabe ab,
    wenn die Person nicht verteilen darf. DERSELBE Fehlercode wie in
    `/mein-stand` (`dauerhafte_aufgabe`) -- die Oberflaeche uebersetzt
    ihn schon, und ein zweiter Code fuer dieselbe Sache waere der, den
    beim naechsten Mal jemand uebersetzt und der andere nicht.

 2. Der Knopf faellt weg, der die Absage holen wuerde (`darf_beenden`
    vom Server). Dieselbe Ueberlegung wie bei „Fertig" auf der
    Zuteilungskarte, die seit dem 30.09. daneben steht: Ein Knopf, der
    eine Absage holt, ist schlimmer als keiner.

    NUR DER LETZTE SCHRITT faellt weg. „starten" und „zur Freigabe"
    bleiben -- auch eine stehende Aufgabe hat einen Anfang, und der
    Unterschied zwischen „offen" und „in Arbeit" sagt etwas.

 3. BEENDET WIRD SIE VON DER LEITUNG. Das stand seit dem 30.09. als
    Satz im Kommentar von `/mein-stand`; jetzt stimmt er auch.

GEPRUEFT -- UND ZWAR BEIDE TUEREN, sonst wandert der Fehler nur:

    eine dauerhafte Aufgabe (#3)
    Tuer 1 (mein-stand) ist zu (409 dauerhafte_aufgabe)
    Tuer 2 (Status) jetzt auch (409 dauerhafte_aufgabe)
      anfangen darf sie trotzdem (200)
      und die Leitung beendet sie (200)
    und die Oberflaeche erfaehrt es (darf_beenden false)

Die dritte Zeile ist die Gegenprobe gegen zu viel Sperre: „gesperrt"
darf nicht heissen, dass gar nichts mehr geht.

GEPRUEFT: pruef-zuteilung 90 -> 96 ok · pruef-bewerbung-aufgaben 164 ·
pruef-aufgabenbrett 49 · pruef-aufgaben-vorlagen 46 · pruef-struktur 102.

WAS AUS DERSELBEN MELDUNG NOCH OFFEN IST (VanVan, #6): Bei den
VORLAGEN laesst sich weder die Frist anpassen noch „dauerhaft"
einstellen, und eine Anmerkung fehlt auch. Das ist ein eigener Umbau
und steht hier nur, damit es nicht untergeht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 19:26:55 +02:00
DogFatherGitandClaude Opus 5 2fb92f86f3 Die Routenwache war unvollstaendig -- 13 Routen waren ihr unsichtbar
GEFUNDEN ALS FEHLALARM, GEBLIEBEN IST EIN ECHTER FUND.

pruef-struktur meldete:

    assets/js/manager-ziele.js: Schnittstelle gibt es nicht
      -> /workspace/api/manager-ziele

Nachgesehen statt geglaubt: Die Seite ruft diese Adresse NIE auf. In
Zeile 31 steht `const BASIS = '/workspace/api/manager-ziele'`, benutzt
wird ausschliesslich `${BASIS}/stand`, `${BASIS}/eintraege`,
`${BASIS}/eintrag/${id}`.

DER EIGENTLICHE FUND LAG EINE EBENE TIEFER. Der SERVER registriert
seine Routen genauso:

    const BASIS = "/workspace/api/manager-ziele";
    managerZieleRouter.get(`${BASIS}/stand`, ...)

Die Sammelregel verlangte aber, dass ein Routenpfad direkt mit
`/workspace/` beginnt. ALLE DREIZEHN Routen dieses Moduls fehlten
damit in der Liste -- gemessen, nicht geschaetzt. Die Wache war also
nicht zu streng, sie war UNVOLLSTAENDIG: Zu diesen Routen konnte sie
gar nichts sagen, weder dass es sie gibt noch dass es sie nicht gibt.
Und weil die Aufrufe dorthin ebenfalls zusammengesetzt sind, ist es
nie aufgefallen -- ausser an dieser einen nackten Konstanten.

    Server-Routen eingelesen:  401 -> 414

GEAENDERT

 1. Einfache Praefix-Konstanten werden je Datei aufgeloest. Mehr
    nicht: Wer seinen Pfad aus drei Variablen zusammensetzt, bleibt
    unauffindbar -- und das ist richtig so, denn geraten wird hier
    nicht. Ohne bekannten Wert wird GAR NICHTS eingetragen; eine
    geratene Route waere schlimmer als eine fehlende, weil sie einen
    toten Aufruf als lebendig durchgehen liesse.

 2. Eine nackte Praefix-Konstante im Browser gilt als Praefix, wenn
    es Routen DARUNTER gibt. Abgeleitet, nicht aufgezaehlt -- eine
    Ausnahmeliste mit „manager-ziele" darin waere die naechste, die
    niemand pflegt.

GEGENPROBEN IN BEIDE RICHTUNGEN, weil die neue Regel etwas
durchlaesst:

    eine Praefix-Konstante wird als Praefix erkannt (Routen darunter)
    eine erfundene Adresse OHNE Routen darunter bleibt ein Fund
    und eine echte Route bleibt eine echte Route, kein Praefix

DAZU VIER SCHLUSSZEICHEN. Die Wache fuer das deutsche
Anfuehrungszeichen meldete vier Stellen in denselben zwei Dateien:
`„${was}" löschen?` und drei Geschwister. Berichtigt auf `“`.

UND EINE KORREKTUR AN MIR: Ich habe pruef-struktur heute dreimal als
„99 ok, Exitcode 0" protokolliert und dabei zwei rote Zeilen
uebersehen -- mein Filter zeigte nur die ersten drei FEHL-Zeilen und
die Zahl der gruenen. Gefunden habe ich es erst, als dieselbe Pruefung
spaeter Exitcode 1 meldete. Nachgemessen mit `git stash`: Die zwei
Funde stecken auch in HEAD, sie sind also nicht aus meiner laufenden
Arbeit gekommen. Eine Zusammenfassung, die nur die gruenen Zeilen
zaehlt, ist keine.

GEPRUEFT: pruef-struktur 102 ok, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 19:25:54 +02:00
DogFatherGitandClaude Opus 5 63e3924a08 Die Erinnerungen wirklich zugestellt -- und eine Zeile, an der alles hing
`pruef-manager-ziele` prueft, was `zielRufe()` ZURUECKGIBT. Eine Liste
ist aber keine Benachrichtigung. Dazwischen liegen noch: der
Fuenf-Minuten-Takt, die Artenliste, der Schalter in der Glocke, die
Ruhezeit, die Verschluesselung und das Merkmal gegen Doppelsendungen.
Dieser Weg war genauso nie gelaufen wie der Monatswechsel -- und er
laeuft zum ersten Mal am 1. November um 00:05 Uhr, von selbst, fuer
alle gleichzeitig.

DIE WICHTIGSTE FRAGE STAND GLEICH AM ANFANG

Am 1. um 00:05 ist RUHEZEIT (Vorgabe 22 bis 7). Die Meldung darf dann
nicht herausgehen -- aber sie darf auch nicht VERFALLEN. Das haengt an
einer einzigen Zeile in `benachrichtige`: Das Merkmal wird erst
geschrieben, NACHDEM wirklich zugestellt wurde. Waere es umgekehrt,
bekaeme am 1. November niemand eine Meldung, und zwar fuer immer --
der Takt haette sie als „schon geschickt" abgehakt, waehrend alle
schliefen. Gemessen: nachts null zugestellt UND null Merkmale, um
09:00 dann zwei. Die Zeile haelt.

GEPRUEFT WIRD DIE ECHTE UHRZEIT, NICHT EINE GEFAELSCHTE RUHEZEIT. Das
Haus kann die Ruhezeit per Umgebungsvariable verstellen; das waere
hier die falsche Frage gewesen. Gefragt ist, was am 1. November um
fuenf nach null passiert -- also wird die Uhr dorthin gestellt.

WAS SONST NOCH BEWIESEN IST (20 Pruefungen, 0 Fehler)

  * Der Takt laeuft 288-mal am Tag. Drei weitere Laeufe direkt
    hintereinander stellen NICHTS mehr zu -- ohne das Merkmal
    bekaeme jeder 288 Meldungen und legte das Handy weg.
  * Der Schalter in der Glocke schlaegt die Erinnerung: Wer die Art
    abgeschaltet hat, bekommt nichts, obwohl bei ihm etwas offen ist.
  * Ein Creator bekommt nichts (er hat diese Pflichten nicht), und
    wer kein Geraet angemeldet hat, erzeugt keine Geisterzustellung.
  * Am 11. ist Ruhe. Ohne diese Gegenprobe hiesse „es kommt an"
    moeglicherweise „es kommt jeden Tag", und der ganze Terminplan
    der Vorlage waere wirkungslos.
  * Der Glueckwunsch kommt genau einmal, und danach ist fuer den
    Fertigen Ruhe -- waehrend der andere am 16. weiter gemahnt wird.

GEMESSEN WERDEN ZUSTAENDE, NICHT ZEITPUNKTE. Der Server startet seinen
eigenen Takt und kann jederzeit in die Pruefung hineinlaufen. Deshalb
steht nirgends „nach meinem Aufruf kamen genau drei dazu", sondern „in
push_verschickt steht jetzt genau eine Zeile je Person".

UND DIE ERSTE PRUEFUNG DER DATEI PRUEFT DIE PRUEFUNG. „Null
zugestellt" ist gleich die erste erwartete Antwort; ohne den Beweis,
dass ueberhaupt etwas ankommen KANN, hiesse sie moeglicherweise „der
Dienst ist gar nicht angeschlossen".

NUR DIESE EINE DATEI IST DRIN. Der erste Anlauf dieses Commits hat
mit `git add -A` drei Dateien mitgenommen, die ich nie angefasst
habe -- sie wurden waehrenddessen von einer anderen Sitzung im selben
Verzeichnis bearbeitet (Zeitstempel: Sekunden alt). Zurueckgenommen,
bevor etwas gepusht wurde; ihre Arbeit liegt unveraendert im
Arbeitsverzeichnis.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 19:18:56 +02:00
DogFatherGitandClaude Opus 5 72e51c57b6 Den Monatswechsel durchgespielt -- und zwei stille Fehler gefunden
Der zentrale Weg dieser Kachel war nie gelaufen: „Am 1. jedes Monats
um 00:00 Uhr starten alle Zaehler automatisch bei 0." Der erste
Oktober lag vor der Auslieferung, der erste November liegt dahinter.
Er laeuft ohne Zutun und betrifft alle gleichzeitig -- waere er
falsch, waere er fuer alle auf einmal falsch, und niemand wuesste
warum.

Dieselbe Lage gab es am 01.09.2026 schon einmal in RunOne (der Umbau
zur Hashkette war seit Tagen live und nie gelaufen). Die Lehre stand
danach in der Projektnotiz, und sie gilt hier woertlich: Was sich
nicht zuruecknehmen laesst, wird vorher auf einer Kopie durchgespielt.

`pruef-monatswechsel.mjs` verstellt dafuer die Uhr -- eine Huelle um
`Date`, ganz oben, vor jedem Import. Damit laeuft der ECHTE Code
durch zwei echte Monatswechsel (20. Oktober -> 1. November, 00:05 ->
3. Dezember), ohne dass eine Zeile dafuer umgebaut werden muesste.
41 Pruefungen, 0 Fehler: Zaehler bei 0, keine Warnung am ersten Tag,
die neuen Zielzahlen greifen, die alten Eintraege stehen unveraendert
da, der Oktober ist zu, der Verlauf misst ihn am OKTOBER-Ziel, und
„Neuer Monat" geht an alle drei -- auch an den, der den Oktober voll
hatte.

WAS DABEI AUFGEFALLEN IST -- zwei Fehler, beide stumm

1. DIE SUCHE NACH DEM ROLLENWECHSEL MASS DIE FALSCHE PERSON.
   `WHERE person_id = ?` im Protokoll findet den, der die Aenderung
   GEMACHT hat -- also DogFather --, nicht den, dessen Rolle sich
   geaendert hat (workspace-personen.js schreibt die betroffene
   Nummer ins `detail`). Fuer den Betroffenen fand die Abfrage
   deshalb nie etwas; bei DogFather schob jede fremde
   Rollenaenderung SEINEN Pflichtbeginn. In der echten Datenbank
   stand bei ihm „grund: rollenwechsel" -- ein plausibler Wert aus
   der falschen Zeile.

   NACHGESEHEN, OB ES SCHADET: Alle sechs Zeilen stehen auf 2026-10,
   und das ist ohnehin der frueheste moegliche Monat. Der Fehler
   hatte noch keine Wirkung -- er haette sie beim naechsten
   Rollenwechsel bekommen.

2. `node:sqlite` BINDET EINE ZAHL ALS REAL.
   Der erste Versuch der Reparatur lautete
   `detail LIKE ('#' || ? || ' %')` und traf NIE -- ohne Fehler, ohne
   Warnung, immer leer. Nachgemessen:

       SELECT ('#' || ? || ' %')  mit der Zahl 42  ->  '#42.0 %'

   Gesucht wurde „#42.0 ", gespeichert ist „#42 ". Mit derselben Zahl
   als Zeichenkette stimmt es sofort. Das Muster wird jetzt in
   JavaScript gebaut; im uebrigen Haus kommt dieselbe Verkettung mit
   einer Zahl nicht vor (nachgesehen).

   Gefunden hat das nicht das Lesen, sondern eine Pruefung, die den
   ECHTEN Weg benutzt (die Route der Personenverwaltung) statt den
   Protokolltext selbst zu schreiben. Haette sie ihn selbst
   geschrieben, haette sie ihre eigene Annahme geprueft und waere
   gruen gewesen.

AUSSERDEM BERICHTIGT

Der Pflichtbeginn wurde EINMAL gesetzt und nie wieder angesehen
(`INSERT OR IGNORE`). Wer die Rolle verliert und spaeter zurueck-
bekommt, haette damit keinen Schonmonat mehr bekommen, obwohl die
Vorlage ihn zusichert. Jetzt wird neu gerechnet, wenn seit der
Festlegung ein Rollenwechsel dazugekommen ist -- und nur dann;
geprueft wird ausdruecklich, dass ein zweiter Abruf nichts bewegt.

GEPRUEFT: 216 + 41 = 257 Pruefungen, 0 Fehler

Mit drei Gegenproben an der neuen Stelle: DogFathers Pflichtbeginn
bewegt sich NICHT, wenn er die Rolle eines anderen aendert; ein
unbeteiligter Scout behaelt seinen Wert; und ein zweiter Abruf
rechnet nichts neu. Ohne die erste waere der Fehler von oben
unentdeckt geblieben, ohne die zweite hiesse „einer hat sich
geaendert" vielleicht „alle".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 18:02:28 +02:00
DogFatherGitandClaude Opus 5 baf8288433 Korrigieren duerfen jetzt beide: Spicy Media und DogFather
Filipe auf die Rueckfrage, wer fremde Eintraege richtigstellen darf:
„ja spicy und dogfather".

Die Vorlage kannte dort nur DogFather („Vergangene Monate sind
gesperrt ... Ausnahme: DogFather"). Das gilt ab jetzt fuer beide --
und zwar fuer BEIDE Faelle, nicht nur fuer einen:

  * einen fremden Eintrag aendern oder loeschen
  * einen abgeschlossenen Monat dafuer kurz oeffnen

ES IST EINE MENGE UND KEINE ZWEITE LISTE. `darfKorrigieren()` gibt
`siehtAlles()` zurueck -- dieselbe Menge, die schon ueber die
Team-Uebersicht und die Zielzahlen entscheidet. Eine eigene
Aufzaehlung derselben zwei Rollen waere die, die beim naechsten Umbau
auseinanderlaeuft. Und inhaltlich gehoert es zusammen: Wer alle
Zahlen sieht und die Ziele setzt, muss einen Zahlendreher gerade
ruecken koennen; zwei verschiedene Grenzen fuer „darf alles sehen"
und „darf etwas richtigstellen" koennte spaeter niemand mehr
erklaeren.

Der Name der Variablen hiess vorher `istAdmin` -- also die Rechnung
statt ihrer Bedeutung. Jetzt heisst sie, was sie beantwortet.

NACHVOLLZIEHBAR BLEIBT ES UNVERAENDERT: Jede Korrektur an einem
fremden Eintrag und jede Aenderung an einem abgeschlossenen Monat
steht mit Name, Rolle und Zeit im Protokoll -- geprueft wird jetzt
ausdruecklich, dass dort auch `spicy` auftaucht.

GEPRUEFT: 206 Pruefungen, 0 Fehler (vorher 194)

Die Grenze wird in beide Richtungen gemessen, nicht nur in eine:
Spicy aendert wirklich (200, und der neue Wert steht in der
Datenbank), Spicy loescht wirklich -- aber ein Manager und ein
fremder Scout werden weiterhin abgewiesen (403), und danach steht
immer noch der Wert von Spicy da. Ohne diese Gegenproben hiesse
„Spicy darf" moeglicherweise „jeder darf". Loeschen ist eigens
geprueft: PATCH und DELETE sind zwei Routen, und zwei Routen koennen
auseinanderlaufen.

Auch die Freigabe fuer alte Monate wird nach Spicys Korrektur wieder
geschlossen gemessen -- eine geoeffnete Tuer ist kein Erfolg.

EINE MEINER PRUEFUNGEN WAR WIEDER FALSCH, NICHT DER CODE: Ich hatte
erwartet, dass ein Manager mit einer fremden Nummer in der Adresse
„nicht bearbeitbar" bekommt. Er bekommt `true` -- weil er gar keine
fremde Liste bekommt, sondern seine eigene; die Nummer wird fuer ihn
schlicht nicht beachtet. Richtiges Verhalten, falsche Frage. Gemessen
wird jetzt, was zaehlt: dass bei ihm kein einziger fremder Eintrag
ankommt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 17:52:36 +02:00
DogFatherGitandClaude Opus 5 b46f75484f Ein Klick statt eines Formulars -- der Schnell-Eintrag
Filipe mit dem Bildschirmfoto der Zeilen: „ich will das viel perfekter
und geiler. will dass es viel einfacher ist. am besten so wenig wie
moeglich zu tippen. fertige sachen, bereit um ab zu gehen."

GEZAEHLT, WAS EIN EINTRAG VORHER KOSTETE -- das war der Punkt:

    Manager Meeting   Knopf, Dialog, Speichern     2 Klicks + Fenster
    Schulung          dazu die Art waehlen         3 Klicks + Fenster
    Werbung           dazu den Link tippen         2 Klicks + tippen
    Creator           dazu den Namen tippen        2 Klicks + tippen

Ein Fenster fuer die Aussage „ich war heute im Meeting" sind drei
Handgriffe fuer null Angaben. Vier Aufgaben im Monat, acht Klicks,
acht Fenster.

JETZT

    Manager Meeting   EIN Klick  („Heute eingetragen")
    Schulung          EIN Klick  (zwei fertige Knoepfe)
    Werbung           Einfuegen + Eintragen, kein Tippen
    Creator           ein Klick je Lead -- oder mehrere Namen auf
                      einmal einwerfen

Am echten Bildschirm nachgemessen: 0/2 vorher, EIN Klick, 1/2 nachher,
„Rueckgaengig" bringt 0/2 zurueck. Nicht „der Knopf ist da", sondern
„danach steht eine andere Zahl dort".

DREI ENTSCHEIDUNGEN DAHINTER

1. DER WEG NIMMT EINE LISTE. „Drei Creator auf einmal" ist EIN
   Vorgang. Wer drei Namen aus Discord kopiert, hat das Monatsziel in
   einem Zug erledigt -- das ist der eigentliche Gewinn, nicht der
   gesparte Klick.

   JEDER EINTRAG WIRD EINZELN GEPRUEFT UND EINZELN BEANTWORTET. Die
   ganze Liste zurueckzuweisen, weil ein Name schon dasteht, waere
   die bequeme und die falsche Loesung: Dann weiss niemand, welcher
   der drei das Problem war, und tippt alles noch einmal. Geprueft
   wird genau dieser Fall -- zwei gehen durch, einer wird im Klartext
   abgelehnt, mit Namen.

2. KEINE SICHERHEITSABFRAGE VORHER, SONDERN „RUECKGAENGIG" DANACH.
   Eine Nachfrage bei jedem Klick waere der Handgriff, den wir gerade
   abgeschafft haben, in neuer Verkleidung. Sie kostet jeden; das
   Zuruecknehmen kostet nur den, der sich vertippt hat. Acht Sekunden
   statt drei -- lang genug, um es mit einem Daumen zu treffen.

3. DIE ZULETZT GEWAEHLTE ART IST VORGEWAEHLT -- abgeleitet aus dem
   letzten Eintrag, nicht in einer Einstellung gespeichert. Eine
   Spalte „Lieblingsart" waere ein zweiter Bestand, der veralten
   kann; der letzte Eintrag veraltet nie.

WAS MIR DABEI AUFGEFALLEN IST

Ein Ein-Klick-Knopf macht den Doppeltipper zur wahrscheinlichsten
Fehleingabe -- bei „Heute eingetragen" merkt man nichts davon, es gibt
ja keine Angabe. Zwei Meetings an einem Tag zu VERBIETEN waere aber
falsch, sie sind moeglich. Also ein Hinweis statt einer Sperre:
„Fuer diesen Tag stehen jetzt 2. War das Absicht?" -- und das
Zuruecknehmen liegt ohnehin daneben. Mit Gegenprobe, dass beim ERSTEN
keine Warnung kommt; sonst waere sie keine Warnung, sondern ein
Begleittext.

AUSSERDEM

  * Die Zeilen bauen sich beim Eintragen nicht mehr neu, sondern
    ziehen nur die Zahlen nach. Sonst verschwaende das Feld, in dem
    man gerade tippt, unter der Hand.
  * „Einfuegen" holt den Link aus der Zwischenablage -- mit drittem
    Ausgang: Firefox gibt sie ohne Erweiterung nicht her, und dann
    wird das gesagt, statt dass ein Knopf stumm bleibt.
  * Im Dialog drei fertige Tage (Heute / Gestern / Vorgestern) statt
    eines Kalenders. Was nicht mehr in diesen Monat gehoert, wird gar
    nicht erst angeboten -- am 1. und 2. fallen welche weg.
  * Der Dialog heisst jetzt „Mehr Angaben" und ist die Ausnahme fuer
    Notiz oder altes Datum. Dass er fuer etwas Normales gebraucht
    wurde, war sein Fehler.

GEPRUEFT: 194 Pruefungen, 0 Fehler (vorher 168)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 17:48:04 +02:00
DogFatherGitandClaude Opus 5 f6d2437985 Manager-Ziele zu Ende gebaut -- und dabei zwei Loecher gefunden
Filipe: „perfektioniere alles jetzt sofort, es muss ready sein."

Die Vorlage Punkt fuer Punkt gegen das Gebaute gehalten, nicht gegen
meine eigene Liste von heute Mittag. Vier Punkte standen noch offen,
und auf dem Weg dorthin sind zwei Fehler aufgefallen, nach denen
niemand gesucht hat.

DIE ZWEI FEHLER ZUERST -- beide gefunden durch Messen, nicht Denken

1. EINE GELOESCHTE PERSON HAETTE IHRE ZAHLEN MITGENOMMEN.
   `mz_eintrag.person_id` stand auf ON DELETE CASCADE. Die Vorlage
   sagt aber: „Wer die Rolle verliert, sieht die Kachel nicht mehr;
   die Daten bleiben fuer den DogFather erhalten." Mit CASCADE waere
   genau das nicht wahr gewesen -- `DELETE FROM personen` haette den
   Monatsverlauf eines Menschen lautlos mitgenommen.

   Jetzt SET NULL, und Name und Rolle stehen zusaetzlich als Text am
   Eintrag (dieselbe Bauweise wie bei support_meldungen). Die Rolle
   ist nicht Zierde: Ohne sie wuerde ein abgeschlossener Monat
   rueckwirkend an den Zielzahlen einer anderen Rolle gemessen.

   Der Umbau laeuft auf dem Bestand von heute Mittag -- Spaltenliste
   AUS PRAGMA abgeleitet, nicht gepflegt, und geprueft werden Zeilen
   UND Spalten. Am 11.09.2026 hat genau so ein Umbau drei Spalten mit
   Inhalt verloren, ohne Fehlermeldung, bei unveraenderter Zeilenzahl.

2. MEIN EIGENER SPERR-TRIGGER HAETTE DAS LOESCHEN BLOCKIERT.
   ON DELETE SET NULL ist kein Loeschen, sondern ein UPDATE auf
   person_id. Der Trigger sah eine Aenderung an einem abgeschlossenen
   Monat und brach ab -- `DELETE FROM personen` waere damit
   gescheitert, an einer Stelle, die mit Monatszielen nichts zu tun
   hat. Erlaubt ist jetzt genau eine Aenderung an einem alten Monat:
   dem Eintrag seinen Besitzer zu nehmen. Als BEDINGUNG und nicht als
   `UPDATE OF <spaltenliste>` -- eine Liste muesste jemand pflegen.

   Weil `CREATE TRIGGER IF NOT EXISTS` eine geaenderte Fassung nicht
   erneuert, wird die alte am INHALT erkannt und ersetzt. Eine
   Fassungsnummer muesste jemand hochzaehlen, und das wird vergessen.

DIE VIER OFFENEN PUNKTE DER VORLAGE

  04  Jede Aufgabenzeile hat ihr eigenes Zeichen -- aus dem Haus
      (`window.Bereiche`), nicht neu gezeichnet: Trichter, Bildschirm,
      Buch, Rahmen. Das Statuszeichen bleibt daneben; ein eingefaerbtes
      Aufgabenzeichen allein traegt die Stufe nicht.
  05  „Farbiger Rand + Badge": Eine Kachel, an der eine Warnung haengt,
      traegt jetzt einen feinen Saum -- JEDE Kachel, nicht nur diese.
      Eine Regel, die nur an einer Stelle gilt, wird beim naechsten Mal
      vergessen.
  08  Die Team-Tabelle ist sortierbar: jede Spalte ein Knopf (kein
      anklickbares <th> -- das erreicht die Tastatur nicht), mit
      aria-sort, und sortiert wird nach ANTEIL statt nach nackter Zahl.
      Dazu eine Ampel-Spalte mit Wort. Auf dem Handy verschwindet die
      Kopfzeile im Kartenmodus, deshalb steht das Sortieren zusaetzlich
      in der Leiste -- sonst waere es auf einem Telefon nicht
      vorhanden.
  09  Wer die Rolle verliert, steht weiter in der Uebersicht, als
      „nicht mehr dabei" und mit der Rolle von damals. Wer geloescht
      wurde, erscheint als zusammengefasste Zeile unter dem
      mitgeschriebenen Namen.

WAS DER SAUM MICH GELEHRT HAT

Er stand zuerst in start.css und war wirkungslos -- der Browser
lieferte weiter den Faseschatten. Der Grund steht seit dem 25.09.2026
in module.css: `:is()` uebernimmt die Spezifitaet seines staerksten
Arguments, und `.gruppe[data-gruppe]` macht die ganze Modulliste
(0,2,0) -- genau so stark wie `.kachel[data-warn="ja"]`, bei
Gleichstand gewinnt die zuletzt geladene Datei. Dieselbe Falle wie
damals bei den Fokusringen, dieselbe Antwort: Was gegen die Modulform
gewinnen muss, gehoert in die Datei mit der Modulform. Gemerkt habe
ich es nur, weil die Bildmessung den errechneten Schatten AUSGIBT
statt ein Bild zu machen.

Beim Herausschneiden blieb eine Klammer zu viel in start.css stehen --
gefunden von pruef-css-klassen („eine schliessende Klammer ohne
oeffnende"), bevor sie still CSS verschluckt hat.

AUSSERDEM BEHOBEN

  * Spicy Media sah an einer FREMDEN Liste „Bearbeiten" und „Loeschen",
    und der Server antwortete mit 403. Ein Knopf, der nichts tut, ist
    schlimmer als kein Knopf.
  * Klick auf eine Person klappt jetzt alle vier Zeilen auf. Die
    Vorlage verspricht „zeigt deren Eintraege" -- zugeklappt zeigte
    der Klick nur Zahlen.
  * Der CSV-Export kennt drei Staende statt zwei: „pflichtig", „neu,
    noch ohne Pflicht", „nicht mehr dabei". Vorher hiess beides „nein".
  * Das Aufklappen baute die ganze Liste neu und riss den
    angeklickten Knopf weg (Fokus sprang nach oben).

GEPRUEFT: 168 Pruefungen, 0 Fehler (vorher 141)

Neu darunter: der Umbau auf einem echten Alt-Bestand (Zeilen, Spalten,
Inhalt, Indizes, Trigger, und ein zweiter Lauf, der nichts mehr tut),
das Loeschen einer Person mit Eintraegen aus einem abgeschlossenen
Monat -- mit Gegenprobe, dass dieselbe Sperre den INHALT weiterhin
nicht aendern laesst.

Zwei meiner neuen Pruefungen haben zuerst sich selbst gemessen statt
den Code: Eine verglich gegen einen Eintrag, den sie vorher geloescht
hatte (404 sah aus wie ein haltender Riegel), die andere meldete eine
fehlende Spalte, die nur ihr eigener Handeinsatz verursacht hatte.
Beide berichtigt.

Am Bildschirm nachgemessen bei 412 px und 1280 px: kein waagerechtes
Schieben, kein eigenes Beruehrziel unter 40 px, genau EINE Kachel mit
Saum und zwanzig ohne.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 17:34:58 +02:00
DogFatherGitandClaude Opus 5 db656f6e14 Manager-Ziele: vier feste Monatsaufgaben, die sich selbst zuruecksetzen
Filipe mit der Vorlage „Prompt · Kachel Agentur-Aufgaben" (02.10.2026):
Scouts, Manager, DogFather und Spicy Media bekommen vier Pflichten je
Monat -- Creator rekrutieren, Manager-Meeting, Schulung oder Community
Talk, Werbung auf TikTok -- mit Fortschritt, Ampel, Warnungen und
einem Monatsschnitt, der nichts loescht.

DREI ENTSCHEIDUNGEN, DIE VON DER VORLAGE ABWEICHEN -- alle abgestimmt:

1. DIE KACHEL HEISST „Manager-Ziele", nicht „Agentur-Aufgaben".
   Es gibt bereits eine Kachel „Agentur" und eine „Aufgaben". Eine
   dritte mit beiden Woertern im Namen waere auf einem Handy nicht
   mehr auseinanderzuhalten.

2. DIE ZIELZAHLEN GELTEN JE ROLLE, und DogFather UND Spicy Media
   duerfen sie aendern. Ein Scout muss nicht dieselbe Zahl schaffen
   wie die Leitung.

3. DIE SCOUT-PIPELINE IST ANGEBUNDEN, in beide Richtungen: Vorschlaege
   aus uebergebenen Leads, Namensvorschlaege beim Tippen, die
   Verbindung bleibt am Eintrag gespeichert. Aber NICHTS zaehlt von
   selbst -- gezaehlt wird nur, was ein Mensch bestaetigt hat. Ein
   Zaehler, der sich allein fuellt, ist einer, dem niemand glaubt.

WAS ANDERS GEBAUT IST, ALS ES NAHELAG

DAS ZIEL WIRD PRO MONAT EINGEFROREN (`mz_ziel` hat den Monat im
Schluessel). Laege nur ein aktueller Wert in `einstellungen`, schriebe
jede spaetere Aenderung rueckwirkend den ganzen Verlauf um: Ein Monat,
der mit 2/2 abgeschlossen war, staende nach einer Erhoehung auf 4
ploetzlich als „nicht erreicht" da. Ein Verlauf, der sich rueckwirkend
aendert, ist keiner. Es gibt deshalb gar keinen Weg, den laufenden
Monat umzuschreiben -- gespeichert wird immer in den naechsten.

DIE SPERRE VERGANGENER MONATE SITZT IN DER DATENBANK, nicht im Code
(drei Trigger). Die Ausnahme fuer DogFather laesst sich in SQLite
nicht ueber die Sitzung abfragen, also ist sie ein sichtbarer Vorgang:
`mz_freigabe` wird fuer die eine Handlung geoeffnet, im `finally`
wieder geschlossen und verfaellt nach zwei Minuten von selbst. Jede
Korrektur steht mit Name und Zeit im Protokoll.

DER LAUFENDE MONAT STEHT IN EINER TABELLE (`mz_lage`), nicht in
`strftime(...,'localtime')`. Sonst entschiede die Zeitzone des Servers,
und am Monatsersten zwischen 00:00 und 02:00 griffe die Sperre fuer
den falschen Monat. Gerechnet wird durchgehend in Europe/Berlin
(identisch mit dem Europe/Luxembourg der Vorlage, aber dieselbe
Zeitrechnung wie der Rest des Hauses).

KEIN ZWEITER ZAEHLER FUER DIE KACHELWAND. Rand und Abzeichen auf der
Startseite kommen aus `workspace-hinweise.js` und damit aus derselben
Rechnung wie die Seite (`standFuer`). Zwei Rechnungen ueber dieselbe
Sache laufen auseinander, und zwar lautlos.

KEIN IMPORTKREIS ZU workspace-push.js. Die Erinnerungen entstehen hier
als Liste (`zielRufe`), verschickt werden sie im vorhandenen
Fuenf-Minuten-Takt. Der Tag steht im Merkmal -- dadurch geht pro
Person hoechstens EINE Meldung am Tag heraus, obwohl der Lauf
288-mal stattfindet.

GETRENNTE HAEUSER: Auf crew.dogfather-universe.com gibt es diese
Kachel nicht, auch nicht fuer DogFather. Gemessen, nicht angenommen.

GEPRUEFT (141 Pruefungen, 0 Fehler) -- mit Gegenproben zu jeder Sperre

  * Vier Rollen kommen herein, drei bekommen 404 (nicht 403), und die
    ANZAHL steht in der Bedingung. „Alle abgewiesen" waere auf einer
    leeren Liste wahr.
  * Die Ampel wird mit EINGESETZTEN Tagen gemessen, nie gegen die
    Wanduhr -- diese Pruefung sagt am 16. November dasselbe wie heute.
    (gate-oeffnung.mjs im Shop war gruen, bis der Kalender sie
    ueberholte.)
  * Die Datenbank lehnt einen Eintrag im Vormonat selbst ab; danach
    wird nachgewiesen, dass die Freigabe nur EINMAL gewirkt hat.
  * Neun Absagen mit dem jeweils richtigen Grund -- und eine
    Instagram-Adresse, die durchgehen MUSS, weil sonst nur bewiesen
    waere, dass die Pruefung streng ist, nicht dass sie richtig ist.
  * Am 7. des Monats ist Ruhe: Ohne diese Zeile bewiese der
    Erinnerungs-Block nur, dass immer etwas kommt.

ZWEI BEFUNDE KAMEN AUS DER MESSUNG, NICHT AUS DEM NACHDENKEN

  * Beim Aufklappen einer Zeile wurde die ganze Liste neu gebaut --
    der angeklickte Knopf existierte danach nicht mehr, der Fokus
    sprang an den Seitenanfang. Gefunden hat es die Bildmessung, der
    die Schaltflaeche unter der Hand wegbrach.
  * Zwei meiner Messungen waren falsch, nicht der Code: Der
    Haus-Test schickte den Keks nicht mit (401 statt 404), und
    `Response.text()` entfernt ein BOM beim Dekodieren -- der Export
    hatte eines, die Pruefung sah es nur nicht. Jetzt wird in Bytes
    gemessen.

Kachelton 47 (#7368ff) ist mit tools/kachel-farbe-einzeln.mjs gegen
alle 46 vorhandenen gerechnet, nicht ausgesucht: Abstand 0,0899,
Kontrast 4,61:1. Beruehrziele, waagerechtes Schieben und
Schriftgroessen sind am Bildschirm bei 412 px und 1280 px nachgemessen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 16:53:09 +02:00
DogFatherGitandClaude Opus 5 731537b682 Eine Wahrheit statt zwei: Der Status der Aufgabe gilt
VanVan im Support (Runde 1, „Ging noch nicht"): „Das dort steht ich
bewerbe mich ist jetzt weg, aber dafür hat er noch mal 2 Buttons
hinzugefügt mit ich fange an und fertig. Wenn man auf ich fange an
drückt steht dort in Bearbeitung und wenn man auf fertig drückt dann
wird es zu erledigt. Die Aufgabe bleibt aber im status offen stehen.
Die beiden Buttons können entfernt werden, weil es darüber ja den
button starten gibt, der auch korrekt funktioniert."

SIE HAT ETWAS GROESSERES GEFUNDEN ALS ZWEI UEBERFLUESSIGE KNOEPFE.

Es gab ZWEI Zustaende nebeneinander, und sie kannten sich nicht:

    aufgaben.status             offen · arbeit · review · erledigt
    aufgaben_zuteilung.zustand  angenommen · arbeit · erledigt

Die zwei Knoepfe setzten den zweiten (`/mein-stand`), der
Starten-Knopf den ersten. Auf der Karte stand „in Bearbeitung", in der
Liste „offen" -- und beides stimmte. Das ist schlimmer als ein Fehler:
Es gibt nichts, dem man glauben kann. Zwei Antworten auf dieselbe
Frage sind in diesem Haus verboten, und genau das war es.

WAS ICH BEINAHE FALSCH GEMACHT HAETTE

Ihr Wunsch war „entfernt die Knoepfe". Bevor ich das tue, habe ich
gemessen, was danach bliebe -- am Bildschirm einer Modi mit einer
angenommenen Aufgabe:

    Karten-Knoepfe:  []
    Schritt-Knoepfe: []

KEIN EINZIGER. Die Modi sieht den Starten-Knopf NICHT, weil
`darfAendern` fuer sie falsch ist: Sie ist weder Leitung noch
`creator_id`, `verantwortlich_id` oder `erstellt_von` -- die Zuteilung
laeuft ueber eine eigene Tabelle. VanVan ist Leitung und sieht ihn;
deshalb klang „den gibt es doch" selbstverstaendlich.

Haette ich die Knoepfe einfach geloescht, haette ich der Modi die
einzige Handlung weggenommen, die sie hatte -- eine Meldung „behoben",
nach der weniger geht als vorher.

ALSO WIRD IHR SATZ WAHR GEMACHT

 1. Wer eine Aufgabe WIRKLICH hat (angenommen/arbeit/erledigt), darf
    ihren STATUS setzen. Damit sieht die Modi denselben Knopf wie alle
    -- gemessen: „Schritt-Knoepfe: [starten ▶]".

    ENG GEFASST: nur der Status, nur allein in der Anfrage. Die
    Pruefung ist `Object.keys(...).length === 1` und nicht „enthaelt
    status" -- sonst waere die schmale Tuer die breite mit einem
    Zusatzfeld.

 2. Der Statuswechsel zieht die Zuteilung MIT. Ohne das waere das
    Entfernen eine stille Verschlechterung gewesen: Die Zaehler einer
    Person („offen / in Arbeit / erledigt") lesen die ZUTEILUNG, nicht
    die Aufgabe. Jede Zuteilung waere fuer immer auf „angenommen"
    stehen geblieben, und die Zahlen haetten aufgehoert, die
    Wirklichkeit zu zeigen -- ohne dass irgendwo etwas rot wird.

    ABGELEITET, NICHT ZWEIMAL GESCHRIEBEN: `STATUS_ALS_ZUSTAND` gibt
    es seit dem 22.09. Benutzt wird genau sie, mit EINER Abweichung,
    und die steht daneben: Wer zugesagt hat, faellt beim Zurueckdrehen
    auf „angenommen", nicht auf „offen". Eine Zusage verschwindet
    nicht, weil jemand den Status zurueckstellt.

 3. Die zwei Knoepfe sind weg. Der Weg `/mein-stand` bleibt -- er ist
    die Schranke fuer den, der die Schnittstelle direkt anspricht.

GEGENPROBEN ZUM ERWEITERTEN RECHT (ein Recht ohne Gegenprobe ist ein
Loch mit Begruendung):

    Anna hat eine Aufgabe, die ihr NUR zugeteilt ist
      (darf_aendern false, darf_status true)
    sie setzt den Status ihrer Aufgabe (200)
    mit einem zweiten Feld kommt sie nicht durch (403)
    und umschreiben darf sie gar nicht (403)
    der Titel steht unveraendert da („Clips schneiden")
    und wer sie nicht hat, setzt auch keinen Status (404)
    zurueckgedreht steht Anna wieder auf „angenommen"

    eine Bewerbung bleibt eine Bewerbung (abgelehnt -> abgelehnt)

ZWEI EIGENE FEHLER, BEIDE VON DER MESSUNG GEFUNDEN:

 · Mein erster Zeuge war Bea und die Pool-Aufgabe. Die Gegenprobe
   wurde rot: Bea darf sie ohnehin umschreiben, weil das Uebernehmen
   aus dem Pool sie verantwortlich macht. An ihr laesst sich ueber die
   neue, schmale Tuer gar nichts zeigen. Der reine Fall wird jetzt
   GESUCHT (darf_aendern falsch, Zuteilung angenommen) statt
   hingeschrieben -- eine feste Nummer waere die naechste, die beim
   naechsten Umbau nicht mehr stimmt.
 · Mein Abschnitt stellte Annas Aufgabe auf „arbeit" und liess sie so
   stehen; ein spaeterer zaehlte ihre „angenommen" und wurde dadurch
   rot. Eine Pruefung, die den Bestand fuer die naechste veraendert,
   misst ab da etwas anderes als sie glaubt. Jetzt raeumt sie auf --
   und die Rueckfahrt ist selbst eine Messung.

ZWEI PRUEFUNGEN MUSSTEN MITZIEHEN, und das ist richtig so: Beide
verlangten „Ich fange an" -- geschrieben von mir am 30.09. fuer
VanVans ERSTE Meldung. Ihre Absicht bleibt woertlich dieselbe („kann
sie wirklich etwas tun?"), nur ist der Griff jetzt der Statusknopf.
`knoepfeAn` sieht dafuer auch neben den Zuteilungsblock: „kann sie
etwas tun?" laesst sich am Block allein nicht beantworten.

GEPRUEFT: pruef-zuteilung 75 -> 90 ok · pruef-bewerbung-aufgaben
162 -> 164 ok · pruef-struktur 99 · pruef-resuemee 35 ·
pruef-aufgabenbrett 49 · pruef-rechtetafel 19 ·
pruef-aufgaben-vorlagen 46.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 15:11:35 +02:00
DogFatherGitandClaude Opus 5 664b799568 Geprüft: Die Benachrichtigung kommt an, wenn die App ZU ist
Filipe: „mach noch einen check ob alles mit den benachrichtigungen jetzt
perfekt klappt und dass die leute sie auch bekommen wenn die app zu ist."

DREI PRUEFUNGEN GAB ES SCHON -- UND KEINE BEANTWORTET DIE FRAGE

    pruef-push       die Verschluesselung, gegen die Testvektoren aus
                     RFC 8291 und RFC 8292 gerechnet        (24 ok)
    pruef-push-weg   Zustellung, TTL, VAPID-Kopf, 410-Fall  (20 ok)
    pruef-push-ziel  wer was bekommt und wer nicht          (38 ok)

Sie hoeren alle beim Push-Dienst auf. Danach faengt der Teil an, um den
es geht: Der Browser muss den Service Worker AUFWECKEN, obwohl keine
Seite offen ist, und der muss etwas anzeigen.

NEU: pruef-push-zu.mjs (13 Pruefungen)

    1. Seite auf, Service Worker meldet sich an.
    2. ALLE Seiten des Workspace zu -- nachgezaehlt, nicht behauptet.
    3. Ein echter Push ueber das DevTools-Protokoll
       (`ServiceWorker.deliverPushMessage`) -- derselbe Weg, den
       Apple und Google benutzen.
    4. Erst DANACH wieder eine Seite, und gefragt, was dasteht.

Eine Meldung, die in Schritt 4 dasteht, kann nur in Schritt 3
entstanden sein. Gemessen:

    nach dem Push steht 1 Meldung da — bei geschlossener App
      „Neue Nachricht" · „VanVan hat dir geschrieben."
      sie weiss, wohin sie fuehrt (/workspace/chat.html)
      und traegt das Gesicht des richtigen Hauses (crew-192.png)
      mit dem Abzeichen fuer die Statusleiste (abzeichen-96.png)

DAS MESSINSTRUMENT IST EINE LEERE SEITE, und das steht so im Kommentar:
`ServiceWorker.enable` gibt es nur an einer SEITE, nicht am Browser
(nachgemessen -- am Browser antwortet das Protokoll „wasn't found").
Eine Sitzung an der App-Seite stirbt mit ihr. `about:blank` gehoert
nicht zum Haus, und dass KEINE Workspace-Seite mehr offen ist, wird
ausdruecklich gezaehlt.

AUCH EIN PUSH OHNE DATEN ZEIGT ETWAS AN. Das ist kein Schoenheitstest:
Ein Browser, der eine Push-Berechtigung hat und mehrmals schweigt,
ENTZIEHT sie wieder -- ab da kommt gar nichts mehr an. Der Fehler, der
sich selbst verschlimmert. Gemessen: „Creator Workspace · Es gibt
etwas Neues."

DER DRITTE AUSGANG, UND ER WAR NOETIG

Mein erster Lauf meldete „nach dem Push steht 0 Meldungen da" -- das
sah aus wie ein schwerer Befund am Haus. Es war der Browser.
Fuenf Aufbauten gemessen, eine Antwort:

    headless (Vorgabe), grant mit origin       -> denied
    headless (Vorgabe), grant ohne origin      -> denied
    headless (Vorgabe), permissions im Kontext -> denied
    headless=old                               -> denied
    mit Fenster (headless: false)              -> GRANTED

Ein kopfloser Chromium verweigert Benachrichtigungen, egal wie man die
Erlaubnis erteilt. Die Pruefung oeffnet deshalb ein Fenster -- und wenn
die Berechtigung trotzdem fehlt, endet sie mit Rueckgabewert 2 und dem
Satz „konnte nicht nachsehen. Das ist KEIN Befund am Haus." Eine
Pruefung, die ihre Voraussetzung nicht hat, darf nicht rot werden.

WAS DAMIT NICHT BEWIESEN IST, und das gehoert in denselben Absatz: ob
ein bestimmtes Handy sie auch anzeigt. Das haengt an den Einstellungen
des Geraets (Nicht stoeren, Berechtigung entzogen, auf dem iPhone die
Installation auf dem Startbildschirm). Geprueft ist der Weg bis zum
Browser, nicht die Laune des Telefons.

AM LAUFENDEN SYSTEM NACHGESEHEN (nur gelesen)

Zehn Anmeldungen, alle gesund -- `fehler = 0` bei jeder einzelnen, und
`zuletzt_ok` bei vieren auf heute 12:31 Uhr. Der Push-Dienst hat also
heute Zustellungen angenommen, und der laeuft ueber Apple und Google,
nicht ueber eine offene Seite.

    BananaStift  iPhone, Android, Windows   zuletzt ok 01.10. 18:18
    Diene        Android                    heute 12:31
    Dogfather    Android                    heute 09:18
    Ghost        Android                    heute 12:31
    Marina       Android                    heute 09:53
    Miss         iPhone                     heute 12:31
    Tamy         Android                    01.10. 18:18
    VanVan       Android                    heute 12:31

GEPRUEFT: pruef-push-zu 13 ok · pruef-push 24 · pruef-push-weg 20 ·
pruef-push-ziel 38 · pruef-ports 10 · pruef-portnummern 41 ·
pruef-pruefzaehler 7. (Die Portnummern leiten sich aus der
alphabetischen Stelle ab -- eine neue Pruefdatei verschiebt sie.)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 14:53:17 +02:00
DogFatherGitandClaude Opus 5 4c08c8859d Beim Antworten im Support darf jetzt ein Bild mit
VanVan (Support): „Wenn man hier im Support auf deine Frage 'geht es
wieder' reagiert und antwortet, kann man auch kein Bild hinzufügen. Das
müsstest du auch noch hinzufügen, damit man nochmal ein Bild anhängen
kann, wenn das Problem noch besteht oder sich durch die Änderung ein
neues Problem ergeben hat."

Ihr zweiter Halbsatz ist der eigentliche Grund, und ich waere nicht
darauf gekommen: Das Bild beim MELDEN zeigt das ERSTE Problem. Taucht
durch die Aenderung ein neues auf, hilft das alte Bild niemandem.

WO ES LIEGT: AN DER RUNDE, NICHT AN DER MELDUNG

Die Meldung hat schon ein Bild -- das vom ersten Mal. Wuerde es hier
ueberschrieben, waere nach Runde drei nicht mehr zu sehen, womit es
angefangen hat. Genau diese Frage loest einen wiederkehrenden Fehler,
und genau deshalb gibt es die Rundentabelle ueberhaupt (ihre eigene
Begruendung steht seit dem 25.09. darueber).

DERSELBE WEG WIE BEIM MELDEN, NICHT EIN ZWEITER

Text und Urteil reisen im Kopf (`x-text`, `x-geht`), das Bild im
Rumpf, eine Route fuer beides. Die Begruendung stand schon beim
Melden und gilt hier genauso: Zwei Routen haetten einen Zustand
dazwischen -- eine Antwort, die schon zaehlt, waehrend das Bild noch
laedt. Ein leerer Rumpf ist zulaessig; ein Bildschirmfoto ist Hilfe,
keine Huerde.

DIE SPALTEN MUESSEN NACHGETRAGEN WERDEN, und das ist die Stelle, an
der es sonst schiefgeht: Die Tabelle entsteht mit `CREATE TABLE IF NOT
EXISTS`. Auf einer Datenbank, die es schon gibt -- also auf dem Server
-- sieht das den Namen, findet ihn, und ist fertig. Die vier neuen
Spalten kaemen dort NIE an: lokal alles gruen (jede Pruefung legt ihre
Datenbank frisch an), live ein Schreibfehler. Zwanzig Zeilen weiter
oben steht derselbe Fall schon einmal, damals mit einem Index.
Deshalb ein ALTER-Nachtrag, der die Tabelle SELBST fragt
(`PRAGMA table_info`) statt einer gepflegten Liste.

DATENBANK VORHER GESICHERT (Hausregel bei Schemaaenderungen):
`sicherungen/vor-support-rundenbild-20261002-142949.db`, geprueft mit
`integrity_check: ok`, 20 Personen, 16 Runden.

DER DIALOG KANN JETZT EIN BILD -- UND ZWAR NUR, WENN MAN IHN FRAGT

Das Feld ist eine Option von `frageNach` und standardmaessig AUS.
Ohne diese Vorgabe bekaemen die 56 anderen Rueckfragen im Haus ein
Bildfeld, nach dem niemand gefragt hat.

Es steht dort und nicht in support.js, weil Grund und Bild in
DENSELBEN Kasten gehoeren: Zwei Dialoge nacheinander hiessen, dass
jemand beim zweiten abbricht und den ersten umsonst getippt hat --
dieselbe Begruendung, aus der die Anzahl-Zeile dort gelandet ist.

Mit Vorschau. Wer sieht, was er anhaengt, haengt seltener das falsche
Bild an.

IM NOTAUSGANG GIBT ES KEINS, und das wird gesagt statt verschwiegen:
`window.prompt` kann keine Datei. Wer einen Browser ohne `<dialog>`
hat, kann antworten -- nur eben ohne Anhang. `bild: null` sorgt dafuer,
dass die aufrufende Stelle nicht raten muss.

GEPRUEFT

pruef-support 48 -> 78. Fuenf vorhandene Aufrufe mussten auf den neuen
Weg mitgezogen werden -- haette ich das vergessen, haetten sie ab
heute nur noch ihre eigene Veraltung gemessen. Neu dazu:

    die Antwort geht mit Bild durch (200)
    im Verlauf haengt das Bild an Runde 1
      und zwar an DIESER Runde, nicht oben an der Meldung
    der Melder bekommt es wieder (200, 70 von 70 Bytes)
    und ueber den gemeinsamen Ausliefer-Weg (Accept-Ranges)
    die Leitung sieht es auch (200)
    ein Fremder bekommt 404 — nicht 403, sonst waere die Nummer verraten
    ohne Anmeldung gar nichts (401)
    ohne Bild geht es genauso (200)
    eine PDF wird abgelehnt (415)

pruef-nachfrage 53 -> 69, am echten Bildschirm, mit echten Dateien
ueber `DataTransfer`:

    ohne Angabe bleibt die Bildzeile verborgen
    der Knopf ist 44 px hoch (Fingermass)
    nach der Wahl steht der Name da, Vorschau ist da
    ein 300x900 grosses Bild wird auf 160 px gedeckelt
      und der Senden-Knopf steht weiter im Fenster
    Gegenprobe: Abbrechen gibt nichts zurueck, auch kein Bild
    und beim naechsten Oeffnen ist es leer

ZWEI EIGENE FEHLER, BEIDE VON DER MESSUNG GEFUNDEN:
 · Meine erste Fassung las die neue Meldung ueber `.id` statt
   `.meldung.id` und meldete „#undefined". Die Pruefung hatte recht,
   der Fehler war meiner.
 · Die Obergrenze der Vorschau habe ich zuerst an einem 1x1-Bild
   gemessen: „3 px, hoechstens 160" -- gruen und wertlos, ein ein
   Pixel hohes Bild kann keine Grenze ueberschreiten. Jetzt entsteht
   im Browser ein 300x900 grosses, und die Grenze wird wirklich
   geprueft.

Dazu unveraendert gruen: pruef-aufbewahrung 45 · pruef-css-klassen 37 ·
pruef-struktur 99.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 14:30:39 +02:00
DogFatherGitandClaude Opus 5 58911d7c4f Auf dem Handy steht jetzt da, wer reagiert hat
VanVan (Support): „Wenn man auf dem Handy auf die Reaktionen unter einer
Nachricht geht, dann sieht man nicht wer darauf reagiert hat. Auf dem PC
funktioniert es."

DIE URSACHE STAND IM QUELLTEXT, mit Kommentar und allem:

    b.title = `${r.wer.join(', ')} · ...`

Ein `title` erscheint beim UEBERFAHREN MIT DER MAUS. Auf einem Finger
gibt es kein Ueberfahren -- und das Antippen schaltet stattdessen die
eigene Reaktion um. Die Auskunft war also nicht versteckt, sondern an
ein Geraet gebunden, das die Haelfte des Teams nicht benutzt. „Auf dem
PC funktioniert es" war der entscheidende Satz ihrer Meldung.

GEAENDERT: Unter den Kacheln steht auf Fingergeraeten eine Zeile mit
den Namen -- je Zeichen, mit dem Zeichen davor:

    👍 Patrick · ❤️ VanVan, Miss

WARUM EINE ZEILE UND KEIN LANGDRUECKEN. Ein langer Druck ist die
uebliche Antwort und die schlechteste: Man muss wissen, dass es ihn
gibt. Hier sind es Leute aus EINEM Raum, also kurze Listen -- sie
passen hin. Was dasteht, muss niemand finden.

WARUM NUR AUF DEM FINGER. Am Rechner funktioniert das Ueberfahren, und
eine Dauerzeile unter jeder zweiten Nachricht waere dort Unruhe ohne
Gewinn. Der `title` bleibt unveraendert.

ZWEI KLEINIGKEITEN, DIE KEINE SIND:
 · `aria-hidden="true"` an der Zeile. Jede Kachel traegt ihre Namen
   schon im `aria-label`; ohne das hoerte ein Vorleseprogramm alles
   doppelt.
 · Die Farbe ist die der Blase (`--blase-leise`), nicht eine feste.
   Derselbe Grund wie bei der Sprachnachricht: Jede Blase traegt die
   Farbe ihres Absenders, und eine feste Schrift ergaebe auf Babyblau
   wieder 1,91:1.

GEPRUEFT AUF BEIDEN GERAETEN, sonst beweist es nichts (pruef-chat-optik,
62 -> 71). Am Handy MUSS die Zeile da sein, am Rechner MUSS sie fehlen
und der Titel die Namen tragen. Ohne die zweite Haelfte waere eine
Regel, die immer gilt, genauso gruen -- und haette am Rechner eine
Zeile angehaengt, die niemand bestellt hat.

    auf dem Handy steht die Zeile da (true)
      und sie nennt den Namen: „👍 Patrick"
      und ein Vorleseprogramm hoert sie nicht doppelt (aria-hidden)
    am Rechner bleibt sie weg — dort funktioniert das Überfahren
      und die Namen stehen wie bisher im Titel

Gemessen wird mit einem FREMDEN Namen (DogFather schreibt, Patrick
reagiert). Mit der eigenen Reaktion staende „Du" da, und die Pruefung
haette den Fall nicht gemessen, um den es geht.

GEPRUEFT: pruef-chat-optik 71 ok · pruef-chat 63 ok ·
pruef-chat-aufloesen 126 ok.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 14:17:51 +02:00
DogFatherGitandClaude Opus 5 b808171704 Der Kamerahinweis wird wieder sichtbar -- und eine eigene Regression weg
ICH HATTE ES GESTERN FALSCH BEHAUPTET UND HEUTE SELBST VERSCHLIMMERT.
Beides steht hier, weil beides zum Befund gehoert.

WAS ICH GESAGT HATTE: „Auf 390 px ist der Hinweis 0 px hoch und
deshalb nicht zu lesen -- wo er hingehoert, ist eine Gestaltungsfrage
und gehoert Filipe."

Der zweite Halbsatz war eine Ausrede. Im Quelltext stand die ganze
Zeit eine 6-Sekunden-Uhr (reaktion.js, `sagFehler`), die ihn wieder
ausblendet. Statt das nachzusehen, habe ich aus zwei Messungen zu
verschiedenen Zeitpunkten einen Widerspruch gebaut (62 px hier, 0 px
dort) und ihn fuer eine Eigenschaft der Breite gehalten.

ALSO ABGETASTET STATT HERGELEITET (390x844, nach dem Laden):

    nach  500 ms  Text 104 Zeichen · hidden=nein ·   0 px
    nach 5000 ms  Text 104 Zeichen · hidden=nein ·   0 px
    nach 7000 ms  Text 104 Zeichen · hidden=ja   ·   0 px

Die Uhr stimmt also -- und trotzdem ist er die ganzen sechs Sekunden
NULL PIXEL hoch. Ein `role="alert"`, den niemand sehen kann. Das war
auf 390 px schon vorher so.

UND AUF 320 PIXELN HABE ICH ES HEUTE SELBST KAPUTTGEMACHT. Vorher
bekam `#fehler` dort eine stillschweigende fuenfte Rasterzeile mit
71 Pixeln -- sichtbar, aber auf Kosten des Bildes (56 statt 127).
Seit die Regie aus dem Fluss ist, bleibt fuer diese Zeile nichts
uebrig: Der Hinweis kostete nichts mehr und war dafuer unsichtbar.
Von „sichtbar und zu teuer" auf „gratis und wirkungslos" ist keine
Verbesserung.

DIE URSACHE, und sie steht seit dem 30.09. im Haus beschrieben:
`#fehler` ist ein Kind des Saals ohne Platzangabe. Der Saal hat vier
Zeilen; das Feld landet in einer fuenften, die es nicht gibt.

ERSTER REPARATURVERSUCH, GEMESSEN UND ZURUECKGENOMMEN: `grid-row: 2`
ohne `position: absolute`. Damit belegte das Feld die Zelle, der Raum
wich in eine stillschweigende zweite SPALTE aus, und das BILD fiel auf
0 px (320) bzw. 2 px (360). Bei `.raum` steht der gleiche Satz fuer
eine zweite ZEILE -- derselbe Fehler, andere Achse. Ich habe den
Kommentar gelesen, nachdem die Messung ihn mir bestaetigt hatte, nicht
davor.

SO GEHT ES: dasselbe Muster wie beim Pult. `position: absolute` nimmt
das Feld aus dem Fluss -- es belegt keine Zelle und verdraengt nichts.
`grid-row: 2` sagt dann nur noch, WORIN es liegt, `align-self: end`
setzt es an die Unterkante. Keine gerechnete Zahl.

GEMESSEN DANACH:

    320x568   Hinweis 62 px · im Fenster · obenauf · Bild 180 -> 180
    390x844   Hinweis 42 px · im Fenster · obenauf · Bild 219 -> 219
    430x932                                        · Bild 242 -> 242

Sichtbar, wenn er kommt. Nach sechs Sekunden wieder weg. Und er
kostet dem Bild kein Pixel mehr.

DIE PRUEFUNG STELLT DEN ZUSTAND SELBST HER (pruef-reaktion-schmal,
38 -> 44). Im Betrieb erscheint der Hinweis, wenn Kamera oder Mikrofon
fehlen -- auf einem Messrechner immer, auf einem Handy mit Freigabe
nie. Eine Pruefung, die darauf wartet, prueft die Messumgebung. Sie
schreibt den Text jetzt selbst hinein, macht ihn sichtbar, misst Hoehe
UND Bildhoehe, und raeumt wieder auf.

GEPRUEFT: pruef-reaktion-schmal 44 ok · pruef-reaktion 421 ok ·
pruef-css-klassen 37 ok · pruef-community-sicht 10 ok ·
pruef-breiten 23 ok.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 14:04:05 +02:00
DogFatherGitandClaude Opus 5 4a0ddf7d49 Die Regie wird auch auf dem kleinen Handy zur Schublade
Filipe: „auf so apps wie youtube und so geht es doch auch auf dem handy
also perfektionier es endlich."

Er hat recht gehabt, und meine Begruendung von 2026-09 war ueberholt.

WAS AUF 320x568 WIRKLICH PASSIERTE (Regie offen, laufende Sendung):

    Bild 0 px · Pult 1324 px IM RASTER · Transportleiste endet bei
    1567 von 568 Pixeln Fenster

Die Regie stand im Fluss statt darueber und schob alles hinaus. Ab
360 px war genau das laengst geloest -- es war dieselbe Seite, nur
schmaler. In reaktion.css stand dazu eine Sperre `and (min-width:
360px)` mit der Begruendung, der Kopf der Regie brauche 210 Pixel und
es seien nur 190 da. Fuenf Versuche hatten das nicht geloest.

DIE RECHNUNG STIMMTE NICHT MEHR. Seit 2026-09 gibt es einen Block
`@media (pointer: coarse)` ohne Breitengrenze, der den Kopf strafft.
Nachgemessen am 02.10.: 197 px, nicht 210 -- und mit einer weiteren
Straffung 147. Der Platz, der damals fehlte, war inzwischen da. Wer
der alten Begruendung geglaubt haette, haette nie nachgesehen.

VIER VARIANTEN DURCHGEMESSEN STATT DIE SECHSTE ZU RATEN
(320x568, Regie offen):

    heute             Bild   0 · Kopf 197 · Schublade 1324
    nur Sperre weg    Bild 180 · Kopf 197 · Schublade  234 · Inhalt  36
    + Knoepfe enger   Bild 180 · Kopf 147 · Schublade  234 · Inhalt  86
    + 86 % statt 72   Bild 180 · Kopf 147 · Schublade  280 · Inhalt 132

Die dritte Variante (Messwerte einzeilig) brachte gegenueber der
zweiten NULL und ist deshalb nicht eingebaut -- die bestehende
coarse-Regel erledigt das schon. Eine Regel, die nichts aendert, ist
eine, die beim naechsten Mal jemand sucht.

GEAENDERT

 1. Die beiden Sperren `and (min-width: 360px)` sind weg. Die Regie
    liegt jetzt auf JEDEM Fingergeraet ueber dem Bild statt im
    Raster, rollt in sich und hat einen stehenden Kopf.
 2. Neuer Block fuer unter 360 px: die drei grossen Knoepfe in EINE
    Zeile (`nowrap`, weniger Polsterung) und die Schublade darf
    86 statt 72 Prozent hoch werden.

    DIE 44 PIXEL HOEHE BLEIBEN -- das ist die Daumengrenze des
    Hauses. Nur die Breite gibt nach, und nachgemessen wird KEIN
    Knopf abgeschnitten (`scrollWidth <= clientWidth`).
    Die 86 statt 100 Prozent sind derselbe Gedanke wie die
    urspruenglichen 72: Oben bleibt ein Streifen Bild stehen, weil
    man sehen muss, worueber man gerade redet.

NACH DEM UMBAU GEMESSEN:

    320x568   Bild 180 px (war 0) · Kopf 147 (war 197)
              Schublade 280 · sichtbarer Inhalt 132 · Rest rollt 994 px
              Transportleiste endet bei 568 von 568
    360x640   Bild 203 px   unveraendert
    390x844   Bild 219 px   unveraendert

Zu UND auf ist das Bild auf 320 px jetzt gleich hoch -- das Oeffnen
der Regie kostet es nichts mehr.

EIN NEBENBEFUND HAT SICH MITERLEDIGT. Der Hinweis „Kamera oder
Mikrofon sind nicht freigegeben" sass in einer impliziten FUENFTEN
Rasterzeile (der Saal deklariert vier) und kostete das Bild 71 Pixel
(56 statt 127). Weil das Pult nicht mehr im Fluss steht, gibt es
diese Zeile nicht mehr: gemessen kostet der Hinweis jetzt 0 px
(325 -> 325).

WAS ICH DABEI FALSCH GEMACHT UND ZURUECKGENOMMEN HABE: Ich wollte
den Hinweis zusaetzlich mit `grid-row: 2` festnageln. Gemessen fiel
das Bild daraufhin auf 0 px (320) und 2 px (360) -- die explizite
Platzierung verdraengte die automatische des Bildes. Sofort wieder
entfernt. Die Messung hat es gefunden, nicht das Nachdenken; ohne
den Lauf davor haette ich eine Verschlechterung ausgeliefert.

DIE PRUEFUNG WURDE SCHAERFER, NICHT GRUENER (pruef-reaktion-schmal,
24 -> 38). Bis heute protokollierte sie den Mangel unter 360 px nur,
statt ihn zu behaupten -- richtig, solange es keine Reparatur gab,
falsch in dem Moment, in dem es eine gibt. Jetzt gilt auf JEDER
Breite: Bild behaelt seine Hoehe (zu und auf), Transportleiste bleibt
im Fenster, Inhalt der Schublade erreichbar, drei Knoepfe mit 44 px
unbeschnitten und obenauf, Zu-Knopf in jedem Zustand erreichbar.
Die Konstante `AUS_DEM_FLUSS_AB = 360` ist geloescht -- eine
Konstante, die nichts mehr trennt, ist der Anfang einer Erklaerung,
die nicht stimmt.

GEPRUEFT: pruef-reaktion-schmal 38 ok · pruef-reaktion 421 ok ·
pruef-css-klassen 37 ok · pruef-community-sicht 10 ok ·
pruef-breiten 23 ok · pruef-fingermass 5 ok.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 13:43:29 +02:00
DogFatherGitandClaude Opus 5 31437ac0dc Die Reaction auf dem kleinen Handy: gemessen, bewacht -- und ein Befund
MEINE EIGENE MERKLISTE WAR FALSCH.

Dort stand seit dem 01.10.: „320x568 zeigt noch ein 320x75 grosses
Videofeld und eine 1 px schmale Chatleiste." Nachgemessen stimmte davon
keine einzige Zahl. Eine Bestandsliste ist ein Wegweiser, keine
Wahrheit -- auch meine eigene.

WAS WIRKLICH DASTEHT (320x568, laufende Sendung):

    Regie ZU   Bild 127 px · Transportleiste endet bei 568 von 568
    Regie AUF  Bild   0 px · Transportleiste endet bei 1585 von 568
    Regie AUF bei 390/430: Bild unveraendert, Transport am Fensterrand

Die Chatleiste ist auf JEDER Handybreite `display: none` -- sie liegt
dort im Registerstreifen. Absicht, keine 1-px-Leiste.

Dass bei OFFENER Regie auf 320 px das Bild verschwindet, ist der in
reaktion.css dokumentierte Mangel samt sechs gescheiterten Versuchen.
Er wird hier NICHT repariert und auch nicht gruen abgehakt -- sonst
wuerde eine spaetere Reparatur rot.

DIE ENTSCHEIDENDE FRAGE WAR EINE ANDERE: Kommt man wieder heraus?
Gemessen in jedem Zustand und auf jeder Breite: Der Knopf, der die
Regie zumacht, steht im Fenster UND liegt obenauf (`elementFromPoint`,
nicht nur „sichtbar"). Es ist also ein Schoenheitsfehler und keine
Falle. Das war vorher niemandem bekannt, weil es niemand gemessen hat.

NEU: pruef-reaktion-schmal.mjs (24 Pruefungen)

Die Reaction-Seite war im Browser so gut wie unbewacht -- von fuenf
Pruefungen, die reaktion.html erwaehnen, oeffnet sie nur eine
ueberhaupt in einem Browser, und keine auf 320 px. Bewacht wird jetzt
die Grenze:

  1. Mit geschlossener Regie muss das Bild auf jeder Handybreite
     mindestens 100 px hoch sein (heute 127 / 219 / 242).
  2. Ab 360 px -- genau dort verlaeuft `@media (pointer: coarse) and
     (min-width: 360px)` -- muss das Bild seine Hoehe auch bei
     OFFENER Regie behalten.
  3. In JEDEM Zustand muss der Zu-Knopf im Fenster stehen und
     anklickbar sein.

Mit Gegenproben, die beweisen, dass sie rot werden kann: ein auf 0
gedruecktes Bild faellt durch, und ein zugedeckter Knopf gilt nicht
als anklickbar, obwohl er im Fenster steht.

-------------------------------------------------------------------
EIN BEFUND, DER FILIPE GEHOERT UND NICHT MIR

Beim Messen kam etwas heraus, das nicht auf der Liste stand. Die
Seite zeigt ein Hinweisfeld „Kamera oder Mikrofon sind nicht
freigegeben. Im Browser oben in der Adresszeile laesst sich …".
Gemessen, zweimal reproduziert:

    320 px   Das Feld kostet das Bild 71 px: 56 -> 127
             (es landet in einer impliziten FUENFTEN Rasterzeile;
              der Saal deklariert vier)
    390 px   Das Feld kostet 0 px -- weil es dort 0 px HOCH ist

Also: Auf dem kleinen Handy frisst der Hinweis mehr als die Haelfte
des Bildes. Auf dem normalen ist er ueberhaupt nicht zu lesen. Eine
Meldung, die erklaert, wie man die Kamera freigibt, und die man dabei
nicht sehen kann, ist keine.

Wo dieser Hinweis hingehoert, ist eine Gestaltungsfrage und damit
Filipes. Deshalb steht die Messung im Protokoll der Pruefung, aber
nicht als Behauptung im Code.

WIE ES GEMESSEN WIRD, nachdem der erste Anlauf wackelte: Nicht die
Hoehe des Feldes (die hing davon ab, WANN gelesen wurde -- in einem
Lauf 62 px, im naechsten 0), sondern der Unterschied vorher/nachher im
selben Lauf: Bild messen, Meldung leeren, Bild noch einmal messen.
Zweimal hintereinander identisch.

GEPRUEFT: pruef-reaktion-schmal 24 ok · pruef-ports 10 ok ·
pruef-portnummern 41 ok · pruef-pruefzaehler 7 ok · pruef-struktur 99 ok.
Die Portnummern leiten sich aus der alphabetischen Stelle ab, eine neue
Pruefdatei verschiebt sie -- deshalb stehen die beiden Port-Pruefungen
mit dabei. Der Gesamtlaeufer liest das Verzeichnis (`readdirSync`) und
findet die neue Datei von selbst; es gibt keine Liste, die veralten
koennte.

AM PRODUKT IST NICHTS GEAENDERT.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 12:29:54 +02:00
DogFatherGitandClaude Opus 5 ea53d950cd Fingermass: beide Grundlinien auf NULL -- kein blindes Telefonfenster mehr
Seit dem 29.09. haelt pruef-fingermass zwei Zahlen, und beide muessen
GENAU stimmen: waechst eine, ist eine neue blinde Messung dazugekommen;
sinkt sie, deckt sie Platz fuer die naechste. Nach dem Grosscheck von
heute sagte die Pruefung selbst, was zu tun ist:

    FEHL Nur noch 0 blinde Fenster — die Grundlinie steht auf 1.
         Bitte in pruef-fingermass.mjs auf 0 senken.
    FEHL 0 Fenster mit Variable und ohne hasTouch (Grundlinie 2).

Beide Zahlen zaehlten dasselbe: `pruef-grosscheck`. Im Kommentar stand
seit dem 01.10. woertlich, warum sie stehen blieben -- „die Datei zu
aendern waere ein Zweizeiler; sie zu pruefen hiesse, 206 Seiten ueber
vier Rollen laufen zu lassen, und das braucht Filipes Zusage. Eine
Aenderung, die ich nicht pruefen darf, liefere ich nicht aus."

Die Zusage kam heute („mach jetzt den prüf groß check"), der Lauf ist
gruen, also faellt die Ausnahme. Beide Grundlinien stehen auf 0.

DAS IST MEHR ALS EINE KLEINERE ZAHL: Es gibt im ganzen Haus kein
Telefonfenster mehr ohne Finger und keines, bei dem offenbleibt, ob am
Telefon mit Mauszeiger gemessen wird. Jedes neue ist ab jetzt ein
Befund und kein Bestand. 29 Dateien messen am Telefon, 28 Fenster
haben einen Finger, 0 blind.

    pruef-fingermass: 5 Pruefungen, 0 Fehler

-------------------------------------------------------------------
NACHTRAG ZUR ZEITBOMBE VON HEUTE NACHT -- UND EINE KORREKTUR AN MIR

Heute Nacht war pruef-gifs rot, weil sie ins Treff-Gespraech schrieb,
wo zwischen 0 und 6 Uhr die Nachtruhe gilt. Repariert, indem sie sich
ein eigenes Gespraech anlegt.

Danach wollte ich wissen, ob noch andere Pruefungen dieselbe Bombe
tragen, und habe sie gestartet „solange das Fenster offen ist". Es war
NICHT offen: Im Protokoll stand 11:40 Uhr. Der Rechner war zwischendurch
aus, und ich hatte meine eigene, veraltete Zeitnotiz fuer die Gegenwart
gehalten -- genau der Fehler, vor dem in CLAUDE.md steht, dass auch
meine eigenen Notizen altern. Die erste Runde beantwortete die Frage
also gar nicht.

DIE NACHT BRAUCHT MAN DAFUER AUCH NICHT. Das Fenster ist eine
Einstellung (`TREFF_NACHT_AB` / `TREFF_NACHT_BIS`), und pruef-treffchat
macht es laengst so: Fenster verschieben statt Systemuhr. Damit laesst
sich die Nacht um 11:42 Uhr herstellen.

GEMESSEN, STATISCH AUSGEWAEHLT: Von 16 Pruefungen, die in einen Raum
schreiben, legen 13 ihn selbst an; uebrig blieben sechs Kandidaten.
Alle sechs mit kuenstlicher Nachtruhe (Fenster 11-13 Uhr, jetzt 11:42):

    pruef-chat-kanaele    81 ok      pruef-chat-aufloesen  126 ok
    pruef-entwicklung     79 ok      pruef-chatkachel       40 ok
    pruef-loeschen        31 ok      pruef-anruf           132 ok

489 Pruefungen, 0 Fehler. Keine weitere Zeitbombe dieser Art.

UND WEIL GRUEN NUR DANN ETWAS HEISST, WENN ES AUCH ROT WERDEN KANN --
drei Messungen statt einer Behauptung:

    1. Kommt der Schalter an?    istNachtruhe false -> TRUE
    2. ALTE pruef-gifs, Nacht:   2 FEHL  (die Methode findet es)
    3. NEUE pruef-gifs, Nacht:   0 FEHL  (die Reparatur haelt wirklich)

Ohne (2) waere (3) wertlos gewesen: Sechs gruene Laeufe sehen genauso
aus, wenn der Schalter gar nicht ankommt.

AM PRODUKT IST NICHTS GEAENDERT -- eine Pruefdatei, zwei Zahlen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 11:45:16 +02:00
DogFatherGitandClaude Opus 5 7edb9c1bdb Grosscheck: mit Finger messen -- und 0 px ist keine kleine Schrift
AUFTRAG: „mach jetzt den prüf groß check."

ERGEBNIS DES LAUFS: 206 Seiten, 122 551 Elemente, 3 870 bedienbare.
Rechner (1280 px) alle vier Rollen sauber, 33 oeffentliche Seiten auf
beiden Groessen sauber, alle fuenf Gegenproben schlagen an. Vier
Beanstandungen, alle dieselbe Stelle -- und beide Ursachen lagen in der
Pruefung, nicht am Produkt.

1. ER HAT OHNE FINGER GEMESSEN

Die drei Browser-Kontexte setzten nur die Fenstergroesse. Ohne
`hasTouch` meldet Chromium `pointer: fine`, und KEINE Regel aus
`@media (pointer: coarse)` greift -- dort stehen im ganzen Haus die
44-Pixel-Beruehrziele. Ausgerechnet die Zeile `if (breite < 700 &&
r.klein.length)` misst genau diese Beruehrziele. Die Handy-Haelfte
dieses Laufs hat also eine Seite vermessen, die es auf keinem Handy
gibt. Dieselbe Luecke wie am 01.10. bei pruef-breiten, wo von sechs
Befunden nach dem Nachruesten genau einer uebrig blieb; 57 andere
Pruefdateien hatten es laengst, diese nicht.

Jetzt `hasTouch: b <= 860, isMobile: b <= 860` an allen drei Stellen --
gleiche Schwelle, gleiche Schreibweise wie ueberall sonst.

2. „0px" IST KEINE KLEINE SCHRIFT, SONDERN GAR KEINE

Gemeldet wurde viermal (einmal je Rolle) dasselbe:

    kalender.html  zu klein: A.k-pille 0px | A.k-pille 0px
                             | SPAN.k-anlass "🇩🇪 Tag der D" 0px

Am echten Bildschirm nachgemessen statt der Zahl geglaubt:

    Kasten 8x8 · Schrift 0px · Zeilenhoehe 0px
    GEMALTER TEXT: Hoehe 0 -- kein einziger Textkasten
    pointer-events: none · alle Kinder display:none
    title="Tag der Deutschen Einheit — gesetzlicher Feiertag"
    Tagesdialog: „10:00 Uhr Ein absichtlich sehr langer Titel …"

Im schmalen Monatsraster (Zelle 46 px breit) wird ein Termin
absichtlich zu einem farbigen PUNKT. `font-size: 0` ist dort das
Mittel, nicht der Mangel; kalender.css begruendet es ausfuehrlich, und
den Namen nennt der Tagesdialog. Es wird nichts gemalt -- die Frage
„ist dieser Text zu klein zum Lesen?" ist bei 0 px falsch gestellt.

Die Messung fragt jetzt `0 < Groesse < Grenze`. Zwischen 1 und 11,5 px
faellt alles weiterhin auf, und genau dort liegt der echte Mangel.

WAS DAS NICHT IST: ein Freibrief. `font-size: 0` versteckt Text auch
vor dem sehenden Auge -- aber das ist ein FEHLENDER Inhalt, kein zu
kleiner, und mit `display: none` entkaeme er dieser Messung ohnehin
genauso.

3. UND DIE AUSNAHME PRUEFT SICH IN BEIDE RICHTUNGEN

Eine Ausnahme ohne Gegenprobe ist der Anfang einer Liste, die niemand
pflegt. Deshalb zwei neue Gegenproben, direkt neben den fuenf
vorhandenen:

    ein Absatz mit 6 px  -> MUSS gemeldet werden
    ein Punkt mit  0 px  -> darf NICHT gemeldet werden

Ohne die erste waere die neue Regel auch dann gruen, wenn sie gar
nichts mehr findet.

AM PRODUKT IST NICHTS GEAENDERT -- eine einzige Pruefdatei. Kein
Stempel, kein Neustart noetig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 04:56:52 +02:00
DogFatherGitandClaude Opus 5 87a3a14978 pruef-gifs war nicht kaputt, sondern nachts rot -- und ein Weg war ungeprüft
DIE ZWEI FEHLER AUS DEM LETZTEN LAUF WAREN KEINE FEHLER AM PRODUKT.

    FEHL das GIF steht danach wirklich im Verlauf
    FEHL und die Tafel geht zu -- man will sehen, wie es ankommt

Gemessen statt geraten: eine Sonde, die jede Anfrage mitschreibt. Die
Antwort stand sofort da, um 04:30 Uhr:

    POST /workspace/api/chat/raeume/1/gif
    403 {"fehler":"Das Rudel schläft. Ab 06:00 Uhr geht es weiter …",
         "nachtruhe":{"zu":true,"ab":0,"bis":6,"minuten":90}}

Die Pruefung klickte „das erste Gespraech in der Liste". Das erste ist
der TREFF, den der Server beim Start selbst anlegt -- und im Treff gilt
die Nachtruhe von 0 bis 6 Uhr. Also: tagsueber gruen, nachts rot, seit
es diese Pruefung gibt. Es ist derselbe Fehler wie am 06.09. im Shop
(„ein Test, der die Wanduhr als Annahme benutzt, misst irgendwann das
Gegenteil") -- dort ein Oeffnungstermin, hier ein Raum mit Nachtruhe.

Warum es nie jemandem auffiel: Fuer Dogfather Universe gibt es keinen
naechtlichen Pruefdienst (nachgesehen: `systemctl list-timers` kennt nur
`vandiy-pruefung` und `runone-pruefung`). Die Pruefung lief immer nur
dann, wenn jemand sie von Hand startete -- und das war bisher nie
nachts.

WAS GEAENDERT IST

1. pruef-gifs legt ein eigenes Gespraech mit Miss an und oeffnet GENAU
   DAS. Fuer ein normales Gespraech gibt es keine Nachtruhe; die Messung
   gilt jetzt rund um die Uhr. Findet es den Knopf nicht, bricht es laut
   ab statt still auf nichts zu klicken.

   Gemessen, 04:40 Uhr:
     verschicken: {"vorher":0,"nachher":1,"imVerlauf":true,
                   "adressen":["/workspace/api/chat/anhang/1"],
                   "tafelZu":true}
   17 Pruefungen, 0 Fehler. Und nebenbei belegt die Adresse, was der
   Quelltext behauptet: Das GIF wird KOPIERT und haengt danach als
   ganz normaler Anhang an der Nachricht.

2. DIE NACHTRUHE IST NICHT UNTER DEN TISCH GEFALLEN -- sie steht jetzt
   dort, wo sie hingehoert: in pruef-treffchat (110 -> 114). Dort wird
   das Fenster ueber die EINSTELLUNG verschoben, nicht ueber die
   Systemuhr, und beide Zustaende kommen in einem Lauf vor.

   DENN DER GIF-WEG WAR DORT ALS EINZIGER DER DREI UEBERHAUPT NICHT
   GEPRUEFT. Im Quelltext steht neben der Regel woertlich: „Sie nur
   beim Text und beim Anhang zu pruefen hiesse, dass man nachts zwar
   nicht schreiben, aber ein GIF schicken kann -- der Weg, den jeder
   findet, der es einmal versucht." Genau dieser Weg hatte keine
   Pruefung. Der Kommentar hat den Fehler beschrieben und nicht
   verhindert -- dieselbe Luecke wie beim Spaltenverlust vom 11.09.

   Gemessen, beide Zweige in einem Lauf:
     Fenster 7–9 Uhr, jetzt 4 -> 404 „Dieses GIF gibt es nicht mehr."
     Fenster 4–6 Uhr, jetzt 4 -> 403 „Das Rudel schläft. Ab 06:00 …"

   ZWEI ENTSCHEIDUNGEN DABEI, beide mit Grund:
   · Gefragt wird als DogFather, nicht als Gast. Die GIF-Kiste gehoert
     dem Rudel; ein Gast bekaeme seine 403 von der falschen Schranke
     (`nurRudel`) -- gruen, ohne die Nachtruhe je beruehrt zu haben.
   · Mit einer Nummer, die es NICHT gibt. Kommt trotzdem die
     Nachtruhe-Absage, steht die Schranke VOR dem Nachschlagen.
     Stuende sie dahinter, verriete der Server nachts an der Nummer,
     welche GIFs es gibt.

AM PRODUKT IST NICHTS GEAENDERT. Nur zwei Pruefdateien -- kein Stempel,
kein Neustart noetig.

GEPRUEFT: pruef-gifs 17 ok (vorher 15 ok / 2 FEHL) ·
pruef-treffchat 114 ok (vorher 110).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 04:36:14 +02:00
DogFatherGitandClaude Opus 5 34a227605c Der Ausliefer-Helfer haengt nicht mehr an Express -- und ist einzeln prüfbar
GEFUNDEN BEIM MESSEN, NICHT BEIM LESEN.

Nach dem Ausliefern wollte ich auf dem Server nachweisen, dass die DORT
liegende `helfer-ausliefern.mjs` wirklich Teilanfragen beantwortet. Dafuer
habe ich ihr einen winzigen Server vorgesetzt -- `node:http`, eine
Wegwerfdatei in /tmp, eigener Port. Die volle Datei kam sauber
(`accept-ranges: bytes`, `content-length: 1000`). Beim ersten Abschnitt:

    TypeError: res.status is not a function
        at liefereDatei (.../helfer-ausliefern.mjs:134:9)

`res.status()` gibt es nur an einer EXPRESS-Antwort. Alle zehn Aufrufer
SIND Express-Handler, im Betrieb lief also alles richtig -- 146 Pruefungen
in pruef-chat-anhaenge und 33 in pruef-wissen-neu haben es bestaetigt, und
sie hatten recht. Trotzdem ist es ein Mangel: Der Helfer hing an Express,
ohne dass irgendwo stand warum, und liess sich nur noch INNERHALB der
ganzen Anwendung pruefen.

GEAENDERT: Die drei Stellen setzen jetzt `res.statusCode = n` und rufen
`res.end()`. Das kennen beide Antwortarten, und Express aendert daran
nichts -- an der ausgelieferten Antwort ist kein Unterschied messbar.

DAZU EINE PRUEFUNG, DIE OHNE SERVER AUSKOMMT (pruef-struktur, +14):
`bereichLesen()` steht ausdruecklich als eigene, ausgefuehrte Funktion da.
Jetzt wird sie auch einzeln befragt -- ohne Browser, ohne Server, ohne
Datenbank:

    kein Kopf / leerer Kopf          -> volle Datei
    bytes=0-9 · bytes=5- · bytes=-8  -> der richtige Abschnitt
    bytes=0-5000                     -> endet am Dateiende (erlaubt)
    bytes=1000- · 9-5 · -0 · leere Datei -> 416
    mehrere Bereiche · fremde Einheit · Unsinn -> volle Datei

Die letzte Zeile ist die wichtigste: NICHT VERSTANDEN ist etwas anderes als
UNERFUELLBAR. Auf einen Kopf, den der Server nicht liest, gehoert die ganze
Datei -- nie eine falsche Teilmenge und nie eine Absage.

DIE LEHRE, die ich mir aufschreibe: Durch zehn Express-Handler hindurch
waere das nie aufgefallen. Was sich einzeln pruefen laesst, wird einzeln
geprueft -- und ein Helfer, den man nur mit der ganzen Anwendung messen
kann, ist schwerer zu beweisen als einer, dem eine Antwort genuegt.

GEPRUEFT: pruef-struktur 85 -> 99 ok · pruef-chat-anhaenge 146 ok ·
pruef-wissen-neu 22 ok. Danach dieselbe Messung auf dem Server noch einmal,
gegen die ausgelieferte Datei.

BERICHTIGUNG ZUM COMMIT DAVOR: Dort steht „pruef-wissen-neu 33 ok". Das
war keine Messung, sondern geschaetzt -- nachgezaehlt sind es 22 (16 vorher
plus meine 6). Die Zahl stimmte nicht, der Befund schon. Eine Zahl, die man
nicht gezaehlt hat, gehoert nicht in eine Zusammenfassung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 03:46:32 +02:00
DogFatherGitandClaude Opus 5 4324547eb3 Teilanfragen: Sprachnachrichten kommen jetzt auch auf dem iPhone an
Filipe: „zeurst schaust du mal ob es im system liegt dass miss, die modi,
keine sprachnachrichten hoeren kann oder ob es an ihr liegt weil bei allen
anderen klappt nur bei ihr nicht"

ES LAG AM SYSTEM.

WAS GEMESSEN WURDE (nicht vermutet)

1. An ihrer Rolle liegt es nicht. Der Weg `/workspace/api/chat/anhang/:id`
   fragt drei Dinge: gibt es die Nachricht, ist die Person im Raum, hat sie
   das Gespraech weggeraeumt. Keine Rollenpruefung. Gegen eine Wegwerf-
   Datenbank gemessen: `anmelden admin=200 modi=200`, Anhang als modi
   HTTP 200, 40018 Bytes -- genau wie als admin.

2. Sie ist in allen drei Raeumen mit Sprachnachrichten, geloescht_bis = 0,
   alle sechs Tondateien liegen auf der Platte. (Live-Datenbank, nur
   gelesen, auf einer Kopie, Kopie danach geloescht.)

3. Sie ist die EINZIGE im Haus mit Safari. Aus dem Caddy-Protokoll, ueber
   IP und Minute mit ihren Protokolleintraegen abgeglichen: iPhone,
   iOS 18.7, Safari 26.6.1. Alle anderen Geraete der letzten zwei Wochen:
   Android-Chrome 3900 Anfragen, Windows-Chrome/Edge/Firefox 2646.
   Neun von zehn iPhone-IP-Praefixen sind ihre.

4. DER FEHLER: Der Anhang-Weg beantwortete eine Teilanfrage
   (`Range: bytes=0-1`) mit einer vollen HTTP 200 -- ohne `Accept-Ranges`,
   ohne `Content-Length`, als `chunked`. Zum Vergleich dieselbe Anfrage an
   `express.static`: HTTP 206, `accept-ranges: bytes`,
   `content-range: bytes 0-1/2480`.

   Safari verlangt fuer <audio> und <video> zwingend Teilanfragen und
   verweigert die Wiedergabe bei einer 200. Chrome und Firefox nehmen die
   ganze Datei klaglos. Bilder brauchen das nicht -- deshalb sah sie Fotos
   und hoerte nichts, und deshalb fiel es sieben Tage lang nur ihr auf.

WAS GEAENDERT IST

A) EIN GEMEINSAMER AUSLIEFERWEG (server/helfer-ausliefern.mjs)

   Im Haus gaben ZEHN Stellen eine Datei mit `createReadStream(pfad)
   .pipe(res)` hinaus: Chat-Anhang, Chat-GIF, Dateiablage (ansehen und
   laden), Material (ansehen und laden), Steckbriefbild, Buehnenbild,
   Supportbild, Wissens-PDF. Nur eine davon zu reparieren hiesse, eine
   Liste zu fuehren, welche Stelle schon richtig ist -- und die naechste
   neue macht es wieder falsch. Alle zehn gehen jetzt ueber
   `liefereDatei(req, res, pfad)`: `Accept-Ranges`, `Content-Length`,
   206 mit `Content-Range`, 416 mit `bytes */groesse`. Mehrere Bereiche in
   einer Anfrage werden absichtlich nicht bedient (das darf ein Server);
   die Antwort ist dann die GANZE Datei, nie eine falsche Teilmenge.

   WAS ES AUSSER SAFARI BRINGT, gemessen: Eine MP4-Sprachnachricht meldete
   in Chromium ohne Teilanfragen 0,23 s statt 1,96 s Laenge -- der Kopf
   einer MP4 steht am Ende der Datei. Eine Ogg-Datei meldete „Infinity"
   statt 2,02 s. Und ein PDF-Betrachter springt jetzt zu einer Seite, ohne
   die ganze Datei zu holen.

B) AUFGENOMMEN WIRD AAC IN MP4 (workspace/assets/js/chat.js)

   Die Reihenfolge der Behaelter beantwortete bisher die Frage „was kann
   DIESES Geraet am liebsten". Richtig ist „was koennen die ANDEREN
   abspielen" -- die hoeren es.

   Gemessen mit echten Aufnahmen aus echten Browsern, danach in beiden
   Engines abgespielt:
     Chromium nimmt auf: webm/opus, mp4(AAC), mp4(Opus)
     Firefox  nimmt auf: webm/opus, ogg/opus -- MP4 gar nicht
     Beide spielen alle vier Behaelter vollstaendig ab (2 s rein, 2 s raus)

   ZWEI FALLEN, die die Messung gezeigt hat:
   - Ein blankes `audio/mp4` ist nicht AAC: Chromium meldet darauf
     `audio/mp4;codecs=opus` zurueck -- MP4 aussen, Opus innen, fuer Safari
     genauso unbrauchbar wie WebM. Deshalb steht `audio/mp4;codecs=mp4a.40.2`
     VOR dem blanken `audio/mp4`.
   - Firefox kann kein MP4 aufnehmen und faellt sauber auf WebM/Opus
     zurueck. Kein Rueckschritt -- das ist der heutige Stand.

   Die Pruefung nimmt jetzt im echten Browser ueber den echten Knopf auf,
   und der Server erkennt: audio/mp4, 45583 Bytes, 2734 ms.

   BERICHTIGT: In zwei Kommentaren stand „Safari und das iPhone koennen
   nur MP4". Das stimmt nicht. An Miss' eigener Aufnahme nachgemessen:
   Behaelter WebM, Mux-Programm „WebKit", Tonspur A_OPUS. Safari NIMMT
   WebM auf -- ob es WebM abspielt, ist eine andere Frage.

C) EIN AUSWEG STATT EINER VERTROESTUNG (chat.js, chat.css)

   Vorher stand im Fehlerfall „Sprachnachricht laesst sich gerade nicht
   laden". Das war fuer Miss die ganze Auskunft, und es stimmte nicht
   einmal: Die Datei kam an, ihr Browser konnte den Behaelter nicht.
   „Gerade" heisst „gleich nochmal versuchen" -- bei einem fremden
   Behaelter hilft kein Versuch mehr.

   Jetzt wird unterschieden (Fehlercode 4 = Format, alles andere = Laden)
   und daneben steht ein Weg, der wirklich zum Ton fuehrt: Herunterladen,
   44 px hoch, in der Farbe der Blase, mit eigenem Vorlesewort. Nur im
   Fehlerfall -- ein Knopf an jeder Sprachnachricht waere Unordnung fuer
   alle, damit einer Person geholfen ist.

WAS JETZT NACHGEZAEHLT WIRD

- pruef-chat-anhaenge: 119 -> 146 Pruefungen. Dreizehn davon messen
  Teilanfragen am Foto (0-9, -8, 5-, ueber das Ende hinaus, 416, mehrere
  Bereiche, unverstandener Kopf) und vergleichen jeden Abschnitt BYTEWEISE
  mit der vollen Datei -- eine 206 mit den falschen Bytes waere schlimmer
  als keine. Drei Gegenproben legen dieselbe Messlatte an erfundene
  Antworten (die alte volle 200, falsche Gesamtgroesse, falsche Bytes) und
  muessen durchfallen. Neun weitere pruefen die Sprachnachricht selbst und
  den Ausweg.
- pruef-wissen-neu: +6. Der Weg zur PDF war der EINZIGE der zehn, den nie
  eine Pruefung abgerufen hat -- genau der, bei dem eine Umstellung
  unbemerkt danebengeht. Jetzt beide Spielarten (ansehen und laden).
- pruef-struktur: +6. Wer kuenftig wieder `createReadStream(...).pipe(res)`
  schreibt, bekommt einen Befund. Mit Gegenproben in beide Richtungen; die
  Probetexte sind zusammengesetzt, sonst meldet die Wache ihre eigene
  Begruendung als Fund. Pruefdateien sind ausgenommen, weil sie an niemanden
  ausliefern -- dort ist ein Weg ohne Teilanfragen die Gegenprobe.
  (Beim ersten Lauf hat die Wache sofort meine eigene Messdatei gefunden.)

WAS NICHT NACHGESEHEN WERDEN KONNTE

Ob iOS-Safari WebM/Opus ueberhaupt abspielt. Playwrights WebKit startet auf
diesem Rechner nicht (`icuuc77.dll`, auch nach Neuinstallation), und ein
iPhone habe ich nicht. Der dritte Ausgang: konnte nicht nachsehen. Deshalb
sind A, B und C drei Sicherungen hintereinander statt einer Wette auf eine.

GEPRUEFT (alles einzeln, kein Gesamtlauf)

  pruef-chat-anhaenge   146 ok   pruef-material     159 ok
  pruef-wissen-neu       33 ok   pruef-spenden      172 ok
  pruef-struktur         85 ok   pruef-support       63 ok
  pruef-video            74 ok   pruef-steckbrief    65 ok
  pruef-galerie          26 ok   pruef-eintrag-bild  24 ok
  pruef-chat             63 ok   pruef-chat-optik    62 ok
  pruef-haus-trennung   100 ok

Die beiden Haeuser bleiben getrennt (pruef-haus-trennung, 100 ok). Der
Ausliefer-Weg gehoert beiden gleichermassen und traegt nichts Haus-
spezifisches; die Aufnahme betrifft faktisch nur Team Dogi, weil nur dort
der Mikrofonknopf steht („also nur die modis rechte linke hand und
dogfather").

NICHT VON MIR, SCHON VORHER ROT: pruef-gifs meldet zwei Fehler („das GIF
steht danach wirklich im Verlauf", „die Tafel geht zu"). Gegen den
unveraenderten Stand von HEAD nachgemessen -- dieselben zwei Fehler, mit
denselben Zahlen. Ein eigener Befund, kein Nebenschaden dieser Arbeit.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 03:41:18 +02:00
DogFatherGitandClaude Opus 5 365e789cce Tagesgrenze: jetzt auch die Vergleiche, nicht nur das Schreiben
Von den sechzehn Stellen vom 01.10. SCHREIBEN zehn einen Tag in die
Datenbank — die decken die zwei Abschnitte von vorhin ab. Sechs
VERGLEICHEN gegen „heute": ist diese Frist vorbei, faellt dieser
Lead in den Zeitraum, ist dieser Bericht aktuell.

Davon findet ein Schreibtest keinen einzigen. Die Spalte sieht
richtig aus; falsch ist die Zahl, die jemand auf dem Bildschirm
liest.

ZWEI AUFGABEN GENUEGEN. Die Regel im Haus ist `frist < heute`:

    Frist = gestern (Ortszeit)  ->  muss ueberfaellig sein
    Frist = heute   (Ortszeit)  ->  darf es nicht sein

Mit dem alten UTC-Tag geht das in BEIDEN Zweigen der verschobenen
Uhr schief:

    Etc/GMT-14 (Ortstag = UTC+1): heute_alt waere gestern -> 0 statt 1
    Etc/GMT+11 (Ortstag = UTC-1): heute_alt waere morgen  -> 2 statt 1

GEGENPROBE AM ECHTEN CODE: In workspace-aufgaben.js den UTC-Tag
wieder eingebaut -> „genau eine ist ueberfaellig (0)". Zurueckgedreht
und wieder gruen.

UND EIN BEFUND AN MEINER EIGENEN PRUEFUNG, bei genau dieser
Gegenprobe: Die zweite Zahl (`heute`) blieb 1 — aber sie zaehlte die
FALSCHE Aufgabe. Mit dem UTC-Tag galt die von gestern als heute
faellig. Mit zwei Zahlen allein ist das nicht zu trennen; in beiden
Zweigen bleibt sie 1.

Sie steht jetzt ausdruecklich als BEGLEITPROBE da: Sie zeigt, dass
ueberhaupt gezaehlt wird, und der Unterschied kommt aus der Zeile
darueber. Eine Zahl, die aus dem falschen Grund stimmt, soll nicht
aussehen wie ein Beweis.

Dazu im Lauf eine ausgerechnete Zeile, die sagt, WARUM die Zahlen
etwas beweisen: „mit dem UTC-Tag waeren es 0 statt 1".

IM FENSTER NACHGEMESSEN (00:09 bis 00:40 Ortszeit, UTC noch der
Vortag) — die restlichen Pruefungen, die ich gestern zur falschen
Tageszeit geprueft hatte: zuteilung 75, aufgabenbrett 49,
content 45, vorlagen 24, bewerbung 91, scout-zuteilung 37,
unterstuetzung 70, aufbewahrung 45, ics 38, entwicklung 79 — alle 0
Fehler. Zusammen mit den vierzehn von vorhin sind das 24 Dateien,
die diesmal im richtigen Zeitfenster gemessen wurden.

pruef-tagesgrenze: 8 -> 12 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 00:36:44 +02:00
DogFatherGitandClaude Opus 5 c5f4d237e3 Tagesgrenze: der Fehler von gestern ist jetzt rund um die Uhr pruefbar
UM 00:09 DES 02.10. WAR DAS FENSTER OFFEN — Ortszeit 2026-10-02,
UTC noch 2026-10-01. Genau die zwei Stunden, in denen der Fehler von
gestern zuschlug.

Ich habe die Reparatur am 01.10. zwischen 10 und 16 Uhr geprueft,
also zu einer Zeit, in der der Fehler GAR NICHT AUFTRETEN KONNTE.
Jetzt nachgeholt — vierzehn Dateien, 1083 Pruefungen, 0 Fehler. Die
entscheidende Zeile in pruef-kreislauf:

    ok   und er liegt HEUTE, nicht gestern (2026-10-02, heute ist 2026-10-02)

Gestern um dieselbe Uhrzeit stand dort 2026-09-30 gegen 2026-10-01.

DABEI IST MIR DAS EIGENTLICHE PROBLEM AUFGEFALLEN

Diese Zeile kann den Fehler nur ZWEI STUNDEN AM TAG ueberhaupt
sehen. Den Rest des Tages sind Ortszeit und UTC-Tag derselbe, und
sie ist wahr, ohne irgendetwas zu beweisen — ein gruener Haken ohne
Aussage, 22 Stunden lang.

pruef-tagesgrenze.mjs wartet deshalb nicht auf Mitternacht, sondern
verschiebt die Uhr. Node uebernimmt eine zur Laufzeit gesetzte TZ
(nachgemessen: Stunde 0 wird zu Stunde 12 unter Etc/GMT-14), und sie
steht VOR allem anderen — sonst haette der Server schon seine
Vorstellung vom heutigen Tag.

Welche Zone, haengt von der Uhrzeit ab: Es gibt keine, in der sich
die zwei Tage IMMER unterscheiden, dafuer braeuchte es 24 Stunden
Versatz. Ab 10 Uhr UTC also Etc/GMT-14, davor Etc/GMT+11; bei 10 Uhr
gehen beide, die Grenze ist kein scharfer Rand.

UND DAS WIRD NACHGESEHEN: Unterscheiden sich die Tage wider Erwarten
nicht, bricht sie mit dem dritten Ausgang ab (3) statt gruen zu
melden. Eine Pruefung ohne ihre Voraussetzung darf nicht bestaetigen
— daran ist am 03.09. die Gitea-Pflichtpruefung wochenlang
vorbeigelaufen.

Geprueft werden die zwei Stellen, die es wirklich getroffen hat: ein
Eintrag OHNE Datum, und die Kette Wunsch -> Termin.

GEGENPROBE: Den alten Weg in workspace-bereiche.js wieder eingebaut
(beide Stellen) -> 8 Pruefungen, 2 Fehler, beide mit dem falschen
Tag im Klartext. Die Zahl bleibt bei 8, nichts wird still
uebersprungen.

ZWEI DINGE AM DETEKTOR IN pruef-struktur

1. EINE AUSNAHME, DIE SICH SELBST PRUEFT. pruef-tagesgrenze benutzt
   den falschen Weg absichtlich und wurde deshalb zu Recht und
   trotzdem falsch gemeldet. Sie ist jetzt ausgenommen — aber nicht
   als stille Liste: Es wird nachgesehen, dass jede ausgenommene
   Datei das Muster WIRKLICH enthaelt. Raeumt es jemand weg, ist die
   Ausnahme veraltet und faellt auf.

2. EINE LUECKE, DIE MIR DABEI AUFFIEL. Der Detektor kannte nur
   `.slice(0, 10)`. Denselben UTC-Tag bekommt man mit
   `.split("T")[0]` und `.substring(0, 10)`. Gemessen schreibt das
   heute niemand so — aber „niemand schreibt es so" ist kein Schutz,
   sondern Glueck. Beide zaehlen jetzt mit, mit eigenen Gegenproben.

GEPRUEFT: pruef-struktur 75 -> 79, pruef-tagesgrenze 8, beide 0
Fehler. Ports nach der neuen Datei: bis 5417, 464 Nummern, 0
Kollisionen. pruef-arbeitsschloss 48/0, pruef-fingermass 5/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-02 00:17:10 +02:00
DogFatherGitandClaude Opus 5 e8a5d7bc7e pruef-glocke: drei Viertel der Pruefung sind nie gelaufen
8 Pruefungen standen am Ende da. Jetzt sind es 36.

SCHRITT FUER SCHRITT NACHGEMESSEN, statt der Meldung zu glauben:

  1. Drei von acht Rollen scheiterten mit „Zeitsperre nach 25 s"
     beim Warten auf start.html -- hand, linke, modi. Danach brach
     die Datei ab; alles dahinter lief nie.
  2. Nicht an der Last: allein dasselbe Bild.
  3. Was antwortet die Anmeldung im Browser? 401 ungueltig.
  4. Dieselbe Anmeldung ueber die Schnittstelle, am SELBEN laufenden
     Server: 200. Es lag also nie am Server.
  5. Der Unterschied ist die KACHEL. Es gibt zwei Anmeldeseiten:
         workspace/index.html       spicy, admin, manager, scout, creator
         workspace/crew-index.html  admin, hand, linke, modi, gast
     Auf 127.0.0.1 kommt die Agenturseite.

KEIN FEHLER AM PRODUKT. Der Server ist auf einer Pruefadresse
absichtlich grosszuegig, damit Pruefungen alles testen koennen (das
steht so im Quelltext); die zwei Seiten sind die Trennung der zwei
Haeuser.

DER FEHLER WAR EIN NOTNAGEL IN DER PRUEFUNG:

    const kachel = await seite.$(`.rolle[data-rolle="${rolle}"]`)
      || await seite.$(".rolle");

Er sollte verhindern, dass ein Klick auf eine fehlende Kachel
abbricht. Seit die Kachel am 30.09. BINDEND ist (`718b267d`, auf
Filipes Wunsch), macht er aus „diese Kachel gibt es hier nicht"
etwas Schlimmeres: Er klickt irgendeine, der Server weist zu Recht
ab, und heraus kommt eine Zeitsperre nach 25 Sekunden, die wie ein
Fehler an der Glocke aussieht.

EIN NOTNAGEL, DER STILL DAS FALSCHE GREIFT, IST SCHLIMMER ALS EIN
LAUTER ABBRUCH. Jetzt wird die richtige Seite PROBIERT (nicht aus
einer Liste von Crew-Rollen gelesen -- die waere die naechste, die
beim sechsten Eintrag nicht mitwaechst), und findet sich die Kachel
auf keiner der beiden, bricht es mit Namen ab und zeigt, welche
Kacheln dastehen.

DAS IST HEUTE DER ZWEITE FALL DERSELBEN WURZEL. Bei
pruef-crew-wand-bild war es dieselbe Folgewirkung der bindenden
Kachel, nur sichtbarer. Nach jener Aenderung bin ich die Pruefungen
zum Zugang gelaufen und nicht die, die nebenbei eine Anmeldung
brauchen.

DENSELBEN NOTNAGEL GIBT ES NOCH EINMAL, in pruef-gifs. Dort zielt er
auf `creator`, und die Kachel steht auf der Agenturseite -- er
greift heute nie. Das ist Glueck und kein Entwurf, also ist er auch
dort weg.

GEPRUEFT: pruef-glocke 8 -> 36 Pruefungen, 0 Fehler, alle acht
Rollen. pruef-gifs 17 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 23:26:01 +02:00
DogFatherGitandClaude Opus 5 775aabef38 Standwache: hat sich der Stand WAEHREND des Laufs geaendert?
Die zweite Sitzung hat die Luecke benannt: Das Arbeitsschloss
schuetzt den Commit und die Stempellaeufe, nicht die Pruefläufe. Wer
misst, waehrend ein anderer speichert, misst einen Stand, den es
nicht mehr gibt.

Am 06./07.09.2026 sind so fuenf Gesamtlaeufe wertlos geworden — rund
zwei Stunden Wartezeit ohne einen einzigen Befund. Am 01.10. dieselbe
Lage, nur anders: zwei Sitzungen im Verzeichnis, eine misst, die
andere speichert. Aufgefallen ist es nur, weil die andere es von
sich aus gesagt hat.

DIE FRAGE IST EINE MESSUNG, KEINE ZUSTAENDIGKEIT

„Haelt jemand das Schloss" waere die falsche Frage, und zwar in
beide Richtungen:

  * Sie blockiert zu viel: Wer zwei Stunden am Schloss sitzt, haette
    in der Zeit keinen Prueflauf mehr. Eine Sicherung, die das eigene
    Arbeiten anhaelt, wird abgeschafft.
  * Sie blockiert zu wenig: Filipe am Editor hat kein Schloss, mein
    eigenes Werkzeug auch nicht.

Gefragt wird deshalb: Ist der Stand am Ende noch derselbe wie am
Anfang? Das trifft jede Quelle.

AN DER NOTBREMSE, NICHT IN 179 DATEIEN

Gemessen: 179 von 231 Pruef- und Messdateien rufen `notbremse`. Das
ist die eine Stelle, an der alle etwas bekommen — dieselbe
Ueberlegung wie bei der Notbremse selbst. Einzelne Dateien
nachzuruesten hilft nur bis zur naechsten ohne.

Fingerabdruck: Anzahl, Gesamtgroesse und juengste Aenderung von
workspace, assets, server, webdesign und den Seiten im
Wurzelverzeichnis — 670 Dateien in 27 ms. Kein Hash ueber den
Inhalt: Gesucht ist „hat jemand gespeichert", und das aendert immer
mindestens die Zeit.

BILDER ZAEHLEN NICHT. Die Messdateien legen selbst welche ab; eine
Wache, die bei jedem Bildschirmfoto anschlaegt, wird weggeklickt und
nimmt die echte Meldung mit.

SIE HAELT NICHTS AN. Ein Lauf, dessen Grundlage sich verschoben hat,
ist nicht „nicht in Ordnung" — er ist NICHT NACHSEHBAR. Deshalb
Rueckgabewert 3 (nicht 1, das waere eine Aussage ueber den Code; und
nicht 0, ein gruener Haken ueber einen Stand, den es nicht mehr
gibt, waere das Schlimmere) und ein ausdruecklicher Satz, dass das
kein Befund ist.

GEPRUEFT — pruef-arbeitsschloss 35 -> 48 Pruefungen, 0 Fehler:

  zwei Aufnahmen hintereinander gleich   (sonst waere jede Meldung
                                          wertlos)
  geaenderte Datei            -> faellt auf
  neue Datei                  -> faellt auf
  neues Bild                  -> faellt NICHT auf
  Lauf mit Aenderung          -> Rueckgabe 3, sagt NICHT NACHSEHBAR
  Lauf ohne Aenderung         -> Rueckgabe 0  (Gegenprobe; sonst
                                 waere „endet mit 3" auch wahr, wenn
                                 sie IMMER 3 meldet)

Alles in einem Wegwerf-Verzeichnis mit gefaelschtem Baum — moeglich,
weil die Wache ihre Wurzel aus ihrem EIGENEN Pfad ableitet. Waere
sie festgeschrieben, liesse sich die Wache nicht pruefen, ohne am
echten Haus zu wackeln.

UND AM ECHTEN LAUF NACHGEWIESEN: Mitten in pruef-arten eine Datei
gespeichert -> Rueckgabe 3, mit Groesse und Uhrzeit. Ohne Eingriff
bei neun Laeufen (treff 85, kalender 141, material 159,
erwaehnung 129, arten, dabei-optik, tagesblick, aufgabenbrett,
kopfleiste, seiteninhalt) kein einziger Fehlalarm.

EINE ERWARTUNG VON MIR WAR FALSCH, und die Wache hatte recht: Ich
hatte im gefaelschten Baum eine zaehlende Datei erwartet, es sind
zwei — die Seite UND die Kopie der Wache selbst im server-Ordner.
Der zaehlt mit, und das ist richtig: Eine geaenderte Pruefdatei
verschiebt den Stand genauso wie eine geaenderte Seite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 23:18:13 +02:00
DogFatherGitandClaude Opus 5 ec0ee61691 Arbeitsschloss: der Haken bleibt auf LF, und ein Messfehler von mir
ZWEI NACHTRAEGE ZUM SCHLOSS.

1. DER HAKEN HAT KEINE DATEIENDUNG

Damit greift keine der Regeln in .gitattributes von sich aus — und
git kuendigt beim Committen selbst an: „LF will be replaced by CRLF
the next time Git touches it". Auf Linux ist `#!/bin/sh` mit einem CR
dahinter ein Programmname mit einem unsichtbaren Zeichen am Ende
(„bad interpreter"), und die Datei hat schon einen Kommentar genau
darueber.

Eigene Zeile dazu: `tools/git-haken/* text eol=lf`.

NACHGEMESSEN, DAMIT HIER KEINE BEHAUPTUNG STEHT: Auf Windows
blockiert auch ein CRLF-Haken richtig — Rueckgabe 1, null Commits,
richtige Meldung. Das ist also Vorsorge und keine Reparatur. Aber ein
Haken, der still nicht laeuft, ist genau die Sicherung, die aussieht,
als waere sie da.

Zwei neue Pruefungen dazu: der Haken hat reine LF-Enden (byteweise
gemessen), und die Regel steht in .gitattributes.

2. EIN MESSFEHLER VON MIR, UND ER GEHOERT AUFGESCHRIEBEN

Ich habe gemeldet, im Verlauf lägen 73 CR-Bytes. Es war keines.
Gemessen hatte ich mit einer Rohrkette aus `tr` und `od`, und `tr`
nimmt in dieser Shell die Maskierung fuer das Wagenruecklauf-Zeichen
nicht als Zeichen — gezaehlt wurden am Ende Zeilenenden, und die
Datei hat 73.

Mit Python byteweise nachgemessen: 0 im Arbeitsbaum, 0 im Index. Die
Datei war immer LF; git hat nur VORHERGESAGT, was beim naechsten
Auschecken passiert.

Das ist heute der dritte Messfehler aus Shell-Maskierung — nach zwei
`\b`, die als Steuerzeichen in regulaeren Ausdruecken landeten und
dort je eine Pruefung lahmgelegt haben. Und beim Aufschreiben dieser
Lehre ist sie mir ein viertes Mal passiert: Aus dem Kommentar
`tr -d '\r'` wurde `tr -d ''`, die Aussage hat sich selbst bewiesen
und dabei unlesbar gemacht.

DIE REGEL STEHT JETZT, und zwar im Werkzeug selbst: Alles mit einem
Rueckstrich gehoert in eine DATEI, nie in ein Hier-Dokument. Und wer
Bytes zaehlen will, zaehlt Bytes — `readFileSync` ohne Zeichensatz,
und 13 ist 13.

GEPRUEFT: pruef-arbeitsschloss 33 -> 35 Pruefungen, 0 Fehler.
Steuerzeichen im ganzen Haus: 834 Dateien, keines.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 20:07:20 +02:00
DogFatherGitandClaude Opus 5 603319a145 Arbeitsschloss: zwei Sitzungen sehen sich jetzt
HEUTE ZWEIMAL NUR GUTGEGANGEN. Zwei Claude-Sitzungen arbeiteten
gleichzeitig in diesem Verzeichnis, ohne voneinander zu wissen.
Keine hat etwas falsch gemacht — sie konnten es nicht wissen.

  * Beide haben `git add -A` benutzt. Haette die eine
    unfestgeschriebene Arbeit der anderen im Baum gehabt, waere sie
    mitcommittet worden — unter fremdem Namen, in einer fremden
    Begruendung, und niemandem waere es aufgefallen. Nachgesehen:
    diesmal war nichts dabei.
  * Beide haben den Stempellauf gestartet. Der schreibt 45 Dateien
    um. Wer dort eine offen hatte, bekam sie unter den Haenden weg
    geaendert.

Dasselbe hat in RunOne am 03.09.2026 sieben Minuten Ausfall
gekostet. Dort gibt es seitdem `arbeitsschloss.sh`; diese Fassung
uebernimmt seine Lehren.

WAS ES IST UND WAS NICHT. Es ist kein Riegel — wer wirklich muss,
kommt vorbei. Es beantwortet die eine Frage, die heute niemand
beantworten konnte: „arbeitet hier gerade sonst jemand?"

Die teuren Fehler liegen bei einem Schloss alle in derselben
Richtung: Es blockiert zu viel und wird deshalb abgeschafft. Also:

  * Es blockiert NICHT, wenn das Schloss DEINES ist. RunOnes erste
    Fassung fragte „ist abgeschlossen" statt „haelt es jemand
    anders" — damit haette, wer ordentlich abschliesst, nie mehr
    ausliefern koennen. Dafuer gibt es `fremd`.
  * Es VERFAELLT nach zwei Stunden, und dass da jemand war, steht
    beim Uebernehmen dabei.
  * Es blockiert NICHT, wenn es selbst unlesbar ist — dritter
    Ausgang, kein Stillstand.
  * Notausgang: SCHLOSS_ZWANG=ja git commit …

DAS PROBLEM, AN DEM RUNONE HAENGT, IST HIER GELOEST. Dort faellt die
Kennung im Zweifel auf den Systembenutzer zurueck, und zwei
Claudian-Sitzungen laufen BEIDE als `claudian` — die Sicherung griff
ausgerechnet zwischen den zwei Faellen nicht, fuer die sie gebaut
wurde. Deshalb ist dort `export ARBEITER=…` Pflicht, und Pflicht
heisst: man vergisst es.

Hier steht `CLAUDE_CODE_SESSION_ID` in jeder Sitzung und ist je
Sitzung verschieden (nachgesehen, 36 Zeichen UUID). Zwei Sitzungen
auf demselben Windows-Benutzer unterscheiden sich damit von selbst,
ohne dass jemand etwas tun muss. Reihenfolge: ARBEITER, dann
Sitzungskennung, dann Benutzername MIT Warnung.

NIEMAND MUSS DARAN DENKEN:
  * die beiden Stempelwerkzeuge nehmen es selbst und geben es selbst
    frei — auch nach einem Absturz und bei Strg+C (wie `bauen.sh` im
    Shop; eines, an das man denken muss, wird vergessen und ab da
    umgangen)
  * `tools/git-haken/pre-commit` bricht jeden Commit ab, solange
    jemand ANDERS das Schloss haelt. Das ist die Stelle, die heute
    gefehlt hat: `git add -A` ist der Griff, den man ohne Nachdenken
    macht, und gegen einen Reflex hilft keine Regel auf Papier.
  * `core.hooksPath` statt `.git/hooks` — letzteres ist nicht
    versioniert und waere nach einem Klon genau dann leer, wenn es
    gebraucht wird.

GEPRUEFT, server/pruef-arbeitsschloss.mjs: 33 Pruefungen, 0 Fehler —
in einem WEGWERF-Verzeichnis mit eigenem git, damit kein echtes
Schloss angefasst wird. Darunter am echten git:

    ohne Schloss committen        -> geht      (0)
    mit dem EIGENEN Schloss       -> geht      (0)
    mit einem FREMDEN Schloss     -> bricht ab (1), nennt wer und warum
    und es stehen genau ZWEI Commits da, nicht drei
    SCHLOSS_ZWANG=ja              -> kommt vorbei
    ohne das Schloss-Werkzeug     -> laesst durch

Dazu: verfallenes Schloss laesst durch, mit laengerer Frist blockt
dasselbe Schloss wieder (Gegenprobe), unlesbarer Inhalt und
unlesbarer Zeitstempel blockieren nicht.

Portnummern nach der neuen Pruefdatei nachgemessen: Pruefbereich bis
5415, 462 Nummern, 0 Kollisionen. pruef-struktur 75/0,
pruef-fingermass 5/0, pruef-ports 10/0.

In DEPLOY.md steht es jetzt an erster Stelle — eine Sicherung, von
der nur der weiss, der sie gebaut hat, ist die erste, die umgangen
wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 20:04:28 +02:00
DogFatherGitandClaude Opus 5 1afb38258c Anfuehrungszeichen: drei Loecher in meiner eigenen Wache
Die zweite Sitzung hat in den Praesentationen des Vaults 83 Stellen
gefunden — und damit auf Loecher in MEINER Wache gezeigt. Ich habe
sie nachgemessen, alle drei waren echt.

LOCH 1 — SIE SAH NUR `server/workspace-*.js`

Also ausgerechnet nicht `workspace.js`, die groesste Datei des
Hauses. Der weitere Filter fand dort sofort drei Stellen:

    workspace.js:3404  Kanal „Chat-Moderation"     (Protokoll)
    workspace.js:3422  „${titel}" -> ${haus}       (Protokoll)
    workspace.js:3304  „${… || "ohne Titel"}"      (siehe Loch 3)

Das ist heute der DRITTE Fall von „die Wache kennt nur die halbe
Menge" — nach pruef-struktur (sah nur die Pruefdateien, nicht die
Anwendung) und pruef-fingermass (sah keine variable Breite).

LOCH 2 — IHR AUSDRUCK GILT JE ZEILE

Ein `„`, das erst in der naechsten Zeile mit einem geraden `"`
schliesst, fiel durch. Gemessen: drei echte Faelle, zwei davon
sichtbarer Seitentext.

    workspace/leistung.html       „nicht / zugeordnet"
    workspace/leistung.html       „Backstage-Tabelle / einfuegen"
    workspace/assets/js/ampel.js  „noch ' + 'verbessern"

Beim letzten laeuft das Zitat ueber eine Zeichenketten-Verkettung.

Neue Regel ohne Fehlalarme: erst alle RICHTIG geschlossenen Paare
entfernen (auch mehrzeilig), dann die einzeilig falschen (die meldet
die alte Regel). Was danach noch ein `„` hat und binnen drei Zeilen
ein gerades `"`, ist ein Fund. Ausgenommen bleibt das Zeichen ALS
WERT — in `content: "„";` und in den Sprachtabellen ist das `„` der
Inhalt und das `"` die Begrenzung.

LOCH 3 — EINE AUSNAHME, DIE EINEN FUND VERSCHLUCKT HAT

Gefunden durch die ZAHL, nicht durch den Blick: Der weitere Filter
liess die Ausnahmen von 12 auf 13 steigen. Die dreizehnte war

    `… „${zeile[titelSpalte] || "ohne Titel"}"`

Der Ausdruck blieb am `"` von `"ohne Titel"` haengen; als Inhalt kam
`${zeile[titelSpalte] || ` heraus, das endet auf ein Leerzeichen,
und damit galt „der Satz geht in der naechsten Zeile weiter". Das
echte Schlusszeichen stand hinter dem `}` und war gerade.

Dass die Ausnahmen gezaehlt UND genannt werden, hat ihn gefunden.
Genau dafuer steht die Zeile dort.

Behoben an der Wurzel: Anfuehrungszeichen innerhalb einer Einsetzung
`${…}` werden vorher durch X ersetzt, bei gleicher Laenge und
gleichen Zeilenumbruechen. Das nimmt einer ganzen Sorte
Fehlklassifizierung die Grundlage — die Ausnahmen fielen danach von
13 auf 11.

UND EIN VIERTES, BEIM MESSEN AUFGEFALLEN

`„Van-Van”` in assets/js/data-modis.js schliesst mit U+201D, dem
ENGLISCHEN Zeichen. Zweimal, beide Male in einer DEUTSCHEN Zeile
(`de:` und `"de-CH":`) — nicht einmal eine Uebersetzung, in der es
richtig waere. Eigene Regel dafuer, die keine Ausnahme braucht: Wer
mit `„` oeffnet, schliesst deutsch; in fremdsprachigen Zeilen steht
gar kein `„` am Anfang.

DIE AUSNAHMEZAHL IST JETZT STRENG. Sie stand auf „hoechstens 12" —
damit waere der Anstieg auf 13 nicht aufgefallen. Jetzt genau 11,
wie bei den Grundlinien in pruef-fingermass.

GEPRUEFT: pruef-struktur 68 -> 75 Pruefungen, 0 Fehler. Dazu
leistung-optik 59/0, ampel 47/0, treff 85/0, modi-verborgen 87/0 —
die Seiten, deren Text ich angefasst habe. Steuerzeichen: 830
Dateien, keines. Beide Stempel gesetzt.

Sechs echte Stellen berichtigt, vier neue Gegenproben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 19:28:38 +02:00
DogFatherGitandClaude Opus 5 2b3f140112 Wissen: ein gerades Schlusszeichen, von der Wache gefunden
workspace/assets/js/wissen.js:556

    ... legst du unter „Dateien" ab.      (gerades ")
    ... legst du unter „Dateien“ ab.

Die Zeile ist nicht von mir: Sie kam heute um 14:33 aus einer
zweiten Sitzung im selben Verzeichnis (Commit 63a56980). Die Wache,
die ich heute Vormittag gebaut habe (95c4599b), hat sie beim ersten
Lauf danach gemeldet — mit Datei und Zeile.

GENAU DAFUER WAR SIE DA. 199 Stellen aufzuraeumen ist nichts wert,
wenn am Abend desselben Tages die naechste dazukommt. Zwischen
Aufraeumen und erstem Rueckfall lagen fuenf Stunden.

NACH DEM FREMDEN ZUSAMMENLAUF DAS HAUS DURCHGESEHEN:
  pruef-struktur         68 / 0   (nach dieser Berichtigung)
  pruef-wissen-formular  30 / 0   (neu, aus der anderen Sitzung)
  pruef-dateien-liste    15 / 0   (neu, aus der anderen Sitzung)
  pruef-wissen-neu       16 / 0
  pruef-ports            10 / 0   460 Ports durchprobiert
  pruef-portnummern      41 / 0
  pruef-fingermass        5 / 0

UND EINE WACHE, DIE ICH BEWUSST NICHT GEBAUT HABE: Nach den zwei
Zeitbomben von heute (pruef-dabei-optik, pruef-chat-anhaenge — beide
gruen allein, rot unter Last) habe ich die ganze Klasse
nachgemessen. 850 feste Wartezeiten in 139 Dateien — dagegen eine
Wache zu bauen waere eine Warnung, die immer kommt.

Das engere Merkmal der beiden echten Faelle: Sie lasen einen Wert,
den eine Ueberblendung DURCHLAEUFT (`opacity`), nach einer festen
Wartezeit. Gemessen: 8 solche Stellen im ganzen Haus, 4 ohne
Absicherung — drei davon sind die heute reparierten, und die vierte
(pruef-glocke:380) ist keine: Am `.glocke__strich` haengt gar keine
Blende, nur an Rahmen, Hintergrund und Farbe.

Also null echte Funde und vier Fehlalarme. Eine solche Wache ist
schlechter als keine. Die Lehre steht stattdessen ausfuehrlich an
den zwei Stellen, an denen sie etwas gekostet hat.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 19:17:49 +02:00
DogFatherGitandClaude Opus 5 159036efc9 helfer-port: die gemessene Zahl ist ein Stand, keine Wahrheit
Im Kommentar stand „die Pruefungen reichen bis 5409, Luft fuer 245
weitere Dateien". Noch am selben Tag kamen zwei Pruefdateien aus
einer anderen Sitzung dazu, und daraus wurde 5413/243.

Das ist kein Fehler, sondern der Beweis, dass die Umstellung von
gestern richtig war: Zwei fremde Dateien haben alle Nummern
dahinter verschoben, und es musste niemand etwas nachtragen.
Nachgemessen danach: 460 Nummern, alle verschieden, 0 Kollisionen,
pruef-ports 10/0 und pruef-portnummern 41/0.

Aber eine Zahl im Kommentar, die sich am Tag ihrer Messung schon
bewegt hat, ist genau die Sorte, der jemand spaeter glaubt. Sie
steht jetzt als STAND da, mit dem Hinweis, wo die heutige zu holen
ist: pruef-portnummern sagt sie bei jedem Lauf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 15:50:41 +02:00
DogFatherGitandClaude Opus 5 b2b016f8dd Reaktion auf 320 px: das Bild ist ganz zu sehen
NACHGEMESSEN, wie es nach dem Einklappen der Reiterleiste wirklich
aussieht — und zwar im ANFANGSZUSTAND, mit zugeklappter Leiste:

                Regie   Raum   Kino   Schiene   Pult   Transport
    412x915       45     620    232     388      128     181
    390x844       45     549    219     330      128     181
    360x640       45     345    203     143      128     181
    320x568       45      75     75       1      198     181

Die Regieleiste ist von 101 bzw. 148 auf 45 Pixel geschrumpft — auf
320 px sind das 197 gewonnene Pixel.

EIN MESSFEHLER VON MIR, hier festgehalten: Mein erster Lauf zeigte
die Leiste GROESSER als vorher (148, 195, 242). Das Werkzeug klappt
sie weiter oben selbst auf, um die Register zu messen, und ich habe
danach die Hoehen gelesen. Gemessen war also der falsche Zustand —
eine Messung, die veraendert, was sie misst.

WAS AUF 320 BLEIBT: Der Raum hat 75 Pixel, das Bild wollte 180. Das
Pult liegt mit `z-index: 60` darueber, die Knoepfe sind also
erreichbar — und genau deshalb melden pruef-breiten und pruef-handy
nichts. Zu sehen war vom Bild trotzdem nur das obere Drittel.

`max-height: 100%` an der Leinwand. Gemessen wird der Kasten damit
320x75; die Breite bleibt, das Verhaeltnis gilt nicht mehr — aber
der Spieler darin setzt das Bild mittig mit Balken links und
rechts. Es ist klein und GANZ, statt gross und zu zwei Dritteln
hinter dem Pult.

(Im Kommentar stand zuerst, die Breite folge dem Verhaeltnis. Tut
sie nicht — 320x75, nicht 133x75. Berichtigt, bevor jemand sich
darauf verlaesst.)

AUF 360, 390 UND 412 AENDERT SICH NICHTS: Dort ist der Kasten
hoeher, als 16:9 verlangt, und `max-height` greift nicht ein.
Nachgemessen: 203, 219, 232 — wie vorher.

GEPRUEFT: pruef-handy 186/0, pruef-breiten 23/0, pruef-reaktion
421/0, mess-quer „NICHTS rollt seitlich".

EHRLICH BLEIBT: 320x568 zeigt weiterhin keinen Chat (Schiene 1 px),
und das Bild ist dort 320x75. Mit 198 Pixeln Pult und 181 Pixeln
Transport von 499 geht nicht mehr. Das waere ein eigener Schritt
und eine eigene Entscheidung — kein Nebenbei.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 15:47:14 +02:00
DogFatherGitandClaude Opus 5 63a56980c0 Wissen: Eine Absage ohne Alternative ist eine halbe Antwort
Wer eine Nicht-PDF in die Ablage zieht, bekam "Das ist keine
PDF-Datei." -- richtig, aber eine Sackgasse. Filipe hat heute eine
HTML-Praesentation dort abzulegen versucht, keinen Weg genannt
bekommen und den Fehler bei sich gesucht.

Jetzt steht dabei, wohin sie gehoert: unter "Dateien". Das ist die
einzige Stelle, an der wir es ueberhaupt sagen koennen -- beim
Auswaehlen ueber den Knopf greift schon `accept`, und die Datei ist
im Fenster des Betriebssystems gar nicht erst anklickbar.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 14:33:06 +02:00
DogFatherGitandClaude Opus 5 5a9f1f467c Wissen und Dateien: Zwei Raster, die ihren Inhalt verloren haben
Filipe zum Bildschirmfoto der Wissen-Seite: "erstens sieht das richtig
scheisse aus". Zu sehen war die Kategorie-Auswahl quer ueber "STUFE",
"GERAET", "VEROEFFENTLICHT AM" und den Tag-Knoepfen. Text auf Text.

Zweimal dieselbe Ursache, zweimal ein Raster, das Kinder in eine Zelle
zwingt, die zu klein ist:

1. FORMULAR "NEUE ANLEITUNG" (aufgaben.css). Die Regel
   `grid-template-rows: 1fr 44px` gibt jeder Zelle eine feste
   Eingabezeile -- richtig und wichtig, damit alle Felder auf einer
   Linie sitzen. Die Zelle "Hauptkategorie" enthaelt aber keine
   Eingabe, sondern sechs Gruppen mit zwanzig Knoepfen. Gemessen: der
   Kasten 40 px hoch, sein Inhalt 442 -- 402 px liefen ueber alles
   darunter. Unter 560 px passierte das nicht, weil dort ohnehin
   `auto auto` gilt; deshalb sah es am Handy richtig aus.
   Es ist exakt die Falle, die eine Regel darueber schon einmal
   zugeschnappt ist ("EINE ZELLE, DIE AUFKLAPPT ..."). Dieselbe
   Antwort, diesmal fuer .katwahl.

2. DATEILISTE (dateien.css). .datei hat die Spalten `34px 1fr auto`.
   Die ersten vier Kinder sitzen richtig; alles danach wird automatisch
   platziert und landet in der ZEICHENSPALTE. Gemessen: "Fassung 2" in
   34 px Breite, 22 px herausragend; auf 390 px zusaetzlich die
   Metazeile ("1,9 MB" in zwei Zeilen) und "Sichtbar fuer" mit 49 px
   Ueberstand.

ZWEI NEUE PRUEFUNGEN, und die erste war erst selbst falsch:
pruef-wissen-formular.mjs verglich zunaechst den KASTEN der Auswahl mit
dem der Zelle und meldete gruen, waehrend das Bildschirmfoto die
Ueberlappung deutlich zeigte. Der Kasten ist ja brav 44 px hoch --
herausgelaufen ist sein INHALT. Jetzt wird scrollHeight gegen
clientHeight gemessen, und die Pruefung wird rot, bevor der Fix
dazukommt. pruef-dateien-liste.mjs legt bewusst zweimal dieselbe Datei
ab, damit "Fassung 2" und "nicht mehr aktuell" ueberhaupt entstehen.

Versionsstempel neu gesetzt (202610011426, 670 Verweise in 45 Dateien).
Ohne ihn liegt die Korrektur auf dem Server und kommt bei niemandem an:
Cache-Control steht auf immutable.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 14:27:44 +02:00
DogFatherGitandClaude Opus 5 3a07c52499 Die drei dauerhaft roten Pruefungen sind gruen
Alle drei waren vorbestehend (Gegenprobe gegen den alten Stand
derselben Datei), und keine der drei war ein Fehler am Haus.

1. pruef-browser — WINDOWS BLOCKIERT WEBKIT

   Schritt fuer Schritt nachgegangen:
     - gemeldet: „WebKit: browserType.launch: Target page, context
       or browser has been closed"
     - nicht an paralleler Last; allein dasselbe Bild
     - `npx playwright install --force webkit` nennt den Grund:
       „Full list of missing libraries: icuuc77.dll"
     - die Datei IST da, 1,8 MB, im Ordner webkit-2336
     - Playwrights eigenes Werkzeug sagt, warum:
           PrintDeps.exe icuuc77.dll
           -> Eine Anwendungssteuerungsrichtlinie hat diese Datei
              blockiert.

   Smart App Control laesst die unsignierte Bibliothek nicht laden.
   Das ist eine Einstellung des Rechners, kein Fehler im Haus — und
   sie zu aendern waere Filipes Entscheidung, keine meine. (Smart
   App Control laesst sich nur ABschalten; wieder einschalten geht
   ohne Windows-Neuinstallation nicht. Fuer einen Testbrowser ist
   das der falsche Preis.)

   Der Kommentar im Code sagte es schon richtig — „eine Maschine,
   die nicht startet, ist nicht ,in Ordnung', sie ist nicht
   nachgesehen" —, umgesetzt war es als FEHLER. Jetzt drei
   Ausgaenge wie in pruef-ports: „BESTANDEN — 0 Fehler, 2 nicht
   nachsehbar". Damit daraus kein stiller Freispruch wird, haengen
   zwei Dinge daran: mindestens ZWEI Maschinen muessen wirklich
   gemessen haben, und die Zahl der Seitenaufrufe wird aus den
   gelaufenen Maschinen abgeleitet statt gegen eine feste 3
   geprueft.

2. pruef-crew-wand-bild — MEINE EIGENE FOLGEWIRKUNG VOM 30.09.

       anlegen("Marina", "modi", "CODE-MODI-0001");
       { name: "Modi", rolle: "creator", code: "CODE-MODI-0001" }

   Marina ist ein `modi`, angemeldet wurde sie mit der Kachel
   `creator`. Bis zum 30.09. war das egal; seit `718b267d` („die
   gewaehlte Kachel ist bindend", auf Filipes ausdruecklichen
   Wunsch) wird es zu Recht abgelehnt. Drei Befunde aus einer
   Wurzel, und mir ist es damals entgangen, weil ich nach der
   Aenderung die Pruefungen zum Zugang gelaufen bin und nicht die
   zum Wandbild.

   Die Ursache war aber nicht die falsche Zeile, sondern dass es
   ZWEI gab. `anlegen` gibt jetzt zurueck, was es angelegt hat, und
   die Anmeldung nimmt genau das. Nebenbei beweist die Pruefung
   damit zum ersten Mal, was sie beweisen sollte: Der Modi bekommt
   „Aufgaben · Team Dogi" und seine eigenen Zeichen.

3. pruef-chat-anhaenge — EINE BLENDE, DIE UNTER LAST STILLSTEHT

   Gemeldet: „0 Figuren" und „[]" statt der zwei Schriftzuege —
   aber nur mit vier parallelen Pruefungen. Allein zweimal gruen.

   Gemessen, was wirklich dasteht: lage „hoch", Figuren da, Bilder
   geladen (447x450), Deckung exakt „0". Nicht 0,3 oder 0,7 — die
   Ueberblendung hatte nicht ANGEFANGEN. Unter Last wird
   `requestAnimationFrame` gedrosselt, und eine Blende, die auf
   Bildern laeuft, steht still.

   Mein erster Versuch — „warten, bis sich nichts mehr aendert" —
   war genauso falsch wie die feste Wartezeit davor: Stillstand
   heisst auch „noch nicht angefangen", und er kam sofort zurueck.
   Auf eine Bewegung zu warten, die nicht laeuft, geht nicht.

   Also wird sie abgeschaltet. Das Haus hat die Regel schon:
   `@media (prefers-reduced-motion: reduce)` nimmt genau diesen
   beiden Dingen die Blende. Der Endwert steht damit sofort da, die
   Messung haengt nicht mehr am Rechner, und der Weg wird nebenbei
   zum ersten Mal wirklich begangen.

   Nicht tautologisch: Die Gegenprobe „und OHNE die zwei Figuren —
   die gehoeren ins Hochformat (0)" steht weiter und bleibt gruen.

GEPRUEFT, und zwar unter DERSELBEN vierfachen Last, die sie vorher
rot gemacht hat:

  pruef-chat-anhaenge  123 / 0     pruef-material      159 / 0
  pruef-crew-wand-bild  45 / 0     pruef-kalender      141 / 0
  pruef-browser       11+2 offen   pruef-start-ansicht 160 / 0
  pruef-dabei-optik     23 / 0     pruef-neue-seiten   109 / 0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 13:54:45 +02:00
DogFatherGitandClaude Opus 5 2f3b8630c7 Messungen am Telefon: 37 bekommen ihren Finger
Gestern Mittag gemessen: 39 `newContext`-Aufrufe nehmen ihre Breite
aus einer Variablen und setzen kein `hasTouch`. Ohne das meldet der
Browser `pointer: fine`, und KEINE Regel aus `@media (pointer:
coarse)` greift — dort stehen im ganzen Haus die 44-Pixel-
Beruehrziele, die ausgeblendeten Tastenkuerzel und die
eingeklappte Reiterleiste.

Was das anrichtet, war an pruef-breiten zu sehen: drei Befunde auf
320, 390 und 430 Pixeln, die mit dem Finger allesamt verschwanden —
Messfehler, keine Fehler.

37 DAVON HABEN IHN JETZT. Nur `hasTouch`, nicht `isMobile`: Gefragt
ist genau die eine Sache, um die es geht. `isMobile` waere eine
zweite Aenderung in derselben Zeile, und wenn danach etwas anders
aussieht, wuesste niemand, welche von beiden es war.

ZWEI BLEIBEN STEHEN, beide in pruef-grosscheck.mjs. Die Aenderung
dort waere ein Zweizeiler; sie zu pruefen hiesse, 206 Seiten ueber
vier Rollen laufen zu lassen, und das braucht Filipes Zusage. Eine
Aenderung, die ich nicht pruefen darf, liefere ich nicht aus.
Grundlinie in pruef-fingermass steht deshalb auf 2.

JEDE EINZELN NACHGELAUFEN — 37 Laeufe:

  34 gruen, darunter pruef-handy 186, pruef-material 159,
  pruef-start-ansicht 160, pruef-kalender 141, pruef-erwaehnung 129,
  pruef-bewerbung-aufgaben 163, pruef-neue-seiten 109

  3 mit Befunden, ALLE DREI VORBESTEHEND (Gegenprobe: alter Stand
  derselben Datei, gleicher Lauf, gleiche Zahl):
    pruef-browser        3  (WebKit startet auf diesem Rechner nicht)
    pruef-chat-anhaenge  2
    pruef-crew-wand-bild 3

EINE ZEITBOMBE GEFUNDEN UND ENTSCHAERFT

pruef-dabei-optik meldete „Haekchen: 0 -> 0" — aber nur, wenn vier
andere Pruefungen gleichzeitig liefen. Allein: „0 -> 1", gruen.

Dort stand `waitForTimeout(250)` mit der Begruendung „250 ms sind
reichlich ueber den 160" (der Dauer der Blende). Auf einem Rechner,
auf dem nebenher vier Browser messen, sind sie es nicht. Die
Pruefung war damit gruen, solange nichts anderes lief, und rot im
Gesamtlauf — also genau dann, wenn niemand sie einzeln nachstellen
kann.

Eine Wartezeit ist eine Annahme ueber den Rechner. Gewartet wird
jetzt auf das, worauf es ankommt: dass das Haekchen da ist. Laeuft
die Frist ab, faellt die Pruefung mit dem ECHTEN Wert um und nicht
mit einem Messfehler. Gegenprobe: unter derselben vierfachen Last,
die sie vorher rot gemacht hat, jetzt gruen.

UND DIE GRUNDLINIE WIEDER STRENG. Ich hatte sie kurz auf
„hoechstens" gestellt — damit haette ein Rueckgang stillschweigend
Platz fuer die naechste Suende gedeckt. Genau davor warnt der Kopf
derselben Datei bei der anderen Grundlinie, und ich habe es eine
Stunde spaeter selbst falsch gemacht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 13:37:05 +02:00
DogFatherGitandClaude Opus 5 dc5e6a0c24 Reaktion: das Chatfeld bekommt einen Namen
pruef-handy-teamdogi meldete auf beiden Geraeten und fuer Modi und
Community dasselbe:

    reaktion.html: Bedienelement ohne Namen — input#chat-feld

Sein einziger Name war der PLATZHALTER. Der ist keiner: Er
verschwindet in dem Moment, in dem jemand anfaengt zu tippen, und
danach hat das Feld fuer ein Vorleseprogramm gar keinen Namen mehr.
Der Knopf daneben macht es seit jeher richtig
(`aria-label="Senden"`).

UND DER NAME WANDERT MIT. Das Feld sagt im Platzhalter, warum
gerade nicht geschrieben werden kann — „Der Chat ist gerade zu",
„Du bist gerade stumm geschaltet", „Gerade schreibt nur das Team".
Ein fester `aria-label` haette genau diese Auskunft fuer das Ohr
verschluckt. Er kommt deshalb aus derselben Zeile wie der
Platzhalter: eine Angabe, zwei Ausgaben. Zwei getrennte Texte
waeren die naechste Stelle, an der einer gepflegt wird und der
andere nicht.

GEPRUEFT

  pruef-handy-teamdogi  8 Befunde -> 14 Pruefungen, 0 Fehler
  pruef-reaktion        421 Pruefungen, 0 Fehler
  pruef-handy           186 Pruefungen, 0 Fehler

Damit ist die Liste der alten offenen Punkte abgearbeitet:
  - pruef-fingermass (Grundwert 1)       unveraendert 1, dazu eine
                                         zweite Zahl fuer die
                                         Faelle, die sie bisher gar
                                         nicht sehen konnte
  - Regie/Transport auf 320x568          die Ueberlappung ist weg
  - report.html 27x18 px                 gibt es nicht mehr; beide
                                         Messungen melden die Seite
                                         sauber (Notiz war veraltet)
  - Ueberstand pruef-handy-teamdogi      0 Befunde

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 12:24:46 +02:00
DogFatherGitandClaude Opus 5 48470961c7 Reaktion am Handy: nichts liegt mehr auf einem Knopf
AUSGANGSLAGE, gemessen: pruef-breiten meldete auf sechs von neun
Breiten einen verdeckten Knopf, pruef-handy auf allen drei
Telefonen. Immer dieselbe Stelle: „Offen", „Team" und „Zu" aus dem
Chatkopf lagen auf dem Pult. Wer sie antippte, traf „Starten" oder
„Beenden".

ENDSTAND: pruef-breiten 23 Pruefungen / 0 Befunde, pruef-handy 186 / 0,
mess-quer „NICHTS rollt seitlich", pruef-reaktion 421 / 0.

Davon waren DREI VON VIER Befunden Messfehler. Gefunden, weil ich
ihnen nachgegangen bin statt ihnen zu glauben.

1. pruef-breiten MASS OHNE FINGER

   newContext({ viewport: { width: breite, height: hoehe } })

   Ohne `hasTouch` meldet der Browser `pointer: fine`, und KEINE
   Regel aus `@media (pointer: coarse)` greift — dort stehen die
   44-Pixel-Beruehrziele, die ausgeblendeten Tastenkuerzel und seit
   heute die eingeklappte Reiterleiste. Auf 320, 390 und 430 Pixeln
   wurde also eine Seite vermessen, die es auf keinem Telefon gibt.
   Aufgefallen, weil mess-quer dieselbe Seite auf 390 MIT Finger
   misst und dort nichts findet. -> 390 und 430 sofort gruen.

2. DER VERDECKUNGS-FINDER KANNTE KEINE ROLLKAESTEN

   Gemeldet war auf 1024, 1920 und 2560 immer ein Feld AUS DEM PULT
   „unter" der Transportleiste — und auf 1280 und 1440 nichts. Das
   Pult rollt in sich; was unten herausgerollt ist, liegt
   rechnerisch dort, wo die Leiste steht, und `elementFromPoint`
   liefert die Leiste. Verdeckt ist da nichts — es ist weggerollt.
   Das Fenster kannte der Finder schon (`r.bottom < 0`), den
   Rollkasten nicht. -> drei Breiten gruen, die Gegenproben
   („ein echtes Hindernis wird gefunden") schlagen weiter an.

3. UND EIN ECHTER BEFUND, ZWEIMAL

   a) Reiterleiste: acht Register brauchen am Handy zwei Zeilen
      (100 px auf 360, 148 auf 320). Sie klappen jetzt hinter ihren
      eigenen Wert — dasselbe Muster wie die Tempo-Gruppe, und der
      Knopf zeigt, wo man steht. NICHT einzeilig zum Wischen:
      Filipes Ansage vom 28.09. galt dem Wischen nach links und
      rechts, und mess-quer misst genau das.

   b) Bei OFFENER Regie nimmt das Pult auf 412x915 vierhundert-
      vierundachtzig der 846 Pixel. Nebeneinander stehen Regie und
      Bild erst ab 1100 px. Am Fingergeraet tritt die Chatschiene
      deshalb beiseite, solange die Regie offen ist — wer etwas
      einstellt, muss das Bild im Auge behalten, den Chat nicht, und
      der ist einen Fingertipp entfernt.

4. MEINE EIGENE WACHE WAR BLIND — ZWEIMAL

   pruef-fingermass sucht `width: <Zahl>`. In pruef-breiten stand
   `width: breite`, eine Variable: kein Treffer, also „in Ordnung".
   Sie meldete dabei brav „1 blindes Fenster, unveraendert zur
   Grundlinie" — und war selbst blind. Jetzt gibt es einen dritten
   Ausgang: Breite vorhanden, aber keine Zahl, und kein hasTouch
   daneben -> „konnte nicht nachsehen", mit eigener Grundlinie.

   Beim ersten Anlauf meldete der 45 Faelle, darunter jedes
   `newContext({ permissions: [...] })`. Zu grob: Ein Fenster ganz
   OHNE Breite ist das Standardfenster, kein Telefon. Enger gefasst.

   UND DANN WAR DIE ZAHL 0 — WEIL DER AUSDRUCK TOT WAR. Das `\b` in
   `/\bwidth\s*:/` war ein echtes Rueckschritt-Zeichen (0x08),
   unsichtbar im Quelltext. Heute Nacht hat mich dasselbe schon
   einmal eine halbe Stunde gekostet. Mit heilem Ausdruck sind es
   39 echte Faelle — etwa mess-chat-liste bei 390 px ohne Finger.
   Als Grundlinie festgehalten: Sie darf nur sinken, jede neue
   faellt auf, und abgearbeitet wird Datei fuer Datei mit je einem
   Lauf danach.

   Ein Werkzeug sucht jetzt alle Steuerzeichen im ganzen Haus
   (tools, gitignoriert). Es fand zwei: meins von heute und ein
   aelteres in pruef-reaktion.mjs — `!/^none\b/.test(wert)` hat
   dort nie gegriffen. Beide bytewise ersetzt, 830 Dateien sauber.

5. mess-quer MUSS TUN, WAS EIN MENSCH TUT

   Es wartete auf eine SICHTBARE Reiterleiste und lief in die
   Zeitsperre, seit sie zugeklappt startet. Jetzt wartet es auf die
   Leiste und klappt auf — vor jedem Register, denn ein Klick
   schliesst sie wieder.

WAS NICHT GEMACHT WURDE, UND WARUM: Die Messwerte im Pult („Sehen
zu", „Mit Bild", „Gaeste", „Upload") standen in meiner eigenen
Auswahl als Sparposten. Beim Nachsehen steht beim Upload die
Begruendung im Quelltext: „der Unterschied zwischen ,es ruckelt bei
euch?' und ,ich sehe, dass es zu viel wird'". 26 Pixel gegen echte
Information waehrend der Sendung — falscher Tausch.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 12:10:29 +02:00
DogFatherGitandClaude Opus 5 d7f3e747b8 Reaktion: 26 Pixel zurueck fuer den Chat am Handy
Die rechte Gruppe der Transportreihe war auf 360x640 gemessen
122 Pixel hoch statt 44: In der dreispaltigen Reihe bekommt sie nur
89 Pixel Breite und bricht dreimal um. Das Wort „Weiter" davor ist
dabei eine Beschriftung fuer zwei Knoepfe, die ihre Aufgabe selbst
draufstehen haben — „Naechstes" und „Wechseln zu <Titel>".

Dieselbe Ueberlegung wie beim Wort „Tempo", das aus genau diesem
Grund schon weg ist. Am Rechner bleibt es: Dort ist Platz, und dort
ordnet es die Leiste.

GEMESSEN (mess-quer, mit Finger, Regie zugeklappt):

    Transportleiste   207 -> 181 px   auf 320, 360, 390 und 412
    Chatschiene       +26 px          auf jedem Handy
    Rechner/Tablet    unveraendert    (158 / 185)

WAS DAS NICHT LOEST, UND DAS SAGE ICH LIEBER GLEICH: Die verdeckten
Chatstufen auf 320 und 360 sind weiterhin da. pruef-breiten und
pruef-handy melden unveraendert 6 bzw. 3 Befunde. Der Grund steht
jetzt mit Zahlen im Quelltext — es ist eine Platzfrage, keine
Regelfrage, und sie braucht eine Entscheidung.

EIN VERSUCH, DER ZURUECKGENOMMEN WURDE: `minmax(0, auto)` statt
`auto` an der Kinozeile des Raums. Gemessen null Pixel Unterschied
(Kino vorher wie nachher 203 px). Der Raum ragt naemlich nicht aus
eigener Kraft ueber seine Zeile — die Zeile hat auf 360 px noch
161 Pixel, und ein 16:9-Video auf 360 px Breite will 203. Keine
Angabe an DIESEN Zeilen aendert daran etwas. Die Begruendung steht
jetzt dort, damit es niemand ein zweites Mal probiert.

Eine Regel, die nur aussieht, als taete sie etwas, ist schlimmer
als keine.

GEPRUEFT: pruef-handy 186 Pruefungen (3 Befunde, unveraendert),
pruef-breiten 23 (6 Befunde, unveraendert) — also keine neue
Beanstandung und keine verschwundene Pruefung. Stempel gesetzt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 10:46:22 +02:00
DogFatherGitandClaude Opus 5 95c4599baa Anfuehrungszeichen: 199 falsche Schlusszeichen im sichtbaren Text
Deutsch oeffnet mit „ und schliesst mit “. An 199 Stellen, die ein
Mensch liest, stand als Schlusszeichen ein GERADES " -- „Nächstes"
statt „Nächstes“. Auf sechzehn oeffentlichen Seiten, in vierzig
Dateien des Workspace und in zwoelf Servermodulen, die Texte
verschicken.

Auf dem Bildschirm sieht man den Unterschied sofort. Beim Schreiben
nicht: Das gerade " liegt auf der Tastatur, die anderen nicht.

WARUM EIN ERSTER ANLAUF ZURUECKGENOMMEN WURDE

Ein gerades " ist an vielen Stellen SYNTAX und kein Schriftzeichen --
Grenze einer Zeichenkette, Grenze eines HTML-Attributs, Zeichen in
einem regulaeren Ausdruck. Wer stumpf ersetzt, macht aus

    „<a href="https://…                  ein kaputtes Attribut
    /^["'„»\s]+|["'“«.\s]+$/              einen kaputten Ausdruck
    "… nichts „mal " + "eben …"          eine kaputte Zeichenkette

DIE UNTERSCHEIDUNG LAEUFT AN MERKMALEN, NICHT AN EINER LISTE

  < > = dazwischen        -> HTML-Marke oder Attribut
  endet auf Leerzeichen   -> die Zeichenkette hoert hier auf, der
                             Satz geht in der naechsten Zeile weiter.
                             Ein deutsches Schlusszeichen steht NIE
                             hinter einem Leerzeichen.
  Rueckstrich mittendrin  -> regulaerer Ausdruck
  ${ ohne }               -> mitten in einem Ausdruck

Eine Liste erlaubter Ausnahmen waere die naechste, die niemand
pflegt. Zwoelf Stellen bleiben dadurch stehen, alle zwoelf einzeln
angesehen und alle zwoelf zu Recht -- dort steht das richtige
Schlusszeichen ohnehin weiter unten im Satz.

Fuenf davon waren allerdings ECHTE Fehler HINTER dem Link
(`…>HasiDog</a>".`) -- die erste Regel hatte nur das Attribut
gesehen, nicht den Satz danach. Gezielt nachgezogen.

Ein maskiertes `\"` in workspace-vorlagen.js (28 Hooks) wird zu “ --
ohne Rueckstrich, denn “ begrenzt nichts.

KOMMENTARE BLEIBEN, WIE SIE SIND. Dort liest es niemand ausser mir;
eine Wache, die auch Kosmetik anmahnt, wird weggeklickt. Beim ersten
Messen fielen ausserdem acht Stellen aus buehne.html faelschlich an,
weil `/* */` in HTML (in <style> und <script>) nicht ausgeblendet
war -- jetzt schon.

DIE WACHE DAZU

pruef-struktur prueft es ab sofort mit derselben Regel: 322 Dateien
mit sichtbarem Text, 0 Funde, und die zwoelf bewussten Ausnahmen
werden GEZAEHLT und genannt (erlaubt: 12). Eine Ausnahme, die niemand
sieht, waechst -- und irgendwann steht der echte Fall darin.

GEPRUEFT

  pruef-struktur   59 -> 68 Pruefungen, 0 Fehler
  node --check auf allen geaenderten JS-Dateien
  nachgemessen: 199 geaendert, 12 mit Grund stehen geblieben

  gruen geblieben: bewerbung-aufgaben 163, nachwuchs 262,
  reaktion 421, support 63, content 45, terminregel 35, treff 85

  Und nachgesehen, ob eine Pruefung noch die alte Schreibweise
  ERWARTET: 13 Fundstellen, alle dreizehn nur Text in ihrer eigenen
  Ausgabe, keine einzige ein Vergleich mit dem Seitentext.

GEGENPROBE: In reaktion.html ein Schlusszeichen zurueckgedreht ->
„workspace/reaktion.html:546 „Nächstes"", mit Datei und Zeile. Und
die Erkennung einzeln gegen HTML-Attribut, fortgesetzte
Zeichenkette, regulaeren Ausdruck und eingesetzten Wert geprueft.

Stempel gesetzt: workspace 670 Verweise in 45 Dateien, oeffentlich
554 in 48 Seiten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 01:56:15 +02:00
DogFatherGitandClaude Opus 5 7dc5356c80 Datum: der Tag kommt aus der Ortszeit, nicht aus UTC
GEFUNDEN UM 01:22, von pruef-kreislauf -- und nur, weil nachts
gearbeitet wurde.

Die Pruefung legt einen Wunsch mit dem HEUTIGEN Datum an und macht
daraus einen Termin. Gemessen:

    geschickt:   datum = 2026-10-01   (heuteLokal auf dem Server)
    gespeichert: datum = 2026-09-30

Der Termin lag also in der Vergangenheit. Auf „Was ansteht" sortiert
er sich damit in den Abschnitt „Vorbei" ein -- und der ist mit
Absicht zugeklappt. Beim Wunsch stand „Daraus wurde ein Termin", auf
dem Brett war er nicht zu sehen. Zwei Stunden jede Nacht (im Winter
eine), genau in den Stunden, in denen hier gearbeitet wird.

URSACHE

    const jetzt = () => new Date().toISOString();   // UTC
    ... jetzt().slice(0, 10) ...                     // UTC-Tag

ES WAR NICHT EINE STELLE. Nachgemessen: SECHZEHN in vierzehn Modulen,
davon ZEHN, die den falschen Tag in die Datenbank schreiben --
Termine, Wuensche, Highlights, Talente, Leads, Videos, Vorlagen --
und sechs, die „heute" vergleichen (ueberfaellige Aufgaben, Berichte,
die Frist einer Entwicklungsaufgabe).

NICHT ANGEFASST, WEIL RICHTIG: Rechnungen auf einem Datumstext mit
fester Uhrzeit (`Date.parse(tag + "T12:00:00Z") + n * 86400000`). Die
bleiben in jeder Zeitzone am selben Kalendertag -- kalender, teamlage
und serien machen es so, und das bleibt.

WARUM ES NIEMAND GEMERKT HAT

pruef-struktur sucht dieses Muster seit dem 06.09.2026. Aber:
  - sie sah NUR in die `pruef-*.mjs`, nie in die Anwendung
  - sie kannte die Schreibweise ueber eine FUNKTION nicht
    (`const jetzt = () => ...` statt `const jetzt = ...`)

Die Wache stand vor den Pruefungen, nicht vor dem Haus -- derselbe
Fehler wie heute Nacht bei den Messports: eine Sicherung, die nur die
halbe Menge kennt, faellt in der anderen Haelfte aus, und zwar
lautlos, denn sie meldet ja „nichts gefunden".

Jetzt sieht sie in beides und kennt beide Schreibweisen. Beim ersten
scharfen Lauf fand sie sofort 23 weitere Stellen in den Pruefdateien
selbst -- dieselben Zeitbomben, gegen die sie gebaut worden war.

EINE ZWEITE WACHE, WEIL ICH SELBST HINEINGELAUFEN BIN

Mein Umbauwerkzeug hat in elf Modulen `heuteLokal()` eingesetzt und
die Einfuhr weggelassen: Es hat erst ersetzt und DANN gefragt, ob der
Name schon in der Datei steht -- da stand er, mein eigener Aufruf.
`node --check` sagt dazu nichts, „Laedt jedes Server-Modul?" auch
nicht: Die Datei ist syntaktisch tadellos. Erst der Aufruf faellt um
mit `ReferenceError: heuteLokal is not defined`. Gefunden hat es
pruef-video, zufaellig. Die anderen zehn waeren durchgerutscht.

Deshalb neu: „Ruft ein Modul etwas, das es nie eingefuehrt hat?" --
die Namen des Hauses aus den export-Zeilen gelesen, nicht
aufgezaehlt. 460 Aufrufe in 350 Dateien, alle mit Einfuhr.

pruef-kreislauf STELLT JETZT DIE RICHTIGE FRAGE

Sie war rot und hat den Fehler dabei nur gestreift: „`.kette` wird
nicht sichtbar", Zeitsperre nach 15 s. Das klingt nach der Anzeige
und schickt einen zur falschen Stelle. Neu:
  - eine Zeile fragt das DATUM (ohne Browser, nennt den Fehler beim
    Namen)
  - der Browserteil klappt zu, was zu ist, und misst dann die Kette;
    „gar nicht da" wird von „da und unsichtbar" unterschieden

NEBENBEFUND IN pruef-ics

Die Probe „fast richtig" war `echt.slice(0, -1) + "A"`. Der
Schluessel ist base64url; sein letztes Zeichen ist eines von
sechzehn. Endet er auf „A", IST die Probe der echte Schluessel, der
Server antwortet zu Recht mit 200, und die Pruefung meldet ein Loch,
das es nicht gibt -- einmal je sechzehn Laeufe. Heute Nacht zweimal
hintereinander, und die Suche ging eine halbe Stunde in eine
Aenderung, die damit nichts zu tun hatte.

GEPRUEFT

  pruef-struktur   44 -> 59 Pruefungen, 0 Fehler
  pruef-ics        37 -> 38, 0 Fehler
  pruef-kreislauf  Absturz bei Nr. 17 -> 25 Pruefungen, 0 Fehler

  und gruen geblieben: treff 85, arten 28, video 74, uebernahme 39,
  entwicklung 79, content 45, vorlagen 24, zuteilung 75,
  scout-zuteilung 37, unterstuetzung 70, aufbewahrung 45,
  bewerbung 91, treff-start 42, uebergang 65, nachwuchs 262,
  auskunft 46, modi-ideen 30, neue-seiten 109, spicy 85,
  wege-nach-draussen 67, aufgabenbrett 49, agentur 62,
  bereiche-lesend 37 -- beide Haeuser

GEGENPROBEN, DIE WIRKLICH ROT WERDEN

  - den UTC-Tag im `daraus`-Weg wieder eingebaut: pruef-kreislauf
    meldet „er liegt HEUTE, nicht gestern (2026-09-30, heute ist
    2026-10-01)", 25 Pruefungen, 1 Fehler -- und der Browserteil
    bleibt gruen, weil er jetzt aufklappt. Jede Frage bei ihrer
    eigenen Pruefung.
  - eine Einfuhr aus workspace-video.js entfernt: die neue Wache
    meldet „workspace-video.js: heuteLokal() (aus helfer-tag.mjs)"
  - beide Erkennungen je gegen einen gebauten Rueckschritt geprueft
    (Funktion, Variable, zwei Schritte, Date.now-Rechnung) und gegen
    das, was NICHT anschlagen darf (UTC-Mittag, voller Zeitstempel,
    fremdes Date, Name im Kommentar, Eigenschaft am Objekt)

EIN FEHLER BEIM UMBAU, HIER FESTGEHALTEN: Mein erster Lauf ueber die
Pruefdateien hat stumpf ersetzt und dabei KOMMENTARE umgeschrieben --
in sieben Dateien stand die alte Schreibweise als Beleg in der
Begruendung, und daraus wurde das Gegenteil. Bemerkt hat es der
Vergleich der Zahlen (34 Stellen statt der gemessenen 24), nicht die
Absicht. Zurueckgenommen und mit Schutz fuer Kommentare und
Zeichenketten wiederholt.

Datenbank vorher gesichert. Keine Schemaaenderung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 01:45:16 +02:00
DogFatherGitandClaude Opus 5 f6225d7341 Ports: auch die Messwerkzeuge leiten ihre Nummer ab
GEMESSEN, BEVOR ICH ETWAS ANGEFASST HABE:

  204 pruef-Dateien, abgeleitete Ports 5000-5409 (dicht belegt)
  24 mess-Dateien, Nummern von Hand: 4471 bis 5493
  davon IM Pruefbereich: 5387, 5397, 5397, 5399, 5399, 5401, 5403, 5405
  untereinander doppelt: 5397, 5399, 5461, 5483, 5491

Aufgefallen ist es, weil mess-buehne und mess-reaktion beide auf 5483
lagen und ein haengengebliebener Lauf gestern einen ganzen Messlauf
gekostet hat.

Beim Umbau kam das Groessere heraus: EINUNDZWANZIG der 24 Messdateien
hatten nicht nur eine Nummer von Hand, sondern ueberhaupt keinen
Waechter -- schlicht `const PORT = 5397;`. Liegt dort schon ein
Server, startet der eigene still nicht, und gemessen wird ab da ein
fremder Stand. Genau der Fehler, gegen den helfer-port.mjs gebaut
wurde; die Messdateien standen die ganze Zeit ausserhalb.

WAS JETZT GILT

Zwei Sorten, zwei Bereiche, beide abgeleitet aus der Stelle im
Alphabet -- jede Sorte unter ihresgleichen, sonst verschoebe eine
neue Pruefung die Nummern aller Messungen. Pruefungen ab 5000,
Messungen ab MESS_BASIS = 5900.

5900 und nicht 5500: dazwischen bleibt Platz fuer 245 weitere
Pruefdateien (bei 5500 waeren es 45). Nach oben 5948 + AUSWEICHEN
4000 = 9948, also unter 10080, der naechsten gesperrten Nummer.
Nachgerechnet, nicht geschaetzt -- eine geschaetzte 4500 hatte bei
BASIS schon einmal danebengelegen.

Eine Wache dazu: Waechst der Pruefbereich bis an MESS_BASIS heran,
bricht die Ableitung ab und sagt, was zu tun ist. Eine stille
Ueberschneidung waere genau der Fehler, den das hier beseitigt.

Die zweite Nummer kommt ueber nr=1, nie ueber `PORT + 1`:
portNummer ueberspringt gesperrte Nummern, deshalb kann die naechste
Zahl die Nummer der naechsten DATEI sein, sobald einmal eine Sperre
dazwischenliegt. Heute liegt dort keine -- das ist Glueck, kein
Entwurf.

NEBENBEI GEFUNDEN UND MIT REPARIERT

Sechs bild-*.mjs riefen den Waechter und warfen seine Antwort weg:

    await portMussFreiSein(4315, "das Bildwerkzeug");
    process.env.PORT = "4315";
    const BASIS = "http://127.0.0.1:4315";

Er lief, meldete nichts und wirkte nicht. Gibt das System den Port
dauerhaft nicht her, weicht er auf Port + 4000 aus und GIBT DIE NEUE
NUMMER ZURUECK -- diese Werkzeuge hoerten danach trotzdem auf der
alten und stuerzten mit `listen EACCES` ab, also mit genau dem
Fehler, gegen den er gebaut wurde. Dazu stand die Zahl dreimal je
Datei. Jetzt einmal, und die Antwort wird benutzt.

tiktok-videos.mjs hatte den Waechter ABGESCHRIEBEN -- eine kurze
eigene Fassung ohne den dritten Ausgang: Bei EACCES meldete sie
"belegt" und brach ab, statt auszuweichen. Auf diesem Rechner ist
genau das am 23.09. eingetreten (Port 5040, Windows-Dienst).
mess-fokus und mess-notizblock hatten dieselbe Abschrift. Eine
abgeschriebene Sicherung ist dieselbe Falle wie eine abgeschriebene
Liste.

GEPRUEFT

  pruef-portnummern  15 -> 41 Pruefungen, 0 Fehler
  pruef-ports         8 -> 10 Pruefungen, 456 statt 408 Ports geprobt
  node --check auf allen 33 geaenderten Dateien

Gegenproben, die wirklich rot werden:
  - eine Messdatei auf eine feste Nummer zurueckgesetzt -> 2 FEHL,
    danach wieder 41/0
  - die Wache: in einem Wegwerf-Ordner mit 452 pruef-Dateien bricht
    eigenerPort ab statt still zu ueberlappen; eine Datei knapp
    darunter bekommt weiter ihre Nummer (5846)
  - die Erkennungen fuer feste Nummern, PORT + 1 und weggeworfene
    Waechterantworten je gegen einen gebauten Rueckschritt

Am echten Verhalten gemessen:
  - mess-chat-liste und mess-alle-einzelsicht (beide vorher 5397)
    GLEICHZEITIG gestartet: 5906 und 5900, beide exit=0. Vorher war
    das unmoeglich.
  - die 48 neuen Nummern 5900-5947 auf diesem Rechner durchprobiert:
    keine belegt, keine vom System gesperrt
  - bild-chat.mjs durchgelaufen, drei Bilder, exit=0

Kein Eingriff am laufenden Dienst: helfer-port.mjs wird von index.js
und workspace.js nicht geladen (nachgesehen), nur von Pruef- und
Messwerkzeugen. Beide Haeuser unberuehrt -- es wird keine Zeile
angefasst, die eine Seite ausliefert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 01:19:41 +02:00
DogFatherGitandClaude Opus 5 8e18c7bcf0 Aufgaben: eine Bewerbung auf eine erledigte Aufgabe ist keine mehr
Beim Durchsehen der echten Daten am 30.09. gefunden, Filipe am
01.10.: „mach alles los."

GEMESSEN: Zwei Bewerbungen von Miss standen auf „beworben" -- an
Aufgaben, die laengst `erledigt` bzw. `review` waren. Bei ihr stand
weiter „wartet auf Antwort", und in der Liste der Leitung stand eine
Entscheidung an, die es nicht mehr gibt.

DAS MUSTER GIBT ES IM HAUS SCHON. `uebernahmeAbschliessen` raeumt
genau so die offenen Bewerbungen weg, wenn jemand anderes eine
Pool-Aufgabe bekommt -- samt dem Kommentar daneben: „Ohne diese Zeile
blieb eine Bewerbung auf ,beworben' stehen, nachdem jemand anders die
Aufgabe bekommen hat." Derselbe Fall, ein anderer Ausloeser, dieselbe
Behandlung.

ZWEI WEGE FUEHREN IN DEN ENDZUSTAND -- erledigen und abbrechen. Beide
rufen jetzt dieselbe Funktion; nur einen zu bedienen waere die
Haelfte, die man spaeter sucht. Der SATZ ist verschieden:
„abgebrochen" ist nicht „erledigt", und wer gewartet hat, soll den
Unterschied lesen koennen.

KEIN `entschieden_von`. Niemand hat entschieden, die Frage hat sich
erledigt. Dadurch faellt die Zeile auch aus der Absagen-Uebersicht
von gestern heraus (die fragt `entschieden_von IS NOT NULL`) --
richtig, es ist keine Absage an diesen Menschen.

KEINE BENACHRICHTIGUNG. „Deine Bewerbung: diesmal nicht" waere
falsch -- es hat niemand nein gesagt. Der Satz steht an der Zeile.
Wenn Filipe hier doch eine Meldung will, ist es eine eigene Art mit
eigenem Wortlaut, kein Anhaengsel an die bestehende.

GEPRUEFT -- pruef-bewerbung-aufgaben 163/0 (9 neue):

  bewirbt sich          -> „beworben"
  Aufgabe erledigt      -> faellt weg, mit Satz, ohne Entscheider
  Aufgabe abgebrochen   -> ebenso, mit anderem Satz
  Aufgabe noch offen    -> Bewerbung bleibt   <- die Gegenprobe

Ohne die letzte Zeile hiesse „faellt weg" womoeglich nur, dass jede
Bewerbung wegfaellt.

Ein eigener Messfehler unterwegs: Mein Lesehelfer fragte
`/api/aufgaben/:id` und bekam `undefined` -- die Antwort dort hat eine
andere Form. Vier Pruefungen waren rot, waehrend der Mechanismus im
Protokoll nachweislich lief. Jetzt ueber die Liste, die in dieser
Datei erprobt ist.

Die eine vorhandene Zeile wird nachgetragen; auf einer Kopie der
echten Datenbank durchgespielt (danach 0 offene Bewerbungen auf
durchgelaufenen Aufgaben, integrity_check ok).

pruef-zuteilung, pruef-aufgabenbrett, pruef-zwischenspeicher.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 00:59:27 +02:00
DogFatherGitandClaude Opus 5 09375047a7 Entwicklung: die Karte geht auf dem Zugetragenen auf
Filipe, 01.10.2026: „mach alles los." Damit auch der offene Punkt von
gestern: „Zugetragen" ist beim Aufmachen einer Karte die Vorgabe.

DER ALTE EINWAND BLEIBT GUELTIG -- er steht jetzt in der Bedingung
statt im Weg. Er lautete: „Ein Filter, der beim Öffnen schon etwas
versteckt, lässt einen Punkte suchen, die gestern noch da waren."
Richtig, und er trifft genau EINEN Fall: den, in dem gar nichts
zugetragen ist. Dann zeigte „Zugetragen" eine LEERE Karte, und eine
leere Karte sieht aus wie ein Fehler.

Also: Hat dieser Mensch zugetragene Punkte, steht der Filter darauf.
Hat er keine, steht er auf „Alle". Beides ist eine Auskunft, keines
ist eine Suche.

UND ER WIRD JE MENSCH NEU ENTSCHIEDEN. Bisher blieb der Filter ueber
den Personenwechsel hinweg stehen -- richtig, solange er eine
Erwartungsstufe meinte („wer Fortgeschritten gewaehlt hat, will das
weiter sehen"). „Zugetragen" ist eine Aussage UEBER DIESE PERSON;
sie mitzunehmen waere die falsche Frage.

GEMESSEN, beide Faelle:

  Diene (2 zugetragen)   -> Filter „Zugetragen", 2 Punkte
  VanVan (nichts)        -> Filter „Alle", 68 Punkte
  ein Klick auf „Alle"   -> wieder 68

Die Messung fragt jetzt, WAS DASTEHT, bevor jemand etwas anfasst.
Vorher klickte sie auf den Filter und zaehlte nach -- seit er die
Vorgabe ist, haette derselbe Klick ihn AUSgeschaltet. Sie haette das
Gegenteil gemessen und trotzdem eine Zahl gemeldet.

ZWEI NACHZUEGLER AUS DEM SICHT-WEG VON GESTERN

`pruef-werdegang` wurde rot: „403 Forbidden" im Browser, ohne Adresse.
Die Meldung sagte nicht, WORAN sie scheitert -- also sagt sie es
jetzt (`403 /workspace/api/chat/sicht`).

Die Ursache lag in der Messumgebung, nicht im Programm: Der
HTTPS-Vorbau der Pruefung reicht den Host OHNE Port weiter, waehrend
der Browser seine Herkunft MIT Port schickt. `gleicheHerkunft`
vergleicht beides und antwortet folgerichtig 403. mess-reaktion macht
es seit Langem richtig; zwei Dateien nicht.

Aufgefallen ist es erst jetzt, weil der Sicht-Weg der erste
zustandsaendernde POST ist, der auf JEDER Seite laeuft. Live stimmen
Herkunft und Host ueberein (beide ohne Port, Caddy reicht den Host
durch) -- nachgemessen.

GEPRUEFT
pruef-werdegang 103/0 (war 103/1), pruef-entwicklung 79/0,
pruef-entwicklung-kacheln 34/0, mess-vanvan-karte ohne ein einziges
ACHTUNG, pruef-zwischenspeicher 34/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 00:52:07 +02:00
DogFatherGitandClaude Opus 5 718b267de0 Zugang: die gewaehlte Kachel ist bindend
Filipe, 01.10.2026: „mach das. es soll fest sein."

VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode immer
noch über jeden Button der Startseite anmelden, egal welche Rolle man
hat."

ICH HATTE ZUERST ABGERATEN -- und lag falsch, weil ich eine alte Lage
beschrieben habe.

Am 09.09.2026 hatte Filipe entschieden, dass die Modis KEINE eigene
Eingangskachel bekommen: „damit die von der workspace auch nicht mal
sehen dass die modis von mir einen eigenen zugang haben." Wer keine
Kachel hat, muss irgendeine nehmen koennen -- daher der stille Zugang.

SEIT DER HAUSTRENNUNG AM 24.09.2026 STIMMT DAS NICHT MEHR. Auf
`crew.` steht laengst ein eigener Kachelsatz mit ALLEN fuenf Rollen:
DogFather, rechte Hand, linke Hand, Modi, Community (CREW_KACHEL, und
crew-index.html zeigt sie). Das Verbergen leistet seither die ADRESSE
-- wer sie nicht kennt, findet die Wand nicht; wer sie kennt, liest
die Rollennamen ohnehin offen darauf.

Der stille Zugang war damit ein Rest. Er hat niemanden mehr
geschuetzt und nur dafuer gesorgt, dass die Kachelwahl folgenlos
blieb. Nachgesehen habe ich das erst, NACHDEM Filipe widersprochen
hat; die Kachelsaetze standen die ganze Zeit im Quelltext.

WAS SICH NICHT AENDERT: Auf der Agenturwand war der stille Zugang nie
aktiv. Ein Team-Dogi-Code verhaelt sich dort weiterhin wie ein
erfundener -- gleiche Antwort, gleicher Weg, gleiche Dauer. Das ist
jetzt ausdruecklich gemessen.

EINE PRUEFADRESSE IST KEINE WAND. `127.0.0.1` ist weder crew. noch
Agentur. Ohne den stillen Zugang gaelte dort der Agentursatz -- und
kein Modi kaeme mehr herein. Fuenfzig Pruefdateien melden Team-Rollen
ueber diese Adresse an. Auf einer Adresse ohne Wand gibt es deshalb
ALLE Kacheln; welche auf welcher ECHTEN Wand steht, misst
pruef-modi-verborgen mit ausdruecklichem Host-Kopf.

GEPRUEFT -- pruef-modi-verborgen 87/0 (war 85; die fuenf Zeilen „jede
Kachel geht" sind durch sieben ersetzt, die die neue Regel und ihre
Gegenproben messen). Die Anzahl ist Zeile fuer Zeile verglichen.

  Modi-Kachel + Modi-Code      -> herein
  admin/hand/linke/gast        -> abgewiesen
  rechte Hand auf ihrer Kachel -> herein
  Agenturwand + Modi-Code      -> wie ein erfundener

pruef-crew-adresse 169/0 (unveraenderte Anzahl, zwei Zeilen
umgedreht).

SECHZEHN PRUEFDATEIEN MELDETEN SICH UEBER FREMDE KACHELN AN -- ein
Rest derselben Zeit. Systematisch gesucht statt einzeln entdeckt:
Waere ich dem roten Lauf hinterhergelaufen, haette ich beim zwoelften
aufgehoert.

UND DABEI EIN EIGENER FEHLER: Mein erster Durchlauf las die Rolle am
CODENAMEN ab (CODE-MODI- -> modi). Das ging gut, bis „Nane" kam: ein
Modi mit dem Code CODE-NANE-0001. Zwei Pruefungen wurden rot, und
zwar an einer Stelle („die Stimmen stimmen"), die mit Anmeldung
nichts zu tun hat. Ein Codename ist eine Beschriftung, keine
Tatsache -- die Rolle steht in `anlegen()`. Danach abgeleitet blieben
genau zwei Abweichungen uebrig, und beide sind absichtliche
Gegenproben.

Drei Browserpruefungen tippten die Creator-Kachel mit einem
Modi-Code. Die Modi-Kachel gibt es nur auf der Crew-Wand, und ein
Browser auf 127.0.0.1 bekommt die Agenturwand; sie melden sich jetzt
ueber die Schnittstelle an und bekommen den Keks. Gemessen werden
soll dort, was ein Modi SIEHT -- nicht, wie er hereinkommt.

Grün: pruef-modi-verborgen, pruef-crew-adresse, pruef-treff 85/0,
pruef-galerie, pruef-kanaele, pruef-modi-katalog 150/0,
pruef-modi-ideen, pruef-modi-kategorien, pruef-modi-checkliste 75/0,
pruef-modi-livecheck, pruef-kachelraster, pruef-team-ampel 32/0,
pruef-team-stufen 47/0, pruef-wunschliste, pruef-bremse,
pruef-gespraech, pruef-personen-formular 43/0, pruef-start-ansicht,
pruef-community-sicht, pruef-reaktion 421/0, pruef-abzeichen,
pruef-chat, pruef-chat-kanaele 81/0, pruef-entwicklung 79/0,
pruef-bewerbung-aufgaben 154/0, pruef-struktur,
pruef-zwischenspeicher 34/0.

`code_kennung` wird weiter geschrieben, aber nicht mehr gelesen --
sie war der Suchschluessel des stillen Weges. Stehen gelassen: Eine
Spalte zu entfernen ist eine Schemaaenderung mit Sicherung, und sie
kostet nichts.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 00:22:55 +02:00
DogFatherGitandClaude Opus 5 4503b1a475 Benachrichtigungen: nicht "Verbindung offen", sondern "sieht jemand hin"
Diene im Support (vor 5 Tagen): „Die Benachrichtigungen werden nicht
angezeigt, wenn neue Nachrichten reinkommen. Erst, wenn man die App
öffnet."

ERST GEMESSEN, WAS NICHT DAS PROBLEM IST. Am echten Bestand
nachgesehen: Diene HAT ein angemeldetes Geraet (Android, Chrome, seit
dem 29.09.), und alle zehn Geraete im Haus melden `fehler = 0`. An
der Zustellung liegt es nicht.

DANN NACHGESTELLT (pruef-abzeichen, Abschnitt 8):

    Verbindung offen  ->  KEINE Benachrichtigung
    Verbindung zu     ->  sie kommt

Genau sein Befund.

DER GEDANKE WAR RICHTIG, DIE FRAGE FALSCH. Im Quelltext stand:

    if ((zuschauer.get(personId) || new Set()).size) continue;

und daneben die Begruendung -- „wer die Seite offen hat, sieht die
Nachricht ohnehin; ihm auch noch eine Meldung aufs Handy zu schicken
ist der schnellste Weg, dass er Benachrichtigungen abschaltet." Das
stimmt. Nur beantwortet `zuschauer` eine ANDERE Frage: ob eine
VERBINDUNG offen ist. Ein Handy mit der App im Hintergrund haelt sie
weiter -- und der Server hielt Diene fuer anwesend, waehrend sein
Bildschirm schwarz war.

DIE SEITE WEISS ES, DER SERVER NICHT. `document.visibilityState` ist
die einzige Stelle, die den Unterschied kennt. Also sagt sie es --
ueber einen winzigen Weg (`/api/chat/sicht`), beim Aufbau, bei jedem
Wechsel und mit `keepalive` beim Weggehen.

MIT VERFALL, und das ist der wichtige Teil: Ein Geraet, das
abstuerzt, im Funkloch steht oder eingefroren wird, sagt gar nichts
mehr. Ohne Verfall bliebe es fuer immer „sichtbar" und fuer immer
still. Wer nicht widerspricht, gilt nach zweieinhalb Minuten als weg
-- eine Meldung zu viel ist laestig, eine zu wenig ist genau der
Fehler, den Diene gemeldet hat. Dazu alle Minute ein Lebenszeichen,
solange die App vorn liegt.

EINE STELLE FUER DIE FRAGE. Sie wurde an zwei Orten gestellt:
`siehtZu()` und eine Abschrift mitten in `chatEreignis`. Die
Abschrift war die kaputte. Jetzt fragen beide dieselbe Funktion.

GEPRUEFT -- vier Lagen, und die zweite ist die wichtigere
Gegenprobe:

  App liegt hinten        -> Meldung kommt      (war: nichts)
  sieht wirklich hin      -> KEINE Meldung      (Absicht bleibt)
  App weggelegt           -> Meldung kommt wieder
  gar keine Verbindung    -> Meldung kommt

Ohne die zweite Zeile hiesse die Reparatur nur „jetzt kommt immer
eine", und das waere der schnellste Weg, dass jemand
Benachrichtigungen abschaltet.

UND EINE PRUEFUNG HAT DEN FEHLER MITGETRAGEN. pruef-anruf-klingelt
hielt den WORTLAUT der kaputten Zeile fest -- genau das, wovor ihr
eigener Kommentar drei Zeilen darueber warnt („Die Pruefung hat den
alten Wortlaut bestaetigt statt sein Verhalten"). Sie prueft jetzt
beides: dass gefragt wird, und dass die Frage die richtige ist.

pruef-abzeichen 26/0, pruef-chat, pruef-anruf 132/0,
pruef-chat-kanaele 81/0, pruef-anruf-klingelt 25/0, pruef-push-ziel
38/0, pruef-arten 28/0, pruef-reaktion 421/0, pruef-struktur,
pruef-zwischenspeicher 34/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 23:48:49 +02:00
DogFatherGitandClaude Opus 5 d4a3e54a72 Aufgaben: dauerhafte Aufgaben, die nicht abgehakt werden
VanVan im Support: „Man kann bei den Aufgaben, wenn man sie verteilt,
ob selbst erstellt oder über die Vorlage noch nicht festlegen, dass
die Aufgabe dauerhaft sein soll und somit nicht vom Modi in den Status
erledigt gesetzt werden kann."

Nachgesehen: Das Wort kam im Aufgabenmodul kein einziges Mal vor. Es
war keine vergessene Zeile, es fehlte ganz.

WAS EINE DAUERHAFTE AUFGABE IST: keine, die man abarbeitet, sondern
eine, die man TUT. „Neue begruessen" ist nicht fertig, wenn man es
einmal gemacht hat.

ZWEI FOLGEN, und die zweite faellt leicht durchs Raster

1. Der Zugeteilte kann sie nicht auf „erledigt" setzen. Die Sperre
   steht im SERVER -- ein fehlender Knopf ist eine Bitte, abgelehnt
   wird an der Route. „Ich fange an" bleibt erlaubt: Auch eine
   stehende Aufgabe hat einen Anfang.

2. SIE HAT KEINE FRIST. Eine dauerhafte Aufgabe mit Frist waere ab
   dem naechsten Tag fuer immer ueberfaellig -- und eine Warnung, die
   immer kommt, ist keine mehr. Die Frist wird GELOESCHT, nicht
   ignoriert: Ein Datum, das dasteht und nicht gilt, ist schlimmer
   als keins.

WER DARF DAS SETZEN: nur, wer verteilt. Koennte der Zugeteilte seine
eigene Aufgabe dauerhaft machen, waere das eine Ausrede; koennte er
es zuruecknehmen, waere die Sperre ein Knopf weiter offen. Beides
nachgemessen.

UND SIE LAESST SICH BEENDEN. Eine Pflicht, die niemand mehr beenden
kann, waere eine Falle statt einer Regel.

DREI STELLEN, KEINE VIERTE: das Anlegeformular auf „Aufgaben", das
auf „Eure Aufgaben" (dort wird verteilt) und das Bearbeiten-Feld.
Ueber das letzte laeuft VanVans „oder ueber die Vorlage" -- eine
Vorlagen-Aufgabe entsteht ohne Formular, ein Schalter im
Vorlagenbrett waere eine vierte Stelle fuer dieselbe Frage.

An der Karte steht die Marke fuer ALLE, nicht nur fuer den
Zugeteilten: Wer sie ansieht, soll wissen, warum dort kein „Fertig"
steht. Ein fehlender Knopf ohne Erklaerung liest sich wie ein Fehler.

GEPRUEFT
pruef-bewerbung-aufgaben 154/0 (10 neue) mit vier Gegenproben: eine
GEWOEHNLICHE Aufgabe laesst sich sehr wohl abhaken (sonst hiesse 409
nur, dass niemand je etwas abhaken kann), „Ich fange an" geht
weiterhin, der Zugeteilte setzt und nimmt „dauerhaft" nicht, und nach
dem Beenden durch die Leitung geht das Abhaken wieder.

ZWEI EIGENE FEHLER, beide von Pruefungen gefunden

* Ein BACKTICK in einem Kommentar -- mitten in einem Template-String
  (`SPALTEN`). Er hat ihn beendet, die Datei war syntaktisch kaputt.
  Dieselbe Familie wie die deutsche Anfuehrung in einem
  Anfuehrungsstring: ein Zeichen, das in der Umgebung etwas bedeutet.
* `toISOString().slice(0,10)` fuer „morgen" -- pruef-struktur hat es
  noch am selben Abend gefunden. Zwischen 00:00 und 02:00 liegt der
  UTC-Tag noch auf gestern; die Pruefung haette nachts falsch
  angeschlagen. Jetzt ueber `tagLokal()`.

Und einer, den nur die Messung zeigen konnte: `holen()` in
workspace-zuteilung liest die Aufgabe mit einer eigenen, kurzen
Spaltenliste. Ohne `dauerhaft` darin fragte die Sperre `a.dauerhaft`
und bekam `undefined` -- sie war still wirkungslos, und im Quelltext
daneben sah alles richtig aus.

pruef-aufgabenbrett, pruef-zuteilung, pruef-aufgaben-vorlagen,
pruef-entwicklung 79/0, pruef-css-klassen, pruef-deutsche-texte,
pruef-struktur, pruef-zwischenspeicher 34/0.

Schemaaenderung: ADD COLUMN dauerhaft. Datenbank vorher gesichert und
geprueft (integrity_check ok, 12 Aufgaben).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 18:52:37 +02:00
DogFatherGitandClaude Opus 5 5e26df788b Bewerbungen: die Absage bleibt lesbar, und ihr seht, was ihr absagt
VanVan im Support: „Wenn sich ein Modi auf eine Aufgabe bewirbt und
man diese ablehnt, dann bekommt der Modi keine Benachrichtigung
darüber, dass die Aufgabe abgelehnt wurde und sieht somit auch eine
eventuelle Begründung nicht. Außerdem haben auch wir nirgendwo eine
Übersicht, bei wem wir welche Aufgaben schon abgelehnt haben."

GEMESSEN, BEVOR GEBAUT WURDE -- die Pruefungen standen zuerst da und
waren rot:

    Frida sieht ihre beantwortete Bewerbung     0
    Die Leitung sieht die Absagen               0

DIE URSACHE. `vorlagenBewerbungenFuer` fragt `WHERE zustand =
'beworben'`. Sobald jemand antwortet, faellt die Zeile aus JEDER
Ansicht heraus -- mitsamt der Begruendung, die Filipe am 23.09.
ausdruecklich verlangt hat („mit einem text als notiz"). Der Satz
wird also verlangt, geschrieben und weggesperrt.

Bei einer ZUSAGE fiel das nicht auf: Dort entsteht eine Aufgabe, und
an ihrer Karte steht die Antwort. Bei einer ABSAGE entsteht nichts.

Die Benachrichtigung selbst gab es (`bewerbung_antwort`, vorgabe an,
fuer ja und nein). Sie war nur das EINZIGE -- wer sie wegwischt oder
kein Geraet angemeldet hat, erfuhr nie, warum.

WAS JETZT DASTEHT

* BEIM BEWERBER: „Antwort auf deine Bewerbung" mit dem Ergebnis, dem
  Satz und dem Namen dessen, der geantwortet hat. Beide Ausgaenge --
  eine Liste, die nur Absagen sammelt, waere eine andere Sache. Nach
  14 Tagen verschwindet sie von selbst.

  SIE STEHT VOR DEM ZUKLAPPEN. Beim ersten Anlauf lag sie im Koerper
  des Vorlagenbretts, und der wird nur gebaut, wenn das Brett
  aufgeklappt ist -- zugeklappt ist die Vorgabe. Eine Antwort, die
  man erst aufklappen muss, ist wieder keine.

* BEI DER LEITUNG: „Schon abgesagt", 90 Tage, mit der Zahl JE MENSCH
  vorn. Das ist VanVans eigentliche Frage („falls sich jemand immer
  wieder bewirbt und immer wieder abgelehnt wird"), und die
  beantwortet eine Liste von zwanzig Zeilen nicht.

  AUS BEIDEN WEGEN -- Vorlage und Aufgabe. Eine Uebersicht, die nur
  die Haelfte zeigt, ist schlimmer als keine: „Frida wurde nie
  abgelehnt" waere dann eine Auskunft, die stimmt und taeuscht.

  ZUGEKLAPPT. Eine Liste von Absagen, die immer offen steht, ist eine
  Sammlung von Nein-Sagen ueber Menschen, mit denen man morgen wieder
  arbeitet.

  KEIN ROT. Eine Absage ist kein Fehler; „diesmal nicht" ist keine
  Aussage ueber den Menschen. Gedeckter Bernstein, und ab zwei Malen
  faellt die ZAHL auf -- nicht nur die Farbe.

ZWEI EIGENE FELDER UND NICHT `bewerbungen` ERWEITERT. Dort heisst
eine Zeile im Browser „wartet auf Antwort", samt Zurueckziehen-Knopf.
Beantwortete Zeilen hineinzumischen haette bei einer Absage genau das
gezeigt. Ein Feld, dessen Bedeutung sich aendert, bricht seine Leser
lautlos.

`entschieden_von IS NOT NULL` TRENNT DREI DINGE, die alle `abgelehnt`
heissen: die Leitung hat eine Bewerbung abgelehnt (das hier), die
Person hat eine Zuteilung abgelehnt (ihre Entscheidung), und „von
jemand anderem uebernommen" (gar keine Absage).

Haustrennung gilt: `darfSchreibenMit` je Zeile.

GEPRUEFT
pruef-bewerbung-aufgaben 144/0 (weitere 10 Pruefungen plus zwei
Bilder). Die Gegenprobe steht in der Vorgeschichte: Dieselben
Pruefungen waren vor dem Bau rot.

Zwei eigene Messfehler, beide im Text festgehalten: Ich habe zuerst
auf dem AUFGABENbrett gemessen -- der Vorlagenkatalog steht aber auf
„Eure Aufgaben" (`zweig: 'team'`). Und `innerText` liefert den Text
so, wie er DASTEHT: Die Zeile suchte „Diesmal nicht" und fand
„DIESMAL NICHT", weil das Schild `text-transform: uppercase` traegt.

pruef-vorlagen 24/0, pruef-aufgaben-vorlagen, pruef-zuteilung,
pruef-aufgabenbrett, pruef-entwicklung 79/0, pruef-css-klassen,
pruef-zwischenspeicher 34/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 18:34:24 +02:00
DogFatherGitandClaude Opus 5 c933bcd2e0 Aufgaben: wer verantwortlich ist, hat auch eine Zuteilung
VanVan im Support: „Wenn ein Modi sich auf eine Aufgabe beworben hat
und die von uns angenommen wurde, dann steht beim Modi unter der
Aufgabe immer noch ich bewerbe mich."

GEMESSEN AN DEN ECHTEN DATEN (lesend, auf einer Kopie):

    Aufgaben mit Verantwortlichem:     11
    davon OHNE Zuteilungszeile:         8

Darunter Marinas zwei offene Vorlagen-Aufgaben -- genau die zwei
Karten aus ihrem Bildschirmfoto.

DIE URSACHE. `katalogAufgabeAnlegen()` schrieb eine Zeile in
`aufgaben` mit `verantwortlich_id` und KEINE in
`aufgaben_zuteilung`. Das Brett liest aber die Zuteilung, nicht den
Verantwortlichen: Es fand nichts, lieferte `meine_zuteilung: null`,
und die Bedingung im Browser beginnt mit `!mein` -- also bot sie an,
sich auf die eigene Aufgabe zu bewerben.

ES WAR NICHT NUR EIN FALSCHER KNOPF. „Ich fange an" und „Fertig"
haengen an derselben Zeile. Der Mensch bekam eine Karte, auf der er
das Falsche tun konnte und das Richtige nicht.

WARUM DIE VORHANDENE PRUEFUNG ES NICHT FAND: Sie geht den Weg ueber
das AUFGABENbrett -- dort war alles in Ordnung, nachgemessen steht
nach dem Annehmen richtig „Ich fange an | Fertig". VanVans Weg ist
der ueber das VORLAGENbrett, und der endet in einer neu angelegten
Aufgabe. Dieser Weg war nie geprueft.

DREI TEILE

1. `katalogAufgabeAnlegen` legt die Zuteilungszeile mit an. Mit
   Zustand: `angenommen`, wenn die Person darum gebeten hat und die
   Bitte angenommen wurde; `offen`, wenn die Leitung zutraegt -- dann
   steht bei ihr Annehmen/Ablehnen, und das ist richtig, sie hat noch
   nicht ja gesagt.

2. Eine Umstellung traegt nach, was schon dasteht. Wiederholbar
   (`NOT EXISTS` + `INSERT OR IGNORE`), deshalb bei den Umstellungen
   und nicht in einem Skript, das jemand vergisst. Auf einer KOPIE
   der echten Datenbank durchgespielt: 8 Zeilen angelegt, danach 0
   ohne Zuteilung, `integrity_check ok`. Marinas Karten stehen
   danach auf `angenommen`.

3. Ein Riegel im Browser: Auf eine Aufgabe, die mir schon gehoert,
   bewirbt man sich nicht. Er faengt jeden weiteren Weg ab, der eine
   Aufgabe ohne Zuteilungszeile anlegt -- nicht alle acht kamen aus
   der Vorlage.

GEPRUEFT
pruef-bewerbung-aufgaben 126/0 (15 neue: der ganze Vorlagenweg von
der Bewerbung bis zum Knopf auf ihrem Brett). NACHGESTELLT: Ohne die
Zuteilungszeile wird sie rot („und sie hat eine Zuteilungszeile
(undefined)"). pruef-zuteilung, pruef-aufgabenbrett, pruef-vorlagen
24/0, pruef-aufgaben-vorlagen, pruef-struktur, pruef-zwischenspeicher
34/0.

Ein Messfehler unterwegs, im Text festgehalten: Mein neuer Block
bewarb sich auf dieselbe Vorlage wie ein spaeterer Abschnitt und
nahm ihm damit seine -- zehn Pruefungen wurden rot, ohne dass am
Programm etwas falsch war.

Datenbank vor der Umstellung gesichert und geprueft
(integrity_check ok, 12 Aufgaben, 3 Zuteilungen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 18:08:36 +02:00
DogFatherGitandClaude Opus 5 721ad262df Entwicklung: „Deine Karte" laesst sich einklappen
VanVan im Support: „Deine Karte im Bereich eure Aufgaben kann man
noch nicht einklappen, was die Seite unnötig lang zieht und
unübersichtlich macht."

GEMESSEN (mess-vanvan-karte, Abschnitt 5). Es ist IHRE eigene Karte,
nicht die eines Modi -- im Bildschirmfoto steht an jedem Punkt „1 ×
Läuft", also eine einzige Antwort. Ueber die rechte Hand urteilt nur
DogFather; bei ihr ist deshalb alles durch und die Karte entsprechend
lang, waehrend ein Modi zwei Stimmen braucht.

                       vorher     nachher
  Seite gesamt         7245 px    2945 px
  davon „Deine Karte"  6186 px    1886 px   (zugeklappt 636 px)
  Schalter                   0    6 + „Alle"-Knopf

6186 von 7245 px waren eine einzige Karte -- 85 Prozent der Seite,
68 Zeilen am Stueck, kein einziger Schalter.

DERSELBE MECHANISMUS WIE NEBENAN, NICHT EIN ZWEITER. Die Karte der
Leitung klappt seit Langem auf und zu. Die Klassen, der Pfeil, die
Zahl im Kopf und der Knopf „Alle auf-/zuklappen" sind dieselben --
ein zweiter Mechanismus daneben waere der, der beim naechsten Umbau
vergessen wird, und er saehe anders aus, obwohl er dasselbe tut.
Herausgeloest als `klappAbschnitt()`.

WELCHER STEHT OFFEN: Was ich TUN soll („Deine Aufgaben"), und von den
Beobachtungen die erste Kategorie. Alle zu hiesse „jedes Mal erst
suchen", alle auf waere der Zustand von vorher.

DIE ZAHL STEHT IM KOPF (14, 12, 12, 11, 10, 9). Eine zugeklappte
Kategorie, die nicht sagt, wie viel in ihr steckt, klappt man einmal
auf und danach nie wieder zu.

GEPRUEFT
Die Messung ist jetzt selbst die Wache: Sie schlaegt an, wenn es
keine Schalter gibt (so ist der Befund entstanden), wenn Zuklappen
weniger als die Haelfte spart, und wenn es Schalter ohne
„Alle"-Knopf gibt. Alle drei nachgestellt. Ein ANTEIL und keine feste
Pixelzahl -- 68 Punkte heute, vielleicht 90 naechstes Jahr.

pruef-entwicklung 79/0, pruef-werdegang 103/0,
pruef-entwicklung-kacheln 34/0, pruef-css-klassen,
pruef-zwischenspeicher 34/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 17:33:37 +02:00
DogFatherGitandClaude Opus 5 51c47e1c07 Entwicklung: der Mensch sieht, was seine Aufgabe ist
VanVan im Support: „wenn ich … Aufgaben an einen Modi zutrage und
auch bewerte, dann sieht der Modi zwar die Auswertung im Bereich
Entwicklung, aber bei ihm taucht nichts im Bereich eure Aufgaben
unten in der Karte auf."

IHR FALL NACHGESTELLT (server/mess-vanvan-karte.mjs): VanVan traegt
einem Modi zwei von 68 Punkten zu und bewertet sie, Filipe bewertet
nichts -- genau wie bei ihr.

  vorher   seine Karte: fertig=0 von 68, alles „offen",
           Punktzeilen sichtbar: 0
           Kennt sie das Wort „zugetragen"?  NEIN
  nachher  Abschnitt „Deine Aufgaben (2)" mit beiden Titeln

ZWEI DINGE WAREN EINS, DIE GETRENNT GEHOEREN

  Was er TUN soll   die Zuteilung. Die gibt es, bevor jemand etwas
                    bewertet, und sie gehoert ihm.
  Was man SIEHT     die Bewertung. Die erscheint erst, wenn alle
                    hingesehen haben.

`meine-karte` kannte nur das Zweite. War die Bewertung noch nicht
vollstaendig, stieg die Anzeige mit `return` aus -- und damit sah er
gar nichts, obwohl ihm zwei Aufgaben zugetragen waren. Das ist die
falsche Reihenfolge: Wer seine Aufgabe erst sieht, wenn sich zwei
Leute ueber ihre Ausfuehrung einig sind, kann sie nicht angehen.

Die Regel fuer die Bewertung bleibt unveraendert. Eine einzelne
Meinung soll bei einem Menschen nicht als Urteil des Teams ankommen.

UND DIE ANDERE HAELFTE: NIEMAND SAGTE ES IHR

VanVan hatte gesetzt, es kam nicht an, und nichts auf ihrem
Bildschirm erklaerte das. Ein Mensch, der das zweimal erlebt, hoert
auf zu setzen. An einem Punkt, den sie bewertet hat, steht jetzt
leise: „Er sieht das noch nicht -- es fehlt noch eine Einschaetzung."
Ohne Namen: Wer fehlt, waere eine Aufforderung, jemanden
anzutreiben.

IHRE ZWEITE BEOBACHTUNG, EBENFALLS GEMESSEN

„bei jedem Punkt läuft obwohl auch wenn die Aufgaben darüber gar
nicht zugetragen wurde." Stimmt: Die vier Bewertungsknoepfe („✓
Läuft ↗ Wächst ! Da hakt es – Kann ich nicht sagen") stehen an allen
68 Punkten, auch an den nicht zugetragenen. Beim Durchscrollen liest
man deshalb ueberall „Läuft".

DIE 68 BLEIBEN. Filipe am 25.09.2026 ausdruecklich: „dogfather und
die rechte hand sollen immer noch die 68 sachen sehen wie vorher …
unsere sicht soll sich nicht aendern." Also kein Ausblenden und
keine neue Vorgabe, sondern ein Knopf mehr in der Leiste, die es
schon gibt: „Zugetragen · 2". „Alle" bleibt, was beim Aufmachen
gilt. Gemessen grenzt er auf 2 Punkte ein, Kopf „2 / 2".

NEBENBEI ZUSAMMENGEFUEHRT
* `beurteilerZahl()` an einer Stelle -- beide Enden stellen dieselbe
  Frage, zwei Abschriften saegten irgendwann Verschiedenes ueber
  denselben Punkt.
* `antwortReihe()` und `punkteGefiltert()` ebenso.
* Die Abfrage stand zuerst je Punkt in der Schleife: 68
  Datenbankfragen fuer eine Zahl, die sich nicht aendert.

GEPRUEFT
pruef-entwicklung 79/0 (9 neue, mit Gegenproben in beide Richtungen:
ein nicht zugetragener Punkt traegt die Marke nicht, und sobald der
zweite Beurteiler setzt, geht es durch). mess-vanvan-karte ohne
ACHTUNG. pruef-werdegang 103/0, pruef-entwicklung-kacheln 34/0,
pruef-deutsche-texte, pruef-css-klassen, pruef-zwischenspeicher 34/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 16:48:24 +02:00
DogFatherGitandClaude Opus 5 a3ec558127 Reaction: der Gleichlauf rechnet ohne Uhrenvergleich
Filipe: „die videos muessen perfekt laufen wenn ich die reaktions
mache."

GEMESSEN, NICHT VERMUTET. mess-reaktion hat einen neuen Abschnitt:
Er liest den Spielstand am ECHTEN <video>-Element in beiden Browsern,
rechnet beide auf denselben Augenblick um und sagt, wie weit Host und
Zuschauerin auseinanderliegen. Die vorhandene Pruefung fragte nur, ob
Start und Stopp ANKOMMEN -- zwei Videos koennen beide laufen und
trotzdem zwanzig Sekunden auseinander sein.

                        vorher      nachher
  Im Lauf                0,12 s     -0,04 s
  Wer dazukommt          6,91 s      0,26 s
  Uhr des Geraets 30 s vor  -29,97 s      0,26 s

DER SCHLIMMSTE FUND: DIE UHR DES TELEFONS

Der Zuschauer rechnete `Date.now() - stand.gesendet`. `gesendet` kam
vom SERVER, `Date.now()` vom Geraet -- zwei Uhren, die nie jemand
verglichen hat. Wessen Telefon dreissig Sekunden vorgeht, schaute
29,97 s weiter als alle anderen. Kein langsames Netz, kein schwaches
Handy. Oertlich faellt das nie auf: Auf einem Rechner sind beide
Uhren dieselbe.

Jetzt geht ein ALTER hinaus statt einer Uhrzeit -- die Differenz
zweier SERVERzeiten. Der Empfaenger braucht dafuer gar keine Uhr,
nur eine Stoppuhr (`performance.now()`), und die haelt Zeitumstellung
und Aufwachen aus dem Ruhezustand aus.

WEITER

* WER DAZUKOMMT, STEIGT RICHTIG EIN. Der gespeicherte Stand war so
  alt wie der letzte Takt des Hosts; neue Spalte `sekunde_am` sagt,
  wann er galt.
* DAS TEMPO GEHT IN DIE HOCHRECHNUNG EIN. Bei 2x laeuft die Videouhr
  doppelt so schnell -- das fehlte ganz.
* JEDER RECHNET ALLE ZWEI SEKUNDEN SELBST NACH statt nur auf Zuruf.
  Wer stockte, hing bis zu fuenf Sekunden hinterher.
* DER VORLAUF NACH EINEM SPRUNG WIRD GEREGELT, nicht geschaetzt --
  gemessen wird der Rest, nicht die Ladezeit (siehe unten).
* PUFFERN IST AUCH IN DER TRANSPORTLEISTE KEINE PAUSE. Der
  Start-Stopp-Knopf rief beim Puffern `playVideo()` -- wer Pause
  drueckte, bekam „weiter". Lampe und Knopfbild flackerten bei jedem
  Stocken. Die Lektion vom 29.09. war nur an einer Stelle eingeloest.
* DAS TEMPO MELDET UEBER `hostMelden()` statt ein zweites Mal von
  Hand -- es hielt Puffern fuer Stillstand und hielt damit beim
  Umschalten alle an.
* EIN VIDEO-RUNDRUF STATT DREI ABSCHRIFTEN. Beim Einbau hatte ich
  zuerst nur eine nachgezogen; das Tauschen der beiden Videos haette
  still die alte Rechnung weiterverschickt.

DREI EIGENE FEHLER UNTERWEGS, alle im Text festgehalten

1. ZWEI FUNKTIONEN HIESSEN `springen`. Meine „spring AUF die Stelle"
   wurde von der vorhandenen „spring UM so viele Sekunden"
   ueberschrieben -- lautlos, rueckwirkend fuer die ganze Datei. Ein
   Zuschauer bei Sekunde 100, dem „geh auf 101" gesagt wird, waere
   bei 201 gelandet. DREI BROWSERLAEUFE HABEN ES NICHT GEFUNDEN:
   oertlich blieb der Abstand unter der Sprungschwelle, die Zeile
   lief kein einziges Mal. Gefunden hat es erst eine Frage an die
   ganze Datei -- die steht jetzt als Pruefung drin und wurde
   nachgestellt (rot).
2. DER VORLAUF LERNTE NUR NACH OBEN. Gemessen wurde die Ladezeit
   nach einem Sprung; ein Sprung in geladenes Material dauert aber
   gar nicht, meldet nichts und lehrt nichts. Ergebnis: -0,95 s
   stabil. Jetzt wird das ERGEBNIS geregelt statt der Ursache.
3. DER AUSREISSER VON 39,84 s WAR MEINE EIGENE MESSUNG -- der Block
   davor schickt eine erfundene Position. Jetzt wird abgeklungen und
   in Messreihenfolge ausgegeben.

GEPRUEFT
pruef-reaktion 421/0 (14 neue, darunter der Riegel gegen die
Rueckkehr der Uhrenrechnung und die Wache gegen doppelte
Funktionsnamen -- beide nachgestellt), mess-reaktion ohne ein
einziges ACHTUNG, pruef-buehne 38/0, pruef-struktur, pruef-
zwischenspeicher 34/0.

Schemaaenderung: ADD COLUMN sekunde_am. Datenbank vorher gesichert
und geprueft (integrity_check ok, 20 Personen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 15:45:48 +02:00
DogFatherGitandClaude Opus 5 d5c84c7608 Abzeichen am App-Symbol - und die Zahl gehoert zu einem Haus
Die kleine Zahl auf dem Symbol des Startbildschirms. Sie fehlte ganz;
setAppBadge kam im Haus kein einziges Mal vor.

ZWEI ENTSCHEIDUNGEN

Sie zaehlt ungelesene Nachrichten und nichts sonst. Ein Abzeichen
muss weggehen koennen: Nachrichten verschwinden, sobald man sie
liest; eine ueberfaellige Aufgabe verschwindet nicht dadurch, dass
man die App oeffnet. Eine Zahl, die dauerhaft dasteht, ist nach drei
Tagen kein Hinweis mehr, sondern ein Fleck.

Und sie hat EINE Quelle. Im Browser haengt sie an chatZahlZeigen() -
der einen Stelle, an der die Zahl ohnehin gesetzt wird (beim Laden,
aus dem Ereignisstrom, beim Lesen). Fuer die geschlossene App - wo
das Abzeichen ueberhaupt erst etwas wert ist - reist dieselbe Zahl in
der Benachrichtigung mit. Der Service Worker setzt sie nur, wenn eine
dabei ist: Eine Aufgabenerinnerung mit "0" haette dem Chat sein
Abzeichen weggenommen.

DER FUND NEBENBEI

Beim Herausloesen der Abfrage fiel auf, dass sie nie nach dem Haus
gefragt hat - die Raumliste zwanzig Zeilen darueber tut es laengst.
Gemessen: Eine Managerin schreibt DogFather an der Agenturwand an,
sein Zaehler auf crew. springt von 0 auf 1. Seit dem 24.09. soll das
nicht mehr sein. Aufgefallen ist es erst jetzt, weil dieselbe Zahl ab
heute auf dem Startbildschirm steht - und eine Zahl, die etwas
Falsches zeigt, ist schlimmer als keine.

Behoben ueber hausWo(); die Meldung nimmt das Haus des Raums, aus dem
sie stammt.

GEPRUEFT

server/pruef-abzeichen.mjs, 19 Messungen am echten Weg: ein
nachgebauter Browser macht die Benachrichtigung mit seinem privaten
Schluessel auf und liest die Zahl heraus. Mit Gegenproben - ohne Zahl
kommt keine mit, NaN rutscht nicht durch, eine echte Sieben schon.
Und Abschnitt 7 wird rot, sobald man die Hausregel wieder herausnimmt
(nachgestellt).

Zwei eigene Messfehler unterwegs, beide im Text festgehalten: eine
Suche, die im Kommentar landete statt im Code (jetzt ueber
jsOhneKommentar), und Aufrufe ohne Host-Feld - ueber 127.0.0.1 gibt
es kein Haus, die Pruefung mass also eine Regel an einer Verbindung,
die sie gar nicht kennt.

helfer-push-aufmachen.mjs: das Entschluesseln stand als lokale
Funktion in pruef-push-weg; zwei Abschriften waeren die, die
auseinanderlaufen.

Nachbarlaeufe gruen: push, push-ziel, push-weg (17 unveraendert),
arten, portnummern, struktur, chat, chat-kanaele, chatkachel, anruf,
haus-trennung, zwischenspeicher.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 13:39:55 +02:00
DogFatherGitandClaude Opus 5 2c12b8706e Highlights des Teams sind sofort zu sehen -- ohne zweiten Klick
Filipe, 30.09.2026: „wenn wir bei highlights videos rein setzen will
ich nicht mehr dass wir sie freigeben muessen, sobald die reingesetzt
wurden sollen die sofort zu sehen sein."

=====================================================================
WAS ICH NICHT GETAN HABE, UND WARUM NICHT
=====================================================================
Die naheliegende Loesung waere gewesen, `highlight` aus
`TREFF_FREIGABE_BRETTER` zu streichen. Das waere falsch: Auf diesem
Brett laedt auch die COMMUNITY hoch -- Clips, Bilder, Fanart. Im
Quelltext steht woertlich daneben:

    „Zwei Schloesser, weil hier fremde Inhalte hochgeladen werden --
     Urheberrecht und Anstand sind nichts, was man nachtraeglich
     klaert."

Filipe meint nicht das. Er meint: „wenn WIR videos rein setzen".

=====================================================================
DIE UNTERSCHEIDUNG STAND SCHON IM HAUS -- nur nicht im Code
=====================================================================
Derselbe Quelltext sagt ueber die zwei Freigabe-Bretter
Verschiedenes:

    ansteht    -> der SCHALTER „Im Treff zeigen". Das Team entscheidet
                  JE TERMIN, ob die Community ihn sieht.
    highlight  -> der Urheberrechts- und Anstandsfilter.

Ein Filter fragt „hat das jemand angesehen?". Wenn der, der ihn
bedienen darf, den Eintrag SELBST anlegt, ist die Antwort ja. Genau
diese Begruendung steht seit dem Uebernehmen aus dem Katalog im
Haus: „Eine zweite daneben waere keine Sicherheit, sondern ein
Klick."

Ein Schalter dagegen ist eine Entscheidung je Fall. Termine bleiben
deshalb unberuehrt -- sonst stuende jeder interne Termin sofort im
Treff, und danach hat niemand gefragt.

Neu: `FREIGABE_IST_FILTER` und `sofortFreigeben()` in
workspace-treff.js. DIE BEDINGUNG FRAGT DIE ROLLE, NICHT DEN WEG --
waere der Weg gefragt, waere aus dem Filter ein Loch geworden, sobald
jemand einen zweiten Weg baut. Ein Community-Mitglied ab „Stamm"
darf weiterhin einstellen; sein Eintrag wartet auf das Team.

Gerufen an ZWEI Stellen: beim Videoweg und beim Anlegen von Hand.
Beide hatten es bisher nicht.

=====================================================================
DIE VORHANDENE FREIGABEPRUEFUNG BEWEIST DAS NICHT
=====================================================================
Sie blieb nach der Aenderung gruen -- und das zu Recht: Sie legt ihre
Eintraege unmittelbar in der Datenbank an und prueft damit den
Mechanismus, nicht den Weg. Haette ich mich darauf verlassen, waere
eine Aenderung ausgeliefert worden, fuer die keine Zeile spricht.

pruef-treff (+5): DogFather legt ueber den echten Weg an -> die
Community sieht es SOFORT. Ein TERMIN bleibt verborgen. Die Regel
gibt fuer eine Rolle von aussen NICHT frei und fuer Termine
ueberhaupt nicht.

pruef-video (+3): Der Videoweg hat seinen eigenen Aufruf -- genau
dort wird einer vergessen. Geprueft wird die Freigabezeile selbst,
samt Gegenprobe „freigegeben ist nur, was auch angelegt wurde".

Meinen Abschnitt hatte ich erst HINTER das Abschalten des
nachgebauten TikTok-Dienstes gehaengt -- der Kopf der Datei warnt
woertlich davor („das Abschalten steht ganz hinten"). Gelesen habe
ich ihn, als es rot wurde.

UND `pruef-struktur` HAT MEINE EIGENE NEUE ZEILE GEFANGEN: Sie bildete
das Datum aus UTC statt Ortszeit -- zwischen Mitternacht und zwei Uhr
waere es der falsche Tag gewesen. Behoben mit `tagLokal()`, Minuten
nach dem Schreiben.

Gemessen: pruef-treff 85/0 (war 80), pruef-video 74/0 (war 71),
pruef-highlights 31/0, pruef-bereiche-lesend 37/0,
pruef-treff-werkzeuge 73/0, pruef-alle-sehen-es 43/0,
pruef-community-sicht 10/0, pruef-wege-nach-draussen 67/0,
pruef-struktur 44/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 12:55:12 +02:00
DogFatherGitandClaude Opus 5 f53791cefd Dritte Schicht: auch die Webdesign-Seiten trugen Stempel vom August
Nach den 35 oeffentlichen Seiten und den zwei Zahlen des Service
Workers lag dieselbe Faeulnis noch eine Ebene tiefer:

    webdesign/*.html   49x ?v=20260823wd20   (23. August)
                        1x ?v=20260825wd51   (25. August)

Zwei VERSCHIEDENE Stempel in 13 Seiten, und beide aus dem August. Sie
verweisen auf dieselben Dateien wie die Startseite -- darunter
`main.css` --, und der Server schickt dazu ein Jahr `immutable`. Wer
den Bereich seit August besucht hatte, hatte sie eingefroren, ganz
unabhaengig vom Service Worker.

Dritte Schicht desselben Fehlers an einem Vormittag. Alle drei hatten
dieselbe Ursache: eine Zahl, die ein Mensch pflegen sollte.

Der Stempler nimmt die 13 Seiten jetzt mit -- 554 Verweise in 48
Seiten, EIN Stempel. `workspace/` bleibt ausgenommen: Dort arbeitet
`workspace-stempel.mjs`, und zwei Werkzeuge auf demselben Ordner
waeren zwei Antworten auf dieselbe Frage.

Und die Wache liest sie mit. Haette sie nur die Wurzel gelesen, waere
sie gruen gewesen und haette die Haelfte geprueft -- genau die Sorte
gruener Haken, die nichts bedeutet.

Viermal heute ist mir beim Schreiben ein Backslash durch die Shell
verlorengegangen (`\1` wurde zum Steuerzeichen, `\\` zu nichts).
Die Hausnotiz sagt das seit Langem; ich habe es viermal trotzdem
gemacht. Ab jetzt: alles mit Backslash geht durch das Werkzeug, nicht
durch die Befehlszeile.

Gemessen: pruef-zwischenspeicher 34/0, pruef-bewegung 9/0,
pruef-css-klassen 37/0, pruef-struktur 44/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 12:14:23 +02:00
DogFatherGitandClaude Opus 5 12fa0e45ba Der Webdesign-Bereich lieferte seit dem 27.08. ein veraltetes main.css aus
Der Stempel-Fund von eben hatte eine Fortsetzung: DEPLOY.md verlangte
seit dem 26.08. „ZWEI Zahlen hochzaehlen", mit Begruendung und
Messwerten daneben.

    webdesign/sw.js       const CACHE_NAME = "dogfather-webdesign-v64"
    assets/js/wd-core.js  .register("/webdesign/sw.js?v=64", …)

Gemessen am 30.09.2026 standen beide seit dem 27.08. auf v64 --
waehrend SIEBEN Commits die Dateien geaendert hatten, die der Service
Worker vorhaelt. Er haelt sechs vor, und `/assets/css/main.css` ist
eine davon.

Wer den Webdesign-Bereich einmal geoeffnet hatte, bekam sie seither
aus seinem Zwischenspeicher. Auch die Behebung von heute Vormittag
waere dort nicht angekommen.

EIN KOMMENTAR, DER VOR EINEM FEHLER WARNT, VERHINDERT IHN NICHT. Die
Anleitung war richtig, ausfuehrlich und begruendet. Getan hat es
trotzdem niemand -- fuenf Wochen lang. Das ist dieselbe Lehre wie am
11.09., als ein Warnhinweis neben einer abgeschriebenen Spaltenliste
stand und drei Spalten mit Inhalt trotzdem verlorengingen.

DESHALB MACHT ES JETZT DAS WERKZEUG. `tools/seiten-stempel.mjs`
setzt beide Zahlen auf denselben Stempel wie die Seiten. Passt eines
der zwei Muster nicht mehr, bricht es ab, statt stillschweigend
weiterzulaufen -- sonst waere die Zahl ab da wieder von Hand
gepflegt, und das merkt niemand.

Dass der Vorrat bei jedem Stempeln neu aufgebaut wird, ist Absicht:
sechs kleine Dateien kosten nichts, ein unbemerkt alter Stand fuenf
Wochen.

UND EINE WACHE DAZU. `pruef-zwischenspeicher` prueft jetzt:
  · beide Zahlen stehen da
  · sie sind GLEICH -- sonst wird der Vorrat geleert, aber der
    Service Worker gar nicht erst neu geladen (Cloudflare ersetzt
    sein `no-cache` durch vier Stunden)
  · die Zahl ist nicht aelter als die vorgehaltenen Dateien

Die Liste der vorgehaltenen Dateien wird AUS DEM SERVICE WORKER
gelesen, nicht abgeschrieben -- eine zweite hier waere die, die beim
naechsten Eintrag auseinanderlaeuft.

Gegenprobe gemacht: die zwei Zahlen um eine Minute auseinander ->
rot, zurueck -> gruen.

DEPLOY.md sagt jetzt, dass es automatisch geht, und nennt den Befund
im Wortlaut daneben.

Gemessen: pruef-zwischenspeicher 34/0 (war 30/0), pruef-bewegung 9/0,
pruef-css-klassen 37/0, pruef-struktur 44/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 12:12:32 +02:00
DogFatherGitandClaude Opus 5 d087d02a63 Seit fuenf Wochen kam keine Aenderung der Website bei einem wiederkehrenden Besucher an
Gefunden beim Nachgehen des letzten roten Pruefstand-Eintrags. Eine
Kette aus drei Funden, und der dritte wiegt am schwersten.

=====================================================================
1. EINE ENDLOSE BEWEGUNG AUF ETWAS UNSICHTBAREM
=====================================================================
`pruef-browser` scheiterte in WebKit daran, dass der Anmeldeknopf nie
ruhig wurde. Eine der zwei laufenden Bewegungen war:

    .knopf__laden { opacity: 0; animation: dreh .8s linear infinite; }

Dieselbe Suche, ueber ALLE 42 Stilvorlagen beider Haeuser und der
Website, fand einen zweiten: An jedem Navigationspunkt der
oeffentlichen Seite lief eine elf Sekunden lange Aurora -- unsichtbar
bis zum Ueberfahren, auf jeder Seite, fuer immer.

Beides faellt niemandem auf: Nichts stuerzt ab, nichts sieht falsch
aus. Es kostet nur Rechenzeit und Akku.

NEU: `server/pruef-bewegung.mjs` mit sechs Gegenproben -- darunter
die wichtigste, dass ein Beispiel IM KOMMENTAR nicht zaehlt (genau
diese Falle hat am 29.09. eine andere Pruefung dreimal getroffen).
Der Gesamtlauf findet sie von selbst, sie laeuft ab heute Nacht mit.

=====================================================================
2. DIE WEBSITE HATTE KEINEN STEMPLER
=====================================================================
Fuer den Workspace gibt es `workspace-stempel.mjs` seit Langem. Die
oeffentliche Website hatte nichts -- dort stand ein VON HAND
gepflegter Stempel, und der ist gealtert wie jede von Hand gepflegte
Liste.

NEU: `tools/seiten-stempel.mjs`, 447 Verweise in 35 Seiten. Er kennt
beide Schreibweisen (mit und ohne fuehrenden Schraegstrich) UND die,
die in einem `style="…url(…)"` stehen -- zwei Hintergrundbilder auf
streamplan.html waeren sonst ein Jahr lang die alten geblieben.
Dieselbe Luecke gab es im Workspace-Stempler schon einmal, dort bei
den App-Symbolen.

=====================================================================
3. UND DESHALB KAM SEIT DEM 27.08. NICHTS MEHR AN
=====================================================================
    Stempel in allen 35 Seiten:     ?v=20260828e  (zuletzt 27.08.)
    Aenderungen an assets/ seither: 6 Commits
    Der Server dazu:  Cache-Control: max-age=31536000, immutable

`immutable` heisst: Der Browser fragt nicht einmal nach. Wer die
Seite einmal geladen hatte, behielt Stilvorlagen und Skripte bis zu
EINEM JAHR.

Darunter der Partnercode DOGI10 auf der gepraegten Muenze und der
komplette Sprachumbau der Oberflaeche. Sie lagen auf dem Server, sie
waren ausgeliefert, und niemand sah sie.

Dieselbe Sorte Fehler wie am 09.09. im Workspace („eine Aenderung ist
nicht gemacht" -- sie war es, nur unsichtbar) und dieselbe wie bei
VanVans Shop: Eine Aenderung ist erst fertig, wenn sie auf der
Adresse ankommt, die der Nutzer benutzt.

`pruef-zwischenspeicher` fragt jetzt nicht mehr nur, OB ein Stempel
dasteht, sondern ob er NEUER ist als die Dateien, auf die er zeigt.
Gegenprobe gemacht: eine Datei zwei Stunden in die Zukunft gesetzt ->
rot, Zeit zurueck -> gruen. Eine Stunde Nachsicht, damit die Wache
nicht bei zwei Minuten anschlaegt und weggeklickt wird.

DEPLOY.md hat jetzt einen Schritt 0 mit beiden Stemplern und dem
Grund dafuer -- der Befund steht im Wortlaut daneben.

Gemessen: pruef-bewegung 9/0, pruef-zwischenspeicher 30/0,
pruef-browser 17/0, pruef-css-klassen 37/0, pruef-struktur 44/0,
pruef-workspace-umzug 3/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 11:38:38 +02:00
DogFatherGitandClaude Opus 5 8e4e525861 Auf der Zugangswand drehte sich ein unsichtbarer Kreisel -- fuer immer
`pruef-browser` stand seit dem 28.09. rot, und zwar NUR in WebKit
(Safari): „element is not stable" beim Klick auf den Anmeldeknopf, 53
Versuche ueber 30 Sekunden. Chromium und Firefox waren gruen.

Nachgemessen wanderte sein Kasten pro Bild um ein Fuenftel Pixel:

    746.12,575.12  ->  745.10,575.60   (sechs Bilder)

Zwei Bewegungen liefen dabei -- `.buehne__bild` und `.knopf__laden`.
Beide sind echte Befunde.

=====================================================================
1. DER KREISEL DREHT SICH FUER IMMER, UNSICHTBAR
=====================================================================
    .knopf__laden { opacity: 0; animation: dreh .8s linear infinite; }
    .knopf[disabled] .knopf__laden { opacity: 1; }

Nur die Deckkraft schaltete um. Die Drehung lief ab dem Laden der
Seite, auf JEDEM Knopf, fuer immer -- nicht zu sehen und trotzdem
jedes Bild neu gerechnet. Auf einer Seite, auf der man einen Code
eintippt, ist das reine Verschwendung.

Und sie kannte die Hausregel nicht: Wer weniger Bewegung eingestellt
hat, bekam sie trotzdem. Jetzt dreht sie nur, wenn der Knopf
wirklich arbeitet -- und bei `prefers-reduced-motion` steht der Ring
still, statt zu verschwinden: Ein unsichtbarer Kreisel sagt gar
nichts, ein stehender sagt „ich arbeite noch".

=====================================================================
2. DIE KARTE BEWEGTE SICH, WENN MAN NACH IHR GRIFF
=====================================================================
Die Parallaxe folgte dem Zeiger AUCH ueber der Anmeldekarte. Wer die
Maus zum Codefeld fuehrt, bewegte damit das Feld. Bei zehn Pixeln
keine Katastrophe -- aber genau verkehrt herum: Was man bedienen
will, soll stillstehen.

Und es war der Grund fuer den Wettlauf: Der Zeiger bewegte das Ziel,
das er treffen wollte. Ein Wettlauf zwischen Maus und Karte ist auch
fuer einen Menschen keiner, den er gewinnen soll.

Ueber der Karte wird das Ziel nicht mehr nachgefuehrt. Die
Annaeherung laeuft aus und haelt an; verlaesst man die Karte, geht es
weiter. Das Bild lebt, die Bedienung steht.

=====================================================================
WARUM ES NUR WEBKIT GEZEIGT HAT
=====================================================================
Chromium liefert fuer eine zusammengesetzte Verwandlung oft den
Layout-Kasten OHNE die laufende Bewegung -- dort sah der Knopf ruhig
aus, obwohl er es nicht war. WebKit sagt die Wahrheit. Eine Maschine,
die frueher „gruen" meldet, hat nicht recht; sie sieht nur weniger.

Nachher: pruef-browser 17/0 (war 14/1), alle vier Maschinen.
Dazu gruen: crew-adresse 169/0, crew-wand-bild 45/0, kachelfarben
31/0, css-klassen 37/0, struktur 44/0, tippziele 13/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 11:27:57 +02:00
DogFatherGitandClaude Opus 5 69517e090b Wer im Chat hochscrollt, wird nicht mehr ans Ende gerissen
`pruef-chat-ausbau` stand seit dem 28.09. rot:

    FEHL die Stelle bleibt stehen (0 -> 3574)
    FEHL der Knopf sagt, wie viel wartet ("Zum neuesten")
    FEHL er zaehlt mit ("Zum neuesten")
    FEHL pruef-chat-ausbau: unbehandelter Fehler   (der Knopf blieb verborgen)

WAS WIRKLICH PASSIERTE: Man liest weiter oben im Verlauf, jemand
schreibt -- und man wird ans Ende gerissen. Der Zaehler „1 neue
Nachricht" wurde dabei zurueckgesetzt, der Knopf blieb verborgen.

DIE URSACHE STAND AN DER FALSCHEN STELLE. Die Zuhoerer, die „der
Mensch hat selbst gescrollt" feststellen (Rad, Finger, Taste,
Zeiger), hingen INNERHALB des Sprung-Blocks zur Neu-Linie -- wurden
also erst angehaengt, NACHDEM einmal gesprungen worden war.

In einem ruhigen Gespraech passiert das nie: Wer alles gelesen hat,
bekommt keine Neu-Linie, der Block laeuft nicht, die Zuhoerer gibt es
nicht. Scrollt er hoch und es kommt eine Nachricht, entsteht die
Linie ZUM ERSTEN MAL -- der Block laeuft, haengt die Zuhoerer an und
springt im selben Atemzug. Das Hochscrollen von vorhin hat nie jemand
bemerkt.

Das ist der haeufigste Fall ueberhaupt: ein stiller Chat, man liest
etwas weiter oben nach, jemand schreibt.

Die Wache steht jetzt beim Aufbau, bei den uebrigen Zuhoerern des
Verlaufs. Ausdruecklich NICHT am `scroll`-Ereignis: Der Sprung
scrollt selbst, und `scroll` unterscheidet nicht, wer gescrollt hat.
Rad, Finger, Taste und Zeiger tut nur ein Mensch.

UND DIE PRUEFUNG HAT SELBST GEMOGELT. Sie schrieb `e.scrollTop = 0`
-- das setzt die Bildlaufposition zu, ohne dass ein Rad gedreht
wurde. Damit haette sie den Fehler auch nach der Behebung noch
gemeldet. Sie dreht jetzt das Rad (`mouse.wheel`) und prueft, dass
sie oben angekommen ist. Dieselbe Lehre wie bei den Fingergeraeten:
`setViewportSize` macht aus einer Maus keinen Finger, und
`scrollTop = 0` macht aus einem Programm keinen Leser.

Nachher: 70 Pruefungen, 0 Fehler (vorher 24/4).
    die Stelle bleibt stehen (0 -> 0)
    der Knopf sagt, wie viel wartet ("1 neue Nachricht")
    er zaehlt mit ("2 neue Nachrichten")
    wer unten steht, wird weiterhin mitgenommen -- ohne Knopf

Alle sieben Chatpruefungen gruen: anhaenge 123/0, aufloesen 126/0,
ausbau 70/0, kanaele 81/0, neu-stelle 63/0, neu 36/0, optik 62/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 11:22:14 +02:00
DogFatherGitandClaude Opus 5 75ede0a8e9 Die Rueckfragen sagten nicht, was passiert -- und eine lief gar nicht ueber den Hausdialog
`pruef-nachfrage` und `pruef-call-kategorien` standen seit dem 28.09.
rot und waren als „nicht angesehen" vermerkt. Nachgemessen sind es
drei echte Befunde und eine Zeitbombe.

=====================================================================
1. FALSCHE FELDNAMEN -- die Erklaerung erschien NIE
=====================================================================
Der Hausdialog kennt `was:` und `ja:`. An vier Stellen in
`reaktion.js` stand `text:` und `knopf:`. Beides wird stillschweigend
ignoriert.

Wer „Sendung beenden?" las, bekam den Titel und zwei Knoepfe -- genau
die Frage, die `confirm()` stellt und derentwegen `nachfrage.js`
ueberhaupt gebaut wurde. Es stuerzt nichts ab, es fehlt nur; so etwas
findet keine Syntaxpruefung und kein Blick auf den Bildschirm, wenn
man den Satz nicht vermisst.

Alle vier tragen jetzt `was` UND `bleibt`. Beim Beenden steht dabei
das, was seit heute frueh dazugekommen ist: dass Titel, Video,
Vorschaubild, Beginn und das zweite Video geleert werden -- wer das
nicht weiss, traegt danach alles noch einmal ein und haelt es fuer
einen Fehler.

=====================================================================
2. `window.frageNachText` GIBT ES NICHT
=====================================================================
Nur EINE Zeile im ganzen Haus nennt es; gesetzt hat es niemand. Die
Abfrage „Wie viele Dogen waren es?" lief damit IMMER ueber den
nackten `prompt()` -- ausgerechnet die, die am haeufigsten vorkommt.

Der Hausdialog kann das laengst besser: `zahl:` ist ein Zahlenfeld
mit Obergrenze und eigener Fehlerzeile.

=====================================================================
3. DER DOPPELTE NOTNAGEL WAR TOTER CODE
=====================================================================
`window.frageNach ? await frageNach(...) : confirm(...)` -- der
Notnagel fuer Browser ohne <dialog> steckt schon IN `nachfrage.js`,
und zwar mit DEMSELBEN Text. Meiner daneben zeigte im Ernstfall
WENIGER und im Normalfall nie etwas.

Im Notizblock stand sogar der nackte `window.confirm()`, ganz ohne
Hausdialog. Er fragt „bist du sicher"; der Hausdialog sagt, was
passiert und was bleibt. Beim endgueltigen Loeschen ist das `bleibt`
der halbe Grund fuer die Rueckfrage: Der Papierkorb ist der Ort, an
dem man etwas wiederfindet.

=====================================================================
4. EINE ZEITBOMBE IN pruef-call-kategorien
=====================================================================
Sie legte eine Wiederholung „in vier Tagen" an -- im Quelltext stand
woertlich „also mit grosser Wahrscheinlichkeit dieser Monat". Heute
ist der 30.; vier Tage spaeter ist Oktober. Der Server verlangt
kuenftig UND im laufenden Monat, und am Monatsende gibt es beides
zusammen nicht.

DIE ANWENDUNG HATTE RECHT. Dieselbe Art wie bei `pruef-kalender` am
29.09. Die nahe Auspraegung wird jetzt GERECHNET (letzter Tag des
Monats, 23:59) statt gehofft -- plus ein benannter dritter Ausgang
fuer die eine Minute im Monat, in der es keinen kuenftigen Termin
mehr in diesem Monat gibt. Die drei anderen Aussagen werden auch dann
geprueft; ein Ausstieg, der gar nichts mehr misst, waere ein stiller
Aussetzer.

Gemessen: pruef-nachfrage 53/0 (war 51/2), pruef-call-kategorien 22/0
(war 21/1), pruef-notizen 79/0, pruef-reaktion 407/0, mess-reaktion
0/0, pruef-css-klassen 37/0, pruef-struktur 44/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 11:10:49 +02:00
DogFatherGitandClaude Opus 5 9125583120 Die geschlossene Reaction-Kachel sah aus wie die Aufgaben-Kachel
`pruef-kachelfarben` stand seit dem 28.09. rot und war als „nicht
angesehen" vermerkt. Nachgemessen ist sie ein echter Befund:

    engstes Paar 0.0191 (Aufgaben <-> Reaction), Grenze 0,02

Beide sind entsaettigtes Blaugrau -- die Aufgaben tragen Silber, die
Reaction im Zustand „zu" ein blaues Grau. Genau darueber ging Filipes
Klage vom 22.09.: „ich seh immer wieder sehr viele die einfach
komplett die gleiche farbe haben."

GESUCHT, NICHT GERATEN. Was auf dem Schirm ankommt, ist der Ton UNTER
Sternenfeld, Vignette und Wolke -- aus den 32 gewoehnlichen Kacheln
laesst sich die Abbildung schaetzen. Sie traf auf einen Punkt genau:

    #8b93a4 -> geschaetzt rgb(64,67,84), gemessen rgb(65,68,83)

Damit vorgesiebt, danach wirklich gerendert und nachgemessen -- eine
Schaetzung allein waere eine Rechnung, die plausibel aussieht.

UND NICHT „AM WEITESTEN WEG". Der groesste Abstand ist ein
Rechenergebnis, keine Gestaltung; er fuehrte zu dunklen Lilatoenen.
Gesucht wurde unter denen, die gleich hell bleiben wie bisher UND
warm sind: Die geschlossene Kachel ist die erste Stufe einer Folge
(zu -> gleich -> live, grau -> bernstein -> rot). Ein warmes Grau
fuehrt dorthin, ein blaues steht quer dazu.

    #b8a8a0   Abstand 0,0481 statt 0,0191, Kontrast 8,7:1

Nachher am echten Bildschirm: 31 Pruefungen, 0 Fehler, engstes Paar
jetzt 0,0277 (Willkommen <-> Notizen). Die Rohfarbe kommt zu 56,5 %
an (vorher 38,9 %).

NEBENBEI: `pruef-zentrale-ring` war ebenfalls als rot vermerkt und ist
inzwischen gruen (14/0) -- der Eintrag im Pruefstand war veraltet.
Eine Bestandsliste altert, auch die eigene.

Gemessen: pruef-kachelfarben 31/0, pruef-zentrale-ring 14/0,
pruef-crew-wand-bild 45/0, pruef-css-klassen 37/0, pruef-struktur
44/0, pruef-haus-seiten 38/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 10:52:46 +02:00
DogFatherGitandClaude Opus 5 0031091bdd Die Eckenwahl zeigt, wo die Kameras stehen -- der letzte offene Punkt der Werbung
Offener Punkt vom 29.09.2026:

  „Die Eckenbilder koennen auf den Kamerakacheln landen. 'Unten
   rechts' liegt im Layout 'Kino' genau dort, wo die Kameras stehen.
   ... aber die Regie warnt dich (noch) nicht vorher."

GEZEIGT, NICHT VERBOTEN. Ein Platz, den die Regie ablehnt, waere
falsch: Vielleicht soll das Logo genau dorthin, weil die Kameras
gleich umziehen oder weil auf „nur Video" geschaltet wird. Wer
entscheidet, braucht die Auskunft -- nicht die Entmuendigung.
Dasselbe Verhaeltnis wie beim Tempo-Knopf, der grau wird statt zu
verschwinden.

NUR IM LAYOUT „KINO". `kamera_ecke` steuert den Stapel nur dort; bei
„gleich" und „Kamera gross" stehen die Kameras woanders, bei „nur
Video" gar nicht. Ein Hinweis, der auch dann erschiene, warnte vor
etwas, das nicht passieren kann -- und so etwas gewoehnt man sich ab.

AM KNOPF UND IM VORLESETEXT. Ein gestrichelter Rahmen in Bernstein
(40 %, gedaempft -- was gewaehlt ist, muss lauter sein als was zu
bedenken ist) UND der Satz „hier stehen gerade die Kameras" in
`title` und `aria-label`. Eine Markierung, die nur eine Farbe ist,
gibt es fuer den nicht, der Farben schlecht unterscheidet oder die
Seite vorlesen laesst.

Gemessen in mess-reaktion, mit Gegenprobe -- eine Markierung, die
immer da ist, ist keine:
    Eckenwahl im Kino (Kameras unten rechts): ur:benannt
    Gegenprobe bei „nur Video": 0 Hinweis(e)
„benannt" prueft ausdruecklich, dass der Satz dransteht und nicht nur
die Farbe.

Gemessen: mess-reaktion 0/0, pruef-reaktion 407/0, pruef-css-klassen
37/0, pruef-struktur 44/0, pruef-tippziele 13/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 10:43:42 +02:00
DogFatherGitandClaude Opus 5 6a42ce3432 Der Vorhang geht von selbst wieder auf -- ein offener Punkt weniger
Offener Punkt vom 29.09.2026, woertlich aus der Projektnotiz:

  „Nimmst du jemanden aus der Sendung und machst es gleich wieder
   rueckgaengig, steht bei ihm weiter 'Du bist aus dieser Sendung'.
   ... Das sauber zu loesen hiesse, ihm waehrend der Sperre eine
   langsame Nachfrage zu lassen -- das ist ein eigener Umbau."

Der Umbau ist seit gestern da: Der geschlossene Saal fragt alle 15
Sekunden nach. Dasselbe Muster passt hier -- nur die FRAGE muss eine
andere sein.

NUR DIE EINE FRAGE, NICHT DER GANZE STAND. `rausgenommen()` schliesst
den Ereignisstrom mit Absicht: Wer draussen ist, soll die Sendung
nicht weiterverfolgen. `/api/reaktion` braechte Video, Titel und
Stand mit -- genau das, was ihr genommen werden soll. `POST /dabei`
beantwortet dagegen nur „bin ich wieder dabei?" und verraet nichts:

    403 aus_der_sendung / treff_massnahme  -> weiter warten
    409 saal_zu                            -> weiter warten
    200                                    -> neu laden

NEU GELADEN WIRD NUR BEI 200, und das ist der Unterschied zwischen
einer Loesung und einer Schleife. Schliesst der Saal, waehrend jemand
draussen ist, kaeme 409; wuerde darauf neu geladen, stuende die
Massnahme danach immer noch, der Vorhang kaeme wieder, und die Seite
laedt sich im Kreis.

ZWANZIG SEKUNDEN. Eine Massnahme ist kein Anruf -- wer
zurueckgeholt wird, ist eine halbe Minute spaeter wieder da.

UND WARUM NEU LADEN STATT WEITERZEICHNEN: `rausgenommen()` hat die
Verbindungen abgebaut, den Strom geschlossen und den Vorhang
angehaengt. Das im Betrieb wieder aufzubauen waere viel Zustand --
und genau das tut ein Neuladen in einem Schritt. Bisher haben wir
den Menschen darum GEBETEN.

DIE PRUEFUNG FEHLTE, und das ist der eigentliche Punkt: Der Mangel
stand seit dem 29.09. in der Notiz und hatte keine. So bleibt ein
bekannter Mangel fuer immer bekannt -- niemand merkt, wenn er behoben
ist, und niemand merkt, wenn er zurueckkommt. Jetzt wartet
mess-reaktion nach der zurueckgenommenen Massnahme darauf, dass der
Vorhang von selbst verschwindet. Gegenprobe gemacht: Nachfrage
abgeschaltet -> „Der Vorhang hebt sich von selbst: NEIN", Rueckgabe 1.

Gemessen: mess-reaktion 0/0, pruef-reaktion 407/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 10:37:05 +02:00
DogFatherGitandClaude Opus 5 0fbd3f45b3 Die Chatkiste steht immer, Beenden raeumt auf -- und eine verspaetete Antwort ueberschreibt nichts Neueres mehr
Filipe, 30.09.2026: „wenn eine sendung beendet wurde soll alles
automatisch verschwinden. also von daten die da stehen von dem video."
Und: „mach dass ich die chat kiste immer sehe bitte und nicht erst
wenn das video läuft."

=====================================================================
1. BEENDET HEISST LEER
=====================================================================
Beim Beenden verschwinden Titel, YouTube-Adresse, Videotitel,
Vorschaubild, Beginn und das zweite Video samt seiner Stelle. Vorher
blieb alles stehen; beim naechsten Aufmachen stand dort der Titel der
letzten Sendung und ein Beginn, der in der Vergangenheit liegt.

ERST DER VERLAUF, DANN DAS LEEREN -- weg vom Schreibtisch heisst
nicht weg aus der Welt. Geprueft: Nach dem Beenden steht die Sendung
weiter in `reaktion_verlauf`, samt Video.

EINE FELDLISTE, NICHT ZWEI. Die Aufzaehlung stand in der
Zuruecksetzen-Route; jetzt brauchen sie zwei Wege. `SENDUNGS_FELDER`
und `PULT_EINSTELLUNGEN` stehen einmal oben. Zwei Abschriften waeren
die, die beim naechsten Spaltenzuwachs auseinanderlaufen -- genau so
sind am 11.09. drei Spalten mit Inhalt verlorengegangen.

Einstellungen (Bildaufteilung, Kameragroesse, Chatmodus) und die
Warteschlange bleiben -- die raeumt weiter nur „Alles zuruecksetzen"
ab. Wer nur vorbereitet und dann zumacht, behaelt seine Eingaben; das
ist eine Entscheidung und steht als Pruefung fest.

DAS FELD „BEGINN" WURDE NIE GELEERT, nur gefuellt:
`if (lage.beginnt_am && document.activeElement !== …)` -- zwei Fragen
in einer Bedingung, und die zweite beantwortete die erste
stillschweigend mit nein. Das betraf auch den vorhandenen
Zuruecksetzen-Knopf.

=====================================================================
2. DIE CHATKISTE STEHT IMMER
=====================================================================
Sie lag in `#teil-live` und ging mit ihm weg. Im Wartebereich stand
dabei woertlich „Der Chat ist schon offen" -- der Satz stimmte sogar,
der Server laesst dort schreiben (201, geprueft); zu sehen war der
Chat trotzdem nicht.

Die drei Haeute und die Schiene liegen jetzt in einem gemeinsamen
`.raum`: links wechseln die Haeute, rechts steht der Chat. Das Raster
wandert mit nach oben statt sich zu verdoppeln -- zwei
`grid-template-columns` fuer dieselbe Frage waren am 28.09. der
Grund, warum die Regieleiste null Pixel bekam.

Wer nicht schreiben darf, liest den Grund im Feld („Der Saal ist zu").

DER UMBAU HAT DREI DINGE VERSCHOBEN, und die Messung hat sie sofort
gefunden: Kino 0 px hoch, Spendenkarte bei x=1458 ausserhalb des
Bildes, „Kamera aus"-Schild kam nicht an. Eine Ursache: Zwei Regeln
(`grid-row: 2` und `grid-area: kino`) zielten auf die drei Haeute,
weil die frueher unmittelbar im Saal lagen. Gefunden hat das nicht
das Nachdenken, sondern eine Messung der ganzen Kette --
`teil-live 0x0 @1440,742` lag NEBEN dem Raum.

=====================================================================
3. „DER SAAL IST ZU" ERREICHTE NIEMANDEN, DER DARIN SASS
=====================================================================
`stand: "zu"` loescht `reaktion_dabei`, und `melden()` suchte seine
Empfaenger erst danach -- in genau dieser geleerten Liste. Die Seiten
der Zuschauer blieben auf „live" stehen.

`melden(art, daten, wer)` nimmt jetzt eine Empfaengerliste; die
Stand-Route bestimmt sie VOR jeder Aenderung.

UND EINE ZUGESPERRTE SEITE VERSTUMMTE FUER IMMER. War der Saal zu,
hielt `anschliessen()` jeden Takt an -- und Rundrufe bekam sie auch
keine, weil sie in keiner Liste mehr stand. Machte der Host wieder
auf, passierte bei allen mit offenem Reiter NICHTS. Nicht in dreissig
Sekunden: nie, bis jemand von Hand neu lud. Gemessen: Server sagt
„vorbereitung", die Seite zeigt „zu", auch nach 40 Sekunden.
Jetzt fragt eine geschlossene Seite alle 15 Sekunden nach -- der
ruhigste Zustand des Hauses, dort kostet das nichts.

=====================================================================
4. WER ZULETZT ANTWORTET, HAT NICHT RECHT
=====================================================================
Eine Abfrage ist Sekundenbruchteile unterwegs. Kommt in dieser Zeit
ein Rundruf an, ist SEIN Stand der neuere -- und trotzdem hat die
verspaetete Antwort ihn ueberschrieben.

Gemessen: Die Regie schaltet die Werbung auf Wechsel, der Rundruf
zeichnet ihn, und einen Augenblick spaeter steht wieder Laufband.
Eine feste Wartezeit in der Messung hatte das zugedeckt; es fiel
erst auf, als ich sie durch eine echte Bedingung ersetzte.

Drei Runden Raten lagen daneben. Gefunden hat es eine Mitschrift der
Aufrufkette:

    wechsel:2  @ EventSource
    laufband:2 @ zeichnen < standHolen < signalEmpfangen

Eine Folgenummer zaehlt jeden angekommenen Rundruf. Jede Abfrage, die
die Seite VON SICH AUS macht -- nach dem Verbindungsaufbau, im
geschlossenen Saal, bei jedem Verbindungssignal, nach einer
abgelehnten Anwesenheitsmeldung, und der Anwesenheitstakt selbst --
verwirft ihr Ergebnis, wenn inzwischen etwas Neueres da war.

Abfragen nach einer EIGENEN Handlung bleiben hart: Sie bringen Dinge
mit, die kein Rundruf traegt (die Verwaltungslisten der Regie). Die
Unterscheidung steht am Aufruf, nicht in einer Bedingung im Inneren.

=====================================================================
5. UND DIE MESSUNGEN WARTEN NICHT MEHR AUF DIE UHR
=====================================================================
Feste Wartezeiten sind dieselbe Falle wie feste Schwellen: Sie
stimmen, bis daneben etwas langsamer wird, und melden dann einen
Fehler, den es nicht gibt. Zweimal ist mir das in einer Stunde
passiert -- einmal beim Band, einmal bei den Ecken. Der Werbeblock
wartet jetzt fuenfmal auf das Ergebnis, der Gleichlauf viermal; laeuft
eine Frist ab, ist es ein echter Befund.

Die erste Fassung der Gleichlauf-Gegenprobe war selbst falsch -- sie
hielt das Selbstheilen des Systems fuer einen Fehler.

Neu in mess-reaktion: „Die Chatkiste in jedem Zustand" (alle drei,
mit Breite und Sperrgrund) und „Beendet heisst leer (im Pult)" -- dort
gemessen, wo Filipe hinsieht, nicht in der Datenbank.
Neu in pruef-reaktion (+14): das Leeren, die Gegenprobe „vorher war
etwas drin", der Verlauf bleibt, und die Entscheidung „wer nur
vorbereitet hat, behaelt seine Eingaben".

Gemessen: mess-reaktion dreimal hintereinander 0/0, pruef-reaktion
407/0, pruef-css-klassen 37/0, pruef-struktur 44/0, pruef-tippziele
13/0, pruef-haus-seiten 38/0, pruef-haus-trennung 100/0, pruef-buehne
38/0, pruef-push-ziel 38/0, mess-buehne 0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-30 02:36:13 +02:00
DogFatherGitandClaude Opus 5 2c3b90d75c Benachrichtigungen: die Reaction laedt ein, jedes Haus bekommt sein Gesicht -- und die Videos haengen nicht mehr
Filipe, 29.09.2026: „ich will dass du die benarichtigungen
perfektionierst. dogfather und alle anderen sollen die
benachrichtigungen perfekt von dieser seite hier bekommen."
Und dazu, mit einer Bildschirmaufnahme: „wieso haengen die videos
immer."

=====================================================================
1. WARUM DIE VIDEOS HAENGEN -- zwei Zeilen, eine Rueckkopplung
=====================================================================

Die Aufnahme zeigt den YouTube-Zaehler bei 0:13 von 31:34, vier
Bilder lang unbewegt, in der Mitte der Ladering.

  a) `hostMelden()` rechnete `laeuft = getPlayerState() === 1`.
     Zustand 3 heisst PUFFERN -- „ich will spielen, mir fehlen
     gerade Daten". Der Host meldete in diesem Moment „laeuft
     nicht", und zwar sofort, weil `onStateChange` bei jedem
     Zustandswechsel meldet.

  b) `empfaenger()` fuegt den Host ausdruecklich hinzu, und
     `folgen(d)` lief im Ereignisstrom fuer alle -- auch fuer ihn.
     Seine eigene Meldung kam zurueck und traf dort auf
         if (!stand.laeuft && getPlayerState() === 1) pauseVideo();

  Der Host puffert eine halbe Sekunde, laeuft weiter -- und wird vom
  Echo seines eigenen Pufferers angehalten. Bei einem 31-Minuten-Video
  passiert das in den ersten Sekunden zuverlaessig.

  Und alle Zuschauer bekamen bei JEDEM Pufferer des Hosts ein
  Pause-Play-Paar. Das ist das Ruckeln, das man fuer die eigene
  Leitung haelt.

GEMESSEN, NICHT HERGELEITET (mess-reaktion):
    vorher   Host=laeuft -> Pufferer gemeldet -> Host=pause
    nachher  Host=laeuft -> Pufferer gemeldet -> Host=laeuft

Drei neue Messungen, jede mit Gegenprobe:
  · ein gemeldeter Pufferer haelt den Host nicht an
  · ein ECHTES Anhalten (Knopf gedrueckt) haelt alle an -- sonst
    waere das Erste mit kaputtem Gleichlauf bezahlt
  · beim Puffern meldet der Server `laeuft=true`; ist der Pufferer
    nicht herzustellen, sagt die Messung das (dritter Ausgang)
Beide Behebungen einzeln zurueckgenommen: beide Male rot.

Die erste Fassung der Gegenprobe war selbst falsch -- sie hielt das
Selbstheilen des Systems (der Host meldet alle fuenf Sekunden die
Wahrheit) fuer einen Fehler. Deshalb drueckt sie jetzt den Knopf,
statt eine Meldung zu faelschen.

=====================================================================
2. DIE REACTION LAEDT EIN
=====================================================================

Nachgemessen war `workspace-reaktion.js` STUMM: kein einziges
`benachrichtige`. Beim Einschalten lief `melden("reaktion", ...)`
ueber den Ereignisstrom -- also nur an Leute, die die Seite ohnehin
offen haben. Das Kino machte auf, und die Einladung verliess das Haus
nie. Dasselbe Muster wie bei den Bewerbungen am 23.09.

Neue Art `reaktion_live`, eigene neben `dogfather_live`: Das eine ist
sein Stream auf TikTok, das andere das Kino hier im Haus.

Eingeladen wird, wer ein Geraet hat und NICHT der Agentur gehoert
(`AGENTUR_ROLLEN` -- keine neue Liste). Nicht der, der eingeschaltet
hat. Und nicht zweimal: Eine Bremse von zwei Stunden faengt den
Neustart ab, denn das Merkmal haengt an `gestartet_am` und das wird
bei jedem Wechsel nach live neu gesetzt.

Geprueft Ende zu Ende in pruef-reaktion (+10): Sendung geht auf
Sendung, danach stehen genau fuenf Einladungen in `push_verschickt` --
rechte Hand, linke Hand, Modi, zweimal Community. Nicht der Host,
nicht die Creatorin. Einladung abgeschaltet: sechs Fehlschlaege.

=====================================================================
3. DARF DAS NACHTS KOMMEN? -- drei Antworten statt zwei
=====================================================================

Hier stand `art === "test" || art === "anruf"`, 230 Zeilen von der
Artenliste entfernt. Am 18.09. hat das eine Nacht lang alle Anrufe
verschluckt; behoben wurde damals dieser eine Fall.

GEMESSEN AM LIVE-BESTAND: `dogfather_live` ging an allen sieben
Abenden vom 22. bis 28.09. zwischen 20:28 und 21:06 raus -- jedes Mal
knapp vor der Sperre um 22 Uhr. Geht Filipe einmal um 22:05 live,
bekommt niemand etwas, und niemand erfaehrt warum.

`ruhe` steht jetzt an der ART:
  "immer" (Vorgabe)  22-7 gesperrt   -- Erinnerungen
  "spaet"            nur 1-7         -- etwas laeuft GERADE
  "nie"              nie             -- ein Mensch wartet am Hoerer

=====================================================================
4. JEDES HAUS BEKOMMT SEIN GESICHT
=====================================================================

Im Service Worker stand fest `workspace-192.png`. Von acht Menschen
mit angemeldetem Geraet gehoeren fuenf ins Crew-Haus -- die sahen auf
jeder Benachrichtigung das Symbol des Hauses, in dem sie nicht
arbeiten.

Entschieden wird es auf dem SERVER: Im Browser stuende sonst die
verborgene Crew-Adresse in einer Datei ohne Anmeldung (der Befund vom
21.09. bei crew-haus.css) -- und es waere eine zweite Fassung der
Hausteilung. Zweistufig, beide Stufen gibt es schon: die Zielseite,
wenn sie in genau ein Haus gehoert (GEHOERT_ZU_ADRESSE), sonst
`AGENTUR_ROLLEN`.

=====================================================================
5. DAS ABZEICHEN WAR EIN KLOTZ
=====================================================================

`badge` ist das winzige Zeichen in der Statusleiste; Android benutzt
davon NUR den Alphakanal. Dort stand dasselbe `workspace-192.png` --
ein vollflaechiges Quadrat ohne Transparenz, also ein ausgefuellter
Klotz. Es stuerzt nichts ab, deshalb faellt es niemandem auf.

`assets/img/abzeichen-96.png`: der gefuellte Umriss des Huskys, weiss
auf durchsichtig, 3,5 KB. Drei Fassungen gebaut und bei ECHTER Groesse
(24 px) verglichen -- Strichbild zerfaellt, Flaeche traegt.

`server/helfer-png-alpha.mjs` liest den Alphakanal wirklich (PNG
auspacken, Zeilenfilter zuruecknehmen). Eine Pruefung auf „die Datei
gibt es" haette den Klotz nie gefunden -- die Datei gab es ja. Die
Gegenprobe ist der alte Zustand selbst: dieselbe Rechnung meldet auf
`workspace-192.png` „kein Alphakanal, Deckung 100 %".

Das Abzeichen liegt NICHT bei den App-Symbolen -- `pruef-struktur`
verlangt dort zu jedem Namen den vollen Satz und hielt es fuer eine
neue App. Der Waechter hat recht: Ein Abzeichen ist kein App-Symbol.

=====================================================================
Gemessen: mess-reaktion 0, pruef-reaktion 393/0 (+10),
pruef-push-ziel 38/0 (+27), pruef-push 24/0, pruef-push-weg 20/0,
pruef-glocke 36/0, pruef-struktur 44/0, pruef-haus-trennung 100/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-29 23:48:46 +02:00
DogFatherGitandClaude Opus 5 a43bc565ec Werbeeinblendung fuer die Reaction: Laufband, Wechsel und zwei Bilder in sechs Ecken
Filipe: „ich will dass du auch perfektionierst dass ich einen banner
durchlaufen kann, oder erscheinen lassen kann mit werbung drauf ...
und ich will auch das dogfather logo oben rechts links unten rechts
links genau wie oben unten mittig, so dass ich es wegmachen und
hinzufuegen kann."

DAS BAND
Zwei Arten: „Laufband" zieht die Botschaften von rechts nach links,
„Wechsel" blendet sie nacheinander ein. Ein Rabattcode gehoert in den
Wechsel -- wer „DOGI10" lesen will, waehrend es wandert, hat es
gesehen und nicht behalten. Die Dauer ist einstellbar (8-40 s).

Das Band ist Glas, kein Balken: ein Verlauf, unten dicht genug, dass
jede Schrift traegt, oben offen. Man sieht das Video weiter.

Das Laufband traegt die Folge ZWEIMAL. Wandert es um 50 % seiner
Breite, steht die zweite dort, wo die erste war, und der Sprung
zurueck ist unsichtbar. Ohne sie entstuende am Ende jedes Durchlaufs
eine leere Flaeche -- das sieht aus, als sei die Einblendung
abgestuerzt.

Wer weniger Bewegung eingestellt hat, bekommt den Wechsel statt des
Laufbands -- nicht „aus". Die Werbung soll auch dann wirken.

DER RABATTCODE
Ein Wort in Grossbuchstaben mit einer Ziffer darin bekommt eine
eigene Flaeche in Bernstein: „DOGI10" ja, „VANVAN" nicht. Er ist der
einzige Teil der Botschaft, den jemand ABSCHREIBEN soll.

Der Text wird NIE als HTML eingesetzt -- die Kennzeichnung baut echte
Elemente. Sonst waere ein Eingabefeld im Regiepult ein Weg, fremdes
Markup in den Stream zu bringen.

DIE ZWEI BILDER
Der Husky und der Haekelhase aus der Zusammenarbeit mit VanVan,
jeweils an einem von sechs Plaetzen: oben und unten, je links,
mittig, rechts -- oder aus. Links und rechts mittig gibt es mit
Absicht nicht: dort liegen bei jedem Videodienst die Bedienelemente.

Zwei Bilder auf denselben Platz werden abgelehnt (400 ecke_belegt) --
sie laegen uebereinander, und man saehe von beiden nichts.

Wer unten steht, weicht dem Band aus, und die Spendentafel rueckt
hoch. Beides im Stilblatt ueber `:has`, nicht im Programm: Das Band
kennt die Tafel nicht und die Tafel kennt das Band nicht.

Der Husky ist schwarz und laege auf dunklem Videobild als Silhouette
in der Nacht. Zwei weiche helle Schatten legen eine Kontur darum --
dieselbe Loesung, die jeder Sender fuer sein Wasserzeichen nimmt.

IM STREAM, NICHT NUR IM SAAL
Beides laeuft in der Buehnenquelle mit, die OBS abfilmt, mit
groesserer Schrift (24 statt 18 px) -- ein Stream wird auf einem
Handy gesehen, oft in einem Viertel des Bildes. Gemessen: die OFFENE
Quelle zieht eine Umschaltung nach, ohne dass die Szene neu geladen
werden muss.

EINE QUELLE, NICHT DREI
`werbungStand()` steht in `reaktion-tabellen.js` und wird von Saal,
Regie und Buehne aufgerufen. Erst standen dort drei Abschriften
derselben Abfrage; beim Entfernen der Datenbank-Kennung habe ich eine
davon geaendert, und die anderen lieferten sie weiter.

WAS DIE PRUEFUNGEN DABEI GEFUNDEN HABEN
- pruef-buehne: Die Botschaften trugen ihre Datenbank-Kennung in die
  OBS-Auskunft, die nur mit einem Schluessel geschuetzt ist. Die
  Feldliste geht jetzt zwei Ebenen tief -- eine abschliessende Liste,
  die nur die oberste kennt, laesst sich umgehen, indem man ein Feld
  in ein vorhandenes Objekt legt.
- pruef-reaktion: Acht Fehlerwoerter ohne deutschen Satz. Nachgetragen
  im Hausstil: was nicht geht UND was stattdessen.
- pruef-struktur: Die Suche nach totem CSS las `buehne.html` und
  `tafel.html` nicht -- eine Ausnahme, die fuer eine ganz andere
  Frage gemacht war (Startbildschirm-Symbol). Sie haette verlangt,
  `.obs-buehne` zu loeschen, also die Regel, die den Stream traegt.
- pruef-tippziele: Erkannte als Anhebung nur `min-height`/`min-width`.
  Ein `height: 44px` im Fingerblock hebt genauso -- Fehlalarm, und
  ein Fehlalarm an einer Pruefung, die nach jeder Aenderung laeuft,
  wird weggeklickt. Zwei Gegenproben dazu.
- mess-reaktion: Die Regieleiste am Handy wurde gegen die feste Zahl
  SIEBEN geprueft und meldete „zeigt nur 8 von 7". Sie zaehlt jetzt
  selbst.
- mess-buehne: Die Konsolenmeldung zeigte dauerhaft vier
  Fehlschlaege, alle von den Pruefungen selbst bestellt. Jetzt eng
  gefiltert, benannt, mit Gegenprobe -- und ein UNERWARTETER
  Fehlschlag in der Quelle, die in den Stream geht, faellt ab sofort
  durch.

Gemessen: mess-reaktion 0, mess-buehne 0, pruef-reaktion 383/0,
pruef-buehne 38/0, pruef-tippziele 13/0, pruef-struktur 44/0,
pruef-css-klassen 0, pruef-haus-trennung 100/0, pruef-haus-seiten 38/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-29 17:16:26 +02:00
DogFatherGit 077925ab25 Dreizehn rote Pruefungen, eine Ursache: openssl steht nicht im PATH
DER BEFUND

Im naechtlichen Lauf standen dreizehn Pruefungen mit derselben Zeile
rot:

    [uncaughtException] Error: spawnSync openssl ENOENT

Kein Programmfehler. Die Pruefungen brauchen einen https-Vorbau (der
Sitzungskeks des Hauses ist `secure` und kommt ueber http nicht an),
und dafuer erzeugen sie ein Wegwerf-Zertifikat mit openssl.

GEMESSEN, NICHT VERMUTET

  openssl liegt hier:   C:\Program Files\Git\mingw64\bin\openssl.exe
                        C:\Program Files\Git\usr\bin\openssl.exe
  im System-PATH steht: C:\Program Files\Git\cmd   (nur git.exe)
  im Benutzer-PATH:     nichts mit Git

Wer aus Git Bash startet, erbt die mingw-Pfade und merkt nie etwas.
Die Aufgabenplanung startet `node.exe` DIREKT, ohne Shell -- und
bekommt sie nicht. Bei mir gruen, nachts rot, und der Grund steht
nicht im Code.

Das Schlimmste daran ist nicht der Ausfall: Dreizehn dauerhaft rote
Zeilen in einer Notiz, die Filipe morgens liest, gewoehnen einem das
Hinsehen ab -- und decken dabei die echten Befunde zu.

DIE REPARATUR

`server/helfer-openssl.mjs` sucht openssl erst im PATH (ohne `where`
oder `which` -- beides sind selbst Programme und koennen genauso
fehlen), danach an den Orten, an denen es auf einem Windows-Rechner
mit Git wirklich liegt.

Dazu `zertifikatBauen(schluessel, zertifikat, host)`. Die acht
Aufrufformen im Haus waren identisch bis auf die Variablennamen
(schl/zert, schluesselDatei/zertDatei, zKey/zCrt, sk/zt, key/crt) --
eine Stelle traegt alle neunundzwanzig. Zwei Tage zuvor war eine
davon um ein `-addext` aermer als die anderen; gemerkt hat es
niemand, weil der Browser den fehlenden Alternativnamen erst bei
einer Weiterleitung anmahnt. Eine Stelle kann nicht von sich selbst
abweichen.

KEIN EINTRAG IN DEN SYSTEM-PATH. `mingw64\bin` enthaelt rund hundert
Programme mit Unix-Namen (`find`, `sort`, `link`), die gleichnamige
Windows-Befehle verdecken. Das fuer eine Pruefung zu aendern haette
an ganz anderen Stellen Fehler verursacht, die niemand hierher
zurueckverfolgt.

GEGENPROBE IN BEIDE RICHTUNGEN, mit dem PATH des Nachtlaufs:

  vorher (direkter Aufruf):  ABSTURZ: spawnSync openssl ENOENT
  nachher (ueber den Helfer): Zertifikat gebaut, 1236 Bytes

Und eine echte Pruefung unter denselben Bedingungen:

  PATH ohne mingw64 -> pruef-chat-neu-stelle
  63 Pruefungen, 0 Fehler, 0 Abstuerze

Genau diese Datei stand im Nachtlauf mit ENOENT rot.

EINE WACHE DAGEGEN

pruef-struktur prueft ab jetzt, dass niemand openssl wieder direkt
ruft -- der naechste merkt es dort und nicht erst in einem
Nachtlauf, den niemand liest. Drei Gegenproben.

Beim ersten Anlauf schlug sie auf ihre EIGENEN Probetexte an: Sie
liest alle Serverdateien, und dazu gehoert sie selbst. Die Texte
werden jetzt zusammengesetzt. Derselbe Selbsttreffer ist mir heute
schon zweimal passiert.

DER DRITTE AUSGANG BLEIBT, WO ER HINGEHOERT

`helfer-kachel-echtfarbe.mjs` faengt den Fehler weiterhin ab und
meldet `moeglich: false` mit Grund, statt abzubrechen. Eine
Sicherung abzuschaffen, weil ihr Anlass gerade behoben ist, ist der
Anfang des naechsten stillen Fehlschlags.

NEBENBEI: pruef-community-sicht

Sie war rot mit "ZU VIEL: reaktion.html" -- mein eigener Rueckstand
vom 28.09. Die Reaction steht als Kachel im Community-Bereich; die
Liste war nicht nachgezogen. Jetzt 10 / 0.

Die Liste bleibt bewusst von Hand gepflegt: Sie ist eine ABSICHT,
keine Ableitung. Aus rechte.js gelesen verglichen sich zwei Kopien
derselben Quelle -- immer gruen, nie ein Beweis.

GEPRUEFT
  pruef-struktur         ALLES IN ORDNUNG (mit der neuen Wache)
  pruef-community-sicht  10 / 0
  pruef-chat-neu-stelle  63 / 0  (mit dem PATH des Nachtlaufs)
  pruef-notizen, -teamlage-karten, -werdegang: EXIT 0, keine Abstuerze
  mess-quer              EXIT 0
  29 Dateien: node --check auf allen, kein direkter Aufruf mehr
2026-09-29 16:14:13 +02:00
DogFatherGit b846693de5 Die letzten fuenf blinden Messungen bekommen einen Finger
Die Grundlinie der Fingerwache sinkt von 6 auf 1.

DIE SCHWEREN FAELLE

pruef-notizen, pruef-teamlage-karten, pruef-terminregel,
pruef-werdegang, pruef-befinden.

Bei diesen fuenf stand mitten im Ablauf ein
`setViewportSize({ width: 390 })`. Das aendert nur die Groesse --
`hasTouch` gehoert zum KONTEXT und ist beim Anlegen entschieden.
Nachtragen geht nicht; es braucht ein zweites Fenster.

DAS MUSTER, DAS FUER ALLE FUENF GETRAGEN HAT

  const handyKontext = await browser.newContext({
    viewport: { width: 390, height: 844 }, hasTouch: true, isMobile: true });
  await handyKontext.addCookies(await kontext.cookies());
  const handy = await handyKontext.newPage();
  await handy.goto(seite.url(), { waitUntil: "networkidle" });

Drei Entscheidungen darin:

  - Die Anmeldung wandert als Keks mit, statt sie zu wiederholen.
    Eine zweite Anmeldung waere eine zweite Stelle, die veralten
    kann.
  - Die Adresse kommt von `seite.url()`. Sie ein zweites Mal
    hinzuschreiben waere eine zweite Wahrheit darueber, welche
    Seite gemessen wird.
  - Das fruehere Zuruecksetzen auf 1280 px faellt weg. Die breite
    Seite war nie schmal -- es gibt nichts zurueckzustellen.

Bei pruef-terminregel liessen sich die vier Schritte, die den
schwebenden Hinweis erzeugen, nicht uebernehmen: Sie werden im
neuen Kontext nachgefahren (oeffnen, "Neu", Datum eintragen).

ALLE FUENF DANACH GRUEN

  pruef-notizen         EXIT 0
  pruef-teamlage-karten EXIT 0  (39 geprueft)
  pruef-terminregel     EXIT 0  (35 Pruefungen)
  pruef-werdegang       EXIT 0
  pruef-befinden        EXIT 0

Diese Seiten halten die Fingerregeln also schon ein. Es hatte nur
nie jemand nachgesehen.

EINES BLEIBT: pruef-grosscheck

Die Datei zu aendern waere ein Zweizeiler. Sie zu PRUEFEN hiesse,
206 Seiten ueber vier Rollen und zwei Bildschirmgroessen laufen zu
lassen -- das braucht Filipes Zusage. Eine Aenderung, die ich nicht
pruefen darf, liefere ich nicht aus. Die Grundlinie steht deshalb
auf 1 und nicht auf 0.

GEPRUEFT
  pruef-fingermass  3 / 0, neun Gegenproben, Grundlinie 1
2026-09-29 16:00:57 +02:00
DogFatherGit d5e873d597 Zehn Messungen bekommen einen Finger -- und eine Zeitbombe faellt auf
Die Grundlinie der Fingerwache sinkt von 17 auf 6.

WAS UMGESTELLT WURDE

pruef-alter, pruef-countdown, pruef-gespraech, pruef-treffchat,
pruef-modi-verborgen, pruef-nachwuchs, pruef-personen-liste,
pruef-serien, pruef-team, pruef-kalender.

Alle zehn legen ein eigenes Handyfenster an; dort fehlte nur
`hasTouch`. Ohne ihn meldet der Browser einen feinen Zeiger, und
keine Regel aus `@media (pointer: coarse)` greift -- dort stehen die
44-Pixel-Beruehrziele.

JEDE EINZELN GELAUFEN, ALLE GRUEN

Diese Seiten halten die Fingerregeln also schon ein. Es hatte nur
nie jemand nachgesehen.

Vorher geprueft, wie gross jede ist: 1 bis 7 Seitenaufrufe, 1 bis 5
Fenster -- echte Einzelpruefungen. (Zum Vergleich: die Pruefung von
gestern Nacht hatte 244 Seitenaufrufe, und genau das hatte ich
vorher nicht nachgesehen.)

DIE ZEITBOMBE IN pruef-kalender

Beim Umstellen fiel sie rot aus -- zweimal, an einer Stelle, die mit
dem Finger nichts zu tun hat:

  FEHL im naechsten Monat ist kein Tag mehr "heute"

Gegen den ausgelieferten Stand gemessen: identisch rot. Nicht
meine Aenderung, sondern der Kalender.

Heute ist der 29. September. Das Oktober-Raster zeigt in seiner
ersten Zeile die letzten Septembertage mit, und einer davon IST
heute. Die Anwendung macht dabei alles richtig: `kalender.js` setzt
die Marke an `tag === daten.heute`, also am DATUM und nicht an der
Rasterposition. Genau das sollte die Pruefung beweisen -- und schlug
an, weil die Anwendung es tat.

Geschrieben wurde sie an einem Tag in der Monatsmitte. Von da an war
sie richtig, bis der Kalender sie einholte. Dasselbe Muster wie
`gate-oeffnung.mjs` am 06.09.2026 im Shop: Ein Test, der die
Wanduhr als Annahme benutzt, misst irgendwann das Gegenteil.

Gefragt wird jetzt, was gemeint war: Ein EIGENER Tag des
Folgemonats darf nie „heute" sein; ein mitgezeigter Randtag
(`data-fremd="ja"`) dagegen sehr wohl, und zwar genau dann, wenn er
es ist. Das gilt an jedem Tag des Jahres. Die Meldung nennt jetzt
beide Zahlen:

  ok  im naechsten Monat ist kein EIGENER Tag mehr "heute"
      (0 eigene, 1 mitgezeigte Randtage)

WAS UEBRIG BLEIBT: SECHS SCHWERE FAELLE

pruef-befinden, pruef-notizen, pruef-teamlage-karten,
pruef-terminregel, pruef-werdegang, pruef-grosscheck.

Dort schaltet `setViewportSize` mitten im Ablauf auf Handyformat um
-- und der Finger laesst sich nachtraeglich nicht setzen, er gehoert
zum Kontext. Jeder Fall braucht einen eigenen Kontext samt
Anmeldung: Umbau, nicht Einzeiler.

`pruef-grosscheck` bleibt unangetastet, bis Filipe einen Lauf
freigibt. Eine Aenderung, die ich nicht pruefen darf, liefere ich
nicht aus.

GEPRUEFT
  alle zehn einzeln: EXIT 0, keine FEHL-Zeile
  pruef-kalender     EXIT 0 (vorher 2 Fehlschlaege, auch auf HEAD)
  pruef-fingermass   3 / 0, Grundlinie 6
2026-09-29 14:51:52 +02:00
DogFatherGit 59b2a6d0e5 Was nur fuer Vorleseprogramme dasteht, ist kein zerquetschter Text
DER BEFUND WAR EIN FEHLALARM

pruef-handy-teamdogi meldete auf notizen.html, nur bei 412 px:

  Text auf fast nichts gedrueckt -- a.zurueck „Team Dogi…" 0 statt 82px

Nachgemessen ist das Absicht. start.css setzt auf schmalen Schirmen
`.kopfleiste .marke__text` auf 1x1 Pixel mit `clip-path: inset(50%)`
-- das uebliche Muster fuer "bleibt fuer Vorleseprogramme,
verschwindet fuer das Auge". Der Grund steht daneben: Der Text
steht auf jeder Seite zwei Zeilen tiefer noch einmal als
Ueberschrift.

WARUM DIE ERKENNUNG DANEBENGRIFF

`nurVorlesen()` gab es laengst -- sie sah aber nur das Element
SELBST an. Der Link darin ist 0 Pixel breit, aber eine Zeile hoch,
und traegt selbst kein `clip-path`. Er fiel damit durch beide
Bedingungen. Die Funktion steigt jetzt die Kette der Vorfahren hoch.

DAS MACHT DIE REGEL SCHAERFER, NICHT LAXER

Ausgenommen wird nur, was in einem nachweislich abgeklemmten Kasten
sitzt. Der echte Fund vom 20.09.2026 -- ein Gespraechsname, der in
einer normalen Kopfzeile auf null gequetscht wurde -- hat keinen
solchen Vorfahren und wird weiter gemeldet.

Und das ist nicht behauptet, sondern gemessen: Die Gegenprobe
bekommt ein PAAR statt eines Falls. Derselbe zerquetschte Text
einmal in einem abgeklemmten Kasten (darf nicht gemeldet werden)
und einmal ohne (muss gemeldet werden). Eine Regel, die enger
misst, kann zu eng sein; dann faellt echter Schaden durch und der
Lauf bleibt gruen. Sechs Gegenproben statt vier.

GEMESSEN

  244 Seitenaufrufe, 123409 Elemente, 5393 Bedienelemente
  0 Befunde   (vorher: 4-5, darunter die 40-Pixel-Knoepfe)
  alle sechs Gegenproben greifen, zweimal hintereinander gleich

  span#gp-laut  „Dieser Name ist wirklich…" 0 statt 320px  -> gemeldet
  span#gp-leise                                            -> nicht

OFFEN GEBLIEBEN

Die Ueberstandsmessung derselben Datei nimmt abgeklemmte Elemente
NICHT aus -- mein Gegenprobe-Element taucht dort als 523 px auf.
Auf echten Seiten hat das keine Folgen (0 Befunde), aber es ist
dieselbe Inkonsistenz an einer zweiten Stelle. Nicht angefasst,
weil der Nachweis dafuer wieder den ganzen Lauf braucht.
2026-09-29 14:35:29 +02:00
DogFatherGit af61f77e92 Die Transportknoepfe sind am Daumen wieder 44 Pixel hoch
DER BEFUND

pruef-handy-teamdogi meldete auf iPhone UND Android, bei zwei
Rollen, denselben Mangel:

  reaktion.html: zu kleine Tippziele --
  button#v-zurueck 48x40, button#v-vor 48x40, button#v-naechstes 83x40

Die Grundregel von `.spur__knopf` steht auf `min-height: 40px`. Am
Rechner ist das richtig; am Finger sind es vier Pixel zu wenig, und
eine Ausnahme dafuer gab es nicht.

WARUM DAS ERST HEUTE AUFFAELLT

Die Transportleiste war am Handy bis gestern gar nicht erreichbar --
sie lag 162 Pixel unter dem Fensterrand, und der Koerper hat
`overflow: hidden`. Was nicht sichtbar ist, wird nicht gemessen. Die
Reparatur von gestern hat den Mangel also nicht verursacht, sondern
aufgedeckt.

Gemessen nach der Aenderung: Transportleiste 207 statt 203 Pixel,
Saal 775 = Leiste 101 + Kino 467 + Regie 336. Kein Knopf liegt ueber
einem anderen, die Leiste verdeckt kein Bedienelement der Regie.

DIE FINGERWACHE ZAEHLT JETZT FENSTER, NICHT DATEIEN

Die erste Fassung fragte: "Steht `hasTouch` irgendwo in der Datei?"
pruef-kalender allein hat sieben Fenster, davon drei schmale -- ein
einziges `hasTouch` haette alle drei freigesprochen. Genau diese
Mischung ist im Haus die Regel.

Die geschaerfte Fassung fand prompt zwei Dateien, welche die grobe
freigesprochen hatte. Beim Nachmessen:

  - pruef-chat-optik: FEHLALARM. Ihr `setViewportSize` sitzt auf
    einer Seite, deren Kontext `hasTouch: breite < 900` traegt --
    wer danach nur die Groesse aendert, behaelt den Finger. Die
    Wache zaehlt solche Stellen jetzt nur noch, wenn in der ganzen
    Datei kein einziges `hasTouch` steht. Wo ich raten muesste,
    zaehle ich nicht: Eine Wache, die im Zweifel meldet, wird
    weggeklickt.
  - pruef-handy-teamdogi: ECHTER FUND. Ihr zweiter Kontext hatte
    keinen Finger, der erste schon. Repariert.

Grundlinie damit von 23 auf 17. Neun Gegenproben statt sechs,
darunter beide neuen Faelle.

Drei Anlaeufe, drei Zahlen: grep 18, Wache je Datei 16, Wache je
Fenster 17 (nach Abzug des Fehlalarms). Die erste Zahl, die eine
Wache liefert, ist selten die richtige.

NOCH OFFEN AUS DEMSELBEN LAUF

notizen.html, nur auf 412 px: `a.zurueck` „Team Dogi…" ist 0 Pixel
breit statt 82. Noch nicht angesehen.

GEPRUEFT
  pruef-reaktion, -tippziele, -css-klassen: alle EXIT 0
  pruef-fingermass    3 / 0
  mess-reaktion       EXIT 0, kein ACHTUNG, kein offener Punkt
2026-09-29 14:23:57 +02:00
DogFatherGit 315eb08cc4 Eine Wache dafuer, dass am Telefon mit dem Finger gemessen wird
DER FUND VON HEUTE WAR GROESSER ALS DIE EINE FUSSZEILE

`page.setViewportSize({ width: 412 })` aendert nur die Groesse.
`hasTouch` gehoert zum KONTEXT und laesst sich danach nicht mehr
setzen -- ohne ihn meldet der Browser `pointer: fine`, und KEINE
einzige Regel aus `@media (pointer: coarse)` greift. Dort stehen im
ganzen Haus die 44-Pixel-Beruehrziele.

Eine Messung mit Mauszeiger auf 412 Pixeln vermisst also eine Seite,
die es auf keinem Telefon gibt -- und meldet dabei "in Ordnung".
Das ist die dritte Sorte falscher Haken: nicht uebersprungen, nicht
rot, sondern gruen und wertlos.

GEZAEHLT: 30 Dateien oeffnen ein Telefonformat. 16 davon messen
darin Groessen, ohne einen Finger zu haben.

pruef-ueberlappung IST UMGESTELLT

Sie sucht Bedienelemente, die uebereinander liegen -- also genau die
Groessen, die erst unter `pointer: coarse` entstehen. Sie hat bis
heute mit dem Zeiger gemessen. Mit Finger: 20 Seiten-Breiten-Paare,
0 Befunde. Das ist zum ersten Mal wirklich geprueft und nicht nur
behauptet. Oberhalb von 860 px bleibt es beim Zeiger; ein Laptop
hat keinen Finger.

DIE UEBRIGEN 16 WERDEN NICHT HEUTE NACHT UMGESTELLT

Sechzehn Pruefungen anzufassen und jede einzeln neu laufen zu lassen
waere ein Gesamtlauf durch die Hintertuer -- und genau die Ausrede,
die in CLAUDE.md steht. Stattdessen haelt `pruef-fingermass.mjs`
eine Grundlinie: Sie meldet nicht 16 Fehler auf einmal (eine
Warnung, die immer kommt, wird weggeklickt und nimmt den echten Fund
mit), sondern schlaegt an, sobald eine SIEBZEHNTE dazukommt.

Sie schlaegt auch an, wenn die Zahl SINKT. Wer eine Messung
repariert und die Grundlinie stehen laesst, deckt Platz fuer die
naechste Suende. Das kostet eine Zeile und haelt die Wache scharf.

DIE ERSTE ZAHL EINER WACHE IST SELTEN DIE RICHTIGE

Mein grep hatte 18 gezaehlt. Zwei davon waren Zahlen in Kommentaren
("gemessen bei 412 px"), keine Fenster. Die Pruefung liest deshalb
nur die Stelle, die ein Fenster AUFMACHT, und blendet Kommentare
vorher aus.

DREI AUSGAENGE, SECHS GEGENPROBEN

Findet sie weniger als 50 Pruefdateien, ist das kein "alles in
Ordnung", sondern "konnte nicht nachsehen" (Rueckgabewert 2). Die
Gegenproben decken beide Richtungen ab, darunter der Fall
`setViewportSize` -- der kann `hasTouch` gar nicht nachtragen und
zaehlt deshalb immer.

`tools/alles-pruefen.mjs` liest den Ordner, keine gepflegte Liste --
die neue Wache laeuft ohne Zutun mit.

GEPRUEFT
  pruef-fingermass    3 / 0   (neu)
  pruef-ueberlappung  EXIT 0 -- 20 Paare, 0 Befunde, jetzt mit Finger
  pruef-portnummern   15 / 0
2026-09-29 14:04:06 +02:00
DogFatherGit 3dd4cef42d Die Handgriffe unter jeder Nachricht: drei Zeilen werden zwei
EINE RECHNUNG, DIE NIE GEMESSEN WURDE

In chat.css stand seit dem 25.09.2026 neben den 44-Pixel-Knoepfen
der Fusszeile:

  "Fuenf mal 44 plus vier Abstaende sind 236 px -- eine Blase hat
   auf 412 px innen 251 px. Die Reihe bleibt damit einzeilig."

Sie vergisst die Uhrzeit. Die ist 57 Pixel breit und steht in
derselben Reihe; 236 + 57 sind 293.

Auffallen konnte das nicht, weil die Regel nie lief: Alle
Handy-Messungen des Hauses liefen bis gestern mit einem MAUSZEIGER.
`setViewportSize` macht aus einem Browser kein Telefon -- `hasTouch`
gehoert zum Kontext und laesst sich danach nicht mehr setzen. Ohne
ihn meldet der Browser `pointer: fine`, und KEINE einzige Regel aus
`@media (pointer: coarse)` greift. Dort stehen im ganzen Haus die
44-Pixel-Beruehrziele. Die Rechnung wurde also gedacht und nie
gesehen.

Mit Finger gemessen, 412 px: 234 Pixel Platz fuer 277 Pixel Inhalt.
DREI Zeilen, 96 Pixel hoch -- unter jeder einzelnen Nachricht.

DIE UHRZEIT BEKOMMT IHRE EIGENE ZEILE

Sie ist das einzige Stueck der Reihe, das kein Beruehrziel ist.
Damit behalten die fuenf Knoepfe ihre 44 Pixel nebeneinander:
5 x 44 + 4 x 2 = 228 und passen in 234.

Gemessen jetzt: zwei Zeilen, 74 Pixel. Die Knopfzeile braucht 224
von 234.

EIN VERSUCH, DER ES NICHT WURDE

Zuerst hatte ich die Blase am Fingergeraet von `min(66%, 62ch)` auf
82 Prozent verbreitert -- daneben steht ja die Absicht, sie solle
"auf dem Handy trotzdem die Breite ausnutzen". Die Messung kam
SCHLECHTER zurueck (188 statt 234 Pixel Platz), und das lag an der
Messung selbst: Sie las "die erste Fusszeile". Wie breit die ist,
haengt vom Text darueber ab. Dieselbe Aenderung sah dadurch mal
besser und mal schlechter aus, ohne dass sich etwas geaendert hatte.

Der eigentliche Grund, warum 82 Prozent nicht helfen: `max-width`
ist eine Obergrenze, keine Breite. Eine kurze Nachricht hat eine
schmale Blase, und die Fusszeile bricht darin genauso um. Bei
allen vier gemessenen Nachrichten brach sie.

MESSUNG GESCHAERFT

  - Sie fragt jetzt, WIE VIELE Fusszeilen umbrechen, nicht wie die
    erste aussieht.
  - "Inhalt" ist die breiteste ZEILE, nicht die Summe aller Kinder.
    Seit die Uhrzeit absichtlich umbricht, waere die Summe die
    Breite zweier Zeilen uebereinander -- sie meldete 444 Pixel in
    einer 234 Pixel breiten Fusszeile und sah wie ein Ueberlauf aus.
  - `mess-notizblock` misst am Handy jetzt ebenfalls mit Finger
    (eigener Kontext, `hasTouch`). Vorher zeigten seine
    Handy-Bilder eine Seite, die auf keinem Handy so aussieht.

DIE KLAMMERWACHE HAT WIEDER EINEN ECHTEN FUND GEMACHT

Beim Zuruecknehmen des 82-Prozent-Versuchs blieb das schliessende
`}` der Medienabfrage stehen. Zweiter echter Fund in zwei Tagen,
beide Male an meinem eigenen Werkzeug.

GEPRUEFT
  pruef-chatkachel, -css-klassen, -tippziele, -handy: alle EXIT 0
  mess-chat-optik   EXIT 0 -- 2 Zeilen, 74 px (vorher 3 / 96)
  mess-notizblock   EXIT 0
2026-09-29 13:59:20 +02:00
DogFatherGit 7351820c55 Der Waechter gegen Namensstreit gilt jetzt fuer das ganze Haus
Er wurde gestern fuer `reaktion.css` gebaut, nachdem `.stufen` dort
zweimal stand und die Stufenleiter der Spenden dadurch das Aussehen
der Chat-Leiste bekam -- drei Stufen nebeneinander, 572 Pixel in
einer 327 Pixel schmalen Spalte, mit der waagerechten Rollleiste auf
Filipes Bildschirmfoto.

Eine Wache, die nur eine Datei ansieht, findet genau die Fehler
dieser einen Datei. Auf alle 36 Stilvorlagen angewandt fand sie
GENAU EINE weitere Stelle.

DER FUND: `.wahl2__eintrag` in gate.css

    Zeile 1584  display: block   (mit text-overflow: ellipsis)
    Zeile 2634  display: flex    (fuer Personenbilder, 08.09.2026)

Kein Streit zweier Bauteile, sondern eine spaetere Erweiterung --
und trotzdem ein echter Fehler: `text-overflow: ellipsis` wirkt bei
`display: flex` NICHT auf ein anonymes Flex-Kind. Der Knopf
„… eintragen" in jeder Auswahl des Hauses hat langen Text seither
HART abgeschnitten statt mit „…" gekuerzt.

GEMESSEN -- und nur im Bild zu sehen: `scrollWidth` ist in beiden
Faellen gleich (364 px bei 200 px Breite). Die Zahlen sagten
„kein Unterschied", das Bildschirmfoto zeigte einen. Ein Beleg mehr
dafuer, dass zwei gleiche Zahlen nicht dasselbe Ergebnis bedeuten.

REPARIERT
  - Der eigene Eintrag bekommt einen `.wahl2__name`-Span, wie jeder
    andere Eintrag auch. Damit kuerzt er wieder mit „…".
  - Die zwei Grundregeln sind eine. Wer die erste las, glaubte an
    `display: block` -- 1050 Zeilen weiter stand das Gegenteil.

DIE WACHE
  923 Grundregeln in 36 Stilvorlagen, keine Klasse zweimal
  verschieden gebaut. Gezaehlt wird nur, was sich widersprechen
  kann: nicht dieselbe Klasse in einem Zusammenhang (`.saal .pult`),
  nicht eine Variante in einer Medienabfrage, nicht
  „erst versteckt, dann gezeigt". Sechs Gegenproben, darunter der
  echte Fall vom 28.09. und eine Klasse im Kommentar.

GEPRUEFT: css-klassen, freie-namen, suchfeld, tippziele alle EXIT 0.
2026-09-29 13:45:02 +02:00
DogFatherGit 0c696f286d Der Kopf der Regie bleibt stehen, waehrend ihr Inhalt rollt
Drei kleine Dinge an der Schublade von vorhin, und eine ehrliche
Notiz zu dem, was nicht ging.

  - `overflow-y: auto` statt `overflow: hidden`. Reicht der Platz
    nicht, rollt die Schublade senkrecht -- statt ihren Inhalt
    unter der Transportleiste verschwinden zu lassen. Senkrechtes
    Rollen war nie das Problem; Filipes Ansage vom 28.09. galt dem
    Wischen nach links und rechts.

  - `flex: none` am Kopf. Ohne das ist er ein Flex-Kind mit
    `shrink: 1` -- was nichts hilft, weil sein `min-height: auto`
    ihn nicht unter die Hoehe seines Inhalts laesst. Er ragte dann
    einfach hinaus.

  - Der Kopf klebt beim Rollen (`position: sticky`). Sonst scrollt
    man „Auf Sendung" weg -- den Knopf, um den es geht.

AUF 320 PIXELN BLEIBT ES BEIM BEKANNTEN MANGEL

Dort bleiben zwischen Registern und Transportleiste rund 190 Pixel,
und der Kopf der Regie allein braucht 210. Sechs Versuche haben nur
bestimmt, WER verdeckt wird: „Vorbereiten" unter der Leiste, die
Schublade ueber „Gaeste" und „Bild", oder beim rollenden Container
22 Pixel Ueberlappung. Keiner hat es geloest.

Das steht jetzt mit Zahlen und Versuchen im Stilblatt -- samt dem
Hinweis, dass es ein eigenes Nachdenken braucht (die Regie wird dort
ein eigener Bildschirm statt einer Schublade) und nicht den siebten
Versuch mit derselben Werkzeugkiste.

NEBENBEI: Die Klammerwache hat ihren zweiten Fund in zwei Tagen
gemacht -- beim Umbauen blieb erneut eine schliessende Klammer ohne
ihren Anfang stehen. `pruef-handy` und `mess-reaktion` waren dabei
gruen; ohne die Wache waere es unbemerkt mitgegangen.

GEPRUEFT: css-klassen, handy, tippziele, reaktion alle EXIT 0;
mess-reaktion EXIT 0 (133 px sichtbares Bild, kein Knopf ueber
einem anderen), mess-quer EXIT 0.
2026-09-29 13:41:04 +02:00
DogFatherGit a6b37909ca Die Transportleiste steht am Handy in einer Reihe
Auf dem Bildschirmfoto nach dem Umbau lagen der runde Play-Knopf und
seine Nachbarn uebereinander. `pruef-handy` meldete das nicht: Sie
fragt, ob die MITTE eines Knopfes frei ist -- zwei Knoepfe koennen
sich an den Raendern ueberlagern und beide „erreichbar" sein. Wer
danebentippt, trifft trotzdem den falschen.

GEMESSEN (neue Stelle in mess-reaktion, die jedes Knopfpaar der
Leiste auf Ueberschneidung prueft):

    tempo-auf / v-spiel   21 x 44 px
    v-spiel / v-tauschen  21 x 38 px

URSACHE: `grid-template-columns: auto 1fr auto`. Tempo links und
„Wechseln zu <Videotitel>" rechts nahmen so viel, dass die mittlere
Spalte schmaler wurde als der 58 Pixel breite Play-Knopf -- und ein
zentrierter Inhalt, der breiter ist als seine Spalte, ragt ueber
BEIDE Raender.

Jetzt `minmax(0, auto) max-content minmax(0, auto)`: Die Mitte ist
so breit wie ihre drei Knoepfe zusammen und schrumpft nie, die
Seiten geben nach. `min-content` war dabei die falsche Zwischenstufe
-- damit war die Spalte so breit wie ihr BREITESTER Knopf, und
„−10" und „+10" brachen darunter um.

GEPRUEFT: pruef-handy, -tippziele, -css-klassen, -reaktion und
mess-quer alle EXIT 0; mess-reaktion meldet „Kein Knopf der
Transportleiste liegt ueber einem anderen" und 133 Pixel sichtbares
Bild.
2026-09-29 13:18:42 +02:00
DogFatherGit e272dd4673 Am Handy ist die Transportleiste wieder erreichbar
Der offene Punkt von gestern Nacht, jetzt geloest -- und dabei stellte
sich heraus, dass er schlimmer war als gemeldet.

WAS WIRKLICH LOS WAR

Gemeldet war: "Am Handy bleibt bei offener Regie vom Bild nichts."
Gemessen auf 390x844 ergab sich mehr:

    Saal 69..844 (775 px)
    Zeilen  101 + 0 + 511 + 325 = 937
    transport 681..1006  -- 162 Pixel UNTER dem Fensterrand

Der Koerper hat `overflow: hidden`; die Leiste war also nicht
abgeschnitten, sondern weg. Play, "Naechstes" und die Sprungknoepfe:
bei offener Regie nicht erreichbar. Das Bild hatte dabei null Pixel.

DIE RECHNUNG, DIE ES ERKLAERT

    Regieleiste   101  (zwei Zeilen Register)
    Regie-Kopf    207  (fuenf Zeilen zu je rund 44 px -- der
                        Klapp-Knopf stand allein in einer)
    Regie-Inhalt  305
    Transport     325  (Schiene 48 + drei Gruppen untereinander)
                 ----
                  938  von 775.

Video, Regie und Transport passen auf einem Handy nicht nebeneinander.
Das ist keine Frage der Gestaltung, sondern des Platzes.

VIER SCHNITTE UND EINE ENTSCHEIDUNG

  1. Die Tempo-Gruppe klappt hinter ihren eigenen Wert -- dasselbe
     Muster wie "Aa" im Chat, das dort 73 Pixel gespart hat. Der
     Knopf zeigt "1x" oder "1,5x", man muss zum Nachsehen also nicht
     aufklappen. Am Rechner gibt es ihn nicht.
  2. Der Klapp-Knopf rutscht neben die Lampe statt in eine eigene
     Zeile.
  3. Die drei Gruppen der Transportreihe stehen nebeneinander (158
     statt 240 Pixel) -- moeglich, seit die Tempo-Gruppe klappt.
  4. Die Messwerte stehen in einer Zeile, die grossen Knoepfe
     bekommen weniger Polsterung.

Das reichte nicht. Also die Entscheidung: AM HANDY LEGT SICH DIE
REGIE UEBER DAS BILD, statt ihm Platz wegzunehmen -- als Rasterfeld
ueber die Zeilen 2 und 3, unten angedockt, hoechstens 72 Prozent
hoch. Oben bleibt ein Streifen Bild stehen (gemessen 135 px): Wer
mitten in der Sendung etwas einstellt, muss sehen, worueber er redet.

Gemessen jetzt: Saal 775 = Leiste 101 + Bild 481 + Regie 346, und
der Transport steht bei 601..844 -- erreichbar.

DREI VERSUCHE, DIE ES NICHT WURDEN (und warum)

  - `position: absolute` mit gemessener Transporthoehe: lief, lag
    aber 17 Pixel ueber den Registern. Der Bezugsrahmen eines
    absolut gesetzten RASTERFELDES ist sein Rasterbereich, nicht der
    Container -- mit `grid-row: 3` (0 Pixel hoch) wurde aus
    `max-height: 100%` eine Hoehe von einem Pixel.
  - `top` UND `bottom` UND `height: fit-content`: Der Browser
    verwirft dann das `bottom`; die Regie ragte 101 Pixel in die
    Leiste.
  - `grid-row: 2 / 4` mit `align-self: end` statt absolut: ragte 146
    Pixel nach oben und schob die Seite 198 Pixel breiter.

AUF 320 PIXELN BLEIBT ES BEIM ALTEN

Dort passen Register (104), Regie-Kopf (210) und Transportleiste
(158) zusammen nicht in die 499 Pixel Saal -- es fehlten 17. Fuenf
Verteilungen haben nur bestimmt, WER verdeckt wird: erst
"Vorbereiten" und "Beenden" unter der Leiste, dann die Schublade
ueber "Gaeste" und "Bild". Die Schublade greift deshalb erst ab 360
Pixeln; darunter bleibt der Stand von vorher -- ein bekannter Mangel,
aber kein neuer. Der Grund steht im Stilblatt.

NEBENBEI GEFUNDEN

  - `.muenzsatz` brach nicht um und ragte auf 320 px 8 Pixel hinaus
    -- die Tafel rollte dort wieder waagerecht.

WACHEN GESCHAERFT

  - Die Klammerwache von gestern hat heute ihren ersten echten Fund
    gemacht: Beim Herausschneiden einer Regel blieb eine `}` stehen.
    Ohne sie waere das als drei Befunde in `mess-reaktion`
    aufgetaucht, die wie Programmfehler ausgesehen haetten.
  - Der Namensstreit-Waechter meldete `pult (grid vs. flex)` und
    `messwerte__paar (grid vs. flex)` -- beides Fehlalarm: Eine
    Regel in einem Zusammenhang (`.saal .pult`) und eine in einer
    Medienabfrage sind Varianten, kein Streit. Er nimmt beides jetzt
    aus. Dabei fiel auf, dass sein Muster die schliessende Klammer
    verbrauchte, die der naechste Treffer als Anfang braucht -- der
    echte Fall vom 28.09. (`.stufen` zweimal) wurde dadurch gar
    nicht gefunden. Die Gegenprobe deckt jetzt fuenf Faelle ab.
  - `mess-reaktion` mass die HOEHE der Kinozeile und haette 431
    Pixel gemeldet, waehrend das Bild vollstaendig verdeckt war.
    Sie misst jetzt, wieviel oberhalb der Schublade uebrig bleibt.

GEPRUEFT
  pruef-reaktion, -css-klassen, -tippziele, -handy, -struktur,
  -buehne: alle EXIT 0
  mess-reaktion  EXIT 0, kein ACHTUNG, kein offener Punkt
  mess-quer      EXIT 0 -- fuenf Groessen, nichts rollt seitlich
  mess-buehne    EXIT 0
2026-09-29 12:56:03 +02:00
DogFatherGit a9e0834cfb Nichts wird mehr nach links oder rechts geschoben
Filipe, 28.09.2026: "ich will auch nicht dass man sachen nach links
und rechts schieben muss. perfektion das untereinander. ich will
niemals irgendwas nach links oder rechts swippen muessen." Dazu ein
Bildschirmfoto der Tafel "Gestaltung" mit waagerechter Rollleiste.

GEMESSEN, NICHT GERATEN

Ein grep nach `overflow-x` findet nur die absichtlichen Roller. Er
findet nicht die Stelle, an der ein Inhalt breiter ist als sein
Kasten und der Browser von sich aus eine Rollleiste anhaengt -- und
genau das war auf dem Bild zu sehen. `server/mess-quer.mjs` geht
deshalb im echten Browser jedes Element durch, auf fuenf
Bildschirmgroessen, in allen sieben Registern, bei offener und
zugeklappter Regie und in allen fuenf Anordnungen.

Erster Lauf: 78 Stellen. Davon waren 54 KEINE -- `overflow-x: hidden`
ist abgeschnittener Text, dort laesst sich nichts schieben. Die
Messung trennt das jetzt; wer es mitzaehlt, findet die echten nicht
mehr. Uebrig blieben vier Ursachen:

  1. DIE REGISTER rollten absichtlich waagerecht. Auf 412 px standen
     von 605 px Registern 193 rechts ausserhalb -- dass es
     "Gestaltung" und "Spenden" gibt, erfuhr man nur beim Wischen auf
     Verdacht. Sie brechen jetzt um. Das kostet oben rund 45 Pixel
     und bringt Gewissheit dafuer.

  2. `.stufen` STAND ZWEIMAL IN reaktion.css -- einmal fuer die
     Stufenleiter der Spenden (`display: grid`), 600 Zeilen spaeter
     fuer die Chat-Leiste Offen/Team/Zu (`display: flex`). Die
     spaetere gewinnt: Die Stufenleiter stellte ihre drei Stufen
     NEBENEINANDER, 572 Pixel in einer 327 Pixel schmalen Spalte.
     Das ist die Rollleiste auf Filipes Bild. Die Chat-Leiste heisst
     jetzt `.chatstufen` / `.chatstufe`.
     Dritter Fall dieser Art nach `.tafel` und `.stufe-knopf`.

  3. DIE TAFELN KONNTEN NICHT SCHRUMPFEN. Ein Gitterfeld hat von
     sich aus `min-width: auto` und besteht auf seinem unteilbarsten
     Inhalt. Mit `minmax(0, 1fr)` und `min-width: 0` bricht jetzt
     alles um, statt hinauszulaufen.

  4. DIE TRANSPORTLEISTE ragte am Handy 76 Pixel ueber beide Kanten
     ("Naechstes" war nur halb zu sehen). Zwei Gruende: `.transport__teil`
     hatte kein `flex-wrap` (die mittlere Gruppe schon -- zwei Regeln
     fuer dieselbe Sache, eine vergessen), und im Umschalter steht
     ein ganzer Videotitel, der als Flex-Kind auf seiner vollen
     Breite bestand.

NEBENBEFUND: EINE FESTE ZAHL VON GESTERN

Der Saal stand auf `height: calc(100dvh - 69px)` -- 69 war einmal
die gemessene Hoehe der Kopfleiste. Sie ist 73 geworden, und der
Saal endete damit 4 Pixel unter dem Fensterrand: Der Play-Knopf war
nur mit Scrollen zu erreichen. Die Antwort ist keine neue Zahl,
sondern eine Regel, die misst -- der Koerper ist jetzt eine Spalte,
die Kopfleiste nimmt, was sie braucht, der Saal bekommt den Rest.
(Dabei noch ein Spezifitaetsunfall: `.reaktion-seite` (0,1,0)
verliert gegen `body.start` (0,1,1) aus start.css.)

NEUE WACHEN

  - `mess-quer.mjs` mit Gegenprobe (ohne die Reparaturen findet sie
    47 px, mit ihnen nichts).
  - pruef-reaktion: kein absichtliches `overflow-x: auto` mehr; und
    zwei Grundregeln derselben Klasse mit verschiedenem `display`
    sind ein Namensstreit. Der bisherige Waechter verglich nur
    ZWISCHEN Stilvorlagen -- `.stufen` stand zweimal in DERSELBEN.
  - pruef-css-klassen: jede Klammer hat ihr Gegenstueck. Beim
    Umschreiben blieb heute das Ende einer Regel ohne ihren Anfang
    stehen; der Browser wirft die Zeile weg und schliesst dafuer den
    naechsten @media-Block zu frueh. Drei Befunde sahen daraufhin wie
    Programmfehler aus.

MESSUNG NACHGEZOGEN

`mess-reaktion` stammte noch aus der Zeit vor "Regie links" und
"drei Kacheln" und meldete drei Dinge, die keine Fehler waren --
gemessen gegen den Stand von HEAD: identisch rot. Sie misst ausserdem
seit heute mit FINGER statt Mauszeiger; ohne `hasTouch` greift keine
einzige Regel aus `@media (pointer: coarse)`, und dort stehen alle
44-Pixel-Beruehrziele des Hauses.

OFFEN UND AUFGESCHRIEBEN

Am Handy bleibt bei offener Regie vom Bild nichts (0 px). Der Mangel
besteht seit dem Umbau "Regie links"; drei Versuche, ihn heute zu
loesen, haben Knoepfe verdeckt -- und ein verdeckter Knopf ist
schlimmer als ein kleines Bild. Die Versuche und der richtige Weg
(Tempo-Gruppe hinter einen Knopf, wie "Aa" im Chat) stehen in
reaktion.css. `mess-reaktion` meldet ihn als dritten Ausgang: nicht
als Fehler und nicht als bestanden.

GEPRUEFT
  pruef-reaktion     384 / 0   (vorher 379)
  pruef-spenden      172 / 0
  pruef-buehne        36 / 0
  pruef-css-klassen, -tippziele, -struktur, -handy: ohne Befund
  mess-quer          EXIT 0 -- 28 Stellen, fuenf Groessen, nichts rollt
  mess-reaktion      EXIT 0, 1 benannter offener Punkt
  mess-buehne        EXIT 0
2026-09-29 02:34:09 +02:00
DogFatherGitandClaude Opus 5 813d2e85a1 Die Kuerzel stehen jetzt an dem, was sie bedienen
Filipe, 28.09.2026: "das soll nicht ueberall sein sondern da perfekt
integriert werden."

Er hat recht: Die Legende war ein eigener Absatz am Ende der Regie --
hinter ALLEN Registern. Damit stand sie unter "Ton", unter "Spenden",
unter "Gestaltung", also an sechs Stellen, an denen keines ihrer
Kuerzel etwas tut. Eine Legende, die ueberall steht, gehoert nirgends
hin.

Und eine Legende ist ohnehin der Umweg: Sie zwingt dazu, vom Knopf zu
einer Liste zu schauen und zurueck. Steht die Taste AM Knopf, liest
man sie beim Bedienen -- und lernt sie dabei.

  Leertaste  unter dem runden Play-Knopf   (ein Wort passt nicht
             hinein, und der Knopf soll das Zeichen bleiben, das man
             blind trifft)
  Pfeile     an -10 und +10
  + und -    am Wort "Tempo"
  N          an "Naechstes"
  T          an "Wechseln"
  M          am Mikro-Knopf in der Senderleiste
  1 bis 5    bei der Anordnung im Register "Bild"

Nichts geht verloren, jedes steht dort, wo es wirkt.

UND DIE PRUEFUNG STELLT EINE ANDERE FRAGE ALS VORHER. Sie pruefte, ob
ein Kuerzel IRGENDWO in der Legende steht. Jetzt prueft sie, ob es am
RICHTIGEN Knopf steht -- ein Kuerzel an der falschen Stelle ist
schlimmer als keins. Dazu eine Gegenprobe, dass die alte Legende
wirklich weg ist: Stuende beides da, pflegte beim naechsten Kuerzel
jemand nur eine der beiden Stellen.

Der Chat bleibt unveraendert: Er liegt in `#teil-live` und erscheint
damit nur, wenn die Sendung laeuft -- so, wie Filipe es erwartet hat.

pruef-reaktion 379/0 - pruef-css-klassen ok - pruef-tippziele 11/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 20:51:30 +02:00
DogFatherGitandClaude Opus 5 a6d55d939a Die Regie steht links neben dem Video, nicht nur unten
Filipe, 28.09.2026: "anstatt alles nur unten zu haben wieso nicht
rechts und links noch ausnutzen um mehr ueberblick zu haben."

ICH HATTE IHN ZWEIMAL FALSCH VERSTANDEN. Beim ersten Mal baute ich
zwei Spalten INNERHALB der unteren Leiste, beim zweiten Mal Kacheln
darin. Gemeint war der BILDSCHIRM: Die Regie klebte als 272 Pixel
hoher Streifen unten, waehrend darueber das ganze Bild frei war. Man
sah entweder das Video oder die Bedienung.

AUFGEKLAPPT steht sie jetzt LINKS neben dem Video, ueber die volle
Hoehe. Rechts der Chat, unten die Senderleiste und der Transport --
die Anordnung jedes Sendepults: Was man bedient, liegt neben dem, was
man dabei ansieht.

ZUGEKLAPPT bleibt alles wie vorher, eine schmale Leiste unten. Wer
die Regie zumacht, will das Bild gross; eine leere Spalte daneben
waere das Gegenteil.

WAS DAS NEBENBEI LOEST: Die Kacheln hatten unten 272 Pixel fuer sich
-- drei Felder untereinander passten nicht hinein, und die
Transportleiste verdeckte den Rest. In einer Spalte stehen rund 700
Pixel zur Verfuegung. Die Enge war nie eine Frage der Gestaltung,
sondern des Platzes.

DER TRANSPORT VERLAESST DAS REGISTER. Er lag in "Sendung" und war
damit weg, sobald jemand auf "Ton" oder "Spenden" ging. Jetzt ist er
eine eigene Zeile unter dem Saal -- und damit auch bei zugeklappter
Regie da. Der Play-Knopf ist der eine, den man mitten in einer
Sendung blind treffen muss.

`:has(.pult[data-auf="ja"])` UND KEINE KLASSE AM KOERPER: Der Zustand
steht schon am Pult; ein zweiter Merker waere die zweite Antwort auf
dieselbe Frage. Erst ab 1100 px -- darunter bleibt fuer das Video
keine Breite: 26rem Regie plus 23rem Chat sind 784 Pixel. Gerechnet,
nicht geraten.

=======================================================================
DREI BEFUNDE GEGEN DIE EIGENEN PRUEFUNGEN -- UND EINER IST ERNST

1. "GENAU EINE REGEL DARF DIE ZEILEN DES SAALS SETZEN" war die
   Faustregel zum Befund vom Nachmittag, aber nicht die Frage, um
   die es geht. Eine zweite FASSUNG (Handy, aufgeklappte Regie) ist
   richtig und noetig -- sie setzt die Zeilen neu UND verteilt die
   Kinder neu. Der Fehler war eine zweite ANGABE, die die Zeilenzahl
   VERKLEINERT und die Kinder stehen laesst. Geprueft wird jetzt
   genau das: Jede Fassung, deren Gegenstand der Saal IST, muss
   gleich viele Zeilen haben.

2. DER ERNSTE: Dieselbe Pruefung hatte einen BLINDFLECK. Ihr Muster
   liess den Regelrumpf ueber eine oeffnende Klammer hinweg laufen
   (`[^}]*` statt `[^{}]*`) -- damit fiel jede Regel INNERHALB eines
   `@media` heraus. Gemessen: Sie meldete "alle 1 Fassungen",
   obwohl zwei dastanden. Ein Fehler im Medienblock -- und genau
   dort steht die ganze Handyansicht -- waere unbemerkt
   durchgegangen. Die Gegenprobe beweist jetzt, dass eine Fassung
   mit weniger Zeilen wirklich auffaellt.

3. Auch beim Regieplatz zaehlte sie Fassungen statt Wirkung und
   schlug an, sobald eine dritte dazukam. Jetzt prueft sie, ob eine
   Fassung eine KACHEL VERGISST -- dann verschwindet die in genau
   dieser Ansicht, und gemerkt haette es niemand.

pruef-reaktion 374/0 - pruef-css-klassen ok - pruef-tippziele 11/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 20:45:34 +02:00
DogFatherGitandClaude Opus 5 6033d1b6f2 Der Regieplatz sind jetzt Kacheln
Filipe, 28.09.2026, zum ersten Versuch: "ich wollte was hoch
professionelles wo rechts links und unten kacheln sind wo alles drin
ist, schoen verteilt. wieso so einen kleinen scheiss."

Er hat recht, und es steht auf seinem Bildschirmfoto:

  DIE LINKE SPALTE WAR LEER. "Was laeuft" zeigte nur einen Titel --
  und wenn nichts laeuft, steht dort nichts. Ein grosses schwarzes
  Loch neben einer vollen Spalte sieht nicht nach Aufteilung aus,
  sondern nach Fehler.

  ES WAREN KEINE KACHELN. Zwei Spalten mit einer Trennlinie sind eine
  Teilung, keine Gliederung. Ohne Rahmen, ohne Kopf, ohne eigenen
  Grund fehlt genau das, was eine Flaeche aufgeraeumt aussehen
  laesst.

  DIE LEISTE WAR EIN KASTEN MIT LUFT. `1fr auto 1fr` schiebt drei
  kleine Knopfgruppen an die Raender eines 1400 Pixel breiten
  Kastens. Leere zwischen Knoepfen liest sich als "hier fehlt noch
  etwas".

WAS JETZT DASTEHT

  LINKS   Eine Kachel "Was laeuft" mit VORSCHAUBILD -- damit ist sie
          immer gefuellt. Ohne Video steht der Satz darin, der sagt,
          was zu tun ist; ein leerer Kasten sagt nur, dass etwas
          fehlt. Sie geht ueber beide Zeilen der rechten Seite,
          sonst franste eine Seite unten aus.
  RECHTS  Zwei Kacheln: "Die Sendung" (Titel, YouTube, Beginn) und
          "Bereitlegen" (zweites Video, Vorschaubild, Zuruecksetzen).
  UNTEN   Die Transportleiste, dichter: jede Gruppe beschriftet
          ("Tempo", "Weiter"), und der Umschalter ist aus der linken
          Kachel hierher gewandert. Er ist ein Handgriff IM Live wie
          "Naechstes" -- und fuellt die rechte Seite, die vorher leer
          war.

Das Vorschaubild nimmt ein eigenes, wenn eines eingetragen ist, sonst
YouTubes. Laedt keines, tritt der Platzhaltersatz ein: Ein Bild, das
404 antwortet, steht genauso im Dokument wie eines, das laedt -- auf
dem Bildschirm ist an seiner Stelle nichts.

UND EIN FUND DER HAUSPRUEFUNG: `kachel` gibt es bereits in start.css
und module.css. Ein Namensstreit ueber Stilblaetter hinweg ist genau
die Sorte Fehler, die spaeter irgendwo ganz anders etwas verschiebt
-- und den niemand dort suchen wuerde. Heisst jetzt `regiekachel`.

pruef-reaktion 369/0 - pruef-css-klassen ok - pruef-tippziele 11/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 20:12:21 +02:00
DogFatherGitandClaude Opus 5 99e62eebbe Regieplatz, Bildschirm teilen, Zuruecksetzen und der Preis
Vier Sachen aus Filipes Ansagen vom 28.09.2026.

=======================================================================
1. DER REGIEPLATZ

"kann das nicht bissl aufgeteilt sein auf links und rechts und eine
barre unten in der mitte. kannst du das nicht hoch professionell
machen und hochwertig vom aussehen?"

Die Teilung folgt dem, was WANN gebraucht wird:
  LINKS   Was laeuft. Das liest man.
  RECHTS  Was eingetragen wird. Das tippt man VOR der Sendung.
  UNTEN   Der Transport. Den fasst man WAEHREND der Sendung an.

Vorher stand alles in einem Stapel, und wer im Live an den Play-Knopf
wollte, musste an den Eingabefeldern vorbeiscrollen. Der Play-Knopf
ist jetzt rund und 58 px -- der einzige, den man blind treffen muss,
und die Form unterscheidet ihn schon vor dem Hinsehen.

UND EIN FUND, DEN NUR DIE MESSUNG FAND: Nach dem Umbau lag die Leiste
bei y=986 in einem 900 Pixel hohen Fenster. Die Rechnung ging auf
(links, rechts, Leiste darunter) und das Ergebnis war trotzdem
falsch. Jetzt klebt sie (`position: sticky`) -- unten, wie gewollt,
und immer sichtbar. Ihr Grund musste dafuer dicht werden: eine
halbdurchsichtige Leiste, durch die Text scrollt, ist die Flaeche,
auf der man sich im Live verliest.

=======================================================================
2. DEN BILDSCHIRM TEILEN

"waere es nicht einfach eine bildschirm uebertragung zu installieren
und es zu perfektionieren?"

Ja -- der Weg war schon da: Die Kamerabilder laufen als
Direktverbindung von Mensch zu Mensch. Geteilt wird deshalb AN STELLE
der Kamera; `replaceTrack` tauscht die Bildspur in jeder bestehenden
Leitung aus, ohne dass eine einzige neu ausgehandelt werden muss.
Eine zweite Spur daneben waere eine zweite Verhandlung je Zuschauer,
und jede davon kann scheitern.

Vier Dinge, die sonst schiefgegangen waeren:
  - Wer waehrenddessen dazukommt, bekommt den Bildschirm und nicht
    das Gesicht.
  - Das eigene Fenster zeigt, was die anderen sehen -- sonst waere es
    die eine Anzeige, der man nicht trauen kann.
  - Der Stopp-Knopf des Browsers wird gehoert; sonst bliebe die Seite
    auf "teilt" stehen und sendete ein totes Bild.
  - Der Kameraknopf wird grau, solange geteilt wird. Er haette keine
    Wirkung mehr -- und ein Knopf, der still nichts tut, ist
    schlimmer als keiner.

Ein Bildschirm wird ausserdem NICHT zugeschnitten: `cover` ist fuer
ein Gesicht richtig, bei einem Schreibtisch faellt links und rechts
genau das weg, worum es geht.

UND DIE WAHRHEIT STEHT AN DER BEDIENUNG: Netflix, Disney+ und Prime
bleiben beim Teilen schwarz (Widevine schaltet den Videobereich ab --
auf Discord und Zoom ist es genauso), und einen Film weiterzusenden
waere eine oeffentliche Wiedergabe. Wer das erst erfaehrt, nachdem im
Stream zehn Minuten ein schwarzes Rechteck stand, erfaehrt es zu
spaet.

=======================================================================
3. ALLES ZURUECKSETZEN

"brauch ich auch noch einen button wo ich alles easy zuruecksetzen
kann."

"Alles" heisst: der Schreibtisch, nicht das Gedaechtnis. Geleert
werden Titel, Video, zweites Video, Vorschaubild, Beginn,
Warteschlange, Gaesteliste; Anordnung, Kameragroesse, Ecke, Tempo und
Chatmodus gehen auf Vorgabe.

NICHT ANGETASTET werden Spenden, die Dogen der Leute, der Chatverlauf
und die Massnahmen der Moderation. Eine bezahlte Spende aus den
Buechern zu nehmen waere eine Faelschung; eine stillschweigend
aufgehobene Sperre waere eine Entscheidung, die niemand getroffen
hat. Beides steht nebeneinander im Dialog, BEVOR etwas passiert -- ein
"Bist du sicher?" ohne diese Liste ist keine Frage, sondern eine
Huerde.

Im Live ist der Knopf grau und sagt warum. Und die Spalten stehen
einzeln da statt als "alles ausser": Eine Ausnahmeliste waechst still
mit jeder neuen Spalte mit, und dann loescht das Zuruecksetzen
irgendwann etwas, das es nie loeschen sollte.

=======================================================================
4. DER PREIS BEI DEN DOGEN

"da muss ich auch sehen so viel dogen sind so viel euro. damit ich
auch immer weiss was es ist. aber nur ich. die leute sollen nur sehen
was dogen kosten."

Das ist keine Ruecknahme von "nie Geld", sondern ihre Grenze. Die
Regel war richtig fuer alles, was ANZEIGE ist -- Karte, Stream, Chat,
Punktestand -- und falsch fuer die eine Stelle, an der jemand KAUFT.

GENAU ZWEI AUSNAHMEN, und die Pruefung nennt sie beim Namen statt die
Regel aufzuweichen:
  knoepfe[].cent      fuer alle -- der Preis am Kaufknopf
  kurs_cent_je_doge   nur fuer die Leitung

DIE ERLAUBNIS STECKT IN DEN DATEN UND NICHT IN EINEM `if`. Ein
Zuschauer hat den Kurs nicht und kann deshalb GAR KEINEN Preis
ausrechnen -- auch nicht, wenn eine spaetere Zeile es versuchte. Eine
Abfrage "darf der das sehen?" in der Oberflaeche waere eine Regel, die
man vergessen kann; eine fehlende Zahl ist eine, die man nicht
vergessen kann.

Eine Zahl statt dreissig Einzelumrechnungen: Wer je Zeile einen Cent
mitschickt, hat dreissig Gelegenheiten, eine zu vergessen.

=======================================================================
FUENF BEFUNDE GEGEN DIE EIGENEN PRUEFUNGEN

1. Eine Pruefung fragte "liegt die Leiste unter beiden Spalten?" --
   das tut eine klebende Leiste beim Hochscrollen absichtlich nicht.
   Sie stellte die Frage von vorher. Jetzt zaehlt die Reihenfolge im
   Dokument, die beim Scrollen wie beim Stillstand gilt.
2. Eine Messung klickte auf einen Namen und wartete 400 ms auf die
   UHR -- und verschluckte den Klickfehler still. Derselbe Lauf war
   dreimal gruen und beim vierten rot, ohne Codeaenderung. Jetzt wird
   auf das Merkmal gewartet, bis zu dreimal, und die Zahl der
   Anlaeufe steht im Protokoll.
3. Eine Pruefung loeschte erst selbst den Chat (eine Sendung zu
   beenden tut das mit Absicht) und fragte dann, ob er noch da ist.
4. "Die Dogen sind unberuehrt (0 Staende)" -- null bleibt auch dann
   null, wenn das Zuruecksetzen sie mitnaehme. Jetzt steht vorher
   eine echte Spende da, und die Zahl gehoert in die BEDINGUNG.
5. `knopf-still--haupt` stand seit Wochen im HTML und war in KEINEM
   Stilblatt definiert -- eine Klasse, die aussieht, als sei etwas
   hervorgehoben, und auf dem Bildschirm ist es das nicht. Gefunden
   beim Nachsehen, ob es sie gibt, bevor ich sie ein zweites Mal
   benutze.

Und eine neue Pruefung, die es vorher nicht gab: ALLE 118 Kennungen,
die das Programm mit `$('...')` anspricht, werden gegen das HTML
gehalten. Nach einem Umbau, der die halbe Tafel neu sortiert, waere
eine verlorene Kennung KEIN Fehler beim Laden -- `$()` gibt still
`null` zurueck, und der Fehler erscheint erst, wenn jemand mitten in
der Sendung den Knopf drueckt.

pruef-reaktion 365/0 (vorher 321) - pruef-spenden 172/0 (vorher 167) -
pruef-buehne 36/0 - pruef-css-klassen ok - pruef-tippziele 11/0 -
mess-reaktion und mess-buehne ohne Beanstandung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 20:03:38 +02:00
DogFatherGitandClaude Opus 5 96bdd79a91 Die Dogen-Muenzen: drei Saetze zu je drei Stufen
Filipe, 28.09.2026: "ich werde die drei varianten schicken fuer
niedrige spenden. mittlere und hohe spenden. alle drei varianten will
ich drauf so dass ich sie aussuchen kann wie ich will. aber pass sie
sofort diesen 3 kategorien an."

DIE ZUORDNUNG IST GELESEN, NICHT GERATEN

In allen drei Saetzen geht es nacktes Metall -> Steinkranz ->
Vollbesatz; Filipes Dateinummern (01/02/03) und die Uhrzeiten seiner
Entwuerfe laufen genau mit. Klassik: Palladium, Gold mit Saphir,
Diamant. Amethyst: Stahl, Rosegold, Vollbesatz. Neon: Chrom auf
Schwarz, Steinkranz, Vollbesatz.

AUS 25 MB WURDEN 443 KB

Je Bild 320 px WebP statt 1254 px PNG, Faktor 58. Die Zahl ist
gemessen: Groesster Fall in der Seite 110 px (Karte, hoechste Stufe),
auf der OBS-Tafel 189 px, bei doppelter Bildschirmdichte rund 220.
Drei Megabyte fuer ein 24-Pixel-Zeichen waeren ein Ladebalken mitten
in der Sendung -- wer auf dem Handy zusieht, bekaeme die Karte, wenn
sie schon wieder weg ist. Die Originale liegen neben den
Datenbanksicherungen, nicht im Repo: 26 MB, die bei jedem Klon
mitkaemen und die niemand ausliefert.

WELCHE MUENZE WANN -- ABGELEITET STATT GEPFLEGT

"Niedrig, mittel, hoch" gibt es im Haus schon: die Stufenleiter. Zwei
eigene Grenzen daneben waeren eine zweite Antwort auf dieselbe Frage,
und spaetestens beim Verschieben einer Stufe zeigte die Muenze etwas
anderes an als der Name auf der Karte. Die Leiter wird deshalb in
DRITTEL geteilt -- bei den drei Werksstufen genau eine je Muenze, bei
sechs zwei je Muenze, bei einer einzigen ueberall die mittlere.

DIE MUENZE STEHT AUCH GROSS AUF DER KARTE

Sonst haette Filipe neun Bilder fuer ein 24-Pixel-Zeichen gezeichnet.
"dogen" ist dafuer eine neue Vorlage neben Herz, Welle und Krone --
und die drei Werksstufen bekommen sie EINMAL zugeteilt, nur wo noch
die Werksvorlage steht und kein eigenes Bild hochgeladen ist. Wer
danach ein Herz zurueckstellt, findet es morgen nicht wieder als
Muenze vor: Eine Einstellung, die sich gegen den Benutzer durchsetzt,
wird abgeschafft.

Und steht sie gross da, nimmt das Stilblatt die kleine neben der Zahl
weg -- dieselbe Muenze in zwei Groessen auf einer Karte sieht aus wie
ein Versehen.

AM BILDSCHIRMFOTO NACHGEBESSERT

Bei 0,92em blieb an den Spendenknoepfen ein 13,5-Pixel-Fleck uebrig;
bei einem flachen Symbol reicht das, bei einer Muenze mit Pfote,
Schriftzug und Steinen nicht. Jetzt 1,05em ueberall und 1,6em auf den
Knoepfen. In der Auswahl sahen "Amethyst" und "Neon" bei 40 px
praktisch gleich aus -- und genau sie auseinanderzuhalten ist der
Zweck dieser Liste. Jetzt 56/64/72 px. Und was gewaehlt ist, steht
als WORT da: Neben neun glaenzenden Muenzen geht ein ruhiger Rahmen
unter, und wer Farben schlecht unterscheidet, sieht ihn gar nicht.

EIN SATZWECHSEL ERREICHT ALLE

Die Karten trugen ihren Satz immer selbst mit und waren richtig. Die
Muenzen an den Spendenknoepfen und beim eigenen Stand aber nicht --
die holt eine Seite nur bei einer Spende neu. Eine Einstellung, die
nur dort ankommt, wo sie gemacht wurde, ist keine Einstellung des
Hauses.

ZWEI BEFUNDE GEGEN DIE PRUEFUNG SELBST

1. Sie verlangte "erste Grenze ECHT kleiner als zweite". Bei genau
   zwei Stufen fallen beide absichtlich zusammen -- sie meldete einen
   Fehler, wo das Verhalten richtig ist.
2. Sie prueft die Muenzverteilung jetzt auf einer FRISCHEN Datenbank.
   Vorher lief sie auf der, die ein frueherer Abschnitt umgebaut
   hatte: Eine Pruefung, die den eigenen Kollateralschaden misst,
   misst sich selbst. Dazu eine Gegenprobe, dass eine selbst
   gewaehlte Vorlage NICHT ueberschrieben wird.

UND DREI AN DER MESSUNG

Sie suchte noch die gezeichnete Muenze (svg), wo jetzt ein Bild
liegt. Umgestellt nicht auf "ist ein img da", sondern auf
`naturalWidth > 0` -- ob es etwas ZEIGT. Ein img, das 404 antwortet,
steht genauso im Dokument wie eines, das laedt; auf dem Bildschirm
ist an seiner Stelle nichts. Und beim Satzwechsel las sie die vorige
Karte, die noch acht Sekunden stand: Die Karten laufen in einer
Schlange, also wird auf das Merkmal gewartet, das nur die neue hat.

pruef-spenden 167/0 (vorher 136) - pruef-reaktion 321/0 -
pruef-css-klassen ok - pruef-tippziele 11/0 -
mess-reaktion und mess-buehne ohne Beanstandung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 19:36:05 +02:00
DogFatherGitandClaude Opus 5 c00c209ac9 Dogen statt Geld -- und die Texte schreiben die Leute selbst
Filipe, 28.09.2026:
  "der text der dazu erscheint sollen die leute selber schreiben
   koennen. soll auf nicht zu viel aber auch nicht zu wenig
   schreiben koennen. aber es sollen personalisierte texte sein von
   den leuten selbst."
  "mann soll nie die summe sehen sondern die dogen auch mit dem
   symbol ... es soll auch nie geld da stehen sondern Dogen."
  "ich will dass die den leuten auch als punkte hinzugefuegt werden."

DER TEXT KOMMT VON DEM, DER GIBT

Bisher konnte ihn nur die Leitung tippen; beim Melden schickte der
Zuschauer gar nichts mit. Jetzt stehen nach dem Tippen auf einen
Betrag zwei Felder da: Name auf der Karte (mit dem eigenen Namen
vorausgefuellt) und der eigene Text, bis 140 Zeichen.

140 ist gemessen, nicht geraten: Die Karte steht je nach Stufe sechs
bis elf Sekunden. Bei 140 Zeichen sind das zwei bis drei Zeilen -- die
fasst man im Vorbeischauen. Bei 200 wird die Schrift auf einer kleinen
Karte so eng, dass niemand mehr hinsieht, und ein Gruss, den keiner
liest, ist schlechter als ein kurzer. Der Zaehler erscheint erst ab
30 uebrigen Zeichen; einer, der von Anfang an mitlaeuft, macht aus
einem Gruss eine Aufgabe.

UND EINE SCHRANKE DAVOR. Der Text kommt von einem Fremden und steht
gleich im Livestream. Er laeuft ohnehin durch die Bestaetigung -- neu
ist, dass die Leitung ihn dort AENDERN kann. Ohne das bliebe nur "ganz
ablehnen", und dann faellt wegen eines Wortes eine echte Spende unter
den Tisch.

NIE WIEDER GELD AUF DEM BILDSCHIRM

Ein Doge sind zehn Euro (Filipes Angabe "1 euro sind 0,10 dogen",
rueckgefragt und bestaetigt -- zwischen den beiden Lesarten liegt der
Faktor 100). Gerechnet wird in Tausendsteln, nie in Kommazahlen.

Das Entscheidende ist nicht die Beschriftung: DER BROWSER BEKOMMT
KEINEN EURO-BETRAG MEHR, auch nicht verborgen im JSON. Der Kurs steht
einmal auf dem Server. Was nicht gesendet wird, kann an keiner Stelle
versehentlich erscheinen, und niemand muss daran denken. Gemessen:
38 Felder im Stand, kein Geldfeld, kein Eurozeichen, auch nicht auf
der Buehnentafel. Der einzige Ort, an dem noch ein Euro entsteht, ist
die PayPal-Adresse -- weil PayPal ihn braucht.

DIE PUNKTE: EIN BUCH, KEIN ZAEHLER

Ein Feld `dogen` an der Person waere kuerzer gewesen -- und die zweite
Antwort auf dieselbe Frage. Der Stand IST die Summe der Buchungen, und
eine Summe kann sich nicht von ihren Posten entfernen. Weil Filipe
spaeter etwas daran haengen will ("spezielle sachen ... wo mit diesen
dogpunkten zu tun hat"), steht neben jeder Zeile ein Grund und ein
Datum: Ein Zaehler, der kleiner wird, laesst keine Frage mehr
beantworten.

Dass nie doppelt gutgeschrieben wird, entscheidet ein eindeutiger
Index in der Datenbank und keine Bedingung im Programm -- "nochmal
zeigen" und ein wiederholter Strom koennen es damit gar nicht
ausloesen.

Ohne Person keine Punkte: Eine von Hand eingetragene Spende hat oft
nur einen Vornamen auf dem Handy. Daraus eine Person zu RATEN waere
schlimmer als keine Gutschrift -- deshalb waehlt die Leitung sie aus,
und tut sie es nicht, laeuft die Karte trotzdem.

DAS SYMBOL IST VORBEREITET

Filipe: "die symbole schick ich dir spaeter." Es wird im Regiepult
hochgeladen, ohne Deploy -- bis dahin steht eine gezeichnete Muenze
da. Es liegt bei den Stufenbildern, weil das der einzige Weg ist, der
Bilder OHNE Anmeldung ausliefert; sonst fehlte es ausgerechnet im
Stream.

=======================================================================
UND EINE REPARATUR AN DEM, WAS HEUTE MITTAG LIVE GING

Seit 3fedeea7 war der Buehnenmodus (reaktion.html?nur=buehne) kaputt:
Leinwand null Pixel hoch, im Stream ein schwarzes Bild. Das ist die
Fensterquelle fuer den Fall, dass Gaeste im Bild sind.

Ursache: Teil A hat die Zeilen des Saals festgenagelt (#teil-live auf
Zeile 2). Im Buehnenmodus stand aber seit jeher eine eigene Regel, die
dem Saal nur EINE Zeile gibt -- das Video landete in einer impliziten
Zeile, die sich nach ihrem Inhalt bemisst, waehrend die Leinwand ihre
Hoehe aus der Zeile nimmt. Beide warten aufeinander, heraus kommt
null.

Das ist heute der VIERTE Fall von "zwei Regeln fuer dieselbe Frage"
(Tafeln, Saalzeilen, Kamerabreite, Buehnenmodus). Die Loesung ist
jedes Mal dieselbe: nicht die zweite Regel richtig stellen, sondern
sie abschaffen.

DREI DINGE, DIE DARAN LEHRREICH SIND:

1. MEINE EIGENE PRUEFUNG WAR GRUEN UND WERTLOS. Ich hatte nach Teil A
   extra geprueft: "genau eine Regel bestimmt die Zeilen des Saals".
   Sie verlangte, dass die Zeile mit `.saal` BEGINNT -- und hat
   `body[data-nur="buehne"] .saal { … }` deshalb nie gesehen. Jetzt
   zaehlt sie jede Regel, in deren Auswahl `.saal` vorkommt, mit einer
   Gegenprobe, die eine eingeschobene zweite wirklich findet.

2. EINE SEITE MIT ZWEI ANSICHTEN BRAUCHT BEIDE MESSUNGEN. Nach Teil A
   liefen `pruef-buehne` (Schnittstelle) und `mess-reaktion` (normale
   Ansicht). `mess-buehne` -- die einzige, die diese Ansicht
   ueberhaupt oeffnet -- lief nicht.

3. EIN PYTHON-SKRIPT, DAS ERST AM ENDE SCHREIBT, MELDET "ok" FUER
   AENDERUNGEN, DIE NIE ANKOMMEN. Eine fehlgeschlagene Zusicherung hat
   einen ganzen Stapel verworfen, obwohl die erste Aenderung schon
   bestaetigt war. Die Messung meldete daraufhin "Auf der Karte steht:
   undefined" -- kein Fehler im Code, sondern eine Zeile, die nie
   geschrieben wurde. Gefunden hat es die Messung, nicht das Lesen.

pruef-spenden 136/0 (vorher 95) - pruef-reaktion 321/0 -
pruef-buehne 36/0 - pruef-css-klassen ok - pruef-tippziele 11/0 -
mess-reaktion und mess-buehne ohne Beanstandung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 18:54:02 +02:00
DogFatherGitandClaude Opus 5 3fedeea716 Kamerafenster: Groesse und Ecke lassen sich stellen
Filipe: "und danach perfektionierst du auch die verschiedenen
groessen von kamera und so, perfektionier das alles bitte."

Sechs Groessen (0,6x bis 2x) und vier Ecken, beide an der SENDUNG
und nicht am Browser: Was Filipe einstellt, sehen alle. Waere es
eine Einstellung je Geraet, redete er ueber ein Bild, das bei den
Zusehenden anders aussieht -- und im Stream stuende ein drittes.

Anordnung, Groesse und Ecke gehen jetzt EINEN Weg (/layout), weil
sie zusammen eine einzige Frage beantworten: Wie sieht das Bild aus?
Drei getrennte Aufrufe waeren drei Rundrufe, und dazwischen saehen
die Zusehenden eine Mischung -- neue Anordnung, alte Ecke. Eine
falsche Angabe laesst auch das Gute stehen, statt halb umzustellen.

Die Ecke gibt es, weil unten rechts bei TikTok die Knopfreihe liegt,
bei YouTube die Fortschrittsleiste, und Untertitel fast immer unten
stehen. Eine feste Ecke ist eine, die bei jeder zweiten Plattform
im Weg ist.

Die OBS-Videoquelle kennt jetzt die Anordnung und blendet sich bei
"Nur Kamera" aus -- sonst laege im Stream ein stehengebliebenes
YouTube-Bild unter den Kameras, und Filipe saehe es nicht, weil er
auf seine Szene schaut und nicht auf die Quelle.

VIER BEFUNDE, ALLE VON DEN PRUEFUNGEN UND KEINER VOM AUGE:

1. Die Knoepfe fuer Groesse und Ecke gab es gar nicht. HTML und
   Stilblatt waren da, das Programm nicht. Gemessen: "0 von 0
   Eckknoepfen gesperrt", und der Hinweistext stand noch wortgleich
   wie im HTML -- zwei leere Kaesten, die aussahen, als sei alles
   in Ordnung.

2. Bei "Nur Kamera" war der Stapel 493 px breit statt 1072. Der
   neue Deckel max-width: 46% -- richtig gegen ein zu grosses
   Fenster bei "Video gross" -- galt still auch dort, wo die
   Kameras die ganze Flaeche fuellen sollen.

3. Am Handy haette die Groesseneinstellung ueberhaupt nichts
   bewirkt: Dort stand weiterhin width: clamp(88px, 26vw, 140px)
   am Fenster selbst. Das ist die dritte Wiederholung derselben
   Sache an einem Tag (die Saalzeilen, die Tafeln, jetzt die
   Kamerabreite): Zwei Regeln fuer dieselbe Frage sind die
   Garantie, dass eine davon irgendwo falsch gewinnt. Breite und
   Rand gehen jetzt ueber --kam-grund/--kam-rand, --kam wird an
   genau EINER Stelle gerechnet, und eine Pruefung zaehlt das nach.

4. Die Pruefung schlug auf ihren EIGENEN Kommentar an, der die
   entfernte Zeile zitiert. Ein Werkzeug, das bei jedem Lauf
   meckert, wird nach dem zweiten Mal weggeklickt -- samt dem
   echten Befund darin. Gezaehlt werden jetzt Regeln, nicht Prosa.

Gemessen beim Zuschauer und nicht in der Datenbank: 1x -> 208 px,
2x -> 416 px, alle Fenster innerhalb der Leinwand, und jede der
vier Ecken am Abstand zu den Kanten nachgewiesen statt an ihrem
eigenen Namen. Ein Knopf, der gerade nichts bewirken kann, ist
grau, und der Satz darunter sagt warum.

pruef-reaktion 320/0 - pruef-buehne 36/0 - pruef-css-klassen ok -
pruef-tippziele 11/0 - mess-reaktion ohne Beanstandung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 14:35:02 +02:00
DogFatherGitandClaude Opus 5 2b02d88767 Die Regieleiste steht jetzt über dem Saal
Filipe: „ich hätte das gerne oben also nicht in dieser kachel sondern
über der kachel wo die videos laufen werden und das soll extrem
perfektioniert werden."

WARUM DAS MEHR IST ALS EIN UMHÄNGEN
Die Register standen INNERHALB des einklappbaren Teils. Wer die Regie
zuklappte, um mehr Bild zu haben, hatte sie nicht mehr — und genau
dann braucht man sie. Oben ändert sich ihre Aufgabe: aus dem
Inhaltsverzeichnis einer Schublade wird eine Steuerleiste über der
Sendung. Daraus folgen vier Dinge, die vorher nicht nötig waren:

1. EIN REGISTER MACHT DIE ZUGEKLAPPTE REGIE AUF. Vorher wechselte nur
   der Reiter, die Tafel lag im zugeklappten Teil — sichtbar passierte
   nichts. Nur auf, nie zu: Zugemacht wird mit dem Griff. Ein Knopf,
   der beim zweiten Druck das Gegenteil tut, versteckt irgendwann
   etwas, das jemand gerade liest.

2. SIE BRICHT NICHT UM, SIE ROLLT. Sieben Register in zwei Zeilen
   kosten am oberen Rand rund 90 px — und zwar dem Video. Gemessen:
   eine Zeile auf 1440 px wie auf 390 px, dort mit Einrasten und
   weichen Rändern als Auskunft, dass es weitergeht.

3. SIE LÖST EIN, WAS `role="tablist"` VERSPRICHT. Pfeiltasten wandern,
   Pos1/Ende springen, genau ein Register liegt in der Tabulatorfolge.
   Steht die Rolle im Markup und tut das Programm es nicht, sagt ein
   Vorleser etwas an, was nicht stimmt — schlimmer als keine Rolle.
   Gemessen wird das gedrückt, nicht gelesen: fünf Tastendrücke, und
   Fokus, Auswahl und offene Tafel müssen jedes Mal dasselbe sagen.

4. EINE GLEITENDE MARKE zeigt, wo man steht — Glas mit Lichtkante,
   darunter ein roter Streifen zur offenen Tafel. Ist die Regie
   zugeklappt, wird er leise: Der Streifen führt dann nirgendwohin.
   Dazu ein Schild „Regie" links (am Handy weg), damit die sieben
   Wörter am oberen Rand nicht wie eine zweite Navigation aussehen.

DER FEHLER, DER MICH ZWEI ANLÄUFE GEKOSTET HAT
Die Leiste war im Browser 1 px hoch, ihre Register standen 55 px hoch
daneben und ragten über das Video. Ursache: 900 Zeilen weiter unten
stand eine ZWEITE `grid-template-rows` für `.saal` (aus der Zeit, als
der Saal zwei Zeilen hatte). Sie stand später und gewann — die Leiste
landete in der `1fr`-Zeile und bekam null Pixel.

Und fast hätte ich das Falsche repariert: Beim Durchprobieren habe ich
`style.gridTemplateRows` gesetzt — ein Stilattribut schlägt jede Regel
im Stilblatt. Damit „funktionierten" `auto` und `min-content` gleich
gut, weil beide die zweite Regel aushebelten, und es sah nach einem
Unterschied zwischen den beiden aus. Erst nach dem Entfernen der
Doppelung hat die Gegenprobe gezeigt: `auto` tut es genauso. Eine
Probe, die mehr ändert als das, wonach man sucht, beantwortet eine
andere Frage. Es gibt jetzt eine Prüfung, dass genau EINE Regel die
Zeilen des Saals bestimmt.

ZWEI WEITERE FUNDE AUS DER MESSUNG
Am Handy blieben bei offener Regie 131 px für das Bild — ein Streifen.
Mein erster Versuch (62dvh → 52dvh) machte es auf 75 px SCHLECHTER:
Die Ursache lag woanders, die Leiste des Pults bricht dort in vier
Zeilen um und ist rund 200 px hoch, wovon ein Anteil der Fensterhöhe
nichts wissen kann. Mit `min(52dvh, 19rem)` sind es 210 px.

Und die Spendenkarte wurde als „steht aus dem Bild heraus" gemeldet:
413 statt 430 px, links −1. 413 ist genau das 0,96-fache — die Messung
hatte die Karte im Ausblenden erwischt. Sie wartet jetzt auf
`data-da="ja"` und misst nur, was ganz da ist.

GEPRUEFT
pruef-reaktion 280 (vorher 260), 0 Fehler — Abschnitt 18 neu.
mess-reaktion: Rückgabewert 0, kein ACHTUNG; misst die Leiste jetzt
auf 1440 und auf 390 px, samt Tastatur und Aufklappen.
Dazu grün: handy, buehne, struktur, css-klassen, tippziele.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 14:13:07 +02:00
DogFatherGitandClaude Opus 5 d2f02ba84e Spenden: Stufen gestaltbar, Bild hochladen, Größe je Stufe
Filipes Wunsch: „mach paar fertige und so dass ich auch hochladen
kann. auch so dass ich das anders gestalten kann oder die größe
verändern kann. ... auch spezielle sachen bei speziellen spenden."

WAS ES SCHON GAB, WAS FEHLTE
Drei Stufen ab Werk, fünf gezeichnete Zeichen, Farbe und Dauer je
Stufe — und sogar schon ein Feld für ein eigenes Bild. Es fehlte der
Weg, das alles zu ÄNDERN: Um eine Stufe umzubenennen, hätte jemand in
die Datenbank greifen müssen.

DIE GRÖSSE IST DAS „SPEZIELLE BEI SPEZIELLEN SPENDEN"
Je Stufe, nicht einmal für alle: Eine Rudel-Legende darf größer
dastehen als ein Danke. Eine einzige Größe für alle wäre wieder eine
Preisliste. Umgesetzt als EINE Schriftgröße, alles darin in `em` —
nicht `transform: scale()`, denn die Karte kommt schon mit
`translateX()` herein, und zwei `transform` an derselben Stelle
schließen einander aus; außerdem wird Text beim Skalieren matschig.
Nur nach oben (1 bis 2,5), und das ist eine ehrliche Grenze: Das
kleinste Wort auf der Karte steht bei 11,52 px, die Hausgrenze ist
11,5. Ein Faktor von 0,8 machte daraus 9,2 px. Kleiner geht an der
richtigen Stelle — die OBS-Tafel hat ihren eigenen Regler in der
Adresse, dort ist es eine Videoeinblendung und kein Text zum Lesen.

AUSPROBIEREN, OHNE EINE SPENDE ANZULEGEN
Der naheliegende Weg wäre gewesen: eine Spende eintragen und danach
löschen. Das ist verboten — in ein laufendes System kommen keine
Testdaten, und „gelöscht" heißt bei Geld nicht „war nie da". Die
Probe schreibt deshalb NICHTS und geht nur an den, der drückt; eine
Probe im ganzen Saal wäre eine Spende, die es nicht gab.

DREI FEHLER, DIE DIE PRÜFUNG GEFUNDEN HAT

1. `protokolliere()` wurde an 17 Stellen falsch herum gerufen —
   `(personId, aktion, detail, ip)` statt `(aktion, {…})`. JavaScript
   beschwert sich nicht: Das zweite Argument war ein Text, und einen
   Text zu zerlegen ergibt lauter `undefined`. Auf dem echten Server
   nachgemessen: 39 Protokollzeilen mit Aktionen wie „16.0", alle
   ohne Person, ohne Detail, ohne IP. Betroffen waren Material,
   Hilfe, Bühne, Reaction und Spenden — also jede Änderung an
   Dogi-Media und jede Maßnahme im Live-Chat, ausgerechnet das,
   wofür es ein Protokoll gibt. Alle 17 berichtigt, und
   pruef-struktur wacht jetzt darüber (mit Gegenprobe).

2. Beim Speichern der Leiter bekam jede Stufe eine NEUE Kennung
   (DELETE + INSERT). Ein Bild-Hochladen gegen die eben noch gültige
   Kennung antwortete mit 404 — im Alltag trifft das jeden, der einen
   zweiten Bildschirm offen hat. Jetzt werden vorhandene Zeilen
   geändert statt ersetzt; das Bild bleibt von selbst daran hängen.

3. `ab_cent` ist eindeutig. Zwei Stufen ihre Beträge tauschen zu
   lassen scheiterte mit „UNIQUE constraint failed", obwohl das
   Ergebnis in Ordnung gewesen wäre: Beim Umschreiben stößt die
   Leiter auf sich selbst. Jetzt in drei Schritten — löschen,
   geparkte Zwischenwerte, endgültige Werte —, und das ist nach
   außen nie sichtbar.

UND DREI, DIE IN MEINER MESSUNG STECKTEN
Die Messung hat eine noch laufende Karte aus dem vorigen Abschnitt
erwischt und daraus drei Fehler gemeldet, die keine waren —
darunter „die Probe läuft im ganzen Saal". Sie zählte außerdem die
versteckten Dateifelder als zu kleine Tippziele. Jetzt räumt sie
vorher auf, wartet auf die Karte MIT DER ERWARTETEN GRÖSSE (die
Karten laufen in einer Schlange — einen Knoten zu entfernen beendet
sie nicht) und lässt die Einblendung zur Ruhe kommen, bevor sie misst.
Ein Bildschirmfoto aus der Einblendphase sah aus, als stünde die
Karte links heraus; nachgemessen: links 18 px, ganz im Bild.

GEMESSEN, NICHT ANGENOMMEN
Karte bei Größe 1: Schrift 16 px, Betrag 25,92 px. Bei Größe 2:
32 px und 51,84 px — Faktor exakt 2,00. Hätte eine einzige Regel noch
in `rem` gestanden, wäre die Karte ungleichmäßig gewachsen, und auf
einem Bild sieht beides nur „größer" aus.

AUCH DAS BILD IST GEPRÜFT
Es liegt am Bühnen-Router und nicht am Spenden-Router: Die
Spendentafel in OBS hat keine Anmeldung, und ein 401 als JSON in
einem `<img>` ergibt ein kaputtes Bild ohne jeden Hinweis. Ohne
Schlüssel, aber mit 128 Bit zufälligem Dateinamen — dieselbe
Größenordnung wie der Bühnenschlüssel, und es ist ein Zierbild, das
ohnehin im Stream steht. Kein Ausbruch aus dem Ordner (vier Wege
geprüft, gemessen wird die Wirkung und nicht der Statuscode).

NACHGETRAGEN AUS BLOCK 4
`reaktion_meldungen` fehlte im Löschkonzept — eine bestehende Prüfung
hat es gefunden. 30 Tage nach dem Erledigen; meistens sind sie
ohnehin früher weg, weil der Live-Chat beim Beenden gelöscht wird und
die Meldungen daran hängen. Wer meldet, muss sich darauf verlassen
können, dass daraus keine dauerhafte Liste wird.

GEPRUEFT
pruef-spenden: 95 Prüfungen (vorher 46), 0 Fehler.
pruef-reaktion 260, pruef-buehne 36, pruef-aufbewahrung 45,
pruef-struktur, pruef-meldungen, pruef-css-klassen, pruef-tippziele,
pruef-deutsche-texte, pruef-auskunft alle grün.
mess-reaktion und mess-buehne: Rückgabewert 0, kein ACHTUNG.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 10:14:26 +02:00
DogFatherGitandClaude Opus 5 74c74a08ab Reaction: Geschwindigkeit, zwei neue Anordnungen, zweites Video
Filipes Wunsch: „auch bei den videos sachen wie pause
geschwindigkeit. meine kamera größer machen video kleiner. nur mein
bild, nur das video, möglichkeit zwischen allem zu wechseln so wie ich
will, auch gerne so dass ich vielleicht noch ein zweites nebenbei
vorbereiten kann so dass ich hin und her switchen kann."

GESCHWINDIGKEIT
Sechs Stufen von 0,5× bis 2× (0,25× fehlt mit Absicht — bei einem
Viertel klingt Sprache wie ein defektes Band). Sie gilt für ALLE: Wer
sie nur bei sich umstellte, redete über eine Stelle, die die anderen
noch nicht gesehen haben. Die OBS-Bühne zieht sie mit nach — ohne das
liefe der Stream nach fünf Minuten auf 1,5× zweieinhalb Minuten hinter
dem Saal her.
Und der Zuschauer SIEHT sie: ein kleines Schild „1,5×
Geschwindigkeit" auf der Leinwand, nur wenn es nicht 1× ist. Ohne das
hält jeder Zweite seine Leitung für kaputt.
Zwei Fallen, die dabei zugemacht wurden: Der Fünf-Sekunden-Takt des
Hosts schreibt das Tempo NICHT mit (sonst drehte ein Takt mit altem
Wert die Einstellung zurück), und nach jedem Videowechsel wird es neu
gesetzt (YouTube stellt beim Laden auf 1 zurück). Gesetzt wird nur,
was `getAvailablePlaybackRates()` hergibt — einen unmöglichen Wert
ignoriert der Player schweigend, und dann stünde der Knopf auf 1,5
und es liefe 1,0.

ZWEI ANORDNUNGEN MEHR
„Nur Video" und „Nur Kamera" sind kein weiteres Größenverhältnis,
sondern ein Weglassen — und genau das braucht OBS: Dort liegt die
Kamera ohnehin als eigene Quelle, die Bühnenseite soll sie nicht
doppelt zeigen. `display: none` und nicht `opacity: 0`: ein
unsichtbarer YouTube-Rahmen spielt weiter und hält den Ton.
Tasten 1–5, wie vorher 1–3.

DAS ZWEITE VIDEO — und warum es nicht die Warteschlange ist
Die Schlange ist eine Reihenfolge: eins nach dem anderen, das
Gespielte ist weg. Filipe will etwas anderes — zwei Videos
NEBENEINANDER, hin und her, und jedes merkt sich seine Stelle. Mit
der Schlange nachgebaut wäre es eine Schlange, aus der man nie wieder
herauskommt. Der Umschalter steht nur da, wenn es etwas zum Umschalten
GIBT; ein Knopf, der „kein zweites Video" antwortet, ist im Live eine
Falle. Getauscht wird in EINEM Schreibvorgang (BEGIN IMMEDIATE) —
ein Abbruch dazwischen hätte dasselbe Video auf beiden Seiten und die
gemerkte Stelle des anderen verloren. Und die Stelle kommt vom Host
und nicht aus der Datenbank: dort steht der Stand vom letzten Takt,
bis zu fünf Sekunden alt.
Was daneben bereitliegt, sieht nur, wer sendet — es ist die Rückhand,
und die verrät man nicht vorher (`zweit` ist aus `oeffentlich()`
ausgenommen).

DER FEHLER, DEN DIE MESSUNG GEFUNDEN HAT
Bei „Nur Kamera" war der Kamerabehälter 2175 px breit in einer
1072 px breiten Leinwand — von zwei Gästen stand nur einer im Bild,
der zweite lag hinter `overflow: hidden`. Auf dem Bildschirmfoto sah
das aus wie eine Anordnung für einen, und niemand hätte gefragt, wo
der zweite geblieben ist.
Zwei Ursachen: Die Leinwand ist ein Raster mit einer Spalte nach
Inhaltsbreite — ein zu breites Kind im Fluss zieht die Spalte mit, und
`width: 100%` bezog sich danach auf die gewachsene Spalte. Die
Begrenzung wuchs also mit dem, was sie begrenzen sollte; `max-width:
calc(50% - 8px)` rechnete gegen denselben Wert und war wirkungslos.
Jetzt `position: absolute; inset: 0` (kann das Raster nicht mehr
aufziehen) und `flex: 1 1 0; min-width: 0` an den Fenstern — eine
Regel, die nicht rechnet, kann sich nicht verrechnen.
Die Messung prüft seitdem bei JEDER Anordnung, ob alle Kamerafenster
innerhalb der Leinwand liegen.

GEMESSEN, NICHT ANGENOMMEN
Dass in der Datenbank 1.5 steht, sagt nichts darüber, ob das Video
schneller läuft. Die Messung liest deshalb die Uhr der Regie zweimal
ab und rechnet nach: 1× → 1,00 Sekunden je Sekunde, 2× → 2,00.
Der Umschalter ebenso: hin, zurück, und die Uhr steht wieder bei 79 s
statt bei 0.

GEPRUEFT
pruef-reaktion: 260 Prüfungen (vorher 216), 0 Fehler.
pruef-buehne 36, pruef-struktur, pruef-meldungen, pruef-tippziele,
pruef-css-klassen alle grün. mess-reaktion: Rückgabewert 0, kein
einziges ACHTUNG.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 09:48:26 +02:00
DogFatherGitandClaude Opus 5 a02cf5c026 Reaction: Rollen sichtbar, Moderation im Live-Chat
Filipes Wunsch: „die modis, linke hand und rechte hand soll im chat
extra aussehen und auch sachen wie stummschaltungen, sperrungen,
meldunge und alles mögliche im chat machen können falls sich jemand
nicht benimmt."

WER SPRICHT
Jeder Beitrag aus dem Team trägt jetzt ein Abzeichen: „Dogi", „Team"
(beide Hände) und „Modi". Ein WORT und nicht nur eine Farbe — rund
acht Prozent der Männer unterscheiden Rot und Grün schlecht, und hier
hängt an der Unterscheidung etwas. Gedeckte Töne auf schwacher Fläche,
11,52 px (die Hausgrenze ist 11,5), weil daneben ein Video läuft.
Die Wörter sagen den RANG nicht: Filipe steht nie über seinem Team.
Eine Prüfung schlägt an, wenn dort „Chef", „Boss" oder „Leitung"
stünde.

WAS DIE MODERATION KANN
Am Namen öffnet sich ein Menü mit vier Wegen: Beitrag wegnehmen,
10 Minuten stumm, aus der Sendung — und der Verweis in den Treff, wo
längere Maßnahmen hingehören (mit Begründungspflicht und Frist in
Tagen). Die Reaction baut kein zweites Sperrsystem daneben: Wer im
Treff eine Pause hat, schreibt hier auch nicht. Neu ist nur, was der
Treff nicht hat — MINUTEN. Höchstens eine Stunde; wer länger etwas
braucht, nimmt den Treff.
Nicht gegen das Team: Wer einen Modi stummschalten könnte, hätte einen
Weg, die Moderation selbst auszuschalten, mitten in der Sendung.

MELDEN DARF JEDER
Die Moderation sieht nicht alles, wer mitliest schon. Zweimal melden
zählt einmal (sonst füllt einer allein die Liste). Bei der Moderation
erscheint im Kopf der Schiene „1 Meldung" — nur wenn etwas offen ist;
eine Zahl, die immer dasteht und meistens null ist, wird nach drei
Tagen nicht mehr gelesen.

VIER FEHLER, DIE DABEI AUFGEFALLEN SIND

1. `oeffentlich()` nahm `meldungen` und `massnahmen` NICHT aus dem
   Rundruf. Der Rundruf wird aus dem Stand dessen gebaut, der gerade
   etwas getan hat — bei einer Moderationshandlung wären der gemeldete
   Text, der Name des Gemeldeten und der Name des MELDERS an jeden im
   Saal gegangen. Wer meldet, muss sich darauf verlassen können, dass
   das niemand sieht.

2. `meldung.js` hatte zwei Schlüssel doppelt: `geschlossen` und
   `nur_leitung`. Der spätere gewinnt stillschweigend — in der Hilfe
   stand dadurch „Der Saal ist zu". Ein Wort, ein Satz; eine Prüfung
   hält das jetzt fest.

3. Wer stummgeschaltet war, bekam bei OFFENEM Chat „Der Chat ist
   gerade zu" — der Aufrufer reimte sich den Grund aus der Chat-Stufe
   zusammen. Jetzt gibt `schreibGrund()` den echten Grund zurück.

4. Wer rausgenommen wurde, merkte nichts: Das Video lief weiter, nur
   die Anwesenheitsmeldung schlug still fehl. Jetzt hält alles an und
   es steht ein Satz da, der sagt, dass es nur für heute gilt.

UND EINER, DEN NUR DAS BILDSCHIRMFOTO GEFUNDEN HAT
Das Menü lag messbar komplett im Fenster (x=1099..1315 von 1440,
y=652..840 von 900) und war trotzdem abgeschnitten: Die Chatliste
rollt, und ein rollender Vorfahre beschneidet sein Kind. „Im Fenster"
und „sichtbar" sind zwei verschiedene Fragen, und ich hatte die
falsche gemessen. Das Menü hängt jetzt fest am Fenster und klappt nach
oben oder links, wo kein Platz ist. Die Messung fasst seitdem mit
`elementFromPoint` an jeden Knopf an, statt Rechtecke zu vergleichen.

GEPRUEFT
pruef-reaktion: 216 Prüfungen (vorher 156), 0 Fehler — zwei neue
Abschnitte. mess-reaktion misst die Moderation jetzt im echten
Browser: Abzeichen, Überlauf der Schiene, Menü, Stummschaltung beim
Betroffenen, Meldung bis zur Moderation, Rauswurf.
Dazu grün: pruef-meldungen, pruef-struktur, pruef-css-klassen,
pruef-tippziele, pruef-deutsche-texte, pruef-hilfe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-28 09:32:10 +02:00
DogFatherGit cb8e59bb08 Eine Arbeitsdatei war mitgewandert
tools/.messkopf.txt ist ein Zwischenstand beim Bauen der Messung --
sie gehoert nicht in die Geschichte. Die uebrigen Zwischenstaende
stehen schon in .gitignore; dieser Name fehlte.
2026-09-28 09:08:59 +02:00
DogFatherGit 079cf8c74f Drei Quellen fuer OBS und TikTok Studio -- ohne Anmeldung, mit Schluessel
Filipe: "ich will das alles auch so perfekt dass ich es ganz einfach
und easy mit obs oder mit tiktok studio verbinden kann. also so dass
man dan nur die kamera und das video sieht."

WARUM OHNE ANMELDUNG -- nachgesehen, nicht angenommen

OBS speichert die Anmeldung einer Browser-Quelle NICHT zuverlaessig;
im OBS-Forum stehen dazu Meldungen bis in die aktuelle Fassung 31.
Eine Quelle, bei der man sich nach jedem Programmstart neu anmelden
muss, ist mitten in einer Sendung unbrauchbar.

Deshalb ein SCHLUESSEL in der Adresse -- derselbe Weg, den jedes
Alert-Werkzeug im Netz geht. 32 Byte aus dem Zufall des Systems,
verglichen wird zeitgleich (`timingSafeEqual`): Ein gewoehnlicher
Vergleich bricht beim ersten falschen Zeichen ab, und aus den
Bruchteilen einer Millisekunde laesst sich ein Schluessel Zeichen
fuer Zeichen erraten.

DREI QUELLEN, WEIL DREI DINGE VERSCHIEDEN SIND

  buehne.html   Das laufende YouTube-Video, auf die Sekunde genau wie
                bei allen anderen. Stumm (der Ton kommt aus dem
                Mischpult) und ohne jede Bedienung -- was hier zu
                sehen ist, geht in den Stream.

                DIE EIGENE KAMERA IST ABSICHTLICH NICHT DRIN. Sie ist
                in OBS direkt als Geraet verfuegbar, in besserer
                Qualitaet und frei in Groesse und Lage -- genau das,
                was Filipe will ("meine kamera groesser machen video
                kleiner"). Den Umweg ueber den Browser zu nehmen
                hiesse, Qualitaet gegen nichts einzutauschen und die
                Groesse festzulegen statt sie freizugeben.

  tafel.html    Nur die Spendenkarten, auf DURCHSICHTIGEM Grund.
                Groesse und Lage stehen in der Adresse (`&g=1.6`,
                `&pos=or`): Wer in OBS eine Quelle einrichtet, hat die
                Adresse ohnehin vor sich -- ein Wert, den man
                stattdessen im Regiepult suchen muesste, waere ein
                Fensterwechsel mitten im Einrichten. Alles rechnet in
                `rem`, ein Wert nimmt Schrift, Bild und Polsterung
                gleichmaessig mit.

  Buehnenmodus  `reaktion.html?nur=buehne` -- dieselbe Seite, nur ohne
                alles Bedienbare. Fuer den Fall, dass GAESTE im Bild
                sind: Deren Kameras kommen ueber eine
                Direktverbindung an, und die braucht eine angemeldete
                Seite. Diese eine wird als Fenster aufgenommen.

                ES IST DIESELBE SEITE UND NICHT EINE ZWEITE. Eine
                eigene muesste Video, Kameras, Verbindungsaufbau und
                Nachfuehrung noch einmal enthalten -- und beim
                naechsten Umbau saehe eine von beiden anders aus.

WAS HERAUSKOMMT, IST DIE EIGENTLICHE FRAGE

Wer den Schluessel hat, sieht genau das, was ohnehin im Stream
steht: Video, Stand, Sekunde, Titel -- und die Spendenkarten. Kein
Chat, keine Namen von Zusehenden, keine Zahlen ueber das Haus. Die
Pruefung zaehlt die Felder der Auskunft EINZELN auf und weist jedes
verbotene namentlich nach; eine Auskunft, die "ungefaehr das
Richtige" enthaelt, ist bei einem Weg ohne Anmeldung keine.

Ein neuer Schluessel macht die alten Adressen sofort tot -- und
schliesst die laufenden Quellen. Sonst liefe eine mit dem alten
weiter, obwohl er zurueckgezogen ist, und man haelt sich fuer
sicher, ohne es zu sein.

SIE MUESSEN TAGE LAUFEN, OHNE DASS JEMAND HINSIEHT

Das ist der Unterschied zu einer Seite im Browser: Wer eine Seite
offen hat, merkt, wenn sie haengt. Eine Quelle in OBS laeuft im
Hintergrund, und ein Stillstand faellt erst auf, wenn die erste
Spende nicht erscheint -- mitten in der Sendung. Deshalb ein
Lebenszeichen alle 25 Sekunden, eine eigene Wache (70 Sekunden ohne
alles = neu verbinden) und ein sofortiger Neuaufbau, wenn der
Rechner aus dem Ruhezustand kommt.

Und: Ein Fehler wird angezeigt, aber nur der, der etwas bedeutet --
ein falscher Schluessel. Alles andere bleibt still, weil jede
Flaeche hier im Stream zu sehen waere.

ZWEI EIGENE FEHLER, BEIDE VON DER MESSUNG GEFUNDEN

1. Die Quellen kamen mit 401 zurueck, obwohl die Seiten laengst
   geladen waren: `aufgabenRouter` haengt eine Schranke ueber ALLE
   Pfade unter /workspace/api. Genau dafuer stehen `sicherungRouter`
   und der Weg fuers Profilbild schon davor -- die Buehne ist der
   dritte Fall derselben Art und steht jetzt dort.

2. `waitUntil: "networkidle"` auf einer Seite mit Ereignisstrom. Der
   Strom endet absichtlich nie; die Messung wartete auf einen
   Zustand, der nicht eintreten kann, und brach nach 30 Sekunden ab.
   Dieselbe Falle wie am 06.09. beim Regressionslauf.

ZWEI PRUEFUNGEN WURDEN DABEI GENAUER

  `pruef-struktur` verlangte von den zwei OBS-Quellen ein Symbol fuer
  den Startbildschirm, ein Manifest und eine Leistenfarbe. Sie
  laufen in einem Programmfenster und werden nie installiert -- sie
  fallen aus dieser Frage heraus, benannt und mit Grund.

  Die Namensstreit-Regel zaehlte jede Klasse, die irgendwo in einem
  Selektor vorkommt. Damit galt auch
  `body[data-nur="buehne"] .kopfleiste { display: none }` als eigene
  Klasse -- dabei ist das das Gegenteil: eine absichtliche
  Bezugnahme, um sie im Buehnenmodus wegzunehmen. Gezaehlt wird
  jetzt nur, was am ANFANG einer Regel steht, also als eigenes
  Bauteil gemeint ist. Mit Gegenprobe in beide Richtungen -- sonst
  haette ich eine Regel nur so lange geschaerft, bis sie schweigt.

GEMESSEN

  mess-buehne     (neu) Ein Browserfenster OHNE jeden Keks: beide
                  Quellen arbeiten, 0 Kekse, Grund durchsichtig
                  (rgba(0,0,0,0)), Karte laeuft an (25 EUR,
                  Rudel-Legende, 348x178). Falscher Schluessel: kein
                  Inhalt, Grund im Bild. Neuer Schluessel: alter 404,
                  neuer 200. Buehnenmodus: Kopf, Chat, Pult und
                  Schild weg, Leinwand da, Saal 720 von 720.
  pruef-buehne    (neu) 36 Punkte, 0 Fehler
  pruef-reaktion  156 (war 154), spenden 46, haus-trennung 100,
                  haus-seiten 38, struktur 35, css-klassen 33,
                  verborgen 25, rechtetafel 19, portnummern 15,
                  ports 8 -- alle 0 Fehler.
2026-09-28 09:08:42 +02:00
DogFatherGit dcd0298700 Spenden: vier Knoepfe, eine Karte im Bild -- und die Wahrheit ueber PayPal
Filipe: "ich will dass das richtig perfekt gemacht wird so dass die
leute so einfach wie moeglich eine spende aufs paypal machen koennen.
und wenn jemand spendet soll auch der betrag erscheinen mit einem
bild."

WAS GEHT UND WAS NICHT -- NACHGESEHEN, NICHT ANGENOMMEN

Hinterlegt ist ein PayPal.me-Link auf ein PRIVATES Konto. Daraus
folgt zweierlei, und beides bestimmt den ganzen Aufbau:

  ES GEHT: `paypal.me/<name>/5EUR` oeffnet PayPal mit schon
  eingetragenem Betrag. Ein Tipp, fertig. Belegt an PayPals eigener
  Hilfeseite zu PayPal.Me.

  ES GEHT NICHT VON SELBST: PayPal meldet eine Zahlung nur, wenn ein
  Webhook oder IPN eingerichtet ist -- beides braucht Zugangsdaten,
  die nur Filipe selbst anlegen kann. Ob ein PRIVATES Konto das
  ueberhaupt kann, sagt PayPals eigene Doku nicht eindeutig; ich habe
  es gesucht und nicht gefunden, und etwas zu behaupten, das ich
  nicht belegen kann, waere hier das Gefaehrlichste.

DESHALB DREI HERKUENFTE UND NICHT EINE

  "hand"      Filipe sieht die PayPal-Meldung auf dem Handy und tippt
              den Betrag ins Pult. Geht immer, braucht nichts, ist in
              drei Sekunden getan, und die Karte laeuft sofort.
  "gemeldet"  Der Zuschauer sagt nach dem Spenden selbst Bescheid.
              Landet als OFFEN und wird erst gezeigt, wenn die
              Leitung es bestaetigt.
  "paypal"    Kommt automatisch, sobald ein Webhook eingerichtet ist.
              Bis dahin steht dieser Weg leer da -- die Tabelle und
              die Sperre gegen doppelte Zahlungsnummern sind schon
              fertig.

WARUM EINE MELDUNG NICHT SOFORT ERSCHEINT: Sonst tippt irgendwer
"500 Euro" und steht damit gross im Bild. Eine Spende ist eine
Aussage ueber Geld; die gehoert bestaetigt, bevor sie oeffentlich
wird. Der Weg dahin ist EIN Tipp -- billig genug, dass niemand in
Versuchung kommt, ihn abzukuerzen. Beim Bestaetigen darf der Betrag
berichtigt werden: Die Leitung hat die PayPal-Meldung vor sich und
weiss es besser als die Behauptung.

FUER DIE ZUSCHAUER

Vier Betraege im Chat (2, 5, 10, 25 EUR) statt eines Links. Wer eine
Liste sieht, rechnet; wer vier Knoepfe sieht, tippt. Die Adresse wird
NICHT zweimal gepflegt -- sie steht auf der Unterstuetzen-Seite, und
von dort wird sie gelesen. Steht dort nichts oder ist der Weg auf
unsichtbar, gibt es hier auch keine Knoepfe. An einer Adresse, die
kein paypal.me ist, wird kein Betrag angehaengt: Er fuehrte sonst zu
einer Seite, auf der etwas anderes steht als auf dem Knopf.

DIE KARTE

Betrag gross, Name, Gruss, ein Bild dazu -- und eine Farbe, die von
der Stufe kommt. Drei Stufen ab Werk: Danke (ab 1), Starke Runde (ab
5), Rudel-Legende (ab 20), je mit eigener Vorlage, Farbe und Dauer.
Gilt immer die HOECHSTE, die noch passt; mit Ober- UND Untergrenze je
Stufe waere die doppelte Gelegenheit, eine Luecke zu lassen -- durch
die faellt dann ausgerechnet der grosse Betrag.

EINE NACH DER ANDEREN. Drei Spenden in zehn Sekunden sind keine
Seltenheit; uebereinander gelegt waere keine mehr lesbar, und
ausgerechnet die groesste ginge unter. Bei voller Schlange werden die
Zeiten gekuerzt, nicht die Karten weggeworfen -- wer gegeben hat,
soll es sehen.

DIE KARTE IST EIN EIGENES STUECK (spendenkarte.js/.css) und haengt an
nichts aus der Reaction. Dieselbe Karte laeuft spaeter als eigene
Seite fuer OBS und TikTok Studio; zweimal gebaut hiesse, sie sieht
nach der naechsten Aenderung an einem der beiden Orte anders aus --
und man merkt es erst im Livestream.

DER BETRAG STEHT IN CENT

Nie als Kommazahl. 0.1 + 0.2 ist in keiner Programmiersprache 0.3,
und bei Geld faellt das irgendwann jemandem auf -- meistens dem, der
zahlt. Formatiert wird erst auf dem Bildschirm.

DREI EIGENE FEHLER, VON DEN PRUEFUNGEN GEFUNDEN

1. Ein Weg aus einer Verzweigung: `/spenden/${id}/${ja ?
   "bestaetigen" : "ablehnen"}`. `pruef-struktur` hat das zu Recht
   beanstandet -- ein Tippfehler im selteneren Zweig faellt erst auf,
   wenn er mitten in einer Sendung gebraucht wird. Beide Wege stehen
   jetzt ausgeschrieben da.

2. "Genau 5 Register" -- zweimal am selben Tag dieselbe feste Zahl,
   in der Messung UND in der Pruefung. Beim sechsten Register wurden
   beide rot, obwohl nichts kaputt war. Jetzt wird gezaehlt: zu jedem
   Reiter gehoert eine Tafel, und keine steht ohne Reiter da.

3. Die Messung war zu ungeduldig: Die erste Karte laeuft elf
   Sekunden (die hoechste Stufe steht am laengsten), die zweite
   wartet in der Schlange -- richtig so. Die Messung wartete 1,6
   Sekunden und meldete "laeuft nicht". Jetzt wird auf das Merkmal
   gewartet, nicht auf die Uhr.

GEMESSEN

  mess-reaktion   4 Betragsknoepfe mit richtiger Adresse.
                  25 EUR von Hand -> Karte "Rudel-Legende" bei der
                  Zuschauerin. 500 EUR gemeldet -> steht NICHT im
                  Bild, wartet im Pult. Bestaetigt mit berichtigten
                  10 EUR -> Karte "Starke Runde". Stufe passt zum
                  Betrag, beide Male.
  pruef-spenden   46 Punkte, 0 Fehler (neu) -- darunter die
                  Gegenprobe, dass ohne Zahlungsnummer beliebig viele
                  Zeilen nebeneinander stehen duerfen (sonst liesse
                  sich nur EINE Spende von Hand eintragen).
  pruef-reaktion  154, unterstuetzung 70, aufbewahrung 45,
                  struktur 35, css-klassen 33, portnummern 15,
                  tippziele 11, ports 8, meldungen 8 -- alle 0 Fehler.

SCHEMA: zwei Tabellen (spenden, spenden_stufen) mit einem
Einmalig-Index auf die Zahlungsnummer. Auf einer Kopie der echten
Datenbank durchgespielt: 20 Personen, 227 Chatnachrichten, keine
Tabelle verliert eine Spalte.
2026-09-28 08:34:42 +02:00
DogFatherGit 28b492527e Kamera und Chat -- die zwei fehlenden Host-Steuerungen
Filipes Notiz nennt acht: "Host-Steuerung fuer Kamera, Mikrofon,
Video, Gaeste, Lautstaerke, Chat, Layout und Start/Ende."
Nachgezaehlt war sechsmal etwas da und zweimal nichts.

KAMERA

Es gab keinen Weg, das eigene Bild abzuschalten. Wer kurz aufstehen,
trinken oder etwas holen wollte, musste die Sendung verlassen oder
sich dabei filmen lassen.

Jetzt liegt eine SENDERLEISTE ueber dem Bild -- Kamera, Mikro und ein
Pegel. Sie gehoert jedem, der sendet, Host wie Gast: Ein Gast, der
sein eigenes Bild nicht abschalten kann, muesste den Host darum
bitten, und das ist keine Bedienung, sondern eine Bitte.

DAS BILD WIRD AM GERAET ABGESCHALTET (`track.enabled = false`), nicht
am Server: Die Verbindung bleibt stehen, der Ton laeuft weiter, und
beim Wiedereinschalten ist das Bild sofort da. Der Server erfaehrt es
nur, damit bei den ANDEREN "Kamera aus" im Fenster steht. Ohne diese
Beschriftung sind ein abgeschaltetes und ein kaputtes Bild dasselbe
schwarze Rechteck -- und dann fragt jemand im Chat, ob die Technik
hakt.

Erst das Geraet, dann die Ansage. Andersherum stuende bei allen
"Kamera aus", waehrend noch ein Bild fliesst; man glaubte sich
unsichtbar. Geht die Ansage nicht durch, wird das Geraet
zurueckgesetzt -- ein Knopf, der halb wirkt, ist schlimmer als einer,
der gar nicht wirkt.

Das Mikro laeuft denselben Weg. Erst wollte ich es rein oertlich
lassen; das waere dieselbe stille Falle gewesen: Wer sich selbst
stummschaltet und trotzdem redet, saehe bei allen anderen ein ganz
normales Fenster.

CHAT

Es gab Moderation -- Beitraege wegnehmen -- aber keine Steuerung des
Chats selbst. Einen Beitrag zu loeschen, nachdem er stand, ist etwas
anderes, als ihn gar nicht erst zuzulassen.

Drei Stufen: OFFEN, TEAM (wer moderiert, darf -- wer aufraeumen soll,
muss dabei reden koennen) und ZU (nur die zwei, die fuehren). Zwei
Stufen waeren zu wenig: "zu" ist in einer Sendung fast immer zu viel,
dann sitzen alle vor einem stummen Fenster. Die mittlere ist die, die
man wirklich braucht.

Die Schalter stehen im Kopf der Chatschiene, nicht im Regiepult: Man
moderiert, wo man liest. Ein Umweg ueber ein Register waere in dem
Moment, in dem es laut wird, genau ein Umweg zu viel.

EIN GESPERRTES FELD SAGT, WARUM. "Gerade schreibt nur das Team" statt
eines Feldes, das sich nicht beschreiben laesst und schweigt --
sonst schreibt jemand in den Hauschat, dass die Reaction hakt. Und
die Stufe gilt AM SERVER: Ein ausgegrautes Feld haelt niemanden auf,
der die Schnittstelle kennt. Beide Antworten kommen aus derselben
Funktion; zwei Rechnungen waeren zwei Gelegenheiten, dass ein Feld da
ist und mit 403 antwortet.

EIN FUND NEBENBEI: "MEIN MIKRO" WAR EIN PLACEBO

Gemessen: `staende.mikro` wird nirgends gelesen. Der Schieber liess
sich bewegen, die Zahl daneben aenderte sich -- und es passierte
nichts. Das ist schlimmer als ein fehlender Regler: Man glaubt, man
haette leiser gestellt.

Technisch ist das auch richtig. Die eigene Lautstaerke laesst sich
nicht am Regler aendern; man muesste den Ton umrechnen und die Spur
in jeder Verbindung austauschen. Was man beim eigenen Mikro braucht,
ist AN oder AUS -- und ein Pegel, der zeigt, dass es ankommt. Genau
das steht jetzt dort, als vierte Spalte im Pult, mit demselben
Zustand wie die Senderleiste. Die drei anderen Regler bleiben Regler:
Sie steuern, was ICH hoere, und das geht am Empfaenger.

UND EINER IN MEINER EIGENEN ARBEIT

`kasten.append(el("div","pegel")).append(el("i"))` -- `Node.append()`
gibt `undefined` zurueck, nicht das angehaengte Element. Ein
TypeError beim Aufbau des Pults, den `node --check` nicht sieht.
Beim Verkuerzen nicht nachgesehen, was die Methode zurueckgibt.

Dazu: Die Pegel-Takte liefen in `pultAufbauen()`. Das Pult hat nur,
wer die Sendung fuehrt -- ein Gast haette seinen Pegel nie gesehen,
und genau er braucht ihn am dringendsten.

GEMESSEN

  mess-reaktion   Der Host schaltet ab, und bei der Zuschauerin steht
                  "Kamera aus" bei DogFather, Bild verdeckt.
                  Stufe "Team": Feld gesperrt mit Grund, und der
                  Server lehnt denselben Versuch mit 403 ab.
  pruef-reaktion  154 Punkte, 0 Fehler (vorher 132), neuer Abschnitt
                  13 mit 22 Punkten und Gegenprobe (es geht auch
                  wieder auf -- eine Sperre, die man nicht loesen
                  kann, ist keine Stufe, sondern ein Ende)
  dazu gruen      handy 180, css-klassen 33, struktur 35,
                  tippziele 11, aufbewahrung 45, meldungen 8

Der neue Abschnitt baut sich seine Buehne selbst. Abschnitt 9 beendet
die Sendung; sich auf den Stand eines frueheren Abschnitts zu
verlassen ist die Kopplung, die spaeter jemand aus Versehen
zerreisst.

SCHEMA: drei Spalten (reaktion_dabei.kamera_aus, .mikro_aus,
reaktion.chat_modus), alle per ALTER TABLE. Auf einer Kopie der
echten Datenbank durchgespielt: 20 Personen, keine Tabelle verliert
eine Spalte.
2026-09-28 08:16:49 +02:00
DogFatherGit d79f6faa23 Die Reaction-Kachel steht hinter Dogi-Media
Filipe: "die kachel von der kategorie, reaktion, soll nach der
kachel, dogi-move, erscheinen bitte und danke."

EINE KACHEL "DOGI-MOVE" GIBT ES NICHT -- das Wort kommt im ganzen
Haus nicht vor. Die einzige, die passt, ist "Dogi-Media" (Bilder und
Videos zum Posten). Dorthin ist sie gesetzt; sollte etwas anderes
gemeint gewesen sein, ist es eine Zeile zurueck.

Die Reihenfolge der Community-Kacheln ist damit:

  Willkommen - Rudel-Chat - Highlights - Anschlagbrett -
  Was ansteht - Wunschliste - Dogi-Media - REACTION - Draussen

Geprueft: reaktion 132, kachelraster 24, kachel-universum 13 --
alle 0 Fehler.

Die angefangene Arbeit an der Host-Steuerung (Kamera- und
Chat-Spalten) bleibt bewusst im Arbeitsstand: Sie ist unfertig und
hat in dieser Lieferung nichts zu suchen.
2026-09-28 08:04:07 +02:00
DogFatherGit 711a5470ab Die Regie wird eine Regie -- und das Video lief bei niemandem
Filipe: "perfektionier das auch mit den videoos. pefektionier auch das
aussehen und das layout von der regie. ich will dass du das viel
hochwertiger und profissioneller machst."

DAS VIDEO LIEF BEI NIEMANDEM -- AUCH NICHT BEIM HOST

Gemessen ueber ein neues Merkmal am Rahmen: `onStateChange` ist nie
ausgeloest worden, bei keinem der drei Browser. Zwei Ursachen, die
sich gegenseitig verdeckt haben:

  Ein Player mit Ton darf ohne Handlung des Menschen nicht losgehen.
  Ohne `mute: 1` greift `playVideo()` nicht -- und ein Zuschauer hat
  keine Bedienung (mit Absicht), haette also NIE eine Moeglichkeit
  gehabt, es zu starten. Eine Stunde Standbild.

  `onReady` tat `if (host) takt(); else folgen();`. Der Host hat damit
  nur GEMELDET, wo er steht, und nie selbst begonnen. Er meldete
  "laeuft nicht", und alle anderen folgten ihm brav ins Stehen.

Die Messung bricht ab jetzt ab, wenn der Player nicht bei beiden
laeuft. Ein gruener Haken ueber einem Standbild ist wertlos.

DIE WARTESCHLANGE

Vorher gab es genau EIN Videofeld. Wer zwei Sachen hintereinander
schauen wollte, tippte mitten in der Sendung eine YouTube-Adresse ein
-- vor Publikum, mit laufender Kamera, ein Tippfehler von einem
schwarzen Rechteck entfernt. Jetzt wird vorher eingeraeumt und im Live
nur weitergeschaltet: anhaengen, schieben, "Jetzt", "Naechstes".

Die Titel kommen von YouTube selbst (oEmbed, kein Schluessel, kein
Kontingent) und werden EINMAL geholt und hingelegt. Klappt der Abruf
nicht, steht dort die Kennung -- kein erfundener Name. Die Grenze ist
ueber die Umgebung veraenderbar, damit die Pruefung den vollen Fall in
Sekunden erreicht statt dreissig Videos anzuhaengen.

DIE REGIE

Vorher fuenf Kaesten untereinander in einem Bereich, der hoechstens
die halbe Bildschirmhoehe hat -- man sah fuenf halbe Dinge. Die drei
grossen Knoepfe lagen ganz unten, hinter acht Feldern und vier
Reglern. Wer mitten in der Sendung "Beenden" drueckt, drueckt es, weil
etwas passiert ist; das darf nicht hinter einer Bewegung liegen.

  Eine Leiste, die IMMER steht: Lampe, Laufzeit, Zuschauer, wie viele
  davon Bild bekommen, Gaeste, gemessener Upload -- und rechts die
  drei Knoepfe.

  Register statt Stapel: Sendung, Warteschlange, Ton, Gaeste, Bild.

  Eine Videospur mit echter Bedienung: Pause, +/-10 s, Positionsband,
  Restzeit, "Naechstes". Vorher musste man ins YouTube-Bild fassen --
  und was dort passiert, passiert nur bei einem selbst.

  PEGEL an den Reglern, aus einer echten Messung (AnalyserNode). Sie
  beantworten die Frage, die man sich sonst erst nach der Sendung
  stellt: "War mein Mikro ueberhaupt an?" Ein Regler auf 100 sagt
  darueber nichts. Beim YouTube-Regler steht dabei, dass dort nichts
  zu messen ist -- Ton aus einem fremden Rahmen laesst sich nicht
  abgreifen, und ein erfundener Ausschlag waere schlimmer als keiner.

  Der Upload wird an der Verbindung gemessen (`getStats`), nicht aus
  "zwoelf mal 350 kbit/s" gerechnet.

  Tastaturkuerzel -- und die Legende steht darunter. Ein Kuerzel, das
  niemand kennt, ist keins.

VIER FEHLER, DIE NUR DIE MESSUNG GEZEIGT HAT

1. `.tafel` WAR SCHON VERGEBEN. Die Anmeldeseite hat diese Klasse und
   setzt sie `position: absolute`; reaktion.html laedt beide
   Stilvorlagen. Die Register-Tafel trug damit NICHTS zur Hoehe bei
   (114 px Raster, 294 px Inhalt) und malte quer ueber Register und
   Kuerzel -- 197 Pixel, um die die Seite ueberlief. Auf dem Bild sah
   es aus wie ein Anzeigefehler; es war ein Namensstreit. Dritter
   Fall dieser Art nach .knopf-still und .schalter, deshalb steht er
   ab jetzt in einer Pruefung: keine Klasse aus reaktion.css darf in
   gate/start/module/haus.css vorkommen.

2. `node:sqlite` kennt kein `.transaction()`. Von Hand geklammert.

3. Das Schild war auf dem Handy 10,24 px gross -- unter der
   Hausgrenze von 11,5 px. Gefunden von `pruef-handy`, das die
   GEZEICHNETE Groesse misst; die Stilvorlagen-Pruefung haette die
   Zeile in der Medienabfrage durchgelassen.

4. Die Messung klickte blind auf den Griff des Pults ("umschalten")
   und machte es damit ZU, seit es aufgeklappt startet. Sie stellt
   den Zustand jetzt her, statt ihn umzuschalten.

UND DIE HARTNAECKIGSTE: DAS BILD DES GASTES KAM BEIM HOST NICHT AN

Erst in einem von drei Laeufen, dann in drei von drei -- und zwar
SCHLIMMER, nachdem ich einen Wachhund dagegen gebaut hatte. Vier
Ursachen, hintereinander gemessen statt geraten:

  a) `kameraHolen()` wurde beim Host FUENFMAL betreten. Die Wache
     `if (meinStrom) return` wirkt erst, wenn die Kamera DA ist --
     solange die erste Anfrage laeuft, geht jede weitere als zweite
     Anfrage an dasselbe Geraet. Eine blieb liegen, und mit ihr der
     Anruf, der darauf wartete. Der Platz in `ruftGerade` blieb
     belegt, und damit kam nie wieder eine Leitung zustande. Jetzt
     bekommen alle dasselbe Versprechen zurueck.

  b) Der Wachhund riss Leitungen ab, die gerade verhandelt wurden --
     zwischen "Leitung angelegt" und "Angebot abgeschickt" liegen
     drei await.

  c) "Ruf mich an" brach dasselbe ab: Der Bittende weiss nicht, dass
     es schon laeuft, und fragt alle drei Sekunden weiter.

  d) Meine Reparatur von (b) und (c) war "signalingState !== stable
     heisst: in Arbeit" -- ohne Uhr. Damit war eine Leitung, deren
     Antwort nie ankommt, vor BEIDEN Aufraeumwegen sicher, dauerhaft.
     Der Zuschauer bekam daraufhin gar nichts mehr; ich hatte den
     Fehler nur von einer Seite auf die andere geschoben. "Wird
     verhandelt" ist ein Zustand MIT DAUER und steht jetzt an genau
     einer Stelle.

Dazu ein eigener Fehler beim Aufraeumen: Mit der Messspur ist
`ruftGerade` mit herausgefallen. Vier Laeufe ohne jedes Bild -- und
`node --check` sieht das nicht, eine fehlende Variable ist
syntaktisch tadellos.

GEMESSEN

  mess-reaktion   fuenf Laeufe hintereinander ohne Beanstandung;
                  beide Kameras 640 px bei Host UND Zuschauerin,
                  Video laeuft bei beiden, Upload 0,9 Mbit/s,
                  Warteschlange 2 Zeilen mit Vorschaubildern,
                  kein Ueberlauf (4 px statt 197)
  pruef-reaktion  132 Punkte, 0 Fehler (vorher 88)
  pruef-handy     180 Punkte, 0 Fehler
  dazu gruen      css-klassen 33, struktur 35, tippziele 11,
                  meldungen 8, kamera-richtlinie 10

SCHEMA: neue Tabelle `reaktion_liste`, neue Spalte
`reaktion.video_titel` (ALTER TABLE, keine Abschrift der Spalten).
2026-09-28 03:45:15 +02:00
DogFatherGit 85101176d2 Zwei fuehren die Sendung: DogFather und die rechte Hand
Filipe, 28.09.2026: „die rolle dogfather und vanvan sollen alles sehen
und bereit machen auch vorher. nur die zwei sollen alles sehen,
vorbereiten und einschakten koennen."

DREI DINGE AENDERN SICH, UND ZWAR GENAU DIESE DREI

1. VORBEREITEN UND EINSCHALTEN duerfen jetzt beide -- einstellen,
   Vorbereitung, auf Sendung, beenden, Gaeste holen und entfernen,
   stummschalten, Anordnung, Video steuern. Beide dasselbe; es gibt
   hier keinen Ersten und keinen Zweiten. Das ist eine AUFGABE und
   kein Rang: Wer die Sendung fuehrt, bedient die Technik.

2. „ALLES SEHEN" heisst die Namensliste derer, die zusehen. Die
   bekamen bisher auch die linke Hand und die Modis, weil sie
   moderieren duerfen. Das war eine Vermischung zweier Dinge, die
   nichts miteinander zu tun haben: Wer einen Beitrag wegnehmen darf,
   muss deshalb nicht wissen, wer im Saal sitzt. Ab jetzt bekommt die
   Liste nur, wer auf der Buehne steht.

   Die Moderation bleibt unveraendert bei DogFather, beiden Haenden
   und den Modis -- einen Beitrag wegzunehmen ist weder „alles sehen"
   noch „vorbereiten" noch „einschalten", sondern dasselbe, was sie im
   Treff ohnehin tun.

3. WER AUF SENDUNG DRUECKT, IST IM BILD.

   Vorher stand als Host, wer zuletzt etwas eingestellt hatte. Mit
   zwei Leuten, die vorbereiten duerfen, waere das eine Falle: VanVan
   richtet am Nachmittag alles ein, Filipe drueckt abends auf Sendung
   -- und im Bild stuende VanVans Name, waehrend Filipe redet.

   Beim Einstellen wird `host_id` deshalb nur noch gefuellt, wenn
   dort noch niemand steht (damit die Ankuendigung „Als Naechstes"
   jemanden nennen kann). Wer die Sendung FUEHRT, entscheidet sich
   beim Einschalten.

GEPRUEFT IN BEIDE RICHTUNGEN

Nur zu messen, wer darf, hiesse: Die Tuer laesst sich spaeter weit
aufmachen, ohne dass etwas rot wird. pruef-reaktion misst deshalb
auch, wer ausdruecklich NICHT darf -- und dass es genau zwei sind:

  genau zwei fuehren die Sendung: admin, hand
  die rechte Hand darf einstellen / vorbereiten / Anordnung
  linke, modi, gast: duerfen nicht einstellen (403)
  ein Modi holt niemanden dazu (403)
  wer eingeschaltet hat, fuehrt die Sendung (Filipe)
  drueckt die rechte Hand, fuehrt sie (VanVan)
  die rechte Hand sieht, WER dabei ist -- sie fuehrt mit
  linke, modi: moderieren, bekommen die Namensliste aber nicht
  admin/hand: sehen Regiepult -- linke/modi/gast: nicht

Das Regiepult haengt an `ich.host` und an nichts sonst. Ein zweiter
Ort, an dem der Browser dieselbe Frage noch einmal beantwortet, waere
der, der spaeter abweicht -- und dann stuenden Knoepfe da, die mit 403
antworten.

pruef-reaktion 74 -> 88 Punkte, 0 Fehler. Dazu gruen: meldungen 8,
rechtetafel 19, verborgen 25, modi-verborgen 85.
2026-09-28 02:01:32 +02:00
DogFatherGit 5d89d108f9 Die Reaction: zusammen schauen, live, mit Kamera und Chat
Filipes Kurznotiz vom 28.09.2026, von links nach rechts:

    Kachel sichtbar -> geschlossen -> Vorbereitung -> Wartebereich/
    Chat -> Countdown -> LIVE -> Reaction + Gaeste + Chat + PayPal
    -> Ende

DREI STAENDE, NICHT SIEBEN

„Wartebereich" und „Countdown" sind keine eigenen Zustaende, sondern
das, was „Vorbereitung" auf dem Bildschirm TUT. Drei Staende, die
sich gegenseitig ausschliessen, sind pruefbar; sieben, von denen sich
vier ueberlappen, sind es nicht.

DAS VIDEO LAEUFT NICHT UEBER DIESEN SERVER

Naheliegend waere: Der Host spielt ab, alle sehen seinen Bildschirm.
Das waere aus zwei Gruenden falsch. Rechtlich ist ein
weitergesendetes YouTube-Video eine oeffentliche Wiedergabe -- genau
die Sache, fuer die Kanaele gesperrt werden. Und technisch kostet es
Bandbreite und Qualitaet.

Jeder Zuschauer laedt das Video deshalb SELBST. Uebertragen wird nur
der Spielstand: Kennung, laeuft/pausiert, Sekunde. Das sind ein paar
Byte, jeder sieht es in voller Qualitaet, und alle sind auf derselben
Sekunde. Nachgefuehrt wird erst ab anderthalb Sekunden Abweichung --
ein Player, dem man jede Sekunde eine neue Position gibt, ruckelt
sichtbar.

DIE KAMERAS LAUFEN DIREKT VON MENSCH ZU MENSCH

Ueber denselben Weg wie die Anrufe im Haus (seit 18.09.), nur mit
mehr Empfaengern. Das hat eine Grenze, und sie ist gerechnet, nicht
geraten: Bei 360p und rund 350 kbit/s sind zwoelf Zuschauer etwa
4 Mbit/s Upload beim Host. Darueber schaltet die Sendung von selbst
auf Ton um -- wer keine Kamera mehr bekommt, hoert alles, sieht das
Video und kann schreiben. Ehrlicher als eine Verbindung, die stockt,
und sichtbar im Regiepult.

Heute sind es elf Menschen im ganzen Haus (gemessen: 1 admin, 1 hand,
1 linke, 4 modi, 4 gast). Die Grenze ist weit weg -- sie steht
trotzdem drin, weil sie sonst erst auffaellt, wenn es zu spaet ist.

DIE SEITE IST ANDERS GEBAUT ALS JEDE ANDERE IM HAUS

Ueberall sonst: Kacheln, Karten, Listen -- man liest, entscheidet,
geht wieder. Hier sitzt man. Eine Stunde, mit anderen, auf EINE
Sache schauend. Deshalb kein Raster, sondern ein SAAL: grosse Flaeche
fuer das Video, Kamerabilder als schwebende Fenster darueber, der
Chat als Schiene daneben. Die Seite scrollt nicht -- ein Video, das
beim Tippen im Chat nach oben rutscht, ist der schnellste Weg, dass
jemand aufhoert zu schreiben.

Fuer den Host ein REGIEPULT: vier senkrechte Regler nebeneinander wie
an einem Mischpult, darueber die Sendung, daneben Gaeste und
Anordnung, unten drei grosse Knoepfe. Es SCHIEBT den Saal, es deckt
ihn nicht zu.

Die Kachel traegt ihren Zustand als Farbe: grau geschlossen,
bernstein in Vorbereitung, rot auf Sendung. Keine Ton-Nummer -- der
Farbraum ist bei 46 voll, und sie braucht auch keine.

PAYPAL: EINE QUELLE

Der Knopf nimmt den Weg, der auf der Unterstuetzen-Seite hinterlegt
ist -- derselbe Eintrag, dieselbe Pflege. Ist dort nichts eingetragen
oder steht er auf unsichtbar, erscheint hier kein Knopf. Eine
geratene Adresse ist an dieser Stelle die gefaehrlichste aller
Abkuerzungen.

=======================================================================
ACHT FEHLER, DIE OHNE MESSUNG LIVE GEGANGEN WAEREN
=======================================================================

1. `data-live` WAR SCHON VERGEBEN. Die Draussen-Kachel bekommt es,
   sobald Filipe auf Twitch sendet. Meine Regel haette ihr waehrend
   jedes Streams die Farbe genommen -- genau dann, wenn sie wichtig
   ist. Heisst jetzt `data-sendung`, und pruef-reaktion haelt beides
   auseinander.

2. DIE INHALTSRICHTLINIE HAETTE YOUTUBE LAUTLOS GESPERRT. Die Datei
   warnt an genau dieser Stelle selbst davor: Am 27.08.2026 hat
   `frame-src 'none'` den Musik-Knopf stillgelegt -- der Knopf
   reagierte, das Feld ging auf, und wo die Player sein sollten,
   blieb es leer. Hier waere das Ergebnis eine schwarze Leinwand vor
   Publikum gewesen. youtube-nocookie.com fuer den Rahmen (setzt keine
   Werbekennungen), www.youtube.com fuer die Einbett-API,
   i.ytimg.com fuer die Vorschaubilder.

3. KAMERA UND MIKROFON WAREN GESPERRT. Dieselbe Falle, vor der
   index.js selbst warnt -- und die am 18.09. schon einmal zugeschlagen
   hat. Die Ausnahme ist jetzt eine benannte MENGE statt eines zweiten
   Sonderfalls, und pruef-kamera-richtlinie.mjs haelt sie GEGEN DEN
   QUELLTEXT: Welche Seite laedt ein Skript, das getUserMedia
   aufruft? Genau die muss drinstehen -- und keine andere. Eine
   Liste, die abgeleitet wird, kann nicht veralten.

4. ZWEI ANRUFE AN DIESELBE PERSON. Zwischen `await kameraHolen()` und
   dem Anlegen der Verbindung laeuft alles andere weiter; jeder Takt
   sagte wieder „den kenne ich noch nicht". Der Empfaenger antwortete
   auf beide Angebote, und die zweite Antwort traf eine Verbindung,
   die laengst stand.

5. DAS ANGEBOT GING HINAUS, BEVOR DER EMPFAENGER ZUHOEREN KONNTE.
   Gemessen:

       [spur] an [3] reaktion_signal | offen: [2,1]
       ...
       [spur] Strom auf fuer 3 Lenny

   Die Anmeldung ist ein gewoehnlicher Abruf und sofort durch, der
   Ereignisstrom eine stehende Verbindung. Der Host erfaehrt vom
   Neuankoemmling also zuverlaessig, BEVOR der zuhoeren kann.
   Die Richtung ist jetzt umgedreht: Wer bereit ist, BITTET um den
   Anruf -- er ist der Einzige, der das sicher weiss. Dazu ein
   eigener, schneller Takt (2,5 s) und eine Ruecknahme, wenn ein
   Angebot bei niemandem ankommt.

6. EIN VIDEO MIT TON STARTET NICHT VON ALLEIN. `videoWidth` war 640,
   das Bild kam also an -- und das Fenster blieb schwarz. Kein
   Fehler, keine Meldung, es passiert einfach nichts. Die Kameras
   starten jetzt stumm (stumm darf losgehen), ein Knopf schaltet den
   Ton frei, und die erste Beruehrung der Seite tut es ohnehin.

7. DIE LADE AM HANDY GING NICHT AUF. Gemessen: ein 390x775 grosser
   Saal mit 219 px Video und 556 px Leere darunter. Statt den Knopf
   zu reparieren, ist die Lade weg -- unter Kopfleiste und Video
   bleiben auf einem Telefon rund 550 px, das ist mehr Chat, als eine
   Lade je zeigen wuerde. Ein Zustand weniger ist besser als ein
   Zustand, der funktioniert.

8. `sendBeacon` KANN NUR POST. Beim Schliessen des Fensters wird ein
   gewoehnlicher Abruf abgebrochen; mein DELETE waere nie angekommen,
   und jeder haette zwei Minuten lang als anwesend gegolten.

Dazu drei Funde der Hauspruefungen, alle von mir verursacht:
17 Schriftgroessen unter der Lesbarkeitsgrenze von 11,5 px, elf
Maschinenworte ohne deutschen Satz, und ein Aufbewahrungseintrag ohne
Rechtsgrundlage.

=======================================================================

GEMESSEN

pruef-reaktion            74 Punkte, 0 Fehler (11 Abschnitte)
pruef-kamera-richtlinie   10 Punkte, 0 Fehler (neu, abgeleitet)
mess-reaktion             beide Kameras kommen an, 640 px, laufen --
                          beim Zuschauer UND beim Host. Diese Messung
                          hat einen Rueckgabewert: Alles andere kann
                          gruen sein, und trotzdem sitzt jeder vor
                          einem schwarzen Rechteck.
pruef-handy               180 (vorher 177), pruef-notizen 79,
pruef-aufbewahrung        45, pruef-meldungen 8, pruef-css-klassen 33,
pruef-struktur            35, pruef-crew-adresse 161,
pruef-haus-trennung       100, pruef-start-ansicht 160 -- alle 0 Fehler.
2026-09-28 01:52:22 +02:00
DogFatherGit 6261d548d0 Die Einblendung nimmt die Farbe des Bereichs an, in dem sie steht
Filipe, 27.09.2026: „nimm dann doch die seiten vom community bereich
ne?"

Er hatte recht, und es war derselbe Fehler noch einmal. Beim ersten
Mal stand die Buehne in einer Farbe aus einem fremden Bereich
(#9cde90, die Notizen-Kachel aus dem Team). Beim zweiten Mal stand
sie in EINER Farbe fuer alles -- und jeder Bereich des Treffs hat
seine eigene:

    Rudel-Chat     #5499ff        Wunschliste    #abff96
    Highlights     #f60684        Dogi-Media     #918a01
    Anschlagbrett  #ffabff        Mitmachen      #577ecc
    Was ansteht    #2dc9ba        Unterstuetzen  #e76006

Ein Video ueber Dogi-Media mit violetten Einblendungen sind zwei
Sachen nebeneinander. Mit der Farbe des Bereichs ist es eine.

ABGELESEN, NICHT ABGESCHRIEBEN

Die Buehne fragt nach jedem Seitenwechsel
`getComputedStyle(document.body).--ton` -- genau den Wert, den die
Seite selbst benutzt. Eine Liste hier waere eine zweite Wahrheit, die
irgendwann von der ersten abweicht; tools/treff-farben.mjs liest
dieselben zwei Quellen (workspace.js fuer die Nummer, start.css fuer
den Farbwert), wenn man sie nachsehen will.

AUFGEHELLT, BIS ES LESBAR IST

#918a01 ist als Flaeche schoen und als Schrift auf dunklem Grund
unlesbar (1,9:1). Die Buehne mischt Weiss dazu, bis 4,5:1 erreicht
sind -- dieselbe Rechnung wie bei den Namen im Chat. Balken, Schein
und Vorhang bekommen den rohen Ton, die brauchen keinen Kontrast.

DER ABSPANN BLEIBT MARKE

Er ist in allen vier Videos derselbe und faellt deshalb auf
--violett/--akzent zurueck, egal auf welcher Seite er steht. Wer drei
Videos gesehen hat, soll den vierten am Schluss wiedererkennen.

UND EIN EIGENER FEHLER, GEMESSEN STATT UEBERSEHEN

Das Ablesen stand zuerst in `auf()` -- und `auf()` laeuft vor jeder
Karte, jedem Untertitel und jedem Rollen. Ueber hundert zusaetzliche
Wege in den Browser fuer eine Antwort, die sich nur beim
Seitenwechsel aendern kann. Video 1 wuchs dadurch von 32,9 auf
36,1 s. Jetzt wird beim Seitenwechsel gelesen: 32,0 s.

Alle vier neu gedreht: 24 bis 34 s, 1080x1920.
2026-09-27 19:37:06 +02:00
DogFatherGit a28a8ea2e3 Die Buehne der Videos ist gestaltet statt hingestellt
Filipe, 27.09.2026: „die graphik sieht scheisse aus und so. mach das
hoch profissionel und nicht so eine halbe geschissene scheisse."

Er hat recht gehabt, und der Grund war nicht Geschmack.

DIE FARBE GEHOERTE NIRGENDWO HIN

Karten und Untertitel standen in #9cde90 -- das ist der Ton der
NOTIZEN-Kachel aus dem Teambereich. In diesen Videos ist die
Community-Seite zu sehen, und die laeuft auf --violett #a98bff und
--akzent #8ec9ff ueber --tinte #07060f (crew-haus.css). Eine
Einblendung in einer Farbe, die im Bild gar nicht vorkommt, sieht
immer aufgeklebt aus, egal wie sauber sie gebaut ist. Das war der
eigentliche Befund; alles andere kam obendrauf.

WAS JETZT STEHT

Die Karte: Zierzeile „- TEAM DOGI -" wie ueber dem Titel in der App,
Ueberschrift mit ausgeglichenen Zeilen, langsame Kamerafahrt von drei
Prozent ueber zweieinhalb Sekunden, feines Korn gegen Streifen in
dunklen Flaechen. Der Abspann bekommt eine eigene hellere Flaeche und
einen Strich -- er ist das Einzige, was der Mensch danach noch tun
soll.

Der Untertitel: Glasflaeche mit Farbstreifen links. Rechts bleiben
17 % frei, dort liegt auf TikTok die Knopfreihe; unten bleibt Platz
fuer Beschreibung und Ton. Vorher war es ein graues Kaestchen mit
gruenem Rand ueber die ganze Breite.

Der Vorhang: Jeder Seitenwechsel laeuft dahinter. Vorher war jeder
Wechsel im Bild -- „Eintraege werden geladen ...", halb aufgebaute
Raster, ein kurzes Aufblitzen. Zusammen sah das nach
Bildschirmaufnahme aus und nicht nach Film.

EINE FUNKTION STATT EINER ZEICHENKETTE

Die Buehne war ein Text, der im Browser ausgewertet wurde, und darin
noch ein Text fuer das Stilblatt -- zwei Ebenen Anfuehrungszeichen, in
denen jedes Backtick von Hand entschaerft werden musste. Dabei ist
jede zweite Aenderung kaputtgegangen. Playwright nimmt auch eine echte
Funktion und reicht ein Argument durch; die ganze Schicht faellt weg.

VIER FEHLER, DIE NUR DAS EINZELBILD GEZEIGT HAT

  1. WAISEN IN DER ZEILE. „Ein Kommentar ist nach / nach / drei
     Sekunden weg." -- ein von Hand gesetztes <br> traf eine Zeile,
     die ohnehin umbrach. Ein Umbruch, den jemand vor drei Tagen
     gesetzt hat, weiss nichts von der Schriftgroesse von heute.
     `text-wrap: balance` rechnet ihn aus; die elf Handumbrueche
     sind weg.
  2. DER STRICH UNTER DEM ABSPANN WAR NIE ZU SEHEN. Er steht in
     einem <span>, und ein span ist inline -- Hoehe, Breite und
     margin:auto gelten dort nicht. Gebaut, unsichtbar, und ohne das
     Bild haette ich weiter geglaubt, er sei da.
  3. DER VORHANG GING ZU FRUEH AUF, dreimal aus drei Gruenden. Erst
     standen 700 ms -- eine Zahl. Dann eine einmalige Frage „steht
     irgendwo, dass geladen wird?" -- und die traf den Moment, BEVOR
     die Seite ihren Ladehinweis gezeichnet hatte. Dann 450 ms Ruhe
     -- zu kurz, weil eine Seite ihre Abschnitte nacheinander laedt
     und es zwischen zweien kurz still ist. Jetzt: 650 ms am Stueck
     ohne Hinweis, ein Aufflackern setzt die Uhr zurueck.
  4. DAS LEUCHTEN AUF DEN BLAUEN WOERTERN war zu breit und hat die
     Buchstabenkanten gefressen; im Video wurde daraus Matsch.

NICHT `networkidle` ABGEWARTET, UND ZWAR ABSICHTLICH: Der Chat haelt
einen Ereignisstrom offen, der nie endet. Ein Warten darauf liefe dort
immer in die Frist und haenge jedem Seitenwechsel neun Sekunden an --
dieselbe Falle wie am 06.09.2026 bei `await antwort.text()` auf einen
Stream.

Alle vier Videos neu gedreht: 1080x1920, 24 bis 33 s, Lecksuche
unveraendert scharf.
2026-09-27 19:05:48 +02:00
DogFatherGit d465c89289 Ein Werkzeug, das abstuerzt, soll abstuerzen
Das Videowerkzeug hat zweimal zwoelf Minuten lang an nichts
gearbeitet. Es war nicht langsam, es war tot: Beim Fuellen des
Medienregals warf es 'no such table: material', und index.js faengt
uncaughtException ab und protokolliert nur. Fuer den Betrieb ist das
richtig -- ein Fehler in einer Nebensache darf die Website nicht
offline nehmen. Wer die Datei importiert, erbt das Netz, und der
laufende HTTP-Server haelt den Prozess danach am Leben.

Von aussen sieht das aus wie 'rechnet noch'. Ein Stillstand ist
schlimmer als ein Fehlschlag: Ein Fehlschlag ist rot und steht da.

Genau diese Falle steht seit dem 06.09.2026 in den Projektregeln
('Auffangnetze im Betrieb sind Fallen in der Pruefung'), und ich bin
trotzdem hineingelaufen -- weil ich das Werkzeug nicht als Pruefung
verbucht habe, sondern als Werkzeug. Der Unterschied ist keiner:
Entscheidend ist, wer index.js importiert.

process.on ERGAENZT, es ersetzt nicht. Die Meldung von index.js kommt
weiterhin, danach endet der Lauf mit Rueckgabewert 8.

Beide Richtungen nachgefahren: PROBE_ABSTURZ=ja endet sofort mit 8,
ein normaler Lauf endet mit 0 und einem fertigen Video. Ein Netz, das
man nie hat reissen sehen, ist eine Hoffnung.
2026-09-27 18:46:53 +02:00
DogFatherGit de4a9d0771 Der Commit-Text gehoert nicht ins Verzeichnis
Beim Committen mit -F landet die Textdatei ueber 'git add -A' selbst
im Stand. Sie ist Arbeitsmaterial wie die Drehprotokolle und die
Sammellaeufe -- alle drei stehen jetzt in .gitignore.
2026-09-27 18:34:46 +02:00
DogFatherGit cf6c72b3d8 Beim Laden stand "SPICY MEDIA - Zentrale" auf jeder Startseite
WAS DAS BILD GEZEIGT HAT

Beim Durchsehen der Einzelbilder einer Videoaufnahme -- vier
Sekunden lang, gleich nach dem Laden:

    ---- SPICY MEDIA ----
         Zentrale
       WIRD GELADEN

Und zwar auf der Startseite eines COMMUNITY-MITGLIEDS.

In start.html steht die Vorgabe des Agenturhauses. Das Teamhaus
bekommt eigene Worte ("Team Dogi" / "Die IrrenAnstalt"), aber erst
wenn /api/ich geantwortet hat. Bis dahin las jeder Modi und jedes
Community-Mitglied die Marke der Agentur in der groessten Schrift
der Seite. Auf einem langsamen Telefon sekundenlang, bei jedem
Aufruf.

Das ist kein Schoenheitsfehler. Spicy Media ist der Betrieb hinter
der Agentur, und seit dem 24.09. sind die beiden Haeuser getrennt.
Genau diese Zeile hat die Trennung bei jedem Seitenaufruf kurz
aufgehoben -- und niemandem ist es aufgefallen, weil die Seite
DANACH richtig aussah. Wer hinsieht, sieht den Endzustand.

GELOEST OHNE SPRUNG

`data-wartet` macht die zwei Zeilen durchsichtig, nicht leer -- der
Platz bleibt stehen, es ruckt nichts. start.js nimmt das Merkmal
weg, sobald es weiss, in welchem Haus es ist; gemessen dauert das
351 ms.

Eine Notbremse in der Seite nimmt es nach vier Sekunden notfalls
selbst weg. Ohne sie waere die groesste Schrift der Seite fuer immer
unsichtbar, falls start.js gar nicht erst laeuft -- und "unsichtbar"
waere schlimmer als das falsche Wort.

DIE PRUEFUNG DAZU -- UND ZWEI MESSFEHLER DARIN

pruef-start-ansicht misst ab jetzt beide Richtungen: nach dem Laden
muessen beide Zeilen sichtbar sein, mit gesetztem `data-wartet`
unsichtbar. Ohne die zweite Haelfte koennte die Regel spurlos
verschwinden, ohne dass etwas rot wird.

Die Pruefung selbst hat mich zweimal getaeuscht, und beide Male
lehrreich:

  1. Sie mass 900 ms nach der Anmeldung -- eine feste Pause. Ob
     /api/ich in dieser Zeit geantwortet hat, haengt vom Rechner ab.
     Dieselbe Pruefung war einmal gruen und einmal rot, bei
     unveraendertem Code. Gewartet wird jetzt auf das Merkmal selbst,
     und wie lange es gedauert hat, steht im Meldetext.

  2. `opacity` hat einen Uebergang von 180 ms, und getComputedStyle
     liefert waehrenddessen den laufenden Zwischenwert statt des
     Ziels. Erst meldete die Gegenprobe "nicht verdeckt", dann die
     Messung davor "nicht sichtbar" -- beide Male war die Regel in
     Ordnung und nur die Animation im Weg. Fuer die Messung wird der
     Uebergang jetzt abgeschaltet.

DAS VIDEOWERKZEUG

server/tiktok-videos.mjs nimmt die vier Clips auf. Sechs Aenderungen,
jede aus einem Einzelbild:

  - DIE NACHTRUHE HAT DIE VORBEREITUNG MITBLOCKIERT. Video 2 zeigte
    einen leeren Chat. Gemeldet wurde "gefuellt", weil nur geprueft
    war, dass es den RAUM gibt. Jetzt werden die Nachrichten
    zurueckgelesen und gezaehlt; unter acht wird nicht gefilmt.
  - DOGI-MEDIA WAR LEER -- ein Video ueber Material zum Mitnehmen,
    und auf dem Bildschirm stand "Gerade ist nichts frei". Sechs
    echte Marken-Bilder werden eingestellt, zwei davon schon
    genommen, damit die Aussage des Films auch im Bild steht.
  - "WILL ICH AUCH - 0" an jedem Wunsch, waehrend der Untertitel
    sagte "die anderen sehen, wer mitwill". Ein Versprechen, das das
    Bild gleich wieder einkassiert, ist schlimmer als ein leeres
    Brett. Jetzt wird ueber die echte Route gestimmt, absteigend
    6/5/4 -- unter zehn Stimmen wird nicht gefilmt.
  - DER WAECHTER FUER VIDEO 2 verglich zwei feste Zahlen
    (TREFF_NACHT_AB === "0"). Das ist die Abschrift einer Einstellung
    und keine Frage nach dem Zustand: Jedes andere Fenster, das den
    Chat genauso schlafen legt, wurde abgewiesen. Gefragt wird jetzt
    `istNachtruhe()` -- dieselbe Funktion, die auch die Seite
    befragt. Mit 12 bis 6 steht im Bild "Ab 06:00 Uhr geht es
    weiter" statt "Ab 24:00 Uhr", und das ergibt fuer einen
    Zuschauer ueberhaupt erst Sinn.
  - ROLLEN IM KASTEN STATT IN DER SEITE. `window.scrollBy` bewegt
    die Seite; im Chat rollt aber der Verlauf in seinem eigenen
    Kasten. Drei Bilder hintereinander sahen gleich aus.
  - EINE FESTE PIXELZAHL TRAF DEN FALSCHEN BLOCK. Video 4 filmte
    den Katalog der fertigen Vorschlaege statt der Wuensche, weil
    "480 nach unten" zufaellig dort endete. `b.zu(wahl)` misst, wo
    das Element steht.

Dazu: Umlaute in allen Bildtexten ("Tueren" stand im Video), der
Abspann bleibt am Ende stehen (vorher sah man die letzte Sekunde
wieder die App), und die Dateigroessen im Regal sind echt.

KEIN LINK, UND ZWAR GEMESSEN

Nach jedem Seitenwechsel wird der SICHTBARE Text nach Adressen
abgesucht -- dogfather-universe, https://, www., jeder Domainname.
Bei einem Fund bricht die Aufnahme ab, und es wird keine Datei
geschrieben. Das mit dem Auge zu pruefen waere genau die Sorte
Kontrolle, die beim vierten Video nachlaesst.

Mit PROBE_LECK=ja schiebt die Suche selbst eine Adresse ins Bild --
nachgefahren, Rueckgabewert 2. Eine Suche, die nur "nichts gefunden"
sagen kann, hat nichts bewiesen.

Gemessen: pruef-start-ansicht 160/0 (vorher 157), pruef-buehne
242/0, pruef-handy 177/0, pruef-kachelraster 24/0,
pruef-css-klassen 33/0.
2026-09-27 18:34:10 +02:00
DogFatherGit 9c45cdc218 Drei Pixel breite Kacheln auf kleinen Handys -- und der Block war auf
der Pruefadresse tot

DER RASTERFEHLER

Auf einem 320 px breiten Geraet waren "Rudel-Chat" und "Anschlagbrett"
DREI PIXEL breit: ein senkrechter Strich mit abgeschnittenem Text. Bei
360 px waren es 43 px. Gefunden habe ich es nicht mit einer Pruefung,
sondern mit dem Auge, in einem Einzelbild einer Videoaufnahme.

Die Ursache stand in start.css: Unter 380 px wird das Kachelraster
einspaltig (`grid-template-columns: 1fr !important`), die
Willkommenskachel behielt aber ihr `grid-column: span 2` aus einem
Block, der 2600 Zeilen spaeter steht und deshalb gewinnt. Ein Gitter
mit einer erklaerten Spalte und einem Kind, das zwei braucht, erfindet
die zweite -- und teilt den Platz 3 zu 281.

WARUM ES KEINE PRUEFUNG GEMERKT HAT, und das ist der eigentliche
Befund: pruef-handy misst Ueberhang und Beruehrziele. Eine 3 px breite
Kachel ragt nicht hinaus, und ihr Link ist 142 px HOCH -- die
Mindestgroesse fuer den Finger war also erfuellt. Beide Pruefungen
waren gruen, und die Kachel war unbenutzbar.

pruef-kachelraster misst deshalb ab jetzt die BREITE jeder Kachel
mit, bei 320, 360 und 390 px. Die Grenze ist abgeleitet und nicht
gesetzt: Eine Kachel muss mindestens ein Drittel der Inhaltsbreite
haben -- schmaler waere sie auch bei drei Spalten nicht. Dazu wird
gezaehlt, wie viele Spuren das Gitter wirklich hat; eine erfundene
Spalte faellt damit auf, bevor jemand sie sieht.

Gegenprobe gefahren: Ohne die neue Regel meldet die Pruefung
"320 px: schmalste Kachel 3 px -- Rudel-Chat 3px, Anschlagbrett 3px"
und wird rot. 15 -> 24 Punkte, 0 Fehler.

DER NOTIZBLOCK AUF DER PRUEFADRESSE

pruef-handy meldete auf notizen.html einen 404 in der Konsole, auf
allen drei Geraetebreiten. Kein Anzeigefehler: Die Seite lud, der
Block blieb leer.

Meine Schranke fragte `haus !== "crew"`. Das klingt richtig und ist es
nicht -- auf einer Pruefadresse (127.0.0.1) hat niemand ein Haus,
`person.haus` ist dort absichtlich `null`, damit die Pruefungen des
Hauses nicht still blind werden. Damit antwortete JEDER Aufruf des
Blocks dort mit 404.

hausWo() in workspace.js macht es seit dem 24.09. richtig herum: Ist
das Haus weder crew noch agentur, wird NICHT gefiltert. Die Schranke
folgt jetzt derselben Regel und weist das ANDERE Haus ab statt "alles
ausser crew". Die Trennung bleibt unveraendert scharf.

pruef-notizen misst ab jetzt BEIDE Enden -- auf `workspace.` 404, auf
der Pruefadresse 200. Wer nur eins misst, kann die Schranke jederzeit
wieder zu scharf stellen, ohne dass etwas rot wird. 76 -> 79 Punkte.

DAS WERKZEUG FUER DIE VIDEOS

server/tiktok-videos.mjs nimmt vier Clips ueber die App auf (eigene
Wegwerf-Datenbank, eigener Port, nie die echte). Eingebaut ist eine
Lecksuche: Nach jedem Seitenwechsel wird der SICHTBARE Text nach
Adressen abgesucht, und bei einem Fund bricht die Aufnahme ab. Filipe
am 27.09.: "es darf kein link zu sehen sein." Das mit dem Auge zu
pruefen waere genau die Sorte Kontrolle, die beim vierten Video
nachlaesst. Mit PROBE_LECK=ja laesst sich zeigen, dass sie anschlaegt
-- nachgefahren, Rueckgabewert 2.

Gemessen: pruef-handy 177/0 (vorher 3 Fehler), pruef-kachelraster
24/0, pruef-notizen 79/0, pruef-start-ansicht 157/0,
pruef-handy-teamdogi 0 Befunde.
2026-09-27 17:34:16 +02:00
DogFatherGitandClaude Opus 5 150555bc33 Der Notizblock -- und eine Pruefung, die zwoelf Kacheln nie angesehen hat
Filipe: „fuer die modis, rechte und linke hand und dogfather eine
kachel hinzufuegst, sie soll: Notizen, heissen. ich will dass du das
auch wie ein notizblock erstellst. ich will dass es uebelst geil und
einzigartig ist."

=================================================================
TEIL 1: DIE FARBE -- UND WAS DABEI AUFFIEL
=================================================================

Fuer die neue Kachel braucht es einen Ton. Beim Suchen fiel auf, dass
tools/kachelton-entzerren.mjs zwoelf der 45 Farben fuer FREI hielt.

Sie sind es nicht. bereicheFuer() gibt fuer die fuenf Rollen des
Agenturhauses null zurueck -- das heisst „nimm die Liste aus dem
Browser", und die steht in workspace/assets/js/bereiche.js. Dort
stehen die Toene 1 bis 22 und 44: Dashboard, Zahlen, Team-Lage,
Scout-Pipeline. Kacheln, die jeden Tag jemand ansieht.

pruef-kachelfarben hatte denselben blinden Fleck. Sie meldete seit
Wochen „33 benutzte Toene" und war gruen. Was sie dadurch NICHT sah:

  * Der Farblauf von gestern Nacht hat zwoelf dieser Kacheln
    verschoben und drei davon unter die Buntheitsgrenze gedrueckt.
    Gruen geblieben.
  * Ton 7, 16 und 22 lagen SEIT JEHER unter der Grenze (0,112 / 0,116
    / 0,068). Nie gemeldet.

Das ist die Sorte gruener Haken, vor der die Hausregel warnt: Er sagt
nur, dass die Bedingung erfuellt war -- nicht, dass sie das Richtige
angesehen hat.

BEHOBEN, und zwar an der Wurzel: Die REGELN (Kontrast, Buntheit)
gelten jetzt fuer jeden Ton, der irgendwo an einer Kachel steht --
gelesen aus denselben fuenf Dateien, die auch pruef-kachel-universum
liest. Dazu die Namen der Kacheln, damit „Ton 1 traegt Dashboard"
ueberhaupt pruefbar ist.

DIE PALETTE WURDE NEU GERECHNET, mit dem dritten Verfahren an einem
Tag -- die ersten zwei stehen als Fehler im Kopf des Werkzeugs:

  1. Alle 45 neu verteilt. Lief ueber zwei ausdrueckliche Wuensche
     hinweg (#ff1a1a, #a8d8ff).
  2. Nur die Kollisionen, aber immer nur EINEN der beiden bewegt.
     Ergebnis: Ton 1 sprang vom Tuerkis ins Altrosa, 0,197 weit.
  3. BEIDE duerfen sich bewegen, und zwar beide nur ein bisschen.
     Zwei Toene, die 0,02 auseinanderstehen und 0,09 brauchen, teilen
     sich das -- jeder rueckt 0,045, und beide bleiben, was sie waren.

  kleinster Abstand   0,0154  ->  0,0905
  zu blass                 4  ->  0
  sichtbar veraendert           7 Kacheln (ueber 0,05)
  kaum zu sehen                28 (13 zwischen 0,02 und 0,05, 15 darunter)

EINE AUSNAHME MIT ZAHL, keine mit Achselzucken: Ton 1 (Dashboard)
bleibt acht Tausendstel unter der Buntheitsgrenze. Gemessen ueber ALLE
16,7 Millionen sRGB-Farben ist die naechste, die alle Regeln haelt,
#7a75c8 -- ein Blauviolett, 0,113 entfernt. Tuerkis erreicht in sRGB
schlicht keine hoehere Buntheit, und das schmale Band teilen sich
schon sieben Toene. Eine Kachel, die ihre Farbfamilie behaelt, ist die
bessere Antwort auf „richtig geil und speziell" als eine, die acht
Tausendstel bunter ist und niemand wiedererkennt. blassBis sagt jetzt
bei jeder Ausnahme, WIE WEIT sie reicht -- vorher hiess blassErlaubt
schlicht „hier wird weggesehen".

DIE NEUE FARBE IST GRUEN UND WOLLTE BERNSTEIN SEIN. Gesucht war die
Farbe von Papier. Gemessen gibt es sie nicht mehr: Der beste Bernstein
im ganzen Farbraum haelt 0,0799 Abstand -- unter der Hausgrenze. Und
Platz schaffen hilft nicht: Setzt man ihn fest, muss ein warmer Ton
das Band verlassen (Ton 45 waere 0,212 weit ins Magenta gewandert).
Die groesste wirklich freie Luecke liegt im Gruen, bei 0,0917. Ein
linierter Block in Gruen ist Papier, seit es Papier gibt.

=================================================================
TEIL 2: DER BLOCK
=================================================================

DREI ENTSCHEIDUNGEN, AUS DENEN DER REST FOLGT:

1. ES GIBT KEINEN SPEICHERN-KNOPF. Nirgends. Wer einen Block
   aufschlaegt und lostippt, drueckt hinterher nicht auf „sichern";
   er klappt ihn zu. Gesichert wird 800 ms nach dem letzten
   Tastendruck. Geht das nicht, bleibt der Text im Browser liegen und
   wird nachgereicht -- und der Fuss sagt ehrlich „noch nicht
   gesichert", statt einen Verlust zu melden, den man gerade nicht
   verhindern kann.

2. DAS BLATT IST EIN SCHREIBFELD MIT EINER DECKSCHICHT. Das Feld
   traegt Text und Cursor und ist unsichtbar; darueber zeichnet eine
   zweite Schicht denselben Text noch einmal -- mit Kaestchen,
   Ueberschriften, Strichen und Links.

   DARAUS FOLGT EINE EISERNE REGEL, und sie steht dreimal im Code:
   KEINE Auszeichnung darf die BREITE eines Zeichens aendern. Kein
   Fettdruck, keine andere Groesse, keine Sperrung. Erlaubt sind nur
   Farbe, Flaeche, Rahmen und Durchstreichen. Ein einziges
   font-weight: 700 verschoebe den Umbruch, und ab der zweiten Zeile
   stuende der sichtbare Text neben dem Cursor.

   pruef-notizen misst das am echten Umbruch: eine Probe mit allen
   Auszeichnungen und einer Zeile, die umbrechen MUSS. Sind beide
   Schichten verschieden hoch, sitzt der Umbruch woanders. Mit
   Gegenprobe -- Fettdruck auf der Deckschicht bricht die Deckung um
   genau eine Zeile (30 px), und die Zeile wird rot.

3. DIE TASTATUR FUEHRT DIE LISTE FORT, NICHT EINE LEISTE. Ein
   Spiegelstrich und Enter macht den naechsten Punkt, ein leeres
   Kaestchen und Enter das naechste Kaestchen -- und ein GESETZTER
   Haken wird dabei nicht mitgenommen, die naechste Aufgabe ist ja
   noch nicht erledigt. Zweimal Enter beendet die Liste. Ein Klick
   aufs Kaestchen hakt ab. Es gibt keine Werkzeugleiste, weil man beim
   Schreiben nie den Stift wechselt.

UND: NIEMAND SIEHT DIE NOTIZEN EINES ANDEREN. Auch DogFather nicht.
Es gibt in workspace-notizen.js keinen siehtAlles()-Zweig, keinen
Umschalter, keine fremde Liste -- jede Abfrage hat person_id = ? fest
eingebaut. Die Kachel steht deshalb in „Fuer dich" und nicht in
„Taeglich": Die Gruppe sagt die wichtigste Eigenschaft, bevor man sie
anfasst.

NUR AUF DER TEAM-ADRESSE. Auf der Agenturadresse ist die Seite ein
404 -- auch fuer DogFather. Das ist dieselbe Trennung wie bei Chat,
Kalender und Aufgaben, und sie steht an zwei Stellen: in
GEHOERT_ZU_ADRESSE (die Datei) und in der Schnittstelle (die Daten).
Die Seite ist nur HTML; die Daten sind die Sache.

Dazu: sechs Papierfarben, Anheften, Suche mit Hervorhebung im Text,
Papierkorb mit dreissig Tagen und einem Eintrag in der
Aufbewahrungsliste (ohne den waere die Frist ein Satz in einem
Kommentar -- genau das ist dem Support am 24.09. passiert).

=================================================================
EIN FUND BEIM BAUEN, DER ALLEN GEHOERT
=================================================================

DELETE /workspace/api/notizen/:id gab es schon -- in
workspace-aufgaben.js, fuer die Notizen AN einer Aufgabe. Weil jener
Router frueher eingehaengt ist, hat er jeden Loeschversuch des Blocks
abgefangen und mit 404 beantwortet.

Von aussen sah das aus wie ein Fehler im neuen Modul: Anlegen ging,
Aendern ging, Loeschen nicht. Man sucht dann im eigenen Code, und dort
ist nichts. Express meldet so etwas nicht -- es nimmt die erste Route,
die passt, und schweigt ueber die zweite.

Der Block liegt jetzt unter /workspace/api/notizblock. Und
pruef-notizen geht seitdem den Routenbaum von express durch und meldet
jedes Paar aus Methode und Pfad, das zweimal vergeben ist. Gemessen:
307 Wege, keine Dublette. Die Pruefung gilt fuers ganze Haus, auch
wenn sie in dieser Datei steht -- hier ist sie gefunden worden.

Nebenbei berichtigt: pruef-crew-adresse verlangte von jedem Eintrag
der Haustafel HTTP 200 mit Inhalt. Das stimmte, solange dort nur
oeffentliche Dateien standen. notizen.html ist die erste Seite hinter
der Anmeldung -- sie antwortet mit 302, und das ist richtig. Gefragt
wird jetzt, was die Tafel wirklich meint: GIBT es das hier.

GEMESSEN, alles nach den Aenderungen:

  pruef-notizen             76 Punkte, 0 Fehler (neu)
  pruef-kachelfarben        31 Punkte, 0 Fehler (vorher 26)
  pruef-kachel-universum    13 Punkte, 0 Fehler
  pruef-crew-adresse       157 Punkte, 0 Fehler
  pruef-buehne             230 Punkte, 0 Fehler -- notizen.html neu in
                           der Liste, schlechtester Kontrast 6,73:1,
                           also 50 % ueber der Grenze
  pruef-rechtetafel, -haus-seiten, -struktur, -css-klassen,
  -jeder-hat-eine-seite, -workspace-seiten, -kachelraster,
  -rueckmeldung            alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-26 12:42:59 +02:00
DogFatherGitandClaude Opus 5 69ba533cee Wer mit der Tastatur bedient, sieht wieder, wo er steht
pruef-barrierefrei-workspace, wissen.html, Scout und Creator: Beim
Durchtabben veraendert sich an den Wissenskacheln NICHTS. Kein Rahmen,
kein Ring, keine Kante. Wer nicht mit der Maus arbeitet, tippt blind.

=== EIN SPEZIFITAETS-UNFALL, UND ER BETRIFFT NICHT NUR DIESE SEITE ===

Die Regel war da und richtig geschrieben:

  wissen.css   .kachel:focus-visible { box-shadow: 0 0 0 3px ... }

Sie kam nur nicht an. Gemessen mit einem neuen Werkzeug
(server/mess-fokus.mjs, echte Tastendruecke, kein focus()):

  :focus true   :focus-visible true
  boxShadow     gleich   rgba(0,0,0,0.95) 7px 7px 14px -10px inset
  outline       gleich   none

`:focus-visible` griff also, und trotzdem blieb alles, wie es war.
Der Grund steht in module.css, in einer Liste von 45 Klassennamen:

  :is(.eintrag-karte, ..., .kachel, ..., .gruppe[data-gruppe], ...)

`:is()` uebernimmt die Spezifitaet seines STAERKSTEN Arguments.
`.gruppe[data-gruppe]` ist eine Klasse PLUS ein Attribut. Damit ist die
ganze Liste (0,2,0) statt (0,1,0) -- genau so stark wie
`.kachel:focus-visible`. Bei Gleichstand gewinnt, was spaeter geladen
wird, und module.css wird zuletzt geladen. Ein einziges Attribut in
einer Aufzaehlung, sechs Zeilen weiter rechts, hat den Fokusring von
jedem Bauteil im Haus verschluckt, dessen Fokusregel aus einer Klasse
besteht.

=== GELOEST WIRD DAS NICHT, INDEM MAN DIE LISTE SCHWAECHER MACHT ===

Das war schon einmal so (`:where()`, Spezifitaet null) und ergab einen
Zwitter aus neuer Form und alter Kante -- der Kommentar in module.css
beschreibt es. Wer die Zahl senkt, verschiebt das Problem auf die
naechste Regel.

Geloest wird es, indem die ANTWORT dort steht: ein Fokusring fuer die
ganze Modulliste, in derselben Datei wie die Form, mit
`:focus-visible` also eine Klasse staerker als die Grundregel. Er gilt
damit fuer jedes Modul im Haus -- auch fuer die, die es noch nicht
gibt, und auch dort, wo nie jemand an eine Fokusregel gedacht hat.

`outline-offset` ist NEGATIV, und das ist kein Geschmack: `clip-path`
(die Fase an der Ecke) schneidet alles ab, was ausserhalb der Form
liegt. Ein Ring mit positivem Abstand waere unsichtbar gewesen -- der
alte war es ja auch. Nach innen gezeichnet bleibt er stehen. Gemessen,
nicht geschlossen.

=== WAS NICHT MITREPARIERT WURDE, UND WARUM ES DASTEHT ===

Derselbe Gleichstand trifft auch Hover-Regeln in frueher geladenen
Dateien: `.ablage:hover` (dateien.css), `.call:hover` (calls.css),
`.kk:hover` (scouting.css), `.fortschritt:hover` (uebersicht.css)
setzen alle `border-color`, und die Grundregel setzt `border: 0`.
Diese vier tun vermutlich nichts.

Angefasst habe ich sie nicht -- es gibt kein Messgeraet dafuer. Fokus
laesst sich pruefen (die Pruefung tabbt und vergleicht), Hover nicht.
Und die naheliegende Loesung wuerde die Form von 45 Bauteilen auf 38
Seiten neu entscheiden; das ohne Messgeraet zu tun waere Raten mit viel
Einsatz. Der Befund steht deshalb als Absatz in module.css, damit der
Naechste nicht wieder bei null anfaengt.

=== UND EINE BEHAUPTUNG VON MIR WIRD ZURUECKGENOMMEN ===

Im Commit d7bb0f7e steht, ein Mindestabstand von 0,10 sei fuer 45
Kachelfarben „rechnerisch nicht mehr moeglich", mit einer Tabelle von
„Decken". Das ist falsch herum gelesen: Das Werkzeug SUCHT eine
Anordnung. Findet es nichts Besseres, sagt das etwas ueber das
Verfahren, nicht ueber die Welt. Nachweisbar ist nur, was es GEFUNDEN
hat -- und wie wenig das eine Decke ist, zeigt der eigene Lauf: Fuer
dieselben 45 Farben kam dasselbe Verfahren je nach Rasterweite einmal
auf 0,0974 und einmal auf 0,0876.

Die Pruefung sagt das jetzt so, und das Werkzeug heisst zwar weiter
kachelton-decke.mjs, erklaert aber in den ersten zwanzig Zeilen, dass
es keine Decke misst. Beide Werkzeuge liegen jetzt ueberhaupt im
Verzeichnis: Sie hiessen `tools/_toene-*.mjs`, und `tools/_*` ist
ausgenommen -- die Kommentare verwiesen also auf Dateien, die es nach
dem Klonen nirgends gibt.

GEMESSEN, alles nach den Aenderungen:

  pruef-barrierefrei-workspace   18 Punkte, 0 Fehler (vorher 2)
  pruef-buehne                  230 Punkte, 0 Fehler
  pruef-kachelraster             15 Punkte, 0 Fehler
  pruef-start-ansicht           157 Punkte, 0 Fehler
  pruef-kopfleiste-farbe          9 Punkte, 0 Fehler
  pruef-rueckmeldung             30 Punkte, 0 Fehler
  pruef-entwicklung-kacheln      34 Punkte, 0 Fehler
  pruef-kachel-universum         13 Punkte, 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:50:54 +02:00
DogFatherGitandClaude Opus 5 80988f2d23 Berichtigt: Die Rechnung hat zwei ausdrueckliche Wuensche ueberfahren
Der Commit davor hat alle 45 Kachelfarben neu verteilt, um acht fast
gleiche Paare zu trennen. Das Ergebnis war rechnerisch besser und
praktisch falsch. pruef-kachelfarben hat sechs Fehler gemeldet:

  Ton 38  #ff1a1a -> #ff241e   „nur die soll knall rot sein!!!"
  Ton 44  #a8d8ff -> #90c3ff   „soll auch babyblau sein mit bissl lila"
  Ton 40, 10, 33          unter die Buntheitsgrenze von 0,12 gedrueckt
  und die Regenbogenkachel zeigte noch die 32 alten Farben

Beide Farben standen mit Datum, Zitat und Begruendung in der Pruefung.
Ich habe sie nicht gelesen, weil ich ein GLOBALES Ziel optimiert habe
-- „alle 45 moeglichst weit auseinander" -- und eine globale Rechnung
kennt keine Einzelfaelle.

=== DIE LEHRE IST NICHT „DIE RECHNUNG WAR FALSCH" ===

Sondern: Eine Gesamtloesung fuer ein LOKALES Problem bezahlt man mit
allem, was an den nicht betroffenen Stellen schon richtig war. Acht
Paare standen zu eng. Verschoben wurden 45.

Der zweite Anlauf (tools/_toene-reparieren.mjs) macht es umgekehrt:
Solange ein Paar zu eng steht, wird das engste genommen und EINER der
beiden auf die naechste erlaubte Farbe geschoben. Sonst nichts.

Und dabei kam das Beste des Tages heraus -- gemessen, nicht geahnt:
Von den 45 Toenen tragen nur 33 eine Kachel, zwoelf stehen bereit. In
JEDEM der acht zu engen Paare ist mindestens einer dieser zwoelf
dabei. Wer den Unbenutzten verschiebt, loest dasselbe Problem, ohne
dass sich fuer irgendjemanden auch nur eine Kachel veraendert.

  kleinster Abstand   0,0154  ->  0,0940
  Paare unter 0,09        14  ->  0
  veraendert                       14 von 45
  davon in Gebrauch                 4 -- und zwar um 0,003 bis 0,012

Vier Zehntausendstel OKLab sind nicht zu sehen. Es gibt also KEINE
Kachel, die ihre Farbe wechselt. Das ist mehr als Bequemlichkeit: Wer
zwei Jahre lang „das Tuerkise" angesteuert hat, sucht danach, wenn es
plötzlich rosa ist.

=== UND DIE WUENSCHE STEHEN JETZT DORT, WO GERECHNET WIRD ===

Die Liste FESTGELEGT ist von server/pruef-kachelfarben.mjs nach
tools/kachelton-regeln.mjs gewandert -- neben die Schwellen, aus
genau demselben Grund, aus dem die Schwellen dort stehen.

In der Pruefung konnte sie nur EINES: eine Abweichung melden, nachdem
sie passiert ist. Das hat sie getan, und das ist ihr Verdienst. Aber
eine Bedingung, die erst NACH dem Schaden spricht, ist die schwaechere
Form. Wer die Farben rechnet, soll gar nicht erst die Moeglichkeit
haben, sie zu verschieben -- das Werkzeug liest die Liste jetzt selbst
und setzt festgelegte Toene sogar zurueck, wenn es sie verschoben
vorfindet.

Dasselbe gilt fuer die Buntheitsgrenze: Sie kommt aus der Regeldatei,
und sie gilt nur fuer benutzte Toene -- so, wie die Pruefung sie
anwendet. Das ist nicht Nachgiebigkeit, sondern Rechnung: Mit
Buntheit >= 0,12 fuer ALLE 45 ist ein Mindestabstand von 0,09
nachweislich unmoeglich (Decke 0,0853). Die zwoelf unbenutzten duerfen
blasser sein und nehmen genau den Druck aus dem engen
Blau-Tuerkis-Bereich, an dem der erste Anlauf gescheitert ist.

GEMESSEN: pruef-kachelfarben 26 Pruefungen, 0 Fehler (vorher 26 mit
6 Fehlern). pruef-kachel-universum 13 Pruefungen, 0 Fehler.
Regenbogenkachel mit tools/kachel-regenbogen.mjs neu geschrieben --
99 Punkte in drei Groessen, je 33 Farben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:44:40 +02:00
DogFatherGitandClaude Opus 5 954426615f Der Pruefstand bekommt selbst eine Pruefung -- und der Mensch ein Stueck
der Notiz

Jede Nacht laeuft tools/nachtlauf.mjs ueber 193 Pruefdateien und
schreibt das Ergebnis als Notiz in Filipes Vault. Diese Notiz ist das
Einzige, was er von dem ganzen Aufwand zu sehen bekommt.

Und sie war die einzige Datei im Haus, die niemand geprueft hat.

=== WARUM DAS VORHER GAR NICHT GING ===

nachtlauf.mjs startet BEIM IMPORT sofort einen Lauf. Wer die Notiz
messen wollte, haette damit eine halbe Stunde Rechenzeit ausgeloest --
und nebenbei das echte Ergebnis auf Filipes Startseite ueberschrieben.
Am 04.09.2026 hat genau so ein Griff bei RunOne einen roten Alarm ueber
einer fehlerfreien Buchhaltung erzeugt, am Morgen einer Vorstellung.
„Ein Prueflauf ist kein harmloser Lesevorgang."

Der Textbau steht deshalb jetzt in tools/nachtlauf-notiz.mjs: nur
Textbau, kein Nebeneffekt, Importieren ist folgenlos.

=== UND EIN STUECK DER NOTIZ GEHOERT AB JETZT DEM MENSCHEN ===

Oben in der Notiz stand: „von Hand aendern bringt nichts, beim
naechsten Lauf ist es wieder ueberschrieben." Das war ehrlich und
trotzdem falsch herum gedacht.

Das Wertvollste an diesem Pruefstand ist naemlich nicht die Zahl,
sondern der Satz daneben: „die hier ist rot, weil sie den Umbau vom
24.09. nicht mitbekommen hat" oder „die ist echt, Finger weg". Genau
dieser Satz wurde jede Nacht geloescht. Heute Nacht standen 37
Dateien in der Liste, und bei 25 davon waere so ein Satz die halbe
Arbeit gewesen.

Jetzt gibt es einen Bereich zwischen zwei Marken, den der Lauf wieder
einsetzt statt ihn zu ueberschreiben. Fehlt er, wird er leer neu
angelegt -- mit der Erklaerung darin, wozu er da ist.

=== 30 PRUEFUNGEN, JEDE MIT GEGENPROBE ===

  1. Der Block „von Hand" ueberlebt einen Lauf -- UND das alte
     Ergebnis daneben verschwindet wirklich. Ohne die zweite Haelfte
     wuerde die erste nur beweisen, dass die Datei nicht angefasst
     wurde.
  2. Ein leerer Block zaehlt als nicht vorhanden; sonst waere die
     Erklaerung fuer immer weg, sobald jemand sie einmal loescht.
  3. Weniger Pruefungen als gestern werden gemeldet, auch wenn alles
     gruen ist (die Lehre vom 28.08.: 789 statt 804, gruen, und acht
     Pruefungen je Geraet waren still weggefallen). Gegenprobe: Bei
     MEHR Pruefungen darf der Satz NICHT kommen -- eine Warnung, die
     immer kommt, ist keine Warnung mehr.
  4. Der dritte Ausgang sagt „konnte nicht nachsehen", nennt den Grund
     und wie alt der letzte echte Stand ist -- und behauptet nirgends,
     alles sei in Ordnung.
  5. „Keine Pruefung gezaehlt" wird als das benannt, was es ist: kein
     Befund, sondern ein Zaehlproblem. Acht Dateien standen heute Nacht
     aus diesem Grund als rot da.

Punkt 5 der Pruefung hat sich beim ersten Lauf gleich bezahlt gemacht:
Sie zaehlt nach, ob JEDER der vier Aufrufe in nachtlauf.mjs den
Notizpfad mitreicht. Drei davon sind die seltenen Ausgaenge, die man
beim Ausprobieren nie erwischt -- und an jedem einzelnen waere der
Block „von Hand" spurlos verschwunden. Beim Umbau hatte ich genau
diese drei zuerst vergessen.

GEMESSEN: 30 Pruefungen, 0 Fehler. Die echte Notiz im Vault wird dabei
nicht angefasst -- gearbeitet wird in einem mktemp-Ordner.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:19:50 +02:00
DogFatherGitandClaude Opus 5 d7bb0f7e60 45 Kachelfarben: acht Paare waren dieselbe Farbe -- und die Pruefung
konnte es nicht sagen

Filipe am 17.09.: „ich will das jede kachel eine andere farbe hat, es
soll keine die gleiche farben haben bitte und auch keine die sich
irgendwie aehnlich sind ... die farben sollen auch richtig geil und
speziell sein."

Gemessen am 25.09.: #ff8fb4 gegen #fe8ebe, Abstand 0,0154 in OKLab.
Das ist mit blossem Auge DIESELBE Farbe. Acht solche Paare gab es.

=== WARUM ES NIEMAND GEMERKT HAT ===

pruef-kachel-universum hat es gesagt. Jede Nacht. Die Zeile stand da:
„kleinster Abstand 0,0154". Gelesen hat sie niemand -- weil direkt
daneben eine zweite Zeile stand, die NIEMALS gruen werden konnte:
„kein Paar unter 0,10".

Nachgerechnet (tools/_toene-packen.mjs, eine echte Kugelpackung ueber
alle sRGB-Farben, die 4,8:1 gegen den Grund halten, nicht blenden und
bunt genug sind):

  30 Farben  ->  0,115        48 Farben  ->  0,0925
  40 Farben  ->  0,103        52 Farben  ->  0,0840
  45 Farben  ->  0,0974       60 Farben  ->  0,0805

Die Forderung war fuer 21 Farben geschrieben. Bei den heutigen 45
liegt die DECKE bei 0,0974 -- „kein Paar unter 0,10" konnte niemand
erfuellen, mit keiner Palette der Welt.

DAS IST DER EIGENTLICHE BEFUND. Eine Bedingung, die niemand erfuellen
kann, macht nicht nur sich selbst wertlos. Sie faerbt die ganze Datei
rot, und ab da liest man die Zeile darueber nicht mehr. Der echte
Mangel lag acht Tage offen da, versteckt hinter einem Fehlalarm.

=== DIE NEUE PALETTE WURDE GERECHNET, NICHT NACHGEBESSERT ===

Von Hand nachbessern hat sie erst dahin gebracht: Am 08.09. waren es
21 Farben, danach kamen sechzehn dazu, jede einzeln gewaehlt, keine
gegen die anderen geprueft. In drei Schritten:

  1. Aus allen erlaubten sRGB-Farben 45 so waehlen, dass der kleinste
     Abstand so gross wie moeglich wird.
  2. Sie den 45 Kachelnummern so zuordnen, dass jede moeglichst nah an
     ihrer bisherigen Farbe bleibt -- eine Kachel soll wiedererkennbar
     sein, sie rueckt, sie wechselt nicht.
  3. Nachziehen: Jeder Ton darf zurueck in Richtung seiner alten Farbe
     wandern, solange der Mindestabstand haelt.

Ergebnis: kleinster Abstand 0,0154 -> 0,0931, kein Paar mehr unter
0,09. Dreissig der 45 Kacheln haben sich um weniger als 0,02 bewegt --
das sieht man nicht. Nur sieben sind sichtbar gewandert, und alle
sieben lagen in dem Gedraenge aus neun fast gleichen Rot- und
Rosatoenen, das den Ausschlag gegeben hat.

„Richtig geil und speziell" bleibt messbar erhalten: Die Buntheit hat
eine Untergrenze von 0,10 in der Rechnung, damit keine Farbe ins Graue
rutscht. Gemessen kostet das nichts -- mit dieser Grenze ist die Decke
sogar minimal hoeher als ohne (0,0974 gegen 0,0973).

=== UND DIE PRUEFUNG SAGT JETZT ETWAS ERFUELLBARES ===

  kleinster Abstand >= 0,09          (Decke fuer 45 Farben: 0,097)
  hoechstens 48 Farben               (darueber ist 0,09 nicht mehr
                                      erreichbar -- gemessen, nicht
                                      gesetzt)
  Gegenprobe: #ff8fb4 gegen #fe8ebe  muss durchfallen

Die zweite Zeile ist die wichtige: Sie bewacht den GRUND. Wer die
46., 47., 48. Kachel anlegt, kommt noch durch; wer die 52. anlegt,
bekommt gesagt, dass jetzt ueber die Palette geredet werden muss,
statt still wieder in zwei gleiche Farben zu rutschen. Genau das ist
zwischen dem 08.09. und dem 17.09. passiert.

GEMESSEN: pruef-kachel-universum 13 Pruefungen, 0 Fehler (vorher 12
mit 2 Fehlern). Schlechtester Textkontrast auf der fertigen Kachel
7,02:1, am Bildschirmfoto gemessen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:19:29 +02:00
DogFatherGitandClaude Opus 5 ce1a1f758c Zum dritten Mal dieselbe Schrift zu dunkel -- diesmal mit Luft
entwicklung.html, „Noch niemand im Team": 4,42:1 gemessen, noetig sind
4,5:1. Der Befund ist klein. Die Geschichte dahinter ist es nicht.

=== DREIMAL IN VIER WOCHEN, IMMER DERSELBE GRIFF ===

  01.09.  #6d7d92 -> #75859a    gemessen 4,43  ->  4,95
  07.09.  #75859a -> #7f8fa6    gemessen 4,50  ->  rund 4,9
  25.09.  #7f8fa6 -> #95a4ba    gemessen 4,42  ->  5,75

Neben jedem dieser Schritte steht ein sorgfaeltiger Kommentar, der
erklaert, warum genau dieser Wert richtig ist. Alle drei waren richtig
-- fuer den Untergrund, den man GERADE KANNTE.

Der Hintergrund ist aber ein BILD. Bilder haben helle Stellen, und die
liegen bei jedem neuen Layout woanders. Wer eine Schrift auf zwei
Kommastellen genau gegen die hellste Stelle einstellt, die er heute
gefunden hat, stellt sie auf den naechsten Umbau ein.

=== WAS DIESMAL ANDERS GEMACHT WURDE ===

1. NICHT NUR DIE ROTE SEITE ANGESEHEN. Die schlechtesten Werte ALLER
   vierzehn Seiten nebeneinandergelegt:

     hilfe.html      4,90   auf rgb(51,53,56)   <- die hellste im Haus
     teamlage.html   4,98   auf rgb(45,52,64)
     entwicklung     4,42   auf rgb(40,41,44)   <- die, die rot war
     befinden.html   5,38   auf rgb(29,39,46)
     ... zehn weitere ueber 6,3

   Die rote Seite war also NICHT die gefaehrlichste. Zwei andere lagen
   knapper an der Grenze, als der letzte Rutscher gross war -- sie
   waeren als naechste drangewesen. Haette ich nur entwicklung.html
   repariert, haette ich in zwei Wochen dasselbe noch einmal getan.

2. DER BEZUG IST JETZT DIE HELLSTE FLAECHE IM HAUS, nicht die der
   Seite, die gerade rot ist. Beide Toene beider Haeuser gegen
   rgb(51,53,56) gerechnet:

     Gate    still #7f8fa6 -> #95a4ba   4,35 -> 4,86
             leise #94a5bb -> #9fb0c6   4,90 -> 5,56
     Crew    still #8f88b2 -> #a7a0cb   4,10 -> 5,00
             leise #a9a2ca -> #b4aed6   5,10 -> 5,84

   Der stille Ton im Crew-Haus stand bei 4,10 -- UNTER der Grenze, seit
   Wochen, ohne dass eine Pruefung je etwas gesagt haette. Nicht weil
   sie nachsichtig war, sondern weil noch keine Crew-Seite mit dieser
   Flaeche angesehen wurde. Ein gruener Haken heisst nicht, dass
   nachgesehen wurde.

3. PRUEF-BUEHNE PRUEFT JETZT AUCH DIE LUFT. Nicht nur „ueber 4,5",
   sondern: „hat die schlechteste Stelle dieser Seite noch elf Prozent
   Reserve?" Die Zahl ist gemessen und nicht gewaehlt -- beide
   Rutscher oben waren rund elf Prozent gross, und 4,5 mal 1,11 ist
   5,0. Eine Seite unter diesem Wert ist noch in Ordnung und schon in
   Gefahr, und genau das soll sie sagen, solange man es noch in Ruhe
   beheben kann.

   Sie haengt an der jeweiligen Grenze, nicht an einer festen 5,0: Bei
   grossem Text sind 3:1 erlaubt, dieselbe Luft sind dort 3,33. Eine
   hineingeschriebene 5,0 wuerde grossen Text ohne Not anmahnen.

GEMESSEN: pruef-buehne 230 Pruefungen (vorher 192), 0 Fehler.
Schlechteste Seite jetzt hilfe.html mit 5,15:1 -- 15 % ueber der
Grenze. Die Schrift bleibt deutlich leiser als der Haupttext: der
steht bei 11,8:1, also mehr als doppelt so hoch.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 23:19:04 +02:00
DogFatherGitandClaude Opus 5 1ba9d07af2 Zwoelf rote Pruefungen -- und kein einziger Fehler im Programm
Der Rundumcheck geht weiter. Diese zwoelf standen im Nachtlauf als rot
und waren es nicht: Jede hat den Umbau vom 24.09. (die Haustrennung),
den vom 25.09. (die zugetragenen Punkte) oder eine Umbenennung
mitbekommen -- nur ihre Erwartung nicht.

DAS IST KEIN TROST. Ein Fehlalarm zeigt auf eine echte Stelle und nennt
eine plausible Zahl; man sucht danach an richtigem Code. Und zwoelf rote
Zeilen, die immer rot sind, nehmen dem ganzen Satz die Stimme.

=== DIESELBE WURZEL, SECHSMAL: DAS FALSCHE HAUS ===

Seit dem 24.09. antwortet der Server auf der Agenturadresse nicht mehr
ueber Team-Dogi-Leute -- und genau das taten diese Pruefungen:

  pruef-nachwuchs      legte einen Modi ueber die Agenturadresse an
                       (400). Einundzwanzig Meldungen hingen an diesem
                       einen Aufruf. 82 Zeilen auf crew. umgestellt,
                       aus „Mara, Managerin" wurde die linke Hand --
                       im Teamhaus ist sie das, was gemeint war.
                       230 -> 262 Pruefungen, 0 Fehler.
  pruef-schritt        dasselbe beim Aufgabenbrett (404/400).
  pruef-treff-werkzeuge fragte die Einladungsliste eines Modis auf der
                       Agenturadresse ab -- dort ist er nicht.
  pruef-rechte-umstellen benutzte `wissen.html` als zweite Probeseite.
                       Die ist laut Rechtetafel fuer alle offen und auf
                       crew. trotzdem zu: Dort kommt man nur auf Seiten,
                       fuer die es eine Kachel gibt. Jetzt material.html.
  pruef-personen-formular verglich eine Erwartung FUER die Agentur mit
                       einer Messung OHNE Adresse (127.0.0.1) -- vier
                       gegen acht Rollen. Beides war richtig, nur nicht
                       dasselbe.
  pruef-treff          suchte „Support" zwischen den Brettern. Er steht
                       in „Fuer dich", wo er hingehoert -- eine kaputte
                       Seite zu melden ist kein Aushang. Die Liste stand
                       ZWEIMAL in der Datei; nachgezogen wurde eine.
                       Jetzt eine, von beiden benutzt.

=== ZWEIMAL: EINE FESTE ZAHL, DIE DIE SEITE UEBERHOLT HAT ===

  pruef-community-sicht erlaubte „3 bis 8 Seiten". Es sind zwoelf, und
                       jede gehoert dorthin. Statt einer Spanne steht
                       jetzt die LISTE da: Kommt eine dazu, wird die
                       Zeile rot und nennt sie beim Namen. Eine Spanne
                       haette elf statt zwoelf stillschweigend
                       durchgelassen -- in beide Richtungen.
  pruef-nachwuchs      schaltete EINE Person ab und erwartete, dass die
                       Ampel danach schweigt. Der Kommentar darueber
                       sagt selbst: „Die Schwelle wird nicht
                       abgeschrieben, sondern aus dem Verhalten
                       abgeleitet" -- eine feste Anzahl abzuschalten ist
                       aber eine Abschrift in anderer Waehrung. Jetzt
                       wird abgeschaltet, BIS es kippt.

=== UND VIERMAL EIN WERKZEUG, DAS STUMPF WAR ===

  pruef-scout-zuteilung suchte `.person__zeile` -- eine Klasse, die es
                       nicht mehr gibt. `querySelectorAll` liefert dafuer
                       ein leeres Feld, `.some()` darauf ist immer
                       false: Die Pruefung war nicht rot, weil etwas
                       fehlte, sondern weil sie nichts ansehen konnte.
                       Jetzt `.person`, und die ANZAHL der gefundenen
                       Karten steht in einer eigenen Bedingung.
  pruef-loeschen       suchte `::before` in einem Fenster von 600
                       Zeichen ab dem Selektor. Das misst die Laenge des
                       KOMMENTARS: Am 25.09. kam eine Begruendung von
                       zwanzig Zeilen dazu, und die Regel rutschte
                       hinaus. Jetzt wird nach dem Selektor gesucht.
  pruef-portnummern    hielt jedes `listen(` fuer einen Serverstart --
                       auch das blosse Nachsehen, ob eine Nummer frei
                       ist. Damit mahnte sie ausgerechnet die Datei an,
                       die das Vergeben der Nummern prueft. Jetzt zaehlt
                       der Import von `index.js`; dazu vier Gegenproben,
                       damit die engere Fassung nicht zum blinden Fleck
                       wird.
  pruef-spicy          stellte eine Person auf „manager" und dann
                       weiter. An Managern aendert seit dem 22.09. nur
                       DogFather etwas -- die Pruefung hatte sich selbst
                       die Tuer zugezogen. Jetzt kommt „manager" zuletzt,
                       und dass danach nichts mehr geht, ist eine eigene
                       Zeile. Aus dem Stolperstein wird eine Aussage.

=== EINER WAR FAST EIN BEFUND ===

  pruef-alle-sehen-es  meldete „highlight: DogFather 0, Community 0".
                       Das Brett hat als einziges keinen Katalog (dort
                       stehen echte Hoehepunkte, keine Vorlagen), und an
                       einem leeren Brett ist „sehen beide dasselbe?"
                       nicht zu messen: null gleich null waere auch dann
                       wahr, wenn die Community gar nichts duerfte.
                       Die Pruefung legt dort jetzt selbst einen Eintrag
                       an -- und musste dabei zweimal lernen: Der Eintrag
                       gehoert VOR den Katalog (danach ist die
                       Schreibbremse ausgeloest, 429), und er muss
                       FREIGEGEBEN werden, sonst sieht die Community ihn
                       zu Recht nicht. Beides steht jetzt als Aussage in
                       der Pruefung.

GEMESSEN: alle zwoelf gruen -- 43, 10, 31, 262, 43, 15, 56, 69, 37, 85,
73 und 80 Pruefungen, zusammen 804, kein Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 22:54:21 +02:00
DogFatherGitandClaude Opus 5 3b73e1f42e Versionsnummer von anruf.js hochgezaehlt -- sonst bliebe die Reparatur im Zwischenspeicher
Die Datei wird mit fester Nummer eingebunden (anruf.js?v=...). Wer sie
aendert und die Nummer stehen laesst, hat ausgeliefert und trotzdem
nichts bewirkt: Jeder Browser, der die Seite schon einmal offen hatte,
nimmt weiter die alte Datei. Genau die Sorte Auslieferung, die gruen
meldet und nichts tut.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 17:11:31 +02:00
DogFatherGitandClaude Opus 5 29d339b262 Ein turn: ohne Zugangsdaten haette JEDEN Anruf verhindert, nicht nur die vermittelten
Gefunden am 25.09.2026 beim Bau des Podcast-Studios, das dieselbe
Rechnung benutzt, und dort im echten Browser gemessen:

  Failed to construct 'RTCPeerConnection': Both username and credential
  are required when the URL scheme is "turn" or "turns".

`new RTCPeerConnection(...)` WIRFT. Die Folge ist nicht "kein
Vermittlungsserver", sondern KEIN ANRUF -- auch nicht der, der direkt
zustande gekommen waere. Aus einem Randproblem (etwa jeder Fuenfte
braucht Vermittlung) waere ein Totalausfall fuer alle geworden,
ausgeloest davon, dass /etc/coturn-workspace.geheimnis einmal nicht
lesbar ist: Rechte verstellt, beim Neuaufbau vergessen, Datei leer.

server/workspace-turn.js laesst solche Eintraege bewusst stehen, damit
der Grund nicht verschwindet ("KEIN STILLES WEGLASSEN"). Das ist dort
richtig -- es heisst aber, dass im Browser aussortiert werden muss,
bevor die Verbindung gebaut wird. Genau das fehlte. Der Kommentar
daneben behauptete "ein turn: ohne Passwort schadet nicht"; das war
nie gemessen und ist falsch.

Zwei Aenderungen in workspace/assets/js/anruf.js:

1. Beim Uebernehmen der Adressen werden turn:/turns:-Eintraege ohne
   Benutzer UND Passwort aussortiert. STUN bleibt -- es kennt gar keine
   Anmeldung und ist der Weg, der in den meisten Faellen reicht. Der
   Grund geht nicht verloren, er steht weiter in der Konsole (jetzt mit
   dem Dateinamen, in dem man nachsehen muss).

2. `adressenFrisch()` sagt bei gesetztem Grund immer "nicht frisch".
   Sonst waere die Liste fuer immer frisch: Ohne Zugangsdaten bleibt nur
   STUN uebrig, und ein STUN-Eintrag hat keinen Ablaufzeitpunkt --
   `every()` sagt dann "alles gueltig" und es wird nie wieder gefragt.
   Waere die Datei auf dem Server repariert, telefonierte trotzdem
   niemand mehr mit Vermittlung, bis er die Seite neu laedt. (Nebenbei
   die zweite Falle derselben Zeile: `every()` auf einer LEEREN Liste
   ist `true`.)

Geprueft in server/pruef-anruf.mjs: Die Pruefung liest den Filter aus
der ausgelieferten Datei und FUEHRT IHN AUS -- vier Adressen hinein,
zwei brauchbare heraus, mit Gegenprobe, dass er ueberhaupt etwas
wegnimmt. Eine Pruefung, die nur nachsieht, ob irgendwo "filter" steht,
waere auch dann gruen, wenn der Filter das Falsche tut.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 17:02:23 +02:00
DogFatherGitandClaude Opus 5 cdb6c46f8b Der Chat oeffnet dort, wo das Neue anfaengt -- bei allen sechs Rollen
Filipe: "wenn ich in den chat rein gehe und es neue kommentare gibt,
will ich dass mein chat sich da öffnet wo die neuen nachrichten anfangen
die ich noch nicht gesehen hab bitte und nicht immer ganz unten. sonst
muss man immer hoch scrollen um die neuen zu lesen und das ist scheisse.
perfektionier das bei allen rollen."

DIE FUNKTION GAB ES SEIT DEM 09.09.2026 -- eine Linie „Ab hier neu" und
einen Sprung darauf. Sie hat trotzdem nicht funktioniert, und zwar aus
DREI Gruenden, die sich gegenseitig verdeckt haben. Gefunden hat sie
keine Ueberlegung, sondern eine Messung in Pixeln: Wie weit ist die
Linie vom oberen Rand entfernt? Ein negativer Wert heisst „darueber",
also unsichtbar.

1. DER SPRUNG RECHNETE GEGEN DEN FALSCHEN PUNKT.
   `linie.offsetTop` ist der Abstand zum `offsetParent` -- und das ist
   nur dann der Verlauf, wenn dieser `position: relative` traegt. Tut
   er nicht. Gemessen auf 390 px landete die Linie 23 px OBERHALB des
   sichtbaren Bereichs: Man musste genau das tun, was Filipe nicht mehr
   tun wollte. Am Rechner stimmte es zufaellig, weil dort weniger
   dazwischenliegt -- deshalb ist es nie aufgefallen.
   Jetzt: Oberkante der Linie minus Oberkante des Verlaufs plus dessen
   Bildlaufposition. Das gilt immer, egal wer wessen offsetParent ist.

2. JEDES NACHLADEN LOESCHTE DIE LINIE.
   `gelesenBeimOeffnen` wurde bei JEDEM Aufruf gesetzt, auch beim
   sanften Nachladen. Sanft laedt der Verlauf staendig nach -- vor
   allem, wenn der Ereignisstrom sich verbindet. Die Seite laedt,
   zeichnet, meldet „gelesen bis hier", der Strom verbindet sich, laedt
   sanft nach -- und jetzt steht in `gelesen_bis` schon die letzte
   Nachricht. Keine Linie mehr, Sprung ans Ende.
   DAS IST DER FEHLER, DEN FILIPE GESEHEN HAT. Und er wuerfelte: Kommt
   die Verbindung vor dem ersten Zeichnen, passiert nichts; danach ist
   die Linie weg. Ueber sechs Rollen gemessen waren mal drei rot, mal
   zwei, mal andere -- bei unveraendertem Code.

3. UND EIN EINZIGER SPRUNG REICHT NICHT.
   Zwischen Sprung und fertigem Bild waechst die Hoehe noch: Schriften
   kommen an und setzen den Text um, Bilder melden ihre Groesse. Jetzt
   wird nachgezogen -- nach den Schriften, nach jedem Bild, nach zwei
   Bildwiederholungen -- und die Stelle haelt, bis der Mensch selbst
   scrollt. „Ich habe dich an die neue Stelle gesetzt" ist eine Zusage;
   sie beim naechsten Nachladen zu brechen waere schlimmer, als sie nie
   gegeben zu haben.

GEMESSEN -- server/pruef-chat-neu-stelle.mjs (neu), 63 Pruefungen,
0 Fehler, zweimal hintereinander mit demselben Ergebnis:

  Sechs Rollen in beiden Haeusern (DogFather, rechte Hand, linke Hand,
  Modi auf crew.; Manager und Creator auf workspace.), je auf Handy
  (390 px) und Rechner (1280 px). Je Blick: Steht die Linie im
  Verlauf? Ist sie zu SEHEN? Steht Zusammenhang darueber? Und ist der
  Verlauf NICHT am Ende?

  Ergebnis: 115-118 px unter dem oberen Rand am Handy, 150-153 px am
  Rechner -- darueber jeweils die letzte alte Nachricht.

  Dazu drei Gegenproben: Ohne Ungelesenes gibt es keine Linie und der
  Verlauf steht am Ende (sonst laendete man grundlos mitten im
  Verlauf); und die Messung erkennt „nicht sichtbar" auch wirklich
  (-1403 px an einem absichtlich nach unten gescrollten Verlauf) --
  sonst waere jede gruene Zeile darueber wertlos.

DIE PRUEFUNG SELBST HAT ZWEIMAL DAS FALSCHE GEMESSEN, bevor sie das
Richtige maass, und beides steht als Begruendung darin: Sie schickte
`/gelesen` ohne `bis` (die Route verlangt eine Nummer und lehnt sonst
ab -- der Lesestand blieb null, die Linie entstand nie), und sie
benutzte einen Raum je Rolle fuer zwei Blicke, was einen Wettlauf mit
der „gelesen"-Meldung erzeugte. Jetzt bekommt jeder Blick seinen
eigenen Raum: mehr Aufbau, dafuer immer dasselbe Ergebnis.

pruef-chat 63/0, pruef-chat-optik 62/0, pruef-chat-kanaele 81/0,
pruef-treffchat 110/0, pruef-chat-neu 36/0, pruef-pin-fuer-mich 37/0,
pruef-erwaehnung 129/0, pruef-gifs 17/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 14:40:01 +02:00
DogFatherGitandClaude Opus 5 9d219e17ce Ein Bild vom Aushang: zwei Knoepfe, und man sieht welcher mehr bewirkt
server/mess-aushang.mjs zeigt, was pruef-pin-fuer-mich nicht messen
kann -- wie die zwei Knoepfe nebeneinander aussehen. Drei Blicke:
DogFather auf dem Handy (beide Knoepfe), ein Modi auf dem Handy (nur
einer), DogFather am Rechner.

Gemessen: „lösen" 52x50 in Grau, „bei allen" 68x50 in der Warnfarbe
des Hauses. Beide ueber 44 px hoch, beide im Bild, und auf den ersten
Blick unterscheidbar -- genau darum ging es: Zwei gleich aussehende
Knoepfe nebeneinander waeren die schlechteste Loesung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 14:14:35 +02:00
DogFatherGitandClaude Opus 5 bf3c7bd718 Einen Aushang loest jeder fuer sich -- fuer alle nur DogFather und die rechte Hand
Filipe: "jeder soll das fixierte individuel für sich lösen können aber
niemals so dass es sich für alle löst. außer dogfather macht es oder die
rechte hand dan ist es bei jedem weg ansonsten sollen alle anderen
rollen es individuell für sich lösen können. dogfather und die rechte
hand sollen die option haben für sich selbst oder für alle zu lösen."

BIS HEUTE GAB ES NUR EIN LOESEN, UND DAS GALT FUER ALLE. Wer den Knopf
sah, nahm damit jedem im Raum den Aushang weg; wer ihn nicht sah, musste
die Ansage vom Montag bis Freitag ueber jedem Gespraech stehen lassen.

JETZT ZWEI KNOEPFE AM AUSHANG:

  "lösen"      nimmt ihn nur bei MIR weg -- jeder darf das, ohne
               Rueckfrage. Umkehrbar: Das Menue an der Nachricht holt
               ihn mit "wieder oben" zurueck. Eine Rueckfrage vor etwas
               Umkehrbarem lernt man wegzuklicken, und danach klickt man
               auch die weg, die zaehlt.

  "bei allen"  nimmt ihn jedem weg -- nur fuer DogFather und die rechte
               Hand, und MIT Rueckfrage. Er traegt die Warnfarbe des
               Hauses: Zwei gleich aussehende Knoepfe nebeneinander
               waeren die schlechteste Loesung, man traefe den falschen
               und merkte es erst, wenn jemand fragt, wo die Ansage
               hin ist.

EIN EINZIGER KNOPF MIT AUSWAHLFENSTER waere kuerzer und schlechter: Der
haeufige Fall ("weg damit, kenne ich") braeuchte dann zwei Klicks, und
der seltene, folgenreiche waere genauso weit entfernt wie der harmlose.

WAS NICHT IN FILIPES SATZ STEHT UND TROTZDEM NOETIG IST: Wer einen
Aushang SELBST angeheftet hat, darf ihn auch selbst wieder fuer alle
loesen. Sonst entsteht eine Sackgasse -- es haengen hoechstens drei,
und eine Gruppenleitung, die drei angeheftet hat und keinen abnehmen
darf, koennte nie wieder etwas anheften. Sie nimmt damit nur zurueck,
was sie selbst getan hat; das ist die Kehrseite derselben Erlaubnis,
keine neue.

TECHNISCH: eine Tabelle `chat_pin_aus` (Nachricht, Person). Kein
Eintrag heisst sichtbar -- nicht umgekehrt, sonst muesste beim Anheften
fuer jeden Teilnehmer eine Zeile entstehen und wer spaeter dazukommt,
saehe den Aushang nie. Der Verbund steht in der Abfrage und nicht im
Browser: Eine Liste, die alles schickt und im Browser gefiltert wird,
ist eine Liste, die alles schickt.

GEMESSEN -- server/pruef-pin-fuer-mich.mjs (neu), 37 Pruefungen, 0 Fehler:
  - Der Modi nimmt sie bei sich weg. BEI DOGFATHER UND BEIM ZWEITEN
    MODI HAENGT SIE WEITER -- das ist der Kern des Auftrags, und er
    laesst sich nur mit mehreren Anmeldungen messen.
  - Er holt sie zurueck; zweimal wegnehmen ist kein Fehler.
  - Er kann NICHT fuer alle loesen (403), und die Absage sagt, was
    stattdessen geht.
  - Die rechte Hand loest fuer alle -- danach ist sie bei jedem weg.
  - Wer selbst angeheftet hat, loest seinen eigenen (200) und den von
    DogFather nicht (403).
  - Das Nachruecken stimmt: Wer einen von dreien weggenommen hat, sieht
    zwei, waehrend DogFather drei sieht.
  - Drei Gegenproben: fremder Raum 404, ohne Anmeldung 401, erfundene
    Nummer 404.

DIE PRUEFUNG MUSSTE AUF node:http UMGEBAUT WERDEN. Sie braucht
Team-Dogi-Rollen, die es nur auf der Crew-Adresse gibt -- und den
`Host`-Kopf laesst `fetch` nicht setzen (verbotener Kopf, undici
verwirft ihn stumm). Die Anfrage kam auf 127.0.0.1 an, waehrend
`Origin` die Crew-Adresse nannte; jede schreibende Anfrage bekam 403
"fremde_herkunft". Im ersten Lauf sah das aus, als sei die neue Route
kaputt.

AUSSERDEM IN DIESER RUNDE: Die drei Faecher im Chat (Personen, Gruppen,
Kanaele) waren 38 px hoch statt 44. Gefunden vom Handy-Rundgang bei
jeder Rolle -- aber erst, seit der Sammellauf auch die Zeile UNTER dem
Befund mitschreibt. Vorher stand dort nur "1 Befund".

Die Schemaaenderung auf einer Kopie der echten Datenbank durchgespielt:
72 Tabellen, keine Zeile und keine Spalte verloren, chat_pin_aus da.
pruef-chat 63/0, pruef-chat-optik 62/0, pruef-chat-kanaele 81/0,
pruef-treffchat 110/0, pruef-chat-neu 36/0, pruef-handy-teamdogi
0 Befunde, pruef-css-klassen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 14:13:05 +02:00
DogFatherGitandClaude Opus 5 a06184f24f Der Name auf der Teamseite hatte null Pixel -- und drei Messungen waren stumpf
Weiter am Rundumcheck, diesmal der Handy-Rundgang. Von sechs Befunden
war einer ein echter Layoutfehler, zwei waren zu kleine Schrift, und
drei kamen daher, dass die Messung etwas nicht unterscheiden konnte.

=== AUF DEM HANDY KAPUTT ===

1. DER NAME IN DER PERSONENKARTE WAR NULL PIXEL BREIT.
   Gemessen auf 412 px: `h3.tperson__name` mit `w=0` bzw. `w=15`. Der
   Name stand als Buchstabensaeule da oder gar nicht -- auf der Seite,
   die von Menschen handelt.

   `.tperson__text` trug `flex: 1; min-width: 0`. Das erlaubt dem
   Textblock, auf null zu schrumpfen, und Flexbox schrumpft lieber,
   als umzubrechen -- die Pille „zuletzt gesehen" daneben blieb stehen
   und nahm allen Platz. `min-width: 0` war trotzdem richtig gemeint
   (ohne sie blaeht ein langes Wort den Kasten auf); es fehlte nur die
   Untergrenze. Jetzt `min(14ch, 100%)`: vierzehn Zeichen, wenn so
   viel Platz ist, sonst der ganze Platz, der da ist. Die Pille bricht
   um -- `flex-wrap: wrap` stand am Kopf ohnehin schon, es fehlte nur
   der Grund, es zu benutzen.

2. ZWEI BESCHRIFTUNGEN UNTER DER LESBARKEITSGRENZE. `.u-weg__marke`
   10,88 px, `.u-weg__aus` 11,2 px -- die Hausgrenze sind 11,5. Der
   Reflex dahinter: Eine Marke soll leise sein, also macht man sie
   klein. Leise wird sie aber durch Farbe und Gewicht; eine Schrift,
   die man nicht lesen kann, ist nicht leise, sondern weg. Derselbe
   Griff ist mir gestern dreimal an einem Tag passiert.

=== DREI MESSUNGEN, DIE ETWAS NICHT UNTERSCHEIDEN KONNTEN ===

3. `pointer-events: none` IST KEIN BERUEHRZIEL. Die Terminpunkte im
   Monatsraster des Kalenders sind 8 x 8 px und nehmen ausdruecklich
   keine Beruehrung an -- angetippt wird die ZELLE. Sie als „zu klein"
   zu melden ist, als beanstande man die Groesse eines gemalten
   Knopfs. `pruef-breiten` kennt die Ausnahme seit jeher; im
   Handy-Rundgang hat sie gefehlt.

4. `font-size: 0` IST KEINE KLEINE SCHRIFT, SONDERN KEINE. Dieselben
   Punkte: Die Schrift wird auf null gesetzt, die Farbe bleibt.
   Gemeldet wurde „0px, zu klein". Die Grenze nach unten bleibt scharf
   -- alles zwischen 0,1 und 11,5 px ist weiterhin ein Befund, nur die
   glatte Null faellt heraus. Sie ist eine Aussage, keine
   Nachlaessigkeit.

5. `scrollWidth > clientWidth` SAGT BEI INLINE-ELEMENTEN NICHTS.
   Chromium liefert dort fuer `clientWidth` glatt null, und damit ist
   jeder Text breiter als sein Kasten. Der richtige Umgang mit einer
   unmoeglichen Messung ist, sie nicht zu machen -- nicht, ihr
   Ergebnis zu glauben. Dazu: Was per `clip-path: inset(50%)` fuer das
   Auge weggenommen ist (echte <select> unter selbst gebauten
   Umschaltern, Beschriftungen zu Symbolknoepfen), kann nicht
   abgeschnitten sein.

=== UND EINE MELDUNG, DIE JETZT SAGT, WO MAN SUCHEN MUSS ===

„abgeschnitten: Mara (18>0)" hat mich zwanzig Minuten gekostet -- drei
Vermutungen, drei Messungen. Die Meldung nennt jetzt Element, Klasse,
Darstellungsart und Breite: „Mara (18>0, h3.tperson__name, block,
w=0)". Damit war der Fall in einem Blick klar. Eine Pruefung, die nur
sagt DASS etwas ist, ist eine halbe.

GEMESSEN: pruef-breiten 0 Fehler (9 Breiten, 38 Seiten), pruef-team
51/0, pruef-tippziele 11/0, pruef-css-klassen 33/0. Im Handy-Rundgang
bleiben die Kopfleisten-Befunde bei 360/390/412 px -- die nehme ich mir
als Naechstes vor, sie brauchen einen Umbau und keine Korrektur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 13:27:01 +02:00
DogFatherGitandClaude Opus 5 f7276172d0 Drei Fehlalarme, die auf echte Stellen zeigten -- und keiner war ein Fehler
Weiter am Rundumcheck. Diese Runde hat KEINE Zeile am Programm
geaendert: Alle drei Befunde kamen aus den Pruefungen selbst. Das ist
kein Trost, sondern die unangenehmere Sorte -- ein Fehlalarm nennt eine
echte Stelle und eine plausible Zahl, und man sucht danach am richtigen
Code.

1. EIN FARBFORMAT, DAS DIE MESSUNG NICHT KANNTE.

   `pruef-neue-seiten` meldete auf treff-regeln.html einen Kontrast von
   1,07 -- praktisch unsichtbarer Text. Nachgemessen an Ort und Stelle:
   dunkler Text auf HELLBLAUER Flaeche, rund 10:1.

   Chromium gibt eine Farbe, die aus `color-mix()` entstanden ist, als
   `color(srgb 0.37 0.78 0.97)` zurueck -- Werte von 0 bis 1, keine
   Kommas. Die Messung las nur `rgba?(...)`, fand die Flaeche des
   Sprunglinks nicht, ging zum fast schwarzen Elternteil weiter und
   rechnete dunkel gegen dunkel. Im Haus ist `color-mix` ueberall.

   Der Farbleser kennt jetzt beide Formate und faehrt vier Proben mit
   (rgb, rgba, color(srgb), color(srgb / alpha)) -- dazu eine fuenfte,
   die beweist, dass er bei Unbekanntem NICHTS liefert. Ein Leser, der
   im Zweifel Schwarz zurueckgibt, waere schlimmer als der alte: Er
   wuerde nie wieder auffallen.

2. EINE SEITE, DIE ZU KURZ WAR, UM "GEFUELLT" ZU HEISSEN.

   Dieselbe Pruefung verlangte von jeder Seite mehr als 400 Zeichen
   Text. entwicklung.html hat 350 -- seit dem Umbau, bei dem aus
   achtzehn Zahlenkaesten zwei Personenkacheln mit einem Ring wurden.
   Die Seite sagt seither mehr und braucht weniger Worte; die Pruefung
   bestrafte damit genau die Verbesserung.

   Jede Seite darf jetzt sagen, woran man sieht, dass sie da ist: eine
   Zeichenzahl, wo Text die Sache ist -- ein MERKMAL (".e-person",
   mindestens zwei), wo Struktur die Sache ist. Eine Zahl kann beides
   nicht unterscheiden.

3. EIN ABSCHNITT, DER SPAETER KAM ALS DIE MESSUNG.

   "Die rechte Hand sieht ihre eigene Karte" war rot -- versteckt,
   obwohl der Server `hat_karte: true` sagte. Von Hand nachgesehen
   stand sie da. Die Entwicklungsseite laedt nacheinander (Aufgaben,
   Vorlagenbrett, eigene Karte), und zwischen zwei Schritten kann es
   laenger als 600 ms still sein -- die Ruheregel der Pruefung hielt
   das fuer "fertig". Jetzt wartet sie zusaetzlich auf den einen
   Abschnitt, der sich selbst aufdeckt, hoechstens zwei Sekunden.
   Nebenwirkung: Der Vergleich "zwei verschiedene Bildschirme" misst
   jetzt 632 gegen 1191 Zeichen statt 350 gegen 350.

   109 Pruefungen, 0 Fehler (vorher 8).

4. UND EINE FESTE ZAHL, DIE MIT DER SEITE GEWACHSEN IST.

   `pruef-buehne` erlaubte hoechstens ZWEI Texte, um die herum kein
   freier Untergrund zu finden ist. treff-regeln.html hat inzwischen
   40 Textstuecke, drei davon stehen dicht -- 7,5 %. Die Sorge dahinter
   bleibt richtig (eine Pruefung, die kaum hingesehen hat, darf nicht
   "bestanden" sagen), aber das ist eine Frage des ANTEILS: zwei von
   vier waere schlimm, drei von vierzig ist es nicht. Jetzt: zwei
   immer erlaubt, darueber ein Zehntel -- und die Meldung nennt die
   Textanfaenge, damit man in einer Sekunde sieht, worum es geht.

ZWEI NEUE WERKZEUGE, beide aus der Not dieser Runde entstanden:
  mess-farbe-am-text.mjs  -- liest die Farben an Ort und Stelle aus und
                             geht die Elternkette hoch bis zur ersten
                             deckenden Flaeche
  mess-seiteninhalt.mjs   -- zeigt, was auf einer Seite wirklich steht,
                             mit ROLLE=hand auch mit fremden Augen

GEMESSEN: pruef-neue-seiten 109/0, pruef-buehne alles in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 12:48:16 +02:00
DogFatherGitandClaude Opus 5 e7cd1984d8 Ein Rollenname im ausgelieferten Code, die Seite zu breit, und drei Pruefungen, die den Umbau verschlafen hatten
Filipe: "falls es noch was gibt was fehlt oder nicht richtig funktioniert,
auf dem handy oder auf dem pc, oder als installiert, ich will dass du das
alles abcheckst und machst dass jede seite reibungslos klappt."

Gemessen wurde der ganze Bestand: 26 Pruefdateien einzeln, dazu drei neue
Messungen fuer Dinge, die keine Pruefung ansieht. Von 37 roten Meldungen
aus dem Nachtlauf sind nach dieser Runde die haelfte erledigt -- und die
Haelfte davon war gar nicht kaputt.

=== ECHTE FEHLER ===

1. EIN ROLLENNAME STAND IM AUSGELIEFERTEN QUELLTEXT.
   `aufgaben.js` sagte "Modis moechten das uebernehmen -- du
   entscheidest". Diese Datei bekommt JEDER, der die Seite oeffnet:
   jeder Manager, jeder Scout, jeder Creator im anderen Haus. Der
   verborgene Zugang haelt genau so lange, wie der Name dort nicht
   steht. Er stammte aus der Bewerbungsspalte von gestern -- einen Tag
   alt, gefunden von pruef-modi-wortleck. Jetzt: "Jemand moechte das
   uebernehmen". Wer es ist, steht ohnehin mit Namen auf den Karten
   darunter, und die sieht nur, wer sie sehen darf.

2. DIE SUPPORT-SEITE WAR AUF JEDER BREITE UNTER 1440 px ZU BREIT --
   13 px auf dem Handy, 41 px auf dem Tablet quer, 30 px auf dem
   Laptop. Schuld war das weiche Licht, das ich in der Nacht eingebaut
   habe: `inset: -8% -4% 0`. Die vier Prozent rechts sahen nach einer
   Kleinigkeit aus; ein absolut gesetztes Element zaehlt aber zur
   Scrollbreite, auch mit `pointer-events: none` und `z-index: -1`.

   `pruef-breiten` hat es gemeldet und konnte nicht sagen, WAS es ist
   ("13px Ueberstand []") -- ein Pseudoelement hat keine Box im DOM.
   Gefunden hat es eine neue Messung, die JEDES echte Element abfragt:
   keines ragte heraus, und genau das war der Hinweis.
   Jetzt: 0 px auf allen neun Breiten, 38 Seiten, 84 252 Elemente.

3. EIN AUFGABENLINK IM REPORT WAR 27 x 18 px GROSS. Mit der Maus gut,
   mit dem Daumen nicht -- eine Fingerkuppe ist rund 45 px breit.
   Jetzt fuellt der Link die Zeile und ist 44 px hoch, aber nur auf
   schmalen Bildschirmen und an groben Zeigegeraeten. Die zweite
   Bedingung habe ich beim ersten Anlauf vergessen, und der Link blieb
   27 x 21 -- eine Regel, die nur unter idealen Bedingungen greift,
   hilft niemandem auf dem halben Weg dorthin.

4. EINE SEITE LUD DAS FALSCHE MANIFEST. `anruf-probe.html` verwies
   fest auf `crew.webmanifest`; die Seite ist aber fuer ALLE Rollen
   offen und damit auf beiden Adressen erreichbar. Wer sie im
   Agenturhaus oeffnet und die App installiert, bekam "DogFather
   Universe" mit dem Crew-Symbol auf den Startbildschirm. Alle anderen
   38 Seiten machen es richtig: `app.webmanifest`, und die Adresse
   biegt es um.

5. DER KNOPF "+ GIF HINZUFUEGEN" WAR 40 px HOCH, und der Kommentar
   daneben nannte das "die Hausgroesse". Die Hausgroesse sind 44 --
   fuenfmal in derselben Datei so begruendet. Die erste Reparatur
   griff nicht: Die Fingerregel stand 400 Zeilen VOR der Grundregel,
   und bei gleicher Staerke gewinnt die spaetere. Jetzt steht sie
   direkt dahinter, und der Knopf misst 133 x 44 am Finger, 133 x 40
   an der Maus.

   KEINE PRUEFUNG KONNTE DAS FINDEN: Die GIF-Tafel ist zu, solange
   niemand sie aufmacht, und alle Rundgaenge messen, was auf dem
   Bildschirm steht. Dafuer gibt es jetzt server/mess-gifs-handy.mjs.

6. ZWEI KLEINIGKEITEN AUS DER NACHT: eine Fehlerkennung ohne Satz
   (`unbekannter_punkt`) und eine Stelle in support.js, die den
   Serverfehler roh anzeigte statt durch `fehlerText` -- die zwei
   anderen Stellen derselben Datei machen es richtig. So entsteht eine
   Ausnahme: nicht aus Absicht, sondern weil man die Hausregel beim
   Neuschreiben nicht danebenliegen hatte.

7. TOTES CSS (.e-leerwahl, vier Regeln). Der Leerkasten ist am
   24.09. auf Filipes Wunsch wieder verschwunden, sein Stil blieb
   einen Tag laenger stehen.

=== ROT, ABER NICHT KAPUTT ===

Drei Pruefungen haben den Umbau vom 24.09. nicht mitbekommen:

  pruef-anruf meldete 31 Fehler und "ein Gespraech entsteht (403)".
  Sie meldete DogFather auf der AGENTUR-Adresse an und liess ihn dann
  die rechte Hand anrufen -- die es dort seit der Haustrennung nicht
  gibt. Der Server hatte recht. Jetzt telefoniert Team Dogi auf crew.,
  und der Creator bleibt auf workspace. -- seine Gegenprobe ist damit
  sogar schaerfer als vorher (ein Fremder aus dem ANDEREN Haus).
  96 -> 127 Pruefungen, 0 Fehler.

  pruef-crew-wand-bild erwartete vier Rollen auf der Zugangswand. Es
  sind fuenf, seit die linke Hand am 21.09. dazukam. Die Zeile stand
  unter einem Kommentar, der wortwoertlich vor festen Namen in
  Pruefungen warnt ("eine Zeitbombe mit Datum") -- und war selbst
  einer. Jetzt leitet sie die Rollen aus `rollenImHaus("crew")` ab,
  derselben Quelle, aus der der Server die Wand baut.

  pruef-entwicklung-kacheln rechnete noch mit "x von 68". Seit
  Filipes Wunsch ("es sollen nur die menge angezeigt werden die wir
  zutragen") ist das Ganze das, was jemandem zugetragen ist. Sie baut
  jetzt BEIDE Faelle -- eine Person mit vier zugetragenen Punkten und
  eine ohne -- und misst Ring, Bogen, Zeile und Vorleseschild gegen
  die Zuteilung. Dazu eine Gegenprobe mit einer Einschaetzung auf
  einem NICHT zugetragenen Punkt: zaehlt die Uebersicht sie mit,
  stuende dort 2 statt 1. 31 -> 34 Pruefungen, 0 Fehler.

=== WAS DIE BILDSCHAU ANGEHT ===

Meine eigene Messung meldete erst "Mitte 174 von 640" -- die Schau sah
kaputt aus. Sie war es nicht: `querySelector("img")` nahm das
Husky-Zeichen in der Kopfzeile statt des Bildes. Nachgemessen am
richtigen Element steht es auf 195 von 195 (Handy) und 640 von 640
(Rechner), und ein GIF oeffnet sich als GIF. Ein Messfehler, der wie
ein Befund aussieht, kostet mehr Zeit als gar keine Messung -- deshalb
steht die Begruendung jetzt im Quelltext der Messung.

GEMESSEN: pruef-breiten (9 Breiten, 38 Seiten, 84 252 Elemente),
pruef-support 63/0, pruef-gifs 17/0, pruef-chat 63/0, pruef-chat-optik
62/0, pruef-tippziele 11/0, pruef-css-klassen, pruef-struktur,
pruef-meldungen, pruef-modi-wortleck, pruef-crew-adresse,
pruef-installieren, pruef-aufgabenbrett, pruef-entwicklung -- alle 0
Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 12:31:21 +02:00
DogFatherGitandClaude Opus 5 39ca642a52 Acht Pruefungen standen Nacht fuer Nacht als rot da -- sie waren gruen
Der naechtliche Lauf meldete heute frueh "37 Pruefungen sind rot".
Acht davon waren gar nicht rot: fehlerfrei durchgelaufen, Exitcode 0,
keine einzige FEHL-Zeile. Der Laeufer zaehlte bei ihnen aber NULL
Einzelpruefungen, und "null Pruefungen ist ein Fehler" -- eine Regel,
die richtig ist und hier das Falsche traf.

DER GRUND WAR EIN GROSSBUCHSTABE. Der Zaehler suchte `(ok|FEHL)`;
pruef-kachelfarben, -livepunkt, -tippziele, -turn-wege, -leerzustand,
-nachfrage, -tagesruf und -anruf-klingelt schreiben `  OK `.

Zwei Schaeden auf einmal:
  1. Ihre Punkte fehlten in der Gesamtzahl -- allein in fuenf der acht
     sind das 114 Stueck. Ausgerechnet die Zahl, die vor stillen
     Aussetzern schuetzen soll, war selbst eine Luecke.
  2. Acht dauerhaft rote Eintraege in einer Notiz, die morgens gelesen
     wird. Eine Warnung, die immer kommt, ist keine mehr.

Der Zaehler liest jetzt beide Schreibweisen. Die Dateien werden NICHT
vereinheitlicht: Acht umzuschreiben waeren acht Gelegenheiten, etwas
kaputtzumachen -- und die neunte, die morgen jemand anlegt, schreibt
ohnehin wieder, was sie will.

DAZU EINE PRUEFUNG, DIE DAS FESTHAELT (server/pruef-pruefzaehler.mjs).
Ein Kommentar haette den naechsten Fall nicht verhindert. Sie holt
sich den Ausdruck AUS alles-pruefen.mjs (zwei Fassungen desselben
Musters laufen auseinander), startet vier der schnellsten Pruefungen
wirklich -- je zwei in beiden Schreibweisen -- und hat drei
Gegenproben: Sie darf nicht wahllos zaehlen, sie muss zwei als zwei
zaehlen, und sie muss null als null sehen koennen, sonst waere "null
ist ein Fehler" blind.

UND DIE NOTIZ SAGT JETZT, WAS SIE MEINT. Statt "(keine Fehlerzeile
gefunden)" steht bei diesen Faellen: "Kein Befund -- es wurde keine
einzige Pruefung GEZAEHLT", mit der Erklaerung dazu. Fuer alles andere
ohne Fehlerzeile gibt es den dritten Ausgang ("Konnte nicht sagen,
woran es lag") samt den letzten Ausgabezeilen.

NEBENBEFUND, GEFUNDEN VON pruef-rueckmeldung: Die Tuer ins andere Haus
trug Ton 40 -- dieselbe Nummer wie "Entwicklung". Auf DogFathers Wand
standen zwei Kacheln in derselben Farbe, und er ist der Einzige, der
beide sieht; deshalb ist es nie jemandem aufgefallen.

  Die naheliegende Antwort waere eine 46. Farbe gewesen. Gerechnet kam
  ein Abstand von 0,0862 heraus -- unter der Hausgrenze von 0,09. Der
  Farbraum ist bei 45 Toenen voll, und eine zweite benannte Ausnahme
  am selben Tag waere der Anfang vom Ende der Regel.

  Richtig ist die andere Antwort: Die Tuer ist gar keine
  Bereichskachel. Sie fuehrt hinaus und gehoert keinem Bereich an --
  also bekommt sie keine Bereichsfarbe, sondern faellt auf --akzent
  zurueck. Damit unterscheidet sie sich von allen 45 anderen.

  Gefunden hat das die Pruefung erst, nachdem sie SAGEN konnte, welche
  Nummer doppelt ist. Vorher stand dort nur "kein Farbton doppelt (34
  Kacheln vom Server)" -- damit sucht man in vier Listen ueber zwei
  Dateien.

  Dazu: start.js schreibt kein data-ton="undefined" mehr (String()
  macht aus einem fehlenden Wert sonst ein Wort, und jede Pruefung,
  die Toene zaehlt, liest dann Text statt Zahl).

WAS MICH VOR DER FALSCHEN REPARATUR BEWAHRT HAT: Meine erste Vermutung
war, die FEHL-Zeilen staenden zu weit hinten im Ausgabefenster. Die
Gegenprobe dazu wurde rot -- null Dateien. Genau dafuer ist sie da.

GEMESSEN:
- pruef-pruefzaehler (neu): 7 Pruefungen, 0 Fehler.
- pruef-rueckmeldung: 30 geprueft, 0 Fehler (war rot).
- pruef-kachelfarben 26/0, pruef-haus-trennung 100/0,
  pruef-crew-adresse 153/0.
- tools/.nachtlauf-* ist jetzt ignoriert: Laufzeitzustand, der sich
  jede Nacht aendert. Das Ergebnis steht in der Vault-Notiz.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 06:46:49 +02:00
DogFatherGitandClaude Opus 5 257c01b8f0 Support: Babyblau mit Lila, und der Melder bekommt seine Knoepfe wirklich
Nachtrag zu cebdd88e. Ein Bildschirmfoto der fertigen Seite hat drei
Dinge gezeigt, die keine Pruefung sehen konnte.

1. DIE KACHEL WAR IMMER NOCH ORANGE.

   Filipe: "die hauptfarbe der kachel soll auch babyblau sein mit bissl
   lila." Die Seite trug zwar `--akzent: #a8d8ff`, aber der Kopf faerbt
   sich ueber `--ton` -- und der stand am body auf Ton 44, dem Orange
   vom 24.09. Die Variable war gesetzt und wirkungslos.

   Ton 44 ist jetzt #a8d8ff. WEIL DIE FARBE DIESMAL AUS EINEM WUNSCH
   kam und nicht aus einer Rechnung, wurde sie nachgemessen:

     Kontrast gegen den dunklen Grund   12,46:1   (Hausgrenze 4,5)
     Abstand zur naechsten Kachelfarbe  0,1125    (Ton 15)
     Engstes Paar im Haus ohnehin       0,0154
     -> 7,3-fach weiter weg als das schwaechste Glied

   Babyblau haelt die Buntheitsgrenze (0,12) NICHT und kann sie nicht
   halten -- das liegt am Wort. Nachgemessen mit einer Suche ueber den
   ganzen Blaubereich: Es gibt KEINE Farbe, die gleichzeitig babyblau
   aussieht, Buntheit >= 0,12 und Abstand >= 0,09 schafft; der beste
   Kandidat kommt auf 0,075 Abstand. Der Blaubereich ist von sechs
   Toenen besetzt.

   DIE GRENZE WURDE DESHALB NICHT GESENKT, sondern BENANNT ausgenommen
   (`blassErlaubt` in pruef-kachelfarben). Eine gesenkte Grenze gaelte
   fuer alle 45 Toene; eine benannte gilt fuer eine und steht mit
   ihrem Grund da. Und sie kostet etwas: Wer blass sein darf, muss
   beim Abstand >= 0,10 halten -- gemessen, nicht versprochen, mit
   Gegenprobe.

   NEBENBEI ZWEI ALTE ROTE BEHOBEN: Die Prüfung war seit dem 24.09.
   rot (engstes Paar 0,0862 zwischen Ton 41 und 45, und zwei Farben in
   der Regenbogenkachel stimmten nicht mehr). Ton 45 neu gerechnet
   (0,0914) und die Kachel nachgezogen. 22 -> 26 Pruefungen, 0 Fehler.

2. DIE LEITUNG SAH DIE KNOEPFE DES MELDERS.

   Der Server lehnte sie richtig mit 404 ab -- die Karte bot sie ihr
   trotzdem an. `darf_bestaetigen` war eine Aussage ueber die MELDUNG
   statt ueber den BETRACHTER. Zwei Knoepfe, die nur eine Fehlermeldung
   koennen, sind schlimmer als gar keine.

   Jetzt fragen Route UND Anzeige dieselbe Funktion `darfBestaetigen`.
   Es ist ausdruecklich "ist der Melder" und nicht "ist nicht Leitung":
   Die Leitung darf ihre EIGENE Meldung bestaetigen, nur keine fremde.

   Und die Leitung sieht bei "wartet" jetzt, wer dran ist -- "Liegt bei
   Miss" mit ruhig atmendem Punkt, dazu "Noch etwas nachschicken ..."
   statt "Behoben - nachfragen ...". Sie hat ja schon nachgefragt.

3. NACHLEGEN HAETTE DEN VERLAUF VERDOPPELT.

   Antwortet die Leitung ein zweites Mal, waehrend die Meldung beim
   Melder liegt, entstand eine ZWEITE Zeile "Runde 1" -- und sein
   spaeteres Urteil haette beide gleichzeitig beschriftet. Jetzt
   ersetzt ON CONFLICT die Antwort in derselben Runde.

   DER EIGENTLICHE FUND STECKTE IM INDEX: `CREATE UNIQUE INDEX IF NOT
   EXISTS` unter dem alten Namen tut auf dem Server NICHTS -- dort gibt
   es den Namen schon, als gewoehnlichen Index, und IF NOT EXISTS
   sieht nur den Namen, nicht die Bauart. Der Index waere nie eindeutig
   geworden, ON CONFLICT haette kein Ziel gefunden, und das Nachlegen
   waere abgebrochen -- genau dort, wo lokal alles gruen ist, weil jede
   Pruefung ihre Datenbank frisch anlegt. Gefunden beim Durchspielen
   auf einer KOPIE der echten Datenbank. Der alte Index wird jetzt
   ausdruecklich weggenommen, der neue heisst anders.

GEMESSEN:
- pruef-support 59 -> 63 Pruefungen, 0 Fehler (darunter: die Leitung
  bekommt die Knoepfe NICHT, und Nachlegen laesst EINE Runde stehen).
- Die Index-Umstellung auf einer Kopie der echten Datenbank
  durchgespielt: alter Index weg, neuer eindeutig, ON CONFLICT trifft.
- pruef-kachelfarben 26/0, pruef-css-klassen, pruef-deutsche-texte: gruen.
- server/mess-support-runde.mjs (neu) macht vier Bilder: Leitung,
  Melder, Melder auf dem Handy, und den Verlauf nach zwei Runden.
  Es misst den "wer ist dran"-Hinweis ausdruecklich mit -- der war
  einmal stumm ausgefallen (before() auf einem Element ohne
  Elternknoten tut nichts, ohne Fehlermeldung).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 05:10:58 +02:00
DogFatherGitandClaude Opus 5 cebdd88e8d Support: der Melder hat das letzte Wort -- und die Kachel bekommt ihren eigenen Stil
Filipe: "ich will dass die leute die mir was geschickt haben im support,
auch meine notiz bekommen wenn ich fertig bin. damit die bescheid wissen
und dan anklicken koennen, es funktioniert, oder noch nicht. und erst
wenn es funktioniert gedrueckt wird, will ich dass alles richtig fertig
ist. perfektionier den ganzen weg und mit dem gedanken das manchmal
sachen mehrmal nicht sofort perfekt sein werden."

DER GANZE WEG, nicht nur der Schlusspunkt:

1. Die Leitung drueckt "Behoben - nachfragen ...". Der Knopf hiess
   vorher "Erledigt ..." und tat auch das; jetzt stellt er eine Frage,
   also heisst er auch so. Eine Beschriftung, die etwas anderes sagt
   als der Knopf tut, glaubt man genau einmal.

2. Die Meldung steht auf "wartet" -- ein vierter Stand zwischen "wird
   bearbeitet" und "erledigt". Beim Melder heisst er "geht es wieder?",
   weil er aus SEINER Sicht keine Wartezeit ist, sondern eine Frage.

3. Er sieht die Notiz und zwei Knoepfe. "Geht wieder" ohne Rueckfrage
   (der haeufige, harmlose Fall). "Noch nicht" verlangt ein Wort --
   sonst faengt die Suche von vorn an und die naechste Runde waere
   dieselbe wie die letzte.

4. "Noch nicht" ist keine Beschwerde, sondern Runde 2: zurueck in
   Arbeit, Rundenzahl plus eins, Leitung bekommt eine Nachricht, und
   der Verlauf behaelt, was beim letzten Mal versucht wurde. Niemand
   faengt von vorn an -- genau der Fall, den Filipe genannt hat.

5. Erst sein "Geht wieder" schliesst die Meldung. Danach kann weder er
   noch die Leitung sie wieder aufmachen (409).

NUR DER MELDER darf bestaetigen, ausdruecklich nicht die Leitung
(`person_id !== req.person.id`, nicht "ist Leitung") -- sonst nickt sie
ihre eigene Arbeit ab und der ganze Umweg waere Zierde. Eine fremde
Meldung gibt 404, nicht 403: Wer sie nicht sehen darf, soll auch nicht
erfahren, dass es sie gibt.

DER VERLAUF STEHT UNTEREINANDER statt nur der letzten Antwort. Bei
Runde drei war sonst nicht mehr zu sehen, was beim ersten Mal versucht
wurde, und genau das loest einen wiederkehrenden Fehler. Meldungen von
vor diesem Umbau haben keinen Verlauf -- die zeigen wie bisher ihre
blosse Antwort, ein leerer Kasten waere schlechter als der alte Satz.

DIE KACHEL SIEHT ANDERS AUS (zweiter Wunsch: "viel geiler viel
profissioneller ... die hauptfarbe soll babyblau sein mit bissl lila").
`support-seite` traegt den Stil; alle Regeln haengen daran und gelten
damit nur hier. Zwei weiche Lichter, Pillen statt Kaesten als Filter,
eine leuchtende Naht ueber dem Meldefeld. Augenschonend: gedeckt, kein
Neon, Kontrast geprueft.

GEMESSEN:
- pruef-support: 45 -> 58 Pruefungen, 0 Fehler. Der ganze Weg einmal
  durch, MIT einer Runde, die schiefgeht. Dazu drei Gegenproben: die
  Leitung kann nicht fuer den Melder bestaetigen (404), "noch nicht"
  ohne Wort wird abgelehnt (400), eine geschlossene Meldung bleibt zu
  (409, aus beiden Richtungen).
- Die Schemaaenderung auf einer KOPIE der echten Datenbank
  durchgespielt: 72 Tabellen, keine Zeile und keine Spalte verloren,
  support_runden und `runde` da, 'wartet' in der CHECK-Regel.
- pruef-css-klassen, pruef-deutsche-texte, pruef-code, pruef-glocke:
  alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 04:55:14 +02:00
DogFatherGitandClaude Opus 5 939aa6371b Zutragen geht jetzt direkt am Punkt -- ein Griff statt eines Fensters
Filipe: "ich will sofort über diese aufgaben da spezifisch zuteilen
kann bitte. bei allen personnen."

DAS AUSWAHLFENSTER BLEIBT -- es ist der Weg, wenn man jemanden neu
einrichtet und zwoelf Punkte auf einmal vergibt. Der Knopf am Punkt ist
der andere Fall, und der haeufigere: Man liest eine Beobachtung, denkt
"das soll er machen", und will es in dem Moment erledigen -- nicht ein
Fenster aufmachen, in einer Liste von 68 denselben Punkt suchen und
wieder zumachen.

AUS DER MARKE WIRD DER SCHALTER. An derselben Stelle, an der bis eben
nur "Aufgabe" stand, sitzt jetzt der Knopf, mit dem man es tut. Er
steht IMMER da, auch wenn nichts zugetragen ist: Auf einem Handy gibt
es kein Ueberfahren, und einen Knopf, der erst beim Zeigen erscheint,
gibt es dort nicht. Im Ruhezustand ist er ein Umriss -- 68 gefuellte
Kaestchen untereinander waeren ein Balken.

EIN PUNKT, EIN AUFRUF -- und das ist nicht nur Bequemlichkeit: Wuerde
dieser Knopf die ganze Liste schicken (wie das Fenster), loeschte er
die Zutragung, die jemand anderes eine Sekunde vorher gemacht hat.
Genau das misst die Pruefung: erst zutragen, dann nachsehen, ob die
vorherigen unberuehrt sind.

ZWEIMAL DASSELBE IST KEIN FEHLER. Wer zweimal tippt oder zwei Fenster
offen hat, bekommt denselben Zustand -- nicht eine Absage und nicht
einen doppelten Eintrag (`ON CONFLICT DO NOTHING`).

DIE ZAHL KOMMT VOM SERVER ZURUECK und wird nicht im Browser
weitergerechnet: Bei zwei offenen Fenstern waere die eigene falsch, und
niemand saehe, warum. Kopf, Ring und Kachel ziehen damit sofort nach --
ohne Neuladen und ohne Sprung.

EIN FUND AM WERKZEUG, eine Ebene tiefer: tools/_um.py stellt Anker auf
die Zeilenenden der Datei um -- und entwicklung.css hat GEMISCHTE
(Bestand CRLF, ein angehaengter Block LF). Der Anker wurde auf CRLF
gestellt und traf den LF-Teil nicht; die Meldung lautete "Anker 0x",
und man sucht den Fehler im Anker, obwohl er Zeichen fuer Zeichen
stimmt. Genau die Sorte Fehlalarm, gegen die dieses Werkzeug gebaut
wurde. Es probiert jetzt beide Arten und ersetzt mit der, die an der
Fundstelle gilt.

Geprueft: pruef-entwicklung 63 -> 70 Punkte, darunter zwei Gegenproben
(ein erfundener Punkt wird abgewiesen, ein Modi traegt nichts zu).
pruef-tippziele (11) und pruef-css-klassen unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 04:40:21 +02:00
DogFatherGitandClaude Opus 5 177c3c012a Die Bildschau und 2520 Farben statt 360
=== 1. BILDER OEFFNEN SICH MITTIG, MIT HUSKY UND HASE ===

Filipe: "wenn man bilder aufmacht, will ich dass die in der mitte sind.
beim hochformat soll links der husky sein und rechts der hase und beim
querformat soll oben dogfather und unten team dogi stehen da wo platz
ist ... ich will nicht dahin geschmissen sondern was richtig geiles mit
einem geilen hintergrund."

WAS VORHER PASSIERTE, und es war kein Fehler im Code: Der Klick fuehrte
auf die DATEI. Was man dann sah, war die eingebaute Bildanzeige des
Browsers -- schwarzer Grund, Bild oben links in der Ecke, auf seinem
Bildschirmfoto 1200 px Schwarz daneben. Eine Datei hat keine
Gestaltung. Wer Gestaltung will, muss eine SEITE zeigen.

Die Schau liegt jetzt UEBER dem Chat. Escape bringt einen dorthin
zurueck, wo man war, und das Gespraech laeuft im Hintergrund weiter --
ein zweiter Tab braeuchte eine eigene Seite, eine eigene Anmeldung und
einen eigenen Weg zurueck.

DER WEG IN DEN TAB BLEIBT TROTZDEM. Der Verweis hat unveraendert
`href`, `target` und `rel`; mittlere Maustaste, "In neuem Tab oeffnen"
und Herunterladen gehen wie seit jeher. Abgefangen wird nur der
gewoehnliche Klick -- und auch der nur, wenn die Schau geladen ist.
Wer Strg, Umschalt oder Befehl haelt, bekommt den alten Weg; das sind
die Griffe, die Leute seit zwanzig Jahren benutzen.

DIE BEGLEITER STEHEN DA, WO PLATZ IST -- und die Antwort darauf wird
GEMESSEN, nicht geschaetzt: nicht die Fensterbreite, sondern der Rest
neben dem Bild, nachdem es eingepasst ist. Eine Schwelle wie "ab
1100 px" waere fuer ein 3:4-Foto richtig und fuer ein 9:16-Foto auf
demselben Schirm falsch. Unter 170 px bleibt der Husky weg: Eine Figur,
die ein Streifen ist, steht besser nicht da.

Husky und Hase sind eigens verkleinert (2,1 MB und 1,0 MB werden 40 kB
und 32 kB) und bekommen weiche Raender -- ihr Hintergrund ist dunkel,
aber nicht durchsichtig; als Rechteck saehe man zwei Kaesten.

Der erste Anlauf spiegelte den Hasen, damit beide "nach innen" schauen
-- ein alter Reflex aus dem Plakatsatz. Auf dem Probebild stand danach
"Hasi Dog" seitenverkehrt auf seinem Hoodie. Schrift im Bild spiegelt
man nie.

pruef-chat-anhaenge bekommt 14 neue Punkte, darunter beide Formate und
zwei Gegenproben: Strg+Klick oeffnet die Schau NICHT (sonst hiesse "sie
geht auf" nur, dass der alte Weg verloren ist), und im Hochformat liegt
KEINE der Figuren ueber dem Foto.

NEBENBEFUND, den die Pruefung gefunden hat: Die Sprachnachricht war auf
165 px geschrumpft -- zu schmal fuer den Schieber. Ursache war keine
Aenderung an ihr, sondern eine Folge: Die Blase ist so breit wie ihr
breitester Inhalt, und seit die Handgriffe darunter Zeichen statt
Woerter sind (123 statt ueber 400 px), bestimmt das Abspielgeraet die
Breite selbst. Eine Reihe kuerzer zu machen hat einen Schieber schmaler
gemacht, drei Bildschirme weiter.

=== 2. DER FARBKREIS: HELLER UND DUNKLER ===

Filipe: "dieser kreis muss viel perfekter sein. ich will dass die leute
auch heller und dunkler aussuchen koennen ... so dass die leute viel
krassere moeglichkeiten haben."

WARUM DAS BIS HEUTE NICHT GING: Die 360 Toene liegen alle auf DERSELBEN
Leuchtdichte. Das war kein Zufall -- solange die Blase in der gewaehlten
Farbe stand, musste jede dieser Flaechen dieselbe Schrift tragen. Eine
hellere Farbe zuzulassen hiesse damals: irgendwo wird eine Nachricht
unlesbar.

SEIT DEM 25.09.2026 IST DIE BEDINGUNG EINE ANDERE. Die Blase ist fuer
alle dunkles Glas; der Ton ist Kante und NAME. Damit faellt die alte
Regel weg, und an ihre Stelle tritt: der Ton muss als Name auf dem
Blasengrund lesbar bleiben.

DIE ZAHLEN SIND GEMESSEN, NICHT GEWAEHLT. Ueber alle 360 Winkel, jeweils
der schlechteste Fall:

    40 % schwarz   4,468   -- unter der Schwelle, faellt raus
    34 % schwarz   4,555   -- ginge, aber ohne Reserve
    30 % schwarz   4,619   <- die dunkelste Stufe
     0 %           5,12    <- die Mitte, der alte Kreis
    55 % weiss     9,6     <- die hellste Stufe

Sieben Stufen, 2520 Farben statt 360. pruef-chat-neu rechnet jede
einzelne nach -- die knappste hat 2,6 Prozent Reserve.

DIE ALTEN SCHLUESSEL BLEIBEN GUELTIG. "ton-214" heisst weiterhin genau
dieselbe Farbe; die Stufe steht als Zusatz dahinter ("ton-214-s6"). Wer
seit dem 23.09. eine Farbe traegt, traegt nach diesem Umbau dieselbe.

DIE PROBE IN DER MITTE ZEIGT ENDLICH, WAS MAN BEKOMMT. Dort stand eine
gefuellte Flaeche mit heller Schrift -- so sah die Blase bis heute frueh
aus. Jetzt steht dort derselbe Blasengrund und darauf der Ton als Name,
mit genau der Rechnung aus chat.css. Das ist nicht nur ehrlicher, es
macht die sieben Stufen erst moeglich: Eine gefuellte Flaeche muesste
Schrift tragen, und bei sehr hellen Toenen schafft das keine der beiden
Schriftfarben mehr (4,1 statt noetiger 7). Als Name auf dunklem Grund
ist derselbe helle Ton besonders gut lesbar (8,0).

Der Erklaersatz im Fenster war damit falsch geworden ("Alle Toene
leuchten gleich stark") und sagt jetzt, was stimmt.

ZWEI PRUEFUNGEN WURDEN GENAUER:
  pruef-chat-neu mass den HINTERGRUND der Mitte -- eine Darstellung,
  die es nicht mehr gibt. Sie misst jetzt die Schriftfarbe und rechnet
  die Mischung nach. Dabei stolperte sie ueber eine dritte
  Farbschreibweise: Chromium gibt `color-mix`-Ergebnisse als
  `color(srgb 0.676 0.645 0.504)` zurueck. Die Zeile war rot, obwohl
  die Farbe auf den Bildpunkt genau stimmte -- ein Fehlalarm, der
  teurer ist als ein echter Befund, weil man am Aussehen sucht und der
  Fehler im Lesegeraet liegt.
  Und sie prueft nicht mehr 360, sondern 360 x 7 -- nur den Grundton zu
  messen hiesse, sechs Siebtel ungeprueft auszuliefern.

Geprueft: pruef-chat-anhaenge (123), pruef-chat-neu (36),
pruef-chatkachel (40), pruef-chat, pruef-chat-ausbau (69),
pruef-chat-optik, pruef-tippziele (11), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 04:35:12 +02:00
DogFatherGitandClaude Opus 5 4b48aa46f6 Berichtigt: Die Leitung sieht wieder alle 68 -- gezaehlt wird das Zugetragene
Filipe: "falsch, dogfather und die rechte hand sollen immer noch die 68
sachen sehen wie vorher und der button soll einfach perfektioniert
werden damit wir beide sie den jeweiligen als aufgabe geben koennen.
und die modis sollen nicht sehen. aber unsere sicht von dogfather und
rechte hand soll sich nicht aendern."

MEIN FEHLER WAR EINE VERWECHSLUNG von zwei Dingen, die gleich aussehen
und verschieden sind:

  EINGRENZEN  -- die Liste wird je Person kuerzer. Das habe ich gebaut.
  ZUTRAGEN    -- aus der vollen Liste bekommt jemand etwas als AUFGABE.
                 Das war gemeint.

Der Unterschied zaehlt: Die 68 sind das, woran ihr euch entlanghangelt,
wenn ihr jemanden anseht. Eine Liste, die sich je Person verkuerzt,
waere bei jedem Menschen eine andere -- und dann faellt kein Vergleich
mehr auf.

DIE KARTE ZEIGT WIEDER ALLES, und an jedem Punkt steht, ob er diesem
Menschen als Aufgabe zugetragen ist: eine Kante links und das WORT
"Aufgabe". Nicht nur die Farbe -- wer Farben schlecht unterscheidet,
saehe sonst nur einen etwas anderen Kasten.

GEZAEHLT WIRD TROTZDEM DAS ZUGETRAGENE. Filipe: "es sollen nur die
menge angezeigt werden die wir zutragen und erledigte dan auch nur die
die erledigt wurden von den zugetragenen." Aus "0 von 68 angesehen"
wird "3 von 12 erledigt".

BEIDE HAELFTEN MUSSTEN MITZIEHEN, und das ist die Stelle, an der es
leicht schiefgeht: Die Kachel nahm links die Zahl ALLER
Einschaetzungen. Waere nur das Ganze nachgezogen worden, stuende dort
"13 von 3" -- eine Zahl, die groesser ist als ihr Ganzes, und die
niemand mehr erklaeren kann. Der Verbund mit der Zuteilung steht
deshalb schon in der Abfrage, an drei Stellen: Karte, Uebersicht und
Ring.

NULL ZUGETRAGEN IST KEINE NULL, SONDERN EIN SATZ. "0 von 0 erledigt"
liest sich wie ein Versaeumnis; "noch nichts zugetragen" sagt, was zu
tun ist. Der Knopf heisst jetzt auch, was er tut: "Aufgaben zutragen".

Der leere Kasten, der im ersten Anlauf die ganze Karte ersetzte, ist
weg -- genau der hatte die Sicht der Leitung veraendert.

Geprueft: pruef-entwicklung 61 -> 63 Punkte. Die neuen halten
ausdruecklich fest, was ich falsch gemacht hatte: Die Leitung sieht den
GANZEN Katalog (68), und die Liste bleibt auch nach dem Zutragen
vollstaendig -- nur die Marke wandert. Ohne diese zwei Zeilen waere
dieselbe Eingrenzung beim naechsten Umbau wieder eine Zeile Arbeit und
niemandem aufgefallen. Dazu pruef-css-klassen und pruef-tippziele.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 04:04:29 +02:00
DogFatherGitandClaude Opus 5 7099d53da0 Die Handgriffe an der Nachricht werden Zeichen -- eine Zeile statt drei
Filipe: "diese optionen im chat. ich will dass du das viel geiler
machst und es soll viel kuerzer gestaltet sein. so dass es nicht zu
viel aufmerksamkeit auf sich zieht aber jeder sieht dass es da ist.
aber kurz und knapp was richtig geiles schnell benutzbar aber nicht zu
viel platzraubend."

HEUTE FRUEH BEKAMEN DIE FUENF WOERTER ZEICHEN DAVOR. Das war der
richtige Schritt und nur der halbe: Gemessen auf 412 px brauchte die
Reihe danach DREI Zeilen -- "23. Sept. antworten reagieren" /
"loeschen (Notfall) anheften" / "kopieren". Unter zwei Zeilen Text
standen drei Zeilen Bedienung.

WOERTER SIND HIER DER FALSCHE MASSSTAB. Man liest sie nicht -- man
sucht das eine, das man gerade braucht. Fuenf Woerter nebeneinander
sind fuenfmal Lesen fuer einen Griff; fuenf Zeichen sind ein Blick.

Nachgemessen: aus ueber 400 px in drei Zeilen werden 123 px in EINER.

DAS WORT IST NICHT WEG, ES IST NUR NICHT ZU SEHEN. Es steht weiter im
Dokument (`clip-path`, nicht `display: none`) und damit:
  * ein Vorleseprogramm liest "antworten", nicht "Schaltflaeche";
  * `textContent` liefert es weiterhin -- daran haengt
    pruef-chat-ausbau, das den Kopierknopf beim Wort nimmt;
  * unter dem Zeiger steht es als `title`.
Ein Knopf ganz ohne Beschriftung waere kuerzer gewesen und schlechter.

KEINE FLAECHE IM RUHEZUSTAND. Fuenf Kreise nebeneinander waeren wieder
ein Balken. Es gibt nur das Zeichen, gedaempft; die Flaeche entsteht
erst unter dem Zeiger. "Jeder sieht, dass es da ist" heisst sichtbar,
nicht laut. Zwei Ausnahmen, und beide sind Zustand statt Griff: Das
Notfall-Loeschen traegt auch im Ruhezustand Farbe (wer fremde Worte
entfernt, soll den Knopf nicht verwechseln), und eine angeheftete
Nachricht zeigt ihre Nadel dauerhaft -- sonst muesste man jede
Nachricht ueberfahren, um zu sehen, welche haengt.

"kopiert" HAT KEIN WORT MEHR, ALSO BRAUCHT ES EIN ZEICHEN: Der Knopf
wird fuer anderthalb Sekunden gruen und traegt einen Haken. Ohne das
waere der Druck folgenlos -- man weiss nicht, ob es geklappt hat.

44 PX AM DAUMEN (Hausregel): Fuenf mal 44 plus Abstaende sind 236 px,
eine Blase hat auf 412 px innen 251. Die Reihe bleibt damit auch auf
dem Handy einzeilig.

pruef-css-klassen hat sofort gemeldet, dass die Uhrzeit auf 11,2 px
stand -- 0,3 unter der Hausgrenze. Das ist heute das dritte Mal
derselbe Reflex ("klein wirkt leise"), und die Pruefung hat ihn
dreimal gefangen. Leise macht die Deckung, nicht die Groesse.

pruef-chat-ausbau bekommt vier neue Punkte, und sie sichern genau das
ab, was sonst als naechstes "aufgeraeumt" wuerde: dass jeder Handgriff
sein Wort und seinen Vorlese-Satz behaelt, dass KEINES davon zu sehen
ist, und dass alles in einer Zeile steht. Der erste Anlauf mass die
Breite des Kastens und meldete 486 px -- das war die Blase, nicht die
Reihe. Gemessen wird jetzt, worum es geht: die Zahl der Zeilen.

Geprueft: pruef-chat-ausbau (68), pruef-chat-optik, pruef-chat-aufloesen
(126), pruef-chat-kanaele (81), pruef-tippziele (11), pruef-css-klassen,
pruef-lesbarkeit.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:58:43 +02:00
DogFatherGitandClaude Opus 5 b3d3714efd Nicht jeder bekommt alle 68 Punkte -- DogFather und die rechte Hand suchen je Person aus
Filipe: "ich will dass die rechte hand und ich diese aufgaben die es da
gibt, individuel aussuchen koennen wer welche aufgabe bekommt. bis
dahin sollen die keine aufgaben sehen. nur die, die die rechte hand
oder dogfather ihnen zutragen."

VORHER GEFRAGT, UND ES WAR NOETIG. Auf entwicklung.html stehen zwei
Listen untereinander -- das Vorlagenbrett (Aufgaben zum Verteilen) und
der Beobachtungskatalog (die 68 Punkte je Person). Sein Text passte auf
das eine, sein Bildschirmfoto zeigte das andere. Am 24.09. habe ich in
genau dieser Lage geraten und an der falschen Stelle gebaut. Seine
Antwort: der 68-Punkte-Katalog, das Vorlagenbrett "nicht anfassen".

BIS HEUTE GALTEN ALLE 68 FUER JEDEN. Das war bequem und in der Sache
falsch: "Clips, Schnitt und Kommentare" gehoert nicht zu jemandem, der
nur im Chat moderiert -- und ein Punkt, der nie zutrifft, steht
trotzdem in der Zaehlung. "0 von 68" bei jemandem, fuer den zwoelf
gelten, ist keine Auskunft, sondern eine Entmutigung.

EINE TABELLE, EINE ZEILE JE PAAR. Eine kommagetrennte Liste in der
Personenzeile waere schneller gebaut und liesse sich nicht abfragen
("wer hat diesen Punkt?"), nicht zaehlen und nicht absichern. Wer und
wann stehen mit drin -- fuer die Frage "seit wann gilt das eigentlich
fuer ihn", die erfahrungsgemaess dann kommt, wenn sie niemand mehr
beantworten kann.

EINE STELLE FUER DIE ANTWORT, drei Aufrufer: die Karte der Leitung, die
Uebersicht mit den Zahlen und der Auswahl-Dialog. Drei Abschriften
waeren drei Gelegenheiten, dass eine nicht mitzieht -- und dann stuende
in der Uebersicht "von 68", waehrend in der Karte zwoelf Punkte stehen.

DIE ZAHLEN ZIEHEN MIT. "X von Y" zaehlt jetzt das Zugeteilte. Auch die
linke Zahl musste nachgezogen werden: Wer frueher zu einem Punkt
gesetzt hat, der ihm inzwischen nicht mehr zugeteilt ist, haette sonst
"13 von 12" bekommen.

GESPEICHERT WIRD DIE GANZE LISTE AUF EINMAL, in einer Transaktion. Wer
zwoelf Haken setzt und dabei die Verbindung verliert, haette sonst
sieben gesetzte und fuenf verlorene -- und saehe nicht, welche.

EINMALIG WIRD UEBERNOMMEN, wozu es schon eine Einschaetzung gibt. Ohne
das waere der Umbau Datenverlust auf dem Bildschirm: Wer zwanzig Punkte
gesetzt hat, saehe am naechsten Morgen eine leere Karte -- die Daten
liegen noch da, man kommt nur nicht mehr hin. Ein Flag verhindert, dass
die Uebernahme wiederkommt, nachdem jemand bewusst abgewaehlt hat; an
einer Wegwerf-Datenbank durchgespielt, beide Laeufe wie erwartet.

NOCH NICHTS AUSGESUCHT HEISST NICHT "KAPUTT". Die Karte sagt es dann
mit einem Satz und einem Knopf. Ein leerer Bildschirm ohne Erklaerung
ist die schlechteste Antwort von allen -- man weiss nicht, ob es laedt,
ob etwas kaputt ist oder ob schlicht noch niemand ausgesucht hat.

Geprueft: pruef-entwicklung 48 -> 61 Punkte. Zuerst das Wichtigste an
seinem Satz ("bis dahin sollen die keine aufgaben sehen"): ohne
Zuteilung ist die Karte leer -- ohne diese Zeile waere alles Folgende
auch dann gruen, wenn weiterhin alles fuer jeden gilt. Dazu vier
Gegenproben: erfundene Schluessel fallen weg, ein Modi sucht nicht aus
(404) und nach seinem Versuch steht der Bestand unveraendert da, und
alles wieder wegzunehmen geht ebenfalls (eine Auswahl, die man nur
erweitern kann, waere eine Falle). pruef-css-klassen und
pruef-tippziele (11) unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:50:15 +02:00
DogFatherGitandClaude Opus 5 e5e5953c43 Die Schriftleiste klappt hinter einen Knopf -- 73 px weniger Konsole auf dem Handy
Filipe: "die sachen von screen3 verbinde die mit dem auf screen4. so
dass wenn man drauf drueckt man die anderen zu sehen bekommt. damit es
nicht zu viel platz nimmt. und dan screen5, passe die reihenfolge der
sachen danach an und dan perfektionierst du das alles auf dem handy
auch bitte."

F, K, U und S standen als EIGENE ZEILE ueber dem Schreibfeld --
dauerhaft, auf jedem Geraet. Gemessen auf 390 px: Die Konsole brauchte
dafuer drei Reihen statt zwei. Nachgemessen ist es jetzt genau
73 px Hoehe, jeden Tag, fuer vier Zeichen, die man in den seltensten
Nachrichten braucht.

DER KNOPF HEISST "Aa" UND STEHT ALS LETZTES WERKZEUG, direkt vor dem
Schreibfeld -- das ist die neue Reihenfolge, um die Filipe gebeten hat:
Bueroklammer, Mikrofon, GIF und Emoji fuegen etwas EIN; das hier
veraendert, was schon dasteht. Die Reihe geht damit von "dazu" nach
"daran", und das Letzte liegt dem Text am naechsten.

"Aa" und kein Symbol: Ein Stift heisst "bearbeiten", ein Pinsel
"malen". Fuer Fett und Kursiv gibt es seit jeher genau ein Zeichen, das
jeder liest, ohne es zu lernen.

AUF DEM HANDY IST DAS DER GANZE PUNKT: Statt drei Reihen (Zeichen /
Werkzeuge / Feld+Senden) sind es zwei. Der Aa-Knopf faellt dabei nicht
ins Gewicht, weil er IN der Werkzeuggruppe sitzt -- die bricht als
Block um, und ein Knopf mehr laesst das Schreibfeld nicht schrumpfen.
Das ist dieselbe Ueberlegung, die die Gruppe am 23.09. ueberhaupt
entstehen liess.

DIE WAHL WIRD GEMERKT. Wer viel gestaltet, gestaltet weiter -- die
Leiste bleibt dann auch nach dem Neuladen offen. Die TASTENKUERZEL
laufen unabhaengig davon: Strg+B und Strg+I haengen am Schreibfeld,
nicht an der Leiste. Zugeklappt wird sie versteckt, nicht abgebaut.

ZWEI SACHEN AN DEN PRUEFUNGEN, und die erste ist ein Fund:

  pruef-chat-optik verlangte "die vier Werkzeuge stehen in einer
  Gruppe" -- mit einer festen 4. Diese Zahl war vom ersten Tag an eine
  Rechnung von gestern: Kommt ein Werkzeug dazu, wird die Zeile rot,
  obwohl nichts kaputt ist, und wer sie dann auf 5 setzt, macht
  denselben Fehler mit einer anderen Zahl. Dieses Haus ist an festen
  Zahlen schon dreimal hereingefallen (Kopfleiste 06.09.,
  Schriftgroessen 14.09., Tippziele 20.09.). Gefragt wird jetzt, was
  gemeint ist: Liegt KEINES der Werkzeuge ausserhalb der Gruppe? Das
  misst, statt zu rechnen -- und der naechste Knopf bringt es nicht zu
  Fall. Die Anzahl steht trotzdem in der Bedingung, sonst waeren
  "0 von 0" gruen.

  Die Gegenprobe wollte im ersten Anlauf Strg+B tippen. Das lief in
  eine Zeitbombe: Der Treff hat eine Nachtruhe, und zwischen 22 und
  6 Uhr ist das Schreibfeld `disabled` -- die Pruefung waere sechs
  Stunden am Tag rot gewesen, ohne dass an der Sache etwas ist. Genau
  die Sorte Fehlalarm, die am 06.09.2026 schon einmal notiert wurde.
  Gemessen wird jetzt die Sache selbst: Die vier Knoepfe sind weiterhin
  im Dokument und haben nur keine Flaeche mehr.

pruef-tippziele meldete sofort "1 ungedeckt: .chat__schriftknopf
(40h 40w)" -- am Daumen fehlten vier Pixel. Nachgezogen, wie bei den
vier Werkzeugen daneben.

Geprueft: pruef-chat-optik (mit 6 neuen Punkten, alle gruen),
pruef-tippziele (11), pruef-css-klassen, pruef-chat-ausbau (64).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:39:04 +02:00
DogFatherGitandClaude Opus 5 8bf2f440d0 Bewerbungen der Modis bekommen eine eigene Spalte im Aufgabenbrett
Filipe: "ich will in dieser seite auch eine eigene kategorie fuer die
aufgaben wo die modis sich selbst bewerben. ich will dass man die
getrennt sieht. mach es richtig uebersichtlich."

WO SIE VORHER STANDEN, und warum das nicht reichte: nur auf dem
Vorlagenbrett, an der jeweiligen Karte. Das ist der richtige Ort zum
ENTSCHEIDEN -- man liest Aufgabe und Name nebeneinander. Es ist der
falsche Ort zum SEHEN: Wer morgens das Aufgabenbrett oeffnet, sieht
nicht, dass drei Leute auf eine Antwort warten, und das Vorlagenbrett
ist eine Seite weiter. Fuer den Modi gab es ueberhaupt keine Stelle,
an der stand "dein Wunsch ist angekommen".

DIE SPALTE STEHT GANZ VORN. Sie ist die einzige, in der jemand auf eine
ANTWORT wartet -- alle anderen zeigen Arbeit, die laeuft. Und sie
VERSCHWINDET, wenn nichts wartet: Eine leere Spalte "Bewerbungen"
stuende 360 Tage im Jahr im Weg, um an fuenf Tagen etwas zu sagen. Die
vier festen Spalten haben auch leer eine Aussage ("hier landet, was
fertig ist"); diese nicht.

WAS AUF DER KARTE STEHT: der TITEL der Vorlage (nicht ihr Schluessel),
wer sie uebernehmen moechte, und sein eigener Satz dazu -- als Zitat
gesetzt, mit Strich davor. Er gehoert ihm, nicht dem Brett. Ohne ihn
entscheidet man ueber einen Namen.

DER TITEL WIRD NACHGESCHLAGEN, NICHT MITGESPEICHERT. Er gehoert dem
Katalog; stuende er in der Bewerbungszeile, gaebe es zwei Wahrheiten,
und die aeltere gewinnt still, sobald jemand eine Vorlage umbenennt.

EIN EIGENER, KLEINER WEG statt eines Mitschleppens:
`/workspace/api/vorlagen/bewerbungen` liefert nur die Bewerbungen --
nicht den ganzen Katalog, der an `/workspace/api/vorlagen` haengt. Das
Brett zeichnet sich bei jedem Statuswechsel neu; der Katalog ist um ein
Vielfaches groesser als die Handvoll Bewerbungen.

WER ENTSCHEIDEN DARF, SAGT DER SERVER (`darf_entscheiden`) -- nicht der
Rollenname im Browser. `assets/js` bekommt jeder, der die Seite
oeffnet, und ein Rollenvergleich dort ist in diesem Haus allein diese
Woche dreimal veraltet. Bis die Antwort da ist, gilt `false`: lieber
einen Knopf zu spaet zeigen als einen, der eine Absage holt.

DIE FARBE IST NEU IM BRETT. Die vier vorhandenen stehen fuer einen
Arbeitsstand (grau, blau, gelb, gruen); hier wartet niemand auf Arbeit,
sondern auf eine Entscheidung. Kein Rot ("kaputt"), kein Gelb (heisst
schon "zur Freigabe") -- Violett, das im Chat seit gestern fuer "an
dich gerichtet" steht. Eine Sprache im Haus.

Geprueft: pruef-bewerbung-aufgaben 101 -> 111 Punkte. Darunter die drei
Gegenproben, ohne die "die Spalte ist da" nichts bewiese: ohne
Bewerbung gibt es sie NICHT, der Modi bekommt KEINE
Entscheidungsknoepfe (sondern "wartet auf Antwort"), und die Spalte
steht wirklich an erster Stelle. Dazu pruef-aufgabenbrett und
pruef-vorlagen (24), beide unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:29:33 +02:00
DogFatherGitandClaude Opus 5 1a14eb7449 Die rechte Hand fuehrt ihre Aufgaben, jede Karte hat denselben Fuss, und Dubletten lassen sich aufraeumen
=== 1. BEARBEITEN UND LOESCHEN, WAS SIE ANGELEGT HAT ===

Filipe: "kuemmer dich bitte auch drum dass die rechte hand, wenn sie
aufgaben an die modis oder linke hand erstellt, will ich dass sie die
moeglichkeit hat die auch zu bearbeiten und zu loeschen bitte.
perfektionier das fuer sie und fuer dogfather."

WARUM ES VORHER NICHT GING, und es sah nicht danach aus: `creator_id`
heisst nicht "wer hat sie angelegt", sondern "zu wem gehoert sie" (so
steht es am Tabellenkopf). Verteilt die rechte Hand eine Aufgabe an
einen Modi, steht dort der MODI. Sie erfuellte damit an ihrer eigenen
Aufgabe keine der drei Bedingungen von `darfAendern` und bekam 403 --
auf einen Knopf, den die Oberflaeche ihr trotzdem anbot, weil sie ihn
an `darf_verteilen` haengte: eine Auskunft ueber die PERSON, wo die
Frage der AUFGABE gilt.

Die Spalte `erstellt_von` gibt es seit jeher und wird beim Anlegen
gefuellt -- die Sichtbarkeitsregeln fragen sie an sechs Stellen ab. Sie
stand nur nie in dieser einen Zeile. Und sie fehlte in SPALTEN, kam
also in keiner Aufgabe mit: Die neue Regel waere ein Vergleich gegen
`undefined` geblieben.

DIE REGEL IST ALLGEMEIN, NICHT AUF EINE ROLLE GEMUENZT: wer etwas
angelegt hat, darf es auch aendern. Ein Rollenname waere die naechste
zweite Wahrheit -- in dieser Woche ist genau das dreimal veraltet.

LOESCHEN BEKOMMT EINE EIGENE FRAGE, weil es das Einzige ist, was sich
nicht zuruecknehmen laesst: `darfAufgabenVerteilen(person) &&
darfAendern(person, aufgabe)`. Damit darf sie ihre eigenen -- und der
Modi, bei dem die Aufgabe LIEGT, darf sie weiterhin bearbeiten, aber
nicht verschwinden lassen. Ablehnen und Abbrechen sind die Wege dafuer.

Die Loesch-Route holt die Aufgabe jetzt mit der Sichtbarkeitsregel und
antwortet mit 404 statt 403, wenn es sie fuer diese Person nicht gibt
-- sonst liesse sich durch Ausprobieren herausfinden, welche Nummern
vergeben sind. Beim Aendern stand das schon so, eine Route weiter oben.

pruef-verteilen: 19 -> 30 Punkte. Mit drei Gegenproben, ohne die "sie
darf" auch dann gruen waere, wenn jeder alles duerfte: der Modi wird
abgewiesen (403), die Aufgabe steht danach noch da, und eine FREMDE
Aufgabe loescht sie nicht.

=== 2. JEDE KARTE HAT DENSELBEN FUSS ===

Filipe: "wer hat sie soll bitte bei all diesen aufgaben stehen. bei all
diesen kategorien da. ... es soll auch immer gleich aussehen und nicht
manchmal verschoben und so."

ZWEI URSACHEN, und keine davon war Zufall:

  a) "Wer hat sie?" entstand nur, solange oben "Alle" gewaehlt war
     (`if (anAlle)`). Wer auf einen Namen tippte, verlor den Knopf an
     ALLEN zwoelf Karten, ohne dass irgendwo stand, warum. Die Auskunft
     "wer aus dem Team hat diese Vorlage" haengt aber an der VORLAGE,
     nicht an der Auswahl -- sie daran zu binden war der Fehler.

  b) Der Fuss war EINE Reihe mit `flex-wrap`, und wie viele Angaben
     darin stehen, haengt von der Karte ab: "Frist" immer, "fuer:
     Rolle" manchmal, "liegt bei 4 von 5" nur, wenn schon jemand sie
     hat. Karten ohne den dritten Text hatten noch Platz fuer einen
     Knopf, Karten mit ihm nicht -- also stand "An alle" mal neben der
     Frist und mal darunter. Zwoelf Karten, drei verschiedene Fuesse.

Jetzt zwei Reihen mit fester Aufgabe: oben, was man LIEST; unten, was
man DRUECKT. Die Knopfreihe ist immer die letzte Zeile und sitzt am
unteren Rand, also stehen die Knoepfe bei allen Karten einer Reihe auf
derselben Hoehe -- auch wenn der Text darueber verschieden lang ist.

Die Rueckseite verteilt jetzt IMMER an alle. Vorher nahm sie
`katalogZiel()`; solange sie nur bei "Alle" existierte, war das
dasselbe. Seit sie immer da ist, waere es eine Falle: Der Knopf sagt
"Nachholen - 3 fehlen" und gaebe sie einer einzigen Person.

=== 3. DUBLETTEN AUFRAEUMEN ===

Filipe zu "Diene x6 - Ghost x6 - Marina x6 - Miss x6" bei "0 von 24":
"mach aus den 6 1 mal bitte, ich hab mich da geirrt."

`tools/aufgaben-doppelte.mjs` raeumt das auf. Es TUT VON SICH AUS
NICHTS: ohne `--wirklich` zeigt es nur, was passieren wuerde. Mit
`--wirklich` legt es ZUERST eine Kopie der Datenbank an (`VACUUM INTO`,
nicht `cp` -- eine blosse Dateikopie kann das WAL verlieren) und nennt
den Befehl, mit dem man zurueckkommt.

WELCHE BLEIBT, ist nicht beliebig: eine erledigte, wenn es sie gibt
(getane Arbeit wirft man nicht weg), sonst eine begonnene, sonst die
aelteste. An einer Wegwerf-Datenbank durchgespielt: 12 Aufgaben, zwei
Menschen, einer mit einer erledigten darunter -- es blieben genau die
richtigen zwei stehen, die Einzelaufgabe blieb unberuehrt, und das
Nachzaehlen am Ende meldete null Dubletten.

Geprueft: pruef-verteilen (30), pruef-vorlagen (24),
pruef-aufgaben-vorlagen, pruef-aufgabenbrett, pruef-modi-katalog (150),
pruef-bewerbung-aufgaben (101).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:20:04 +02:00
DogFatherGitandClaude Opus 5 c64732b16d Neuer Stil "Nachtprisma", Gespraeche anheften, und unten wieder Luft
Drei Sachen aus einem Bildschirmfoto-Satz.

=== 1. EIN ANDERER STIL, NICHT DIESELBE SPRACHE MIT NEUEN DETAILS ===

Filipe, zum dritten Mal an derselben Stelle: "du verstehst es wirklich
nicht ... ich will eine komplette aenderung vom aussehen. vom
hintergrund und von der grossen kachel. ich will einen ganz anderen
stil ... die leute sollen morgen nichts mehr wieder erkennen vom
aussehen her."

WARUM MEINE ZWEI ANLAEUFE DAVOR NICHT GEREICHT HABEN -- und das ist
kein Geschmacksstreit, sondern ein Fund:

Der Umriss des Chats kommt gar nicht aus chat.css. Er steht in
module.css, in einer Liste von 50 Klassen, und `.chat` ist eine davon:
Fase oben links, Kantenlicht, Punktraster, drei goldene Eckwinkel.
module.css wird NACH chat.css geladen -- und die Staerke des `:is(...)`
dort ist (0,2,0), weil `.gruppe[data-gruppe]` mit in der Liste steht.
Jede meiner Regeln war gleich stark und kam frueher. Deshalb stimmte
beides: "ich habe den Rand geaendert" und "der Rand ist derselbe". Ich
habe zweimal Details INNERHALB eines Rahmens geaendert, den ich nicht
angefasst hatte -- und den erkennt man zuerst.

Der neue Block steht als eine klar benannte Schicht am Ende von
chat.css, mit `.inhalt.chat-seite` -- eine Klasse mehr als module.css,
kein `!important` (das waere eine Tuer, die man nie wieder zubekommt).

  ALT                        NEU
  Fase oben links            rundum 26 px weich
  drei goldene Eckwinkel     keine -- der Koerper traegt sich selbst
  Punktraster                drei weiche Lichter im Hintergrund
  1-px-Rahmen ueberall       kein Rahmen, Lichtkante innen
  Gold als Leitfarbe         Lavendel/Violett, Blasen wie gehabt
  Kaesten nebeneinander      Koerper mit Tiefe und farbigem Schatten

DIE LEITFARBE WIRD AN EINER STELLE GETAUSCHT, nicht an zwanzig. Im
ersten Anlauf habe ich zehn Regeln einzeln umgefaerbt und danach im
Bild gesehen, dass Suchfeld, "Neu", Zaehler und Fokusrahmen weiter
golden waren -- sie nehmen alle `--akzent` und `--rand`. Jetzt stehen
beide am `<main>` der Chatseite. Uebersicht, Kalender und Aufgaben
behalten ihr Gold; nur der Chat soll nicht wiederzuerkennen sein.

#b9a7ff UND NICHT #7a5cff, und das ist gerechnet, nicht gewaehlt: Die
Akzentfarbe ist hier auch FLAECHE unter dunkler Schrift (die
Ungelesen-Marke). Das satte Violett kommt dort auf 3,7:1 -- zu wenig.
Das helle auf 8,9:1, und als Schrift auf dunklem Grund genauso.

WAS UNANGETASTET BLEIBT: `--blasengrund`, `--blase-text`,
`--blase-leise`, `--namen-anteil`. An ihnen haengen die Messungen von
pruef-chatkachel (12 Kacheln) und pruef-chat-neu (360 Ringtoene). Ein
Stilwechsel darf eine Zusage nicht nebenbei aufheben.

pruef-chat-optik hat sofort einen echten Schaden gemeldet: Der neue
Stil nahm allen Blasen den Rahmen -- und damit auch den, mit dem eine
NICHT ABGESCHICKTE Nachricht markiert ist ("der Unterschied ist auch zu
SEHEN, nicht nur im Merkmal (Rand 0px)"). Genau dafuer steht die Zeile
dort. Der Warnton sitzt jetzt zusaetzlich im inneren Saum.

=== 2. GESPRAECHE ANHEFTEN ===

Filipe: "ich will dass man auch individuel jeder fuer sich auch in der
liste chats fixieren kann. auch mehrere nicht nur eins."

Drei Aussagen, und jede wird einzeln geprueft:

  "fixieren"     -> `fixiert_am` an der TEILNEHMER-Zeile; Angeheftetes
                    steht oben, darunter geht die gewohnte Reihenfolge
                    weiter.
  "individuell"  -> die Spalte haengt an der Person, nicht am Raum. Eine
                    Spalte an `chat_raeume` haette alles andere genauso
                    erfuellt und jedem im Raum das Gespraech oben
                    hingeklebt -- gemerkt haette man es erst, wenn sich
                    jemand beschwert. Die Gegenprobe prueft deshalb
                    ausdruecklich, dass es bei Luna weder markiert ist
                    noch nach oben rutscht.
  "auch mehrere" -> keine Obergrenze. Ein Zeitstempel statt Ja/Nein
                    kostet dasselbe und beantwortet die Frage mit,
                    in welcher Reihenfolge mehrere stehen: zuletzt
                    angeheftet oben.

Die Nadel steht IMMER an der Zeile, nicht erst beim Ueberfahren -- am
Handy gibt es kein Ueberfahren (dieselbe Entscheidung wie am 23.09. bei
den Handgriffen), und eine Spalte, die mal da ist und mal nicht, laesst
die Namen daneben wandern. Sie liegt schraeg, solange nichts
angeheftet ist, und steht aufrecht, wenn doch -- das sieht man auch
ohne Farbe.

Der Zustand wird GESCHICKT, nicht errechnet (`an: true/false`): Ein
Schalter, der den Gegenwert selbst ausrechnet, kippt bei zwei schnellen
Klicks oder zwei offenen Fenstern in den falschen Zustand.

Die Karte ist seit heute die ZEILE und nicht mehr der Knopf darin --
im ersten Anlauf sass die Nadel sichtbar ausserhalb der Flaeche, wie
ein Knopf, der danebengefallen ist.

=== 3. UNTEN WIEDER LUFT ===

"schieb das bisschen hoeher bitte, weil das ist unten zu nah am rand."
14 px Polsterung. Sie geht nach INNEN (`border-box`), macht die Seite
also nicht laenger -- sonst waere das Schreibfeld wieder unter den
Bildrand gerutscht, und genau darum ging es am 09.09. schon einmal.

Geprueft: pruef-chat (neuer Abschnitt Anheften, 14 Punkte, alle gruen),
pruef-chat-optik, pruef-chatkachel (40), pruef-chat-neu (32),
pruef-chat-ausbau (64), pruef-chat-kanaele (81), pruef-chat-aufloesen
(126), pruef-chat-anhaenge (109), pruef-erwaehnung (129),
pruef-css-klassen, pruef-tippziele (11), pruef-lesbarkeit.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 03:07:05 +02:00
DogFatherGitandClaude Opus 5 63a3fb4af8 Die rechte Hand sieht die Personenseite wirklich -- Liste, Rollenkarten und das Protokoll
Filipe, zum wiederholten Mal und mit einem Bildschirmfoto genau dieser
Seite: "zum hunderstenmal, also bitte mach dass es jetzt endlich
klappt, die rechte hand sieht das immer noch nicht obwohl ich will dass
die rechte hand das auch sieht."

ZUERST NACHGEMESSEN, NICHT GERATEN. Am 24.09. habe ich auf ein
Bildschirmfoto hin an der falschen Seite gebaut und es im Commit selbst
notiert. Diesmal zuerst mess-hand-personen.mjs: dieselbe Seite, zwei
Anmeldungen, und der Unterschied wird aufgezaehlt. Ergebnis in einer
Zeile -- sie bekam vom Server alle acht Personen (HTTP 200) und sah auf
dem Bildschirm NICHTS davon. Nur das Anlege-Formular, darueber der Satz
"Codes, Sperren und das Protokoll bleiben bei DogFather".

ZWEI URSACHEN, UND NUR EINE WAR EINE SCHRANKE:

  1. Die OBERFLAECHE hat die Liste versteckt, die sie laengst geladen
     hatte. `personen.js` entschied die Ausbaustufe mit
     `ich.rolle !== 'admin'`, setzte damit `data-nur-anlegen`, und
     `personen.css` blendet darauf hin die Liste, das Protokoll und
     "Alle aufklappen" aus. Diese CSS-Regel stammt vom 07.09. und war
     fuer Manager und Spicy Media gedacht; die rechte Hand ist erst
     danach dazugekommen und fiel stillschweigend mit hinein.

     Das ist in dieser einen Datei die DRITTE Stelle, an der ein
     Rollenvergleich im Browser veraltet ist -- nach dem 22.09.
     ("keine Knoepfe") und dem 24.09. ("keine Rollenwahl"). Jedes Mal
     hatte sie das Recht und sah es nicht.

  2. Das Protokoll war am Server zu (HTTP 404). Damit ist der Satz von
     oben ueberholt: Filipes Ansage vom 24.09. -- "die selben rechte da
     haben wie dogfather, das einzige was sie nicht kann ist die
     dogfather rolle oder leute anfassen" -- laesst dafuer keinen Rest.

EINE AUSKUNFT FUER DREI STELLEN. `fuehrtDieZugaenge(person)` steht
jetzt in workspace.js und beantwortet dieselbe Frage fuer die Tuer am
Server, fuer `/api/ich` (`darf_zugaenge_fuehren`) und fuer die
Ausbaustufe der Seite. Drei Abschriften waeren drei Gelegenheiten, dass
die naechste Aenderung nur zwei davon trifft -- genau so ist dieser
Fehler entstanden.

`istHand` WAERE FALSCH GEWESEN. Es fasst beide Haende zusammen, und
fuer die linke gilt ausdruecklich das Gegenteil ("sieht weder
Bewerbungen noch den vertraulichen Meldeweg"). Wer hier den
Sammelbegriff nimmt, dreht eine ausgesprochene Entscheidung
stillschweigend um. Die Prueflung fragt sie deshalb einzeln.

DIE PRUEFUNG ZIEHT NACH (40 -> 49). Abschnitt 6 prueft beides: dass
die rechte Hand dasselbe Protokoll bekommt wie DogFather, und dass die
Auskunft, aus der die Oberflaeche ihre Ausbaustufe baut, mit der Tuer
am Server uebereinstimmt. Genau dieser Abgleich hat gefehlt: Eine
Rechtepruefung, die nur Serverantworten ansieht, hat den Fehler zwei
Tage lang nicht bemerkt. Dazu drei Gegenproben (linke Hand 404, Modi
404, linke Hand `darf_zugaenge_fuehren === false`).

Beim ersten Lauf waren diese Gegenproben rot -- mit 401 statt 404. Die
Abschnitte davor sperren und loeschen absichtlich Leute, und eine tote
Sitzung antwortet mit 401: Das sieht aus wie "darf nicht" und heisst
"gibt es nicht mehr". Ein 401 als Gegenprobe fuer ein 404 ist ein Haken
ohne Gegenstand. Abschnitt 6 legt sich deshalb frische Zugaenge an.

Geprueft: pruef-hand-personen (49, 0 Fehler), pruef-personen-liste,
pruef-personen-kachel (45), pruef-personen-loeschen,
pruef-modi-verborgen (85). Unveraendert rot und an HEAD nachgemessen,
also nicht von diesem Umbau: pruef-personen-formular (2),
pruef-community-sicht (1), pruef-spicy (3).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 02:47:07 +02:00
DogFatherGitandClaude Opus 5 24f9be8e4f Drei Fächer, Gesichter, Zeichen an jedem Handgriff -- der Chat ist nicht wiederzuerkennen
Filipe: "ich will 3 kategorien haben. chats mit einzelnen personen,
gruppen chats und kanäle." Und: "ich will dass du überhaupt die
komplette kachel veränderst, ich will dass alles anderst aussieht und
gestaltet ist, mach wirklich was verrücktes und übertrieben krank
geiles ... dass die ganze community und team morgen total überrascht
sind und den chat nicht wieder erkennen."

DIE LISTE HAT DREI FÄCHER. Personen, Gruppen, Kanäle -- als Mulde mit
drei Schaltern über dem Suchfeld, nicht als drei freie Knöpfe: Drei
Dinge, die einander ausschließen, liest man nur als EINE Entscheidung,
wenn sie in einer gemeinsamen Fassung sitzen. Das gewählte Fach liegt
oben auf (Licht, Schatten, Akzentsaum), die anderen liegen darin -- man
sieht die Wahl an der Tiefe, nicht nur an der Farbe. Die Wahl überlebt
das Neuladen; beim Suchen gilt sie nicht, wer einen Namen tippt will
ihn finden und nicht raten, in welchem Fach er liegt.

WAS EIN GESCHLOSSENES FACH NICHT VERSCHLUCKEN DARF: die Ungelesenen und
den Ruf. Beides steht deshalb AM Fach -- die Zahl in der Warnfarbe, das
@ in der Akzentfarbe. Gefunden hat die Lücke nicht ein Blick, sondern
pruef-erwaehnung: Die Erwähnung lag in einer Gruppe, offen war
"Personen", und das @ war damit nirgends zu sehen.

EIN LEERES FACH MERKT MAN SICH NICHT. Wer nur einen Kanal hat -- jeder
Neue im Haus -- landete auf "Personen" und sah eine leere Liste neben
einem vollen Kanal. Beim ersten Zeichnen wird deshalb ins erste Fach
gewechselt, in dem etwas steht; Reihenfolge: gerufen, dann ungelesen,
dann überhaupt vorhanden. Gespeichert wird das NICHT -- es ist geraten,
nicht gewählt. Gefunden von pruef-gifs.

EIN GESICHT IM KOPF DES GESPRÄCHS. Links in der Liste trägt jedes
Gespräch sein Zeichen, und ausgerechnet beim Öffnen verschwand es. Es
ist dasselbe Zeichen, nicht ein ähnliches: `zeichenFuellen()` füllt jetzt
Liste und Kopf -- rund fünfzig Zeilen standen vorher mitten im Zeichnen
und hätten sonst ein zweites Mal dagestanden. Am Handy bleibt es weg,
nachgerechnet: mit ihm blieben dem Namen 126 px bei 128 Untergrenze, die
Knopfreihe fiele eine Zeile tiefer.

JEDER HANDGRIFF BEKOMMT SEIN ZEICHEN. Unter jeder Blase standen fünf
Wörter in Versalien -- bei zwölf Nachrichten sechzig. Jetzt Pfeil,
Gesicht, Papierkorb, Nadel und zwei Blätter, das Wort klein daneben.
Die Wörter bleiben: "anheften" und "lösen" sehen als Nadel gleich aus,
und "löschen (Notfall)" darf nie ein Rätsel sein. Breiter wird es
trotzdem nicht -- gesperrte Versalien kosten rund ein Viertel mehr
Breite, genau das, was die Zeichen brauchen. Die Zeichen sind Masken:
sie folgen `currentColor` und damit jedem Zustand der Schrift daneben.

AUS DER FUSSZEILE WIRD EINE MULDE, und der Grund wird dabei dunkler,
nie heller -- das ist die Bedingung dafür, dass die Kontrastzusage
gültig bleibt. Die Uhrzeit bekommt ein eigenes Schild: eine Angabe,
keine Bedienung.

AUS DEM FARBFLECK WIRD EIN RING. Der Knopf für die eigene Kachel war
ein voller Kreis in der gewählten Farbe, direkt neben einer gleich
großen Marke -- man las ihn als Meldung, und er meldet nichts. Farbe
erscheint auf dieser Seite überall als Kontur; jetzt auch hier.

AUS DEM TOTEN TRENNER WIRD LICHT. Die senkrechte Linie am Verlauf
stammte aus der Zeit, als Liste und Verlauf EIN Kasten waren; seit dem
Umbau auf zwei Tafeln klebte sie ohne Aufgabe an der Kante. An ihrer
Stelle ein sehr weicher Schein oben rechts, unter vier Prozent Deckung
-- Tiefe, kein Leuchten.

DIE KONSOLE: Das Schreibfeld ist eine Rinne statt eines flachen
Kastens, die vier Werkzeuge sprechen dieselbe Sprache, und der
Absendeknopf ist als einziger gefüllt. Keine Maßzahl angefasst -- die
Zeile ist seit dem 23.09. auf den Pixel voll.

ZWEI PRÜFUNGEN WURDEN GENAUER, NICHT NACHSICHTIGER:

  pruef-chatkachel suchte ihre "freie Stelle" nicht, sie rechnete sie
  aus -- 6 px vom rechten Rand, halbe Höhe. Das lag mal auf dem
  Rollbalken, mal auf einer Blase, und meldete beides Mal "das
  Bühnenbild ist gar nicht da". Sie sucht die Stelle jetzt mit
  `elementFromPoint` und sagt es, wenn es keine gibt.

  pruef-erwaehnung prüft jetzt beides: dass das Fach den Ruf meldet,
  ohne geöffnet zu werden, UND dass die Zeile nach dem Wechsel dasteht
  -- mit der Gegenprobe, dass das Fach wirklich filtert. 126 -> 129.

Nachgebessert: die Ungelesen-Marke am Fach stand auf 0,64 rem = 10,24 px,
unter der Hausgrenze von 11,5. Gemeldet von pruef-css-klassen, bevor es
jemand auf einem Telefon sehen musste -- der zweite Anlauf desselben
Reflexes an einem Tag.

Geprüft: pruef-chat-optik, pruef-chatkachel (40), pruef-chat (ALLES IN
ORDNUNG), pruef-chat-neu (32), pruef-chat-ausbau (64),
pruef-chat-kanaele (81), pruef-chat-aufloesen (126),
pruef-chat-anhaenge (109), pruef-erwaehnung (129), pruef-css-klassen,
pruef-tippziele (11), pruef-lesbarkeit. pruef-gifs hat weiterhin die
zwei Fehler, die schon vor diesem Umbau da waren (an HEAD nachgemessen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 02:25:06 +02:00
DogFatherGitandClaude Opus 5 d47ccf0d5f Die Blase hört auf, eine Farbfläche zu sein -- der Chat sieht anders aus
Filipe: „es hat sich nichts verändert quasi … auch die kachel das
aussehen. die blasen. die schriften. alles soll anders und geiler
aussehen, moderner und spezieller."

ER HATTE RECHT, UND ICH WEISS JETZT WARUM. Der erste Anlauf hat
poliert statt umgebaut -- weil ich die FARBE der Blase für unantastbar
gehalten habe. Genau sie war das Problem: Zwei Drittel jeder Nachricht
waren eine deckende, kräftige Fläche, und darauf kämpfte alles andere
um Aufmerksamkeit. Jede Feinheit, die man darauf legt, verschwindet.

DIE BLASE IST JETZT DUNKLES GLAS -- für jeden dieselbe. Die persönliche
Farbe ist vollständig erhalten, sie sitzt nur woanders:
  * als leuchtende KANTE an der Sprechseite (links beim Gegenüber,
    rechts bei einem selbst),
  * im NAMEN, aufgehellt, damit auch ein dunkler Ton trägt,
  * als Hauch im oberen Verlauf und als Schein unter der Blase.
Man erkennt die Person weiterhin an der Farbe -- und der Text steht
endlich auf einem ruhigen Grund.

DAZU: Die Fußzeile bekommt eine Kante in der Farbe und wird zur
Beschriftung (Versalien, gesperrt, gedämpft); die Uhrzeit trennt sich
von den fünf Handgriffen; die Blase wird schmaler (66 % / 62 Zeichen --
darüber verliert man beim Zeilenwechsel die nächste Zeile); der Text
bekommt Durchschuss, weil helle Schrift auf dunklem Grund optisch
ausstrahlt; das Zeichen neben der Blase spricht dieselbe Sprache wie
die Liste; die offene Gesprächszeile bekommt dieselbe Kante wie die
Blasen.

WAS DAS FÜR DIE MESSUNGEN HEISST -- und das ist der wichtigere Teil:

pruef-chatkachel und pruef-chat-neu haben bis heute gerechnet „Schrift
X auf Kachelfarbe Y". Das gibt es nicht mehr. Die eine wäre GRÜN
geblieben und hätte nichts mehr über den Bildschirm gesagt (die
gefährlichste Sorte, in diesem Haus schon dreimal vorgekommen), die
andere wurde sofort rot. Beide sind mitgezogen:

  * Die feste Schrift wird gegen den festen Blasengrund gemessen --
    und zwar im SCHLIMMSTEN Fall: Die Blase ist zu 92 % deckend,
    dahinter liegt ein Foto, gerechnet wird mit Weiss dahinter.
    Gemessen 14,2:1 (nötig 7) und 7,9:1 (nötig 4,5).
  * NEU: Jede der 13 Kacheln UND alle 360 Töne des Farbrings müssen
    als NAME auf diesem Grund lesbar sein. Das ist die Stelle, an der
    es heute kippen kann.
  * Beides liest `--blasengrund` und `--namen-anteil` aus chat.css
    statt sie abzuschreiben. Wer dort etwas ändert, ändert die
    Prüfung mit.

UND SIE HAT SOFORT ETWAS GEFUNDEN: Mit 58 % Aufhellung schaffte der Ton
„Ziegel" als Name nur 4,31:1 -- unter den nötigen 4,5. Auf dem
Bildschirm sah er gut aus, weil hinter der Blase gerade nichts Helles
lag. Jetzt 50 % und 5,20:1. Dazu eine Gegenprobe, die beweist, dass das
Aufhellen keine Zierde ist (ohne sie: 2,05:1).

DREI EIGENE FEHLER, ALLE VON PRÜFUNGEN GEMELDET
  * 0,66 rem für die Fußzeile = 10,56 px, drei Stellen unter der
    Hausgrenze von 11,5 px. Jetzt 0,72 rem; leise wirkt sie durch
    Versalien und Deckung, nicht durch Kleinheit.
  * Auf dem Handy brach die Fußzeile in drei Zeilen -- schuld war meine
    eigene Regel `margin-right: auto` an der Uhrzeit, die am Rechner
    richtig ist. Dort jetzt Kleinbuchstaben und kein Schub.
  * Der Handy-Block stand MITTEN in der Datei. Eine Medienabfrage
    erhöht die Spezifität nicht -- jede spätere Basisregel gewann
    gegen ihn, und er wirkte halb. Er steht jetzt am Ende.

GEPRÜFT: chatkachel, chat-optik, chat-ausbau, chat, chat-neu,
chat-kanaele, css-klassen, lesbarkeit, tippziele — alle 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 01:42:19 +02:00
DogFatherGitandClaude Opus 5 bfae4447cd Der Chat bekommt Tiefe -- Lichtkante, Glas und Schatten statt flacher Flächen
Filipe: „ich will dass du die komplette seite viel geiler und moderner
machst. die komplette kachel. die chat liste und die chats selber. …
es soll komplett aus der rolle fahren und was was wir noch nie hatten,
ich will es wirklich übertrieben krass."

EIN SYSTEM, NICHT ZWANZIG EINFÄLLE. Alles Folgende geht auf dieselben
drei Regeln zurück, und deshalb passt es zusammen:

  1. LICHTKANTE  — jede Fläche hat oben eine haardünne helle Linie und
     unten eine dunkle. Damit wird aus einer Fläche ein Körper: Licht
     fällt von oben. Was VERTIEFT ist (Suchfeld, Knopfgruppe), bekommt
     es genau andersherum.
  2. TIEFENSCHATTEN — lang und weich, weit unterhalb. Er trägt, er
     umrandet nicht.
  3. GLAS — was oben liegt, ist leicht durchscheinend und verwischt,
     was dahinter ist. Dadurch sieht man die Ebene, ohne eine Linie.

WAS DAS KONKRET HEISST
  * Der Rahmen hat eine Kante statt eines Strichs; zwischen den beiden
    Spalten stossen zwei Platten aneinander.
  * Die Gesprächszeile HEBT sich beim Überfahren, statt sich zu färben
    — der Unterschied zwischen einer Tabelle und einer Bedienung.
  * Das Zeichen (Kreis mit Buchstabe) ist ein Körper mit Licht, Saum
    und eigenem Schein in der Rollenfarbe.
  * Die fünf Handgriffe unter jeder Blase waren unterstrichene Wörter
    — im Netz heisst das seit dreissig Jahren „führt woandershin", und
    genau das tun sie nicht. Jetzt leise Marken. Sie bleiben SICHTBAR:
    Die Entscheidung vom 23.09. gilt weiter (auf dem Handy gibt es kein
    Überfahren).
  * Der Datumstrenner ist ein Schild auf der Linie statt nackter
    Grossbuchstaben.
  * Die Eingabe ist eine Konsole: Glas, Lichtkante, Schatten nach oben.
    Die vier Buchstaben (F K U S) standen frei im Raum — jetzt Schalter
    in einem Streifen über dem Schreibfeld.
  * Der Verlauf hat einen weichen Saum: Nachrichten laufen UNTER Kopf
    und Konsole, statt an einer harten Kante abzubrechen.
  * Titel, Unterzeile und die vier Kopfknöpfe (jetzt eine Gruppe in
    einer Mulde) bekommen eine Rangfolge.

WAS ABSICHTLICH UNANGETASTET BLEIBT: die FARBE der Blase. Sie ist die
persönliche Kachel und wird von pruef-chatkachel gemessen — die Prüfung
rechnet mit dem Farbwert selbst. Ein Verlauf oder Glas darauf hätte den
gemessenen und den gesehenen Wert auseinandergebracht, und zwar still.
Die Blase bekommt Tiefe über Kante und Schatten, nicht über den Grund.

DREI EIGENE FEHLER, VON DEN PRÜFUNGEN GEFUNDEN
  * Die Formatknöpfe hatte ich auf 32 px verkleinert — hübscher, und
    damit unter der Grenze von 44 px, unter der ein Daumen danebentrifft.
  * Vier statt zwei Pixel Abstand dazwischen = sechs Pixel mehr an der
    schmalsten Stelle. Die Zeile ist dort seit dem 23.09. auf den Pixel
    voll.
  * Meine erste Fassung der Gestaltungsleiste zerlegte die Konsole in
    drei Zeilen.

UND EIN FEHLALARM, DER SEIT LANGEM ROT WAR: pruef-chat-optik verglich
die OBERKANTEN von Schreibfeld und Senden-Knopf. Die Zeile ist aber
unten bündig, das Feld zwei Zeilen hoch — die Oberkanten liegen
zwangsläufig 24 px auseinander, obwohl beide nebeneinander stehen.
Gemerkt habe ich es erst, als zwei Reparaturen die Zahl nicht bewegt
haben: Eine Zahl, die sich durch die Reparatur nicht ändert, misst
etwas anderes, als man denkt. Sie fragt jetzt nach der GEMEINSAMEN
Höhe (44 von 44) und ist damit strenger als vorher.

GEPRÜFT: chat-optik, chatkachel, chat-ausbau, chat, chat-neu,
chat-kanaele, css-klassen, tippziele, lesbarkeit — alle 0 Fehler.
Dazu mess-chat-optik.mjs: vier Bilder (Liste und Verlauf, 1440 und
412 px) auf eigener Wegwerf-Datenbank.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 01:20:16 +02:00
DogFatherGitandClaude Opus 5 e5cd016b60 Aus jedem Fenster kommt man heraus, die Kachel dreht sich, der Eingang sieht aus wie das Haus
VIER DINGE, und das erste ist eine Meldung aus dem Support.

1. MISS KAM AUS "AUFGABE BEARBEITEN" NICHT HERAUS.
   „Ich konnte da wieder nicht zurück gehen, musste die App schließen
   damit ich wieder auf die Hauptseite kam."
   Gemessen (mess-dialog-ausgang.mjs), vier Größen:
     412x915 App      782 px Inhalt in 784 px  -- knapp ja
     412x780 Browser  782 px Inhalt in 742 px  -- SACKGASSE
     360x640 klein    794 px Inhalt in 602 px  -- SACKGASSE
     412x430 Tastatur 794 px Inhalt in 392 px  -- SACKGASSE
   `.dialog` hatte `overflow: hidden`, eine Scroll-Höhe gab es NUR für
   `.dialog--breit`. Alles unterhalb des Rands wurde abgeschnitten --
   samt "Abbrechen". Jetzt rollt JEDES Fenster, und Kopf wie Knopfzeile
   bleiben stehen (`position: sticky`), damit man den Ausgang SIEHT,
   ohne erst durch acht Felder zu scrollen. Alle vier Größen: ja.

2. DIE VORLAGENKACHEL DREHT SICH.
   „wenn ich drauf drücke dreht sich die kachel und dan seh ich wer es
   gemacht hat, und immer noch die option es nochmal zu verteilen falls
   neue leute ins team zustoßen."
   Vorne bleibt die Kurzfassung ("liegt bei 3 von 4"), hinten stehen
   die Namen mit ihrem Stand und zwei Knöpfe: "Nachholen – 1 fehlt"
   (oder "Nochmal an alle", wenn wirklich alle sie haben) und "Zurück".
   Nach dem Verteilen dreht sie sich von selbst; wer nur nachsehen
   will, drückt "Wer hat sie?".

3. DER EINGANG SIEHT AUS WIE DAS HAUS.
   Fase und Leuchtschiene statt flachem Kasten, die Schiene in der
   Farbe des Stands. Die drei Zahlen werden drei Felder -- und die
   "0 neu" leuchtet nicht mehr rot: Eine Warnung, die immer kommt, ist
   keine Warnung. Ab 760 px steht das Bild neben dem Text statt
   darunter; die Karte war dadurch dreimal so hoch wie nötig.

4. DER CREATOR-KATALOG IST AUF DER TEAM-SEITE WEG.
   „es gibt keine creator auf dieser seite" -- dort stand "Wähle oben
   einen Creator", eine Aufforderung zu etwas Unmöglichem. Gefragt wird
   jetzt nach den Daten (gibt es jemanden, dem ich das geben kann?),
   nicht nach der Adresse.

DAZU FERTIG GEMACHT, WAS VON GESTERN OFFEN WAR:
  * Die zwei Serien ohne Haus ("Community-Call", "Schulung-Agentur").
    Ursache war meine eigene Abschrift: Bei den Terminen frage ich die
    Teilnehmerliste, bei den Serien hatte ich sie vergessen. Auf einer
    Kopie der echten Datenbank: 0 offene Zeilen.
  * Sieben Schreibwege setzen jetzt `haus` (Aufgaben, Einträge,
    Dateien, Material, Wissen, Video-Titelbild). Dabei gefunden:
    `material` verwaltet seine Spalten SELBST -- meine Spalte stand in
    der falschen Liste und fehlte auf einer frischen Datenbank
    (78 Fehlschläge in pruef-material, jetzt 159/0).
  * unterstuetzen.html lud meldung.js gar nicht -- dort stand das
    Maschinenwort des Servers statt eines Satzes (pruef-meldungen 8/0).

DREI VERALTETE PRÜFUNGEN NACHGEZOGEN, jede STRENGER als vorher:
  * "der Modi legt eine Aufgabe an (201)" -- seit dem 22.09. ist das
    403 und gewollt. Geprüft wird jetzt auch das WORT.
  * "calls.html ist verboten" -- Filipe hat die Kachel selbst verlangt
    ("jeder der einen kalender hat"). Mit Gegenprobe ersetzt.
  * "Review" heißt seit dem 20.09. "Zur Freigabe". Der Name wird jetzt
    aus STATUS_NAME GELESEN statt abgeschrieben.

GEPRÜFT: modi-katalog 150/0 (war 144), modi-verborgen 85/0 (war 80/2),
haus-trennung 97/0, material 159/0, meldungen 8/0, abbrechen-optik 0
Fehler. Dazu grün: an-alle, vorlagen, support, css-klassen,
aufgabenbrett, aufgaben-vorlagen, unterstuetzung, formulare, loeschen,
nachfrage, kalender, chat, leerzustand.

OFFEN UND NICHT ANGEFASST: pruef-breiten meldet auf report.html ein
Berührziel von 27x18 px. Der Link (`class="zurueck"`) ist auf 30
Seiten derselbe und hat gar keinen eigenen Stil; beanstandet wird nur
diese eine Seite, weil dort hinter ihm nur "· Review" steht und die
Prüfung Fließtext-Links erst ab 12 Zeichen Umgebung ausnimmt. Eine
Klasse auf 30 Seiten ohne Prüflauf zu ändern wäre geraten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 00:50:15 +02:00
DogFatherGitandClaude Opus 5 14d6f5000c Der Titel heisst wieder "Zentrale" -- und gehoert jetzt der Adresse
Filipe: "anstatt irrenanstalt soll da auch Zentrale stehen bitte. auch
getrennt von der team dogi seite da steht was anderes und soll auch so
bleiben."

NACHGEMESSEN, BEVOR ETWAS GEAENDERT WURDE -- und es stand NICHT etwas
anderes. `crewWeiche` biegt fuer das Teamhaus sechs Dinge um (Manifest,
App-Symbole, Zugangswand, Buehnen, Marke, Haus-CSS); `start.html` ist
nicht dabei, und kein Skript hat `#ztitel` je angefasst. Auf BEIDEN
Adressen stand seit dem 22.09.2026 derselbe fest eingebaute Titel.
Verschieden war nur die Zierzeile darueber -- "Spicy Media" gegen
"Team Dogi" --, und die hat vermutlich den Eindruck gemacht.

WAS JETZT GILT
  * In start.html steht "Zentrale". Das ist die Vorgabe und gilt fuer
    das Agenturhaus.
  * Das Wort des Teamhauses kommt vom Server (`titelFuer`, direkt neben
    `markeFuer`, nach demselben Muster). Dort bleibt damit woertlich
    stehen, was vorher dastand -- ab dem 24.09. wird jeder Umbau je
    Haus getrennt gefuehrt, und dies ist der des Agenturhauses. Ob
    Filipe dort etwas anderes will, entscheidet er; geraten wird es
    nicht.

NACH DER ADRESSE UND NICHT NACH DER ROLLE, anders als bei der Marke:
Ein Titel sagt, WO man ist, eine Marke sagt, zu WEM man gehoert. Auch
der Sicht-Umschalter aendert ihn nicht -- wer eine fremde Sicht oeffnet,
wechselt die Zahlen, nicht das Haus.

UND ER STEHT NICHT MEHR IN EINER DATEI, DIE JEDER HERUNTERLAEDT.
Derselbe Grund wie bei MODI_MARKE zwei Zeilen darueber: Was nur das
Teamhaus angeht, gehoert nicht in start.html, die jeder Creator beim
Oeffnen bekommt. Die Schreibweise mit grossem A in der Mitte ist
weiterhin so gewollt und steht jetzt in workspace.js.

GEMESSEN
  * pruef-haus-trennung 97 -> 100 Pruefungen, 0 Fehler. Die drei neuen
    verlangen den UNTERSCHIED, nicht den Wortlaut: auf crew. ein
    eigener Titel vom Server, auf workspace. keiner (dort gilt die
    Seite), und die Zierzeilen sind ebenfalls verschieden. Ein
    Vergleich mit "Zentrale" waere beim naechsten Umbenennen rot, ohne
    dass etwas kaputt ist -- diese Sorte Fehlalarm hatte ich heute
    schon einmal.
  * pruef-start-ansicht 157, pruef-deutsche-texte 12 -- unveraendert.
  * Angesehen bei 1280 px und 390 px: "◆ SPICY MEDIA ◆" darueber,
    "Zentrale" darunter.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 00:03:19 +02:00
DogFatherGitandClaude Opus 5 e1ee778c04 Vier Stufen im Agenturhaus -- und die Modi-Liste verschwindet von dort
Filipe, mit dem Bildschirmfoto der LIVE-Punkte: "diese aufgaben auf
screen. alle auf dieser app getrennt von denen auf der team dogi
website bitte, sehr wichtig. die sollen die manager und scouts bewerten
können mit passt passt nicht verbesserung möglich und was weiß ich. und
die creator sollen sehen was bei ihnen passt oder nicht mit der notiz
vom manager oder scout. spicy und dogfather sollen auch bewerten können
wie vorher. ... und wie gesagt von der team dogi seite da ist ein
anderes system auf diesen aufgaben."

WAS AUF DEM BILDSCHIRMFOTO STAND, WAR NICHT SEINE SEITE
Unter "Vor der Sendung" stand die Liste eines MODIS -- erkennbar am
Satz darueber ("Was du vor und beim Start gesehen hast") und an den
Punkten ("Die Ankuendigung kam rechtzeitig"). Am echten Bestand
nachgemessen: Die Auswahl "Person" fuellte sich aus allen Creatorn PLUS
allen Modis, sortiert nach Namen. Der erste Name im Haus ist "Diene",
eine Modi -- und ohne ausdrueckliche Wahl nimmt die Seite den ersten.
DogFather bekam auf der Agenturadresse also zuverlaessig das Teamhaus
zu sehen, und druecken konnte er dort nichts, weil ein Modi-Bericht nur
dem Modi selbst gehoert.

DIE GRENZE, AN DREI STELLEN STATT AN EINER
  * Die Auswahl geht durch EIN Sieb (hat diese Person ueberhaupt eine
    Liste, und steht sie in diesem Haus?) statt durch drei einzeln
    gepflegte Bedingungen.
  * Die Grenze haelt auch gegen eine von Hand eingetragene Nummer --
    eine ausgeduennte Auswahlliste ist Kosmetik, solange ?creator_id=
    durchgeht.
  * Die gueltigen Punkt-Schluessel lagen fuer beide Haeuser in EINER
    Menge. Ein Scout konnte damit bei einem Creator den Stand eines
    Modi-Punktes setzen: angenommen, gespeichert, nie zu sehen.
  * Dazu: `darfCreator` sagt fuer DogFather bei JEDER Nummer ja -- er
    konnte einen Stand an einer Managerin oder an sich selbst setzen.
Drei Lagen wie bei den Aufgaben: crew / agentur / keine Adresse. Der
dritte Ausgang ist kein Schlupfloch, sondern die Bedingung dafuer, dass
die Pruefungen ueberhaupt noch etwas messen koennen.

ZWEI SKALEN, WEIL ES ZWEI VERSCHIEDENE DINGE SIND
Agentur (Betreuung urteilt, Creator liest): Passt / Verbesserung
moeglich / Passt nicht / Trifft nicht zu. Team (Modi berichtet,
DogFather behandelt im Eingang): Passt so / Verbessern, unveraendert --
eine Stufe "Passt nicht" haette dort keinen Empfaenger.
"Trifft nicht zu" ist kein Beiwerk: Ohne sie steht ein Punkt, der bei
diesem Creator gar nicht vorkommt, fuer immer auf "offen" und die
Bilanz zaehlt ihn als unerledigt mit.
Die Worte, die Toene und die Frage im Nachfragefenster kommen vom
Server. Der Browser baut Knoepfe, Marken und Kacheln daraus und kennt
keine Stufe beim Namen -- sonst muesste er ausserdem wissen, WANN
welche gilt, und das waere ein Rollenvergleich in einer Datei, die
jeder herunterladen kann.

DIE NOTIZ TRAEGT JETZT AUCH DIE ROLLE
"mit der notiz vom manager oder scout" -- bis hierher stand am Satz nur
ein Vorname. Wer die Namen im ersten Monat nicht kennt, weiss nicht,
wer da urteilt. Jetzt: "Patrick, Scout · 24.09., 23:43".

DIE UMSTELLUNG DER DATENBANK KOMMT NICHT VON MIR
Eine CHECK-Regel laesst sich in SQLite nicht aendern; die Tabelle muss
neu gebaut werden. Ich hatte den Griff hier zuerst ein zweites Mal
geschrieben -- mit Zeilenzaehlung und PRAGMA-Spaltenliste, aber OHNE
die Sicherung davor, ohne die Indizes und ohne `foreign_key_check`
danach. Drei von fuenf Absicherungen fehlten, und keine davon haette
gefehlt, wenn ich die vorhandene Funktion benutzt haette. Genau davor
warnt ihr eigener Kommentar seit dem 09.09.2026.
Jetzt: `checkListeErweitern` aus workspace.js, ausgegeben statt
nachgebaut. Der Marker ist die erste fehlende Stufe und keine
hingeschriebene -- eine feste Angabe waere an dem Tag falsch, an dem
eine weitere dazukommt.
Und danach wird NACHGESEHEN, was wirklich erlaubt ist: Bricht die
Umstellung ab, werden die neuen Stufen auch nicht angeboten. Ein Knopf,
der beim Druecken scheitert, ist schlechter als kein Knopf.

WAS SONST NOCH NACHGEZOGEN WURDE
  * Der Zaehler auf der Creator-Startseite zaehlte fest
    `stufe = 'verbessern'`. Die staerkste Rueckmeldung, die es gibt,
    waere als Einzige nicht dort erschienen. Jetzt aus dem Katalog.
  * Der Satz unter "Feste Punkte" stand im Browser und sprach in BEIDEN
    Haeusern vom "Creator". Die Teamfassung bleibt wortgleich -- ab dem
    24.09. wird jeder Umbau je Haus getrennt gefuehrt, und dies ist der
    des Agenturhauses.
  * "Passt" setzt weiterhin mit einem Klick. Ein Nachfragefenster vor
    dem haeufigsten Klick einer Betreuung, die vierzig Punkte durchgeht,
    macht aus einem Durchgang eine Sitzung.

GEMESSEN
  * pruef-checkliste-stufen.mjs, neu: 56 Pruefungen, 0 Fehler. Darin
    die Umstellung an einer Datenbank mit dem ALTEN Bauplan und echten
    Zeilen -- Zeilen, Spalten UND Spalteninhalte nachgezaehlt, plus die
    Sicherung. Zu jeder Schranke die Gegenprobe, die durchkommen muss.
  * pruef-checkliste 97, pruef-modi-checkliste 75, pruef-haus-trennung
    97, pruef-manager-sicht 43 -- alle unveraendert gruen.
  * pruef-checkliste rechnete mit festen Zahlen (drei Bilanzkacheln,
    zwei Knoepfe je Punkt) und war rot, ohne dass etwas kaputt war. Sie
    fragt die Zahlen jetzt bei der Schnittstelle ab und zaehlt sie im
    Browser nach. Gleich viele Pruefstellen, 57.
  * Bildschirmfotos bei 1280 px und 390 px (Betreuung, Creator, das
    Nachfragefenster): vier Knoepfe passen auf dem Handy als 2x2, 0 px
    Ueberhang, keine Konsolenfehler.
  * Die neuen Toene sind gerechnet, nicht gegriffen: #d97f87 hat die
    relative Helligkeit 0,317 -- so hell wie das vorhandene Gruen
    (0,320) und heller als das Blaugrau von "offen" (0,241), das den
    Barrierefreiheits-Lauf schon bestanden hat. Kein Signalrot: Ein
    gedaempftes Rosé sagt "das gehoert geaendert", ein Rot sagt "du
    hast versagt".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 23:49:01 +02:00
DogFatherGitandClaude Opus 5 9863645952 Die zwei Häuser sind getrennt -- und die Tür geht in beide Richtungen
Filipe: "ich will dass du zuerst die komplette site vn der workspace
seite trennst. da soll nichts verknüpft sein. wenn ich bei der einen
was mache soll nichts bei der anderen passieren. … es soll nur für
dogfather eine kachel geben wo er mit einem einfachen klick von der
einen auf die anderen seite kommt aber sonst garnichts."

Das kehrt die Entscheidung vom 10.09.2026 um ("getrennt wird das
AUSSEHEN, nicht der Bestand"). Wer den alten Kommentar liest, liest
einen überholten Stand -- das steht jetzt an jeder betroffenen Stelle.

WAS GEMESSEN WAR, BEVOR ETWAS GEBAUT WURDE
  * Nur drei Module trennten nach Haus (Aufgaben, Bereiche, Dateien).
    Chat, Kalender, Wissen, Material, Personenlisten und der Rest nicht.
  * Die Trennung war EINSEITIG: nurHaus() griff nur auf crew.
  * siehtModis() hebelte sie für DogFather auf der Agenturseite aus --
    in seiner Gesprächsliste standen dort beide Häuser nebeneinander.
  * Keine haus-Spalte in der Datenbank.
  * Der Bestand kreuzte aber kaum: 0 von 86 Terminen gemischt, 0 von 7
    Zweier-/Gruppengesprächen, genau EIN Kanal.

WAS JETZT DASTEHT
  * Drei Rollenmengen in crew-adresse.js (crew / agentur / beide) und
    hausVonRolle(); eine unbekannte Rolle bekommt null, kein Haus.
  * Spalte `haus` an acht Wurzeltabellen, nachgetragen aus Belegen:
    238 Zeilen eindeutig, die Wissensablage geschlossen der Agentur,
    vier Restzeilen namentlich, der gemischte Kanal aufgelöst
    (die zwei Scouts gehen heraus, die 7 Nachrichten sind alle vom
    Team). Offen bleiben: null.
  * nurHaus, hausBedingung und darfAnlegen gelten in BEIDE Richtungen.
  * Der siehtModis-Durchgriff ist weg -- aber in DREI Fällen, nicht
    zwei: Prüfadressen bekommen gar kein Haus und verhalten sich exakt
    wie vorher. Die erste Fassung hatte das übersehen und 19 Prüfungen
    umgeworfen, an denen nichts kaputt war.
  * Kalender: getrennt, aber "belegt" bleibt (Filipes Entscheidung).
    Die Blöcke tragen NUR Beginn und Dauer -- kein Titel, keine Person.
    Gebaut als Gegenstück zur Liste (meine Termine MINUS die sichtbaren),
    damit beide nicht auseinanderlaufen können.
  * Die Wissens-Kachel ist auf der Team-Adresse weg UND die Route
    antwortet dort mit 404 -- eine fehlende Kachel ist nur eine Bitte.
  * Die Wechsel-Kachel für DogFather geht jetzt in beide Richtungen.

GEPRÜFT: pruef-haus-trennung 97 statt 81, 0 Fehler (vorher 7, alle
haben die alte Regel behauptet). Die neuen Abschnitte sind DORT
eingezogen statt in eine zweite Datei -- `pruef-haustrennung.mjs` hätte
sich von `pruef-haus-trennung.mjs` um einen Bindestrich unterschieden.
Dazu grün: haus-seiten, crew-adresse, chat, chat-kanaele,
kanal-besetzung, kalender, serien, treffchat, wissen-neu,
modi-checkliste, modi-katalog, rechtetafel, personen-liste, sicht,
verborgen, fremde-sicht, alle-wege.

NICHT VON MIR: pruef-treff (3) und pruef-kachel-universum (2) waren
schon vorher rot -- beim Treff auf dem Stand 40b48e89 nachgemessen,
bei den Farben steht dieselbe Zahl im Kopf der Prüfung selbst.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 20:40:20 +02:00
DogFatherGitandClaude Opus 5 40b48e89f1 Bei "An alle" sieht man jetzt, wer sie hat und wer nicht
Filipe: "wenn ich eine aufgabe an alle verteile will ich dass dogfather
und die rechte hand individuel von jedem sehen wer es gemacht hat oder
nicht."

Vier Fehler, die zusammenhingen -- alle gemessen, keiner geraten:

1. "Alle" waehlen, "An alle" druecken, nichts passiert. Die Zeile
   verglich verantwortlich_id !== "alle"; niemand heisst so, also wurde
   jede Aufgabe uebersprungen und die Liste blieb leer. Die Aufgaben
   entstanden, man sah es nur nicht.

2. Der Vermerk an der Karte haette bei "alle" den Stand EINER fremden
   Person gezeigt -- welcher, haengt von der Reihenfolge der Daten ab.
   Jetzt steht dort, wie weit es ist, und darunter namentlich, wer sie
   hat: Offen / Erledigt / ueberfaellig / hat sie nicht. Das Wort steht
   immer dabei, die Farbe ist nur die Abkuerzung.

3. Die "An wen"-Reihe zeigte SECHS Personen, der Server belieferte VIER.
   Rechte und linke Hand gingen leer aus, ohne ein Wort; einzeln
   angeschrieben kam "Das gibt es nicht mehr, lade die Seite neu" zu
   jemandem, den es sehr wohl gibt. Empfaenger sind jetzt Modis UND
   linke Hand (Filipes Regel vom 22.09.), und die Menge steht EINMAL in
   workspace.js -- SQL-Abfrage, Annahme und Browserliste leiten sich
   daraus ab und koennen nicht mehr auseinanderlaufen.

4. Zweimal "An alle" legte alles doppelt an. Der Kommentar im Server
   behauptete das Gegenteil; aktiv war die Sperre nur beim Massenknopf.
   "An alle" fuellt jetzt Luecken. Die bewusste Wiederholung bleibt:
   Steht am Knopf "Nochmal" (weil wirklich alle sie haben), sagt der
   Browser das ausdruecklich, und dann legt der Server neu an.

Geprueft: pruef-modi-katalog 144 statt 133, 0 Fehler -- elf neue
Pruefungen fuer Empfaenger, Luecken und die Gegenprobe, dass ein
gewolltes "Nochmal" sehr wohl anlegt. Dazu mess-alle-einzelsicht.mjs
(eigene Wegwerf-Datenbank, nie die echte) mit Bildern bei 412 und
1280 px.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 17:26:35 +02:00
DogFatherGitandClaude Opus 5 67b5e00150 Die Support-Kachel steht zwischen "Wer sieht was" und "Vertraulich melden"
Filipe, mit zwei Bildschirmfotos: "die kachel auf screen 2 soll zwischen
den kacheln auf screen3 sein bitte."

ZWEITER FEHLER, DEN ER NICHT GEMELDET HAT -- und der groessere: Die
Support-Kachel hatte GAR KEINE Gruppe. Sie stand deshalb bei JEDER
Rolle in einem eigenen Abschnitt OHNE UEBERSCHRIFT, allein, mit einem
Aufklapp-Kopf, auf dem nur "1" stand. Gebaut habe ich das heute frueh;
auf seinem Bildschirmfoto war es zu sehen, und mir ist es nicht
aufgefallen, weil ich auf die Kachel geschaut habe und nicht auf das,
was um sie herum steht.

Jetzt gehoert sie zu "Fuer dich" und wird VOR den vertraulichen
Meldeweg eingeschoben statt ans Ende gehaengt. Gesucht wird der NACHBAR
ueber sein Ziel, nicht eine Position -- eine feste Zahl waere beim
naechsten Umbau still falsch. Findet sich der Nachbar nicht (ein Modi
hat den Meldeweg nicht), steht sie am Ende der Gruppe.

GEMESSEN, NICHT GERECHNET (1280 px, angemeldet, je Rolle):

  admin/hand  Fuer dich:  Steckbrief | Wissen | Personen & Zugaenge
                          Wie geht's dir? | Wer sieht was | Support
                          Vertraulich melden
  modi        Fuer dich:  Steckbrief | Wissen | Wie geht's dir?
                          Support
  gast        Fuer dich:  Support | Vertraulich melden | Steckbrief

Bei DogFather und der rechten Hand bricht "Vertraulich melden" in eine
eigene Zeile um: Die Gruppe hat jetzt sieben Kacheln, das Raster drei
Spalten, und sieben geht durch drei nicht auf. Die Luecke faellt ans
ENDE -- das ist die bessere der beiden Moeglichkeiten und dieselbe
Regel, die im Kommentar zur Treff-Reihe steht: "eine Luecke in der
Mitte sieht kaputt aus, eine am Ende sieht grosszuegig aus."

NEU: server/mess-kachelreihen.mjs. Die Reihenfolge im Quelltext ist
NICHT die auf dem Bildschirm -- "Willkommen" belegt zwei Spalten,
gruppiert wird nach dem ersten Auftreten einer Gruppe, und eine Kachel
ohne `gruppe` bekommt einen eigenen namenlosen Abschnitt. Genau daran
ist dieser Fehler entstanden. Die Datei misst es im Browser, je Rolle,
und meldet einen Abschnitt ohne Ueberschrift ausdruecklich als Befund.
Sie prueft nichts.

Gemessen: pruef-support 45, pruef-unterstuetzung 70,
pruef-start-ansicht -- gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 14:37:47 +02:00
DogFatherGitandClaude Opus 5 e11f775489 "Unterstuetzen" steht jetzt links, "Mitmachen" in der Mitte
Filipe, mit Bildschirmfoto der letzten Reihe: "wechsel bitte die
reihenfolge, links soll unterstuetzen sein, in der mitte dan mittmachen
und recht regeln & hilfe."

Mein erster Entwurf hatte "Unterstuetzen" HINTER "Mitmachen", mit der
Begruendung "erst dazugehoeren, dann etwas beitragen". Die Ueberlegung
war nicht falsch -- sie war nur meine. Der Kommentar an der Kachel sagt
das jetzt auch so; stehengelassen haette er beim naechsten Lesen eine
Reihenfolge begruendet, die es nicht mehr gibt.

GEMESSEN STATT GERECHNET: Die Reihenfolge im Feld ist nicht die
Reihenfolge im Raster -- "Willkommen" belegt zwei Spalten und
verschiebt alles danach. Im Browser nachgesehen (Gast, 1280 px):

  Reihe 1   Willkommen (2) | Rudel-Chat
  Reihe 2   Highlights | Anschlagbrett | Was ansteht
  Reihe 3   Wunschliste | Dogi-Media | Draussen
  Reihe 4   Unterstuetzen | Mitmachen | Regeln & Hilfe

Nebenbei: Die Rasterskizze im Kommentar darueber zeigt den Stand vom
17.09.2026 und stimmt seither nicht mehr mit der Kachelliste ueberein.
Sie ist jetzt als solche gekennzeichnet, statt als aktuelle Karte
gelesen zu werden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 14:23:23 +02:00
DogFatherGitandClaude Opus 5 aa2e1a4ae2 Eine Kachel "Unterstuetzen" -- und die Gespraechsliste neu gebaut
=== 1. UNTERSTUETZEN (neue Kachel im Community-Bereich) ===

Filipe: "ich brauch auch noch eine kachel im community bereich. wo mein
paypal und meine amazon liste sein wird. wo die leute alle supporten
koennen auf andere art anstatt nur tiktok. jeder soll diese kachel sehen
aber nur dogfather soll sie veraendern koennen oder vieles mehr sehen."

Neu: unterstuetzen.html + css + js, server/workspace-unterstuetzung.js,
server/unterstuetzung-tabellen.js. Ton 45 (#7567fe) ist gerechnet, das
Kachelzeichen ist ein Herz ueber zwei offenen Haenden.

DIE WEGE STEHEN IN DER DATENBANK, nicht im Quelltext -- ein Recht, das
man nur ueber einen Entwickler ausueben kann, ist keines. DogFather
schreibt Titel, Text, Knopf und Adresse selbst, blendet Wege aus und
nimmt neue dazu.

DER PAYPAL-LINK STEHT LEER UND UNSICHTBAR DA. Filipe schrieb "mein
paypal kennst du ja schon" -- gesucht im ganzen Haus und im Vault,
nirgends gefunden. Eine Zahlungsadresse zu RATEN waere der
gefaehrlichste Fehler dieser Seite: Geld an einen Fremden, und niemand
merkt es. Also steht dort nichts, der Weg ist ausgeblendet, und die
Seite sagt genau EINER Person, dass er fehlt.

DREI ARTEN, UND DIE DRITTE IST DIE WICHTIGSTE: geld, geschenk, frei.
"Kostet nichts" bekommt dieselbe Kartenform und dieselbe Groesse.
Waeren die freien Wege kleiner oder weiter unten, waere die Aussage
"das ist zweite Wahl" -- und die Mehrheit derer, die hier lesen, waere
damit zweite Wahl.

DIE ZAEHLUNG IST ANONYM, UND ZWAR VON DER TABELLE HER. DogFather sieht,
wie oft ein Weg geoeffnet wurde (7/30 Tage/gesamt). Was er NICHT sieht,
ist WER -- weil es in unterstuetzung_striche keine Spalte dafuer gibt.
Geprueft wird das ueber PRAGMA table_info, nicht ueber eine Abfrage:
eine Abfrage liesse sich morgen erweitern, eine fehlende Spalte nicht.

Schreiben haengt an istDogFather, nicht an istLeitung -- die rechte Hand
fuehrt dieses Team mit und kommt trotzdem nicht an diesen Link. Jede
Adresse wird beim SCHREIBEN geprueft (nur https:// oder eine Seite
dieses Hauses); javascript:, data:, http:// und // werden abgewiesen.

Neu: server/pruef-unterstuetzung.mjs -- 70 Pruefungen, alle gruen.
Sie misst ueber die CREW-ADRESSE: Beim ersten Lauf waren vier Rollen
gruen und der Zuschauer rot, und es sah nach einem Rechtefehler aus.
Es war ein Messfehler -- ueber 127.0.0.1 landet man still im
Agenturhaus, und dort gibt es die Rolle "gast" gar nicht.

=== 2. DIE GESPRAECHSLISTE (screen1 + screen2) ===

Filipe: "ich will dass die komplette kachel viel krasser und geiler
aussieht. der hintergrund der kachel soll gleich bleiben."

Der Hintergrund ist unangetastet. Zwei echte Fehler auf seinem Bild:

  - Bei "Das Rudel" stand das "@" rechts oben und die orange "6" eine
    ZEILE TIEFER. Der Knopf ist ein Raster mit DREI Spalten und bekam
    VIER Kinder -- das vierte fiel um. Ausgerechnet die wichtigste
    Auskunft der Liste landete an der unauffaelligsten Stelle.
  - Jedes Gespraech mit Profilbild haengte das Bild ZWEIMAL ein: ein
    Block stand Zeichen fuer Zeichen doppelt da. Zu sehen war nichts,
    gekostet hat es die doppelte Ladelast bei jedem Neuzeichnen.

Und eine tote Regel: `.chat-raum__knopf[data-an="ja"]` beschrieb die
Schiene am offenen Gespraech -- gesetzt wird aber `data-offen` am <li>.
Die Regel griff nie, und daneben stand eine zweite, blassere Fassung
derselben Sache. Jetzt steht alles einmal, und die Schiene ist da.

Dazu: Zeilen als Karten, 44px-Gesichter, ein Zaehler neben "Gespraeche",
Suchfeld als Pille mit Lupe, runder Farbfleck statt Quadrat, und der
leere Raum rechts bekommt eine Mitte statt eines Satzes in der Ecke.

=== 3. VIER FUNDE NEBENBEI ===

  - supportAufraeumen() war exportiert und wurde NIRGENDS gerufen. Die
    Meldungen samt Bildschirmfotos waeren fuer immer liegen geblieben,
    obwohl "90 Tage" dokumentiert ist. Jetzt im Loeschkonzept.
  - aufgaben_zuteilung fehlte ebenfalls im Loeschkonzept (seit 21.09.).
    pruef-aufbewahrung ist damit wieder gruen.
  - pruef-start-ansicht war rot, seit "Aufgaben" am 23.09. die silberne
    Kachel bekam -- die ueberschreibt ihr --ton absichtlich. Die
    Pruefung nimmt sie jetzt aus UND prueft die Ausnahme selbst.
  - pruef-buehne meldete auf entwicklung.html 1,79:1 Kontrast bei "Wen
    gehst du durch?" -- die Ueberschrift lag direkt auf dem Foto. Sie
    steht jetzt auf einer deckenden Flaeche.

OFFEN: pruef-buehne meldet treff-regeln.html mal "0 von 40", mal "3 von
40" -- dieselbe Seite, verschiedene Antworten. Eine Pruefung, die
schwankt, ist schlimmer als eine rote. Nicht in diesem Zug behoben.

Gemessen: pruef-unterstuetzung 70, pruef-start-ansicht, pruef-buehne
(bis auf den Wackler), pruef-workspace-seiten, pruef-aufbewahrung 45,
pruef-rechtetafel 19, pruef-css-klassen, pruef-chatkachel 36,
pruef-chat-ausbau, pruef-entwicklung-kacheln 31 -- gruen.

Neu: server/mess-chat-liste.mjs (zeigt die Liste mit sieben Gespraechen
verschiedener Art, prueft nichts).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 14:14:25 +02:00
DogFatherGitandClaude Opus 5 5b244ab7ec Die Personenkachel wird eine Standkarte -- mit den Aufgaben darauf
Filipe: "mach das bitte viel krasser und viel geiler. die aufgaben die
wir verteilen sollen da auch zu sehen sein und so. viel
uebersichtlicher, viel moderner. nicht so banal und einfach."

VORHER: Name, Rolle, ein flacher Balken und drei Zahlenkaesten. Auf
seinem Bildschirmfoto standen in fuenf von sechs Kacheln exakt
dieselben drei Zahlen (0 / 68 / 0) -- achtzehn Kaesten fuer eine
einzige Auskunft. Und die Aufgaben, die er eine Handbreit darunter
verteilt, kamen auf der Kachel derselben Person gar nicht vor.

JETZT drei Zonen in der Reihenfolge, in der man fragt:
  KOPF     Ring mit dem Anteil in der Mitte, Name, Rolle.
  AUFTRAG  Wie viele offen, wie viele ueberfaellig, und die naechste
           mit Namen und Frist ("seit gestern ueberfaellig").
  FUSS     "46 von 68 angesehen" -- und "verschieden gesehen" nur
           dann, wenn es dort etwas gibt.

Der Ring rechnet mit stroke-dasharray auf einem Kreis vom Umfang 100:
der Anteil in Prozent ist damit buchstaeblich die Strichlaenge. Keine
Ampelfarbe -- was "genug" ist, haengt davon ab, wie lange jemand dabei
ist. Gewarnt wird nur an einem Massstab, der nicht geraten ist: einer
ueberschrittenen Frist.

Die Aufgabenzeile wird aus derselben Liste gerechnet wie das
Verteil-Band und der Katalog (alleAufgabenV) und in aufgabenHolen()
nachgezogen -- an EINER Stelle, damit es keine gibt, die es vergisst.

GITTER STATT FLIESSREIHE: Bei sieben Leuten stand die letzte Kachel
allein in ihrer Zeile und wuchs auf 1160 px neben 379 px der anderen.
Eine Person sah dreimal so wichtig aus, weil die Teamgroesse ungerade
ist.

Drei Funde nebenbei, alle durch die neuen Messungen:

  - pruef-schritt verlangte seit dem 23.09. einen Sprung, der an dem
    Tag ABSICHTLICH entfernt wurde. Sie war seither rot, ohne dass
    etwas kaputt war. Neu gefasst auf den Sprung, den es noch gibt:
    den Weg von aussen ueber "?zeigen=person-...".
  - Und der war kaputt. Gesprungen wurde, waehrend in der Karte nur
    "wird geladen ..." stand -- die Seite war zu kurz zum Scrollen,
    der Browser klemmte bei 0 ab. Wer der Talentseite folgte, landete
    oben auf der Liste. Gesprungen wird jetzt, wenn die Karte steht.
  - Auf demselben Weg rief karte() das Vorlagenbrett, bevor es
    eingerichtet war ("zeigen() vor einrichten()"). Das Einrichten ist
    vorgezogen. Ueber "?zeigen=" ging vorher KEINE Pruefung.

Gemessen: pruef-entwicklung-kacheln 31 (vorher 16), pruef-schritt 68
(vorher 65), pruef-entwicklung 48, pruef-modi-katalog 133,
pruef-bewerbung-aufgaben 101, pruef-zuteilung, pruef-css-klassen --
alle gruen. Schriftgroessen unter 11,5 px: 40 statt 42.

Neu: server/mess-entwicklung-kacheln.mjs. Die Pruefung braucht einen
kargen Bestand und zeigt deshalb den Sonderfall (alles auf null); diese
Datei legt sieben Leute mit verschiedenen Staenden und Aufgaben an und
macht Bilder fuer 1280 und 390 px. Sie prueft nichts.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 13:30:17 +02:00
DogFatherGitandClaude Opus 5 1d41e29bf7 Drei weitere Prüfungen, die das Falsche prüften
Der Durchgang, zweiter Teil. Gesucht nach dem schaerfsten Filter, den
es dafuer gibt: dem VERSPRECHEN GEGEN DIE WIRKLICHKEIT -- Pruefsaetze,
die „jede Rolle" oder „jede Seite" sagen. Genau so ist pruef-glocke
heute frueh aufgefallen.

1. pruef-workspace-seiten meldete aufgaben.html als „Breite 1560px".
   KEIN FEHLER: Die Seite traegt zusaetzlich `.inhalt--brett`, und die
   setzt ausdruecklich 1560 px -- mit Begruendung in aufgaben.css („ein
   Brett darf breiter sein als Text, der Kopfbereich bleibt lesbar
   schmal"). Die Pruefung verglich starr mit 1240 und kannte die
   Klasse nicht; sie meldete damit eine Absicht als Fehler, seit dem
   Tag, an dem die Klasse entstand. Mit Gegenprobe belegt: schon vor
   allen Aenderungen von heute rot.
   Jetzt kommt die erwartete Breite aus den KLASSEN des Elements.
   Beide Zahlen bleiben stehen, weil sie etwas aussagen -- kommt
   weder 1240 noch 1560 an, ist die Regel verloren.

2. pruef-meldungen meldete „ohne Satz: ungueltiger_stand". Zuerst ein
   ECHTER Fehler, und zwar meiner vom selben Tag: In
   workspace-support.js stand eine nackte Kennung statt eines Satzes.
   Behoben -- und danach meldete die Pruefung sie WEITER, weil sie das
   Zitat im Kommentar las, der die Behebung begruendet.
   Dieselbe Falle wie ein Grep ueber eine Datei, die ihre eigene
   Geschichte enthaelt; mir ist sie heute schon einmal passiert. Eine
   Pruefung, die verbietet, ueber einen behobenen Fehler zu SCHREIBEN,
   erzieht dazu, die Begruendung wegzulassen. Kommentare zaehlen jetzt
   nicht mehr; Adressen mit // in Zeichenketten bleiben unberuehrt.

3. pruef-auskunft meldete „NICHT EINGEORDNET:
   vorlagen_bewerbungen.aufgabe_id". ECHT: Die Spalte zeigt auf eine
   Aufgabe, nicht auf einen Menschen, und stand in keiner der beiden
   Listen. Das ist mehr als Ordnungsliebe -- bei einer
   Auskunftsanfrage muss das Haus sagen koennen, welche Spalten auf
   eine Person zeigen. Eine unbekannte Spalte ist eine, bei der
   niemand weiss, ob sie mitgehoert.

ZWISCHENSTAND: ACHT Pruefungen an einem Tag, die rot waren oder das
Falsche prueften. Das Muster ist immer dasselbe -- eine Liste oder
Zahl, die zum Zeitpunkt des Schreibens stimmte. Sie wird nicht falsch,
sie wird unzustaendig.

Gruen: pruef-meldungen (8), pruef-auskunft (46),
pruef-workspace-seiten, pruef-support (45), pruef-vorlagen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 13:01:25 +02:00
DogFatherGitandClaude Opus 5 24523cdd4b Die GIF-Kiste ist fertig – eine Prüfung sagt es jetzt auch
Filipe: „mach das mit den gifs auch fertig."

ERGEBNIS: SIE WAR ES SCHON. Hineinlegen, Kiste anzeigen, verschicken,
herausnehmen, Duplikat-Erkennung am Inhalt, Fortschrittsanzeige mit
Abbruch, Standbild bei „Bewegung reduzieren" -- alles vorhanden, alles
live, und pruef-chat-anhaenge deckt die Wege ab.

SECHS „BEFUNDE" MEINES ERSTEN LAUFS WAREN ALLE MESSFEHLER:
  * zu frueh gemessen (`darf_gif` kommt mit den Raumdaten; der Knopf
    wird erst danach freigeschaltet)
  * kein Content-Type gesetzt -> „Keine Datei empfangen"
  * Selektor `.chat-raum` erfunden; die Klasse heisst
    `chat-raum__knopf`
  * nach `title*='ausnehm'` gesucht; der Knopf heisst „Aus der Kiste
    nehmen" und hat die Klasse `gif-kachel__weg`
  * `x-name` geschickt; der Server liest `x-dateiname`
  * nach einer GIF-Adresse im Verlauf gesucht -- das GIF wird beim
    Verschicken KOPIERT und haengt danach als Anhang
  * und einmal `curl` auf chat.html ohne Anmeldung: eine Umleitung,
    null Treffer, und ich hielt die Tafel fuer nicht ausgeliefert

Ich haette beinahe gebaut, was es laengst gibt -- wie heute frueh beim
Farbwerkzeug. Der Unterschied: Diesmal habe ich vor dem Bauen
nachgesehen.

WAS BLEIBT, IST DIE PRUEFUNG. pruef-chat-anhaenge prueft die WEGE;
ungeprueft war die OBERFLAECHE -- dass der Knopf fuer Team Dogi
erscheint und fuer einen Creator nicht, dass die Tafel aufgeht, dass
an jeder Kachel ein Weg zum Herausnehmen steht, dass ein verschicktes
GIF wirklich im Verlauf landet. Genau dort haette ich gebaut, was es
schon gibt. 17 Pruefungen, 0 Fehler.

=== Und der Durchgang durch die Pruefungen (erster Teil) ===

Gesucht nach dem Muster, das heute fuenfmal zugeschlagen hat:
abgeschriebene Listen. Gefunden: pruef-buehne kennt 19 von 38 Seiten,
pruef-workspace-seiten 18 -- je VIERZEHN mit Kopfzeile und damit
ungeprueft. support.html fehlt in beiden; sie ist heute entstanden.

In pruef-workspace-seiten steht die Lehre woertlich im Kopf: „Eine
Pruefung, die eine Seite nicht kennt, kann auf ihr nichts finden."

Ein Probelauf mit abgeleiteter Liste: 30 statt 18 Seiten, 28 rot --
24 davon, weil die Seite gar kein `data-buehne` traegt. Das ist eine
Gestaltungsfrage (welche Szene wohin), keine Reparatur. DIE
ERWEITERUNG IST DESHALB WIEDER DRAUSSEN: Eine Pruefung, die ab sofort
dauerhaft rot ist, wird ab dem zweiten Mal ueberlesen -- und dann auch
die echte Meldung.

Nebenbefund mit Gegenprobe belegt: `aufgaben.html` ist 1560 px breit
statt 1240 (verursacht von BUTTON.schnitt) -- und war das schon VOR
meiner Aenderung. Die fuenfte bestehende rote Pruefung an diesem Tag.

Beides steht in der Vault-Notiz zum Entscheiden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 12:42:37 +02:00
DogFatherGitandClaude Opus 5 d231e989cf Screenshots an einen Beitrag hängen
Filipe (Runde vom 23.09.2026): „mach das man da bitte screenshots
oder kurzschnitte von den live reinposten kann. nach dem selben
prinzip wie bei den anderen nebendran."

ES FEHLTE WENIGER, ALS MEINE EIGENE NOTIZ BEHAUPTETE. Dort stand „ein
eigener Brocken (Upload, Groessenpruefung, Sicherheit), kein
Nebenbei". Nachgemessen statt geglaubt: Die Spalte `dateien.eintrag_id`
gibt es seit dem Video-Einlesen, die Karten zeichnen ihren
Bildstreifen bereits, und die Auslieferung entscheidet die
Sichtbarkeit schon am BEITRAG statt an der Ablage. Gefehlt hat genau
ein Weg -- das Hochladen. Wieder ein Beleg dafuer, dass auch meine
eigenen Listen altern.

„NACH DEM SELBEN PRINZIP" IST WOERTLICH GENOMMEN: `dateiErkennen` aus
dem Chat (eine Fassung, drei Benutzer -- Chat, Support, Beitraege),
derselbe Ordner wie die Dateiablage (die Auslieferung kennt nur einen
Pfad), `express.raw` mit Rechtepruefung VOR der Annahme des Rumpfes.

DER KNOPF STEHT AN DER KARTE, nicht im Anlege-Formular. Ein
Bildschirmfoto faellt einem meist spaeter ein -- beim Nachschauen,
wenn jemand fragt. Wer es nur beim Anlegen mitgeben koennte, muesste
den Beitrag loeschen und neu schreiben. Er erscheint nur, solange
noch Platz ist (drei je Beitrag), damit er nie eine Absage bringt.

ZWEI FEHLER IN MEINEM EIGENEN CODE, beide beim ersten Laden gefunden:
`DATEN_ORDNER` war nicht importiert, und `bereichVon()` hatte ich
erfunden -- es gibt sie nicht. Der Bereich steht am Eintrag selbst
und ist dort auch richtiger: Er kommt aus der Datenbank, nicht aus
der Adresse.

UND ZWEI MESSFEHLER, beide dieselbe Sorte wie den ganzen Tag: Ich
fragte „darf die Community?" an einem Beitrag, den sie gar nicht
sieht (404 -- richtige Antwort, falsche Frage), dann an einem
freigegebenen (403 -- sie braucht eine Stufe zum Schreiben, auch das
richtig). Die Frage, die wirklich zaehlt, ist eine andere: Gilt fuer
ein Bild dieselbe Regel wie fuer einen Beitrag? Gemessen: Beitrag
403, Bild 403. Ein zweiter Weg mit anderen Rechten waere die Tuer,
die niemand bemerkt.

Gemessen: pruef-eintrag-bild, 24 Pruefungen, 0 Fehler -- darunter
als Bild getarntes HTML (415), SVG (415, es ist XML und darf Skripte
enthalten), PDF (415), die Grenze von drei am Server, und das
Abnehmen samt Datei. Gruen: pruef-highlights (31), pruef-anhaenge,
pruef-fassungen, pruef-galerie, pruef-video, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 11:44:01 +02:00
DogFatherGitandClaude Opus 5 7acd7a7674 Das Suchfeld nimmt wieder Eingaben, eigene Kanalnamen, Community in Kanälen
screen1, drei Teile.

=== 1. „bei suchen kann man nichts reinschreiben" ===

MEIN FEHLER VOM SELBEN TAG. Beim Popover-Umbau heute frueh hing die
Liste am <body>, damit sie nicht hinter dem modalen Dialog
verschwindet. Gemessen: Das Suchfeld war da, der Fokus landete nicht
darin, ein getipptes Zeichen kam nicht an.

DER GRUND IST DER FOKUS-KAEFIG. Ein Dialog aus showModal() sperrt den
Fokus auf seinen eigenen DOM-Baum ein. Die Liste lag im Top Layer --
sichtbar und anklickbar, aber ausserhalb des Kaefigs. Klicken braucht
keinen Fokus, Tippen schon. Deshalb fiel es niemandem auf: Die Liste
stand da, sie filterte auf Knopfdruck, nur eine Eingabe kam nicht an.

DIE LOESUNG WAR EINE KOMBINATION, die ich vorher fuer unmoeglich
hielt. Im Dialog wurde die Liste vom clip-path der abgeschraegten
Ecke abgeschnitten, draussen war sie nicht bedienbar. Ein POPOVER
wird aber in die Top Layer gehoben und dort gezeichnet -- der
Beschnitt des Elternteils erreicht es nicht mehr, waehrend der
DOM-Baum (und damit der Fokus) der des Dialogs bleibt. Jetzt haengt
sie wieder im Dialog UND ist ein Popover: bedienbar und unbeschnitten.

Gemessen beides gegeneinander: „comm" getippt -> kommt an, filtert auf
1 Treffer; und die LETZTE Zeile der vollen Liste ist wirklich
anklickbar (elementFromPoint trifft sie selbst, nicht den Dialog).
Daraus ist pruef-suchfeld geworden -- der Fehler war von aussen nicht
zu sehen, und gefunden hat ihn Filipe, nicht ich.

=== 2. „einen neuen namen erstellen den es noch nicht gibt" ===

`data-frei="ja"` war in wahl.js seit langem gebaut und wurde NIE
GESETZT -- dieselbe Sorte Lueue wie `grund_min` heute Morgen. Jetzt
gesetzt; der getippte Text erscheint als eigener Eintrag ganz oben.

Der Server nahm bisher nur die neun festen Zustaendigkeiten. Jetzt
auch einen eigenen Namen: Der SCHLUESSEL wird daraus abgeleitet
(„Technik & Ton" -> "eigen-technik-ton"), der ANGEZEIGTE Name bleibt
wie geschrieben. Das Praefix ist kein Schmuck -- ohne es entstuende
aus dem Namen „Community" derselbe Schluessel wie beim festen Thema,
und der eindeutige Index lehnte ihn ab, obwohl der Kanal nicht
existiert. Gemessen: genau dieser Fall antwortet jetzt mit 201.

Der alte Kommentar sprach sich gegen freie Namen aus („der sichere
Weg zu Clipping neben Clipping-Team"). Das Risiko bleibt und wird
begrenzt: Derselbe Name zweimal ergibt denselben Schluessel und damit
409.

=== 3. „kanäle mit den leuten mit der community rolle" ===

Seit dem 19.09. nimmt `ohneAussen()` die Community aus den Listen
aller anderen. Die Begruendung dort ist ausdruecklich: „Ein
Zweier-Gespraech ist kein Kanal. Es hat keine Nachtruhe, kein Modi
liest mit, und niemand koennte moderieren."

Genau diese Begruendung laesst den Kanal offen. Die Sperre bleibt
fuer GESPRAECHE und faellt fuer KANAELE -- `?fuer=kanal` an der
Partnerliste, und nur fuer den, der Kanaele ueberhaupt aufmachen
darf. Sonst waere der Parameter ein Weg, an `ohneAussen` vorbei Namen
zu erfahren.

Gemessen: DogFather sieht im Gespraech VanVan und Miss, im Kanal
zusaetzlich Kessi und Tom (beide Community). Ein Modi bekommt die
erweiterte Liste auch mit dem Parameter nicht.

Gruen: pruef-suchfeld (8, neu), pruef-chat-kanaele (81),
pruef-treffchat, pruef-chat-neu, pruef-freie-namen (32),
pruef-nachfrage (53), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 11:37:03 +02:00
DogFatherGitandClaude Opus 5 8c599d7961 „An alle" bei „An wen" – und kein Creator mehr auf der Team-Seite
=== screen6: „An alle" ===

Filipe: „bei an ween fehlt noch die option alle neben den namen
allen."

Der Knopf steht VORN, nicht hinten: Wer etwas an das ganze Team geben
will, soll nicht erst an sechs Namen vorbeilesen. Er traegt die
Anzahl der Leute und faerbt sich wie die Stufe „Alle" -- beide
bedeuten „keine Einschraenkung", und zwei Farben dafuer waeren zwei
Aussagen fuer einen Gedanken. Ab zwei Personen; bei einer waere
„alle" derselbe Handgriff wie ihr Name.

EINE ANFRAGE, NICHT SECHS. Der Browser koennte fuer jede Person
einzeln fragen -- und beim dritten von sechs Aufrufen die Verbindung
verlieren. Dann haette die Haelfte des Teams die Aufgabe und die
andere nicht, und niemand saehe, wo es abgebrochen ist.

DER DUPLIKAT-SCHUTZ WANDERTE IN DIE SCHLEIFE. Er fragt, was EINE
Person schon liegen hat; stuende er davor, bekaeme nur die erste ihre
Pruefung und alle anderen die Vorlage doppelt -- genau so entstanden
am 22.09. aus zwei Klicks 112 Aufgaben. Gemessen: erster Klick 36
Aufgaben (12 mal 3 Modis), zweiter Klick 0 angelegt und 36
uebersprungen.

Ein gesperrter Modi bekommt nichts, ein Creator auch nicht, und wer
gar nicht verteilen darf, kommt ueber „alle" ebenfalls nicht weiter.

=== screen4: kein anderer Creator ===

Filipe: „in dieser app gibt es keinen und wird es niemals einen
anderen creator geben wie mich."

Auf der Aufgabenseite war eine Filterreihe mit „Alle Creator"
beschriftet -- und darunter standen Modis. Auf der Team-Adresse gibt
es keine Creator und wird es nie geben. Sie heisst dort jetzt „Für
wen".

DAS HAUS KOMMT VOM SERVER. `/api/ich` schickt jetzt `haus`; es stand
schon an der Sitzung und wurde nie mitgeschickt. Eine Rollenliste im
Browser waere die naechste zweite Wahrheit -- und falsch fuer
DogFather, der in beiden Haeusern arbeitet.

NEUN WEITERE „BEFUNDE" WAREN MEINE MESSFEHLER. Meine erste Messung
lief ueber 127.0.0.1 und meldete unter anderem „CREATOR WORKSPACE" in
der Kopfleiste JEDER Seite. Auf der echten Adresse steht dort „Team
Dogi" -- `person.haus` wird aus dem Host abgeleitet, und auf
127.0.0.1 ist das Haus nun einmal die Agentur. Nachgemessen mit
gesetztem Host: crew. -> haus="crew", marke="Team Dogi". Die
Uebersichtsseite mit ihren Creator-Texten steht auf crew. gar nicht
erst in den Kacheln.

Gemessen: pruef-an-alle, 19 Pruefungen, 0 Fehler. Gruen:
pruef-aufgabenbrett, pruef-aufgaben-vorlagen, pruef-vorlagen,
pruef-entwicklung (48), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 11:27:10 +02:00
DogFatherGitandClaude Opus 5 710b766ffa Die rechte Hand: dieselben Rechte, außer an DogFather
Filipe: „die rechte hand soll das auch sehen. und die selben rechte
da haben wie dogfather. das einzige was sie nicht kann ist die
dogfather rolle oder leute anfassen. also da kann sie nichts
verändern."

ZUERST EIN IRRTUM VON MIR. Ich hatte den Bildschirmfoto-Ausschnitt
fuer die Rechtetafel gehalten und dort gebaut. „Vertritt dich im
Alltag und koordiniert das Team" steht aber in workspace-personen.js:
Gemeint war die PERSONENSEITE. Die Arbeit an der Rechtetafel ist
trotzdem drin (siehe unten) -- sie loeste dasselbe Problem an einer
zweiten Stelle.

=== DIE PERSONENSEITE ===

DIE OBERFLAECHE WAR STRENGER ALS DER SERVER. In personen.js stand
`if (ich.rolle === 'hand') { keine Knoepfe }` mit der Begruendung
„Der Server antwortet ihr auf jeden davon mit 404". Am 22.09. stimmte
das. Seither wurde der Server ZWEIMAL erweitert -- sie durfte
Personen anlegen, Codes neu erzeugen und Rollen aendern -- und diese
Zeile blieb stehen. Sie hatte drei Rechte und sah keinen einzigen
Knopf. Ein Rollenvergleich im Browser ist genau die zweite Wahrheit,
die still veraltet.

Jetzt fragt die Oberflaeche den Server (`darf_zugaenge_verwalten`,
`darf_personen_loeschen`, `rollen_anfassbar`). Dazu kommen SPERREN
und LOESCHEN, die bis heute ausdruecklich bei DogFather lagen --
Filipes „das einzige" ist juenger und eindeutig.

Die Knoepfe „Neuer Code" und „Sperren" standen inline im
DogFather-Zweig; sie sind jetzt Funktionen und werden von beiden
Stellen benutzt. Eine zweite Abschrift waere die geworden, die beim
naechsten Umbau nur halb nachgezogen wird.

ZWEI ECHTE LOECHER FAND DIE NEUE PRUEFUNG:
  * `PUT /personen/:id/rolle` hatte `nurDogFatherBeiLeitung` NICHT.
    Bis heute folgenlos; mit den neuen Rechten konnte die rechte Hand
    darueber die Rolle eines MANAGERS aendern -- waehrend derselbe
    Manager fuer DogFather auf crew. gar nicht in der Liste steht.
    Zwei Wege, zwei Antworten, und der laxere galt fuer die Rolle mit
    weniger Rechten.
  * Die Loesch-Route hatte dieselbe Middleware ebenfalls nicht. Das
    war harmlos, solange die Route selbst nur DogFather durchliess --
    seit die rechte Hand loescht, ist es die Stelle, an der DogFather
    geschuetzt wird.

=== DIE RECHTETAFEL (nicht bestellt, aber dasselbe Problem) ===

Dort durfte sie sehen, aber nichts umstellen. Jetzt umstellen wie
DogFather -- ausser der Spalte „DogFather" und der Zeile „Personen &
Zugaenge" (wer die freischaltet, hat Zugaenge vergeben, ohne einen
anzulegen). Zuruecksetzen bleibt bei DogFather: Der Knopf naehme
genau diese zwei Sperren mit, und eine Sperre, die ein zweiter Knopf
daneben aufhebt, ist keine.

Sie kann sich auch selbst nicht aussperren -- das hat er nicht
gesagt, aber eine Sperre, aus der man sich aussperren kann, ist eine
Falle. Ein festes Feld ist jetzt gar kein Knopf mehr und nennt den
Grund, der fuer DIESE Person gilt.

=== DREI MESSFEHLER VON MIR ===
Ein Manager ist auf crew. fuer die LISTE unsichtbar, fuer DogFathers
direkten Zugriff aber nicht -- ich hielt das eine fuer das andere und
erwartete, dass beide abgewiesen werden. Die Loesch-Vorschau (GET)
fehlte in meinem Waechter. Und `rollen_anfassbar` beantwortet eine
andere Frage als „wen sehe ich".

Gemessen: pruef-hand-personen, 40 Pruefungen, 0 Fehler -- jeder der
fuenf Wege einzeln gegen DogFather und die linke Hand, plus die
Gegenprobe, dass DogFather es kann. pruef-rechte-umstellen von 46 auf
56 Pruefungen. Gruen: pruef-personen-liste, pruef-personen-loeschen,
pruef-personen-kachel, pruef-rollen-anlegen, pruef-rechtetafel.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 11:16:26 +02:00
DogFatherGitandClaude Opus 5 9f5dbb42e3 Support: melden mit Bild, und für die Leitung ein Eingang
Filipe: „da fehlt auch eine support kachel. die jeder sieht. jeder
benutzen kann. jeder kann da probleme von der seite melden und
hinweisen. fotos mit schicken mit einem text. … so einfach wie
möglich, will nichts kompliziertes oder zu viel. kurz und knapp …
bei dogfather und der rechten hand soll die kachel anders gebaut sein
weil die sind die die sich um die probleme kümmern."

WARUM DAS NICHT DER VORHANDENE MELDEWEG IST. Es gibt ihn schon
(hilfe.html) und er sieht aehnlich aus. Drei Unterschiede machen ihn
zu etwas anderem:
  1. Er ist NICHT fuer alle -- in rechte.js steht
     `["gast","hand","admin"]`. Modis, Creator, Scouts, Manager und
     die linke Hand hatten gar keinen Weg, einen kaputten Knopf zu
     melden.
  2. Er kann keine Bilder. Bei „der Knopf tut nichts" ist ein
     Bildschirmfoto die halbe Antwort.
  3. Er ist bewusst schwer: strikter Wechsel, hoechstens drei offene
     Faelle, ein Betreff. Richtig bei einem Vorfall zwischen
     Menschen, zu viel fuer „das Datum steht falsch da".

Deshalb eigen und sehr kurz: EIN Feld, EIN Bild, fertig. Kein
Betreff, keine Kategorie, keine Dringlichkeitsstufe -- wer ein
Formular mit fuenf Feldern sieht, meldet den kleinen Fehler nicht,
und genau die kleinen erfaehrt sonst niemand.

DIE LEITUNG SIEHT ETWAS ANDERES: einen Eingang mit Zahlenband
(neu / in Arbeit / erledigt), drei Filtern und zwei Handgriffen --
„Ich kuemmere mich" und „Erledigt …". Zwei, nicht fuenf; eine
Zuweisung an eine Person und Prioritaeten waeren ein Ticketsystem
fuer zwei Menschen, die nebeneinander sitzen. Das Melde-Feld bleibt
auch fuer sie da, rutscht aber unter den Eingang.

Wer zumacht, schreibt einen Satz dazu -- der Melder sieht nur diesen
Satz, und ohne ihn weiss er nicht, ob etwas behoben wurde oder ob
niemand Zeit hatte. Beide Seiten bekommen eine Benachrichtigung.

UEBERNOMMEN STATT NEU ERFUNDEN:
  * `dateiErkennen` aus workspace-chat.js -- EXPORTIERT, nicht
    abgeschrieben. An ihr haengt die ganze Sicherheit der Uploads
    (der Typ kommt aus den ersten Bytes, nicht aus Name oder
    Content-Type), und eine zweite Fassung waere die, die beim
    naechsten Dateiformat vergessen wird.
  * Die zweigeteilte Sicht und `meldungFuer()` (gibt den Datensatz
    oder null zurueck, nie true/false) aus dem vertraulichen
    Meldeweg.
  * Der Upload-Weg (express.raw, Text im Kopf, Ordner unter
    DATEN_ORDNER, damit die Sicherungspruefung ihn findet).

DIE KACHEL BEKOMMT JEDER -- an EINER Stelle angehaengt: `bereicheFuer`
haengt sie an jede Rollenliste, statt sie in fuenf Listen
einzutragen. Genau so ist heute der Benachrichtigungs-Knopf auf 14
Seiten verschwunden. Dazu der Eintrag in rechte.js (ohne ihn
verschwindet die Kachel lautlos, `nurOffeneKacheln` filtert dagegen)
und in der Browser-Kachelliste fuer die Agentur-Rollen.

TON 44 GERECHNET, NICHT GEWAEHLT -- und dabei zweimal danebengelegen:
  * Ich habe erst einen eigenen Modus in kachel-farben.mjs gebaut.
    `tools/kachel-farbe-einzeln.mjs` gibt es aber seit dem 22.09. fuer
    genau diesen Zweck. Meine Dopplung ist wieder weg.
  * Von Hand hatte ich #bcdbff eingetragen. pruef-kachelfarben lehnte
    es ab (Buntheit 0,060, verlangt sind 0,12) -- und das vorhandene
    Werkzeug verteidigte es trotzdem, weil sein Abstand gut war. Ein
    Werkzeug, das einen regelwidrigen Zustand haelt, weil er zufaellig
    gut misst, behebt genau den Fehler nicht, fuer den es da ist.
    Behoben: Zuerst die Regeln, dann der Abstand. Ergebnis #fd6401,
    Abstand 0,0914 (engstes vorhandenes Paar: 0,0154).

DREI MESSFEHLER VON MIR, die wie schwere Befunde aussahen: `fetch`
verwirft den Host-Kopf (die Community kommt nur auf crew. herein),
die Community bestaetigt ihr Alter (`alter_ok`), und die Startroute
heisst /api/ich. Alle drei stehen in pruef-treff.mjs richtig.

Ein ECHTER Fehler kam dazu: support.html lud bereiche.js nicht, und
kopf.js stuerzte mit „Cannot read properties of undefined (reading
'LEITUNG')" ab -- sichtbar nur in der Browserkonsole. Und
pruef-css-klassen fand sofort, dass auch wahl.js fehlte.

Gemessen: pruef-support 45 Pruefungen, 0 Fehler (alle neun Rollen
kommen herein, jede sieht die Kachel, als Bild getarntes HTML wird
abgelehnt, eine fremde Meldung bleibt fremd, erledigt bleibt
erledigt). Dazu 24 Messungen am Bild in drei Groessen. Gruen:
pruef-kachelfarben (22), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 01:32:55 +02:00
DogFatherGitandClaude Opus 5 4d36f1cbf0 Der Benachrichtigungs-Knopf steht jetzt wirklich überall
Filipe: "dieser button soll bei jeder rolle perfekt funktionieren
bitte."

GEMESSEN, NICHT GERATEN. Serverseitig war nichts rollenabhaengig:
alle drei Routen (Schluessel, Stand, Probe) antworten jeder der acht
Rollen mit 200, und `willHaben` haengt an der Person, nicht an der
Rolle. Der Mangel lag woanders -- und genau dort, wo die Rolle
entscheidet: BEI DEN SEITEN.

14 Seiten haben eine Kopfleiste und luden glocke.js nicht. Welche
Seiten jemand benutzt, haengt an seiner Rolle:

  Creator -> befinden.html, werdegang.html, teilen.html
  Scout   -> talente.html, bewerbungen.html
  Modi    -> treff-moderation.html, treff-regeln.html
  Manager -> entwicklung.html, teamlage.html

Keine dieser Seiten hatte den Knopf. Wer dort war, konnte
Benachrichtigungen nicht einschalten -- und hat nicht einmal gesehen,
dass es sie gibt. Das CSS war ueberall schon da (start.css), es
fehlte allein die eine Skriptzeile. Jetzt steht er auf allen 34
Seiten mit Kopfleiste.

AUSGENOMMEN, UND ZWAR NAMENTLICH: anruf-probe.html. Die Seite hat
kein kopf.js, ist eine eigenstaendige Diagnoseseite, und
anruf-probe.js verweist ausdruecklich auf "im Chat oben auf die
Glocke tippen". Die Ausnahme steht in der Pruefung als Name, nicht
als Schweigen.

WARUM DIE PRUEFUNG DAS NICHT GEFUNDEN HAT -- zwei abgeschriebene
Listen, beide unter einer Ueberschrift, die mehr versprach:

  "Der Knopf ist UEBERALL"   sah 8 von 37 Seiten an.
  "JEDE Rolle bekommt ihn"   sah 4 von 8 Rollen an -- es fehlten
                             rechte Hand, linke Hand, Modi und
                             Spicy Media. Ausgerechnet die Modis
                             sind die groesste Gruppe im Haus.

Beide waren gruen. Sie haben nicht falsch gemessen, sie haben das
Falsche gemessen. Jetzt kommt die Seitenliste aus dem Verzeichnis
(jede Seite mit Kopfleiste) und die Rollenliste umfasst alle acht --
eine Liste, die niemand pflegt, kann nicht veralten. Und die Zahl
steht in der Bedingung, damit "auf allen 0 geprueften" nicht gruen
sein kann.

Dabei fielen zwei Dinge an der Pruefung selbst an: Ihr `anlegen`
setzte keine `code_kennung`, und ihre Anmeldung klickte stur auf
`.rolle[data-rolle="..."]`. Beides brach bei rechter Hand, linker
Hand und Modi ab -- den drei Rollen mit dem STILLEN ZUGANG, die
absichtlich keine eigene Kachel haben (Filipe, 09.09.2026: "damit die
von der workspace auch nicht mal sehen dass die modis von mir einen
eigenen zugang haben"). Sie tippen auf irgendeine Kachel, der Code
entscheidet. Derselbe Stolperstein hat vorher auch meine eigene
Messung dreimal "kommt nicht hinein" melden lassen -- ein Messfehler,
der wie ein schwerer Befund aussah.

31 -> 36 gepruefte Punkte, keiner weggefallen. Gruen: pruef-glocke,
pruef-push, pruef-push-ziel, pruef-css-klassen. Dazu eine eigene
Messung ueber alle acht Rollen: Knopf da, Routen 200/200/200,
8 Messungen, 0 Befunde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 01:06:04 +02:00
DogFatherGitandClaude Opus 5 d85694bd92 Keine fertigen Vorschläge mehr bei den Highlights
Filipe: "nimm die sachen da weg bitte. da sollen nur die sachen rein
kommen die die modis, linke und rechte hand oder dogfather
reinsetzen."

In der Spalte "Noch einzusortieren" standen drei vorgefertigte
Vorschlaege ("Was hier hingehoert", "Fanart von DogFather und Casper
ist ausdruecklich erwuenscht", "Ein Ausschnitt, der auf die Clips
soll"). Jemand hatte sie uebernommen, und danach standen sie zwischen
den echten Clips -- mit Datum, mit Verfasser, aeusserlich nicht von
einem echten Eintrag zu unterscheiden.

WARUM DIESES BRETT ANDERS IST ALS DIE UEBRIGEN: Anderswo ist ein
Vorschlag eine ANREGUNG, die man ausfuellt ("Der naechste Stream mit
DogFather" -> Datum eintragen). Highlights ist eine SAMMLUNG echter
Sachen. Ein vorgefertigter Text ist dort kein Anfang, sondern ein
Platzhalter, der aussieht wie Inhalt. Die anderen Bretter behalten
ihre Vorschlaege -- dazu hat er nichts gesagt.

Nebenbefund: Seine Rollenaufzaehlung ist genau TREFF_TEAM_ROLLEN
(modi, hand, linke, admin). Die Rechteregel stimmte also schon.

ZWEI ECHTE MAENGEL FIELEN DABEI AUF, beide beim Versuch, die drei
Eintraege wegzunehmen:

1. Der Knopf "loeschen" schickte DELETE OHNE GRUND. Der Server
   verlangt bei einem fremden Beitrag auf einem Treff-Brett einen
   (DSA Art. 17) und antwortet mit 400 -- die Oberflaeche zeigte nur
   "Loeschen hat nicht geklappt." Zwei Knoepfe nebeneinander, einer
   ging ("entfernen"), einer nicht, und die Meldung erklaerte nichts.
   Jetzt fragt auch "loeschen" nach dem Grund, wenn der Server einen
   braucht -- erkannt an `treffBrett` vom Server, nicht an einer
   abgeschriebenen Brettliste -- und die Fehlermeldung gibt wieder,
   was der Server gesagt hat.

2. Der Dialog liess DREI Zeichen als Grund durch, der Server verlangt
   ZEHN. Wer "spam" tippte, kam durch die Nachfrage und bekam danach
   eine Absage. `grund_min` steht seit dem 11.09. in /api/treff/lage
   und wurde nie benutzt; jetzt ist es angeschlossen. In nachfrage.js
   bestimmt der Aufrufer die Mindestlaenge (`grundMin`), Vorgabe
   bleibt 3 -- fuer alle anderen Nachfragen aendert sich nichts.

UND ZWEI PRUEFUNGEN, DIE ROT WAREN, OHNE DASS ETWAS KAPUTT WAR:

- pruef-treff-start verlangte `>= 8` Vorschlaege auf dem Schirm. Das
  stimmte bis zum Fenster-Umbau vom 20.09. -- seither kommen
  hoechstens VIER (FENSTER = 4). Vier Tage rot, ohne dass es jemand
  erfuhr. Gefragt wird jetzt der Server selbst. Und die Brettliste
  ["treff","anschlag","wunsch","highlight"] wird gegen den Bestand
  abgeglichen statt abgeschrieben -- mit ausdruecklichem Nachweis,
  dass Highlights keine mehr hat, damit das Wegfallen nicht einfach
  eine Pruefung weniger bedeutet. 41 -> 42 Pruefungen.

- pruef-nachfrage zaehlte `installieren.js` als "diese Seite fragt
  nach", obwohl der Aufruf dort hinter `if (typeof window.frageNach
  === 'function')` steht. Weil die Datei auf fast jeder Seite liegt,
  wurde damit JEDE Seite zur fragenden -- fuenf rote Zeilen, kein
  einziger echter Mangel. Ausserdem wurde die Kurzschreibweise
  `{ titel, … }` als "ohne Titel" gemeldet. 46 -> 53 Pruefungen, alle
  gruen; zwei davon sind neu (Gegenprobe plus Benennung der
  Ausnahmen).

Beide mit Gegenprobe (git stash) belegt: schon vor dieser Aenderung
rot.

Gemessen: 11 Messungen, 0 Befunde -- darunter die Gegenprobe, dass
der alte Weg (DELETE ohne Grund) wirklich mit 400 gescheitert waere.
Gruen: pruef-treff-start (42), pruef-nachfrage (53), pruef-highlights
(31), pruef-anschlagbrett (12), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:50:42 +02:00
DogFatherGitandClaude Opus 5 428235508f Noch einmal auf dieselbe Person: die Liste geht wieder zu
Filipe: "ich will das wenn ich wieder auf die person drücke die liste
unten dan wieder zu geht."

Dasselbe Muster, das die Stufenleiste auf derselben Seite schon hat
("Ein zweiter Klick auf dieselbe Stufe hebt den Filter auf") -- nicht
ein zweites, neu erfundenes. Der Weg zurueck ist derselbe Knopf wie
der Weg hin; ein eigener Schliessen-Knopf daneben waere ein zweites
Ziel fuer dieselbe Absicht.

WIEDERHERGESTELLT WIRD DER AUSGANGSZUSTAND, nicht "alles versteckt" --
und das ist ein Unterschied, der beinahe zu einem Fehler geworden
waere. Das Verteil-Band und das Vorlagenbrett stehen naemlich AUCH
OHNE AUSWAHL da; der Start ruft "verteilBandZeigen(null, null)" selbst
auf. Sie mit auszublenden haette ausgesehen wie Zumachen und waere
Wegnehmen gewesen. Sie fallen deshalb nur auf "niemand gewaehlt"
zurueck. Wirklich weg gehen die zwei Kaesten, die es ohne Person gar
nicht gibt: ihre Aufgaben und ihre Karte.

Gemessen wird genau das: Der Zustand VOR der Auswahl wird aufgenommen
und hinterher Feld fuer Feld verglichen (Band, Brett, Aufgaben, Karte,
eigene Karte, Meins). Dazu: ein dritter Druck macht wieder auf (kein
Einwegschalter), und eine ANDERE Person wechselt, statt zuzumachen.

14 Messungen, 0 Befunde. Gruen: pruef-entwicklung (48),
pruef-entwicklung-kacheln.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:36:21 +02:00
DogFatherGitandClaude Opus 5 362d883392 Personen als Kacheln statt Zeilen
Filipe: "gestalte diese seite auch anders bitte. viel krasser geiler
uebersichtlicher." Auf das Angebot, die Rollen als Kacheln statt
Zeilen zu bauen: "will ich." Entwurf gezeigt, Antwort: "so live".

Eine Person war eine Zeile ueber die volle Breite -- links der Name,
darunter fuenf halbe Saetze, rechts die Knoepfe. Gemessen: 1128 x 74
px, eine pro Reihe, mit achthundert Pixeln Luft in der Mitte. Jetzt
368 x 221 px, drei nebeneinander: sechs Creator brauchen zwei Reihen
statt sechs.

Die Angaben stehen in einem Zahlenband statt als Satzreihe -- aus
"offene Aufgaben: 0 · 2 offene Sitzung(en) · betreut 3 Creator"
werden Felder mit grosser Zahl und kleinem Wort, in jeder Kachel an
derselben Stelle. Man vergleicht zwei Personen mit dem Auge, statt in
jeder Zeile an einer anderen Stelle nach derselben Zahl zu suchen.

Dazu: "vor 21 Tagen" statt "2026-09-15 00:26" (das genaue Datum bleibt
als Titel dran), ein Namenszeichen in der Rollenfarbe mit schmalem
Farbstreifen oben, und "gesperrt" als Marke in der Warnfarbe statt als
graues Wort zwischen fuenf grauen Woertern.

ES FAELLT NICHTS WEG. Name, Rolle, gesperrt, Anmeldung, Aufgaben,
Sitzungen, betreute Creator, zugeteilte Scouts, "gehoert zu", die
Zustaendigkeitsauswahl und alle Knoepfe -- die Messung prueft das
ausdruecklich mit, huebsch und unvollstaendig waere schlechter als
vorher.

Keine feste Spaltenzahl: "auto-fill" laesst den Browser rechnen, bei
1160 px sind es drei, bei 390 px eine. Eine Zahl waere die sechste
Wiederholung desselben Fehlers in diesem Haus.

Nebenbei zwei Altlasten: .marke-rolle und .betreuung__schild standen
auf 11,2 px, unter der Hausgrenze von 11,5. Mit Gegenprobe belegt,
dass das schon vorher so war -- jetzt .75rem.

Gemessen: 14 Messungen, 0 Befunde (1765 px und 390 px). Gruen:
pruef-personen-kachel (45), pruef-personen-liste, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:33:09 +02:00
DogFatherGitandClaude Opus 5 14c8964b24 Die Unterkategorien nach Alter erscheinen jetzt wirklich
Filipe: "wieso sehe ich nichts von diesen unterkategorien?"

Weil ich gestern eine Schwelle eingebaut hatte, die er nie verlangt
hat: Gegliedert wurde erst ab 13 Eintraegen. Seine Spalten haben 3,
1, 1 und 4 -- er hat die Gliederung also nie zu sehen bekommen.

Die Begruendung von gestern stand als Kommentar daneben und klang
vernuenftig: "Bei wenigen Eintraegen waere eine Gliederung Aufwand
ohne Nutzen: sieben Ueberschriften fuer fuenf Karten." Sie war in
beiden Haelften falsch. Erstens war die Ansage klar -- eine eigene
Bedingung daranzuhaengen ist keine Sorgfalt, sondern eine
Entscheidung, die mir nicht zusteht. Zweitens gab es die sieben
Ueberschriften nie: Leere Stufen werden ohnehin uebersprungen, drei
Karten ergeben hoechstens drei Ueberschriften. Genau das misst die
Messung jetzt mit.

Nachgestellt wurde sein Bildschirmfoto: vier Spalten mit 3, 1, 1, 4.
DogFather zeigt "Heute 1 (offen) | Gestern 1 (zu) | Diese Woche 1
(zu)", die Sammelspalte vier Stufen bis "Über sechs Monate". Keine
Stufe steht leer da (9 geprueft), die neueste ist offen, ein Druck
auf die Ueberschrift klappt zu.

Gemessen: 10 Messungen, 0 Befunde. Gruen: pruef-highlights (31),
pruef-anschlagbrett (12), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:31:58 +02:00
DogFatherGitandClaude Opus 5 08ff3e5e40 Die Liste im Dialog rollt, das Anschlagbrett schreibt nicht mehr ab
Zwei Dinge aus Filipes Durchgang.

ERSTENS: "das hoch und runter scollen geht nicht in der liste da."
Die Auswahlliste im Kanal-Dialog liegt seit dem Popover-Umbau in der
obersten Ebene. Das loest das Abschneiden -- aber der Zeiger steht
danach ueber dem Dialog, nicht ueber der Liste, und das Mausrad rollt
den Dialog. Der Horcher haengt jetzt am Dokument (capture) und fragt
selbst, ob der Zeiger im Rechteck der Liste steht. Gemessen:
5 Messungen, 0 Befunde.

ZWEITENS: "gestalte diese seite auch anders ... viel uebersichtlicher."
Am Anschlagbrett stand die Herkunft als vollstaendige Abschrift des
Titels darueber -- derselbe Satz zweimal, direkt untereinander. Jetzt
nennt sie nur noch das Brett, wenn der Titel uebernommen wurde, und
kuerzt sonst auf 60 Zeichen an der Wortgrenze. Dazu Karten mit
620 px Hoechstbreite, zwei nebeneinander statt einer Zeile ueber die
ganze Breite -- lesbar bleibt, was eine begrenzte Zeilenlaenge hat.
Gemessen: 11 Messungen, 0 Befunde; Titel von 352 px statt voller
Breite, zwei Spalten a 571 px.

Geprueft: pruef-anschlagbrett (12, 0), pruef-css-klassen,
pruef-highlights, pruef-chat-kanaele (81, 0), pruef-freie-namen (32, 0).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:18:04 +02:00
DogFatherGitandClaude Opus 5 7f732cc403 Gegliedert nach Alter: sieben Stufen, klappbar
Filipe: "ich will da unterkategorien die man auf und zu klappen kann,
so wie heute gestern, diese woche, diesen monate, über ein monat,
über 6 monate, über ein jahr."

DAS IST DIE BESSERE ANTWORT AUF DIE LANGEN LISTEN als die Zahl von
gestern. Zwoelf ist willkuerlich; eine Gliederung nach Alter
beantwortet die Frage, die man an so eine Liste wirklich stellt --
was ist neu?

DIE ERSTEN VIER STUFEN SIND KALENDERBEZOGEN, die letzten drei
altersbezogen:

  Heute, Gestern          der Kalendertag
  Diese Woche             seit MONTAG -- am Dienstag ist der Freitag
                          davor nicht "diese Woche"
  Dieser Monat            seit dem Ersten
  Ueber einen Monat       der Abstand, weil "Mai" niemandem sagt,
  Ueber sechs Monate      wie lange das her ist
  Ueber ein Jahr

Das klingt uneinheitlich und ist genau richtig.

DIE NEUESTE GRUPPE STEHT OFFEN, die aelteren zu. Wer die Seite
aufmacht, will sehen was neu ist -- und alles Aeltere ist sichtbar
VORHANDEN, ohne den Weg zu verstellen. Die eigene Wahl gewinnt und
wird gemerkt, je Gruppe und je Spalte.

EINE LEERE STUFE ERSCHEINT NICHT. Sieben leere Ueberschriften waeren
schlimmer als eine lange Liste. Und gegliedert wird erst UEBER zwoelf
Eintraegen -- darunter waeren es sieben Ueberschriften fuer fuenf
Karten.

Die Zwoelfergrenze von gestern bleibt, gilt aber jetzt JE GRUPPE: Auch
"Ueber ein Jahr" kann dreihundert Eintraege haben, und dann hilft die
Gliederung allein nicht.

GERECHNET WIRD IN ORTSZEIT (window.heuteLokal), nicht in UTC. Ein
Eintrag von gestern 23:40 waere in UTC schon heute und stuende unter
"Heute", waehrend das Datum daneben gestern sagt.

ZWEI DINGE NACHGESEHEN STATT GERATEN:

  abschnittKlappbar nimmt als vierten Wert ein BOOLEAN (zuVorgabe),
  kein Objekt. Ich hatte "{ offen: ... }" angenommen; beim Nachsehen
  in kopf.js stand etwas anderes da.

  Jede Gruppe braucht einen eigenen Merker. Ohne ihn teilten sich
  "Heute bei DogFather" und "Heute bei HasiDog" denselben Zustand,
  und wer die eine zuklappt, klappt die andere mit.

Gemessen mit Eintraegen ueber alle sieben Stufen: 10 Messungen,
0 Befunde -- Reihenfolge, Zahlen, offen/zu, Klapp-Pfeil, kein
seitlicher Ueberstand, und ein Tipp macht eine zugeklappte Gruppe
wirklich auf. pruef-highlights 31, pruef-galerie und
pruef-css-klassen in Ordnung.

NOCH OFFEN -- screen1: "Screenshots oder Kurzschnitte reinposten"
braucht eine Route, die eine Datei an einen EINTRAG haengt. Die gibt
es heute nicht: workspace-video.js legt Coverbilder beim Einlesen
eines TikTok-Links an, workspace-dateien.js laedt hoch, aber ohne
eintrag_id. Das ist ein eigener Brocken und kein Nebenbei.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:06:59 +02:00
DogFatherGitandClaude Opus 5 2bea133feb Das Protokoll spricht deutsch -- und zwei Pruefungen messen wieder
Filipe: "ich will dass das alles viel anders und krasser und geiler
gestaltet ist bitte ... viel profissioneller und moderner."

--- DIE PERSONENSEITE ---

Auf seinem Bildschirmfoto stand woertlich, was in der Datenbank steht:
"treff_freigegeben", "video_eingelesen", "einstellung_geaendert". Das
sind Spaltenwerte, keine Saetze fuer Menschen. Daneben die rohe
IP-Adresse, quer ueber ein Viertel der Zeile.

KEINE TABELLE MIT 77 EINTRAEGEN. So viele Aktionen gibt es; eine
Liste davon waere am Tag der naechsten unvollstaendig, und niemand
merkte es -- dann stuende einfach wieder der Rohname da. Dieselbe
Falle wie jede abgeschriebene Liste in diesem Haus.

Stattdessen eine REGEL: Unterstriche werden Leerzeichen, der erste
Buchstabe gross. Das ergibt fuer jede Aktion einen lesbaren Ausdruck,
auch fuer die, die es noch nicht gibt. Nachgeprueft an allen echten
Namen:

  treff_freigegeben      -> Treff freigegeben
  einstellung_geaendert  -> Einstellung geändert
  chat_zurueckgenommen   -> Chat zurückgenommen
  vorlage_uebernommen    -> Vorlage übernommen

Die Umlaute sind der zweite Teil: In der Datenbank stehen sie als
ae/oe/ue. Blind zurueckzusetzen waere falsch ("neue" wuerde "neü"),
deshalb nur in Wortteilen, die sicher sind -- gemessen an den 77
echten Namen, nicht geraten.

Der Rohname bleibt als Titel an der Zeile: Wer im Server danach sucht,
braucht ihn genau so, wie er in der Spalte steht.

DIE IP TRITT ZURUECK, verschwindet aber nicht: feste schmale Spalte,
leiser Ton. Sie beantwortet eine Frage, die man selten stellt.

UND DIE BESCHREIBUNGEN BRECHEN UM. Die der linken Hand lief ueber 150
Zeichen in einer Zeile; der Augensprung ans naechste Zeilenende ist
dann so weit, dass man die Zeile verliert. Setzer rechnen seit
Jahrhunderten mit 60 bis 80. Gekuerzt wird nichts -- "78ch" misst in
ZEICHEN und stimmt darum auch, wenn die Schrift groesser gestellt wird.

--- UND DIE ZWEI ALTLASTEN, BEIDE GESTERN GEMELDET ---

pruef-chatkachel suchte dreizehn Toene als dreizehn Knoepfe. Das
stimmte, bis die Kachelfarbe ein FARBKREIS wurde (7a674963): Seither
liegen die meisten auf einem Schieberegler und werden durch Drehen
gewaehlt. Sie meldete seither "mit allen 13 Toenen (2)" -- nichts war
kaputt, sie stellte eine Frage, die es nicht mehr gibt. Jetzt fragt
sie, was zaehlt: Ist der Kreis da, ist er bedienbar, sagt er welche
Farbe eingestellt ist, und stehen die uebrigen daneben. 36 Pruefungen,
alles in Ordnung.

pruef-galerie mass "#liste". Das war richtig, bis die Highlights am
20.09. in Kanalspalten umzogen -- seither nimmt bereich.js dem
Listenkasten sein data-galerie ausdruecklich wieder weg und setzt es
an die einzelne Spalte. Die Pruefung mass also eine leere Huelle.
Dazu erwartete sie "mindestens zwei Spalten", und das ist in einer
schmalen Kanalspalte schlicht falsch: Dort gehoert EINE Kachel je
Reihe. Jetzt sucht sie das Raster ueber das BILD (nicht ueber einen
Kastennamen -- der naechste Umbau darf umbenennen) und fragt nach der
KACHELBREITE: "1 Spalte à 219 px in einem 243 px breiten Kasten".
Eine Galerie, die sich in vier Spalten à 90 px quetscht, waere der
Fehler -- nicht eine Spalte in einem schmalen Kasten.

Beide waren monatelang rot, ohne dass etwas kaputt war. Eine Warnung,
die immer kommt, liest irgendwann niemand mehr -- und dann faellt die
echte daneben auch nicht mehr auf.

Gemessen: pruef-chatkachel 36, pruef-galerie, pruef-css-klassen,
pruef-deutsche-texte -- alle ohne Befund.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-24 00:00:47 +02:00
DogFatherGitandClaude Opus 5 7aef7e4b9a Keine Liste ohne Ende -- und die vierte Spalte sagt, was zu tun ist
Filipe: "der ohne account ist total sinnlos, mach was anderes draus.
und mach die ganze seite noch viel uebersichtlicher und ohne so dass
es extrem lange listen gibt mit der zeit."

ZWEI SACHEN, UND BEIDE FANGEN MIT NACHSEHEN AN.

--- 1. Was liegt eigentlich in "Ohne Account"? ---

Nachgezaehlt in den echten Daten:

  2 x clip     <- eine Luecke: ein Clip kommt IMMER von einem Kanal
  1 x moment
  1 x fanart   <- gehoert zu Recht zu keinem Account

Die Spalte mischte also zwei Dinge, die nichts miteinander zu tun
haben: etwas, das einsortiert gehoert, und etwas, das dort richtig
liegt. Und sie hiess nach dem, was FEHLT. Wer die Zahl sah, wusste
nicht, ob er etwas tun muss -- genau das macht sie "sinnlos".

Jetzt entscheidet der Inhalt ueber Namen und Satz:

  Clips dabei   -> "Noch einzusortieren" + "2 Clips hier haben keinen
                   Account. Öffne sie und trag ihn nach."
  nur Bilder    -> "Ohne TikTok-Quelle" + "Eigene Bilder und Fanart
                   gehören zu keinem Account. Hier ist nichts zu tun."

NICHT IN ZWEI SPALTEN GETRENNT: Das waere eine mehr, und Filipe hat
im selben Satz um weniger gebeten.

--- 2. "mit der zeit" ist der Kern ---

Heute liegen neun Highlights da und alles passt. In einem Jahr sind es
dreihundert, und dann ist jede Spalte eine Rolle ohne Ende. Der Fehler
faellt erst auf, wenn er schon laestig ist -- deshalb jetzt.

Je Abschnitt zwoelf, der Rest auf einen Druck. Zwoelf, weil zwei
nebeneinander passen: sechs Reihen, genug um zu sehen was zuletzt war,
ohne bis zum Anfang der Zeit zu scrollen.

AN EINER STELLE FUER ALLE DREI FORMEN. Die Seite legt Karten an drei
Stellen in einen Kasten -- Kanalspalten, Abschnitte nach Art,
Zeitstrahl. Dreimal dasselbe hinzuschreiben hiesse, dass beim
naechsten Umbau zwei nachgezogen werden und eine vergessen wird.

ES VERSCHWINDET NICHTS, und die Zahlen in den Koepfen zaehlen weiter
ALLE: Eine Ueberschrift, die 12 sagt und 30 meint, waere schlimmer als
eine lange Liste. Gemessen mit 30 Eintraegen: Kopf zeigt 30, Spalte
zeigt 12, Knopf bietet "18 ältere zeigen", nach dem Druck sind alle 30
da und der Knopf ist weg -- er haette nichts mehr zu tun.

Sortiert ist ohnehin nach Datum absteigend, "die ersten zwoelf" sind
also die neuesten zwoelf und nicht die erstbesten.

Gemessen: 8 Messungen mit dem Datenbestand "ein Jahr spaeter",
0 Befunde. pruef-css-klassen und pruef-highlights in Ordnung.

NICHT VON MIR, mit Gegenprobe belegt: pruef-galerie meldet "mit
mehreren Spalten (1)" -- auch mit zurueckgenommener Aenderung. Eine
Altlast, die nachgezogen gehoert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 23:50:21 +02:00
DogFatherGitandClaude Opus 5 d868bb1e35 Die Personenkacheln: aus drei Zahlen wird ein Bild
Filipe: "ich will dass das alles viel anders und krasser und geiler
gestaltet ist. mal was krass modernes ... viel viel viel
uebersichtlicher."

WAS AUF SEINEM BILDSCHIRMFOTO STAND: sechs Kacheln, jede mit drei
gleich grossen Zahlenkaesten -- und bei fuenf davon exakt dasselbe:
"0 angesehen, 68 noch offen, 0 verschieden gesehen". Achtzehn Kaesten
fuer eine einzige Auskunft: Hier ist noch nichts passiert.

DREI ZAHLEN MUSS MAN LESEN UND VERRECHNEN. Einen Balken sieht man.
Und die Frage, die man an diese Liste stellt, ist nicht "wie viele
genau", sondern "wer ist wie weit". Darum liegt unter jedem Namen
jetzt eine schmale Spur, vier Bildpunkte hoch, die genau das zeigt.

KEINE AMPELFARBEN. Was "genug" ist, haengt davon ab, wie lange jemand
dabei ist; eine Schwelle waere geraten und bei der naechsten Person
falsch. Der Balken sagt, WIE WEIT -- er urteilt nicht. Und er traegt
die Akzentfarbe der Seite, nicht Gruen oder Rot.

EINE NULL IST KEINE WARNUNG. "Verschieden gesehen" ist die einzige
der drei Zahlen, die zu einer Handlung fuehrt: Dort lohnt das
Gespraech. Steht dort eine Null -- der Normalfall --, tritt der Kasten
zurueck. Gleiche Groesse, gleicher Platz, nur leiser. Sonst waeren es
sechs gelbe Nullen, und die eine echte siebte faellt dann nicht mehr
auf.

NICHTS WURDE WEGGENOMMEN. Alle drei Zahlen stehen weiter da, gemessen:
drei Kaesten je Kachel, auf Rechner und Handy. Und ein
Vorleseprogramm bekommt den Balken als Satz ("0 von 68 angesehen,
0 Prozent") -- eine Breite allein sagt ihm nichts.

Augenschonend nach Hausregel: kein Leuchten, kein blendender Verlauf,
und die kurze Bewegung beim Neuzeichnen faellt bei
prefers-reduced-motion ganz weg.

Gemessen: 16 Messungen auf beiden Groessen, 0 Befunde.
pruef-entwicklung-kacheln, pruef-entwicklung (48) und
pruef-css-klassen alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 23:28:13 +02:00
DogFatherGitandClaude Opus 5 03220b3924 Kanaele machen nur zwei auf
Filipe: "kanaele sollen auch nur die rechte hand und dogfather
aufmachen koennen."

Bis heute galt `fuehrtTeamDogi` -- und das schliesst die LINKE Hand
ein (WIE_RECHTE_HAND = {hand, linke}). Genau die zwei Worte im Auftrag
schliessen sie aus.

`fuehrtTeamDogi` SELBST WIRD NICHT ANGEFASST. Es haengt an elf
weiteren Stellen: Bereiche, Bretter, Sichtbarkeiten, wer einen Kanal
ueberhaupt sieht. Wer die Funktion aendert, aendert zehn Dinge, die
niemand verlangt hat. Stattdessen eine eigene Regel fuer genau diese
eine Frage -- dieselbe Bauweise wie `darfJedeNachrichtLoeschen` ein
paar hundert Zeilen weiter unten, die aus demselben Grund entstanden
ist ("zwei Rollen, woertlich die zwei aus dem Auftrag").

Nicht `istLeitung` uebrigens: Das schlösse Spicy Media ein, und
genannt wurden zwei Rollen, nicht drei.

AN EINER STELLE, NICHT AN ZWEIEN. Der Server lehnt ab, und die
Oberflaeche bietet es gar nicht erst an -- beide fragen dieselbe
Funktion. Ein Knopf, den man sieht und der dann mit 404 antwortet,
ist schlimmer als keiner.

WAS ES NICHT BETRIFFT: Wer in einem BESTEHENDEN Kanal die Leute
aendert. "Aufmachen" beantwortet diese Frage nicht, also bleibt es
dort beim Alten. Falls das auch enger werden soll, sagt Filipe es.

Gemessen, alle vier Rollen durchgespielt:

  DogFather     darf        -> 201, Seite bietet es an
  rechte Hand   darf        -> 201, Seite bietet es an
  linke Hand    darf NICHT  -> 404, Seite bietet es nicht an
  ein Modi      darf NICHT  -> 404, Seite bietet es nicht an

Dazu die Gegenprobe, dass die Absage nichts verraet: Eine erfundene
und eine echte Kategorie sehen fuer die linke Hand gleich aus (404 /
404). Sonst waere aus der Fehlermeldung abzulesen, welche Kanaele es
gibt. 9 Messungen, 0 Befunde. pruef-chat-kanaele: 81 geprueft,
0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 23:25:42 +02:00
DogFatherGitandClaude Opus 5 f2f3586b5b Die Auswahlliste lag hinter dem Dialog
Filipe: "wenn ich auf zustaendigkeit druecke dan erscheint die auswahl
im hintergrund kontrollier das."

KONTROLLIERT, UND ER HAT RECHT. Gemessen im Browser: Der Kanal-Dialog
ist modal, die Liste hing an BODY, und ein Klick in ihre Mitte traf
DIALOG.dialog -- also den Dialog, nicht die Liste. Sie war da, sichtbar
war sie nicht, bedienbar erst recht nicht.

DER GRUND IST EINE EBENE, KEINE ZAHL. Ein Dialog aus showModal() liegt
in der TOP LAYER, einer Schicht ueber dem ganzen Dokument. Kein
z-index holt etwas aus dem Body davor; die Ebene entscheidet.

DER ERSTE VERSUCH WAR FALSCH, und das Bildschirmfoto hat es gezeigt:
Die Liste IN den Dialog zu haengen bringt sie zwar nach vorn -- und
laesst sie am unteren Rand abschneiden. `.dialog` traegt ein
clip-path fuer die abgeschraegte Ecke, und ein clip-path beschneidet
ALLE Nachkommen, auch "position: fixed". Die Liste endete mitten im
Wort "Events".

Damit ging beides nicht: draussen dahinter, drinnen beschnitten.

DER POPOVER IST GENAU DAFUER GEMACHT. Er hebt ein Element in dieselbe
Ebene wie den Dialog, ohne es zu seinem Kind zu machen: kein Beschnitt,
kein z-index-Wettlauf, und der Browser raeumt ihn beim Schliessen
selbst weg. Fehlt er im Browser, bleibt alles wie bisher -- ausserhalb
eines Dialogs aendert sich ohnehin nichts.

Die drei Zeilen in gate.css nehmen die Vorgaben zurueck, die ein
Popover mitbringt (Rahmen, Polster, und "inset: 0" plus "margin: auto",
was ihn in die Bildmitte stellt).

UND MEINE MESSUNG WAR ZUERST FALSCH, nicht der Code: Sie fragte
document.elementFromPoint und bekam DIALOG -- auch als die Liste
sichtbar darueber lag. Top-Layer-Elemente erfasst elementFromPoint
nicht verlaesslich. Gemessen wird jetzt, was ein Mensch tut: auf einen
Eintrag tippen und nachsehen, ob er ankommt. Er kommt an
("chat -> events"), und die Liste schliesst sich danach.

DAZU EINE EIGENE SCHLAMPEREI VON VORHIN: Die neuen Handy-Kacheln auf
"Eure Aufgaben" hatten .7rem = 11,2 px. Die Grenze des Hauses liegt
bei 11,5 px, und sie steht dort aus einem Grund -- Augenschonung ist
Pflicht, nicht Geschmack. pruef-css-klassen hat es gefangen ("43
Stellen unter 11,5 px, eine mehr als die Grundlinie 42"). Genau dafuer
zaehlt sie mit. Jetzt .75rem, und die Zahl steht wieder bei 42.

Gemessen: 7 Messungen am Dialog ohne Befund, css-klassen wieder in
Ordnung.

NICHT VON HEUTE ABEND, aber gefunden: pruef-chatkachel meldet "mit
allen 13 Toenen (2)". Seit Commit 7a674963 liegen die meisten Toene
auf einem Ring und nur der Rest im Gitter; die Pruefung zaehlt nur das
Gitter. Sie ist damit dauerhaft rot und gehoert nachgezogen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 23:22:05 +02:00
DogFatherGitandClaude Opus 5 cbaa529350 Eure Aufgaben: die Reihenfolge, in der man denkt
Filipe: "die seite eure aufgaben, ich will dass du die so krass
perfektionierst, ich will dass du die so krass uebersichtlich machst."

ERST GEMESSEN, DANN ANGEFASST. Mit sechs Leuten, so wie im echten
Team:

  Handy, Person gewaehlt      8281 px  = 10,6 Bildschirme
  Handy, Katalog offen       11636 px  = 14,9 Bildschirme

Und die Personenwahl -- der ERSTE Schritt -- begann am Handy bei
Bildschirm 5,3. Man scrollte an allem vorbei, um anzufangen; und was
man dabei ueberscrollte (Formular, Katalog), betraf genau die Person,
die man noch gar nicht gewaehlt hatte.

DER PLAN STAND SCHON DA. Im HTML steht seit dem 15.09. ein Kommentar:
"1. Die Ampel. 2. Die Personen. 3. Die Karte." Genau so war es gedacht
-- und genau so war es nicht mehr: Am 22.09. kam das Verteilen auf die
Seite, am 23.09. der Katalog, und beide sind davor gerutscht. Der
Kommentar beschrieb eine Ordnung, die es nicht mehr gab. Wieder eine
Bestandsliste, die altert, waehrend jemand weiterarbeitet.

Die Reihenfolge ist jetzt die, in der man denkt: Wie steht das Team?
-> Wen nehme ich mir vor? -> Was gebe ich ihm? -> Was liegt schon bei
ihm? -> Wie steht er da?

  Handy: Personenwahl beginnt bei Bildschirm 0,5 statt 5,3
  Rechner: bei 0,4 statt 2,0

DIE KACHELN AM HANDY kosteten 1176 px fuer sechs Leute -- anderthalb
Bildschirme nur fuer die Frage, wen man sich vornimmt. Grund war
"min-width: 260px", und der Grund DAFUER steht daneben: Die drei
Bilanz-Kaesten wurden sonst gequetscht. Das stimmt, solange sie
NEBENEINANDER stehen. Am Handy stehen sie jetzt untereinander, jeder
eine Zeile (Ziffer links, Wort rechts) -- so kommt die Kachel mit der
halben Bildschirmbreite aus und zwei passen nebeneinander: 618 px.

KEINE ZAHL FAELLT WEG. Wer verteilt, muss sehen, wer schon wie viel
hat; das ist der Zweck dieser Kaesten. Sie werden kleiner, nicht
weniger. Unter 380 px wieder eine Kachel je Zeile -- zwei haetten dort
je 145 px, und "verschieden gesehen" waere nicht mehr zu lesen.

DER SPRUNG BEIM KACHELKLICK IST WEG. Er war richtig, solange die Karte
direkt unter der Auswahl stand. Jetzt liegen Formular, Katalog und ihre
Aufgaben dazwischen -- ein Sprung zur Karte uebersaehe genau die drei
Dinge, die man nach der Wahl zuerst braucht. (Filipe, 15.09.: "die
seite soll sich nicht immer bewegen wenn ich auf was druecke.") Der
Sprung von der Talentseite bleibt, dort ist er gemeint.

UND DER CHAT KEHRT DAHIN ZURUECK, WO MAN AUFGEHOERT HAT. Die Linie
"Ab hier neu" gibt es seit Tagen -- sie wurde gezeichnet und sofort
ueberscrollt, weil der Verlauf beim Oeffnen ans Ende sprang. Wer nach
zwei Tagen zurueckkam, landete unten und suchte die Stelle, indem er
Uhrzeiten las. Jetzt springt er EINMAL beim Oeffnen dorthin, auf ein
Viertel Hoehe: darueber der Zusammenhang, darunter das Neue. Danach
gilt wieder die alte Regel, damit eine eintreffende Nachricht einen
nicht aus dem Lesen reisst.

Gemessen: entwicklung 48, entwicklung-kacheln 15, modi-katalog 133,
bewerbung-aufgaben 101, chat-optik -- alle ohne Befund.

NOCH NICHT FERTIG: Die Entwicklungskarte ist mit 5975 px weiterhin
72 % der Seite. Das ist der naechste Schritt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 23:07:10 +02:00
DogFatherGitandClaude Opus 5 5b7708fd10 Die Kopfleiste bleibt stehen -- jetzt auf allen Seiten
Filipe: "die leiste soll immer da fest stehen bleiben auch wenn man
runterscrollt, sonnst muss man immer wieder hoch scrollen um zurueck
zu koennen oder so."

GEMESSEN, BEVOR ETWAS ANGEFASST WURDE -- und das war noetig, denn der
Quelltext sagte das Gegenteil:

  entwicklung.html   sticky    klebt
  start.html         sticky    klebt
  aufgaben.html      relative  wandert weg
  chat.html          relative  wandert weg
  wissen.html        relative  wandert weg

Dieselbe Leiste, dasselbe CSS, zwei Verhalten. Der Unterschied war
eine Regel, die es gar nicht darauf angelegt hatte:

  body[data-ton] .kopfleiste { position: relative; }

Sie stand dort einzig, damit ein ::before darunter einen Bezugspunkt
bekommt -- die farbige Kante der Seite. Ihre Staerke ist (0,2,1),
genau wie die der Regel, die das Kleben setzt, und sie steht 8400
Zeilen spaeter. Bei gleicher Staerke gewinnt die spaetere.

WARUM MAN DAS IM QUELLTEXT NICHT SIEHT: "data-ton" haengt kopf.js
erst NACH dem Laden an den Body. Im HTML steht es nirgends. Welche
Seite betroffen ist, entscheidet sich also im Browser -- und nur dort
war es zu messen.

ERSATZLOS WEG, nicht ersetzt: "position: sticky" ist selbst ein
Bezugspunkt fuer absolut positionierte Kinder. Das ::before braucht
die Zeile nicht. pruef-kopfleiste-farbe bestaetigt das: 9 geprueft,
0 Fehler, die Kante traegt weiter die Farbe der Seite.

Dazu gilt die Regel jetzt fuer jedes Haus statt nur fuer "body.start"
-- anruf-probe.html traegt "body.haus" und war nie erfasst.

UND DAS SPRUNGZIEL. Wer von "Eure Aufgaben" auf eine Aufgabe tippt,
landet auf aufgaben.html#a123. Mit einer festklebenden Leiste liegt
das Ziel danach exakt darunter -- die Seite springt, und die gesuchte
Karte ist trotzdem nicht zu sehen. Das sieht aus wie ein kaputter
Link. "scroll-padding-top" haelt jetzt Abstand, und zwar aus der
gemessenen Hoehe (--kopf-hoehe, die kopf.js ohnehin fuehrt und in der
auch das Band der fremden Sicht steckt) -- keine feste Zahl: Am
Rechner sind es 118 px, auf einem 390er-Schirm 115.

DAS WAR DIE FUENFTE SPIELART DERSELBEN FALLE. Die vier anderen stehen
seit dem 07.09. im Kommentar daneben; jedes Mal hat eine Regel
"position" gesetzt, um etwas ganz anderes zu erreichen. Damit es
keine sechste gibt, misst pruef-kopf-messen ab jetzt das VERHALTEN:
Sie scrollt und sieht nach, wo die Leiste danach steht. Auf sechs
Seiten statt drei -- die drei neuen sind die, auf denen es gebrochen
war, plus eine ohne Farbton als Gegenprobe. Seiten, die zu kurz zum
Scrollen sind, melden "nicht nachsehbar" statt stillschweigend gruen
zu werden.

Gemessen: pruef-kopf-messen 42 Breiten (davon 14 Klebe-Messungen),
0 beanstandet. pruef-kopfleiste-farbe 9, pruef-ueberlappung 20
Seiten-Breiten-Paare, alle ohne Befund. Sprungziel auf Rechner und
Handy: 6 Messungen, 0 Befunde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 22:56:04 +02:00
DogFatherGitandClaude Opus 5 47cea0533b Die Personenreihe im Katalog kommt zurueck
Filipe: "ich hab gesagt du sollst die kachel von aufgabe in die eure
aufgabe kategorie machen und du machst sie ganz weg was soll das, da
ist scheisse wenn du einfach sachen machst die ich nicht verlange."

Er hat recht. Der Auftrag war, den Katalog zu VERSCHIEBEN. Ich habe
ihn verschoben und dabei die Personenreihe darin geloescht -- mit
einer Begruendung, die ich mir selbst gegeben habe. Verlangt war das
nicht.

Sie steht wieder vollstaendig da: die Ueberschrift "An wen", ein Knopf
je Person, daneben wie viel offen ist, und was ueberfaellig liegt
faellt auf ("1 spaet"). Dieselben Bausteine wie vorher, dieselbe
Gestaltung -- am CSS musste nichts geaendert werden, es stand noch da.

WAS SICH GEAENDERT HAT, IST NUR, WAS SIE SETZT. Frueher hatte sie eine
eigene Auswahl (kZiel), die nichts von der Seite wusste: Man konnte
oben den einen und unten den anderen waehlen, und dann standen zwei
Antworten auf einem Bildschirm. Auf "Aufgaben" fiel das nicht auf,
weil es dort oben gar keine Personenwahl gab. Auf "Eure Aufgaben"
waere es aufgefallen.

Jetzt ruft ein Tipp in der Reihe dieselbe Funktion wie ein Tipp auf
eine Kachel -- nicht etwas Aehnliches, sondern denselben Weg. Damit
KANN die Reihe nichts anderes meinen als die Kacheln. Zwei Stellen zum
Bedienen, eine Antwort.

Gemessen, in beide Richtungen: Ein Tipp in der Reihe markiert die
Kachel oben, und ein Tipp auf die Kachel markiert den Knopf in der
Reihe. Dazu Namen, Zahlen und die Spaet-Markierung. 14 Messungen,
0 Befunde. pruef-modi-katalog misst wieder drei Reihen statt zwei --
und neu auch die Kopplung selbst: 133 geprueft (vorher 129), 0 Fehler.

WAS ICH DARAUS MITNEHME: "Verschieben" heisst verschieben. Wenn mir
beim Umzug etwas auffaellt, das ich fuer ueberfluessig halte, ist das
eine Frage an Filipe und keine Entscheidung von mir.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 17:27:35 +02:00
DogFatherGitandClaude Opus 5 4454c6d064 Ein zweiter Druck legt nichts mehr doppelt an
Filipe: "diese aufgaben die da alle verteilt wurde, die hab ich nicht
gemacht also sollen die alle da weg, keine ahnung was du da gemacht
hast."

WAS WIRKLICH PASSIERT IST, steht in der Datenbank:

  2026-09-22T16:05:24   35 Aufgaben
  2026-09-22T16:05:25   21 Aufgaben
  2026-09-22T16:05:53   56 Aufgaben

Zweimal "Alle uebernehmen", 29 Sekunden auseinander, von Ghost. 112
Aufgaben an vier Modis -- 14 Vorlagen, jede doppelt, je 28 pro Person.
Alle noch offen, keine einzige angefasst.

Der eine Weg dorthin ist seit dem 22.09. zu: Ein Modi darf nicht mehr
verteilen (darfAufgabenVerteilen). Der andere war offen -- der zweite
Druck selbst. Wer verteilen darf, konnte den Massenknopf beliebig oft
betaetigen, und nichts hat ihn aufgehalten.

DIE SPERRE GAB ES IM HAUS SCHON, im Termin-Zweig derselben Route: "Was
es schon gibt, wird nicht doppelt angelegt." Beim Massenknopf fehlte
sie. Dass sie fehlte, ist nicht aufgefallen, weil niemand zweimal
drueckt -- bis es jemand tat.

NUR DER MASSENKNOPF, NICHT DER EINZELNE. Ein "Nochmal" an einer Karte
ist eine bewusste Entscheidung; manches macht man jede Woche neu, und
der Knopf sagt es sogar. Ein Griff, der zwoelf Aufgaben auf einmal
holt, ist etwas anderes: Ob er schon gedrueckt wurde, sieht man ihm
nicht an, und beim zweiten Mal richtet er zwoelffachen Schaden an.

UND "OFFEN" HEISST OFFEN. Was erledigt oder abgebrochen ist, darf
wiederkommen -- sonst liesse sich eine woechentliche Aufgabe nach dem
ersten Abhaken nie wieder holen. Gefragt wird nicht "gab es die schon
mal", sondern "liegt die gerade noch da".

Die Oberflaeche sagt es jetzt auch: "3 uebernommen. 9 lagen schon
offen da - die kommen nicht doppelt." In Gruen, nicht in Rot: Das ist
keine Stoerung, sondern die Auskunft, dass die Sperre gegriffen hat.
Ein Knopf, der weniger tut als er verspricht UND schweigt, ist
schlimmer als einer, der zu viel tut -- man drueckt ihn noch einmal.

Gemessen am nachgestellten Vorfall: erster Druck 12 Aufgaben, zweiter
Druck 0 statt 12 (waeren 24 geworden). Gegenproben: Abgehaktes laesst
sich neu holen, und der einzelne Nochmal-Knopf legt weiter an.
12 Messungen, 0 Befunde. pruef-modi-katalog 129 und
pruef-aufgaben-vorlagen bleiben gruen.

Die 112 Aufgaben selbst stehen noch in der Datenbank -- sie gehoert
dogiweb, ich habe dort nur Leserecht. Der Befehl dafuer geht an Filipe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 17:21:15 +02:00
DogFatherGitandClaude Opus 5 84e4048ab4 Der Aufgabenkatalog zieht dorthin, wo verteilt wird
Filipe: "das soll auch bitte nicht in der kategorie aufgaben sondern
eure aufgaben sein bitte. setzt das perfekt da rein und pass es
uebeertrieben krass rein."

Und das ist richtig: "Aufgaben" zeigt, WAS liegt. Verteilt wird seit
dem 22.09. auf "Eure Aufgaben" -- dort wird die Person gewaehlt, dort
steht das Formular, dort ihre Aufgaben. Der Katalog ist nichts anderes
als ein zweiter Weg zu derselben Handlung: 101 fertige Aufgaben statt
einer selbst getippten.

WAS DER ERSTE ANLAUF ZERSTOERT HAETTE. Der Block enthaelt ZWEI
Kataloge, und sie gehen an zwei verschiedene Personenkreise -- das
entscheidet der Server. Team Dogi bekommt die 101 Aufgaben in 14
Kategorien, die Agentur den Creator-Katalog (vier Bereiche, vier
Stufen). Ihn einfach herauszuschneiden und drueben hinzulegen haette
dem zweiten Katalog die Heimat genommen. Gemerkt hat das keine
Ueberlegung, sondern die Frage, wer die Zeile "ich.rolle === 'creator'"
eigentlich bedient -- pruef-aufgaben-vorlagen misst sie seit Tagen.

Deshalb eine gemeinsame Datei (vorlagenbrett.js) statt zweier
Abschriften: Die gemeinsamen Teile -- Abruf, Klappkopf, Uebernehmen --
gibt es weiter genau einmal, und jede Seite sagt beim Einrichten, ob
sie den Team- oder den Creator-Zweig zeigt. Fehlt ihr dabei eine
Angabe, sagt die Datei das in der Konsole, statt stumm nichts zu
zeichnen.

WAS DER UMZUG NEBENBEI LOESCHT: Drueben brauchte der Katalog eine
EIGENE Personenwahl, weil es dort keine gab -- eine dritte Knopfreihe
unter zwei anderen, und die Moeglichkeit, oben den einen und unten den
anderen zu waehlen. Hier ist die Person laengst gewaehlt, mitsamt ihren
Zahlen. Eine Auswahl statt zwei.

DREI DINGE, DIE ERST DADURCH AUFFIELEN:

"schon uebernommen" galt im Team-Katalog fuer JEDEN. Sobald irgendwer
eine Vorlage hatte, stand es an der Karte -- auch fuer alle anderen.
Auf einer Seite ohne Personenwahl fiel das kaum auf; hier waere es
offen falsch: Man waehlt Frida, und der Katalog behauptet, sie habe die
Aufgabe schon, weil Rieke sie hat. Der Creator-Zweig machte es von
Anfang an richtig. Und wer verteilt, bekommt ohne gewaehlte Person gar
keine Markierung mehr: "irgendwer hat sie" liest man als "brauche ich
nicht mehr zu vergeben" und ueberspringt, was dem Menschen vor einem
fehlt.

Der Katalog blieb fuer einen Modi GANZ weg. window.__ich kommt ueber
das Netz und ist beim ersten Zeichnen noch nicht da; ein stummes
"return" liess den Block dauerhaft verschwinden, weil niemand ein
zweites Mal zeichnet. Gefunden hat das kein Codelesen, sondern ein
Bildschirmfoto -- die Seite sah vollstaendig aus, nur ohne den Block.
Gewartet wird jetzt mit der Wartestelle des Hauses.

Und er markierte bei einem Modi nichts mehr: Die Aufgabenliste wurde
nur beim Personenwechsel geholt, und ein Modi waehlt nie jemanden.
Damit war die Sperre gegen das zweite Uebernehmen derselben Vorlage
weg. Jetzt gibt es einen Abrufweg fuer beide.

Der Knopf nennt den Namen ("An Rieke"), der Satz darueber auch. Statt
einer Wegbeschreibung zur Personenwahl steht ein Knopf, der hinfuehrt
-- "waehle oben" waere falsch, die Kacheln stehen weiter unten. Und
"auf dem Brett darunter" stimmt hier nicht mehr: Der Kopftext sagt
jetzt, WAS entsteht, nicht WO es landet.

Gemessen: pruef-modi-katalog 129 (vorher 125), pruef-modi-kategorien
29 (vorher 25 mit 3 Fehlern), pruef-aufgaben-vorlagen, pruef-struktur
und pruef-css-klassen alles in Ordnung. Dazu eine Abnahme ueber beide
Seiten und drei Rollen: 32 Messungen, 0 Befunde -- darunter die
Gegenprobe, dass Marinas uebernommene Aufgabe bei Frida NICHT als
uebernommen gilt.

Die 403-Zeilen in pruef-modi-kategorien waren ebenfalls eine Altlast:
Seit dem 22.09. legt im Team Dogi nur die Leitung an ("sie sich nicht
selber aufgaben geben"), die Pruefung tat es weiter als Modi. Sie misst
das jetzt -- samt der Gegenprobe, die es vorher nicht gab.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 17:14:01 +02:00
DogFatherGitandClaude Opus 5 290d7c8d88 Zwei Pruefungen massen einen Stand, den es nicht mehr gibt
Beide Befunde sind heute beim Umzug des Vorlagenkatalogs aufgefallen,
gehoeren aber nicht dazu -- sie lagen schon vorher da und haetten bei
jedem Lauf mitgemeldet, bis sie niemand mehr liest.

pruef-struktur las Server-Routen nur in doppelten Anfuehrungszeichen.
Wer eine Route in einer Schleife registriert, schreibt sie aber als
Template:

    for (const weg of ["annehmen", "ablehnen"])
      router.post(`/workspace/api/vorlagen/bewerbung/${weg}`, ...)

Diese Routen fehlten in der Liste, und die Aufrufe dorthin galten als
"Schnittstelle gibt es nicht" -- obwohl sie laufen. Die Erfassung der
AUFRUFE kannte alle drei Zeichen laengst; nur die der ROUTEN nicht.
Zwei Regeln fuer dieselbe Frage, und eine davon war aelter. Gemessen:
319 statt 315 Routen, und der Fehlalarm ist weg. Die Gegenproben
schlagen weiter an ("erfundene Schnittstelle wird als fehlend
erkannt").

pruef-aufgaben-vorlagen zaehlte KARTEN und erwartete +1. Seit das
Brett gleiche Aufgaben zu einer Sammelkarte zusammenfasst, stimmt das
nicht mehr -- die Pruefung legt kurz davor sieben Vorlagen derselben
Stufe an, und die neue wanderte in eine bestehende Karte. Sie meldete
"9 -> 9" und behauptete damit, das Uebernehmen sei kaputt; drei Zeilen
weiter erkannte sie dieselbe Aufgabe als "schon uebernommen" wieder.
Jetzt zaehlt sie Aufgaben: "9 -> 10 Aufgaben in 9 Karten".

Dieselbe Stelle gab es zweimal. In pruef-modi-katalog ist sie gestern
repariert worden -- hier nicht, weil ich nach dem ersten Fund nicht
weitergesucht habe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 17:13:35 +02:00
DogFatherGitandClaude Opus 5 b1319e3124 Aufgabenbrett: eine Karte ist ein Stueck Arbeit, keine Tabellenzeile
Filipe: "so wie alles gerade ist ist es zu wenig und zu viel zu
gleich". Die Zahl dahinter, an der echten Datenbank gemessen: 115
offene Aufgaben -- aber nur 17 verschiedene. Jede stand acht Mal da.

URSACHE, nicht Symptom: Am 22.09.2026 wurde dieselbe Vorlage zweimal
verteilt, nachgemessen zwischen 16:05:24 und 16:05:53. Zweimal
gedrueckt, weil beim ersten Mal scheinbar nichts passierte. 56 der
115 Karten sind exakte Doppelte.

WAS SICH AENDERT

Aufgaben mit gleichem Titel, gleicher Frist und gleicher Kategorie
stehen jetzt als EINE Karte da: "0 von 8", ein Balken, und die Leute
als Pillen in ihrer Statusfarbe. Wer sie doppelt hat, traegt x2.

Der Hinweis auf die Doppelten steht EINMAL ueber dem Brett, mit Zahl
-- nicht siebzehnmal an den Karten. Eine Warnung, die auf jeder Karte
steht, ist Tapete (Lehre vom 03.09.2026).

Die Spalten wachsen nach dem, was sie tragen: "Offen" mit 17 Karten
bekam vorher genauso viel Platz wie "Erledigt" mit einer -- beide
369 px, gemessen. Innerhalb der Spalte legen sich die Karten
nebeneinander, sobald Platz da ist (auto-fill, keine feste Spaltenzahl).

Das Vorlagenbrett steht oben, solange das Brett leer ist, und wandert
darunter, sobald etwas daliegt. Die urspruengliche Begruendung ("wer
ein leeres Brett hat, soll nicht daran vorbeiscrollen") gilt nur fuer
den leeren Fall.

Am Handy wird aus "Wer hat gerade was" eine wischbare Reihe statt
gestapelter Pillen, mit Randschattierung als Hinweis, dass es
weitergeht.

GEMESSEN (echte Datenlage: 17 Vorlagen, vier Leute, doppelt verteilt)

  Computer  46 077 px -> 2 445 px   (18,8-fach kuerzer)
  Handy     44 216 px -> 5 763 px   ( 7,7-fach kuerzer)
  Brett beginnt am Handy bei 798 statt 901 px -- die erste Aufgabe
  ist damit ohne Scrollen sichtbar.

DREI BEFUNDE NEBENBEI, ALLE VON MIR

1. team.css: Der Schreiben-Knopf auf der Team-Lage stand bei 42 px.
   Am 22.09. habe ich beim Kartenumbau das Polster von 10 auf 9 px
   gesenkt und ihn damit unter die Hausregel gedrueckt. Jetzt
   min-height statt Polsterrechnung -- die Hoehe haengt nicht mehr
   daran, ob jemand spaeter an der Schriftgroesse dreht.

2. chat.css: Die Knoepfe der Aufnahmeleiste standen bei 40 px, der
   Weg-Knopf der GIF-Kiste bei 28. Beide in der Nacht zum 23.09.
   gebaut. Die Leiste bekommt volle 44 px; der GIF-Knopf bleibt klein
   sichtbar und waechst nur in der TREFFERFLAECHE (28 + 2x8 = 44),
   und das nur am Finger -- mit der Maus zielt man genau, eine
   unsichtbar vergroesserte Flaeche waere dort eine Falle.

3. pruef-chat-anhaenge meldete "aus der Kiste genommen (1 uebrig)".
   Kein Codefehler: Die Pruefung setzte `window.confirm = () => true`,
   und heute frueh ist dort der Hausdialog an die Stelle getreten. Sie
   klickte, die Seite fragte, niemand antwortete. Genau der Fall, vor
   dem der Kopf von helfer-nachfrage.mjs seit dem 19.09. warnt -- zum
   zweiten Mal, an einer neuen Stelle. Jetzt ueber `bestaetige`, und
   damit prueft die Zeile ab sofort mit, DASS gefragt wird.

PRUEFUNGEN

pruef-modi-katalog zaehlte Karten und erwartete +1. Seit der
Gruppierung ist das die alte Anordnung, nicht die Sache: Sie zaehlt
jetzt AUFGABEN ueber data-id/data-ids und meldet "2 -> 3 Aufgaben in
2 Karten" -- damit ist beides belegt, das Anlegen und das
Zusammenfassen.

Alles gruen: aufgabenbrett 49, zuteilung 75, bewerbung-aufgaben 101,
modi-katalog 125, chat-anhaenge 109, chat-optik 56, tippziele 11,
teamlage-karten 39, sprung 43, textform 50, formulare 23,
css-klassen 33, zeichen 7, ueberlappung (20 Paare).
Handy-Rundgang: 220 Seitenaufrufe, 112 776 Elemente, 0 Befunde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 16:25:06 +02:00
DogFatherGitandClaude Opus 5 1851d447c3 Der Raumname heilt sich -- und jetzt steht die Gegenprobe dafuer
Nach dem Ausliefern am echten Server nachgesehen: Die Zeile in der
Datenbank hiess weiter "Der Treff". Kein Fehler -- treffAngleichen()
laeuft beim Abrufen der Gespraechsliste, und seit dem Neustart hatte
noch niemand den Chat offen. Sie heilt sich beim ersten Aufruf, und
zwar VOR dem Auslesen der Liste: Der Erste, der hinsieht, sieht schon
den neuen Namen.

Nur war das bis eben eine Herleitung und keine Messung.

pruef-erwaehnung traegt den alten Namen jetzt absichtlich wieder ein,
BEVOR die Gespraechsliste geladen wird, und prueft danach, dass er
weg ist. Ohne diesen Schritt waere die Zeile auch dann gruen, wenn
der Abgleich den Namen gar nicht anfasst -- der Raum wird im Test ja
neu angelegt und traegt den richtigen Namen von Anfang an. Genau so
sieht eine Pruefung aus, die immer bestaetigt.

pruef-erwaehnung: 123 (vorher 122).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 14:31:45 +02:00
DogFatherGitandClaude Opus 5 7a6749630c Das Rudel meint den ganzen Raum -- und die Kachelfarbe wird ein Ring
Zwei Auftraege vom 23.09.2026.

SCREEN 1: "da steht links immer noch der treff anstatt das rudel"

Und er hatte recht, auf eine Art, die niemand sehen konnte:
TREFF_NAME stand schon seit der Umbenennung auf "Das Rudel". Nur
setzt treffRaumId() den Namen ausschliesslich BEIM ANLEGEN -- der
Raum existierte laengst, also blieb die Zeile in der Datenbank auf
"Der Treff" stehen. Im Code das eine, auf dem Bildschirm das andere.

Dieselbe Falle stand direkt nebenan schon beschrieben ("drei Stellen,
von denen die dritte vergessen wird") -- die Vorsorge galt aber nur
fuer die Teilnehmer, nicht fuer den Namen. Eine halbe Selbstheilung
heilt die andere Haelfte nicht. Jetzt gleicht treffAngleichen() auch
den Namen ab; eine kuenftige Umbenennung ist wieder eine Zeile.
(IS NOT statt !=: Bei NULL ergaebe != in SQLite NULL, und die Zeile
bliebe unveraendert liegen.)

"und wenn wir da im chat @rudel machen will ich dass jeder in dem
chat markiert wird. nicht nur team ... und sehr wichtig ich rede nur
von dem chat wo die ganze community auch drin ist."

Bis heute erreichte der Ruf ueberall nur Team Dogi. Die Begruendung
stand im Code und war nicht falsch -- im Rudel-Raum sitzt die
Community. Genau das will Filipe jetzt, und zwar nur dort:

  im Rudel-Raum   -> alle, die drin sind
  ueberall sonst  -> Team Dogi, unveraendert

Was die alte Sorge entschaerft: RUFEN darf weiterhin nur Team Dogi --
kein Zuschauer kann alle wecken. Und die Nachtruhe gilt dort ohnehin.

darf_rudel folgt derselben Frage. Sonst entstuende ein stiller
Widerspruch: Ein Modi mit neun Zuschauern und ohne zweites
Teammitglied traefe mit @rudel neun Leute -- der Vorschlag beim
Tippen waere aber ausgeblendet. Die Funktion gaebe es, und niemand
faende sie.

Das Schild sagt jetzt die Wahrheit: "alle in diesem Chat" statt
"alle im Team". Stuende dort weiter das alte, waere es im Rudel-Raum
gelogen -- und zwar nach unten, also in die Richtung, in der man
leichtfertig drueckt.

Gegenprobe in pruef-erwaehnung: In der Testgruppe sitzen DogFather
und zwei Scouts; ein @rudel dort ruft NIEMANDEN. Waere die Regel
versehentlich im ganzen Haus aktiv, waeren die Scouts markiert.
"sonst nichts anfassen" ist damit gemessen, nicht versprochen.

SCREEN 2: "so eine art diagramm, wo man mit einem kreis herum gehen
kann und die farbe ganz genau selber auswaehlen kann"

Der Haken daran ist nicht die Optik. Die zwoelf Kacheln waren
GERECHNET, damit niemand sich unlesbar machen kann -- alle auf
derselben Leuchtdichte. Ein Farbkreis, der einfach den Farbton dreht,
wirft das weg: Ein gesaettigtes Gelb ist um ein Vielfaches heller als
ein gesaettigtes Blau, und helle Schrift ist darauf nicht mehr zu
lesen.

Der Ring ist deshalb KEINE neue Rechnung, sondern dieselbe in 360
Schritten statt in zwoelf. tools/chat-kacheln-rechnen.mjs --kreis
schreibt server/chat-kreis.js; buntest() und die Kontrastpruefung
darin gelten unveraendert. Ergebnis: ein Ring gleicher Helligkeit --
kein blendendes Gelb, kein abgesoffenes Blau. Das sieht ruhiger aus
als der uebliche Farbkreis, und genau das ist der Punkt.

Der Browser rechnet nichts. Er bekommt die 360 fertigen Farben und
legt sie in dieselbe Tabelle wie die Kacheln -- ab da ist "ton-214"
ein Schluessel wie "veilchen", und jede Stelle, die eine Farbe
nachschlaegt, funktioniert unveraendert.

Welche Kacheln neben dem Ring bleiben, wird ABGELEITET statt
aufgezaehlt: Grau hat keinen Farbton, Babyblau ist die eine helle mit
eigener Schrift. Nachgemessen liegen die elf bunten zwischen 0,0 und
2,4 von ihrer Ringfarbe entfernt, Grau bei 75,4 und Babyblau bei
192,9 -- zwischen 2,4 und 75 ist so viel Luft, dass die Schwelle
nicht knapp ist.

Gespeichert wird erst beim Loslassen. Wer einmal um den Ring fuehrt,
erzeugte sonst dreihundert Anfragen.

Gemessen (pruef-chat-neu, jetzt 32 Pruefungen, als Modi auf crew. mit
dem Finger): 265 px gross, aus 361 Farben gemalt, touch-action none
(sonst schiebt das Handy die Seite weg statt zu drehen), Drehen auf
drei Uhr ergibt genau Winkel 90, die Mitte zeigt exakt #675102,
vorgelesen als "Goldbraun, 90 Grad", in der Datenbank steht ton-90,
Pfeiltaste dreht ein Grad weiter. Und das eigentliche Versprechen:
alle 360 Toene tragen die Schrift der Blase, knappster Faktor 1,000.

Dabei zwei eigene Fehler, beide aufgeschrieben: Der erste Anlauf
wartete 30 Sekunden auf den Farbknopf -- am Handy weicht die Spalte
mit den Gespraechen zur Seite, sobald ein Chat offen ist. "Ist im
HTML" und "ist erreichbar" sind zwei Aussagen. Und die Schriftfarben
wurden an der falschen Klasse gemessen, was einen roten Haken an
einer heilen Stelle ergab.

Ausserdem: Das native confirm() beim Herausnehmen eines GIFs ist
weg -- meine eigene Abkuerzung vom Morgen. Gemeldet hat es
pruef-nachfrage, allerdings erst, nachdem der verlorene Backslash in
derselben Datei repariert war.

Zahlen: pruef-erwaehnung 122 (vorher 119), pruef-chat-neu 32
(vorher 19), pruef-nachfrage 46 bestanden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 14:30:02 +02:00
DogFatherGitandClaude Opus 5 a9d920e7d0 Vier stillgelegte Pruefungen, zwei kaputte Zeichen -- und die Wache dagegen
Gefunden beim Vorbereiten der KLIPY-Anbindung, nicht gesucht.

DER VERLORENE BACKSLASH
In fuenf Dateien stand in einem Suchmuster das BYTE 0x08 statt der
zwei Zeichen \ und b. Gemeint war die Wortgrenze; 0x08 ist das
Rueckschritt-Zeichen und kommt in keinem Text vor. Gemessen:

  /<0x08>modis?<0x08>/i.test("Die Modis sind da")  ->  false
  /\bmodis?\b/i        .test("Die Modis sind da")  ->  true

Folgen, je Stelle:

  pruef-nachwuchs         Das Muster stand in einer VERNEINUNG. Die
                          Zeile lautete damit ok(!false) -- dauerhaft
                          gruen, ohne etwas zu messen. Ausgerechnet
                          die Zeile, die das Durchsickern des
                          Rollennamens verhindern soll.
  pruef-personen-formular dasselbe Muster, dieselbe Verneinung
  pruef-nachfrage         hatDialogMitFeld war immer falsch. Seiten
                          mit einem Formular-Dialog galten als "totes
                          Gewicht" -- der Kommentar direkt darueber
                          warnt woertlich vor genau diesem Schaden.
  pruef-entwicklung       zwei von drei Alternativen tot
  workspace-treff.js      nur ein Kommentar, aber unlesbar

ZWEI KAPUTTE ZEICHEN, BEIDE SICHTBAR
  content: "<0x15>C9<0x00>A0"  in chat.css. Gemeint war U+25C9 und
  ein geschuetztes Leerzeichen. Live stand woertlich "C9 A0" vor
  jedem hervorgehobenen @rudel -- am echten Server nachgemessen.

  content: "¹3"  in chat.css UND entwicklung.css. Gemeint war ein
  Haken. Auf der gewaehlten Kachel stand "¹3"; zu sehen in Filipes
  Bildschirmfoto.

Repariert wird mit der Escape-Schreibweise ("\2713"), nicht mit dem
Zeichen selbst: Sie besteht nur aus ASCII und ueberlebt jede
Kodierung.

WAS DIESE FEHLERART BESONDERS MACHT
Niemand sieht sie beim Lesen. Der erste war committet, ausgeliefert
und lag live -- und als ich in der Datei danach suchte, meldete grep
"Binary file matches" und zeigte die Zeile gar nicht erst an. Wer den
Unterschied durchsieht, liest content: "C9 A0" und denkt sich nichts.

Deshalb neu: server/pruef-zeichen.mjs (7 Pruefungen). Sie sucht rohe
Steuerzeichen in allen ausgelieferten und allen Serverdateien, dazu
Ersatzzeichen und Kodierungstruemmer in CSS-content-Angaben. Mit
Gegenprobe in beide Richtungen -- sie weist an einer selbst gebauten
Datei nach, dass sie anschlaegt, UND dass sie bei einer sauberen
schweigt.

Die erste Fassung der Regel war zu weit: Sie meldete acht KORREKTE
Zeichen (✓, ↯, ↻, „, ⚠). Eine Warnung, die immer kommt, ist keine
Warnung mehr. Die engere Regel kommt aus dem Befund selbst -- der
Latin-1-Block U+0080..U+00BF, in dem echte Typografie nie steht.
Nachgemessen ueber alle 203 content-Angaben im Haus: keine einzige
benutzt ihn.

GEHEIMNISSE STEHEN NICHT MEHR IM PROTOKOLL
einstellungSetzen() schrieb immer Name UND Wert. Nachgemessen in der
echten Datenbank: kopie_schluessel steht vollstaendig drin,
vapid_paar wurde bei 120 Zeichen abgeschnitten -- kurz VOR dem
privaten Teil. Dass der heil blieb, lag an einer Laengengrenze, nicht
an einer Absicht. Keine offene Tuer (das Protokoll liegt hinter
nurAdmin), aber der Wert wandert in jede Sicherung.

Es ist eine REGEL und keine Liste: Wer eine Einstellung so benennt,
meint ein Geheimnis. Stehen bleibt, DASS sich etwas geaendert hat,
wann und durch wen -- nur der Wert fehlt.

EINE VERALTETE PRUEFUNG, UMGEDREHT STATT GELOESCHT
pruef-nachwuchs verlangte, dass die rechte Hand keine Zugaenge
anlegen kann. Das war bis zum 22.09. richtig; dann hat Filipe es
umgedreht ("damit sie das auch machen kann wenn er live ist"). Die
Pruefung war seither rot, ohne dass es auffiel -- sie lief nicht.
Jetzt prueft sie beides: dass die rechte Hand es darf UND dass die
Grenzen stehen (sperren 404, Protokoll 404). Eine Erlaubnis ohne
Grenze ist keine Entscheidung, sondern ein Loch.

Und tools/nachtlauf.mjs wird nachgetragen -- bisher unversioniert.

Zahlen: pruef-nachwuchs 260, pruef-entwicklung 48,
pruef-personen-formular 43, pruef-zeichen 7 (neu), pruef-ports 8.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 14:29:32 +02:00
DogFatherGitandClaude Opus 5 c0d2896419 pruef-chat-neu: die drei neuen Sachen am Stueck, als Modi, auf dem Handy
Jedes Stueck war geprueft -- und jedes in einer anderen Lage als der
echten:

    pruef-chat-anhaenge   Sprachnachricht und GIF, aber als DogFather
                          auf der AGENTURadresse, mit der Maus
    pruef-erwaehnung      der Rudel-Ruf, aber gegen den Server

Der Fall, den Filipe wirklich hat -- ein MODI auf crew., mit dem
FINGER, und ein zweiter Mensch, der es bekommen soll -- war nie am
Stueck gemessen. Genau in solchen Luecken sitzen die Fehler, die
niemand sieht: Jeder Einzeltest ist gruen, und zusammen geht es
trotzdem nicht.

ZWEI BROWSER, ZWEI MENSCHEN. Eine Sprachnachricht, die nur beim
Absender im Verlauf steht, ist keine. Jede der drei Proben wartet
deshalb darauf, dass die ZWEITE Person sie von selbst bekommt -- ohne
Neuladen.

19 Pruefungen, 0 Fehler:
  * Sprachnachricht: Knopf da, Zeit laeuft, Blase mit Laenge, passt auf
    390 px, kommt bei der zweiten Modi an
  * GIF-Kiste: passt auf den Bildschirm, sagt was zu tun ist, GIF
    hineinlegen, verschicken, ankommen -- und die zweite Modi sieht
    dasselbe GIF in IHRER Kiste (sie gehoert dem Rudel)
  * Rudel-Ruf: das @ oeffnet die Liste, "rudel" steht oben mit "alle im
    Team" daneben, 44 px hoch, im Bild; die Nachricht kommt an, der Ruf
    leuchtet beim Empfaenger (Gewicht 700), und in der Datenbank stehen
    genau die Richtigen -- die andere Modi und DogFather, nicht der
    Rufer selbst

ZWEI EIGENE FEHLER BEIM BAUEN, beide in der Datei aufgeschrieben, weil
sie sich wiederholen werden:

  (1) OHNE NOTBREMSE. Der erste Lauf blieb stehen und sah von aussen
      aus wie "laeuft noch" -- ich musste ihn von Hand abbrechen. Ein
      Werkzeug, das haengt, ist schlimmer als eines, das scheitert;
      das steht seit dem 06.09. in den Hausregeln, und ich habe es
      beim Bauen eines Wegwerf-Werkzeugs trotzdem weggelassen.

  (2) MIT ENTER ABGESCHICKT. Auf einem Beruehrgeraet schickt Enter
      ABSICHTLICH nicht ab -- sonst kaeme man nie zu einer zweiten
      Zeile. Die Messung meldete daraufhin "kommt nicht an"; in
      Wahrheit war nie etwas abgeschickt worden. Dasselbe Muster wie
      beim `pointer: coarse` heute frueh: Wer im falschen
      Geraeteprofil misst, misst ein anderes Programm.

Die Datei ist aus einem Wegwerf-Werkzeug entstanden. Sie bleibt, weil
der Weg, den sie geht, sonst von keiner Pruefung gegangen wird.

pruef-ports: 8 von 8 -- die neue Datei verschiebt die Portnummern
aller spaeteren, und das haelt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 12:23:27 +02:00
DogFatherGitandClaude Opus 5 bff7c6ce14 Chat: die Schreibzeile auf dem Handy -- Feld 130 -> 278 px
Filipe schreibt vom Handy. In der Schreibzeile stehen seit heute Nacht
SECHS Dinge: Bueroklammer, Mikrofon, GIF, Emoji, Schreibfeld, Senden --
das Mikrofon und das GIF habe ich selbst dazugestellt.

GEMESSEN, BEVOR ICH ETWAS ANGEFASST HABE (mit echtem Finger, weil
`pointer: coarse` sonst gar nicht greift):

    320 px   Feld 164
    390 px   Feld 130  -- und "Senden" ALLEIN auf einer eigenen Zeile
    412 px   Feld 151  -- dito

Das Feld lag auf seiner Untergrenze von 8 rem. Kaputt war nichts --
nichts ueberlappte, nichts war zu klein --, aber man sah beim Tippen
etwa zwoelf Zeichen, und der Knopf, der die Nachricht wegschickt, war
weiter vom Text entfernt als die Bueroklammer.

Das ist derselbe Fehler wie am 06.09.2026 in anderer Gestalt: Damals
kam ein sechstes Element in die Kopfleiste, und bei 412 px lag ein
Knopf ueber dem anderen.

ZWEI GRUPPEN STATT SECHS EINZELTEILE
------------------------------------
  chat__werkzeuge     Bueroklammer, Mikrofon, GIF, Emoji
  chat__schreibzeile  Feld und Senden

Damit bricht die Zeile an der richtigen Stelle: Die Werkzeuge wandern
GEMEINSAM nach oben, Feld und Senden bleiben zusammen. Und ein siebtes
Werkzeug laesst kuenftig die Gruppe wachsen, nicht das Feld schrumpfen
-- das ist der Unterschied zwischen einer Regel und einer Zahl, die man
beim naechsten Knopf neu suchen muss.

DER EMOJI-KNOPF IST ZU DEN WERKZEUGEN GEWANDERT. Er sass neben
"Senden", und auf dem Handy landeten damit Emoji und Senden gemeinsam
unten links. Ein Emoji ist dasselbe wie eine Bueroklammer: etwas, das
man in den Text einfuegt. Senden ist das Gegenteil.

NACHHER:
    320 px   Feld 214      390 px   Feld 278
    412 px   Feld 299     1280 px   Feld 560

Auf dem Handy drei Zeilen (Werkzeuge / F K U S / Feld+Senden), am
Rechner alles nebeneinander.

DIE 10 rem SIND GEMESSEN, NICHT GESCHAETZT
------------------------------------------
Durchgespielt wurden 8, 10, 11, 12 und 13 rem auf 320, 390 und 412 px.
Ab 11 rem kommt auf 320 px eine VIERTE Zeile dazu -- also schlechter
dort, wo der Platz ohnehin am knappsten ist. 10 rem verbessert 390 und
412 deutlich, ohne 320 zu verschlechtern. Die Messreihe steht im
Kommentar; wer daran dreht, misst bitte wieder nach.

EIN ZWISCHENSTAND, DEN ICH VERWORFEN HABE
-----------------------------------------
Der erste Versuch gruppierte nur Feld+Senden und liess Emoji stehen.
Gemessen: Feld 160 statt 180 -- schlechter als der Zustand davor. Ich
habe ihn zurueckgenommen, statt ihn schoenzureden. Was ich nicht
messen kann, liefere ich nicht aus.

GEPRUEFT
--------
pruef-chat-optik: die Schreibzeile ist jetzt Teil der Pruefung.
Breite des Feldes, Senden neben dem Feld, nichts ueberlappt, alles am
Daumen treffbar, kein Querscrollen -- und am Rechner das Gegenteil:
Dort MUESSEN die Werkzeuge daneben stehen, sonst waere die Zeile
unnoetig hoch.

GEGENPROBE mit der alten Fassung: 5 Zeilen werden rot, darunter genau
die beiden Symptome von oben (Feld 130, Senden eine Zeile tiefer).

UND ZWEI EIGENE FEHLER IN DER PRUEFUNG, BEIDE VON DER GEGENPROBE
GEFUNDEN:

  * Sie mass mit einem SCOUT -- und der bekommt Mikrofon und GIF gar
    nicht zu sehen. Gemessen wurde eine Zeile mit zwei Dingen darin,
    waehrend der gefaehrliche Fall der mit vier ist. Aufgefallen, weil
    die Gegenprobe 178 px meldete und meine Handmessung 130: zwei
    Zahlen fuer dieselbe Sache.
  * Eine Zeile war gruen mit `undefined`: Es gab die Gruppe nicht,
    `y` war undefiniert, und `(undefined || 0) < 834` ist wahr. Ein
    gruener Haken, der nichts angesehen hat -- genau die Sorte, vor
    der die Hausregeln warnen.

pruef-chat, pruef-erwaehnung (119), pruef-chat-anhaenge (109):
unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 12:00:32 +02:00
DogFatherGitandClaude Opus 5 036f30454c Vorlagenbrett: was wartet, steht jetzt ganz oben -- quer ueber alle Kategorien
EIN LOCH, DAS ICH SELBST GEBAUT HABE
------------------------------------
Die Bewerbungen stehen an ihrer Karte, und das ist richtig: Man
entscheidet ueber eine bestimmte Aufgabe, und ihr Text ist die halbe
Auskunft.

Nur steht die Karte in EINER von vierzehn Kategorien. Bewirbt sich
Frida unter "Wachstum" und DogFather oeffnet wie immer
"Chat-Moderation", sieht er nichts -- die Bewerbung ist da, das Brett
ist offen, und trotzdem findet er sie nie.

Die Benachrichtigung von heute frueh hilft, aber sie ist ein Moment:
Wer sie wegwischt, hat keinen zweiten Weg mehr. Ein Brett, auf dem
etwas wartet, muss das selbst sagen koennen.

Jetzt steht ganz oben, ueber den Kategorie-Reitern: "Eine Bewerbung
wartet auf deine Antwort: Marina · Zehn Neue fragen, wie sie
hergefunden haben". Ein Tippen springt in die richtige Kategorie, zur
richtigen Karte, und hebt sie zwei Sekunden hervor.

DER SPRUNG STELLT AUCH DIE STUFE ZURUECK. Ohne das landet man in der
richtigen Kategorie und sieht trotzdem nichts, weil der Stufenfilter
die Karte gerade ausblendet -- eine Reise ins Nichts ist schlimmer als
kein Knopf.

ES DIENT BEIDEN SEITEN, und deshalb steht es nur einmal da: Wer
entscheidet, liest "wartet auf deine Antwort"; wer sich beworben hat,
liest "du hast dich beworben". Der Server schickt ohnehin jedem nur,
was ihn angeht.

UND WIEDER: ERST STAND DIE ABSICHT NUR IM KOMMENTAR
----------------------------------------------------
Im Kommentar stand "ES STEHT GANZ OBEN, ueber den Kategorie-Reitern".
Der Code haengte es darunter -- gesehen auf dem Bildschirmfoto, nicht
beim Lesen. Das ist heute das zweite Mal (nach "gleiche Mittel,
gleiche Staerke" bei den Handkarten). Ein Kommentar, der eine Absicht
beschreibt, erfuellt sie nicht; ich schreibe sie offenbar gern auf,
bevor ich sie baue.

VORHER GEMESSEN, NICHT VERMUTET
-------------------------------
Rundgang als Modi, 390 px, ueber alle 27 Kacheln der Startseite -- die
Liste aus den Kacheln GELESEN, nicht aufgeschrieben. Ergebnis: kein
Querscrollen, keine zu kleinen Ziele, kein Text auf Text, keine
Konsolenfehler. 27 von 27 sauber.

Dabei sah ich im Chat einen magentafarbenen Kasten ohne Beschriftung
und hielt ihn fuer kaputt. Nachgemessen mit echtem Finger
(hasTouch): 44x44-Knopf, 36x36-Farbprobe, quadratisch -- und am Laptop
30x30 / 22x22, ebenfalls quadratisch. Der schmale Balken entstand nur
in meinem Messaufbau (390 px OHNE Beruehrung), also in einer Lage, die
kein Geraet hat. Kein Fehler, und ich habe nichts "repariert", was
nicht kaputt war.

GEPRUEFT
--------
pruef-modi-katalog: 125 Pruefungen, 0 Fehler (vorher 116).

Gemessen wird genau der Fall, um den es geht: eine Bewerbung in einer
Kategorie, die gerade NICHT gewaehlt ist. Dazu der Sprung (landet auf
der richtigen Karte, und dort stehen Annehmen und Ablehnen), die
Daumengroesse (40 px) und der Wortlaut.

MIT GEGENPROBE, und die ist der Kern: Wartet nichts, steht auch nichts
da. Ohne sie bewiese alles darueber nur, dass das Band immer dasteht
-- und ein Hinweis, der immer da ist, wird ueberlesen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 11:32:25 +02:00
DogFatherGitandClaude Opus 5 1f2a4d335e Eine Bewerbung, die niemand sieht, ist keine
Beim Weiterarbeiten am Vorlagenbrett nachgemessen und gefunden:
`benachrichtige` kam in workspace-zuteilung.js KEIN EINZIGES MAL vor,
in workspace-vorlagen.js auch nicht.

Beide Bewerbungswege waren gebaut, beide funktionierten -- und beide
waren stumm:

  * Bewirbt sich Frida, erfaehrt DogFather es nur, wenn er von sich
    aus das Brett aufmacht.
  * Antwortet er, erfaehrt Frida es nur, wenn SIE von sich aus
    nachsieht.

Das ist keine Kleinigkeit, das ist die Funktion. Wer sich bewirbt,
wartet -- und Warten ohne Rueckmeldung fuehlt sich nach zwei Tagen an
wie "interessiert keinen". Genau das soll eine Bewerbung verhindern.

WER ES ERFAEHRT -- ABGELEITET, NICHT AUFGEZAEHLT
------------------------------------------------
Die naheliegende Zeile waere `rolle IN ('admin','hand')` gewesen; so
steht sie in workspace-hilfe.js. Das ist eine Abschrift, und
Abschriften altern: Kaeme morgen eine Rolle dazu, die entscheiden
darf, bekaeme sie keine einzige Meldung -- und niemand merkte es, weil
ja alles funktioniert.

Gefragt wird deshalb die Regel selbst (entscheidetUeberAufgaben),
Person fuer Person. Und zusaetzlich darfSchreibenMit: Wer den Bewerber
gar nicht sehen darf, bekommt auch keine Meldung ueber ihn. Das ist
keine Vorsicht um ihrer selbst willen -- ohne diese Zeile erfuehre die
Agentur ueber eine Push-Nachricht, dass es Team Dogi ueberhaupt gibt.

Gemessen: Die Bewerbung eines Modis erreicht genau zwei Leute
(admin, hand) von sechs Aktiven. Nicht die linke Hand (sie entscheidet
hier nicht mit), niemand aus dem anderen Haus, und nicht der Bewerber
selbst.

ZWEI SCHALTER, ZWEI ENTSCHEIDUNGEN
----------------------------------
"bewerbung_neu" trifft den, der antwortet -- an einem lebhaften Tag
mehrfach, das kann man stumm stellen wollen. "bewerbung_antwort"
trifft den, der wartet; sie kommt einmal, und niemand will sie stumm
stellen. Eine gemeinsame Art hiesse: beides zusammen abschalten oder
beides zusammen ertragen. Dieselbe Ueberlegung wie beim Chat
(Nachricht / Erwaehnung).

Beide von sich aus an. Keine Ausnahme von der Ruhezeit: Eine Bewerbung
wartet, ein Anruf nicht.

DIE NOTIZ STEHT IN DER MELDUNG
------------------------------
Filipe hat sie ausdruecklich verlangt ("mit einem text als notiz").
Sie erst zu verlangen und dann an genau der Stelle zu verschweigen, an
der man sie liest, waere die halbe Funktion. Und das Ergebnis steht im
TITEL -- "angenommen" oder "diesmal nicht" -- damit man es lesen kann,
ohne zu oeffnen. Auch die gute Nachricht.

Der Wortlaut steht in zwei reinen Funktionen (bewerbungText,
antwortText), exportiert, damit eine Pruefung sie lesen kann, ohne
einen Push-Dienst nachzubauen. Genau an so einer Stelle steckte am
18.09. der Fehler "Nachricht von [object Object]", der von aussen
nicht messbar war.

EINE STELLE FUER BEIDE WEGE
---------------------------
workspace-bewerbung-melden.js. Zwei Fassungen waeren zwei
Gelegenheiten, dass eine davon die Ruhezeit, die Abschaltbarkeit oder
die Haeusertrennung vergisst -- und dieselbe Person laese zweimal
etwas Verschiedenes ueber denselben Vorgang.

Die Meldung wird NICHT abgewartet (`void`): Ob sie durchgeht, haengt
am Push-Dienst, an der Ruhezeit und an den Einstellungen des
Empfaengers. Nichts davon darf entscheiden, ob die Bewerbung
gespeichert ist -- die ist es laengst.

NOCH EINE ROTE PRUEFUNG, DIE NIEMAND GESEHEN HAT
-------------------------------------------------
pruef-push-ziel meldete: "aber nicht auf eine Seite, die es fuer ihn
nicht gibt (/workspace/calls.html)". Das sah aus wie ein Befund und
war eine erfuellte Bestellung -- Filipe hatte am 22.09. genau das
Gegenteil bestellt ("jeder der einen kalender hat soll auch sowas
haben"). Nachgemessen: Modi, rechte und linke Hand haben je eine
Calls-Kachel.

Die Pruefung steht jetzt andersherum: Die Calls-Seite MUSS stehen
bleiben. Dieselbe Zeile schuetzt damit das, was sie vorher verboten
hat -- und wird rot, wenn die Kachel je wieder verschwindet. Das
Umlenken selbst bleibt geprueft (Scouting, zweimal).

Das ist die DRITTE stille rote Pruefung an einem Tag (nach
pruef-modi-wortleck und pruef-zuteilung). Die Frage an Filipe, ob ein
naechtlicher Lauf sie selbst anstossen soll, steht in der Vault-Notiz
und wird nicht von mir allein entschieden.

GEPRUEFT
--------
pruef-modi-katalog: 116 Pruefungen, 0 Fehler (vorher 95).
  Neu: die beiden Schalter, wer es erfaehrt (samt Gegenprobe, dass es
  nicht einfach alle sind: 2 von 6), und der Wortlaut an acht Proben.
  Dabei war meine eigene erste Messung falsch -- sie erwartete eine
  Kuerzung bei 50 Zeichen, die nur gilt, wenn eine Notiz danebensteht.
  Steht als Begruendung in der Pruefung.
pruef-push-ziel: 11 von 11 (vorher 1 Fehler).
pruef-zuteilung, pruef-push, pruef-push-weg: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 11:16:30 +02:00
DogFatherGitandClaude Opus 5 6862bba437 pruef-zuteilung stuerzte ab -- an einer Entscheidung vom 22.09.
Beim Nachsehen im Umfeld des Vorlagenbretts gefunden: Die Pruefung
lief gar nicht mehr durch. Sie wartete dreissig Sekunden auf
"#neu-oeffnen" und brach dann ab -- und pruefte damit auch alles
danach nicht mehr.

Der Knopf ist nicht kaputt, er ist WEG -- und zwar auf Ansage:

    Filipe, 22.09.2026: "dieser button kann da jetzt doch endlich
    verschwinden, auf dieser seite sollen ja keine aufgaben mehr
    verteilt werden."

Verteilt wird seither auf der Entwicklungsseite. Die Pruefung ist mit
umgezogen und misst dort dasselbe wie vorher: Stehen Leute zur
Auswahl, und erscheint die Frage "wie soll das laufen" erst, wenn es
wirklich mehrere sind? (4 zur Wahl, vorher verborgen, danach sichtbar.)

DAS IST DIE DRITTE SORTE FEHLER aus den Hausregeln -- kein
uebersprungener Test und kein gruener, der das Falsche prueft, sondern
einer, der seine VORAUSSETZUNG verloren hat. Von aussen sah er aus wie
ein Befund am Programm; er war einer an der Pruefung.

UND DASS DER KNOPF DORT WEG BLEIBT, WIRD JETZT MITGEPRUEFT. Sonst
koennte er stillschweigend zurueckkommen, und Filipes Ansage waere
rueckgaengig, ohne dass es jemand merkt. Genau so entstehen die
Funktionen, von denen niemand weiss, wann sie wiedergekommen sind.

Beim Umbau lief ich selbst in die naechste Stufe desselben Fehlers:
Der erste Anlauf mass null Kaestchen und meldete vier rote Zeilen. Das
Formular startet zugeklappt, und die Liste wird erst beim Aufklappen
gebaut -- gemessen war also eine Seite, die niemand aufgemacht hatte.
Steht jetzt als Begruendung daneben.

pruef-zuteilung: 75 Pruefungen, 0 Fehler (vorher: Absturz nach 40).

Nichts davon ist ausgeliefert -- es aendert sich nur eine Pruefdatei,
die der Dienst gar nicht laedt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 11:06:32 +02:00
DogFatherGitandClaude Opus 5 db8ad683a1 Der verborgene Rollenname stand offen im Netz -- seit dem 22.09.
Gefunden beim Bauen des Vorlagenbretts, nicht gesucht:
pruef-modi-wortleck war ROT, und zwar seit einem Tag. Sieben
Fundstellen in zwei Dateien, die JEDER bekommt, der die Seite oeffnet
-- ohne Anmeldung, aus dem offenen Netz:

    assets/css/team.css     --ton-modi, .tmerkmal--r-modi,
                            .t-gruppe[data-rolle="modi"]
    assets/js/teamlage.js   die Woerter-Tabelle und drei Rueckfaelle

DER ZUGANG HAELT GENAU SO LANGE, WIE NIEMAND DEN NAMEN IM QUELLTEXT
FINDET. Genau dafuer gibt es diese Pruefung: Am 10.09. hatte ich
denselben Fehler schon einmal gemacht und ihn durch Nachsehen
gefunden, nicht durch Nachdenken -- Nachdenken hatte ich vorher
getan. Seither ist die Regel ein Werkzeug statt eines Vorsatzes.

Nur: Das Werkzeug hat einen Tag lang rot geleuchtet, und niemand hat
hingesehen. Das ist der eigentliche Befund an diesem Commit, und er
steht auch in der Vault-Notiz.

WAS SICH AENDERT
----------------
Die Woerter kommen jetzt vom Server (`rolle_name` aus ROLLEN_NAME) --
so wie ueberall sonst im Haus. Der Browser fuehrt keine eigene Liste
mehr; zwei Listen fuer dieselbe Sache waeren ohnehin zwei
Gelegenheiten, dass eine veraltet.

DIE DREI RUECKFAELLE SIND WEG (`|| 'modi'`, `|| 'Modi'`). Am 21.09.
wurde genau so einer an einer vierten Stelle entfernt, mit zwei
Gruenden: Er schreibt den Namen in eine ausgelieferte Datei, und er
hat noch nie etwas bewirkt -- der Server liefert die Rolle immer mit.
Beides galt fuer diese drei ebenso; sie waren damals nur uebersehen
worden. Fehlt die Rolle jetzt doch einmal, bleibt das Merkmal weg
statt falsch.

DER DRITTE FARBTON HEISST NACH SEINER AUFGABE, nicht nach seinem
Traeger: aus `--ton-modi` wird `--ton-team`, der Grundton des Teams.
Die beiden Haende weichen davon ab -- damit braucht die dritte Rolle
gar keinen eigenen Wahlausdruck mehr, und ihr Name steht nirgends in
der Datei. Das ist nicht nur unverfaenglich, es ist auch richtiger:
Eine Farbe gehoert einer Rolle nicht, sie steht fuer sie.

GEPRUEFT
--------
pruef-modi-wortleck: BESTANDEN, 8 von 8 (vorher 1 Fehler).
Ihre eigene Gegenprobe laeuft mit: eine eingebaute Fundstelle wird
erkannt, und "modifiziert", "Modul", "motion", "Modus" schlagen nicht an.

pruef-teamlage-karten: 39 von 39 weiter gruen -- darunter die Zeilen,
auf die es hier ankommt: "jede Karte nennt ihre Rolle im Klartext
(keine Luecke)" und "jede Ueberschrift nennt ihre Rolle und ihre
Anzahl richtig (Rechte Hand 1 · Linke Hand 1 · Modi 5)". Die Woerter
kommen also weiterhin an, nur aus einer anderen Quelle.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 11:03:12 +02:00
DogFatherGitandClaude Opus 5 e736a12cff Vorlagenbrett: Modis bewerben sich, DogFather und die rechte Hand entscheiden
Filipe: "die modis sollen bei all diesen voschlaegen auch nur bewerben
koennen. die aufgaben aus der vorlage, da sollen die modis sich nur
bewerben koennen und nur dogfather und die rechte hand sollen annehmen
oder ablehnen koennen, mit einem text als notiz."

WAS SICH AENDERT
----------------
Auf dem Vorlagenbrett steht fuer einen Modi jetzt "Bewerben" statt
"Uebernehmen". Wer sich beworben hat, sieht das an der Karte -- samt
dem Satz, WER antwortet, und einem Weg zurueck. DogFather und die
rechte Hand sehen die Bewerbung an derselben Karte, mit Namen und dem
Wort dazu, und daneben "Annehmen" und "Ablehnen". Beide fragen nach
einer Notiz.

"ALSO NUR" GILT AUCH AM SERVER, nicht nur im Browser: Die alte Tuer
antwortet einem Modi mit 403 und dem Satz, was stattdessen geht. Ein
ausgeblendeter Knopf ist eine Bitte, abgelehnt wird in der Route.

DIE LINKE HAND STEHT ABSICHTLICH NICHT BEI DEN ENTSCHEIDERN
------------------------------------------------------------
Sie gehoert seit dem 22.09. ueberall dazu ("ich will dass die linke
hand auch ueberall zu sehen ist"). Hier hat Filipe genau zwei genannt.
Das ist keine Vergesslichkeit von mir, sondern seine Aufzaehlung -- und
dieselbe Grenze zieht das Haus schon bei den Aufgaben-Bewerbungen
(entscheidetUeberAufgaben). Sie darf weiter VERTEILEN; das hat er nicht
angefasst.

Sie ist deshalb die schaerfste Probe in der Pruefung: Wer statt "darf
entscheiden" nur "darf verteilen" abfragt, laesst sie mitentscheiden --
und niemandem faellt es auf, weil alles funktioniert.

DIE AUFGABE ENTSTEHT ERST MIT DER ZUSAGE
----------------------------------------
Der naheliegende Weg waere gewesen, beim Bewerben gleich die Aufgabe
anzulegen und die vorhandene Bewerbung aus aufgaben_zuteilung
daranzuhaengen. Dann stuende nach zwoelf Absagen zwoelfmal Arbeit auf
dem Brett, die niemand bestellt hat -- und um das einzufangen, muesste
das Ablehnen Aufgaben LOESCHEN. Loeschen als Nebenwirkung einer Absage
ist genau die Sorte Regel, die irgendwann das Falsche trifft.

Also eine eigene, kleine Tabelle (vorlagen_bewerbungen). Bis jemand ja
sagt, gibt es nur eine Zeile. Die Woerter sind dieselben wie drueben
(zustand, entscheid_text, entschieden_von) -- zwei Namen fuer dieselbe
Sache waeren zwei Sprachen im selben Haus.

Und die Zusage legt die Aufgabe ueber DIESELBE Funktion an wie das
Uebernehmen (katalogAufgabeAnlegen, neu, aus dem Katalog-Zweig
herausgeloest). Damit sieht eine erbetene Aufgabe aus wie eine
verteilte: gleiche Frist, gleiche Kategorie, gleiche Kennung. Ein
zweiter Weg waere ein zweiter Satz Regeln.

KLEINIGKEITEN, DIE SONST WEHTUN
-------------------------------
  * "Alle 12 uebernehmen" gibt es nur fuer die, die verteilen. Ein
    "Alle bewerben" waere der schnellste Weg, zwoelf Bitten auf einmal
    loszuschicken -- und damit zwoelf Entscheidungen fuer jemand anderen.
  * Wer eine Aufgabe schon hat, bekommt keinen Bewerben-Knopf. Der
    Server lehnt das ohnehin ab; ein Knopf, der eine Absage holt, ist
    schlimmer als keiner.
  * Nach einer Absage darf man sich wieder bewerben. Der eindeutige
    Index gilt deshalb nur fuer OFFENE Bewerbungen -- ueber alle
    Zustaende waere eine Absage ein Bann.
  * Gesucht wird ueber den SCHLUESSEL der Vorlage, nicht ueber die
    Nummer in der Liste. Die Nummer verschiebt sich, sobald jemand eine
    Vorlage einfuegt -- genau dieser Fehler ist am 16.09. schon einmal
    passiert.

GEPRUEFT
--------
pruef-modi-katalog: 95 Pruefungen, 0 Fehler (vorher 49).

Die Pruefung ist beim Umbau ROT geworden -- 9 Zeilen, alle dort, wo ein
Modi sich selbst etwas nahm. Richtig so, sie hat die Aenderung bemerkt.
Sie steht jetzt auf dem neuen Weg und misst ihn ganz:

  * der Modi kommt an die alte Tuer nicht mehr heran (403, erst_bewerben)
  * die Bewerbung legt NOCH KEINE Aufgabe an
  * die linke Hand darf verteilen, aber nicht entscheiden (403)
  * der Bewerber selbst erst recht nicht (403)
  * die Zusage erzeugt die Aufgabe -- mit Kategorie, Frist, Besitzer
  * die Notizen stehen in der Datenbank, samt WER entschieden hat
    (direkt gelesen: ein Feld, das der Server annimmt und nirgends
    speichert, saehe von aussen genauso aus)
  * nach einer Absage geht es wieder
  * am Bildschirm: alle Knoepfe heissen "Bewerben", kein einziger
    "Uebernehmen" mehr, die wartende Karte nennt, wer antwortet --
    und DogFather klickt sich durch Annehmen samt Notizfeld, bis die
    Aufgabe auf dem Brett steht

Die Gegenprobe in Abschnitt 7 lief mit dem Zugang des Modis und haette
ab heute nur noch bewiesen, dass die Rechtepruefung greift -- sie
benutzt jetzt DogFather. Genau so verliert eine Pruefung still ihren
Sinn.

pruef-aufgaben-vorlagen: unveraendert gruen.

ZWEI FUNDE NEBENHER, BEIDE AELTER ALS DIESE AENDERUNG -- gemessen, nicht
vermutet (mit gestashten Aenderungen gegengeprueft):
  * pruef-modi-wortleck ist seit dem 22.09. rot: Der Rollenname steht
    in team.css und teamlage.js, also in Dateien, die jeder bekommt.
  * pruef-zuteilung stuerzt seit laengerem ab (#neu-oeffnen ist
    verborgen). Beides kommt als naechstes, getrennt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 10:59:51 +02:00
DogFatherGitandClaude Opus 5 256ea6f7c0 Team-Lage: die linke Hand traegt ihre Farbe -- und die rechte genauso
Filipe, mit dem Bildschirmfoto der Team-Lage: "die farbe der kachel
soll die gleiche sein wie die farbe die der text linke hand hat, aber
mach es richtig knallig so wie die farben bei den modis und linke hand.
soll schoen auffallen bitte."

AUF DEM FOTO WAR GENAU DAS DAS PROBLEM
--------------------------------------
Die Marke "Linke Hand" leuchtet lila, die Karte darunter war fast
farblos: Sie fiel auf den Ton der STUFE zurueck -- dieselbe Lage wie
bei der rechten Hand vor dem 20.09.

"DIE GLEICHE FARBE" IST NICHTS, WAS MAN AUFSCHREIBT
---------------------------------------------------
Es ist etwas, das man ABLEITET. `#f0c14b`, `#d8a7f5` und `#8fd6ff`
standen bisher verteilt in den Dateien: bei der Gruppenueberschrift,
bei der Rollenmarke, und das Gold ein drittes Mal in module.css an der
Karte. Drei Orte fuer dieselbe Farbe sind drei Gelegenheiten, dass
einer beim naechsten Anstrich nicht mitgeht -- und dann traegt die
Marke ein anderes Lila als die Karte, auf der sie liegt.

Jetzt stehen die drei Toene an einer Stelle (:root in team.css) und
werden ueberall von dort geholt. Auch die Namensfarbe ist abgeleitet
statt aufgeschrieben: Sie war `#f7e3ac` und (im ersten Anlauf fuer die
linke Hand) `#f2ddff` -- beides nichts anderes als "der Ton, stark
aufgehellt".

ICH HAETTE FAST EINE RANGORDNUNG GEBAUT
---------------------------------------
Erst habe ich nur die linke Karte angefasst: Lila startet bei 34 % Ton,
das Gold lag weiter bei den 11 %, die jede Karte hat. Nebeneinander sah
die rechte Hand ploetzlich aus wie die schwaechere von beiden -- eine
Rangordnung, die niemand bestellt hat. Daneben stand mein eigener,
gerade erst geschriebener Kommentar: "gleiche Mittel, gleiche Staerke".

Ein Kommentar, der eine Absicht beschreibt, erfuellt sie nicht. Jetzt
EINE Regel fuer beide Haende; der Unterschied ist der Ton und sonst
nichts. Wer morgen an der Wirkung dreht, dreht sie fuer beide.

"RICHTIG KNALLIG" IST EINE ANWEISUNG, KEINE STIMMUNG
-----------------------------------------------------
Deshalb tragen diese beiden Karten ihre Farbe auch in der FLAECHE und
nicht nur an der Kante. Augenschonend bleibt es trotzdem, und das ist
kein Widerspruch, sondern die Bedingung: kraeftig heisst GESAETTIGT,
nicht hell. Der Grund bleibt sehr dunkel, die Farbe liegt als Verlauf
darueber.

Gemessen bei 1280 und 390 px, am gezeichneten Bildschirm:
  linke Hand   Name 15,11:1 · Kleingedrucktes 8,18:1 · Marke 11,18:1
  rechte Hand  Name 15,63:1 · Kleingedrucktes 8,07:1 · Marke 12,49:1
Verlangt sind 4,5.

MEINE ERSTE MESSUNG WAR FALSCH, UND SIE SAH ECHT AUS
-----------------------------------------------------
Sie las `rgb(13, 8, 23)` und `color(srgb 0.87 0.71 0.96)` mit
derselben Rechnung. Die zweite Schreibweise zaehlt aber in 0..1, nicht
in 0..255 -- die helle Rollenmarke kam damit auf 1,09:1. Eine Zahl, die
aussieht wie ein schwerer Befund und keiner ist; haette ich ihr
geglaubt, haette ich eine funktionierende Farbe "repariert". Die
Umrechnung steht jetzt ausgeschrieben in der Pruefung, samt Grund.

GEPRUEFT
--------
pruef-teamlage-karten: 39 Pruefungen, 0 Fehler (vorher 25).
Neu darin: Traegt die Karte denselben Ton wie ihre Marke? Sind es zwei
verschiedene Toene? Liegt die Farbe in der Flaeche? Tragen beide Haende
dieselbe Staerke? Und: kann man den Text darauf noch lesen?

Mit Gegenproben, die beide Richtungen abdecken: Eine Modi-Karte traegt
die Leiste NICHT (sonst faellt keine auf), und mit absichtlich falschem
Ton auf der linken Karte werden genau zwei Zeilen rot -- gemessen.

Kein Neustart noetig: Es aendert sich nur Ausgeliefertes (CSS, Stempel)
und eine Pruefdatei, die der Dienst gar nicht laedt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 10:42:36 +02:00
DogFatherGitandClaude Opus 5 5e503463f5 Chat: die GIF-Kiste des Rudels -- und eine Luecke in der Sicherung
Filipe: "dan will ich auch dass man im chat auch sprachnachrichten und
gifts reinschicken kann. also nur die modis rechte linke hand und
dogfather."

ICH LESE "gifts" ALS GIFs -- die bewegten Bildchen -- und sage das
ausdruecklich, statt es stillschweigend anzunehmen. Im Zusammenhang
("im chat reinschicken", direkt neben Sprachnachrichten) passt nichts
anderes. Sollte er Geschenke gemeint haben, sagt er es, und dann baue
ich das.

EINE EIGENE KISTE STATT GIPHY ODER TENOR
----------------------------------------
Beide brauchen ein Konto und einen Schluessel und bekommen bei jedem
Tastendruck mit, wonach hier gesucht wird -- an eine fremde Firma, aus
einem Arbeitsplatz heraus, in dem sonst nichts nach aussen geht. Dazu
kosten sie ab einer Menge Geld. Beides steht quer zu dem, wie dieses
Haus gebaut ist.

Die Kiste laeuft auf demselben Server wie alles andere, kostet nichts
und wird mit der Zeit besser statt schlechter: Was darin liegt, hat das
Team ausgesucht. Zehn gute GIFs, die alle kennen, sind im Alltag mehr
wert als zehn Millionen fremde -- ein Katalog mit allem ist nicht mehr
Auswahl, sondern weniger.

HABEN WIR DAS SCHON? WIRD AM INHALT BEANTWORTET
-----------------------------------------------
Der Schluessel ist der SHA-256 der Datei. Ueber den NAMEN zu
vergleichen waere die naheliegende Abkuerzung -- und sie versagt genau
dort, wo Dateien "giphy.gif", "giphy(1).gif" und "download.gif"
heissen, also fast immer. Dasselbe Bild waere dreimal dieselbe Kachel.

Dasselbe GIF zweimal hineinzulegen ist deshalb KEIN Fehler: Es ist
drin, und genau das wollte man. Eine Absage waere formal richtig und im
Erleben falsch.

DAS WICHTIGSTE STUECK: ES WIRD KOPIERT, NICHT VERWIESEN
-------------------------------------------------------
Eine Nachricht zurueckzunehmen entfernt ihre Datei von der Platte. Laege
ein Kachel-GIF in demselben Ordner und mehrere Nachrichten zeigten
darauf, naehme das Zuruecknehmen EINER Nachricht das GIF fuer alle
anderen mit -- und in drei Gespraechen stuende ab da ein kaputtes Bild.
Das ist die Sorte Fehler, die erst Wochen spaeter auffaellt und dann
nicht mehr zu reparieren ist.

Deshalb liegt die Kiste in einem eigenen Ordner (chat-gifs/), und beim
Verschicken wird kopiert. Danach ist es ein ganz normaler Anhang: im
Verlauf, in der Suche, zuruecknehmbar, unter derselben Nachtruhe. Keine
zweite Sorte Nachricht mit eigenen Rechten und eigenem Loeschen.

Geprueft wird genau das: GIF hineinlegen, verschicken, aus der Kiste
nehmen -- und danach steht das verschickte immer noch im Gespraech.

"ALSO NUR" GILT AUCH HIER
-------------------------
Ansehen, hineinlegen, verschicken: alle drei nur fuer Team Dogi und
DogFather (istTeamDogi). Der Satz stand im selben Atemzug wie die
Sprachnachrichten; es gibt keinen Grund, warum er fuer das eine gelten
sollte und fuer das andere nicht. Gemessen auch am Knopf vorbei:
403/403/403.

AUGENSCHONEND -- HIER EINE ECHTE FRAGE, KEINE FORMSACHE
--------------------------------------------------------
Zwoelf gleichzeitig laufende Bildchen sind das Gegenteil von ruhig. Wer
"Bewegung reduzieren" gesetzt hat, bekommt deshalb STEHENDE Bilder: das
erste Einzelbild, im Browser auf eine Zeichenflaeche gemalt (kostet
keine zweite Datei), und es laeuft erst, wenn man es anfasst oder mit
der Tastatur darauf steht.

Fuer alle anderen laufen sie. Eine GIF-Auswahl, in der sich nichts
bewegt, ist eine, in der man nicht sieht, was man verschickt -- deshalb
steht dazu eine Gegenprobe in der Pruefung.

NEBENBEFUND, UND ER WIEGT SCHWERER ALS DIE GIFS
-----------------------------------------------
Weil die Kiste einen neuen Datenordner braucht, lief
tools/wiederherstellung-proben.mjs -- und meldete, dass der Ordner
"material" seit dem 22.09. NICHT gesichert wird. 2,4 MB
Materialbibliothek auf dem Server, nach einem Plattenausfall weg, ohne
dass die taegliche Meldung je etwas gesagt haette. Genau die Luecke,
wegen der diese Probe ueberhaupt gebaut wurde -- und sie hat sie
gefunden, weil sie die Ordner aus dem QUELLTEXT liest statt aus einer
gepflegten Liste.

Eingetragen. Danach frisch geholt und zurueckgespielt: 18 von 18 gruen,
"DIE SICHERUNG LAESST SICH ZURUECKSPIELEN" (vorher 3 Fehler).

Dabei war die Gegenprobe daneben selbst kaputt: Sie prueft, ob ein
erfundener Ordner als fehlend erkannt wird, und verlangte dafuer
`=== 1`. Das setzt voraus, dass sonst nichts fehlt. An dem Tag, an dem
wirklich etwas fehlte, wurde sie rot und zeigte damit auf sich selbst
statt auf den Fund -- zwei Meldungen, eine Ursache, und die zweite
lenkt von der ersten ab. Jetzt zaehlt sie die Differenz.

GEPRUEFT
--------
pruef-chat-anhaenge: 109 Pruefungen, 0 Fehler (vorher 86, davor 60).
pruef-chat, pruef-chat-aufloesen (126), pruef-chat-optik: gruen.
tools/wiederherstellung-proben: 18 von 18.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 02:07:56 +02:00
DogFatherGitandClaude Opus 5 2d14907d0d Chat: Sprachnachrichten -- und ein stiller Fehler, der jedes Foto betraf
Filipe: "dan will ich auch dass man im chat auch sprachnachrichten und
gifts reinschicken kann. also nur die modis rechte linke hand und
dogfather."

Dieser Commit macht die Sprachnachrichten. Die GIFs kommen als
naechstes -- ich lese "gifts" als GIFs und sage das ausdruecklich,
statt es stillschweigend anzunehmen.

AUFNEHMEN: TIPPEN, NICHT HALTEN
-------------------------------
Gedruecktbleiben ist der bekanntere Weg und der schlechtere: Wer beim
Sprechen verrutscht, verliert die ganze Aufnahme, und mit einer Hand am
Kaffee haelt niemand neunzig Sekunden still. Einmal tippen startet, das
Haekchen schickt, das Kreuz verwirft.

Drei Minuten Hoechstdauer, danach stoppt sie von selbst -- und schickt
NICHT von selbst ab. Wer die Grenze erreicht, hat gerade mitten im Satz
aufgehoert; das ungefragt zu verschicken waere die schlechteste Sekunde
dafuer.

Unter einer Sekunde wird gar nichts geschickt: Das ist ein Versehen,
kein Inhalt.

Die Aufnahmespur wird beim Beenden UND beim Verlassen der Seite
geschlossen. Ein Mikrofon, das offen bleibt, ist ein Vertrauensbruch,
auch wenn niemand zuhoert.

DREI BEHAELTER, WEIL DIE GERAETE DREI LIEFERN
---------------------------------------------
WebM/Opus (Chrome, Android), MP4/AAC (Safari, iPhone), Ogg/Opus
(Firefox). Wer nur einen nimmt, baut eine Funktion, die bei der Haelfte
des Teams stumm bleibt -- und zwar ohne Fehlermeldung.

DER BEHAELTER ALLEIN GENUEGT NICHT: WebM und MP4 tragen genauso gut
Video. Ein Video, das als "Ton" durchginge, landete in einem
Abspielgeraet ohne Bild -- es liefe, man hoerte etwas, und niemand
wuesste, dass die Haelfte fehlt. Die Erkennung sieht deshalb auf die
KENNUNG DER SPUR: Videospur -> abgelehnt, keine Tonspur -> abgelehnt.

Kein MP3: Kein Aufnahmegeraet im Browser erzeugt MP3. Es zuzulassen
hiesse, eine Tuer fuer Musikdateien aufzumachen, nach der niemand
gefragt hat.

"ALSO NUR" IST DER PUNKT
------------------------
Fotos und PDF darf jeder schicken, auch Creator -- das war eine
Entscheidung vom 09.09. und bleibt. Ton nicht. Geprueft wird in der
Route (istTeamDogi), nicht nur im Browser: Ein ausgeblendeter Knopf ist
eine Bitte, abgelehnt wird erst am Server.

Eigene Byte-Grenze fuer Ton (4 MB statt 12). Zwoelf Megabyte sind fuer
ein Foto richtig und fuer eine Sprachnachricht sinnlos -- das waeren
rund fuenfzig Minuten am Stueck.

Die Laenge kommt vom Absender und ist damit eine BEHAUPTUNG, keine
Messung; das steht so an der Spalte. Sie dient nur der Vorschau, bis
das Abspielgeraet die wahre Laenge kennt. Was schuetzt, sind die Bytes.

"FOTO"/"PDF" STAND AN VIER STELLEN
----------------------------------
Dieselbe Aufzaehlung in Gespraechsliste, Zitat, angehefteter Nachricht
und Benachrichtigung -- jede mit ihrem eigenen Fragezeichen-Doppelpunkt.
Mit der Sprachnachricht waeren es vier Aenderungen gewesen, und die
vierte ist die, die man vergisst. Jetzt anhangWort() an einer Stelle.

DER FUND: JEDES FOTO MELDETE "KEINE VERBINDUNG"
-----------------------------------------------
Beim Anfassen derselben Funktion aufgefallen: In `anhangSchicken` stand
seit dem 19.09. `const { nachricht } = e.daten;` -- ein `e`, das es
dort nicht gibt (gemeint war `ergebnis`). Die Zeile wirft, der `catch`
daneben faengt, und der Absender liest:

    "Keine Verbindung -- der Anhang wurde nicht geschickt."

Das Foto war aber da. Es kam Sekunden spaeter ueber den Ereignisstrom
in den Verlauf, mit einer roten Meldung darueber, die das Gegenteil
behauptet -- und der getippte Begleitsatz blieb im Feld stehen, also
schickt man es noch einmal.

WARUM DAS VIER TAGE UNBEMERKT BLIEB, und das ist der lehrreiche Teil:
pruef-chat-anhaenge war die ganze Zeit gruen. Sie schickt mit `fetch`
an die Route -- der bequeme Weg, und er prueft den Server gruendlich.
Sie prueft aber nicht den Weg, den ein Mensch geht. Der Fehler lag
hinter der Bueroklammer, und dort hat nie jemand hingesehen. Dazu
fuehlt er sich wie ein Netzproblem an -- und Netzprobleme sucht niemand
im Programm.

Jetzt geht ein Block durch das Dateifeld selbst und sieht auf das, was
der Mensch danach sieht: steht dort eine Meldung, und ist das Feld
leer? Gegenprobe gefahren -- mit dem alten Fehler wieder eingesetzt
werden genau diese zwei Zeilen rot, mit dem Wortlaut von oben.

Uebernommen wird eine frisch geschickte Nachricht jetzt an EINER
Stelle (nachrichtUebernehmen), fuer Anhang und Sprachnachricht. Zwei
Fassungen waeren zwei Gelegenheiten fuer denselben Fehler.

AUGENSCHONEND
-------------
Kein Blinkpunkt waehrend der Aufnahme -- der ist genau das, was die
Hausregel ausschliesst. Der Punkt atmet langsam (1,8 s, 45 bis 100 %)
und steht bei prefers-reduced-motion ganz still; die laufende Zeit
daneben traegt die Auskunft ohnehin.

Die Farben der Sprachnachricht-Blase kommen aus `--blase-leise`, der
fuer DIESE Blase ausgerechneten leisen Schrift. Eine feste Farbe waere
dieselbe Wette, die am 22.09. beim Loeschknopf 1,91:1 auf Babyblau
ergeben hat.

GEPRUEFT
--------
pruef-chat-anhaenge: 86 Pruefungen, 0 Fehler (vorher 60).
Aufgenommen wird mit MediaRecorder im echten Browser ueber den echten
Knopf, mit Chromiums erfundenem Mikrofon. Damit prueft der Abschnitt
nebenbei das, was keine gebastelte Datei pruefen koennte: ob die
Erkennung im Server versteht, was ein Browser wirklich erzeugt
(gemessen: 35 829 Bytes audio/webm, 2743 ms).

  * DogFather sieht den Mikrofonknopf, der Scout nicht
  * der Scout schickt dieselbe Aufnahme an der Oberflaeche vorbei:
    403, und nichts davon ist gespeichert
  * ein Video im Ton-Behaelter: 415
  * Laenge, Vorlesewort, Bedienbarkeit, preload=metadata, Breite
  * "Sprachnachricht" steht in der Gespraechsliste statt einer leeren
    Zeile

pruef-chat, pruef-chat-optik: unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 01:51:56 +02:00
DogFatherGitandClaude Opus 5 28b0143166 Chat: "@rudel" ruft das ganze Team -- und nur die vier duerfen es
Filipe: "dan will ich auch dass nur die modis, rechte hand, linke hand
und dogfather, alle auch auf einmal markieren koennen im chat mit
einem, @rudel ,dann sollen alle eine benarichtigung bekommen."

DAS WAR EINE OFFENE FRAGE, UND ER HAT SIE BEANTWORTET
-----------------------------------------------------
In chat-erwaehnung.js stand seit dem 20.09. woertlich: "KEIN @alle. Es
waere in fuenf Minuten gebaut und ist der zuverlaessigste Weg, dass alle
die Benachrichtigungen abschalten -- und dann kommt auch die an, die
wirklich fuer einen bestimmten Menschen gedacht war. Wenn Filipe es
ausdruecklich will, gehoert dazu eine Entscheidung, WER es benutzen
darf; das ist eine Frage an ihn, keine, die ich hier beantworte."

Seine Antwort ist genau diese Entscheidung, und sie ist die Sicherung:
Team Dogi und DogFather duerfen rufen, sonst niemand.

WEN DER RUF ERREICHT: DAS TEAM IM RAUM, NICHT DEN RAUM
------------------------------------------------------
"Rudel" heisst das Team -- dieselben vier Gruppen, die auch rufen
duerfen. In einem Team-Kanal ist das jeder Anwesende, also "alle auf
einmal". Sichtbar wird der Unterschied im TREFF, und dort haette die
andere Lesart wehgetan: Dort sitzt die Community. Ein Ruf, der jeden
Zuschauer weckt, waere etwas anderes als der bestellte -- und beim
zweiten Mal haetten sie die Benachrichtigungen abgeschaltet.

WO WAS ENTSCHIEDEN WIRD
-----------------------
chat-erwaehnung.js bleibt ohne Abhaengigkeiten (die Pruefung soll sie
lesen koennen, ohne einen Server hochzufahren). Sie sagt nur, DASS
gerufen wurde; der Aufrufer sagt ihr, ob der Schreibende darf. Wer zum
Rudel gehoert, entscheidet workspace-chat.js ueber istTeamDogi().

Das Schluesselwort gewinnt gegen einen Menschen, der "Rudel" heisst.
Heute heisst niemand so -- aber das ist eine Tatsache von heute, kein
Gesetz. So herum verliert niemand eine Meldung (wer so heisst, ist im
Rudel dabei); andersherum haette ein einziger Zugang den Ruf ans Team
stillschweigend abgeschaltet.

istTeamDogi() NEU IN workspace.js
---------------------------------
Derselbe Ausdruck ("admin oder TEAM_DOGI_ROLLEN") stand dort dreimal
wortgleich: siehtModis, kanaeleFuer, kategorienFuer. Drei gleiche
Ausdruecke sind drei Gelegenheiten, dass einer beim naechsten
Rollenzuschnitt nicht mitgeht. Jetzt eine Stelle, die drei benutzen.

DIE NACHRICHT MERKT SICH DEN RUF (Spalte chat_nachrichten.rudel)
----------------------------------------------------------------
Beim Lesen muesste der Browser sonst wissen, ob der Absender es DAMALS
durfte. Er kennt nur dessen heutige Rolle -- wechselt jemand die Rolle,
verschwaende die Hervorhebung rueckwirkend aus einem Satz von vorletzter
Woche. Und es waere die zweite Rechnung ueber dieselbe Frage.
Vorgabe 0; alle alten Nachrichten haben kein Rudel gerufen, und das ist
keine Annahme, sondern eine Tatsache: Das Wort gab es noch nicht.

DIE MELDUNG SAGT, WAS LOS IST
-----------------------------
"X hat das Rudel gerufen", nicht "X hat dich erwaehnt" -- letzteres
stimmt beim Rudel nicht, und wer dreimal liest, dass er gemeint sei,
und jedes Mal merkt, dass es alle betraf, glaubt beim vierten Mal auch
dem echten nicht mehr. Auf DEMSELBEN Schalter wie die Erwaehnung: Ein
vierter Schalter waere der, den jemand abschaltet und der dann genau im
wichtigen Moment fehlt. Jeder Ruf steht im Protokoll (chat_rudel) --
"@rudel wird zu oft benutzt" soll eine Zahl sein koennen, kein Gefuehl.

DIE FARBE WIRD ABGELEITET, NICHT GESETZT
----------------------------------------
Eine Nachricht liegt in der Blase, deren Farbe ihr Absender AUSGESUCHT
hat -- siebzehn Moeglichkeiten. Eine feste Farbe darauf ist eine Wette,
und genau die habe ich am 22.09. beim Loeschknopf verloren (1,91:1 auf
Babyblau, gemessen, nachdem es live war). Die Marke nimmt deshalb
`--blase-text` -- die Schrift, die schriftFuer() fuer DIESE Blase mit
mindestens 7:1 ausgerechnet hat. Unterschieden wird ueber Form statt
Farbton: Toenung, Kante, Gewicht 700, ein Zeichen davor. In der
Auswahlliste darf es einen eigenen Ton haben -- sie liegt auf der
Flaeche des Hauses, deren Farbe feststeht.

DER VORSCHLAG ERSCHEINT NUR, WO ER ETWAS BEWIRKT
------------------------------------------------
In einem Zweier-Gespraech mit einem Creator ist ausser mir niemand aus
dem Team. `darf_rudel` fragt deshalb beides: darf ich, und sitzt hier
noch jemand aus dem Team. Dieselbe Ueberlegung wie beim eigenen Namen,
den die Liste auch nicht anbietet. Die Schranke beim Schreiben haengt
nicht daran -- wer es von Hand tippt, ruft eben niemanden.

GEPRUEFT
--------
pruef-erwaehnung: 119 Pruefungen, 0 Fehler (vorher 66).
Neu darin, und die zweite ist die wichtigere:
  * der Modi ruft im Treff genau das Team -- die Liste wird aus der
    Besetzung ABGELEITET, nicht abgeschrieben
  * der Gast im selben Raum ruft NICHTS: kein Eintrag, kein Merkmal,
    kein Vorschlag. Ohne diese Pruefung stuende Filipes "nur die
    modis, rechte hand, linke hand und dogfather" bloss im Kommentar
  * beide Fassungen der Regel (Server und Browser) an 14 zusaetzlichen
    Proben nebeneinander, mit beiden Rechten -- samt Gegenprobe, dass
    der Vergleich einen Unterschied ueberhaupt sehen kann
  * am Bildschirm: der Ruf steht oben in der Liste, sagt daneben, was
    er bedeutet, Enter setzt ihn ein, und im Satz ist er an Gewicht
    und Rahmen erkennbar -- nicht nur an der Farbe

Beim Bauen gemessen statt vermutet: Ein Scout und ein Modi kommen gar
nicht in denselben Raum (403, Haeusertrennung) -- deshalb prueft der
Verhaltenstest im Treff. Und ein Gast meldet sich nur mit
Altersbestaetigung an (400 ohne).

Die Nachtruhe des Treffs wird in dieser Pruefung abgeschaltet (gleiche
Stunden = keine Nachtruhe). Sonst waere sie zwischen Mitternacht und
sechs rot und danach gruen -- ein Test, der die Wanduhr misst.

pruef-chat, pruef-treffchat (110), pruef-chat-kanaele (81),
pruef-chat-ausbau (64): alle unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 01:36:09 +02:00
DogFatherGitandClaude Opus 5 2a3058e98e screen1, nachgefasst: eine zweite Regel lief ebenfalls ins Leere
Beim Nachsehen auf der echten Domain gefunden -- und zwar als Beispiel
fuer genau das, was es zu vermeiden gilt: Mein Live-Test suchte im
ausgelieferten CSS nach "columns: 2" und fand einen Treffer. Es war mein
eigener Kommentar, der die entfernte Regel beschreibt. Textsuche misst
kein Verhalten; das tut die Messung in pruef-befinden.

Dabei fiel `#fragen > .e-feld:first-child` auf. Seit die Gruppen ihren
eigenen Abschnitt haben, ist ein `.e-feld` kein direktes Kind von
`#fragen` mehr -- dieselbe Ursache, die den Spaltenumbruch ausgeloest
hat, nur an einer zweiten Regel. Nachgesehen: `.e-feld` wird im ganzen
Haus an genau einer Stelle gebaut (befinden.js), und immer in eine
`.b-gruppe`.

Eine Regel, die nichts mehr trifft, faellt nicht auf -- sie hoert
einfach auf zu wirken. Deshalb weg statt stehengelassen. Den Abstand
macht jetzt `.b-gruppe:first-of-type` zusammen mit `.b-flaeche .e-feld`.

pruef-befinden: 121 Pruefungen, 0 Fehler, Lage unveraendert
(1 Flaeche, 6 von 6 Koepfen ueber ihren Fragen, 5 von 5 Uebergaengen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 01:10:10 +02:00
DogFatherGitandClaude Opus 5 19d709250d screen1: "Wie geht's dir?" ist EINE Flaeche -- und die Spalten waren der Fehler
Filipe, mit dem Bildschirmfoto der Seite: "ich will dass diese seite
viel uebersichtlicher aussieht, es soll eine riesssen kachel sein wo
alles viel besser und geiler aussieht. los"

WAS ANDERS IST
--------------
Vorher lagen Gruppenkoepfe und Fragen flach nebeneinander in derselben
Spalte: jede Frage eine eigene Kachel mit Rand, Schatten und Fase,
dazwischen ab und zu eine Ueberschrift. Zwoelf Kacheln, kein Zusammenhang.

Jetzt: eine Flaeche (`b-flaeche`), darin je Gruppe ein Abschnitt mit
ihrem Kopf und ihren Fragen. Getrennt wird durch eine Linie, nicht durch
eine Luecke. Die Frage ist darin kein eigener Kasten mehr, sondern ein
flaches Feld; beantwortet erkennt man an der linken Kante. Obendrauf ein
Band, das den eigenen Stand zeigt ("2 von 9 Fragen dieser Runde
beantwortet") -- auf einer Seite, die man ausfuellt, ist genau das die
Uebersicht, die gefehlt hat.

DER EIGENTLICHE FUND: DER SPALTENSATZ
-------------------------------------
Nach dem Umbau stand auf dem Bildschirmfoto rechts oben eine Reihe
Antwortknoepfe ohne Ueberschrift darueber, und die Ueberschrift
"Miteinander" links unten neben fremden Fragen. Eine Ueberschrift, die
neben fremdem Inhalt steht, ordnet den falschen zu -- das ist nicht
unschoen, das ist falsch.

Ursache war `columns: 2` auf `#fragen`, dem Behaelter um ALLES. Solange
darin nur flache Fragen lagen, ging es auf. Seit die Fragen in Gruppen
stecken, schneidet der Spaltenumbruch mitten durch eine Gruppe. Das
`break-inside: avoid` daneben konnte nichts halten: Es galt fuer
`#fragen > .e-punkt`, und ein `.e-punkt` ist seit dem Umbau kein direktes
Kind von `#fragen` mehr. Die Regel lief ins Leere.

Zwei Spalten gibt es weiterhin -- aber INNERHALB einer Gruppe, ueber ein
Raster (`.b-gruppe__fragen`). Ein Raster verteilt Kaesten und bricht
keinen Textfluss um; es kann per Bauart nichts zerschneiden. Damit ist
die Ursache weg und nicht der Schaden ueberklebt.

`.b-feld__liste` stand in derselben Regel und kommt in keiner Seite und
keinem Skript mehr vor -- nachgesehen, nicht vermutet. Faellt mit weg.

GEPRUEFT WIRD DIE LAGE DER KAESTEN, NICHT DIE VERSCHACHTELUNG
-------------------------------------------------------------
pruef-befinden bekommt fuenf Messungen dazu. Wichtig dabei, und der
Grund fuer die Form: Eine Pruefung auf "steht der Kopf im richtigen
Abschnitt?" waere die ganze Zeit gruen gewesen. Nachgemessen war sie es
auch (`kopfInGruppe: true`), waehrend das Bild falsch war. Das HTML war
nie das Problem.

Gemessen wird deshalb, WO die Kaesten liegen: jede Frage unterhalb des
Kopfes ihrer Gruppe, keine Gruppe ragt in die naechste. Gegenprobe
gefahren -- mit dem Spaltensatz zurueck faellt das erste auf 5 von 6 und
das zweite auf 3 von 5, bei 1280 px. Die Pruefung kann also auch "nicht
in Ordnung" sagen.

pruef-befinden: 121 Pruefungen, 0 Fehler (vorher 116).
Gemessen bei 1280 und 390 px, keine Browsermeldungen.

Nebenbei: eine deutsche Anfuehrung in einer Pruefmeldung war mit einem
ASCII-Anfuehrungszeichen geschlossen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 01:08:25 +02:00
DogFatherGitandClaude Opus 5 51562eb276 screen3: Das Verteil-Formular -- Karten statt Zeilen, und alle auf einmal
"diese kachel soll viel geiler sein, also alles was drin ist soll viel
geiler gestaltet sein, viel hochwertiger, viel profissineller, auch
die möglichkeit alle auf einmal auszuwählen und so. mach es hoch krass
profissionel, übersichtlich und richtig krass geil bitte."

VORHER: ein Kaestchen und ein Name je Zeile, untereinander. Bei sieben
Leuten sieben gleiche Zeilen -- man liest alle, um eine zu finden, und
auf dem Handy kostet das sieben Bildschirmzeilen.

JETZT EINE KARTE JE PERSON, im Raster (am Rechner drei Spalten, auf
dem Handy eine). Drei Dinge machen den Unterschied zwischen "Liste"
und "Auswahl":

  1. DIE GANZE KARTE IST DAS ZIEL, nicht das Kaestchen darin. Auf
     einem Handy ist ein Kaestchen 20 px breit, eine Karte 200. Das
     Kaestchen bleibt trotzdem stehen -- es ist das, was ein
     Vorleseprogramm ansagt und was die Tastatur bedient.
  2. DIE GEWAEHLTE KARTE SIEHT ANDERS AUS: Rahmen und Flaeche in der
     Akzentfarbe. Ein Haken allein ist bei sieben Karten zu wenig.
     Ueber `:has(input:checked)` und nicht ueber eine Klasse aus dem
     Skript -- der Zustand steht schon im Kaestchen, ihn zusaetzlich
     als Klasse zu fuehren waeren zwei Wahrheiten.
  3. JEDE KARTE NENNT DIE ROLLE. "Diene" und "Funny" sagen nichts;
     "Diene, Modi" schon. Der Rollenname kommt fertig vom Server
     (`rolle_name`) -- ihn hier aus einem Schluessel zu uebersetzen
     hiesse, die Namen der Rollen in eine Datei zu schreiben, die
     jeder herunterlaedt.

ALLE AUF EINMAL -- UND DIE GRUPPEN DAZU

Eine Schnellwahl ueber der Liste: Alle · Rechte Hand · Linke Hand ·
Modi · Keine.

DIE GRUPPEN WERDEN GELESEN, NICHT AUFGEZAEHLT. Welche Rollen
vorkommen, sagt die Liste selbst. Eine feste Aufzaehlung hier waere
die, die beim naechsten Rollenzuschnitt eine Gruppe verschweigt -- und
niemand merkte es, weil die Knoepfe ja funktionieren. Genau diese
Sorte Liste hat gestern die linke Hand auf der Team-Lage verschluckt.

Gruppenknoepfe nur, wenn es mehr als eine Rolle gibt: "Modi" neben
"Alle" bei einer Liste aus lauter Modis waeren zwei Knoepfe fuer
dasselbe.

DER ZAEHLER ist der Teil, der Uebersicht macht: "2 von 7 ausgewaehlt".
Bei sieben Kaestchen sieht man nicht mehr, wie viele angehakt sind --
man zaehlt nach.

Gemessen bei 1280 und bei 390 px: 7 Karten, fuenf Schnellknoepfe, kein
waagerechtes Scrollen, keine Browsermeldung.
pruef-bewerbung-aufgaben: 101 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:59:22 +02:00
DogFatherGitandClaude Opus 5 54d069c2b8 screen2: Die Aufgaben-Kachel ist Glitzer-Silber
"ich will dass diese kachel einen richtig geilen silber hat als farbe
bitte. mach es richtig geil, ein glitzer silber."

WARUM DUNKLES SILBER UND KEIN HELLES

"Silber" denkt man sich hell. Auf dieser Wand waere es das Ende der
Lesbarkeit: Die Beschriftung jeder Kachel ist HELL (--text), und eine
helle Flaeche darunter laesst davon nichts uebrig. Ein zweiter Satz
Schriftfarben nur fuer diese eine Kachel waere eine Sonderregel, die
beim naechsten Umbau niemand kennt.

Silber ist deshalb als METALL gebaut, nicht als Farbflaeche: Gunmetal,
dunkel und kuehl, mit hellen Kanten und einer Glanzbahn. Das ist, was
gebuerstetes Metall im Halbdunkel macht -- es liest sich sofort als
Silber, ohne zu blenden.

FUENF EBENEN, VON OBEN NACH UNTEN
  1. Der Lesesaum liegt ZUERST, also obenauf -- er ist der Grund,
     warum die Flaeche funkeln darf, ohne dass die Schrift leidet.
     Dieselbe Bauart wie bei der Regenbogen-Kachel.
  2. Das Funkeln: sechzehn helle Punkte, jeder mit Hof, unregelmaessig
     gesetzt (ein Raster saehe aus wie ein Muster, nicht wie Glitzer).
     STATISCH -- blinkende Punkte waeren genau das, was die Hausregel
     verbietet.
  3. Eine diagonale Glanzbahn.
  4. Gebuerstetes Metall: 3-px-Streifen bei 4,5 % Weiss. Man sieht es
     nicht als Streifen, man sieht es als Oberflaeche.
  5. Der Grundverlauf, oben heller als unten.

ALS EIGENES MERKMAL, NICHT ALS TON. Silber hat eine Buntheit nahe
null; als Ton eingetragen haette pruef-kachelfarben es zu Recht
abgelehnt (Mindestbuntheit 0,12). `ton: 13` bleibt deshalb stehen und
ist der Rueckfall -- genau so macht es die Willkommenskachel mit
`regenbogen`. Zwei Stellen tragen das Merkmal, weil die Kacheln fuer
die Modis aus dem Server kommen und die fuer alle anderen aus
bereiche.js.

NACH DEM ERSTEN BILD NACHGEBESSERT: Kantenlicht, Eckwinkel und
Schiene blieben gruen -- sie ziehen ihre Farbe aus `--ton`. Eine
gruene Linie um eine silberne Flaeche ist keine silberne Kachel.
`--ton` wird jetzt fuer diese eine Kachel ueberschrieben, NUR in der
Anzeige: `data-ton="13"` bleibt am Element, die Farbwerkzeuge rechnen
weiter mit Zahlen.

GEMESSEN am echten Bildschirm (pruef-kachelfarben): 32 Kacheln, kein
Paar sieht gleich aus, und jeder Kacheltext erreicht 4,5:1 --
schlechtester 5,86:1. Die silberne ist nicht darunter.

Mitgelaufen: pruef-kachelraster (15/0), pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:55:20 +02:00
DogFatherGitandClaude Opus 5 4b0cda7334 screen4: Die linke Hand ist ueberall zu sehen -- rechte Hand, linke Hand, Modis
"ich will dass die linke hand auch ueberall zu sehen ist. reihenfolge
immer. rechte hand, dan linke hand und dan modis. perfektionier das
bitte."

DER BEFUND: In workspace-teamlage.js stand

    WHERE rolle IN ('hand','modi')

Eine abgeschriebene Rollenliste, und die linke Hand kam darin nicht
vor. Sie fehlte damit nicht nur als KARTE: Der Eingang derselben
Seite sammelt die Rueckmeldungen aus genau dieser Liste. Was sie
meldet, waere nirgends angekommen -- dasselbe, was am 11.09. schon
der rechten Hand passiert ist, an derselben Zeile.

Dieselbe Liste ein zweites Mal in workspace-bereiche.js: Ein Eintrag
im Entwicklungsbereich liess sich ihr nicht zuordnen, mit der Meldung
"Diese Person gehoert nicht zum Team." -- ueber jemanden, der sehr
wohl dazugehoert.

Beide lesen jetzt TEAM_DOGI_ROLLEN, die eine Liste des Hauses
({hand, linke, modi}). Kaeme morgen eine weitere Team-Rolle, waere
sie von selbst dabei.

DIE REIHENFOLGE STIMMTE SCHON. ROLLEN_REIHE nennt hand vor linke vor
modi, ROLLEN_SORTIERUNG leitet daraus das CASE ab. Sie war nur nie zu
sehen, weil eine der drei fehlte.

WARUM DIE PRUEFUNG DAS NICHT GEFUNDEN HAT -- und was daran mein
Fehler war: pruef-teamlage-karten legte eine rechte Hand und fuenf
Modis an, aber KEINE linke Hand. Eine Rolle, die in den Testdaten
nicht vorkommt, kann auch nicht vermisst werden. Sie ist jetzt dabei,
und drei neue Zeilen messen die Reihenfolge gegen ROLLEN_REIHE statt
gegen drei hier hingeschriebene Namen:

    hand → linke → modi
    "Rechte Hand 1 · Linke Hand 1 · Modi 5"

25 Pruefungen, 0 Fehler.

NEBENBEI: EIN EIGENER MESSFEHLER, DEN ICH RICHTIGSTELLEN MUSS

Auf dem Weg dorthin habe ich behauptet, der linken Hand fehlten
FUENFZEHN Seiten in der Rechtetafel. Das war falsch gemessen: Ich
habe den QUELLTEXT von rechte.js gelesen statt das Verhalten. Die
Tafel leitet seit dem 21.09. ab -- „die linke Hand bekommt die Seiten
der rechten", mit fuenf ausdruecklich begruendeten Ausnahmen
(Personen anlegen, Talente, Bewerbungen, vertraulicher Meldeweg,
Rechtetafel). Ueber `darfSeite` gemessen fehlen ihr genau diese fuenf,
und das ist so gewollt.

Derselbe Fehler wie heute Nacht bei pruef-haus-seiten, wo ich zwei
Listen mit einem regulaeren Ausdruck aus dem Quelltext lesen wollte.
Eine Regel steht im Code; ob sie WIRKT, sagt nur eine Messung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:55:03 +02:00
DogFatherGitandClaude Opus 5 d26cdc78ff Der Loeschknopf war auf dem Handy unsichtbar -- und mein erster Ersatz unlesbar
GEFUNDEN, WEIL ICH MIR DEN CHAT ANGESEHEN HABE

Nach dem Umbau von gestern Abend habe ich den Chat im Browser
aufgemacht statt nur die Pruefungen zu lesen. Im Bild klaffte zwischen
"reagieren" und "anheften" eine Luecke von 87 px, in der nichts stand.
Nachgemessen: Der Loeschknopf ist dort -- sichtbar 0.

URSACHE: `.chat-nachricht__weg-knopf { opacity: 0 }`, sichtbar erst
beim Ueberfahren mit der Maus. Das war vertretbar, solange er nur die
EIGENE Nachricht zuruecknahm: ein seltener, absichtlicher Griff.

Seit gestern traegt derselbe Knopf das Notfall-Loeschen fuer DogFather
und die rechte Hand. Und damit wird es zum Fehler:

  * AUF EINEM HANDY GIBT ES KEIN UEBERFAHREN. Der Knopf war dort
    dauerhaft unsichtbar -- eine Funktion, die man auf dem Geraet nicht
    erreicht, gibt es auf dem Geraet nicht. Filipe besteht bei jedem
    Auftrag darauf, dass es auf dem Handy genauso gut sein muss.
  * Er belegte trotzdem Platz. Eine Luecke, die nichts erklaert, sieht
    nach einem Fehler aus.

Was davor schuetzt, versehentlich zu loeschen, ist nicht die
Unsichtbarkeit, sondern die Rueckfrage -- die steht seit dem 19.09. als
eigener Dialog da. Ein Knopf, den man nicht findet, schuetzt niemanden;
er verhindert nur, dass jemand ihn absichtlich benutzt.

UND MEIN ERSTER ERSATZ WAR MESSBAR FALSCH

Ich gab dem Notfall-Knopf den Warnton, gedaempft gemischt mit der
leisen Schrift. Nachgerechnet, bevor ich ihn ausgeliefert habe:

    auf Babyblau            1,91:1   (noetig 4,5)
    auf den dunklen Toenen  4,06 bis 4,13

Unlesbar auf der hellen Kachel, zu wenig auf allen anderen. Die leise
Schriftfarbe ist nicht irgendein Grau -- sie ist genau der Wert, der
auf JEDER Kachel 4,5:1 schafft. Wer daran mischt, gibt diese Zusage
auf.

DER PUNKT TRAEGT DIE FARBE, NICHT DIE SCHRIFT. Denselben Weg geht das
Haus schon beim Namen in der Blase, mit derselben Begruendung: Fuer
eine Schriftfarbe laesst sich bei dreizehn waehlbaren Flaechen kein
Kontrast garantieren, fuer einen 6-px-Punkt daneben ist das egal.
Beim Ueberfahren wird die Schrift HELLER statt bunter -- wer den Knopf
anvisiert, soll ihn am besten lesen koennen, nicht am schlechtesten.

EIN DRITTER FEHLER, DEN DIE GEGENPROBE GEFANGEN HAT

Die neue Pruefung (pruef-loeschen, Abschnitt 5b) sollte zweierlei
sichern: kein `opacity: 0`, und die Notfall-Regel setzt keine eigene
Schriftfarbe. Ich schrieb dafuer `/\bcolor:/` -- gedacht als
Wortgrenze. Geschrieben wurde es durch eine Python-Zeichenkette, und
dort ist \b das BACKSPACE-ZEICHEN. In der Datei stand
`/<0x08>color:/`, ein Ausdruck, der nie etwas findet.

Die Zeile "setzt keine eigene Schriftfarbe" war dadurch GRUEN, ohne je
gesucht zu haben. Aufgefallen ist es nur, weil die Gegenprobe daneben
dieselbe Suche benutzt und ROT wurde -- sie sollte ja etwas finden.

Ohne diese Gegenprobe haette ich eine Pruefung ausgeliefert, die genau
den Fehler nicht sieht, fuer den sie gebaut wurde. Jetzt zwei
schlichte Textsuchen ohne regulaeren Ausdruck.

pruef-loeschen: 25 -> 31, 0 Fehler. Mitgelaufen: pruef-chatkachel (33),
pruef-chat-optik.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:44:07 +02:00
DogFatherGitandClaude Opus 5 dc355ad05b pruef-ports: kann jede Pruefung ihren Port ueberhaupt bekommen?
ENTSTANDEN AUS EINEM ABSTURZ, DEN ICH SELBST AUSGELOEST HABE

Die Portnummer einer Pruefung wird aus ihrer STELLE IM ALPHABET
abgeleitet. Das ist eindeutig von der Bauart her und deshalb gut --
hat aber eine Nebenwirkung, die in helfer-port.mjs auch ausdruecklich
steht: Kommt eine neue Pruefung dazu, verschieben sich ALLE Nummern
dahinter.

In der Nacht zum 23.09. sind sechs neue Pruefdateien entstanden.
`pruef-bereiche-lesend` rutschte dadurch auf Port 5040, und den haelt
auf diesem Rechner ein Windows-Dienst. Der Lauf endete mit

    [uncaughtException] Error: listen EACCES 127.0.0.1:5040

also einem Stapelauszug aus node:net, der wie ein Fehler im Code
aussieht. GEFUNDEN HABE ICH ES DURCH ZUFALL -- ich wollte nur sehen,
ob eine andere Aenderung etwas kaputt gemacht hat.

Nachgemessen habe ich danach ALLE 366 Nummern: Genau eine ist
betroffen. Es lag also kein weiterer Schaden herum. Aber der naechste
Umbau verschiebt wieder alles, und dann faellt es wieder jemandem
zufaellig auf -- oder eben nicht.

WAS DIE PRUEFUNG TUT (unter einer Sekunde)

  * Sie leitet die Liste mit DERSELBEN Regel ab wie helfer-port.mjs
    (alle pruef-*.mjs im Serverordner, sortiert) -- eine eigene Liste
    waere die, die beim Hinzufuegen der naechsten nicht mitwaechst,
    also genau der Fehler, den sie verhindern soll.
  * Keine Nummer doppelt, keine auf einem gesperrten Port.
  * Und sie probiert jeden Port am echten Betriebssystem aus.

BELEGT IST ETWAS ANDERES ALS GESPERRT, und nur eines ist ein Befund:

  EACCES      Das System gibt den Port nicht her. Das geht nicht
              vorbei. Hier muss der Ausweichport frei sein, sonst ist
              die betroffene Pruefung auf diesem Rechner nicht
              lauffaehig.
  EADDRINUSE  Jemand hoert gerade darauf -- meist ein Lauf, dessen
              Server noch schliesst. Das geht vorbei, und es als
              Fehler zu melden waere eine Warnung, die immer kommt.
              Dritter Ausgang.

Der Unterschied ist der ganze Punkt. Wuerde beides gleich behandelt,
waere diese Pruefung im Gesamtlauf regelmaessig rot -- und dann liest
niemand mehr, wenn sie einmal recht hat.

Dazu eine Gegenprobe zur Ableitung: Ein bekannter gesperrter Port
(5060, SIP) darf in keiner Nummer vorkommen. Ohne sie waere „keine
liegt auf einem gesperrten" auch dann wahr, wenn die Sperrliste gar
nicht angesehen wird.

AUSWEICHEN und GESPERRT sind dafuer aus helfer-port.mjs ausgeleitet --
eine 4000 in der Pruefung waere die zweite Fassung, und beim naechsten
Mal stuende in einer der beiden eine andere Zahl.

Ergebnis heute: 183 Dateien, 366 Nummern, 0 doppelt, 1 vom System
gesperrt (5040 -> weicht auf 9040 aus, frei). 8 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:35:52 +02:00
DogFatherGitandClaude Opus 5 24ef154a2c pruef-haus-seiten: zwei gepflegte Seitenlisten durch eine Ableitung ersetzt
GEFUNDEN BEIM NACHGEHEN DER ALTLASTEN

    FEHL  calls.html ist auf crew. noch offen (200)
    FEHL  alle 8 Agenturseiten sind auf der Team-Adresse zu

Richtig gemessen und trotzdem kein Befund: Die Seite SOLL dort offen
sein. Am 22.09. hat Team Dogi die Kachel "Calls & Protokolle"
bekommen; seither gehoert calls.html zum Team. Rot war die Liste,
nicht das Haus.

Es waren ZWEI Listen von Hand -- neun Agenturseiten in Abschnitt 2,
fuenfzehn Teamseiten in Abschnitt 3 -- und in beiden fehlte dieselbe
Aenderung. Zwei gepflegte Listen fuer dieselbe Frage sind zwei
Gelegenheiten, eine zu vergessen.

ABGELEITET STATT GEPFLEGT

Welche Seiten es auf einer Adresse gibt, entscheidet
`gehoertAufDieseAdresse`: Eine Seite gehoert hierher, wenn sie unter
den KACHELN dieser Person steht. Die Pruefung fragt jetzt dieselben
Kacheln (`bereicheFuer` + `zusatzBereicheFuer`) und misst danach ueber
HTTP.

Das beweist NICHT, dass die Regel richtig gedacht ist -- das steht in
der Regel selbst. Es beweist, dass die Schranke tut, was die Kacheln
versprechen, und dass keine Seite durchrutscht, die auf keiner Kachel
steht. Und es gibt keine Zahl mehr, die morgen falsch ist.

ZWEI SORTEN GEHOEREN WEDER DEM EINEN NOCH DEM ANDEREN HAUS

Beim ersten Anlauf zaehlte die Ableitung `crew-index.html`,
`index.html` und `start.html` als Agenturseiten -- und verlangte damit
etwa, dass crew-index.html auf der Agenturadresse steht, wo sie zu
Recht ein 404 ist.

  1. DIE EINGANGSWAENDE (OHNE_ANMELDUNG): jede gehoert zu IHRER
     Adresse, auf der anderen gibt es sie nicht.
  2. DIE SEITEN OHNE KACHEL (OHNE_KACHEL_UEBERALL): der eigene
     Steckbrief, die Regeln des Treffs -- sie gehoeren dem Menschen,
     nicht dem Haus.

Mein erster Versuch las beide Listen mit einem regulaeren Ausdruck aus
dem Quelltext. Das ging schief (leere Mengen, vier neue Fehlalarme)
und war auch der falsche Gedanke: Eine Liste, die man PARST, ist eine
Abschrift mit Zwischenschritt. `OHNE_KACHEL_UEBERALL` ist jetzt
ausgeleitet, beide werden importiert.

Gemessen: 10 Seiten gehoeren nicht zu Team Dogi (automation, content,
leistung, profil, report, scouting, startcheck, team, teilen,
uebersicht), 21 gehoeren dorthin. 38 Pruefungen, 0 Fehler.

Dazu eine Gegenprobe zur Ableitung selbst: `calls.html` darf nicht
mehr unter den Agenturseiten stehen. Stuende es dort, waere die
Ableitung kaputt -- und die Pruefung wuerde denselben Fehlalarm wie
zuvor melden, nur mit mehr Umweg.

NEBENBEI GEKLAERT: team.html schickt einen admin auf der Team-Adresse
auf start.html. Am 22.09. als "auffaellig, nicht untersucht" notiert
-- nachgesehen ist es RICHTIG: team.html ist die Teamuebersicht der
Agentur, Team Dogi hat teamlage.html. Die Umleitung ist die
Haustrennung bei der Arbeit, kein Fehler. Sie steht jetzt in der
abgeleiteten Liste der zehn.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:32:48 +02:00
DogFatherGitandClaude Opus 5 4a5c69cfc6 Die drei Altlasten: ein echter Befund, zwei Pruefungen mit Zahlen von gestern
Alle drei standen seit dem 22.09. in der Notiz und waren mit `git
stash` als vorbestehend nachgewiesen. Nachgemessen, einzeln behoben.

1. pruef-jeder-hat-eine-seite -- EIN ECHTER BEFUND
   "alle 9 Rollen sind zugeordnet -- fehlt: linke"

   Die LINKE HAND fiel im Steckbrief in den Sammelplatz "Weitere":
   Auf der Uebersicht ueber die Menschen des Hauses stand sie unter
   einer Ueberschrift ohne Bedeutung, neben niemandem. Sie gehoert
   dorthin, wo die rechte Hand steht -- beide fuehren Team Dogi mit.

   Beim Nachgehen fiel dieselbe Luecke an einer zweiten Stelle auf:
   In ROLLEN_GRUPPE (der Auswahl, mit wem man schreiben kann) fehlte
   sie ebenfalls und haette eine eigene Ueberschrift mit genau einem
   Namen darunter bekommen -- also die Rangordnung, die zwei Zeilen
   hoeher ausdruecklich vermieden werden sollte.

   WARUM DIE PRUEFUNG DAS FINDEN KONNTE und ein Mensch nicht: Sie geht
   ALLE Rollen des Hauses durch, nicht die vier, die zufaellig
   angelegt sind. Eine Zuordnung, die man an den vorhandenen Leuten
   prueft, ist eine Aussage ueber die Testdaten.

2. pruef-rollen -- DIE MESSUNG WAR FALSCH, NICHT DIE KACHEL
   "DogFather Kachel https://crew... LANDET AUF start.html"

   DogFather bekommt auf der Agenturadresse die Kachel "Zu Team Dogi".
   Ihr Ziel MUSS eine vollstaendige Adresse sein -- das andere Haus
   liegt auf einem anderen Rechnernamen. Im Server steht das
   ausdruecklich (`aussen: true` an der Kachel, samt Begruendung).

   Die Pruefung klebte jedes Ziel an `BASIS + "/workspace/"`. Bei einer
   vollstaendigen Adresse kommt dabei Unsinn heraus.

   Sie kannte ausserdem nur ZWEI Ausgaenge. Ob die andere Tuer
   aufgeht, laesst sich von hier nicht sagen -- der Browser kennt nur
   BASIS. Das ist der dritte Ausgang, und er wird jetzt als solcher
   gemeldet: 314 Pruefungen, 0 Fehler, 1 nicht nachsehbar. Geprueft
   wird stattdessen, was hier zu pruefen IST: dass die Adresse zu
   einem Haus fuehrt, das dieses Haus kennt (aus CREW_ADRESSE, nicht
   abgeschrieben).

3. pruef-kachelraster -- ZWEI ZAHLEN VON GESTERN, UND EIN MESSFEHLER
   "10 Community-Kacheln" (erwartet 8) und "die doppelt breite Kachel
   steht an erster Stelle (Platz 0)"

   `=== 8` stand in der Ueberschrift, im Text und in der Bedingung. Am
   22.09. sind Kacheln dazugekommen, und die Pruefung wurde rot, ohne
   dass am Raster etwas kaputt war.

   Schwerer wog der zweite Teil: Sie suchte "die Community-Gruppe"
   ueber deren Ueberschrift, mit der letzten Gruppe als Rueckfall. Fuer
   DogFather griff der Treffer (1 Kachel), fuer einen Modi der
   Rueckfall (10) -- und beides hiess in der Meldung
   "Community-Kacheln". Eine Pruefung, die je nach Rolle etwas anderes
   misst, kann ihr Ergebnis nicht erklaeren.

   Jetzt werden ALLE Gruppen gemessen, mit Namen in der Meldung, und
   die Frage ist ueberall dieselbe: Hat das Raster ein Loch? Die
   Kachelzahl steht in der Meldung, nicht in der Bedingung. Die Regel
   "eine doppelt breite Kachel steht vorn" bleibt -- es gibt heute
   keine solche Gruppe mehr, aber sie gilt fuer die naechste, und die
   ZAHL der geprueften Gruppen steht daneben.

   Gemessen sieht DogFather 5 Gruppen (1, 6, 11, 4, 1 Kacheln), ein
   Modi 6. Kein Loch in einer davon. 15 Pruefungen, 0 Fehler.

Mitgelaufen und gruen: pruef-steckbrief, pruef-rechtetafel (19),
pruef-chat.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-23 00:29:25 +02:00
DogFatherGitandClaude Opus 5 6be24e204f B3: Jede Seite traegt ihre Farbe -- auch ganz oben in der Leiste
"je nachdem auf welcher seite ich bin wechseln gaaanz oben in der
leiste gewissene symbole und sachen mit ... ich will das auf jeder
seite ... nicht mehr wie auf screen3 sondern genau gleich wie da."

DER BEFUND WAR EINE LADEREIHENFOLGE, KEIN FEHLENDES BAUTEIL

kopf.js setzt `data-ton` am <body> -- auf JEDER Seite, seit Langem.
Die Regel, die daraus eine Akzentfarbe macht, stand aber in
bereich.css:

    body[data-ton] { --akzent: color-mix(in srgb, var(--ton) 88%, #6f8cab); }

und bereich.css laden genau DREI von fuenfunddreissig Seiten
(bereich.html, bewerben.html, teilen.html). Auf den anderen
zweiunddreissig war die Farbe da und wurde nicht gelesen.

Das erklaert auch, warum ausgerechnet die Highlights-Seite sein
Vorbild war: Highlights IST bereich.html -- eine der drei.

Die Regel steht jetzt in start.css. Die liegt auf allen
fuenfunddreissig.

UND DIE LEISTE SELBST. "gaaanz oben in der leiste" ist woertlich zu
nehmen: Der Akzent wirkte bisher weiter unten (Knopfraender,
Fokusringe, Linien an Karten), die Leiste blieb auf jeder Seite
gleich. Sie bekommt jetzt eine Kante unten in der Farbe der Seite,
nach rechts auslaufend, und die Knoepfe rechts nehmen die Farbe beim
Beruehren auf. Dauerhaft eingefaerbt waeren es sechs bunte Knoepfe in
derselben Farbe -- dann traegt nicht mehr die SEITE die Farbe,
sondern die Leiste.

GEMESSEN, NICHT BEHAUPTET (pruef-kopfleiste-farbe.mjs, NEU, 9/0)

Im echten Browser, mit getComputedStyle -- ob eine CSS-Regel WIRKT,
steht nicht in der Datei:

    aufgaben.html   Ton 13  --akzent  #12b37e (gruen)
    chat.html       Ton  4  --akzent  #c16302 (orange)
    kalender.html   Ton  8  --akzent  #ab68ff (violett)

Welche Seiten gemessen werden, steht NICHT in der Pruefung: Sie liest
die Kacheln der Startseite und nimmt drei mit verschiedenen Toenen.
Eine Liste dort waere die, die beim naechsten Umbau eine Seite nennt,
die es nicht mehr gibt.

Zwei Gegenproben: dass die Farben VERSCHIEDEN sind (vorher war
--akzent auf 32 von 35 Seiten dieselbe -- eine Pruefung ohne diesen
Teil waere auch im alten Zustand gruen gewesen), und dass ohne
`data-ton` wieder die Hausfarbe gilt (#8ec9ff). Eine Regel, die auch
dort zuschlaegt, wuerde eine Farbe erfinden.

EIGENER FEHLER, beim ersten Lauf dieser Pruefung
------------------------------------------------
Der Kachel-Selektor war falsch (`.kachel[href]` statt `li.kachel` mit
dem Verweis darin) -- sie fand null Kacheln. Das haette auffallen
muessen, tat es aber fast nicht: DREI Zeilen waren trotzdem gruen,
weil `every()` auf einem leeren Feld `true` liefert. Genau die Falle,
vor der die Hausregel warnt, und ich bin hineingelaufen. Die Zahl
steht jetzt in jeder dieser Bedingungen.

Mitgelaufen und gruen: pruef-css-klassen (keine Stilvorlage verliert
still eine Regel), pruef-chatkachel (33), pruef-teamlage-karten (22).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:52:27 +02:00
DogFatherGitandClaude Opus 5 189d0b3363 B1: Das Anschlagbrett haelt 24 Stunden -- und sieht aus wie ein Anschlagbrett
"die sachen sollen in der seite vom anschlagbrett immer automatisch
nach 24h von da verschwinden. weil alles hat seine kategorie und was
nicht ist auch nicht um ewig auf der seite zu bleiben fertig."

SEINE BEGRUENDUNG IST DIE REGEL. Ein Anschlagbrett sagt, was GERADE
gilt. Was laenger gilt, hat seinen eigenen Bereich -- Regeln stehen bei
den Regeln, Termine bei "Was ansteht". Eine Ansage vom letzten
Dienstag, die noch haengt, ist keine Ansage mehr, sondern Papier an der
Wand.

DIE DREI ENTSCHEIDUNGEN, DIE ICH TREFFEN MUSSTE -- und woran ich sie
festgemacht habe:

1. AB WANN LAUFEN DIE 24 STUNDEN? Ab `erstellt`, nicht ab `datum`.
   `datum` ist ein vom Team gesetztes Feld und kann in der Zukunft
   liegen (es traegt die Termine). Eine Ansage, die morgen gilt, soll
   morgen verschwinden und nicht uebermorgen.

2. VERSCHWINDET SIE GANZ? Nein. Er sagt "von DA verschwinden" -- von
   der Seite. Geloescht wird nichts: Wer eine Ansage geschrieben hat,
   soll sie wiederfinden. Sie kommt als `abgehaengt` mit und steht
   zugeklappt unter einer leisen Zeile "Abgehaengt (3)". Auf dem Brett
   selbst steht sie damit nicht mehr.

3. WER ENTSCHEIDET? Der Server. Die Stunden im Browser nachzurechnen
   waere eine zweite Fassung derselben Regel, und eine davon waere
   irgendwann aelter. Die Frist geht als Zahl mit der Antwort.

DAS AUSSEHEN ("viel besser gestaltet, übersichtlicher, moderner,
hochwertiger, professioneller"): Was haengt, sieht jetzt aus wie etwas,
das haengt -- kraeftiger Rand links in der Farbe seiner ART (Ansage
babyblau, Neue Regel gold, Hinweis lila, Danke gruen), ein Schein von
links, mehr Luft. Die Art stand bisher nur im Text; jetzt sieht man
sie. Abgehaengtes ist grau statt durchsichtig -- durchsichtig hiesse,
das Buehnenbild scheint durch, also Text auf einem Foto.

pruef-anschlagbrett.mjs (NEU, 12/0) misst beide Seiten der Grenze
(23 h haengt, 25 h nicht), rechnet relativ zur jetzigen Uhrzeit statt
mit einem festen Datum, und hat den Eintrag, an dem sich alles
entscheidet: alt aufgehaengt, Datum von heute. Wer nach `datum`
filtert, laesst ihn haengen. Dazu zwei Gegenproben: auf jedem anderen
Brett gibt es das Merkmal gar nicht, und wo die Grenze WIRKLICH liegt,
wird aus den Eintraegen nachgerechnet statt aus der Zahl im Modul.

NEBENBEFUND, den erst dieser Commit ausgeloest hat
---------------------------------------------------
pruef-bereiche-lesend stuerzte ab: "listen EACCES 127.0.0.1:5040".

Die Portnummern werden aus der Stelle im Alphabet abgeleitet -- heute
sind fuenf neue Pruefdateien dazugekommen, und dadurch ist diese
Pruefung auf die 5040 gerutscht. Die haelt auf diesem Rechner ein
Windows-Dienst (svchost, PID 7136).

`portMussFreiSein` kannte nur ZWEI Antworten: EADDRINUSE oder frei.
EACCES galt als frei -- die Pruefung lief weiter, bis der echte Server
auf demselben Port startete und mit einem unbehandelten Fehler
abstuerzte. Ein Stapelauszug aus node:net, der wie ein Fehler im Code
aussieht.

Jetzt drei Antworten. Und ein belegter Port wird anders behandelt als
ein gesperrter: Belegt geht vorbei (der andere Lauf hoert auf),
gesperrt nie. Abzubrechen hiesse, die Pruefung waere auf diesem Rechner
dauerhaft nicht ausfuehrbar -- die Sorte Warnung, die immer kommt und
deshalb weggeklickt wird. Ausgewichen wird um einen festen Betrag
(+4000), damit die Nummer abgeleitet und eindeutig bleibt.

Mitgelaufen und gruen: pruef-bereiche-lesend, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:47:52 +02:00
DogFatherGitandClaude Opus 5 7c23913347 B2: Die Regeln sind eine Flaeche statt sechs Kacheln
"lass bitte die ganzen regeln viel geiler und spezieller aussehen und
nicht sehr viele kacheln sondern eine riesige wo alles schön aussieht
und richtig geil, übersichtlich"

Vorher sechs Kaesten untereinander: jeder mit Rand, Grund und Abstand,
dazwischen jedes Mal ein Schnitt. Beim Lesen faengt man damit sechsmal
neu an -- Regeln lesen sich aber als EIN Text, nicht als sechs
Merkzettel.

JETZT EINE FLAECHE. Die Abschnitte bleiben, ihre Kaesten nicht:
innerhalb der Flaeche trennt eine Linie statt einer Luecke. Dazu ein
Schein in der Hausfarbe oben links, der nach einem Drittel ausgelaufen
ist -- Text auf einem Verlauf liest sich unruhig, und diese Flaeche ist
zum Lesen da.

UEBERSICHTLICH HEISST: EINE SPRUNGLEISTE. Eine lange Flaeche ohne
Wegweiser ist nicht uebersichtlicher als sechs Kaesten, nur laenger.
Die Leiste klebt oben, nennt alle Abschnitte und hebt den hervor, in
dem man gerade steht (IntersectionObserver -- beim Rollen zu rechnen
kostet auf einem Handy spuerbar Strom).

SIE WIRD GELESEN, NICHT GEPFLEGT: Die Eintraege kommen aus den
Ueberschriften, die ohnehin dastehen, und fehlende ids entstehen
dabei. Eine Liste von Hand waere die, die beim siebten Abschnitt
fehlt -- und niemand merkte es, weil die Seite ja funktioniert.

Die fuenf Regeln tragen ihre Zahl jetzt in einem eigenen Kreis. Die
wichtigste Liste der Seite sah aus wie jede andere Aufzaehlung.

ZWEI DINGE, DIE ERST DAS BILDSCHIRMFOTO GEZEIGT HAT

1. AUF DEM HANDY BRAUCHTE DIE LEISTE SECHS ZEILEN -- rund ein Drittel
   des Bildes, und sie klebt oben fest, also dauerhaft. Ein Wegweiser,
   der mehr Platz braucht als der Weg, ist keiner. Jetzt eine Zeile,
   die man seitlich schiebt, mit scroll-snap. Am Rechner bleibt der
   Umbruch: Dort ist Platz, und alles auf einen Blick schlaegt alles
   hinter einer Schiebebewegung.

2. DANACH WAR SIE GANZ WEG -- hinter der Kopfleiste. Ursache:
   `--kopf-hoehe` wurde nur in chat.js gemessen. Auf jeder anderen
   Seite galt der Rueckfallwert 64 px, und auf einem 390-px-Schirm ist
   die Kopfleiste rund 115 px hoch.

   Eine Zahl, die eine Seite misst und eine andere raet, ist schlimmer
   als gar keine: Auf der einen stimmt sie, auf der anderen nicht, und
   niemand sucht den Fehler bei einer Zahl. Die Messung steht jetzt in
   kopf.js -- die Datei liegt auf JEDER Seite -- und zaehlt wie vorher
   Kopfleiste plus Band mit dem fremden Namen, bei jeder Aenderung neu.
   chat.js ruft sie nur noch auf.

Mitgelaufen und gruen: pruef-treff (80/0), pruef-treff-werkzeuge
(73/0), pruef-chat-optik, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:41:47 +02:00
DogFatherGitandClaude Opus 5 73facb7ce9 Nachtrag zu B4: die Aufraeumung lief nie -- .changes an der falschen Stelle
WAS PASSIERT IST

Der Commit 60802170 ist um 23:33 ausgeliefert worden. Im Protokoll des
Servers stand danach:

    [workspace] undefined zurueckgenommene Nachrichten endgueltig entfernt.
    [workspace] 4 blaue Herzen auf babyblau umgestellt

Die zweite Zeile stimmt. Die erste ist der Befund: `undefined` statt
einer Zahl. Nachgesehen in der Live-Datenbank -- die fuenf
zurueckgenommenen Zeilen waren noch da.

URSACHE: `d.prepare("DELETE ...").changes` statt `.run().changes` --
also die Eigenschaft der vorbereiteten ANWEISUNG, nicht die des Laufs.
Die Anweisung wurde vorbereitet und nie ausgefuehrt. Nichts stuerzte
ab, nichts war rot, kein Fehler im Protokoll.

NEBENFOLGE, die es schlimmer gemacht haette: Die Sicherung wird VOR
dem Loeschen geschrieben. Da nie geloescht wurde, blieb die Bedingung
erfuellt -- bei JEDEM Neustart waere eine weitere Sicherungsdatei
entstanden. Genau das, wovor der Kommentar zwei Zeilen darueber warnt.
Ein Kommentar, der vor einem Fehler warnt, verhindert ihn nicht.

WAS JETZT ANDERS IST

Behoben, und die Umstellung ist eine exportierte Funktion geworden:
`loeschspurenAufraeumen(d, dbPfad)`. Nicht aus Ordnungsliebe -- eine
Umstellung, die tief im Hochfahren steckt, kann keine Pruefung
aufrufen. Eine Funktion schon.

pruef-loeschen.mjs (20 -> 25): stellt den alten Zustand her (Text leer,
weg_am gesetzt), ruft die Funktion und misst
  * dass sie eine ZAHL meldet (`typeof === "number"`) -- genau hier
    stand undefined, und 0 sieht in einer Meldung fast so aus,
  * dass die Zeile wirklich verschwindet,
  * und dass beim zweiten Aufruf nichts mehr passiert und nichts
    gesichert wird.

Ohne den ersten dieser drei Haken waere der Fehler auch beim naechsten
Mal durchgegangen: Eine Meldung mit `undefined` ist gruen, solange
niemand sie liest.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:36:02 +02:00
DogFatherGitandClaude Opus 5 60802170a1 B4 + B5: Loeschen heisst Loeschen, die Schrift wechselt mit, und Blau wird Babyblau
Die beiden Auftraege gehoeren zusammen, und zwar in dieser Reihenfolge:
Eine babyblaue Kachel ist HELL. Ohne mitwechselnde Schrift waere sie
unlesbar (1,63:1 gemessen). Erst B4 macht B5 moeglich.

B4a -- LOESCHEN HEISST LOESCHEN
  "Geloeschte Nachrichten verschwinden vollstaendig - keine Spur, kein
   'wurde geloescht'-Hinweis, bei niemandem, auch nicht bei DogFather."

Bis heute blieb die Zeile stehen: Text geleert, weg_am gesetzt, und im
Chat stand "Nachricht zurueckgenommen". Das war ausdruecklich so
begruendet ("ein Loch im Verlauf wirft mehr Fragen auf"). Das Argument
beantwortet aber eine andere Frage: Ein Hinweis "hier stand etwas"
MARKIERT die Stelle. Wer etwas aus Versehen schreibt, will es weg
haben und nicht unterstrichen.

Jetzt ein echtes DELETE. Vier Raender, an denen eine Spur bleiben
koennte, alle gemessen:
  1. die Zeile selbst
  2. chat_reaktionen    (ON DELETE CASCADE - nachgesehen, nicht angenommen)
  3. chat_erwaehnungen  (ebenso)
  4. letzte_am am Raum  - wird neu gerechnet, sonst stuende er oben in
                          der Liste mit einem Zeitpunkt, zu dem es
                          nichts mehr gibt
Dazu: ein Zitat auf eine geloeschte Nachricht wird weggelassen; in der
Gespraechsliste steht kein Hinweis mehr; der Knopf heisst "loeschen".

Die 5 alten zurueckgenommenen Zeilen (Text bereits leer) raeumt eine
einmalige, wiederholbare Umstellung ab - mit Sicherung davor, und nur
wenn es wirklich etwas zu tun gibt.

B4b -- WER DARF WAS
  "jeder nur seine eigenen - ausser DogFather und rechte Hand"
`darfJedeNachrichtLoeschen` = admin oder hand. NICHT fuehrtTeamDogi
(das schloesse die linke Hand ein) und nicht istLeitung (das schloesse
Spicy Media ein, die private Chats nicht einmal sehen darf). Das Recht
kommt vom Server ins Skript, nicht aus einer Rolle im Browser: chat.js
bekommt jeder, der die Seite oeffnet.

B4c -- DIE SCHRIFT WECHSELT MIT
  "am besten schwarz auf hellen Kacheln - und weiss, wenn jemand eine
   schwarze Kachel waehlt"
`schriftFuer(farbe)` waehlt zwischen zwei Paaren, gerechnet aus der
Leuchtdichte, mit denselben Schwellen wie das Rechenwerkzeug (7:1 fuer
den Text, 4,5:1 fuer die Fusszeile). Keine dritte Spalte in
CHAT_KACHELN, die jemand pflegen muesste. Flaeche und Schrift werden
im Browser in EINEM Griff gesetzt (blaseFaerben) - zwei Stellen waeren
irgendwann eine helle Kachel mit heller Schrift.

B4d -- DIE NAMEN
Der Name ist jetzt ein eigener Streifen mit Kante darunter, .84rem,
und der Rollenpunkt wird ein 3x14-Balken. Vorher stand er als erste
ZEILE in der Blase und las sich wie der Anfang des Satzes.

B5 -- BABYBLAU
  "jedes normales blaues herz durch babyblaues herz ersetzen ... jeder
   normale blaue farbe, sei es die kachel im chat oder emojis, nur
   babyblau bitte."
* Herz: U+1F499 -> U+1FA75. Nicht geglaubt, sondern gemessen: 43,9 px
  breit wie die anderen Herzen, ein Ersatzkaestchen waere 20,7. Die
  vier vorhandenen blauen Herzen in der Datenbank wandern mit - sonst
  waeren es vier Reaktionen, die ERLAUBT nicht mehr kennt: still weg.
* Kachel: neue, HELLE Kachel "Babyblau" mit dem Wert von --akzent.
  Gemessen: Text 10,78:1, Fusszeile 4,87:1. Sie steht bewusst nicht in
  der Rechnung des Werkzeugs (das rechnet elf Toene auf EINE
  Leuchtdichte) - sie hat eine andere Leuchtdichte und dafuer ihre
  eigene Schrift. Dasselbe Versprechen, anderer Weg.

PRUEFUNGEN
  pruef-loeschen.mjs (NEU, 20/0): alle vier Raender, die vier Faelle
    der Rechtegrenze (auch: die linke Hand darf NICHT), das babyblaue
    Herz am laufenden Server, und dass der Satz "Nachricht
    zurueckgenommen" nur noch in Kommentaren steht - mit Gegenprobe,
    dass die Suche diesen Unterschied wirklich macht.
  pruef-chatkachel.mjs (33/0): misst jede Kachel mit IHRER Schrift und
    fragt dafuer dieselbe Funktion wie der Server. Neu: dass die
    Schrift ueberhaupt wechselt. Die Leuchtdichte-Regel gilt jetzt fuer
    die gerechneten Toene - das Versprechen dahinter loest die
    Kontrastzeile darueber direkt ein.
  Vier alte Pruefungen umgedreht, die den alten Zustand festgeschrieben
    hatten: pruef-chat, pruef-chat-ausbau, pruef-chat-aufloesen,
    pruef-chat-optik. Alle mit scharferer Messung als vorher (Zahl
    davor/danach statt "ein Hinweis ist da").
  Mitgelaufen und gruen: pruef-alle-sehen-es, pruef-treffchat (110/0).

Gesichert: workspace-vor-loeschumbau-20260922-233313.db
(946 KB, integrity_check ok, 111 Nachrichten, 49 Reaktionen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:33:43 +02:00
DogFatherGitandClaude Opus 5 95da1345fc B9: In einen Kategorie-Kanal gehoert Team Dogi -- und alle davon
VanVans Befund, von Filipe weitergegeben:
  * "Patrick und BananaStift (stifti) aus der Erwaehnen-Liste
     entfernen -- sie stehen dort als SCOUT."
  * "Die Modis zum Erwaehnen hinzufuegen."
  * "Die Modis sehen den Chat Moderation auch gar nicht."

AN DER LIVE-DATENBANK NACHGEMESSEN, bevor etwas gebaut wurde:

    Raum 3  kanal  Chat-Moderation   admin, hand, SCOUT, SCOUT, linke
    Raum 7  kanal  Der Treff         admin, hand, 4x modi, linke, 3x gast
    Raum 8  gruppe Dogi und Modis    admin, hand, 4x modi, linke
    Raum 9  gruppe Abmeldungen       admin, hand, 4x modi, linke

Damit waren alle drei Punkte EIN Befund. Die Erwaehnen-Liste im
Browser zeigt genau `offen.teilnehmer`, also die Teilnehmer des Raums
(teilnehmerVon) -- eine zweite Quelle gibt es nicht. Standen dort zwei
Scouts und kein Modi, dann schlug sie Scouts vor, und die Modis sahen
den Kanal gar nicht. An der Erwaehnung selbst war nichts kaputt.

DIE REGEL

Ein Kategorie-Kanal gehoert Team Dogi: admin + TEAM_DOGI_ROLLEN
(hand, linke, modi), abgeleitet aus der einen Liste des Hauses. Der
Abgleich beim Blick in die Gespraechsliste heilt jetzt in BEIDE
Richtungen:

  hinein  jeder aktive Mensch aus Team Dogi, der im Raum NOCH NIE eine
          Zeile hatte
  hinaus  jeder aktive Teilnehmer, dessen Rolle nicht dazugehoert
          (raus_am, kein DELETE -- der Verlauf bleibt lesbar)

"NOCH NIE EINE ZEILE" ist der wichtige Teil: Wer ueber die
Mitglieder-Route bewusst herausgenommen wurde, hat eine Zeile mit
raus_am und wird NICHT zurueckgeholt. Ein Abgleich, der eine
Entscheidung von Hand beim naechsten Seitenaufruf ueberschreibt,
macht die Route wertlos -- dieselbe Ueberlegung wie bei
treffAngleichen(). Der Treff bleibt ausgenommen: Dort gehoert die
Community dazu.

Dazu dieselbe Schranke an beiden Schreibwegen (Kanal anlegen und
umbesetzen). `darfSchreibenMit` beantwortet eine ANDERE Frage -- "darf
ich diesen Menschen ueberhaupt anschreiben" -- und sagt bei einem
Scout zu Recht ja. Genau diese Luecke hat die zwei Scouts in den
Moderations-Kanal gebracht.

WARUM NICHT "NUR DIE ZUSTAENDIGEN"

Weil es die Zuordnung nicht gibt: `kategorienFuer` gibt JEDEM aus Team
Dogi ALLE Kategorien, eine Tabelle Person -> Kategorie existiert
nirgends. Eine Regel "nur die Zustaendigen" waere eine Liste, die
niemand pflegt. Wer einen engeren Kanal will, nimmt jemanden heraus --
und das haelt.

PRUEFUNGEN

  pruef-kanal-besetzung.mjs (NEU, 16/0): baut die gemeldete Lage nach
  (Scout drin, kein Modi), laesst den Abgleich darueberlaufen und
  misst beide Richtungen. Vier Gegenproben: der von Hand Entfernte
  bleibt draussen; ein Scout kommt auch ueber die Mitglieder-Route
  nicht hinein; der Gast bleibt im Treff; und ein wieder
  hereingeschmuggelter Scout fliegt beim naechsten Abgleich erneut
  hinaus -- die Regel wirkt dauerhaft, nicht einmalig.

  pruef-chat-kanaele.mjs (79 mit 3 Fehlern -> 81/0): Die Zeile "wer
  nicht drin ist, sieht ihn nicht" hat den alten Zuschnitt
  festgeschrieben -- sie prueft jetzt die schaerfere Grenze: wer
  HERAUSGENOMMEN wurde, bleibt draussen, auch nach dem naechsten
  Abgleich. Dieser Weg war bis heute ungeprueft.

Mitgelaufen und gruen: pruef-chat, pruef-treffchat (110/0).

Vor dem Ausliefern gesichert: workspace-vor-kanalregel-20260922-231409.db
(946 KB, integrity_check ok, 17 Personen, 37 Teilnehmerzeilen,
111 Nachrichten).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 23:14:38 +02:00
DogFatherGitandClaude Opus 5 803750edbc Aufgaben verteilen: der Knopf ist nie mehr tot, und die Bewerbung steht im Formular
screen1 -- „dogfather, die rechte hand und die linke hand sollen immer
noch aufgaben werden teilen können plus die option dass die modis sich
für aufgaben bewerben können. weil gerade hängt das und weiß nicht
wieso."

WAS WIRKLICH LOS WAR -- gemessen, nicht geraten

Auf entwicklung.html stand oben „Aufgabe verteilen · Wähl LINKS
jemanden aus", und der Knopf war so lange abgeschaltet. Im Browser
nachgemessen (1420 px, als DogFather):

    Band          oben 284 px, linke Kante 130 px
    Personenwahl  oben 490 px, linke Kante 130 px
    -> UNTER dem Band, 127 px darunter, gleiche linke Kante

Links war nichts. Wer der Anweisung folgte, schaute auf eine leere
Fläche und hatte einen Knopf, der nicht ging. Das Recht selbst war die
ganze Zeit richtig: `darfAufgabenVerteilen` = Leitung oder Hand, also
DogFather, rechte Hand UND linke Hand -- alle drei mit
`darf_verteilen: true` gemessen.

Kurz: Die Regel stimmte, der Weg dorthin nicht.

WAS JETZT ANDERS IST

1. DER KNOPF IST IMMER BENUTZBAR. Er öffnet das Formular, auch ohne
   vorherige Auswahl.
2. DIE FRAGE „für wen" STEHT IM FORMULAR, als erste Zeile, mit allen
   Personen zur Wahl. Wer unten eine Kachel angeklickt hat, findet sie
   angehakt wieder -- beide Wege führen zum selben Ziel.
3. EINE LISTE STATT ZWEIER. „Noch jemanden dazunehmen" ist weg. Es
   waren zwei Bedienungen für dieselbe Frage -- und die
   Bewerbungs-Option steckte ausgerechnet in der zugeklappten
   zweiten: Sie war nur zu finden, wenn man erst aufklappte UND dort
   jemanden ankreuzte. Eine Möglichkeit, die man nicht findet, gibt es
   nicht.
4. DIE BEWERBUNG STEHT DA, sobald zwei Leute angehakt sind: „Wer
   zuerst Zeit hat, übernimmt. Sie bewerben sich, du nimmst an oder
   lehnst ab."

ZWEI FEHLER, DIE DABEI AUFFIELEN

* Nach dem Anlegen wurde `fuerPerson` auf null gesetzt und DANACH
  `aufgabenZeigen(fuerPerson, …)` aufgerufen -- die Liste, die zeigen
  soll, was gerade entstanden ist, blendete sich damit aus. Die Namen
  werden jetzt festgehalten, bevor `reset()` sie abräumt.
* Die Bestätigung sagte immer „steht jetzt bei ihm" -- `fuerName` wird
  nur beim Klick auf eine Kachel gefüllt. Sie sagt jetzt, was wirklich
  passiert ist, und bei einem Pool, dass eine Bewerbung kommt.
* `e-mehr-art` heisst `e-art`: Der Name sagte „gehört zu ‚noch
  jemand'", und das gibt es nicht mehr. Dieselbe Sorte Falle wie
  `tperson__namen` heute Nachmittag.

DIE PRÜFUNG HATTE MEINEN FEHLER FESTGESCHRIEBEN

`pruef-bewerbung-aufgaben.mjs` enthielt wörtlich:

    ok(vorher.aus === true,
      "und ist aus, solange niemand gewaehlt ist");

Sie lief, sie war grün, und sie hat den toten Knopf verteidigt. Das
ist die unangenehmste Sorte: nicht übersprungen, nicht kaputt --
sondern eine Bestätigung meines Entwurfs statt der Sache. Jetzt wird
das Gegenteil verlangt.

Dazu zwei neue Abschnitte (84 -> 101 Prüfungen, 0 Fehler):
  6b  verteilen OHNE vorherige Auswahl, als Pool, samt Nachweis am
      Server (verteilart=pool, zwei Leute darin) und der Meldung, die
      nicht „bei ihm" sagen darf
  6c  alle drei Rollen am Bildschirm: DogFather, rechte Hand, linke
      Hand -- mit Gegenprobe, dass ein Modi das Band NICHT sieht

EIGENER MESSFEHLER, offen notiert: Mein erster Versuch, die Bewerbung
nachzustellen, meldete „kein Abruf, nichts passiert". Der Knopf öffnet
eine Rückfrage, und die hatte ich nicht beantwortet. Die Bewerbung war
nie kaputt -- meine Messung war es. Erst der zweite Anlauf zeigte den
ganzen Weg: POST /api/aufgaben/1/bewerben -> {"ok":true,"zustand":"beworben"}.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 20:18:35 +02:00
DogFatherGitandClaude Opus 5 ba0e326585 Team-Lage: fuenf Stufen mit eigener Farbe, Karten neu gebaut, 404 wirft nicht mehr hinaus
B7 -- "wenn ich auf diese sachen drücke werd ich auf die startseite
geschickt" und "ich will das es ein zwei kategorien mehr gibt und das
soll geiler aussehen und jede seine eigene farbe, stark erkennbar"

1. DER RAUSWURF. Ein Druck auf einen Stufen-Knopf schickte auf die
   Startseite. Ursache: `hole()` stand ACHTMAL Zeichen fuer Zeichen
   gleich in acht Dateien, und darin warf JEDER 404 hinaus -- auch der
   auf eine blosse Handlung. Jetzt eine gemeinsame `assets/js/holen.js`
   mit der engeren, abgeleiteten Regel: Ein 404 wirft nur, solange die
   Seite noch gar nichts bekommen hat.

2. ZWEI STUFEN MEHR, und keine davon erfunden: "Fortgeschritten" gibt
   es im Entwicklungs-Katalog laengst (ENTWICKLUNG_ERWARTUNG), hier
   fehlte genau diese Mitte; "Vertretung" stand bis heute IN der
   Beschreibung von Senior. Keine Datenbankaenderung noetig -- die
   Spalte ist absichtlich ein TEXT ohne CHECK.

3. DIE FARBEN SIND GERECHNET. Nachgemessen lagen "Probe" und
   "Standard" bei 0,0576 OKLab-Abstand; MINDEST_ABSTAND ist 0,090 --
   die beiden waren nebeneinander dieselbe Farbe, und alle drei lagen
   unter MINDEST_BUNTHEIT. Die neuen fuenf sind ein Faecher aus fuenf
   Farbwinkeln im Abstand von 72 Grad; der Versatz ist der, bei dem der
   kleinste Abstand am groessten wird. Ergebnis: 0,1531 untereinander,
   0,1108 zur Rollenmarke daneben, Kontrast 7,4 bis 8,6.

B8 -- "die sollen viel krasser geiler und übersichtlicher sein ... und
die kacheln sollen viel krass geiler und spezieller aussehen auch der
hintergrund, veränder das komplett"

4. DIE KARTE IST NEU: Kopfband in der Farbe der Stufe bis an die
   Kanten, Zeichen von 44 auf 52 px mit Ring, Zahlenband als eigene
   Flaeche, neuer Hintergrund (Farbschein unter dem Kopfband, feine
   Schraffur, dunklere Platte). 781 px hoch gemessen, danach 746.

5. DIE ROLLE STEHT JETZT DA -- als Marke auf der Karte und als
   Ueberschrift ueber jeder Gruppe. Sortiert war schon vorher nach
   Rolle; man konnte es nur nicht sehen.

DREI FEHLER, DIE DABEI AUFFIELEN

* `auto-fit` liess die einzelne Karte der rechten Hand ueber die ganze
  Bildschirmbreite laufen, sobald gruppiert wurde. `auto-fill` haelt
  die leeren Spalten offen.
* Der Name der Person trug `tperson__namen` statt `tperson__name` --
  ein Buchstabe, und damit die Klasse fuer graues Kleingedrucktes. Auf
  einer Seite ueber Personen war der Name kleiner als die Beschriftung
  darunter. Gefunden hat es die neue Pruefung, die ueberall "?" las.
* `stufeSetzen()` suchte das Stufen-Schild mit
  `[class*="tmerkmal--"]:not(...)` -- einer Aufzaehlung dessen, was es
  NICHT ist. Sobald die Rollenmarke davorstand, traf die Suche sie:
  Ein Druck auf "Standard" haette aus "Modi" das Wort "Standard"
  gemacht. Und die Karte faerbte sich beim Setzen nicht mit um.

DREI PRUEFUNGEN, ALLE MIT GEGENPROBE

* pruef-holen.mjs (NEU, 14): fuehrt die echte Datei aus und misst fuenf
  Wege; dieselben fuenf noch einmal an der ALTEN Fassung, die bei genau
  zwei durchfallen muss. Dazu: laedt jede der acht Seiten holen.js, und
  zwar VOR ihrem Skript.
* pruef-teamlage-karten.mjs (NEU, 22): im Browser. Gruppen, Rollenwort,
  Stufenknoepfe nur bei Modis, der Druck selbst (kein Sprung, ein
  Abruf, Schild und Kartenfarbe ziehen mit), Gegenprobe mit dem zweiten
  Druck, und die neuen Baender auf 390 px.
* pruef-team-stufen.mjs (28 -> 47): die abgeschriebene Liste
  ["probe","standard","senior"] ist raus -- geprueft werden jetzt
  Eigenschaften und die Farbabstaende, gelesen aus team.css. Gegenprobe
  ist der Stand von gestern, der durch dieselbe Messung faellt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 19:46:47 +02:00
DogFatherGitandClaude Opus 5 3b76a9aab5 screen1 + A5 + B6: „wer zuerst Zeit hat" gilt wieder, und Aufgaben entstehen dort, wo die Person steht
DREI SACHEN, EIN ZUSAMMENHANG.

--- screen1 --------------------------------------------------------
Filipe zu meinem eigenen Satz „wer zuerst Zeit hat — genau das geht ja
nicht mehr": „falls das nicht mehr geht mach das es geht wenn es wieder
geht ist alles gut."

Er hat recht, und ich hatte zu schnell aufgegeben. „Wer zuerst Zeit
hat" muss nicht heissen, dass man sich selbst bedient -- es kann
genauso heissen, dass die ERSTE BEWERBUNG zuerst drankommt. Damit gilt
beides: Die Leitung entscheidet (sein Wunsch von vorhin), und wer
schnell ist, hat den Vorteil (sein Wunsch von eben).

Die Bewerbungen werden jetzt nach EINGANG sortiert, nicht nach Namen
-- die Abfrage sortiert sonst alphabetisch, und dann haette nicht der
Schnelle den Vorteil, sondern Frida. Der Erste bekommt die Marke
„zuerst da" (nur bei mehr als einer -- sonst ist es keine Auskunft,
sondern Fuellwerk).

Geprueft mit Absicht gegen das Alphabet: Nele bewirbt sich zuerst und
steht vorn, obwohl Frida im Alphabet vor ihr kaeme.

--- B6: der Knopf auf dem Aufgabenbrett ----------------------------
Filipe: „dieser button kann da jetzt doch endlich verschwinden, auf
dieser seite sollen ja keine aufgaben mehr verteilt werden."

ER HAT DABEI AUF DEN TEAM-DOGI-BILDSCHIRM GESEHEN, und das ist der
Unterschied zwischen „weg damit" und „weg damit, aber gemessen":

    Rolle/Haus        aufgaben.html  entwicklung.html  darfAnlegen
    manager/agentur   ja             NEIN              ja
    creator/agentur   ja             NEIN              ja
    scout/agentur     ja             NEIN              ja
    spicy/agentur     ja             NEIN              ja

Haette ich den Knopf einfach entfernt, koennten vier Rollen gar keine
Aufgabe mehr anlegen. Der Server nennt deshalb den ORT, und er leitet
ihn aus den KACHELN der Person ab -- nicht aus dem Seitenrecht (dann
haette DogFather auf der Agenturadresse den Knopf verloren, denn
oeffnen darf er die Seite, nur hat er dort keine Kachel dorthin) und
schon gar nicht aus dem Haus.

--- A5: anlegen, wo die Person steht -------------------------------
Filipe: „dieser buttion da soll nicht einen zu der seite aufgaben
fuehren sondern da in dieser seite die aufgaben erstellen und vergeben
koennen. plus man soll die aufgaben hier in dieser seite auch sehen."

Der Knopf war ein Link auf `aufgaben.html?neu=1`. Jetzt oeffnet er ein
Formular an Ort und Stelle. DREI FELDER, NICHT ZWOELF: Wer hier steht,
hat die Person schon gewaehlt; was fehlt, ist was, bis wann und ob
noch jemand mitmacht. Das grosse Formular auf dem Brett bleibt fuer
den Fall, dass man eine Aufgabe fuer irgendwen irgendwo anlegt -- zwei
vollstaendige Masken fuer dieselbe Sache waeren zwei Gelegenheiten,
eine davon zu vergessen.

Dazu die Aufgaben der gewaehlten Person, auf derselben Seite. Sie
kommen beim Auswaehlen und nicht auf Knopfdruck: Wer jemanden
durchgeht, will wissen, was bei ihm liegt.

Ohne Person ist der Knopf AUS statt weg -- sonst springt die Seite beim
Auswaehlen -- und der Satz daneben sagt, was fehlt.

Gemeldet wird, was der Server WIRKLICH gesetzt hat: `zuteilen` kann
eine Person weglassen (gesperrter Zugang). Wer das verschweigt, laesst
jemanden im Glauben, er habe drei Leute eingetragen.

--- EIN FUND AUF DEM EIGENEN BILDSCHIRMFOTO ------------------------
Die Bestaetigung „Clips vom Samstag schneiden steht jetzt bei Rieke."
stand in WARNROT -- `melde` schreibt immer in denselben Absatz, und
der heisst `.fehler`. Nicht schlimm und genau deshalb heimtueckisch:
Wer Bestaetigungen in Rot liest, sucht den Fehler, und wer sich daran
gewoehnt, ueberliest die echte Warnung. `melde` kennt jetzt eine gute
Nachricht; die Vorgabe bleibt „Fehler", damit die neun vorhandenen
Aufrufe nicht stillschweigend umgefaerbt werden.

GEPRUEFT
pruef-bewerbung-aufgaben 84/0 (von 66) -- neu: die Reihenfolge nach
Eingang mit Gegenprobe gegen das Alphabet, und ein Abschnitt, der A5
und B6 am echten Bildschirm durchspielt (Knopf weg auf dem Brett, kein
Link mehr auf der Entwicklungsseite, Formular oeffnet dort, Aufgabe
steht sofort in der Liste darunter UND wirklich in der Liste des
Servers, Bestaetigung als gute Nachricht gekennzeichnet).

Gruen: pruef-entwicklung, pruef-aufgabenbrett, pruef-css-klassen,
pruef-formulare, pruef-struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 19:09:16 +02:00
DogFatherGitandClaude Opus 5 43545e4acd A4: Bewerben statt selbst nehmen
Filipe, 22.09.2026: „die modis und linke hand sollen da nichts
uebernehmen koennen von aufgaben, ueberhaupt ueberall sollen die keine
aufgaben selber uebernehmen die ihnen nicht zugetragen sind. ich will
dass die sich fuer aufgaben bewerben koennen aber die rechte hand oder
dogfather muessen annehmen oder ablehnen koennen und das mit einem
kommentar als moeglichkeit sogar noch zum hinzufuegen."

ZWEI FRAGEN, DIE MAN AUSEINANDERHALTEN MUSS -- und das war der Schluessel:

    verteilen    eine Aufgabe an ANDERE geben
    entscheiden  bestimmen, wer sie am Ende macht

Sein Satz vom selben Tag („rechte hand linke hand und dogfather ...
koennen alle verteilen") widerspricht dem nicht, er beantwortet die
erste Frage. Die linke Hand verteilt, entscheidet aber nicht -- sie
bewirbt sich wie ein Modi. `entscheidetUeberAufgaben` steht neben
`darfAufgabenVerteilen`, und drei Stellen fragen ab jetzt dieselbe
Funktion.

DAS VERBOT HATTE DREI TUEREN, und die zweite und dritte waren beim
Planen nicht zu sehen:

  1. aus dem Pool „uebernehmen"  -- die offensichtliche
  2. beim Pool „annehmen"        -- dasselbe unter anderem Namen: Wer
                                    zusagt, nimmt sie den anderen weg.
                                    Bei „einzeln"/„mehrere" bleibt es
                                    erlaubt -- dort wurde sie ihm
                                    ZUGETRAGEN, und genau das Wort
                                    steht in seinem Satz.
  3. beim Verteilen sich selbst eintragen -- die linke Hand darf
                                    verteilen, haette sich also selbst
                                    nehmen koennen. Abgelehnt statt
                                    still gefiltert: Wer sich eintraegt
                                    und sich danach nicht findet, sucht
                                    den Fehler bei sich.

EIN FUND, OHNE DEN A4 GAR NICHT FUNKTIONIERT HAETTE
Die rechte Hand soll entscheiden -- und sah die Aufgabe nicht, um die
es ging. Gemessen an einer Pool-Aufgabe, die DogFather fuer zwei Modis
angelegt hat:

    DogFather    sieht sie    1 Bewerbung
    Modi         sieht sie    1 Bewerbung
    rechte Hand  SIEHT SIE NICHT (Liste leer)

Ihre Sichtregel sammelte Menschen mit einer TEAM_DOGI_ROLLE und fragte,
ob einer als Creator, Verantwortlicher oder Ersteller eingetragen ist.
Bei einer Pool-Aufgabe bleibt `verantwortlich_id` leer (das ist ihr
Sinn), und der Ersteller war DogFather -- der in dieser Liste nicht
steht. Alle drei Bedingungen liefen ins Leere.

Auf der Adresse von Team Dogi sehen die Haende jetzt alles. Das ist
zugleich sein Satz „sehen alle aufgaben". Die Haustrennung bleibt:
`sichtbar()` haengt fuer crew weiterhin `AND ohneAgentur(...)` davor.

WIE DIE BEWERBUNG GEBAUT IST
Kein zweiter Tisch, sondern ein weiterer Zustand derselben Zeile
(`beworben`). Die Frage „wie steht diese Aufgabe bei DIESEM Menschen"
wird dort schon beantwortet; eine zweite Tabelle haette zwei Wahrheiten
ueber dieselbe Beziehung.

Die Worte der Person (`grund`) und der Kommentar der Leitung
(`entscheid_text`) stehen in ZWEI Feldern. In dasselbe waere bequemer
und wuerde die Frage mit der Antwort ueberschreiben -- danach wuesste
niemand mehr, worum jemand gebeten hat. Dasselbe gilt, wenn eine
Bewerbung wegfaellt, weil jemand anders die Aufgabe bekommt: Der
Hinweis kommt in das Feld der Leitung, ihre Worte bleiben stehen.

Der Kommentar ist FREIWILLIG. Die Begruendung beim Ablehnen einer
zugeteilten Aufgabe bleibt Pflicht -- dort sagt jemand ab, der gefragt
wurde. Hier bittet jemand; ein „bitte" braucht keine Begruendung.
Filipes Wort ist „als moeglichkeit".

Die CHECK-Regel wurde ueber `checkListeErweitern` erweitert -- den Weg,
der seit dem 09.09. an einer Stelle steht, mit Sicherung vorher,
Spaltenliste aus PRAGMA und Indizes, die mitgehen.

UND EIN SATZ, DER NICHT MEHR STIMMTE
„Frei fuer 3 Leute — wer zuerst Zeit hat" war die Beschreibung des
Pools, solange sich jeder selbst bedienen durfte. Er sagt jetzt jedem,
was FUER IHN gilt.

GEPRUEFT
Neu: server/pruef-bewerbung-aufgaben.mjs, 66/0 -- die Regel selbst,
alle drei Tueren, der erlaubte Weg, die zwei Felder, das Zurueckziehen,
und ein Abschnitt am echten Bildschirm (ein Modi sieht „Ich bewerbe
mich" statt „Ich uebernehme das"; die rechte Hand sieht die Bewerbung
mit Annehmen und Ablehnen; die Bewerberin sieht KEINEN Block zum
Entscheiden -- sonst waere das Verbot einen Knopf weiter offen).

pruef-zuteilung auf die neue Regel umgestellt (sie hielt „Bea
uebernimmt sie" fest und wurde zu Recht rot) -- misst jetzt denselben
Effekt ueber den neuen Weg. Dazu gruen: pruef-aufgabenbrett,
pruef-meldungen, pruef-sicht, pruef-css-klassen.

ALTLAST, nicht von hier: pruef-rollen meldet einen Fehler an der
Kachel „Zu Team Dogi" (absolute Adresse). Mit `git stash` nachgemessen
-- vorher und nachher identisch.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 18:55:06 +02:00
DogFatherGitandClaude Opus 5 b79b75ab70 A3: Calls & Protokolle gibt es jetzt auch bei Team Dogi
Filipe, 22.09.2026: „ich will diese kachel vom workspace auch im team
dogi seite. ich will dass jeder immer nur seine eigenen sachen von
seinem kalender sieht mehr nicht. perfektioniere das bitte. jeder der
einen kalender hat soll auch sowas haben danke."

GEMESSEN, BEVOR GEBAUT WURDE:

    Rolle   Kacheln   Kalender   Calls
    admin      31       ja        NEIN
    hand       31       ja        NEIN
    linke      30       ja        NEIN
    modi       26       ja        NEIN
    gast       12       nein      nein

Die Community hat keinen Kalender. Sein Satz „jeder der einen kalender
hat" beschreibt die Lage also genau -- „alle bekommen es" waere falsch
gewesen.

ES IST EINE REGEL, KEINE VIERFACHE EINTRAGUNG. Hinter jeden Kalender
einer Liste kommt eine Calls-Kachel, in derselben Gruppe. Vier Stellen
von Hand zu pflegen waere die Stelle, an der es beim naechsten neuen
Rollenzuschnitt auseinanderlaeuft. Erkannt wird der Kalender am ZIEL,
nicht am Namen -- Namen sind im Haus schon gewandert, Ziele nicht.

„JEDER SIEHT NUR SEINE EIGENEN" GAB ES SCHON, seit dem 07.09.
(`termineSichtbar`). Es wird jetzt aber nicht mehr GELESEN, sondern am
laufenden Server ausprobiert: Zwei Leute legen je einen Call an und
sehen den des anderen nicht -- auch DogFather nicht. Wer als
Teilnehmer eingetragen ist, sieht ihn schon; das ist die Gegenprobe,
ohne die „niemand sieht etwas" auch bei einer kaputten Liste gruen
waere.

DER TON WAR EINE RECHNUNG UEBER DREI ANLAEUFE

  1. Ton 15, derselbe wie im anderen Haus. Als Zahl frei, auf dem
     BILDSCHIRM nicht: 0,0139 zu „Was ansteht", unter der Grenze 0,02.
  2. Ton 16, ausgerechnet als der entfernteste brauchbare. Die Pruefung
     kennt aber zwei Regeln mehr, die ich nicht beruecksichtigt hatte:
     Rohabstand >= 0,090 (er lag bei 0,0854) und Buntheit >= 0,12 (er
     lag bei 0,116). Und Ton 16 gehoert im anderen Haus zu
     „Start-Check" -- ihn umzufaerben haette dort eine Kachel
     veraendert, nach der niemand gefragt hat.
  3. Unter allen elf freien Toenen erfuellte KEINER alle drei Regeln.
     Eine 32. Kachel braucht einen 32. Ton. Also einen neuen gerechnet,
     additiv, ohne einen vorhandenen anzufassen:

         Ton 43  #027afb   Abstand 0,0925  Buntheit 0,212  Kontrast 4,63:1

     Es bleibt ein Blau -- die Kachel ist damit als dieselbe
     wiedererkennbar wie im anderen Haus.

EIN WIDERSPRUCH IM HAUS, DABEI GEFUNDEN
`tools/kachel-farbe-einzeln.mjs` suchte die Buntheit von 0,30 bis
herunter auf 0,04, `pruef-kachelfarben` verlangt mindestens 0,12. Das
Werkzeug lieferte fuer Ton 43 zuerst ein blasses #bcdbff (Buntheit
0,060) mit dem besten Abstand weit und breit -- und die Pruefung lehnte
es ab. Beide hatten recht; zwei Zahlen fuer dieselbe Regel in zwei
Dateien, die nichts voneinander wissen. Ein Werkzeug, dessen
Vorschlaege die Pruefung danach verwirft, ist schlimmer als keines --
man haelt das Ergebnis fuer fertig.

Die Schwellen stehen jetzt in tools/kachelton-regeln.mjs, und beide
Seiten lesen sie von dort.

NEU: server/pruef-calls-rudel.mjs, 32/0. Sie prueft die REGEL (Calls
genau dann, wenn Kalender -- und direkt dahinter, in derselben
Gruppe), dass Kachel und Zutrittsrecht zusammenpassen, und am
laufenden Server, dass jeder nur seine eigenen sieht.

pruef-kachelfarben 22/0, pruef-start-ansicht, pruef-willkommen,
pruef-struktur, pruef-treff, pruef-modi-checkliste gruen.

ZWEI ALTLASTEN DABEI GEFUNDEN, nicht von dieser Aenderung und noch
nicht behoben (beide vorher schon rot, nachgemessen mit `git stash`):
  pruef-kachelraster        3 Fehler (erwartet acht Community-Kacheln,
                            es sind zehn)
  pruef-jeder-hat-eine-seite 1 Fehler („fehlt: linke" -- die Rolle kam
                            dazu, die Pruefung nicht mit)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 15:15:00 +02:00
DogFatherGitandClaude Opus 5 7ccf904c3c Das Aufgaben-Formular: was aufklappt, bekommt jetzt auch Platz
Filipe, 22.09.2026, zum Bildschirmfoto: „wie scheisse sieht das aus,
verbesser das bitte." Zu sehen: „Anlegen" und „Abbrechen" lagen mitten
in der Personenliste.

GEMESSEN statt geraten, bei 1280 px mit aufgeklappter Liste:

    Zelle            Zeilen          Hoehe   Inhalt
    feld-verant      24px 44px          68      107
    feld-mehrere     43px 44px          87      261   <-- 174 zu viel

Jede Zelle des Formularrasters bekommt zwei Zeilen: Beschriftung oben,
Eingabe unten mit festen 44 px. Das ist richtig und der Grund, warum
alle Eingaben auf einer Linie sitzen (17.09.).

`feld-mehrere` ist aber keine Beschriftung mit Eingabe, sondern ein
Knopf mit einer Liste, die aufklappt. Ihr zweites Kind landet in der
44-Pixel-Zeile und laeuft heraus, sobald jemand sie oeffnet. Was
herauslaeuft, belegt keinen Platz -- also legt es sich ueber das
Naechste, und das Naechste sind die Knoepfe.

DIE MESSUNG HAT MICH VOR DEM NAHELIEGENDEN FEHLER BEWAHRT.
Erster Gedanke: „Zellen ohne eigene Eingabe brauchen die zwei Zeilen
nicht" -- `:has(> input, > select, > textarea)`. Die Messung sagt etwas
anderes: Von sieben Zellen haben SECHS ihre Eingabe nicht als direktes
Kind, weil der Auswahl-Baustein sie in ein <div> wickelt. Die Regel
haette fast das ganze Formular getroffen und genau die Ausrichtung
zerstoert, die sie schuetzen soll.

`aria-expanded` ist gemessen das einzige Merkmal, das nur bei dieser
Zelle steht -- und es ist das inhaltlich richtige: Es sagt „dieser
Bereich kann groesser werden". Etwas, das groesser werden kann, darf
keine feste Hoehe haben.

UND DIE PRUEFUNG, DIE ES HAETTE FINDEN MUESSEN
pruef-formulare war gruen -- sie klappt das Feld nie auf. Ein Zustand,
der nie hergestellt wird, kann nicht gemessen werden.

Neuer Abschnitt: Jedes Element mit `aria-expanded` im Formular wird
geoeffnet, danach darf keine Rasterzelle mehr Inhalt haben, als sie
hoch ist. Nicht diese eine Stelle, sondern die Eigenschaft -- damit
faellt auch die naechste auf, die es noch gar nicht gibt.

ZWEI ANLAEUFE DABEI WAREN FALSCH, und der zweite war der gefaehrliche:
  1. `scrollHeight` der Zelle meldete elf Zellen als kaputt, die alle
     in Ordnung sind: Der Hinweis unter einem Feld haengt seit dem
     17.09. absichtlich absolut darunter. Eine Warnung, die bei
     richtigem Verhalten anschlaegt, wird abgeschaltet.
  2. Nur die direkten Kinder im Fluss -- das war gruen, AUCH MIT DEM
     ECHTEN FEHLER. Nachgemessen mit zurueckgenommener Behebung:
     immer noch gruen. Das Raster staucht das Kind auf die feste
     Zeilenhoehe, das Kind bleibt also brav in der Zelle; was
     herauslaeuft, ist der Inhalt darin.

Jetzt misst sie in die Tiefe (ohne Teilbaeume unter absolut gesetzten
Elementen und ohne eigene Rollbereiche) und ist beidseitig belegt:
  mit Behebung    -> gruen
  ohne Behebung   -> FEHL „feld-mehrere: Inhalt reicht bis 169 px,
                     Zelle ist 87 px hoch"
Dazu eine Gegenprobe, die eine Zelle kuenstlich einklemmt.

Ueberlappungen im Formular: von 12 auf 4 -- und die vier sind Absicht
(der echte <select> liegt unsichtbar ueber seinem Knopf).

pruef-formulare, pruef-aufgabenbrett, pruef-css-klassen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:58:45 +02:00
DogFatherGitandClaude Opus 5 beb6bc2d62 Die Willkommens-Kachel: bunte Punkte statt Balken
Filipe, 22.09.2026: „Ja ist cool mit den ganzen farben, aber ich finde
das passt nicht so gut zum eigentlichen Stil. Würde glaube ich schöner
wirken, wenn die Farben als bunte Punkte auf der gesamten Kachel wären,
vielleicht auch eng an eng und größere und kleinere Punkte, damit es vom
Stil her die Punkte der anderen Kacheln aufgreift, aber trotzdem extrem
heraussticht. Das mit den Farben ist mega. Aber irgendwie passen die
balken/streifen nicht."

ER HAT DEN STIL DES HAUSES GENAUER GELESEN ALS ICH. Jede Kachel der
Startseite ist ein Sternenfeld -- nahe Sterne mit Hof, mittlere Sterne,
ferner Staub, dazu ein schraeger Schleier. Steht so in start.css unter
"NAHE STERNE", seit dem 17.09. Die Streifen waren die einzige Flaeche
weit und breit mit harten Kanten: richtig in der Farbe, falsch in der
Form.

Jetzt 93 Punkte in drei Groessen, jede Groesse einmal alle 31 benutzten
Kacheltoene. Dieselbe Bauart wie ueberall, nur bunt statt weiss -- die
Kachel greift den Stil auf und ist trotzdem die einzige, deren Sterne
Farbe haben.

ABGELEITET, NICHT EINGETRAGEN: Punktzahl, Rasterweite und Reihenfolge
folgen aus der Anzahl der Farben. Der Sprung durch die Farbliste wird
so gewaehlt, dass er teilerfremd zur Laenge ist -- sonst laegen
Nachbarpunkte auf benachbarten Farbwinkeln und es entstuenden Flecken
aus fast gleichen Toenen. Eine feste Zahl wie 7 versagt still, sobald
die Anzahl ein Vielfaches davon ist. Die drei Rasterweiten (197/131/83)
haben bewusst keinen gemeinsamen Teiler; sonst faellt das Feld
regelmaessig aufeinander und man sieht ein Muster.

Der Zufall der Streuung ist ein fester: `Math.random` haette bei jedem
Lauf einen anderen Block ergeben, und jeder Vergleich "hat sich etwas
geaendert?" waere wertlos.

VIER ANLAEUFE FUER DEN LESBAREN TEXT, drei davon falsch:

1. Der Lesesaum der Streifenfassung blieb stehen. Gemessen: 8,27:1 bei
   einer Grenze von 4,5. Das war kein Saum, das war ein Deckel -- er
   verschluckte die untere Haelfte der Kachel, und genau dort sollten
   Punkte sein ("auf der gesamten kachel"). Zurueckgenommen.
2. Danach sass auf dem Handybild ein heller Punkt mitten unter dem Wort
   "gibt". Die Messung sagte weiter 8,2:1 und hatte recht: Sie mittelt
   ueber die Textflaeche. Ein Punkt hinter einem duennen Buchstaben
   verschwindet in diesem Mittel -- im Auge nicht.
3. Also ein dunkler Teich im Kachelhintergrund, 400 px breit. Auf dem
   grossen Bildschirm sass er richtig; die Kachel auf dem Handy ist
   aber selbst nur 366 px breit, und er hat fast alle Farben
   geschluckt. Eine Pixelzahl, die auf einem Geraet passt, ist auf dem
   naechsten falsch.
4. Richtig: der dunkle Grund haengt am TEXT, nicht an der Kachel. Dann
   ist er immer genau so breit wie das, was er lesbar machen soll --
   auf jedem Geraet, ohne eine einzige Schwelle. Und der Verlauf darin
   laeuft vor allen vier Kanten aus, sonst sieht man das Rechteck und
   es steht eine Karte in der Karte.

Nebenbei die alte Falle wieder getreten und behoben: Ein Backtick in
einem Kommentar, der INNERHALB einer Vorlagenzeichenkette steht,
beendet sie. Steht seit heute als Hinweis daneben.

Gemessen: Willkommen 8,36:1 (Grenze 4,5), schlechteste Kachel im Haus
unveraendert "Aufgaben" mit 4,80:1. pruef-kachelfarben 22/0,
pruef-willkommen, pruef-buehne (Kontrast an echten Bildpunkten, alle
Seiten) -- alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:43:56 +02:00
DogFatherGitandClaude Opus 5 25de892fdb screen5: Aus dem Treff wird das Rudel, aus der Zentrale die IrrenAnstalt
Filipe, 22.09.2026: "ersetze die zentrale durch, Die IrrenAnstalt.
genau so geschrieben bitte. und alles was treff heißt oder wo treff
steht soll durch Rudel ersetzt werden bitte."

Die Schreibweise "IrrenAnstalt" mit grossem A in der Mitte ist so
gewollt. Das steht als Hinweis daneben, damit sie beim naechsten Mal
niemand "korrigiert".

WAS UMBENANNT WURDE: alles, was jemand LIEST -- Kachelnamen,
Ueberschriften, Markenzeilen, Saetze, Meldungen, Aufgabenvorlagen.
116 Zeilen in 42 Dateien.

WAS BLEIBT: Adressen (treff-regeln.html), Bezeichner (TREFF_ROLLEN),
Datenbankwerte (bereich = 'treff'), Abfrageteile (b=treff). Eine
Adresse umzubenennen bricht jedes Lesezeichen, und ein Datenbankwert
umzuschreiben waere eine Umstellung ohne Gegenwert. Dieselbe
Entscheidung wie heute frueh bei Dogi-Media, wo material.html auch
material.html geblieben ist.

DREI GRAMMATIKFEHLER IM EIGENEN ENTWURF, alle vor dem Ausliefern
gefunden -- ein blindes Ersetzen reicht hier nicht:

1. "der Treff" ist maennlich, "das Rudel" saechlich. Ohne Tabelle
   waere ueberall "Der Rudel" gestanden. (Und "Treffer" waere zu
   "Rudeler" geworden, "Treffen" zu "Rudelen" -- deshalb greift die
   Regel nur bei Wortgrenze und nie vor einem Kleinbuchstaben.)

2. BINDESTRICH-ZUSAMMENSETZUNGEN. In "der Treff-Chat" gehoert der
   Artikel zu "Chat", nicht zu "Treff". Der erste Durchlauf machte
   daraus "das Rudel-Chat", "das Rudel-Kacheln" und "ein Rudel-Raum".
   Jetzt greift die Artikelregel nur, wenn das Wort allein steht.

3. GESCHUETZTE LEERZEICHEN. In den Markenzeilen steht
   `Der&nbsp;Treff`, damit die zwei Woerter nicht umbrechen. Das
   Muster hat daran vorbeigegriffen: "Der&nbsp;Rudel", auf fuenf
   Seiten. Jetzt wird das Trennzeichen mitgefasst und unveraendert
   wieder eingesetzt.

Gefunden wurden alle drei, weil jede einzelne der 116 Zeilen vor dem
Schreiben als ALT/NEU ausgegeben und gelesen wurde -- und danach
gezielt nach falschen Artikeln gesucht ("den Rudel", "der Rudel",
"einen Rudel"). Uebrig blieben sechs Treffer, und die sind alle
richtig: "einen Rudel-Raum", "der Rudel-Chat", "den Rudel-Regeln" --
Zusammensetzungen, bei denen der Artikel zum letzten Wort gehoert.

UND ZWEI PRUEFUNGEN, die die Umbenennung nicht mitbekommen haetten:
`/Treff/.test(...)` und `/Treff/i.test(...)`. Ein regulaerer Ausdruck
ist keine Zeichenkette -- sie haetten ab sofort nach einem Wort
gesucht, das die Seite nicht mehr sagt, und waeren still rot geworden,
ohne dass etwas kaputt ist.

Geprueft, alle gruen: pruef-treff, pruef-treffchat,
pruef-deutsche-texte, pruef-uebernahme, pruef-crew-adresse,
pruef-willkommen, pruef-wege-nach-draussen, pruef-vorlagen,
pruef-start-ansicht, pruef-struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:25:56 +02:00
DogFatherGitandClaude Opus 5 091c5f9cd9 screen6: Bei DogFather steht jetzt eine Krone
Filipe, 22.09.2026: "bei dogi soll kein husky sein sondern eine krone.
die auch extrem auffaellt damit man den unterschied extrem erkennt."

WARUM ER RECHT HAT: Drei der fuenf Kacheln auf der Anmeldewand trugen
denselben Husky -- DogFather, rechte Hand, linke Hand. Drei gleiche
Zeichen untereinander sind kein Zeichen mehr, sondern Tapete; man
liest dann nur noch die Namen, und dafuer braucht es kein Bild.

WARUM GOLD: Die anderen vier Zeichen liegen alle im Blaubereich
(Husky silbern, Pfote blau, Community blaugrau). Eine Krone im selben
Farbkreis waere eine andere Form, aber kein anderer Eindruck. Gold ist
der einzige Hauston, der hier noch nicht vergeben ist -- und der, den
eine Krone ohnehin hat. Es sind vorhandene Hausfarben und kein
Leuchten: Der Unterschied kommt aus Form und Farbkreis, nicht aus
Helligkeit. Die Wand bleibt augenschonend.

WAS SIE NICHT HEISST: Der Untertitel bleibt "Ueberblick &
Entscheidungen" -- eine AUFGABE, kein Rang. Die vier anderen Rollen
behalten ihre Zeichen unveraendert, an den Texten aendert sich nichts.
Das Zeichen sagt "das ist die Rolle, die du suchst", nicht "der steht
ueber den anderen".

EIN FUND BEIM BAUEN: `.rolle__zeichen` faerbt jedes Rollenzeichen mit
dem Ton der Rolle ein -- gedacht fuer gezeichnete Striche. Der Husky
(ein Foto) und die Pfote (eigene Verlaeufe) merken davon nichts, weil
eine Flaeche ohne `stroke` die Regel stillschweigend ignoriert. Die
Krone haette sie sichtbar abbekommen: ein blauer Rand um eine goldene
Krone. Ausdruecklich abbestellt.

DIE PRUEFUNG HIELT DIE ALTE VORGABE FEST und wurde zu Recht rot: Sie
verlangte seit dem 10.09., dass die rechte Hand DASSELBE Zeichen
traegt wie DogFather. Beide Fassungen geben eine Anweisung von Filipe
wieder; dazwischen ist die linke Hand dazugekommen.

Statt die Paarliste umzuschreiben -- die beim naechsten Umbau wieder
danebenlaege -- prueft sie jetzt die Eigenschaft, um die es geht: Jede
Kachel traegt ein Zeichen, DogFathers kommt genau einmal vor, es ist
auf der Seite auch definiert (ein `use` auf eine vertippte Kennung
zeichnet lautlos nichts), und die zwei Haende lesen sich weiter als
Paar. Mit Gegenprobe.

pruef-crew-adresse 153/0 (von 148), pruef-css-klassen grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:19:30 +02:00
DogFatherGitandClaude Opus 5 a8e49496ad Der Installieren-Knopf war nie zu sehen — jetzt schon
Filipe, 22.09.2026: "und nochmal, ich will einen installieren button.
damit die leute es viel einfacher haben die seite auf dem pc oder auf
dem handy zu installieren!!! bitte das hab ich auch schon paar mal
gefragt. mach das es ist seeeeeeeehr wichtig."

Er hatte recht, und der Knopf war seit dem 20.09. gebaut. Er konnte
nur nie erscheinen. ZWEI URSACHEN, beide ausserhalb dessen, was
geprueft wurde:

1. DER SERVICE WORKER LIEF NIE. Er wurde ausschliesslich in glocke.js
   angemeldet -- also erst, wenn jemand Benachrichtigungen ERLAUBT.
   Auf Filipes Rechner stehen sie auf "Vom Browser blockiert"; das
   steht sogar in seiner Kopfleiste auf dem Bildschirmfoto von heute
   frueh. Ohne Service Worker macht Chrome kein Installationsangebot.

2. UND AUCH MIT WAERE ES NICHT GEGANGEN: Chrome verlangt einen Service
   Worker MIT `fetch`-Zuhoerer. Dieser hatte keinen.

Ohne Angebot kommt `beforeinstallprompt` nie, und der Knopf bleibt
`hidden`. Fuer immer.

WAS SICH GEAENDERT HAT

- Der Service Worker wird jetzt auf JEDER Seite angemeldet, unabhaengig
  von Benachrichtigungen. Das gehoert zum Installieren, nicht zur
  Glocke.
- sw.js bekommt einen `fetch`-Zuhoerer, der NICHTS ablegt. Das
  Versprechen im Kopf der Datei ("bewusst ohne Zwischenspeicher, der
  Workspace liegt hinter einer Anmeldung") bleibt damit wortwoertlich
  gueltig: Er reicht Seitenaufrufe durch und baut nur dann selbst eine
  Antwort, wenn das Netz weg ist. Keine Serverantwort wird aufgehoben.
- Der Knopf zeigt sich, sobald der Browser installieren KANN, statt
  erst nach dem Angebot. Geprueft wird die Faehigkeit
  (`'onbeforeinstallprompt' in window`), nicht der Name des Browsers.
- DIE ANMELDEWAND BEKOMMT IHN AUCH. Sie hat keine Kopfleiste und
  deshalb bisher gar kein Angebot -- dabei ist sie die Seite, auf der
  jeder zuerst landet. Genau die Leute, um die es Filipe geht.
- Dafuer steht der Knopf jetzt in einer eigenen Datei
  (assets/js/installieren.js) statt in kopf.js, das die Wand nicht
  laedt. Und sein Stil in gate.css statt in module.css -- vierter Fall
  derselben Art nach .knopf-still, dem Schalter und .feld-hinweis.
- Ohne `nachfrage.js` (also auf der Wand) erklaert er den Weg als
  Absatz unter sich. Der erste Entwurf rief `window.frageNach?.()`
  auf: Auf dem iPhone steht der Knopf dort von Anfang an da, und er
  haette beim Antippen stumm nichts getan.
- Der Aufruf haengt nicht mehr an der Reihenfolge der Skriptzeilen.
  chat.html und leistung.html laden kopf.js OHNE `defer`, dort waere
  installieren.js immer zu spaet gekommen -- zwei von 37 Seiten ohne
  Knopf, ohne Meldung.
- Chromes Manifest-Warnung zum `share_target` behoben (enctype).

WARUM DIE PRUEFUNG DAS NICHT GEFUNDEN HAT -- und was jetzt anders ist

Sie war gruen, die ganze Zeit. Sie hat `beforeinstallprompt` SELBST
zugestellt und gemessen, ob der Knopf darauf reagiert. Die eine Frage,
auf die es ankam -- "bietet der Browser es ueberhaupt an?" -- hat sie
nie gestellt.

Jetzt fragt sie Chrome direkt (`Page.getInstallabilityErrors`, sein
eigenes Urteil) und misst die Voraussetzungen statt der Reaktion:
laeuft ein Service Worker, OBWOHL Benachrichtigungen auf "denied"
stehen; hat sw.js einen fetch-Zuhoerer; legt er wirklich nichts ab;
steht der Knopf auf der Wand und tut er dort auch etwas.

Gemessen, mit Benachrichtigungen auf "denied":
  Service Worker: activated
  Chromes Urteil: kein einziges Hindernis
  Manifest:       nichts beanstandet
  Knopf:          124x45 px, sichtbar, genau einer

pruef-installieren 29/0 (von 14). Dazu gruen: pruef-css-klassen,
pruef-struktur, pruef-crew-adresse, pruef-start-ansicht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:16:03 +02:00
DogFatherGitandClaude Opus 5 774eeee3e5 Die Umstellung von Dogi-Media merkt jetzt, wenn sie nicht durchkam
BEIM AUSLIEFERN AUFGEFALLEN, NICHT BEIM BAUEN.

Nach Neustart und `git pull` standen die zwei neuen Spalten noch nicht
in der echten Ablage -- die Umstellung laeuft erst beim ersten
angemeldeten Zugriff. Das ist in Ordnung. Beim Nachsehen, WARUM sie
noch nicht da waren, fiel aber der eigentliche Mangel auf:

`bereit = true` stand UNBEDINGT hinter der Schleife, und der Fehler des
`ALTER TABLE` daneben ging still in die Konsole. Ein einziger
misslungener Versuch -- Datei gesperrt, Platte voll -- haette die
Umstellung damit fuer immer als erledigt vermerkt. Danach scheitert
JEDE Liste an `SELECT ... m.gilt_ab`, und zwar fuer alle, mit einem 503
und dem Satz "gerade nicht verfuegbar", der nirgends sagt, woran es
liegt. Bis zum naechsten Neustart.

Jetzt wird nach der Schleife nachgezaehlt. Fehlt etwas, wird geworfen
statt notiert, und der Vermerk bleibt aus -- der naechste Aufruf
versucht es also wieder. Ein Aufruf, der mit einer klaren Meldung
scheitert, ist besser als hundert, die raetseln.

AUF EINER KOPIE DURCHGESPIELT, nicht an den echten Daten erlebt:
Sicherung der laufenden Ablage gezogen (`.backup`, integrity_check ok,
Zeilenzahlen gegen live geprueft), darauf beide ALTER ausgefuehrt. Die
vorhandene Zeile ueberlebt mit leerem Fenster, die Listenabfrage des
Servers laeuft wortgleich durch, integrity_check danach ok.

pruef-material 159/0 (von 155). Neu ist eine Gegenprobe, die den
halb-umgestellten Zustand herstellt -- genau den, der vorher
"erledigt" geheissen haette -- und eine Zeile, die die Spalten in der
laufenden Ablage nachzaehlt statt sie anzunehmen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:03:11 +02:00
DogFatherGitandClaude Opus 5 fc823240ab screen4: Dogi-Media — bearbeiten, entfernen, von wann bis wann
Filipe, 22.09.2026: "wenn wir in der kategorie material was hochladen
will ich dass die rechte und linke hand es auch bearbeiten und loeschen
koennen. dogfather auch fals es ein fehler gab. ... uebrigens ersetz das
wort material durch Dogi-Media. und mach kategorien welche sind benutzt
welche nicht welche sind noch offen, welche laufen von wan bis wann."

WAS JETZT GEHT
- Rechte Hand, linke Hand und DogFather bearbeiten und entfernen jedes
  Stueck, nicht nur ihr eigenes. Bearbeitet wird Text und Zeitfenster,
  nicht die Datei: Sonst zeigte dieselbe Nummer etwas anderes als das,
  was sich jemand gerade angesehen hat.
- Ein vergebenes Stueck bleibt unberuehrt (409). Wer es genommen hat,
  hat sich auf diesen Text verlassen.
- Vier Zustaende, gerechnet statt gespeichert: jetzt frei, kommt noch,
  abgelaufen, schon benutzt. Die Kategorieleiste zeigt zu jedem die
  Anzahl aus den echten Daten und filtert BEIDE Listen.
- "Material" heisst ueberall "Dogi-Media", der Dateiname bleibt.

DREI FEHLER AUS DEM EIGENEN ENTWURF, ALLE VOR DEM AUSLIEFERN GEMESSEN

1. `tagLokal()` ohne Argument gab "NaN-NaN-NaN" zurueck -- eine
   Zeichenkette, die aussieht wie ein Datum. Im Vergleich gewinnt das N
   gegen jede Ziffer, also galt JEDES Stueck mit Enddatum vom ersten Tag
   an als abgelaufen, und "Kommt noch" gab es nie. Kein Absturz, keine
   Meldung. Die drei Kopien der Funktion waren hier auseinandergelaufen;
   alle drei haben jetzt die Vorbelegung und werfen bei einer Zahl, die
   keine ist.
2. `frageNach` liefert bei einer reinen Rueckfrage `true`, nicht
   `{ ok: true }`. Der Entwurf prueft auf `erg?.ok` -- "Entfernen" waere
   ein Knopf gewesen, der nichts tut.
3. Drei erfundene Klassennamen (`knopf--leise`, `m-kat__knopf`,
   `m-karte__weg-knopf`) statt der vorhandenen des Hauses. Jetzt
   `.knopf-still`, `.knopf-still--warn` und die Filterleiste `.filter`.

EIN FUND IM BESTAND, ZWEI WOCHEN ALT

In start.css fehlten an einer Stelle die zwei Zeichen, die einen
Kommentar schliessen. CSS-Kommentare schachteln nicht: Der Block lief
bis zum naechsten Abschluss weiter und verschluckte `.kacheln {`; die
Fehlerbehebung des Browsers nahm danach auch die Regel `.kachel` mit.
In Chromium gemessen, beide Fassungen nacheinander: 738 statt 740
Regeln.

Der Entwurf, der dadurch nie gewirkt hat, ist NICHT wiederhergestellt
worden: Seine Flaeche mischte den Kachelton mit 30/11/3 Prozent ein --
pruef-kachelfarben fiel sofort von 36,5 % auf 4,1 % angekommene Farbe,
und 31 Toene sahen gleich aus. Das ist das Gegenteil dessen, was am
22.09. verlangt war. Er ist geloescht, mit dem Grund daneben. Offen
bleibt eine Frage an Filipe, keine Entscheidung von mir: zu demselben
Entwurf gehoerte ein schmaleres Kachelraster (fuenf bis sechs statt
drei pro Reihe). Das aendert das Aussehen der Startseite sichtbar und
bleibt deshalb, wie es ist.

GEMEINSAME BAUSTEINE AUS DEN SEITENDATEIEN GEHOLT
`.filter` stand Zeichen fuer Zeichen doppelt in dateien.css und
bereich.css, `.feld-hinweis` in aufgaben.css und leistung.css (und die
zwei waren schon auseinandergelaufen). Dogi-Media war jeweils die
dritte Seite, die sie braucht, und laedt keine davon. Derselbe Fehler
wie damals bei .knopf-still und beim Schalter -- jetzt in gate.css
bzw. start.css.

GEPRUEFT
pruef-material 155/0 (von 126, neu: Zeitfenster, Bearbeiten, Entfernen,
Rechte in der Liste und ein Abschnitt am echten Bildschirm mit Browser).
pruef-css-klassen um eine Pruefung erweitert, die genau den
start.css-Fehler findet -- mit sieben Gegenproben, darunter der echte
Fall. pruef-kachelfarben 22/0, pruef-start-ansicht, pruef-struktur,
pruef-meldungen, pruef-zeitraum, pruef-content, pruef-serien 69/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 13:59:55 +02:00
DogFatherGitandClaude Opus 5 fe1dad48e5 screen1: Wohin ein geholtes Video gelegt wird, darf man waehlen
Filipe: "ich will das wenn man da video holt das man auch aussuchen
kann in welcher account es unten angezeigt werden soll."

Bis heute entschied allein der Link: kanalVonHandle liest den Account
aus der TikTok-Adresse, und dort landete das Video. Das ist gut
geraten, aber es IST geraten -- ein Ausschnitt vom Hauptkanal gehoert
oft unter "Clips", und seit dem 21.09. hat jeder Account seine eigene
Spalte, in der das sichtbar wird.

DIE SCHRANKE BLEIBT UNANGETASTET. Der ABSENDER muss weiterhin einer
der drei eigenen Kanaele sein; gewaehlt wird nur die SPALTE. Sonst
waere aus einer Ablagehilfe ein Loch fuer fremde Inhalte geworden --
die Pruefung haelt genau das fest ("ein fremder Absender kommt auch
MIT Wahl nicht herein", 403).

Ohne Angabe bleibt alles wie bisher. Das ist der haeufigste Fall und
soll keinen zusaetzlichen Handgriff kosten; die Vorgabe heisst "Aus
dem Link erkennen".

ZWEI FUNDE BEIM PRUEFEN
  - Die Antwort meldete `auskunft.kanal` -- also das ERKANNTE, nicht
    das, wohin der Eintrag wirklich ging. Seit beides auseinanderfallen
    kann, haette die Seite "DogFather" gemeldet, waehrend das Video
    unter "Clips" steht.
  - `coverAbrufe === 3` in pruef-video war eine Rechnung von dem Tag,
    an dem die Pruefung drei Videos anlegte. Der neue Abschnitt legte
    vier weitere an, und die Zeile wurde rot, ohne dass etwas kaputt
    war. Gemeint war nie eine Summe, sondern eine DIFFERENZ: holt
    derselbe Link ein zweites Mal? Das bleibt richtig, egal wie viele
    Videos davor liefen.

Die Wahl steht UNTER der Zeile, nicht darin: Am 21.09. hat genau so
ein drittes Element in derselben Reihe das Chat-Eingabefeld auf einen
Buchstaben zusammengedrueckt. Am Bildschirm gemessen (1044 px).

Gemessen: pruef-video 71/0 (vier neue Aussagen samt Gegenprobe, dass
ohne Wahl weiterhin der Link entscheidet), pruef-highlights 31/0
(fuenf neue am echten Bildschirm), pruef-meldungen 8/0, pruef-teilen
27/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 13:25:28 +02:00
DogFatherGitandClaude Opus 5 1a7d074e94 Auf dem iPhone trug Team Dogi das Zeichen der Agentur
DIE ZWEITE HAELFTE EINER ENTSCHEIDUNG VOM 10.09.2026
  Der Block, der /workspace/app.webmanifest auf crew.webmanifest
  umbiegt, begruendet sich selbst so: "Sonst hiesse die App auf dem
  Startbildschirm eines Modis 'Creator Workspace' und traege das
  Zeichen mit der Chili -- die zu Spicy Media gehoert, nicht zu
  ihnen."

  Genau das passierte trotzdem -- auf dem iPhone. Android nimmt das
  Symbol aus dem Manifest (crew-192.png, richtig). iOS Safari nimmt es
  NICHT von dort, sondern aus <link rel="apple-touch-icon">, und diese
  Zeile steht in jeder HTML-Datei auf workspace-180.png.

  Gemessen: crew-180.png und workspace-180.png sind verschiedene
  Dateien (30 899 gegen 34 850 Byte). Ein Modi mit iPhone bekam die
  Chili auf den Startbildschirm, derselbe Modi mit Android das richtige
  Zeichen. So etwas faellt beim Ansehen nie auf -- man braeuchte beide
  Geraete nebeneinander.

  Behoben mit derselben Loesung wie beim Manifest: umbiegen an EINER
  Stelle, statt in 37 Dateien eine zweite Zeile zu setzen. Wer eine
  Seite anlegt, schreibt weiterhin workspace-*.png und bekommt auf
  crew. trotzdem das richtige Symbol.

  ABGELEITET, NICHT AUFGEZAEHLT: Umgebogen wird nur, wo es die
  Crew-Fassung wirklich gibt -- gemessen sind das 32, 180, 192, 512 und
  die beiden maskable. workspace-1024.png (TikTok) hat keine und bleibt
  unangetastet; eine kuenftige Groesse kommt von selbst dazu, sobald
  jemand die Datei anlegt.

DREI BEFUNDE VON pruef-struktur, alle aus meiner eigenen Arbeit
  - material.html und willkommen.html hatten weder theme-color noch
    apple-touch-icon. Auf dem iPhone waere das Startbildschirm-Symbol
    ein Bildschirmfoto der Seite gewesen, auf Android die Leiste weiss.
    Beide binden jetzt app.webmanifest statt crew.webmanifest direkt --
    die Adresse biegt es um, und zwei Stellen laufen sonst auseinander.
  - 20 tote CSS-Regeln (.b-analyse*) in entwicklung.css. Am 22.09.
    wurde der Block "Resuemee je Frage" aus dem Skript entfernt, die
    Gestaltung blieb stehen. Das ist nicht nur Ballast auf jeder Seite,
    sondern eine Falle: Wer spaeter .b-analyse im CSS findet, haelt den
    Block fuer lebendig. Vor dem Entfernen geprueft, dass im Bereich
    keine fremde Klasse steht.

EIN RUECKSTAND VOM 21.09. NACHGETRAGEN
  pruef-crew-adresse erwartete vier Rollenkacheln auf der Wand; seit
  die linke Hand dazukam (Commit 21793b6) sind es fuenf. Die Pruefung
  war seitdem rot an einer Stelle, an der NICHTS kaputt war -- und die
  Zeile daneben ("so viele, wie es Rollen auf der Wand gibt") war die
  ganze Zeit gruen und hat den Fehler damit verdeckt.

Gemessen: pruef-crew-adresse 148/0 (war 147/1, neu: vier Aussagen zum
Startbildschirm-Symbol samt Gegenprobe, dass die Agenturadresse
unveraendert bleibt und Groessen ohne Crew-Fassung nicht umgebogen
werden), pruef-struktur 35/0 (war 32/3), pruef-css-klassen 30/0,
pruef-befinden 116/0, pruef-willkommen 67/0, pruef-installieren 14/0,
pruef-textform 50/0, pruef-zwischenspeicher 27/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 13:14:19 +02:00
DogFatherGitandClaude Opus 5 80dee4d0c8 Highlights nach vorn, kraeftige Chatfarben, alle Farben in einer Kachel
screen1 -- HIGHLIGHTS AUF ANSCHLAGBRETTS PLATZ
  Kein Tausch, sondern ein Aufruecken: Highlights nimmt die Stelle,
  alle anderen wandern eine weiter. Inhaltlich stimmt das auch --
  was die Leute selbst gemacht haben, steht vor dem, was ihnen
  angesagt wird.

screen2 -- DIE CHATFARBEN SIND GERECHNET, NICHT GEGRIFFEN
  Gemessen, was drinstand: Buntheit 0,002 bis 0,048, im Mittel 0,028
  -- auf dem Bildschirm zwoelf Grautoene. Das lag nicht an fehlendem
  Mut, sondern an der Fusszeile der Blase: Sie stand auf der leisen
  Hausschrift, und gegen die darf die Flaeche kaum Farbe haben.

  Deshalb ZUERST die Schrift (--blase-text/--blase-leise, eigene
  Farben der Blase), DANN die Flaeche. Andersherum waere es der
  Fehler vom selben Vormittag gewesen, als 27 von 31 Startkacheln
  unlesbar wurden.

  tools/chat-kacheln-rechnen.mjs liest beide Schriftfarben aus dem
  CSS und rechnet daraus die hellste Flaeche, die sie noch tragen.
  Ergebnis: Buntheit 0,072 bis 0,268, alle zwoelf auf DERSELBEN
  Leuchtdichte -- also exakt demselben Kontrast (7,02 bis 7,13:1).

  Zwei Anlaeufe waren falsch und stehen im Werkzeug begruendet:
    - hoechste Buntheit nehmen, dann Kontrast pruefen. Musste
      scheitern: gesaettigtes Gelb ist bei gleicher empfundener
      Helligkeit viel heller als Blau.
    - gleiche OKLab-Helligkeit statt gleicher Leuchtdichte. Das
      Versprechen der zwoelf lautet "ueberall gleich gut lesbar",
      und Lesbarkeit haengt an der Leuchtdichte, nicht am Eindruck.

  WER NICHTS EINSTELLT, BEKOMMT TROTZDEM EINE FARBE. Gemessen an der
  Live-Datenbank hatten vier von fuenfzehn eine gewaehlt -- der Chat
  war fuer alle anderen einfarbig. Jetzt vergibt der Server einen der
  elf bunten Toene aus der Personennummer, stabil. Schrittweite 4:
  elf ist prim, also laufen alle Toene durch, und vier Schritte sind
  131 Grad im Farbkreis -- aufeinanderfolgende Nummern landen so weit
  auseinander wie moeglich. Mit id % 11 sassen zwei Nachbarn im
  selben Gespraech magenta und rot nebeneinander.

  Niemand verliert seine Wahl: veilchen, ziegel und moos sind die
  drei gewaehlten und behalten ihren Farbbereich.

  Dazu: Blasen mit 22px runden Kanten (nur die Ecke zur Person bleibt
  spitz -- sie sagt, wer spricht), Lichtsaum oben innen, weicher
  Schatten. Der Name hell und fett mit Rollenpunkt davor; er stand
  auf leisem Grau mit 85 Prozent Deckung und war der schwaechste Text
  der Seite, ausgerechnet der, der sagt, wer spricht.

  ZWEI REGELBLOECKE FUER DIESELBE BLASE ZUSAMMENGELEGT. Der untere
  gewann und hat an einem Tag zweimal Schaden angerichtet: Er stellte
  die runden Kanten auf 16px zurueck (die Aenderung waere wirkungslos
  ausgeliefert worden), und er mischte 26 Prozent Akzentfarbe in die
  eigene Blase -- die hatte damit eine Farbe, die in CHAT_KACHELN
  nicht vorkommt und die die Kontrastpruefung nie angesehen hat.

screen3 -- ALLE FARBEN DES HAUSES IN EINER KACHEL
  tools/kachel-regenbogen.mjs leitet die 31 benutzten Toene ab
  (bereicheFuer/zusatzBereicheFuer ueber alle Rollen und beide
  Haeuser) und schreibt daraus einen Streifenverlauf mit harten
  Kanten -- "nicht gemischt" war die eigentliche Ansage. Ein Verlauf
  ergaebe Zwischentoene, die es im Haus nicht gibt.

  Gegen einen deckenden Grund gemischt, nicht gegen --flaeche: Die
  ist halbdurchsichtig, und durch 31 schmale Baender schien das
  Buehnenbild -- sie verloren genau das, wofuer sie da sind.

  Der Lesesaum ist staerker als auf den anderen Kacheln, und zwar
  gemessen: Mit deren Werten kam der Text auf 4,45:1, fuenf
  Hundertstel unter der Grenze. Gefunden hat das pruef-kachelfarben,
  nicht der Blick -- 4,45 gegen 4,50 sieht man nicht.

pruef-buehne -- DIE ZAHL GEHOERT IN DIE BEDINGUNG
  Die Abtastung wurde nachsichtiger (fremde Flaechen zaehlen nicht
  mehr als Untergrund eines Textes). Das war richtig und hat einen
  Fehlalarm beseitigt, der seit Tagen kam. Eine Lockerung kann aber
  zu weit gehen, deshalb muss jetzt jeder gefundene Text in genau
  einem von drei Toepfen landen: gemessen, ohne freien Untergrund,
  oder aussortiert. Geht die Rechnung nicht auf, ist unterwegs etwas
  still verschwunden.

  Erster Anlauf war "mindestens 5 Stellen" -- und wurde auf
  uebersicht.html sofort rot, weil die Seite nur vier Texte hat.
  Eine feste Schwelle ist eine Rechnung von gestern; diese war keine
  fuenf Minuten alt.

Gemessen: pruef-kachelfarben 22/0 (war 18, neu: die Willkommenskachel
traegt wirklich alle benutzten Farben, in beide Richtungen geprueft),
pruef-buehne 192/0, pruef-chatkachel 32/0, pruef-chat-optik 45/0,
pruef-chat 48/0, pruef-erwaehnung 69/0, pruef-start-ansicht 153/0,
pruef-treff 80/0, pruef-willkommen 67/0, pruef-treffchat 110/0,
pruef-css-klassen 30/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 12:57:56 +02:00
DogFatherGitandClaude Opus 5 e12392a289 Die Kachelfarben kommen jetzt WIRKLICH auf dem Bildschirm an
Filipe: "ich raste aus im ernst, was verstehst du nicht darunter wenn
ich sage das alle kacheln eine andere farbe haben sollen ich seh
immer wieder sehr viele die einfach komplett die gleiche farbe haben."

ER HATTE RECHT, UND MEINE PRUEFUNG WAR TROTZDEM GRUEN.
Der Grund war ein Messfehler, und zwar meiner: pruef-kachelfarben las
`--ton` aus start.css -- die ROHFARBE. Die lag zwischen allen 31
Kacheln weit auseinander (0,0978 in OKLab). Nur steht sie so nie auf
dem Bildschirm.

GEMESSEN an echten Bildpunkten (neu: tools/kachel-echtfarbe.mjs):
  Rohfarben:              0,0978 auseinander
  Auf dem Bildschirm:     0,0141
  Es kamen an:            14,4 Prozent
  Fuer ein Auge gleich:   ACHT Paare

Drei Stellen haben die Farbe geschluckt, alle in .kachel:
  1. Eine Wolke mit 16 Prozent -- in immer DEMSELBEN Blau, auf jeder
     Kachel. Der staerkste Gleichmacher der ganzen Wand. Sie traegt
     jetzt den Ton der Kachel.
  2. Die Vignette legte bis zu 55 Prozent Dunkelblau darueber.
  3. Der Grund trug den Ton zu 24 Prozent und ging ab 58 Prozent in
     fast reines Schwarz. Zwei Drittel jeder Kachel waren damit
     dieselbe Farbe, egal welcher Ton darueber stand.

Danach: 51,1 Prozent kamen an, NULL ununterscheidbare Paare.

UND DANN HAETTE ICH EINEN FEHLER GEGEN EINEN ANDEREN GETAUSCHT.
Gemessen an jedem einzelnen Kacheltext: VORHER war 1 von 31 unter
4,5:1, DANACH 27 von 31. Also genau das, was Filipe schon zweimal
gemeldet hat ("man bekommt fast nichts gelesen"). Kein Messwert hat
es angezeigt -- pruef-buehne nimmt Stichproben und traf die
Kacheltexte nicht.

Behoben mit einem Lesesaum: ein dunkler Verlauf VON UNTEN, der genau
den Streifen abdunkelt, auf dem gelesen wird, und die oberen zwei
Drittel in Ruhe laesst. Dasselbe Mittel, mit dem jede Bildunterschrift
auf einem Foto lesbar gemacht wird.

  Texte unter 4,5:1:   1 -> 27 -> 0
  Farbe kommt an:      14,4 % -> 51,1 % -> 36,5 %

VERTRAULICH MELDEN IST JETZT KNALLROT.
Filipe: "nicht die kachel draussen soll rot sein sondern die kachel
vertraulich melden nur die soll knall rot sein!!!" Ich hatte screen5
und screen6 vertauscht. Ringtausch ohne neue Farbe:
  Vertraulich melden  28 -> 38  (#ff1a1a, knallrot)
  Draussen            38 -> 39  (die Farbe, die Regeln & Hilfe hatte)
  Regeln & Hilfe      39 -> 28  (das frei gewordene Gruen)

NEU, UND DER EIGENTLICHE LERNEFFEKT:
server/helfer-kachel-echtfarbe.mjs misst beides in EINER Messung --
Farbunterschied UND Lesbarkeit. Wer sie trennt, verbessert das eine
und verliert das andere; genau das ist heute passiert. Benutzt von
der Pruefung und vom Werkzeug, damit es nur eine Fassung gibt.

pruef-kachelfarben 18/0 (war 13), davon fuenf am echten Bildschirm:
  - kein Paar sieht auf dem Bildschirm gleich aus (0,0357)
  - mindestens ein Drittel der Rohfarbe kommt an (36,5 %)
  - jeder Kacheltext erreicht 4,5:1 (schlechtester: 4,80:1)
Mit drittem Ausgang: kein Browser heisst "konnte nicht nachsehen",
nicht "in Ordnung".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 10:26:49 +02:00
DogFatherGitandClaude Opus 5 65d278a18e Der Handy-Rundgang ist zum ersten Mal bei null Befunden
SECHS SACHEN, UND KEINE DAVON WAR DAS, WONACH ICH GESUCHT HABE.

1. ZWEI NATIVE prompt() IN teamlage.js -- die letzten im Haus.
   Sie halten die ganze Seite an, sehen auf jedem Browser anders aus
   als der Rest und koennen nicht sagen, was BLEIBT, wenn man absagt.
   Genau das ist dort die Frage, die jemand vor dem Klicken hat. Jetzt
   derselbe Dialog wie an den 42 anderen Stellen.

2. UND DER GRUND, WARUM SIE NIEMAND GEFUNDEN HAT.
   pruef-nachfrage suchte mit `(?:^|[^.\w])(confirm|prompt)\s*\(`.
   Das `[^.\w]` sollte fremde Methoden ausschliessen -- `angebot
   .prompt()` ist die Installations-Aufforderung des Browsers und kein
   nativer Dialog. Nur trifft dieser Ausschluss ausgerechnet die
   HAEUFIGSTE Schreibweise: `window.prompt(` hat einen Punkt davor.
   Die Pruefung war gruen, waehrend zwei native prompt() dastanden.
   Genau das Muster, vor dem dieses Haus warnt: eine Pruefung, die
   laeuft, gruen ist und das Falsche prueft. Die Gegenprobe kennt
   jetzt beide Schreibweisen -- haette sie das vorher getan, waere es
   am selben Tag aufgefallen.

3. willkommen.html LUD nachfrage.js NICHT.
   Gefunden von der geschaerften Pruefung. kopf.js ruft `frageNach(`
   ohne Absicherung -- auf dieser einen Seite haette ABMELDEN einen
   Absturz ausgeloest. Die Seite ist vom 21.09., die Luecke also
   einen Tag alt.

4. ZWEI FEHLALARME IM HANDY-RUNDGANG ABGESTELLT.
   Er meldete bei JEDEM Lauf dieselben drei Befunde: `button.schnitt
   bis 481px`, die Rechtetafel `table bis 877px`, `a.k-pille 8x8`.
   Nachgemessen bei 390 px: Das Dokument ist exakt 390 px breit,
   NICHTS laeuft ueber -- beide stehen in einem Kasten mit
   `overflow-x: auto`, und der rollt absichtlich. Die Kalenderpunkte
   tragen `pointer-events: none`; der Tipp gehoert der Tageszelle.
   Eine Warnung, die immer kommt, ist keine Warnung mehr (Hausregel
   vom 03.09.). Beide Regeln sind SCHMAL: nur ausdrueckliches
   `overflow-x: auto|scroll` (nicht `hidden` -- dort ist der Inhalt
   wirklich weg), nur ausdrueckliches `pointer-events: none`.
   Die Gegenprobe hat jetzt vier Faelle statt zwei: zwei, die gemeldet
   werden MUESSEN, und zwei, die es NICHT duerfen. Eine engere Messung
   kann auch zu eng sein.

5. DER LETZTE ECHTE BEFUND: 404 BEI JEDEM MODI.
   Der Rundgang meldete "404 (Not Found)" ohne Adresse -- eine
   Pruefung, die einen Fehler findet, ihn aber nicht auffindbar macht,
   kostet mehr Zeit als sie spart. Sie nennt jetzt die Adresse, und
   damit war es in einer Minute klar: `/workspace/api/werdegang/liste`.
   Der Code BEHANDELTE den 404 richtig, der Browser protokolliert ihn
   trotzdem -- derselbe Fall wie am 19.09. bei /anruf/adressen.
   Jetzt sagt der Server in /api/ich, ob jemand Team Dogi fuehrt.
   EIGENES FELD, kein Stellvertreter: `darf_verteilen` sieht aehnlich
   aus, ist aber nicht dasselbe -- ein Manager darf verteilen und
   fuehrt Team Dogi nicht.

   Dabei EINE Wartestelle statt zwei: `window.wennIchDaBin()`.
   `window.__ich` kommt ueber das Netz; zwei Seiten hatten dafuer
   jeweils ein eigenes setInterval. Zwei Fassungen desselben Wartens
   altern unterschiedlich.

6. pruef-werdegang MASS AUF DER FALSCHEN ADRESSE.
   Drei Pruefungen waren dauerhaft rot (`data-ton=null`) -- an einer
   Seite, die in Ordnung ist. Sie oeffnete `127.0.0.1`, also die
   Adresse der AGENTUR; dort ist `person.haus` nicht "crew" und die
   Kachelliste eine andere. Nachgemessen: Alle vier Rollen HABEN die
   Kachel, sobald das Haus stimmt. Jetzt derselbe https-Vorbau wie in
   pruef-willkommen und pruef-zuteilung.

   Beinahe haette ich hier etwas "repariert", das nicht kaputt war:
   Meine erste Messung rief `bereicheFuer(p, "crew")` auf -- das Haus
   wird aber aus `person.haus` gelesen, nicht als Argument. Sie sagte
   "DogFather hat keine Kachel". Eine plausible Herleitung ersetzt
   keine Messung, und eine falsch aufgesetzte Messung auch nicht.

GEMESSEN: pruef-handy-teamdogi 214 Seitenaufrufe, 108.564 Elemente,
4.126 Bedienelemente -- 0 Befunde. Alle vier Rollen, beide Breiten.
Zum ersten Mal.

pruef-werdegang 103/0 (war 100/3), pruef-nachfrage 51/0 (war 49),
pruef-stelle 15/0, pruef-entwicklung 48/0, pruef-start-ansicht 153/0,
pruef-wege-nach-draussen 67/0, pruef-tippziele 11/0, pruef-treff 80/0,
pruef-willkommen 67/0, pruef-sackgassen 13/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 10:14:25 +02:00
DogFatherGitandClaude Opus 5 af56f97f4c screen2: EIN Resuemee statt neun -- mit Schritt und Team-Bezug
Filipe: "ich will dass das viel schoener aussieht und nicht so ein
scheiss durcheinander, man wird ja bekloppt. das resume unten auf
jeder frage hab ich auch schon mehrmals gesagt muss weg ich will ein
ganzes gesamtresume was die leute animiert und pusht immer und mega
geile super team loesungen findet aber auch individuel so dass jeder
sich selber auch verbessert und steigert fuers team."

WAS WEG IST
Der Block "Was dein Verlauf sagt" -- eine Zeile JE FRAGE, jede mit
Titel, Marke, Einordnung aus der Forschung und einem "Was hilft". Bei
neun Fragen neun Kaesten untereinander. Genau das meint "man wird ja
bekloppt": Wenn alles gleich wichtig aussieht, ist nichts wichtig,
und man liest keinen davon.

WAS AN SEINE STELLE TRITT -- UND NICHTS VERLIERT
Die Erkenntnisse sind nicht weg, sie sind zusammengefasst:

  DEIN NAECHSTER SCHRITT. Genau EINER, zu der Sache, die am meisten
  haengt. Kernfragen zuerst -- sie werden in jeder Runde gestellt, ihr
  "hakt" wiegt schwerer als das einer Zusatzfrage, die alle vier
  Runden vorbeikommt. Haengt nichts, nimmt er die Sache, die noch
  WAECHST: "nichts zu tun" ist nur fuer den richtig, bei dem alles
  laeuft. Die Einordnung aus der Forschung steht daneben -- einmal
  statt neunmal, als Grund, warum es dieser Schritt ist.

  WAS DAS TEAM DAVON HAT. Abgeleitet aus der Lage, nicht erfunden.
  Ein "gemeinsam schaffen wir das" an jemanden, bei dem fuenf von
  neun Sachen haken, ist das Gegenteil von Hilfe -- in der schwersten
  Lage ist der Team-Bezug deshalb eine Entlastung ("im Team ist
  gerade nichts von dir gefragt"), keine Aufforderung. Vier Lagen,
  vier Saetze. Die Pruefung verlangt ausdruecklich, dass es KEIN
  Spruch ist, der immer passt.

ZWEI DINGE, DIE ERST DAS BILD GEZEIGT HAT
1. "Die Menge passt gerade" stand ZWEIMAL untereinander -- einmal im
   Thema-Block, gleich darunter als Schritt. Kein Messwert meldet das;
   im Bildschirmfoto sah es aus wie ein Fehler. Der Thema-Block nennt
   die Titel jetzt nur noch, wenn es mehrere sind.
2. "Wenn du eine Sache angehst, dann die: Die Menge passt gerade" --
   die Fragetitel im Katalog sind SAETZE, keine Substantive. Jetzt
   "Fang hier an: 'Die Menge passt gerade'".

EIN FUND DER PRUEFUNG: Die TikTok-Quelle war beim Umzug ins Fazit
verlorengegangen. Filipe hatte sie ausdruecklich bestellt ("eine
professionelle auch mit infos und so aus aller welt was tiktok
angeht"). pruef-befinden hat es gemeldet.

Die Pruefung verlangte bis heute das GEGENTEIL -- eine Zeile je
Frage, zu jeder eine Einordnung. Sie ist beim Umbau rot geworden,
richtig so. Jetzt prueft sie, dass unter den Fragen KEIN Resuemee
mehr steht, dass es GENAU EINEN Schritt gibt (nicht "mindestens
einen" -- das waere auch bei neun gruen) und dass der Schritt Inhalt
hat, nicht nur einen Kasten.

pruef-befinden 116/0 (war 113), pruef-resuemee 35/0,
pruef-entwicklung 48/0, pruef-css-klassen 30/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 09:35:36 +02:00
DogFatherGitandClaude Opus 5 39276ef2ee screen6/7/8: der LIVE-Punkt, und eine Benachrichtigung, die stimmt
Filipe: "in dieser kachel soll wenn ich live bin um 20h bis 22h ein
live button der richtig geil ist mit einem live roten punkt symbol am
besten, das soll aufblinken fuer zwei stunden. man soll nicht drauf
druecken koennen aber so dass es auffaellt. ... die leute sollen auch
automatisch eine benarichtigung bekommen um 20 uhr dass ich live bin."

EINE AUSKUNFT, EINE AUSLEGUNG (workspace/assets/js/live.js)
Drei Stellen sollen dasselbe wissen: die Kachel "Draussen" auf der
Startseite, die Kanalkarten auf der Draussen-Seite, die Pulskarte
darunter. Drei Abfragen waeren drei Auslegungen -- und spaetestens
beim naechsten Umbau steht auf der Kachel LIVE und daneben "wartet".

DER DRITTE AUSGANG IST HIER DIE EIGENTLICHE ARBEIT
Die oeffentliche Seite (assets/js/streamplan.js) faengt jeden Fehler
ab und setzt istLive = false. Aus "wir konnten nicht fragen" wird
dort "er sendet nicht" -- wer das liest, macht zu und verpasst den
Stream. Der Dienst SAGT sogar, ob er nachsehen konnte (autoHealthy);
gelesen wird es dort nicht.
Hier gibt es drei Antworten: live / wartet / weiss-nicht. Bei
"weiss nicht" blinkt nichts -- aber es behauptet auch niemand, dass
nichts laeuft. Sechs Antworten des Dienstes durchgespielt.

BLINKEN OHNE FLACKERN
Hausregel vom 12.08.2026: keine aggressiven Flacker-Effekte. Das ist
kein Widerspruch zu "richtig geil", sondern dieselbe Sache: Ein Rot,
das im Sekundentakt umspringt, liest man als "Alarm, ich sehe weg".
Eins, das atmet und einen Saum nach aussen schickt, liest man als
"jetzt gerade". 1,4 Sekunden, ueberall derselbe Takt -- zwei Rhythmen
nebeneinander waeren Unruhe, einer ist ein Herzschlag. Die Pruefung
verlangt ausdruecklich >= 1 s und einen einheitlichen Takt; nach dem
Wort "animation" zu suchen waere auch bei 0,1 s gruen.
Bei Bewegungsarmut steht alles still -- der rote Punkt bleibt
sichtbar, er bewegt sich nur nicht. Im Kontrastmodus sagt es ein
Rahmen, weil Farben dort nichts tragen.

KEIN KNOPF, UND ES SIEHT AUCH NICHT SO AUS
pointer-events: none ist die halbe Antwort; die andere ist die Form.
Etwas, das wie ein Knopf aussieht und nichts tut, ist eine Sackgasse.
Deshalb eine Marke wie auf einer Kamera: Punkt plus Wort. Das Wort
steht auch fuer Vorleseprogramme da -- ein stummer roter Kreis waere
die halbe Auskunft.

DIE KACHEL WIRD UEBER IHR ZIEL ERKANNT, NICHT UEBER DEN NAMEN.
Der Name hat sich in diesem Haus schon zweimal geaendert ("Unsere
Seiten" -> "Draussen"), das Ziel nie. Am 21.09. hat genau dieser
Unterschied eine ganze Hinweisspalte lahmgelegt.

DIE BENACHRICHTIGUNG ENTSCHEIDET DER DIENST, NICHT DIE UHR.
Eine Meldung "er ist live", waehrend er nicht sendet, funktioniert
genau einmal: Beim zweiten Mal weiss jeder, dass sie nichts bedeutet.
Deshalb prueft der Lauf (alle fuenf Minuten) den echten Status; bei
"weiss nicht" wird NICHTS verschickt. Ein Merkmal mit Datum haelt es
bei einer pro Abend -- sonst kaemen in zwei Stunden 24.
Eigene Art "dogfather_live", vorgegeben an und trotzdem abschaltbar:
Wer jeden Abend dieselbe Meldung bekommt und nie hinschaut, schaltet
sonst ALLES ab, und dann erreicht ihn auch keine Aufgabe mehr.

EIN FEHLER, DEN DIE PRUEFUNG GEFANGEN HAT: Der Versand las aus
"push_geraete" -- diese Tabelle gibt es nicht, sie heisst
push_anmeldungen. Der Block steht in einem try/catch; der Fehler
waere still geblieben, und die Benachrichtigung waere nie gekommen.
Die Pruefung verlangt jetzt ausdruecklich, dass die Tabelle im
Schema existiert.

NEU: pruef-livepunkt 49/0, mit drei Gegenproben.
Daneben gruen: pruef-css-klassen 30/0, pruef-push 24/0,
pruef-draussen 39/0, pruef-zwischenspeicher 27/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 09:28:29 +02:00
DogFatherGitandClaude Opus 5 227c6c0425 screen5 und screen4: zwei Farben gesetzt, 14 auseinandergezogen
screen5 (ausdruecklich VOR screen4, wie gewuenscht):
  "Vertraulich melden" traegt jetzt Ton 28 -- die Farbe, die "Regeln
  & Hilfe" hatte. Beide gehoeren zusammen: Wer Hilfe sucht, landet
  bei einem von beiden. "Regeln & Hilfe" bekam dafuer einen eigenen
  Ton; zwei Kacheln mit derselben Farbe in derselben Ansicht waeren
  genau das, was screen4 abschaffen soll.
  "Draussen" ist knallrot: Ton 38 = #ff1a1a, voll gesaettigt,
  Kontrast 4,84:1 gegen den Grund. Gemessen, nicht geschaetzt -- von
  zehn Rotwerten zwischen #ff0000 und #ff5555 erfuellen alle die
  4,5:1, dieser ist der knalligste, der auf dunklem Grund nicht
  flimmert. Er traegt ab 20 Uhr den LIVE-Punkt.
  Beide sind ab jetzt GESETZT: pruef-kachelfarben wird rot, wenn ein
  Farblauf sie anfasst. Eine Festlegung, die nur im Kommentar steht,
  ist eine Bitte.

screen4: neues Werkzeug tools/kachel-farben-entzerren.mjs.
  Der Unterschied zu den zwei vorhandenen: Es rechnet nur mit den
  BENUTZTEN Toenen. In start.css stehen 42, benutzt werden 31 -- die
  anderen Werkzeuge weichen also Farben aus, die kein Mensch sieht,
  und machen dadurch die Abstaende zwischen den sichtbaren unnoetig
  klein. Welche benutzt werden, wird aus den Kachellisten ABGELEITET.
  Von jedem aehnlichen Paar aendert sich genau EINER -- der, der
  nicht gesetzt ist.
  Ergebnis: engstes Paar 0,0741 -> 0,0978 (Faktor 1,32), 14 Toene
  geaendert, alle 31 erreichen 4,5:1.

ZWEI DINGE, DIE ERST DAS MESSEN GEZEIGT HAT
1. Der erste Lauf schlug fuer "Dateien" ein #ffe5ae vor -- Buntheit
   0,076, ein helles Creme. Rechnerisch die beste Stelle im Farbraum,
   auf dem Bildschirm genau das, was Filipe seit Wochen abschafft.
   Mindestbuntheit eingebaut, Schwelle GEMESSEN: Median aller Toene
   0,168, die fuenf blassesten 0,064-0,088. 0,12 liegt dazwischen.
2. Die Abstandsrechnung fasst einen Ton nie an, der weit weg von
   allen liegt -- auch wenn er blass ist. So blieben drei benutzte
   Toene unter 0,12 stehen. Zweite Runde: jeder blasse wird kraeftig
   gemacht, solange das Minimum ueber 0,095 bleibt. Gemessener Preis
   0,1028 -> 0,0978, also 5 Prozent; auf dem Bildschirm nicht zu
   sehen, waehrend Filipes Klage ueber helle Kacheln konkret ist.

NEU: pruef-kachelfarben 13/0 -- getrennt, eindeutig je Ansicht,
festgelegt, lesbar und nicht blass. Mit vier Gegenproben, damit sie
auch rot werden KANN.
NEU: tools/farben-blick.mjs -- sieht die Wand mit echten Augen an und
misst das, was eine Abstandstabelle nicht beantwortet: ob zwei
NEBENEINANDER liegende Kacheln aehnlich aussehen. Gemessen bei
DogFather und Community: kein Nachbarpaar unter 0,09.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 09:21:54 +02:00
DogFatherGitandClaude Opus 5 5bde49e0cd Was unten im Brett steht, steht jetzt auch oben im Band
Filipe am 22.09.: "die aufgaben die man unten sieht soll man auch
oben sehen."

GEMESSEN an den echten Daten: aufgaben_zuteilung hatte NULL Zeilen,
waehrend im Brett zwei Aufgaben standen (OFFEN 1, IN ARBEIT 1). Jede
Person las oben "nichts zugeteilt". Die Aufgaben hingen am aelteren
Feld aufgaben.verantwortlich_id -- genau dem Feld, nach dem das Brett
gruppiert. Die Uebersicht las eine andere Quelle als die Liste
darunter.

resuemeeFuer() zaehlt jetzt BEIDE Wege und keinen doppelt: Gibt es zu
einer Aufgabe eine Zuteilungszeile fuer die Person, gewinnt die
Zuteilung (genauerer Zustand). Nur wo keine Zeile existiert, zaehlt
das alte Feld. Die Zuordnung status->zustand steht an EINER Stelle;
"review" zaehlt wie "arbeit", "abgebrochen" zaehlt nirgends -- so wie
im Brett auch.

Die Personenliste wird nicht mehr aufgezaehlt, sondern abgeleitet:
die Rollen des Hauses (immer, auch mit null Aufgaben -- wer frei ist,
ist die haeufigste Frage) PLUS jede aktive Person, der eine Aufgabe
gehoert. Ohne den zweiten Teil koennte im Brett eine Aufgabe stehen,
deren Mensch oben fehlt.

pruef-zuteilung 71/0 (war 65). Der neue Abschnitt legt eine Aufgabe
GENAU SO an wie die echten alten -- verantwortlich_id, keine
Zuteilungszeile -- und misst Filipes Satz direkt: "unten im Brett
stehen genauso viele wie oben (2 = 2)". Zahl in der Bedingung, nicht
nur im Meldetext.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 09:12:20 +02:00
DogFatherGitandClaude Opus 5 06f3fecaa7 Material: Bilder und Videos zum Posten, jedes nur einmal
Filipe, 22.09.2026: "ich brauch auch noch eine neue kachel im bereich
community, wo wir als team ... bilder reinschicken koennen, mit text
und wo die leute sei es community oder modis sich die bilder nehmen
koennen zum posten. die community soll keine posten koennen ... sobald
ein bild oder ein video ... runtergeladen wurde, soll direkt blockiert
werden ... damit nie ein bild zwei mal gepostet wird ... und die rechte
hand und dogfather, nur die beiden sollen auch immer sehen koennen wer
das bild oder video runtergeladen hat."

DER KERN IST DIE EINMALIGKEIT, und deshalb sind Nehmen und Laden ZWEI
Schritte. "nehmen" schreibt in EINER Abfrage fest, wer es hat -- mit
`WHERE genommen_von IS NULL` in der Bedingung. Wer zu spaet kommt,
aendert null Zeilen und bekommt 409. Ein einziger Schritt ("laden und
dabei markieren") haette dieselbe Luecke wie ein Pool ohne Sperre:
zwei Anfragen, beide sehen "frei", beide laden.

UND DIE SPERRE GILT AUCH FUER DIE VORSCHAU. Waere sie offen
geblieben, waere sie der Weg, ein vergebenes Bild doch noch zu
bekommen (Rechtsklick, speichern) -- und die ganze Einmaligkeit eine
Behauptung. Ausnahme: wer es selbst genommen hat, sieht es weiter.

WER WEN SIEHT, entscheidet der Server, nicht die Seite. Fuer alle
ausser DogFather und der rechten Hand fehlt das Feld `genommen_von`
ganz -- nicht `null`: Ein Feld, das da ist und leer bleibt, laedt
dazu ein, es spaeter "zu fuellen".

pruef-material.mjs (70 Pruefungen, 0 Fehler) misst den ganzen Weg,
mit Gegenprobe zu jeder Grenze. Die Zahl der vergebenen Stuecke steht
in der BEDINGUNG -- ohne sie waere "keine Namen dabei" trivial wahr.

DREI DINGE HAT ERST DER BLICK MIT ECHTEN AUGEN GEFUNDEN
(tools/material-blick.mjs, drei Rollen, vier Bildschirmbreiten):

  * "hat es genommen am 22.09.." -- eine deutsche Datumsangabe endet
    selbst auf einen Punkt. Kein Pruefprogramm haette danach gefragt.
  * Die Knoepfe standen auf drei verschiedenen Hoehen (1127, 1155,
    1176), weil der eine Text zwei Zeilen hatte und der naechste
    keine. `margin-top: auto` am Fuss statt einer geratenen
    Mindesthoehe.
  * "Schon benutzt" nahm 273 px Hoehe je Stueck fuer ein einziges
    Zeichen -- das Bild ist dort ohnehin nicht mehr abrufbar. Jetzt
    eine Zeile mit 96 px.

Am Handy (412 px) blieb es bei EINER Spalte: 3062 px Seitenhoehe fuer
fuenf Stuecke. Filipe: "es ist alles so lang gezogen, muss ewig
scrollen". Statt einer festen Umbruchschwelle -- die am 06.09. schon
zweimal teuer war -- waechst die Spaltenbreite jetzt mit:
`max(160px, 22%)`. Gemessen 360/412/768/1500 px: 2/2/3/3 Spalten,
nirgends ein Ueberlauf, 412 px jetzt 2014 statt 3062 px.

Dazu neun Saetze in meldung.js. Der wichtigste ist "schon_genommen",
und er ist bewusst kein Fehler: Wer ihn liest, hat nichts falsch
gemacht. pruef-meldungen fand dabei einen Rest aus dem Aufgaben-Block
-- `nur_leitung_legt_an` hatte keinen Satz, ein Modi mit altem Tab
haette rohen Maschinentext gelesen.

pruef-material 70/0 · pruef-meldungen 8/0 · pruef-treff 80/0
pruef-rechtetafel 19/0 · pruef-sackgassen 13/0 · pruef-css-klassen ok
pruef-zwischenspeicher 27/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 02:27:21 +02:00
DogFatherGit e4c6d69ce8 "Wie geht's dir?" -- lesbar und um ein Drittel kuerzer
Filipe: "auf der seite von der kategorie wie gehts die, sind die
kacheln viel zu hell, man bekommt fast nichts gelesen, die sollen viel
kraeftiger und dunkler sein. ich will dass auch alles viel
uebersichtlicher ist, es ist alles so lang gezogen, muss ewig scrollen
um alles zu sehen."

BEIDES GEMESSEN, BEVOR ICH ETWAS ANGEFASST HABE:

  Kachelgrund   rgba(0, 0, 0, .2) -- also 80 % durchsichtig. Die Seite
                traegt ein helles Buehnenbild (Husky, Hase, viel
                Licht), und das schien mitten durch den Text.
  Laenge        2487 px am Rechner, 3431 px am Handy. 3,4 Bildschirme
                fuer neun Fragen.

DIE LESBARKEIT: Die Kacheln sind jetzt deckend -- und nicht schwarz,
sondern einen Hauch heller als die Seite, damit sich eine Frage von
der naechsten abhebt. Gemessen mit pruef-buehne: schlechtester
Kontrast 4.95:1 an 39 gemessenen Stellen (noetig 4.5).

DIE LAENGE -- gespart wurde an Weissraum und Wiederholung, NICHT an
Text. Die Erklaerung unter jeder Frage ist der Grund, warum man sie
ehrlich beantwortet.

  Vier Knoepfe, eine Reihe. Gemessen waren sie 94 von 214 Pixeln je
  Frage -- zwei Reihen, also 450 Pixel Scrollweg allein aus Umbruch.
  Gerechnet: 390 minus 28 Innenabstand minus drei Luecken, geteilt
  durch vier = 86 px je Knopf. "Kann ich nicht sagen" braucht mehr,
  "Unklar" nicht. Der LANGE Name bleibt im `aria-label` -- wer hoert
  statt sieht, bekommt weiterhin den ganzen Satz.

  Die Marke "jede Runde" steht neben der Frage statt darunter. Sie ist
  eine Eigenschaft der Frage, keine eigene Zeile.

  Zwei Spalten am Rechner. Bei 880 px Inhaltsbreite und Fragen, die
  keine 400 brauchen, halbiert das den Weg, ohne eine Frage zu
  verstecken. `break-inside: avoid` ist dabei der Kern -- sonst steht
  die Antwortreihe in der anderen Spalte.

ERGEBNIS: Rechner 2487 -> 1770 px, Handy 3431 -> 2781 px. Eine
Fragekachel am Handy 228 -> 139 px.

Und ein Fehler, den nur das Bildschirmfoto gezeigt hat: Mein erster
Anlauf sparte die Kurzform, wenn sie dem Namen gleicht -- bei "Laeuft"
ist das so. Am Handy ist die lange Fassung ausgeblendet, und der Knopf
zeigte dann nur noch das Haekchen.

Geprueft: pruef-befinden 113/0, pruef-resuemee 35/0,
pruef-entwicklung 48/0, pruef-buehne fuer diese Seite 10/0.
2026-09-22 02:02:46 +02:00
DogFatherGit bc9a902ffb Die Knoepfe stehen nicht mehr vor dem Text -- und verteilt wird bei "Eure Aufgaben"
ZWEI WUENSCHE, EINE URSACHE: beide gehen auf den Block "Noch jemanden
dazunehmen" zurueck, der am 21.09. ins Aufgabenformular kam.

1. "DIE ZWEI BUTTONS SOLLEN NICHT VOR DEM TEXT STEHEN"

Gemessen bei 1280 px: "Anlegen" und "Abbrechen" lagen ueber zwei
Hinweisen, mit 363x27 und 363x10 Pixeln Ueberlappung.

Die Ursache ist eine Regel vom 17.09., und sie ist richtig: Der
Hinweis haengt ABSOLUT unter seinem Feld, damit die Eingaben auf einer
Linie bleiben. Was aus dem Fluss genommen wird, belegt aber keinen
Platz -- solange darunter nur der Rasterabstand kam, fiel das nicht
auf. Mit dem neuen Knopf wurde die Zelle hoeher, und der Hinweis
wanderte mit, direkt auf die Knoepfe.

Jetzt bekommt das Raster unter sich 44 px, wenn es einen haengenden
Hinweis gibt (`:has()`, nicht pauschal -- ein Formular ohne Hinweis
bekaeme sonst Leere geschenkt). Die Hoehe ist gemessen: ein Hinweis
ist zweizeilig 35 px hoch plus 4 px Abstand.

UND EIN ZWEITER FUND AN DERSELBEN STELLE: Der Block sass IN der Zelle
"Wer macht es?". Dadurch stand deren Eingabe bei 780..824, die
Nachbarin "Fuer welchen Kanal?" bei 833..877 -- 53 Pixel Versatz, und
genau das sieht man als "verzogen". Er steht jetzt als eigene
Rasterzeile hinter beiden; danach sind sie wieder buendig. Als eigene
Zeile ist er ausserdem ehrlicher: "Noch jemanden dazunehmen" ist ein
zweiter Schritt, kein Teil des ersten.

Gefunden hat beides pruef-formulare, die seit dem 07.09. auf buendige
Unterkanten prueft und seit dem 21.09. rot war.

2. "BEI EURE AUFGABEN DIE AUFGABEN VERTEILEN"

Filipe, zum wiederholten Mal -- und so stand es auch im Auftrag vom
21.09. (Abschnitt 2). Auf "Eure Aufgaben" steht jetzt ein Band
"Aufgabe verteilen". Es nimmt die gerade gewaehlte Person mit:
"Aufgabe fuer Kessi" fuehrt auf das Aufgabenbrett, oeffnet das
Formular und traegt sie ein.

EIN WEG, KEIN ZWEITES FORMULAR. Zwei Formulare fuer dieselbe Sache
waeren zwei Gelegenheiten, eines zu vergessen -- und man wuesste nie,
welches das richtige ist.

Beim Bauen gemessen: Das Band blieb unsichtbar, bis man eine Person
anklickte -- `window.__ich` kommt ueber das Netz und steht beim ersten
Aufruf noch nicht. Jetzt wird darauf gewartet, laengstens drei
Sekunden, statt eine Zahl aus dem Kopf zu setzen.

Zwei Pruefungen waren selbst kaputt: pruef-formulare zaehlte ein
Eingabefeld mit, das in einem zugeklappten Block liegt und Hoehe 0 hat
-- ein Feld, das man nicht sieht, kann nicht schief stehen.
pruef-entwicklung verlangte, dass ein Modi "Eure Aufgaben" NICHT
bekommt; das hat Filipe heute umgedreht.

Geprueft: pruef-formulare 19/0 (war 18 ok / 1 FEHL), pruef-entwicklung
48/0 (war 45/1), pruef-aufgabenbrett 49/0, pruef-css-klassen 30/0.
Der ganze Weg am Bildschirm gemessen: Band sichtbar, Person mitgenommen,
Formular offen, richtige Person gewaehlt, keine Skriptfehler.
2026-09-22 01:57:08 +02:00
DogFatherGit 4b87f27451 Niemand erfaehrt, was er nicht hat -- und die Kacheln tragen ihre Farbe
ZWEI WUENSCHE, DIE ZUSAMMENGEHOEREN: die Willkommensseite.

1. "KEINER SOLL WISSEN WAS ER NICHT SIEHT"

Filipe: "das geht keinen was an. sie sehen die sachen ja nicht weil es
sie nichts angeht und das muss auch nicht erwaehnt werden.
kontrollier das ueberall bitte."

Durchgesehen: Das Haus macht es ueberall sonst schon richtig -- der
Server antwortet mit 404 statt 403, damit ein "das darfst du nicht"
gar nicht erst verraet, dass es etwas gibt. GENAU ZWEI Stellen taten
das Gegenteil, beide auf der Willkommensseite:

  der Hinweis "Was du nicht siehst" (linke Hand),
  und in ihrer Einleitung "Was du NICHT hast: Personen anlegen,
  Rollen aendern und den vertraulichen Meldeweg".

Beide entfernt, der Hinweis mit einem Kommentar an seiner Stelle --
damit ihn niemand spaeter "nachtraegt", weil er ihn fuer vergessen
haelt. Im Kopf derselben Datei stand die Ueberlegung uebrigens schon:
"Eine Liste von Dingen, die man nicht darf, ist keine Orientierung,
sondern eine Kraenkung."

Die Pruefung verlangte bis heute das GEGENTEIL ("ihr wird gesagt, was
sie nicht hat"). Sie misst jetzt alle fuenf Rollen gegen acht Muster,
mit Gegenprobe -- das "ueberall" aus dem Auftrag.

2. DIE FARBEN DER STARTSEITE

Der Server reicht `ton` durch, die Kachel traegt `data-ton="N"`, und
start.css macht daraus `--ton`. Keine eigene Farbtabelle: Die waere
die, die beim naechsten Farbwechsel stehen bleibt -- genau das ist am
19.09. elf Seiten passiert.

Drei Stellen tragen die Farbe, keine davon eine Flaeche: das Zeichen,
eine schmale Kante links und ein leiser Schimmer in der oberen Ecke.
Eine eingefaerbte Kachelflaeche waere bunt und schlecht lesbar.

UND EIN FEHLER, DEN NUR DAS MESSEN GEZEIGT HAT: Mein erster Anlauf
setzte `--ton: var(--akzent)` als Vorgabe auf `.w-kachel`. Gleiche
Spezifitaet wie `[data-ton="N"]` in start.css -- und willkommen.css
laedt SPAETER. Ergebnis: 0 von 14 Kacheln trugen die richtige Farbe,
alle waren blau. Der Rueckfall gehoert an die Verwendung
(`var(--ton, …)`), nicht an die Deklaration. Danach: 14 von 14.

Geprueft: pruef-willkommen 67/0, pruef-css-klassen 30/0.
2026-09-22 01:43:31 +02:00
DogFatherGit 82335c783d Die rechte Hand legt selbst Personen an -- und sieht die Codes
Filipe: "dan will ich dass die rechte hand auch neue personen
hinzufuegen kann. also neue erstellen kann und die codes genau so
sieht wie dogfather, damit sie das auch machen kann wenn er live ist."

WAS SIE DARF: Modis und Community anlegen, und deren Codes neu setzen.
Die Liste ist ABGELEITET aus ROLLEN_ZUM_AENDERN -- dieselben zwei
Rollen, die sie ohnehin vergeben darf. Zwei Listen waeren zwei
Gelegenheiten, eine davon zu aendern und die andere zu vergessen.

WAS SIE NICHT DARF: eine zweite rechte Hand, eine linke Hand oder
einen zweiten DogFather anlegen -- und an einer linken Hand auch
nichts aendern. Ohne die zweite Schranke haette sie den Code einer
linken Hand neu setzen koennen und damit einen Zugang in der Hand, der
fast so viel darf wie sie selbst. Die alte Schranke kannte nur "admin"
und "manager".

NUR DIE RECHTE, NICHT DIE LINKE. `istHand()` haette beide getroffen;
fuer die linke Hand ist "legt niemanden an" eine ausdrueckliche
Entscheidung vom 21.09.

VIER STELLEN IN DER OBERFLAECHE, die alle an Rollennamen hingen:

  `nurLesen = ich.rolle === 'hand'` -- sie bekam die Liste und kein
  Formular. Jetzt abgeleitet aus `darf_anlegen`.

  Die Wache darueber warf sie auf die Startseite, sobald `nurLesen`
  falsch wurde. Die Seite ging fuer sie einfach nicht auf, ohne
  Meldung.

  Der Sendeweg hing an `ich.rolle === 'admin'`. Fuer sie gab es damit
  GAR KEINEN: Die Seite antwortete "Fuer die Rolle modi gibt es hier
  keinen Weg" -- ein Satz, der wie ein Formularfehler klingt und eine
  fehlende Zeile war.

  UND EIN ECHTER FUND: `rollenwahlErgaenzen()` hing jede Zusatzrolle an
  das Formular, die mit der Personenliste kam -- ohne zu fragen, ob man
  sie anlegen darf. Solange nur DogFather das Formular sah, fiel es
  nicht auf: Er darf sie alle. Der rechten Hand bot es "rechte Hand"
  und "linke Hand" an. Der Server haette es abgelehnt -- aber der Knopf
  verriet eine Rolle, die sie nicht vergeben soll.

Zwei Pruefungen waren dabei selbst kaputt: pruef-personen-formular
erwartete sieben Rollen (seit "linke" am 21.09. sind es acht) und
suchte den Namen im sichtbaren Text -- die Abschnitte sind zugeklappt
und zeigen nur Anfangsbuchstaben. Beides abgeleitet statt gezaehlt.

Geprueft: pruef-personen-formular 43/0 (war 34 ok / 2 FEHL), davon
neun am echten Bildschirm auf der Crew-Adresse -- anmelden, Formular
oeffnen, anlegen, Code lesen, Person in der Liste wiederfinden.
pruef-haus-trennung 81/0 (war 72 ok / 2 FEHL), pruef-rollen-anlegen
11/0.
2026-09-22 01:39:12 +02:00
DogFatherGit 39c0b4dc1f Ein Modi sieht nur SEINE Aufgaben -- und gibt sich selbst keine
Filipe, unmissverstaendlich und mehrfach: "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."

DAS DREHT DIE ENTSCHEIDUNG VOM 09.09. AUSDRUECKLICH UM. Damals: "ja,
sie sind untereinander ein team", damit ein Schichttausch ohne Umweg
geht. Beides steht jetzt im Code nebeneinander, damit niemand spaeter
die aeltere findet und fuer die gueltige haelt.

VIER AENDERUNGEN:

  Die Sicht. Ein Modi sieht nur `a.verantwortlich_id = ich`. Was ihm
  ueber aufgaben_zuteilung gegeben wurde, haengt mitZugeteilten() an --
  ein Pool, in dem er steht, bleibt also sichtbar, bis ihn jemand
  uebernimmt. Die rechte und die linke Hand behalten die Uebersicht.

  Das Anlegen. Im Team Dogi legt nur an, wer auch verteilen darf. 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.

  Der Knopf. "Neue Aufgabe" steht fuer einen Modi gar nicht mehr da.
  Ein Knopf, der mit 403 antwortet, ist schlimmer als keiner: Die
  Meldung erscheint ganz oben, und wer weiter unten steht, sieht nur,
  dass nichts passiert.

  Die Kacheln. Ein Modi sieht jetzt den Bereich "Entwicklung &
  Nachwuchs" mit denselben zwei Kacheln wie die Leitung -- nicht mehr
  zwei eigene mit anderem Namen. Zwei Namen fuer dieselbe Sache ist
  genau der Fehler, der am 19.09. zwei Kacheln "Chat" ergeben hat.
  "Talente" bleibt draussen: Dort stehen Notizen ueber Zuschauer, die
  nichts davon wissen.

UND DIE LINKE HAND SIEHT "DEIN TEAM" NICHT MEHR (Filipes Wunsch).
Abgeleitet, nicht nachgebaut: Ihre Liste ist die der rechten Hand
MINUS dieser einen Kachel, erkannt am ZIEL statt am Namen -- der Name
ist am 17.09. schon einmal gewandert.

Gemessen: admin 30 Kacheln, hand 30, linke 29 (ohne "Dein Team"),
modi 25 (mit dem Bereich, ohne Talente).

Zwei Pruefungen hielten die alte Regel fest und wurden dadurch rot --
genau ihre Aufgabe. Beide umgedreht, mit der alten Entscheidung im
Kommentar. pruef-zuteilung 65/0, pruef-verteilen 19/0 (war 15),
pruef-aufgabenbrett 49/0.
2026-09-22 01:17:11 +02:00
DogFatherGit ea32d6790b Das Auge ist am Finger ein volles Ziel -- und die Leiste bleibt eine Reihe
Filipe zur offenen Entscheidung "36-px-Auge oder 44-px-Fingerziel":
"mach was du am besten haelst es soll nur immer alles einfach zu
bedienen sein und geil aussehen fertig."

DIE ENTSCHEIDUNG WAR EINE SCHEINALTERNATIVE. Gemessen am echten
Aufbau, statt der Notiz zu glauben:

    Breite    Auge      uebrige Knoepfe   Leiste
    360 px    42 x 44   alle 44 x 44      zwei Reihen
    390 px    42 x 44   alle 44 x 44      zwei Reihen
    412 px    34 x 44   alle 44 x 44      eine Reihe
    1280 px  116 x 32   mit Beschriftung

Die HOEHE stimmte laengst. Es fehlten zwei Pixel Breite -- bei 412 px
zehn. Der Umschalter war als einziger Knopf der Leiste kein volles
Ziel, und ausgerechnet er sitzt zwischen zwei anderen.

ZWEIMAL DIE ALTE FALLE AUF DEM WEG:

  Erster Anlauf vergroesserte nur den Knopf. Gemessen bei 412 px:
  Knopf 44, Behaelter 36 -- der Knopf ragte 3 px ueber den Nachbarn.
  Genau so lag am 11.09. der Umschalter ueber dem Chat-Knopf, und wer
  "Meine Sicht" antippte, landete im Chat. Die Lehre von damals steht
  in start.css ("wer nur den Rahmen begrenzt, begrenzt nichts") und
  gilt andersherum genauso.

  Danach brach die Leiste bei 412 um -- "Abmelden" in einer zweiten
  Zeile, genau Filipes Beanstandung vom 09.09. Gerechnet: 386 px
  noetig, 380 verfuegbar. Sechs Pixel. Sie kommen jetzt aus dem
  Weissraum (4->2 zwischen den Zeichenknoepfen, 10->6 zur linken
  Gruppe), nicht aus den Tippzielen -- am Ziel zu sparen ist genau der
  Fehler, der sie ueberhaupt erst auf 34 und 36 gebracht hat.

NEBENGEWINN, nicht geplant: Bei 390 px -- der haeufigsten Breite --
geht die Leiste dadurch von zwei Reihen auf eine, 117 px auf 69. Bei
360 px bleibt sie zweireihig, und das ist richtig: Dort fehlen auch
so noch zwoelf Pixel, und Umbrechen ist die ehrliche Antwort auf zu
wenig Platz.

Am Rechner unveraendert: 116 x 32 mit Beschriftung, weil dort eine
Maus zielt und kein Daumen. Die Regel haengt an `pointer: coarse`.

Gemessen nachher: alle vier Breiten 44 x 44, keine Ueberlappung,
nichts breiter als der Schirm. pruef-tippziele 11/0,
pruef-css-klassen 30/0.
2026-09-22 00:58:42 +02:00
DogFatherGit 2b6c2be1ad Die Stelle bleibt -- auch wenn die Seite dazwischen neu laedt
Filipe, zum vierten Mal: "wenn ich in eine kategorie rein gehe und dan
zurueck geh die hauptseite immer wieder ganz hoch ... ohne dass die
seite hoch scrollt ODER NEU LAEDT."

DAS "ODER NEU LAEDT" WAR DER HINWEIS, und ich habe ihn zweimal
ueberlesen. kopf.js laedt die Seite selbst neu, sobald der Browser sie
aus seinem Rueckwaerts-Speicher holt -- damit keine veralteten Zahlen
dastehen. Nach einem Neuladen heisst die Navigationsart aber "reload",
nicht "back_forward".

UND DIE EIGENTLICHE BOSHEIT stand in einer Zeile, die ich selbst
geschrieben habe: Wurde eine Ankunft nicht als Zurueck erkannt, wurde
die gemerkte Stelle GELOESCHT. Ein einziges Neuladen reichte -- danach
half auch das naechste Zurueckgehen nicht mehr. Deshalb "geht es immer
noch nicht", obwohl ich es dreimal fuer behoben hielt.

WARUM ES IN JEDER MESSUNG FUNKTIONIERT HAT: kopf.js haelt einen
Ereignisstrom offen, und der sperrt den Rueckwaerts-Speicher aus.
`persisted` bleibt hier immer false, die Neulade-Zeile lief nie. Auf
einem echten Handy greift er sehr wohl. Man muss den Weg gehen, den der
Mensch geht -- und wenn man ihn nicht nachstellen kann, baut man gegen
ALLE Wege robust statt gegen einen.

FUENF AENDERUNGEN:

  Die Stelle wird LAUFEND gemerkt (gedrosselt auf 250 ms), nicht nur
  beim Klicken und Verlassen. Deckt auch die Glocke, eine
  Benachrichtigung und einen Absturz des Reiters ab.

  Nichts wird mehr geloescht. Die Stelle verfaellt von selbst nach
  einer Stunde.

  Wiederhergestellt wird jetzt auch bei "reload" und bei "navigate mit
  Herkunft aus diesem Haus" -- nicht nur bei "back_forward".

  Vor dem Neuladen aus dem Rueckwaerts-Speicher wird die Stelle samt
  Merker festgehalten.

  Der Pfeil in der Kopfleiste setzt den Merker jetzt fuer BEIDE seiner
  Wege. Er nimmt history.back() nur, wenn `document.referrer` da ist --
  sonst location.assign(), und das ist fuer den Browser ein Hingehen.
  Hier stand "der braucht nichts"; fuer den zweiten Weg stimmte das nie.

Ein Neuanfang faengt weiterhin oben an: keine Herkunft, kein Merker --
also vom Startbildschirm, aus einer Benachrichtigung, ueber die
Adresszeile.

Beim Bauen fast hineingelaufen: `START` steht in einem anderen Block
derselben Datei und waere an der neuen Stelle ein Absturz gewesen --
dieselbe Falle wie bei `$` am 21.09. Jetzt gibt der erste Block ihn
einmal bekannt, statt ihn abzuschreiben.

Geprueft: pruef-stelle 15/0 (war 9) -- Brotkrume (navigate),
Browser-Zurueck (back_forward), NEULADEN (reload), Neuanfang oben, und
dass eine fremde Ankunft die Stelle nicht wegwirft. Dazu pruef-sprung
43/0, pruef-start-ansicht 153/0, pruef-css-klassen 30/0.
2026-09-22 00:54:28 +02:00
DogFatherGit 66789aabcd Willkommen: eine Seite, die erklaert, was es hier gibt
Auftrag vom 21.09.2026, Abschnitte 7 und 8. Aus der Kachel "Der Treff"
wird die Willkommensseite.

WARUM DAS NICHTS VERLIERT, gemessen am echten Bestand: Das Brett
"treff" hatte NULL Eintraege, der Treff-Chat daneben 29 Nachrichten.
Geredet wird im Chat; das Brett war eine Kachel ohne Inhalt.

DIE SEITE ERKLAERT NICHT "DIE WEBSITE", SONDERN DEINE. Sie baut sich
aus derselben Kachelliste wie die Startseite, durch denselben Filter
(darfSeite). Wer morgen eine Kachel bekommt, bekommt automatisch auch
ihre Erklaerung -- und wer eine nicht hat, liest nicht davon. Eine
Liste von Dingen, die man nicht darf, ist keine Orientierung.

Gemessen: DogFather 30 Kacheln, Modi 25, Community 11 -- und keine
einzige davon ist fuer den Betreffenden gesperrt.

DREI FEHLER, DIE ERST DAS BILDSCHIRMFOTO GEZEIGT HAT:

  body class="gate" ist die ANMELDEWAND (display:flex, zentriert).
  Kopfleiste und Inhalt standen dadurch NEBENEINANDER -- am Handy
  blieben dem Text 260 von 390 Pixeln.

  .huelle gibt es im Haus gar nicht. Der Inhalt stand linksbuendig
  statt mittig, ohne Sicherheitsrand an randlosen Geraeten. Jetzt
  .inhalt wie jede andere Seite.

  Der Text stand direkt auf dem Buehnenbild: Kontrast 1.68:1 am
  Rechner, 2.23:1 am Handy (noetig 4.5). Die Hausregel stand daneben
  in start.css -- "der Text steht auf eigenen Flaechen" -- und diese
  Seite hielt sich als einzige nicht daran. Jetzt 5.19 und 7.73.

UND EIN LECK, ZUM DRITTEN MAL DIESELBE URSACHE:

Die Kachel umzuleiten nahm dem Brett "treff" die Zugehoerigkeit --
TREFF_BRETTER wird aus Kachelzielen abgeleitet. Die Schranke laesst
eine AGENTURROLLE unbesehen durch, wenn ein Brett in keiner Liste
steht: Eine Creatorin konnte das Brett des Treffs lesen.

Behoben, und diesmal dauerhaft laut gemacht: Nachgemessen ist die
Trennung exakt und in beide Richtungen deckungsgleich -- die Bretter
mit `fuerAlle` sind genau die des Treffs plus die Agenturablage. Das
ist eine Eigenschaft des BRETTS und wandert nicht, wenn jemand eine
Kachel umleitet. pruef-treff prueft das jetzt.

Mein erster Entwurf der Regel war zu breit und meldete `content` und
`schutz` -- beides Agenturbretter, die eine Agenturrolle zu Recht
liest. Eine Pruefung, die zu viel meldet, wird abgeschaltet.

AUSSERDEM: 16 Kennungen aus workspace-zuteilung.js hatten keinen
deutschen Satz -- auf dem Bildschirm haette woertlich "nicht_zugeteilt"
gestanden. Gefunden von pruef-meldungen am selben Tag.

Und zwei Erwartungen in pruef-treff abgeleitet statt gezaehlt: die
Zahl der Rollenkacheln auf der Wand (die Anmeldung sucht WHERE rolle=?,
eine Rolle ohne Kachel ist unerreichbar) und "die breite Kachel steht
vorne" ueber die Eigenschaft statt ueber den Namen.

Geprueft: pruef-willkommen 66/0 (neu), pruef-treff 80/0 (war 59 ok /
13 FEHL), pruef-buehne fuer die neue Seite 10/0, pruef-meldungen 8/0,
pruef-css-klassen 30/0, pruef-rechtetafel 19/0.
2026-09-22 00:00:14 +02:00
DogFatherGit b506c7f533 Die Oberflaeche dazu: Resuemee, Annehmen, Ablehnen, Bewerten
Auftrag vom 21.09.2026, Abschnitte 1 bis 5 -- der sichtbare Teil.

UEBER DEM BRETT STEHT JETZT EIN BAND, und es ist rollenabhaengig:

  Modi           "Deine Aufgaben" -- sein persoenliches Resuemee mit
                 offen / in Arbeit / erledigt / ueberfaellig, und
                 darueber EIN Satz, der die Zahlen einordnet. Fuenf
                 nackte Zahlen sind eine Tabelle, ein Satz ist eine
                 Auskunft.
  DogFather,     "Wer hat gerade was" -- eine Zeile je Person mit
  beide Haende   ihren Marken. Antippen filtert das Brett auf sie,
                 noch einmal antippen zeigt wieder alles. Ohne das
                 zweite waere der Filter eine Falle: hinein ja,
                 heraus nein.

WELCHES BAND JEMAND BEKOMMT, entscheidet `darf_verteilen` vom Server
-- aufgaben.js muss die Rollen dafuer nicht kennen.

AN JEDER KARTE steht jetzt, wer sie hat und wie es bei jedem steht:
Name, Zustand, bei einer Ablehnung der Grund daneben (wer "abgelehnt"
liest, will als Naechstes wissen, warum), bei einer Rueckmeldung der
Text dazu.

Und genau die Knoepfe, die fuer DIESEN Menschen gerade gehen:
Annehmen / Ablehnen, bei einem Pool "Ich uebernehme das", danach
"Ich fange an" und "Fertig". Ein "Annehmen" an einer fremden Aufgabe
waere ein Knopf, der mit 403 antwortet -- und die Meldung erscheint
ganz oben, wo man sie bei einer Karte weiter unten gar nicht sieht.
Diese Lektion stand in aufgaben.js schon einmal.

DIE BEWERTUNG SIND DREI BENANNTE KNOEPFE, keine Auswahl im Dialog.
Abschnitt 5 nennt drei Moeglichkeiten -- als Auswahl hiesse das: erst
klicken, dann lesen, dann waehlen. Als drei Knoepfe sieht man sofort,
was es gibt. Bei "Verbesserungsmoeglichkeiten" ist der Text Pflicht
("soll ein Eingabebereich erscheinen"), bei den anderen freiwillig.

AN MEHRERE VERTEILEN ist ZUSAETZLICH und nicht statt dessen: Eine
Person ist der haeufigste Fall und bleibt ein Klick. Wer mehr will,
klappt "Noch jemanden dazunehmen" auf. Die Namen darin werden aus der
Auswahl darueber ABGELEITET -- zwei Namenslisten in einer Datei, die
jeder herunterlaedt, waeren eine zu viel. Die Frage "wie soll das
laufen" erscheint erst ab zwei Leuten; vorher waere sie eine
Entscheidung ohne Gegenstand.

EIN EIGENES MODUL (zuteilung.js), weil aufgaben.js schon 1900 Zeilen
hat. Die Zustandswoerter kommen vom SERVER, nicht aus einer zweiten
Liste im Browser -- sonst heisst derselbe Zustand an zwei Stellen
anders.

ZWEI DINGE, DIE ERST DAS MESSEN GEZEIGT HAT:

(1) `window.nachfragen` gibt es nicht -- der Dialog heisst `frageNach`
    und kennt `grund`/`grundPflicht`, aber keine Auswahl. Ich hatte
    eine Schnittstelle benutzt, die ich mir gemerkt statt nachgesehen
    hatte. Aus der Not wurde die bessere Loesung: drei Knoepfe.
(2) Auf dieser Seite gibt es KEIN Suchfeld -- `#wer` in der
    Kopfleiste ist die Anzeige, wer angemeldet ist. Der Personenfilter
    wirkt deshalb unmittelbar am Brett.

pruef-zuteilung: 66/0 (war 48/0) -- 18 davon am echten Bildschirm.

Der Browserteil scheiterte zuerst mit `chrome-error://chromewebdata/`:
crew.dogfather-universe.com steht in Chromiums eingebauter HSTS-Liste,
der Browser schaltet von sich aus auf https, und der Testserver
spricht http. Abschalten geht nicht (die Liste ist einkompiliert).
Jetzt derselbe https-Vorbau wie in pruef-handy-teamdogi -- eine
Nachbildung waere die zweite Fassung, die anders altert.

Nachbarn gruen: pruef-aufgabenbrett 49/0, pruef-verteilen 16/0,
pruef-css-klassen 30/0, pruef-tippziele 11/0.
2026-09-21 18:01:30 +02:00
DogFatherGit ef0fddc724 Aufgaben an Menschen: zuteilen, annehmen, ablehnen, bewerten
Auftrag vom 21.09.2026, Abschnitte 2 bis 5 -- der Serverteil.

DREI ARTEN ZU VERTEILEN, und der Unterschied zwischen den letzten
beiden ist der ganze Punkt:

  einzeln   eine Person, sie macht es
  mehrere   mehrere Personen, JEDE macht ihren Teil
  pool      mehrere sehen es, EINE nimmt es -- danach ist es fuer die
            anderen weg, damit niemand doppelt arbeitet

EINE EIGENE TABELLE, KEINE SPALTEN AN DER AUFGABE. Abschnitt 4
verlangt ausdruecklich: *"Die Aufgabe muss in der Auswertung auf die
einzelnen zugewiesenen Personen aufgeteilt werden"* -- und gleichzeitig
soll "die urspruengliche gemeinsame Aufgabe ihre uebergeordnete
Struktur" behalten. Eine Aufgabe hat EINEN Titel und EINE Frist, aber
je Mensch einen eigenen Stand, einen eigenen Grund beim Ablehnen, ein
eigenes Erledigt-Datum und eine eigene Rueckmeldung. Das in Spalten zu
pressen hiesse, dieselbe Aufgabe mehrfach anzulegen.

`aufgaben.status` bleibt daneben unberuehrt. Zwei Ebenen, weil es zwei
Fragen sind: "Wie steht die Aufgabe?" und "Wie steht sie bei IHM?" Ein
einziges Feld koennte bei drei Leuten nicht gleichzeitig "angenommen"
und "abgelehnt" sein.

DER WICHTIGSTE EINZELNE HANDGRIFF -- und er steht nicht im Auftrag:
Wer eine Aufgabe BEKOMMEN hat, sieht sie jetzt immer. Bei "mehrere"
und "pool" bleibt `verantwortlich_id` leer, und die alten Sichtregeln
fragen genau danach. Ohne die Erweiterung stuende eine Aufgabe im
Resuemee der Leitung und waere fuer den, der sie machen soll,
unsichtbar -- der unangenehmste denkbare Fehler in einem
Aufgabensystem, und man sieht ihn nirgends. Die Erweiterung ist ein
ODER, kein UND: Sie erweitert die Sicht, die Haustrennung darueber
bleibt ein UND und wirkt weiter.

WAS SONST NOCH ENTSCHIEDEN WURDE, mit Grund im Code:

  - Ablehnen braucht eine Begruendung (mind. 3 Zeichen). Ein leeres
    Nein ist fuer den, der verteilt hat, keine Information -- er muss
    dann nachfragen, und genau das sollte die Nachricht ersparen.
  - "Verbesserungsmoeglichkeiten" braucht einen Text. Ein leeres
    "kann besser" sagt nichts ausser, dass jemand unzufrieden war.
  - Bewertet wird erst, wenn jemand FERTIG ist. Eine Rueckmeldung auf
    etwas, das noch laeuft, ist keine Bewertung, sondern eine
    Einmischung.
  - Beim Pool wird VOR dem Schreiben gefragt, ob schon jemand zugesagt
    hat -- sonst nehmen zwei im selben Moment dieselbe Aufgabe und
    beide sehen "hat geklappt".
  - Wer schon geantwortet hat, behaelt seinen Stand, wenn die Aufgabe
    noch einmal gespeichert wird. Sonst muesste er ohne Grund erneut
    zusagen.
  - Wer nicht mehr dabei ist, faellt raus -- aber nur, solange er noch
    nicht geantwortet hat. Jemandem eine angenommene Aufgabe
    wegzunehmen, ohne dass er es erfaehrt, waere die unangenehmste Art,
    Arbeit zu verlieren.
  - "pool" mit einer Person wird "einzeln". Ein Pool aus einem
    Menschen ist keiner.

`verantwortlich_id` bleibt und wird mitgefuehrt (einzeln = die Person,
pool = der Uebernehmer, mehrere = leer): Brett, Startseite und
Uebersicht gruppieren danach. Drei gewachsene Ansichten gleichzeitig
umzubauen waere der groessere Eingriff -- und im haeufigsten Fall
sagen beide dasselbe.

KEIN CHECK an der nachgetragenen Spalte `verteilart`, mit Absicht: Ein
CHECK auf einer nachgetragenen Spalte hiesse, die Tabelle neu zu bauen
-- der Weg, der in diesem Haus am 11.09. und heute schon Spalten
gekostet hat. Geprueft wird beim Schreiben.

pruef-zuteilung.mjs, 48 Aussagen -- ein Arbeitstag durchgespielt.

Ein Fehlschlag beim ersten Lauf, und er war lehrreich: "Cem hat keinen
eigenen Stand" schlug fehl, weil Cem die Aufgabe gar nicht SIEHT
(`null?.x` ist `undefined`, nicht `null`). Die Zusicherung konnte
"sieht sie nicht" und "sieht sie ohne Stand" nicht unterscheiden --
also pruefte sie beides nicht richtig. Dass er sie nicht sieht, ist
genau Abschnitt 1: *"Eine Modi darf nicht automatisch die
vollstaendige Aufgabenuebersicht aller anderen Modis sehen."* Beide
Faelle stehen jetzt einzeln da, mit einer Gegenprobe, dass seine Liste
ueberhaupt laedt.

Nachbarn gruen: pruef-verteilen 16/0, pruef-aufgabenbrett 49/0,
pruef-umstellung 18/0.
2026-09-21 17:52:52 +02:00
DogFatherGit 21793b6c36 Neue Rolle: die linke Hand
Aus dem Auftrag vom 21.09.2026, Abschnitt 6: "Die linke Hand erhaelt
grundsaetzlich dieselben Rechte wie die rechte Hand in allen Bereichen,
die die Modis, Aufgaben, Aufgabenzuweisungen, Uebersichten,
Kommunikation und Auswertungen betreffen. Die linke Hand darf keine
neuen Personen oder Accounts hinzufuegen. Die linke Hand darf keine
privaten bzw. persoenlichen Bereiche oder Informationen von Dogfather
sehen."

GEMESSEN VOR DEM BAUEN: Die Rolle "hand" steht an 35 Stellen im
Servercode und 17-mal in der Rechtetafel. Haette ich ueberall ein
"linke" danebengeschrieben, waere die naechste Stelle, die jemand
hinzufuegt, die erste, die es vergisst -- und eine vergessene Stelle
heisst hier: Die linke Hand sieht etwas nicht, ohne dass jemand merkt,
warum.

DESHALB EINE REGEL STATT DREISSIG ABSCHRIFTEN:

  WIE_RECHTE_HAND = new Set(["hand", "linke"])   in workspace.js
  istHand(person)                                fuer die Faehigkeiten
  eine Schleife ueber SEITEN                     fuer die Rechtetafel

Die Schleife gibt der linken Hand jede Seite der rechten -- ausser
fuenf, und jede davon steht mit Grund da:

  personen.html      legt Personen an
  bewerbungen.html   fuehrt zu neuen Personen
  talente.html       fuehrt zu neuen Personen
  hilfe.html         vertraulicher Meldeweg
  rechte.html        Rechteverwaltung

Gemessen: 25 Seiten fuer die rechte Hand, 20 fuer die linke. Als
Kacheln: 30 gegen 26 -- die vier verbotenen erscheinen gar nicht erst,
statt beim Antippen abgelehnt zu werden.

ZWEI DINGE, DIE ERST DAS MESSEN GEZEIGT HAT:

(1) OHNE KACHEL AUF DER ANMELDEWAND GIBT ES DIE ROLLE NICHT. Die
    Anmeldung sucht `WHERE rolle = ?` auf die angetippte Kachel -- es
    gibt keinen rollenuebergreifenden Sonderweg, auch nicht auf der
    Crew-Wand. Eine linke Hand haette sich mit dem richtigen Code
    NIEMALS anmelden koennen, und der Fehler haette ausgesehen wie ein
    falscher Code.

(2) DIE REIHENFOLGE DER DATENBANK-UMSTELLUNG ZAEHLT.
    `checkListeErweitern` baut die CHECK-Regel NEU aus der Liste, die
    man ihm gibt. Mein Schritt stand zuerst bei der rechten Hand --
    der Schritt fuer "gast" darunter nahm die Rolle damit wieder
    heraus, denn seine Liste kennt sie nicht. Die Kette ist kumulativ;
    neue Schritte gehoeren ans ENDE. Das steht jetzt auch dort.

Dazu zwei kleinere Funde beim Bauen:

  - Meine erste Ableitung aenderte die Rollenliste AN ORT UND STELLE.
    Mehrere Seiten teilen sich dieselbe Liste (`ALLE`) -- das haette
    die Rolle allen Seiten gegeben, die sie benutzen, auch einer
    Ausnahme. Faellt nicht auf, solange keine Ausnahme `ALLE` benutzt.
    Jetzt eine Kopie je Seite.
  - ROLLEN_NAME fehlte der Eintrag: Die linke Hand haette ueberall
    "linke" geheissen statt "Linke Hand". Gefunden hat das
    pruef-rechtetafel, weil sie diese Tabelle gegen ROLLEN haelt.
    Ihre Meldung nennt jetzt, WELCHE Liste was vermisst -- vorher
    zeigte sie beim Fehlschlag nur eine der beiden.

NICHT BEKOMMEN -- und jedes einzeln begruendet im Code:
Personen anlegen (ANLEGBAR.linke = []), Rollen aendern
(darfRollenWechseln), Bewerbungen, der vertrauliche Meldeweg. Beim
Meldeweg ist es bewusst das kleinere Recht: Ein Wort von Filipe
oeffnet ihn, eine versehentlich gelesene Meldung laesst sich nicht
zurueckholen.

UNBERUEHRT GEBLIEBEN, obwohl dort "hand" steht:
workspace-leistung.js:406 -- dort heisst "hand" nicht die Rolle,
sondern "von Hand eingetragen".

Am laufenden System gemessen: Datenbank nimmt die Rolle, Anmeldung
HTTP 200, 26 Kacheln, darf_verteilen = true, personen/hilfe/rechte
antworten mit 302, aufgaben und teamlage mit 200.

pruef-rechtetafel 19/0 (war 18/1), pruef-schranke 39/0,
pruef-umstellung 18/0.
2026-09-21 17:44:48 +02:00
DogFatherGit 432e533c86 Am Handy wird aus einer Kalenderpille ein Punkt
GEMESSEN, was dort wirklich stand:

    Fenster   Zelle   Pille   Platz fuer Text
     360 px   42 px   32 px   16 px  ->  1-2 Buchstaben
     390 px   46 px   36 px   20 px  ->  2-3 Buchstaben
     412 px   49 px   39 px   23 px  ->  3 Buchstaben
     768 px   95 px   85 px   69 px  ->  lesbar

"Content-Ideen sammeln" wurde zu "C…" -- eine Zeile, die Hoehe kostet
und nichts sagt. Drei Termine an einem Tag waren drei solche Zeilen.

JETZT: ein Punkt je Termin, nebeneinander. Man sieht, DASS an dem Tag
etwas ist und wie viel, und tippt den Tag an, um zu lesen, was. Der
Tagesdialog dafuer steht seit jeher, ist lesbar und hat 44-px-Zeilen;
er war nur schwer zu finden, solange das Raster so tat, als koenne man
dort lesen.

  - Zeitraum: bleibt ein durchgehender Balken. Ihn auch zu Punkten zu
    machen naehme genau das weg, wofuer er am 21.09. gebaut wurde.
  - Anlass (Feiertag u. a.): ein ECKIGES Zeichen, damit man es vom
    runden Termin unterscheidet. "DE…" fuer "Tag der Deutschen
    Einheit" sagt genauso wenig.
  - Erledigtes: hohl statt voll -- sonst saehe ein abgehakter Termin
    aus wie ein offener, und der Kalender loege.
  - Die Punkte sind NICHT einzeln antippbar (pointer-events: none).
    Ein 8-px-Link waere ein Nadeloehr; so faellt jeder Tipp auf die
    Zelle. Am Rechner bleibt die Pille ein Link.

DREI DINGE, DIE ERST DAS BILDSCHIRMFOTO GEZEIGT HAT:

(1) Die Zahlen sagten 8 x 8 -- und der Titel lief trotzdem quer ueber
    die Nachbarzellen. Ursache: start.css traegt eine Sammelregel
    `body.start .k-pille { font-size: .75rem }`, um ein Element
    spezifischer als `.k-tag .k-pille` (0,2,1 gegen 0,2,0). Sie
    gewinnt, egal welche Datei spaeter laedt. Aufgeklaert hat es die
    Frage an den Browser, WELCHE Regeln auf das Element passen.

(2) `.k-tag` traegt `container-type: inline-size` und ist damit der
    Behaelter fuer ihre KINDER. Eine Regel fuer `.k-tag` SELBST in
    `@container` wird gegen den naechsten Behaelter darueber geprueft
    und greift nie. Die Zelle blieb eine Flex-Spalte, jeder Punkt bekam
    eine eigene Zeile. Jetzt fragt die Zelle das Raster -- ein
    benannter Behaelter, Schwelle gerechnet: 46 + 8 + 7 x 60 = 474.

(3) Die Kinder der Pille (Uhrzeit, Wiederholzeichen) haben eine eigene
    Schriftgroesse und hielten den Punkt auf 26 px Hoehe. Ein 8 x 26
    grosser "Punkt" ist ein Strich.

pruef-kalender: 141/0 -- vorher 135 ok und 6 FEHL.

Die sechs waren KEIN Fehler am Kalender, und nur einer davon war neu:

  - Vier kamen von Screen 11 (Termin von-bis): Ein Eintrag ueber fuenf
    Tage setzt fuenf Marken, und die Pruefung zaehlte Marken statt
    Eintraege. Sie hatte am 17.09. schon gelernt, ihre Erwartung
    abzuleiten -- veraltet war diesmal nicht die Erwartung, sondern
    das, was gemessen wurde. Gezaehlt wird jetzt ueber den VERWEIS
    (`zeigen=eintrag-N`), der an jedem Tag derselbe ist. Der `title`
    ginge nicht: Er endet mit "(Tag 3 von 5)".
  - Zwei waren meine: Die Pruefung las die Farbe aus der linken Kante
    -- die faellt beim Punkt weg, also meldete sie "1 Farbe" statt 5.
    Gelesen wird jetzt `--pfarbe`, die Quelle selbst.

Neun neue Zusicherungen, darunter die, die beim Bauen gefehlt hat:
"nichts ragt ueber den Rand seiner Zelle hinaus". Groesse allein
genuegt nicht -- die Pille war bereits 8 x 8 und trug trotzdem Text.
Gegenprobe: Raster auf 1200 px aufziehen, Titel muss zurueckkommen.

Nachbarn gruen: pruef-tippziele 11/0 (sieht die 11 neuen Regeln, zaehlt
den Punkt richtig nicht als Tippziel), pruef-css-klassen 30/0,
pruef-zeitraum 16/0, pruef-terminregel 35/0.
2026-09-21 17:01:54 +02:00
DogFatherGit bfbe6feafe Fett, kursiv, unterstrichen, durchgestrichen -- ueberall
Filipe, 21.09.2026: "dan will ich dass die leute auch immer die art
von text aussuchen können, fettgedrückt, unterstrichen und so alles.
das überall sei es im chat jeder für sich oder sei es wenn die modis
oder rechte hand oder dogfather eine aufgabe oder sachen posten."

VORHER GEMESSEN: Es gab genau EINE Auszeichnung im ganzen Haus --
fett, und nur auf den Brettern (`mitFett` in bereich.js). Im Chat
konnte niemand etwas hervorheben.

EINE QUELLE FUER DAS GANZE HAUS: workspace/assets/js/textform.js.
Chat, Bretter und Aufgaben zeichnen ihren Text jetzt durch denselben
Zerleger. Drei Fassungen derselben Regel waeren drei Fassungen, die
verschieden altern.

  **fett**   _kursiv_   __unterstrichen__   ~~durchgestrichen~~

Dazu eine Leiste ueber jedem Schreibfeld: F K U S, 44 px am Finger,
Strg+B/I/U, und ein zweiter Druck nimmt die Zeichen wieder weg.

DIE WORTGRENZEN SIND DER EIGENTLICHE BAU. Ein Zerleger, der alles
auszeichnet, ist schlimmer als keiner: `datei_name_hier` hiesse
plotzlich anders, als es heisst, und `@max_muster` ebenso. Deshalb
stehen bei den Unterstrichen Wortgrenzen -- bei Sternchen und Tilden
nicht, die kommen in Text nicht versehentlich paarweise vor.

GEBAUT MIT createTextNode, NIE innerHTML. Wer Text zu Auszeichnung
macht, ist einen Tippfehler von einer Luecke entfernt. Das ist heute
sicher; pruef-textform misst es, damit es das morgen auch ist.

EIN ECHTER FEHLER DABEI GEFUNDEN -- in meinem eigenen Einbau von
vorhin: Auf dem Aufgabenbrett stand `$('f-text')` in einem Block, der
`$` gar nicht kennt (die Datei hat drei getrennte Bloecke).
`ReferenceError: $ is not defined`, die Leiste kam dort nie an, und
die Seite sah dabei vollkommen normal aus. Derselbe Block beginnt
ausserdem mit `if (!feld) return;` auf ein Aufwand-Feld, das mit
Textgestaltung nichts zu tun hat -- die Leiste haette an einer
voellig fremden Bedingung gehangen. Jetzt ein eigener Block, ohne
fremden Helfer und ohne fremde Bedingung.

Gefunden hat es die Pruefung, weil sie die Leiste AM FELD sucht,
statt den Aufruf im Quelltext zu zaehlen. Sie sammelt seitdem auch
Skriptfehler ein -- ein ReferenceError ist immer ein Befund, auch
wenn man noch nicht weiss, was er anrichtet.

pruef-textform.mjs, 50 Aussagen:
  - welche Seite das Modul braucht, wird ABGELEITET (beide
    Richtungen: keine ohne, keine umsonst) -- 3 brauchen, 32 nicht
  - 13 Regelfaelle im echten Browser an der echten Datei, davon
    sechs, die NICHT gestaltet werden duerfen
  - eine echte Nachricht wird zu <strong>/<em>/<u>/<s>
  - Sicherheitsprobe: <b> und <img onerror> bleiben Text, nichts
    wird ausgefuehrt -- und die echte Auszeichnung daneben wirkt
    trotzdem (sonst waere nur bewiesen, dass gar nichts passiert)
  - die Leiste legt Zeichen wirklich um und wieder ab
  - Gegenproben fuer beide Richtungen

Nachbarn unveraendert gruen: pruef-chat-optik 45/0 (war 39 -- die
Antwortleiste kam dazu), pruef-aufgabenbrett 49/0, pruef-nachfrage
49/0, pruef-css-klassen 30/0, pruef-tippziele 11/0, pruef-meldungen
8/0.
2026-09-21 16:42:43 +02:00
DogFatherGitandClaude Opus 5 7305f694d5 Die Stelle bleibt -- auch wenn man ueber die Kopfzeile zurueckgeht
Filipe, zum vierten Mal: "muss ich jedes mal wenn ich von einer seite
zurück scrolle immer wieder runter scrollen um weiter zu schauen und
das nervt."

DIE WIEDERHERSTELLUNG GAB ES SEIT DEM 20.09. -- sorgfaeltig gebaut,
mit Warten auf die nachgeladene Hoehe, mit Aufgeben nach drei
Sekunden, mit "wer selbst scrollt, gewinnt".

SIE LIEF NUR FAST NIE. Denn sie lief ausschliesslich bei
`navigation.type === "back_forward"`, also beim Zurueck-Knopf des
Browsers. Im Haus geht man anders zurueck: ueber die Kopfzeile ("TEAM
DOGI › HIGHLIGHTS"), und dort steht ein ganz gewoehnliches
`<a href="start.html">`. Fuer den Browser ist das eine Fahrt
VORWAERTS. Die Bedingung war also falsch -- und der else-Zweig
loeschte die eben gemerkte Stelle noch dazu.

IM KOPF DERSELBEN DATEI STAND DIE LOESUNG ALS ABSICHT: "Ein eigener
Merker faengt den Fall ab, dass der Zurueck-Knopf der Kopfleiste
benutzt wurde." Gebaut wurde er nie.

UND DESHALB HAT ES IN JEDEM TEST FUNKTIONIERT: Wer mit `goBack()`
prueft, prueft den einen Weg, den niemand geht. Gemessen am 21.09.:
ueber goBack sauber wiederhergestellt, ueber den Link in der
Kopfzeile oben gelandet. Gefunden hat es Filipes Bildschirmvideo --
17 Sekunden, drei Bilder, und der Ablauf war eindeutig.

Der Merker gibt es jetzt wirklich: Beim Klick auf einen EIGENEN
Zurueck-Weg (`.zurueck`, `.zurueck-knopf`) wird das Ziel notiert; wer
dort binnen 30 Sekunden ankommt, bekommt seine Stelle zurueck. Er
gilt fuer genau eine Ankunft -- wer die Seite eine Minute spaeter
normal oeffnet, faengt wieder oben an. Und NUR fuer diese zwei
Klassen, nicht fuer jeden Link: Sonst landete man beim Oeffnen eines
Brettes mitten darin.

Dazu der Rueckwaerts-Speicher des Browsers: Holt er eine Seite aus dem
Speicher, laeuft keine Zeile mehr, und unser `manual` verbietet ihm
gleichzeitig, die Stelle selbst wiederherzustellen. Ein `pageshow`
faengt das ab. Dieser Fall ist NICHT gemessen -- in Playwright greift
der Speicher nicht -- sondern aus der Spezifikation begruendet. Das
steht auch so im Kommentar, damit niemand spaeter glaubt, er sei
nachgewiesen.

NEU: pruef-stelle.mjs, 9 Pruefungen. Sie geht beide Wege zurueck --
Kopfzeile UND Browser -- und haelt ausdruecklich fest, dass der erste
KEIN "back_forward" ist. Dazu die Gegenprobe, dass eine frisch
geoeffnete Seite oben anfaengt: Ohne sie waere alles auch dann gruen,
wenn die Seite IMMER zur alten Stelle springt, und das waere
schlimmer als das Problem.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 14:24:19 +02:00
DogFatherGitandClaude Opus 5 9a30f9e304 Beim Antworten war das Schreibfeld einen Buchstaben breit
Filipes Bildschirmfoto: Die Antwortleiste nimmt die ganze Breite, und
daneben steht ein Schreibfeld, in dem der Text senkrecht laeuft --
"defi / niti / v / hah / a".

DIE ABSICHT STAND DA, DIE REGEL NICHT. `.chat__eingabe` ist eine Reihe
OHNE Umbruch, und die Antwortleiste ist darin ein gleichberechtigtes
Element -- sie nimmt ihren Platz NEBEN dem Schreibfeld. Das
`margin-bottom: 8px` an der Leiste sagt seit jeher, dass sie darueber
gehoert; durchgesetzt wurde es nie.

Dazu stand am Schreibfeld `min-width: 0`. Das ist woertlich die
Erlaubnis, auf nichts zu schrumpfen -- und genau das hat es getan.

BEHOBEN MIT EINER REGEL, NICHT MIT EINER ZAHL: Die Zeile darf jetzt
umbrechen, die Antwortleiste nimmt sich mit `flex-basis: 100%` immer
die ganze Zeile, und das Schreibfeld hat eine Untergrenze von 8rem.
Bricht es darunter, bricht lieber die Zeile um, als dass das Feld
unbenutzbar wird.

Gemessen an der schmalsten Breite, die das Haus kennt:
  320 px: Schreibfeld 166 px, Antwortleiste 670 px (eigene Zeile)
  430 px: Schreibfeld 216 px
Vorher: rund 30 px.

pruef-chat-optik prueft das jetzt mit -- und nicht nur die Breite des
Feldes, sondern auch, dass die Leiste wirklich eine eigene Zeile
nimmt. Ohne die zweite Zeile waere die erste nur zufaellig gruen,
solange der zitierte Text kurz genug ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 14:11:04 +02:00
DogFatherGitandClaude Opus 5 314561fb64 Aufgaben an bestimmte Leute verteilen -- jetzt auch sichtbar
Filipe: "ich sehe noch immer nicht dass dogfather oder die rechte hand
wenn sie aufgaben verteilen die spezifisch an leute verteilen können.
mach das endlich auch weil das ist seeehr wichtig damit wir arbeiten
können mit den leuten."

GEMESSEN, BEVOR GEBAUT WURDE -- und die Messung hat zwei verschiedene
Antworten gegeben:

  DogFather   Feld sichtbar, vier Menschen in der Auswahl
  Rechte Hand Feld VERSTECKT, Auswahl leer

Fuer ihn gab es die Zuteilung also, fuer sie nicht. Beides war falsch,
jedes auf seine Art.

1. DIE RECHTE HAND KAM NIE AN DIE FELDER

   Das Absenden fragte `ich.darf_verteilen` -- das sagt der Server:
   Leitung ODER rechte Hand (seit 20.09.). Das ANZEIGEN fragte eine
   andere Menge aus bereiche.js: spicy, admin, manager. Zwei
   Bedingungen fuer dieselbe Sache, und eine davon war nie nachgezogen
   worden.

   Der Server haette ihre Zuteilung angenommen; sie konnte sie nur
   nirgends eintragen. Vier Stellen betroffen, und eine davon war
   gefaehrlich: Beim BEARBEITEN wurde `verantwortlich_id` nicht
   mitgeschickt -- die rechte Hand haette durch blosses Speichern die
   Zuteilung einer Aufgabe stillschweigend geloescht. Kein Fehler,
   keine Meldung, die Aufgabe gehoert danach niemandem.

   Alle vier fragen jetzt den Server. `LEITUNG.has(ich.rolle)` bleibt
   nur noch als Rueckfall hinter `??`, fuer den Fall einer aelteren
   Serverfassung.

2. UND FUER DOGFATHER LAG ES AM WORT

   Das Feld hiess "Verantwortlich" und stand auf "—". Das liest sich
   wie eine Eigenschaft der Aufgabe, nicht wie eine Frage an einen
   selbst. Es heisst jetzt "Wer macht es?", der leere Wert "— noch
   niemand —", und darunter steht, was die Auswahl bewirkt: Die
   Aufgabe steht bei ihm unter "Nur meine", und er bekommt eine
   Meldung.

   Eine Frage beantwortet man. Ein Strich uebersieht man.

WARUM KEINE PRUEFUNG DAS GEFUNDEN HAT: Alle fragten den Server, und
der war in Ordnung -- Rechte da, Leute da, Zuteilung wird angenommen.
Eine Erlaubnis, an die niemand herankommt, sieht von dort aus wie eine
Erlaubnis. pruef-verteilen liest deshalb jetzt auch den Quelltext der
Oberflaeche: dieselbe Frage an beiden Stellen, und die Beschriftung
muss eine Frage sein. Kommentare zaehlen dabei nicht mit -- beim
ersten Lauf hat die Pruefung meine eigene Begruendung als Befund
gezaehlt.

pruef-verteilen 16/0 · pruef-aufgabenbrett in Ordnung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 14:07:25 +02:00
DogFatherGitandClaude Opus 5 8a214ecd0e Keine Mischung mehr -- Team Dogi nur noch bei Team Dogi
Filipe: "ich will dass du im workspace alles von team dogi weg nimmst.
nur was ich im kalender eintrage soll ich im workspace sehen und im
team dogi. aber die kacheln von team dogi soll ich nur bei team dogi
sehen und die von workspace nur bei workspace bitte. ich will keine
mischung mehr von kacheln. wie gesagt nur die der kalender soll
verbunden sein von dogfather sonst nichts."

GEMESSEN, WIE SCHLIMM ES WAR: Auf der Agenturadresse bekam DogFather
0 eigene Kacheln ueber die Schnittstelle und 17 fremde -- Dein Team,
Ideen-Board, Rueckmeldung, Wer sieht was, Entwicklung, Werdegang,
Talente und den ganzen Treff samt Moderation. Zwei Betriebe auf einer
Seite.

Das Bittere daran: Dieselbe Datei hatte den Fehler fuer die ANDERE
Richtung am 10.09. schon erkannt und behoben ("Fuenfundzwanzig
Kacheln, von denen zwei Drittel Creator, Scouts und Agentur betreffen,
waeren dort Fenster in ein Haus, in dem er gerade nicht ist"). Nur
andersherum stand es weiter so.

DIE AUSNAHME BRAUCHTE NICHTS: Nachgemessen filtern die Terminabfragen
in workspace-kalender.js NICHT nach Haus. Was er eintraegt, steht
ohnehin auf beiden Adressen. Die Verbindung, die er will, existierte
schon -- sie musste nur nicht zerschnitten werden.

STATT SIEBZEHN BRETTERN STEHT DORT EINE TUER. Ohne sie waere von der
Agenturadresse aus kein Weg mehr zu Team Dogi sichtbar; er muesste die
Adresse tippen. Das ist die Sorte Sackgasse, die dieses Haus nicht
baut. Eine Tuer ist keine Mischung: Sie zeigt kein Brett, sie geht
hinueber. Und sie kommt vom Server, nur fuer `admin` -- in keiner
ausgelieferten Datei steht sie.

MEIN ERSTER ENTWURF GAB SIE AUCH DER RECHTEN HAND UND DER MODERATION.
pruef-modi-checkliste hat es sofort gemeldet: "Modi bekommt 1
Zusatzkachel(n), erwartet keine". Wer NUR zu Team Dogi gehoert, hat
auf der Agenturadresse nichts zu suchen -- die Tuer waere dort seine
einzige Kachel gewesen, also eine Seite, die aus nichts als einem
Ausgang besteht.

VIER PRUEFUNGEN VERLANGTEN DANACH DIE ALTE WELT. Keine davon war ein
Mangel; alle vier haben am falschen Ort gesucht:

  pruef-haus-trennung  verlangte woertlich, dass die Team-Kachel AUCH
     auf der Agenturadresse steht. Sie prueft jetzt die Trennung in
     beide Richtungen -- kein Brett von Team Dogi drueben, aber die
     eine Tuer -- und leitet die Namen aus der Antwort von crew. ab,
     statt sie abzuschreiben.
  pruef-start-ansicht  zaehlte acht Gruppennamen in fester
     Reihenfolge. Gemeint war eine Ordnung ("die Community steht ganz
     unten, denn dort stehen Namen und Saetze von Zuschauern"), und
     die wird jetzt als Regel geprueft -- bedingt, mit drittem Ausgang
     auf Adressen, wo es diese Gruppen gar nicht gibt.
  pruef-treff und pruef-rueckmeldung fragten ueber die Agenturadresse
     nach Brettern, die dort nicht mehr stehen. Sie fragen jetzt dort,
     wo diese Bretter zuhause sind.

EINE HALBE STUNDE WAERE DABEI FAST VERLOREN GEGANGEN: `fetch` kann den
Host-Kopf nicht setzen -- er ist ein verbotener Kopfzeilenname und
wird STILLSCHWEIGEND verworfen. Die Anmeldung ueber die Crew-Wand
genuegt nicht; jede einzelne Abfrage braucht die Adresse. Deshalb geht
die Messung jetzt ueber http.request, so wie es `anmelden()` in
derselben Datei laengst tut.

pruef-haus-trennung 74/0 · pruef-modi-checkliste 75/0 · pruef-treff
72/0 · pruef-rueckmeldung 30/0 · pruef-start-ansicht 153/0 ·
pruef-haus-seiten 34/0 · pruef-entwicklung 46/0 · pruef-befinden
113/0 · pruef-rechte-umstellen 46/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 14:00:14 +02:00
DogFatherGitandClaude Opus 5 a39d02da5a Ein Vorschlag ist ein Vorschlag -- DogFather entscheidet
Filipe: "bei diesen vorschlägen ist sehr wichtig dass immer wenn es um
was geht was ich machen soll oder so dass immer erwähnt wird dass ich
immer am ende entscheide ob ich was mache oder nicht. ich kann immer
annehmen oder ablehnen. über all auf der website soll dass bei den
vorschlägen erwähnt werden."

WARUM DAS MEHR IST ALS HOEFLICHKEIT: Auf den Karten stehen Saetze wie
"Was soll DogFather im naechsten Stream unbedingt machen?" oder
"Welches Spiel soll DogFather mal ausprobieren?". Wer so gefragt wird,
schreibt etwas hin -- und rechnet damit. Passiert es dann nicht, sieht
es aus wie ein gebrochenes Versprechen, obwohl nie eines gegeben
wurde. Der Satz verhindert genau diese Enttaeuschung vorher, statt sie
hinterher zu erklaeren.

GEMESSEN, BEVOR GEBAUT WURDE -- und die Messung hat den Auftrag
groesser gemacht: Die Vorschlagskarten sieht NUR das Team. Die
Community bekommt sie mit 404 gar nicht; sie liest nur, was daraus auf
dem Brett landet. Ein Satz allein ueber den Karten haette also genau
die Leute nicht erreicht, um die es geht.

Deshalb steht er jetzt an ZWEI Stellen, aus EINER Quelle:
  - ueber den Vorschlagskarten (das Team beim Auswaehlen)
  - auf dem Brett selbst, unter der Ueberschrift (die Community beim
    Lesen)

WELCHE BRETTER IHN TRAGEN, WIRD ABGELEITET: genau die, fuer die es
ueberhaupt Vorschlaege gibt. Eine zweite Liste "Bretter mit Hinweis"
waere die naechste, die altert -- wer ein Brett in den Katalog
aufnimmt, denkt nicht daran, es auch dort einzutragen. Auf einem Brett
fuer Termine oder Dateien steht er nicht: Ein Hinweis, der ueberall
steht, wird nirgends gelesen.

EINMAL UND NICHT AUF JEDER KARTE. Vier Karten nebeneinander mit
viermal demselben Satz liest niemand mehr. Er steht ueber dem Block,
wo man ihn liest, bevor man die erste antippt.

Der Text selbst steht an genau einer Stelle im Haus
(VORSCHLAG_HINWEIS), und pruef-vorschlaege haelt beide Anzeigeorte
dagegen -- mit Gegenprobe, dass ein Brett ohne Vorschlaege ihn NICHT
traegt.

pruef-vorschlaege: 28 Pruefungen, 0 Fehler (war 21)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:41:06 +02:00
DogFatherGitandClaude Opus 5 2c2c42d4aa Drei rote Zeilen im Werdegang -- alle drei verlangten Altes
Keine davon war ein Mangel an der Seite. Alle drei verlangten einen
Zustand, den Filipe am 19.09.2026 ausdruecklich geaendert hat.

1. "alphabetisch (Rieke, Diene)"

   Filipe am 19.09.: "die reihenfolge der listen soll immer angepasst
   sein hatten wir doch schon. die rechte hand rolle immer zuerst und
   dan die modis." Der Server sortiert seitdem nach ROLLEN_SORTIERUNG,
   dann nach Namen -- die Pruefung verlangte weiter rein alphabetisch.

   Sie prueft jetzt dieselbe Ordnung, abgeleitet aus derselben
   Konstante wie der Server. Wer dort eine Rolle verschiebt,
   verschiebt sie hier mit. Was bleibt, ist die eigentliche Aussage:
   sortiert wird nach etwas, das nichts ueber die Person sagt -- eine
   Liste nach Aktivitaet waere eine Rangliste mit anderem Namen, eine
   nach Rolle ist es nicht.

2. "jede Zelle traegt ihr Zeichen, nicht nur ihre Farbe"

   Im Quelltext der Seite steht seit dem 19.09. woertlich: "Leer ist
   jetzt WIRKLICH leer -- kein Zeichen, dafuer ein gestrichelter
   Rahmen. Man sieht das Fehlen, statt es zu lesen." Die Pruefung
   verlangte das Gegenteil.

   Gemessen werden jetzt beide Haelften, und die zweite ist die
   wichtigere: Stuende in einer leeren Zelle doch ein Zeichen, waere
   "noch nichts gesetzt" nicht mehr von "gesetzt" zu unterscheiden --
   und das faellt beim Hinsehen nicht auf, weil es nach Inhalt
   aussieht.

3. "unter dem Diagramm steht eine Legende (7 Eintraege)"

   Hier stand `=== 2`. Inzwischen sind es sieben: zwei fuer die
   Bewegungsrichtung, vier Stufen und der leere Zustand. Wieder eine
   Rechnung von gestern.

   Gefragt wird jetzt, was die Legende leisten muss: zu JEDER Stufe,
   die der Server kennt, ein Eintrag -- und einer fuer den leeren
   Zustand. Kommt eine Stufe dazu, waechst die Erwartung mit.

ZWEIMAL HAT MICH DABEI DIE ZAHL IN DER BEDINGUNG GERETTET. Erst
fragte ich die Stufen an der Liste ab -- die liefert sie gar nicht,
sie stehen an der einzelnen Karte. Ohne `stufenSoll.length > 0` waere
der Vergleich gegen eine leere Liste gelaufen und haette "die Legende
nennt jede davon" bestaetigt, ohne eine einzige zu kennen. Dieselbe
Zeile hatte zuvor schon in pruef-modi-checkliste einen stillen
Totalausfall verhindert.

pruef-werdegang: 103 Pruefungen, 0 Fehler (war 95, davon 3 rot)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:15:35 +02:00
DogFatherGitandClaude Opus 5 9d4a40ff58 Zwei Pruefungen waren rot, weil etwas richtig gemacht wurde
pruef-auskunft und pruef-treff-werkzeuge -- beide bestraften eine
Verbesserung. Das ist die unangenehmste Sorte roter Pruefung: Wer sie
zweimal so erlebt, faengt an, rote Laeufe zu erklaeren statt sie zu
lesen.

1. "DIE COMMUNITY HAT KEINEN STECKBRIEF"

   So stand es woertlich in der Bedingung. Am 19.09. hat Filipe genau
   das Gegenteil entschieden -- "jeder soll ein steckbrief haben, jeder
   der ein account hat ... jeder soll genau wie ich foto und so
   hinzufuegen koennen" -- und die Community hat seitdem einen.

   Was die Zeile schuetzen wollte, steht in ihrem eigenen Kommentar:
   "Ohne die zweite Stelle haette die Gruppe mit den wenigsten Rechten
   auch dieses nicht -- und sie ist die groesste." Die Sorge ist
   richtig und hat mit der Anzahl der Seiten nichts zu tun. Die Frage
   lautet: KOMMT JEDE ROLLE AN IHRE AUSKUNFT?

   Genau das wird jetzt gemessen -- welche Seiten den Knopf tragen,
   aus den Dateien gelesen statt aufgezaehlt, und ob jede der acht
   Rollen mindestens eine davon erreichen darf, aus der Rechtetafel
   gelesen statt angenommen. Mit Gegenprobe (eine erfundene Rolle
   erreicht keine) und mit der Zahl in der Bedingung.

2. "DIE COMMUNITY STEHT BEI 8 VON 33"

   Hier stand `community.seiten < 5`. Die Zahl stimmte an dem Tag, an
   dem sie geschrieben wurde. Seither hat der Treff eigene Seiten
   bekommen -- Regeln, Steckbrief, Hilfe, Draussen -- und die
   Community steht bei acht. Die Pruefung war rot, WEIL der Treff
   gewachsen ist. Dieselbe Fehlerklasse wie die Umbruchschwelle vom
   06.09.: Wer eine Zahl notiert, notiert einen Zustand, keine Regel.

   Gemeint war eine ORDNUNG: Ein Mitglied sieht weniger als die
   Moderation, die weniger als die rechte Hand, die weniger als
   DogFather. Nachgemessen 8 / 19 / 25 / 32 von 33. Geprueft wird
   jetzt das Verhaeltnis -- und zusaetzlich, dass die Community das
   Minimum ueber ALLE acht Rollen ist, nicht nur in dieser Kette. Das
   bleibt richtig, wenn der Treff weiterwaechst, und faellt sofort
   auf, wenn jemand die Reihenfolge versehentlich umdreht.

pruef-auskunft         46/0  (war 46, davon 1 rot)
pruef-treff-werkzeuge  73/0  (war 70, davon 1 rot)

Damit sind alle vier Pruefungen gruen, die heute frueh rot waren.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:12:36 +02:00
DogFatherGitandClaude Opus 5 95d753791d Die dritte Fassung derselben Pruefung -- diesmal ohne Liste
pruef-modi-checkliste war rot: "und alle stehen in einer Gruppe fuer
euch beide -- ausser: Der Treff, Treff-Chat, Anschlagbrett, ..."

DIE URSACHE WAR EINE GEPFLEGTE LISTE, zum zweiten Mal. Erst stand dort
`["Team Dogi"]`, dann `["Team Dogi", "Entwicklung & Nachwuchs"]`, und
daneben der Satz: "Kommt eine dritte Gruppe, wird diese Zeile rot. Das
ist Absicht." Am 21.09. kam sie -- der Treff -- und nichts daran war
falsch.

WARUM DIE FRAGE SELBST NICHT MEHR PASSTE: `bereiche_zusatz` hiess
einmal "die eine Kachel, die nur ihr zwei habt". Seit es den Treff
gibt, steht dort fuer DogFather auch der GANZE Treff -- zehn Kacheln
in der Gruppe "Community", die die rechte Hand, die Moderation und
jedes Mitglied ebenso sehen. Das ist der zweite Haushalt, kein Mangel:
Fuer ihn ist der Treff eine Zugabe, fuer sie das Zuhause.

MEIN ZWEITER VERSUCH WAR SCHLECHTER ALS DER ERSTE, und gefangen hat
das nur die Gegenprobe. Ich wollte die verbotenen Gruppen MESSEN statt
sie aufzuzaehlen: "welche Gruppen sieht ein Creator, welche Spicy
Media?" Nachgemessen sind das in dieser Pruefdatenbank NULL -- beide
haben dort gar keine Kacheln. Die Bedingung waere damit immer wahr
gewesen, und aus einer roten Pruefung waere eine gruene geworden, die
nichts mehr misst. Gefangen hat es allein die Zahl in der Bedingung
(`sehenAlle.size >= 2`). Ohne sie haette ich eine Pruefung stillgelegt
und es fuer eine Reparatur gehalten.

JETZT WIRD NACH DER KACHEL GEFRAGT, NICHT NACH IHRER GRUPPE: Gibt es
unter den Zugaben mindestens eine, die sonst NIEMAND hat? Gemessen am
Ziel, gegen Modi, Spicy Media und Creator zusammen. Das ist die
urspruengliche Aussage, und sie altert nicht -- die Gruppe war immer
nur ein Hilfsmerkmal.

Die alte Gruppen-Zeile steht nicht mehr daneben. Sie waere jetzt immer
wahr, und eine Zeile, die immer bestaetigt, bestaetigt nichts.

Die Meldung sagt seitdem auch etwas:
  DogFather    davon 3, die sonst niemand hat (Dein Team, Wer sieht
               was, Talente), erwartet mindestens eine
  Creator      davon 0, die sonst niemand hat, erwartet keine

75 Pruefungen, 0 Fehler (war 70, davon 2 rot)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:10:41 +02:00
DogFatherGitandClaude Opus 5 25b5cf6224 "Unveraenderlich" stand auch auf Adressen, die sich aendern
Beim Nachmessen der Crew-Sperre von vorhin: Der Ursprung lieferte
korrekt 404 und eine bereinigte gate.css -- Cloudflare lieferte
weiterhin die ALTE Fassung, 27 806 Byte, `cf-cache-status: HIT`.

DIE URSACHE STAND IM EIGENEN KOMMENTAR. In index.js hiess es:
"`originalUrl` steht hier nicht zur Verfuegung -- geprueft wird
deshalb die Dateiart." Nachgemessen stimmt das nicht: `res.req
.originalUrl` ist da und liefert "/start.html?v=123". Die Annahme war
nie geprueft worden, und aus ihr folgte eine Zusage, die das Haus
nicht halten kann: JEDE CSS- und JS-Datei ging mit
`max-age=31536000, immutable` hinaus -- auch unter ihrer Adresse OHNE
Stempel.

"immutable" heisst woertlich: Der Inhalt unter DIESER Adresse aendert
sich nie. Fuer `gate.css?v=...` stimmt das, der Name wechselt ja mit
dem Inhalt. Fuer `gate.css` ist es falsch -- und dort haette die alte
Fassung ein Jahr im Zwischenspeicher gelegen, waehrend der Server
laengst etwas anderes sagt. Ein Zwischenspeicher, der etwas Falsches
zeigt, ist schlimmer als gar keiner: man glaubt ihm.

Jetzt haengt die Zusage an der Bedingung, die sie traegt. Mit Stempel
bleibt alles wie bisher -- die Seiten rufen ohnehin immer `?v=...`
auf, dort kostet es nichts. Ohne Stempel wird nachgefragt. Die
oeffentliche Seite benutzt ebenfalls `?v=` (mit Buchstabe am Ende);
geprueft wird nur, OB einer da ist, nicht wie er aussieht.

DIESELBE SORTE FEHLER GLEICH NEBENAN: pruef-zwischenspeicher hat einen
Abschnitt "Was einen Stempel traegt, darf liegenbleiben" -- und rief
die Dateien OHNE Stempel ab. Auch hier beschrieb der Text etwas, das
der Code nicht tat. Er liest den Stempel jetzt aus der Seite und misst
damit genau die Adresse, die ein Browser anfordert. Dazu vier neue
Zeilen fuer den umgekehrten Fall, mit Gegenprobe an derselben Datei --
sonst waere "ohne Stempel: no-cache" auch dann gruen, wenn ALLES auf
no-cache stuende, und jeder Seitenaufruf waere unnoetig langsam.

UND MEIN EIGENER FEHLER VON GESTERN, behoben: Die Stempelpruefung
verglich seit dem 20.09. den Stempel mit dem ZEITPUNKT des letzten
Commits an assets/. Das kann gar nicht aufgehen -- der Stempel wird
immer VOR dem Committen gezogen, die Commit-Zeit ist also immer die
juengere. Stempeln um 12:59 und Committen um 13:00 genuegte fuer einen
Fehlalarm; heute ist genau das passiert.

Gefragt wird jetzt die REIHENFOLGE der Commits, die hat keine Uhr:
Liegt der letzte Commit an den HTML-Seiten (dort steht der Stempel)
auf oder nach dem letzten an assets/? `merge-base --is-ancestor`
beantwortet das ohne Zeitstempel. Mit Gegenprobe ueber das Elternteil
-- und mit drittem Ausgang, wenn es keines gibt.

pruef-zwischenspeicher: 27 Pruefungen, 0 Fehler (war 22, davon 2 rot)

NOCH OFFEN und nur von Filipe zu machen: Cloudflare haelt die alten
Fassungen unter den stempellosen Adressen weiter im Zwischenspeicher.
Der Ursprung ist sauber; geleert werden muss der Rand einmal von Hand.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:04:38 +02:00
DogFatherGitandClaude Opus 5 ea8ceaa539 Das Farbhaus von Team Dogi lag oeffentlich im Netz
Ausgeloest von pruef-modi-wortleck, die seit Tagen rot war: "24
Fundstellen -- der verborgene Zugang waere damit auffindbar." Die
erste Frage war, ob sie recht hat. Gemessen: ja, und schlimmer als
gedacht.

WER DIESE DATEIEN BEKOMMT: Nicht nur Kollegen. `curl` ohne jeden Keks
auf workspace.dogfather-universe.com liefert die Skripte und
Stilvorlagen des Arbeitsplatzes mit HTTP 200 -- fuer jeden im Netz
lesbar.

DARUNTER crew-haus.css, 27 806 Byte, das ganze Farbhaus von Team Dogi
samt seiner Kommentare. In deren Kopf stand seit dem 10.09. woertlich
"Diese Datei wird NUR auf crew.dogfather-universe.com ausgeliefert."
Das war eine Behauptung, keine Tatsache: Die Weiche biegt `haus.css`
auf diesen Namen um, wer den Namen direkt nannte, ging an ihr vorbei.
Ein Kommentar, der eine Absicht beschreibt, erfuellt sie nicht.

Zwei Stellen im Haus haben sich damit widersprochen -- die Datei sagte
"nur auf crew.", pruef-crew-adresse verlangte ausdruecklich das
Gegenteil ("sie ist kein Geheimnis"). Durchgesetzt war die offene
Fassung. Filipe hat am 21.09. entschieden: zusperren. Die alte
Begruendung dagegen war die Sorge, eine Sperre koenne die Pruefung
blind machen -- die ist jetzt beantwortet statt vermieden: Jeder
Eintrag der Tafel wird in BEIDE Richtungen gemessen, und dass die
Umbiegung von `haus.css` auf crew. weiterhin greift, ebenfalls.

DIE ADRESSE WAR DAS EIGENTLICHE GEHEIMNIS, nicht das Wort. Die
Rollennamen stehen auf der Zugangswand von Team Dogi ohnehin offen --
so gewollt. WO sie liegt, stand dagegen im Klartext in gate.css,
gate.js und crew-haus.css, alle drei oeffentlich abrufbar. Jetzt steht
sie in keiner ausgelieferten Datei mehr.

DIE PRUEFUNG SELBST HATTE DREI MAENGEL:

  1. Sie kannte die Mehrzahl nicht. `\bmodi\b` fand "ein Modi", nicht
     "die Modis" -- 23 weitere Stellen, darunter der Satz "Fuer die
     rechte Hand und die Modis gibt es dort den stillen Zugang". Also
     genau die Auskunft, die sie verhindern soll, in der Form, die sie
     nicht sah.
  2. Ihre Ausnahmeliste war abgeschrieben. Sie nannte eine Datei; die
     zweite, die der Server auf crew. begrenzt, haette sie nie
     erfahren. Ausgenommen ist jetzt genau das, was der Server auch
     durchsetzt (GEHOERT_ZU_ADRESSE) -- kein Muster, sondern die
     Durchsetzung selbst.
  3. Sie mahnte 45 Kommentare an. Filipes Entscheidung: in Kommentaren
     ja, in Code und sichtbaren Texten nein. Rot, das immer da ist,
     wird ueberlesen -- und dann faengt sie auch den echten Fall nicht.

Dafuer neu: helfer-ohne-kommentar.mjs, ein Zerleger, der Kommentare
zeichengenau durch Leerzeichen ersetzt, ohne Zeichenketten,
Vorlagen oder Suchmuster zu beschaedigen. KEIN Suchausdruck -- genau
daran ist am 20.09. die Portumstellung gescheitert, mit gueltigem
JavaScript ohne das Feld `port`. Dreizehn Proben in beide Richtungen
beweisen, dass er weder zu viel noch zu wenig wegnimmt; ein Zerleger,
der zu viel nimmt, macht die ganze Pruefung STILL gruen.

Von 45 blieben damit drei echte, alle behoben:
  - daten.modis  -> daten.leute (Feldname in der Auskunft, also Code)
  - zwei Saetze, die Menschen lesen, auf "die Moderation" umgestellt --
    fuer jemanden, der neu im Treff ist, sogar klarer

Nebenbei, beim selben Durchgang gefunden und geschlossen:
  - teamlage.js fiel auf einen Rollennamen zurueck. Nachgemessen: Die
    Stilvorlage kennt zu dieser Karte gar keine solche Regel -- der
    Rueckfall hat nie etwas bewirkt und nur das Wort ausgeliefert.
  - werdegang.js fuehrte die Saetze ueber den Rollengruppen selbst,
    mit den Rollennamen als Schluessel. Der Kommentar daneben
    behauptete sogar, sie seien "abgeleitet, nicht abgeschrieben".
    Sie kommen jetzt vom Server, und pruef-werdegang misst, dass
    jede Gruppe ihren eigenen behaelt.

pruef-modi-wortleck  8/0  (war 5, davon 1 rot)
pruef-crew-adresse 144/0  (war 135)
pruef-werdegang    98 statt 95 Pruefungen, dieselben 3 alten Fehler
pruef-team-ampel 32/0, pruef-team-stufen 28/0, pruef-hilfe 84/0

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:00:01 +02:00
DogFatherGitandClaude Opus 5 eca9aed279 Der Treff sagt jetzt, ob gerade gestreamt wird
Filipe zu dieser Seite: "mach was anderes daraus oder mach es viel
krass und geiler ... erstell was was mich von den socken schmeisst. es
soll wirklich sogar ein wow effekt fuer die community ergeben." Dazu
die eine Auflage: die Kachel bleibt.

WAS SIE WAR: zwei Karten mit zwei Adressen. Sauber gebaut, richtig
beschriftet -- und niemand kam ein zweites Mal wieder. Wer im Treff
ist, kennt die Website. Den Rabattcode merkt man sich beim ersten Mal.

DIE FRAGE, DIE WIRKLICH JEMAND HAT, IST EINE ANDERE: Laeuft er
gerade? Und wenn nicht -- wie lange noch? Die Antwort kennt das Haus
seit dem 20.08.: postfach.dogfather-universe.com/live-status, derselbe
Dienst, von dem der oeffentliche Streamplan lebt. Im Treff gab es sie
bisher nicht.

Jetzt steht oben ein Puls: ein Ring, der sich ueber den Tag bis zur
naechsten Sendezeit fuellt, darin der Countdown auf die Sekunde. Sendet
er, wird die Karte rot, atmet im Ruhepuls und traegt den Titel des
Streams plus einen Weg hin. Darunter die drei Accounts und -- wenn die
Verwaltung eines eintraegt -- das besondere Event mit eigener Uhr.

DREI AUSGAENGE, NICHT ZWEI. Das ist der eigentliche Unterschied zur
oeffentlichen Seite: streamplan.js faengt dort jeden Fehler ab und
setzt `istLive = false`. Aus "wir konnten nicht fragen" wird "er sendet
nicht" -- und wer das liest, macht die Seite zu und verpasst den
Stream. Der Dienst liefert `autoHealthy` sogar mit; gelesen wird es
draussen nicht. Hier schon: Bei einer Stoerung steht "Konnten wir
gerade nicht nachsehen", dazu der Hinweis, dass das NICHT heisst, dass
kein Stream laeuft. Der Countdown laeuft dabei weiter -- er braucht
kein Netz.

NICHTS IST ABGESCHRIEBEN. Die drei Accounts kommen ueber
/workspace/api/draussen aus derselben KANAELE-Liste, an der die
Aufgabenverteilung haengt; die Adressen baut der Steckbrief. Die
Sendezeit steht im Server, und pruef-draussen haelt sie gegen
FIX_STUNDE in streamplan.js -- verschiebt jemand den Termin und aendert
nur einen Ort, wird die Pruefung rot.

Gemessen, bevor gebaut wurde: der Dienst antwortet und meldet sich
gesund, CORS steht auf *, und `connect-src` der Treff-Seiten fuehrt
postfach bereits. Ohne das Letzte waere der Abruf still blockiert
worden und haette ausgesehen wie ein toter Dienst.

Die Kachel heisst jetzt "Draussen" statt "Unsere Seiten" -- drei Dinge
statt zwei Adressen. Ziel und Datei bleiben gleich.
pruef-wege-nach-draussen schreibt den Namen nicht mehr ab, sondern
verlangt, dass Kachel und Seitenueberschrift uebereinstimmen. Zwei
Namen fuer denselben Ort waren schon einmal ein echter Fehler.

Nebenbefund, dort gleich behoben: Dieselbe Pruefung verlangte, dass
die Community-Kacheln restlos in Dreierreihen aufgehen -- obwohl ihr
eigener Kommentar sagt, eine freie Zelle am Ende sei erlaubt. Sie war
rot bei einwandfreiem Raster. Gemessen wird jetzt, was wirklich
schiefgeht: eine doppelt breite Kachel, die in der letzten Spalte
beginnt und die Zelle davor leer laesst. Mit Gegenprobe.

pruef-draussen: 39 Pruefungen, alle vier Lagen im echten Browser --
die Stoerung wird dafuer absichtlich hergestellt.
pruef-wege-nach-draussen: 67 statt 66, keine Fehler mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 12:06:23 +02:00
DogFatherGitandClaude Opus 5 9a71f3a242 Eine Null zu viel -- HasiDog-Videos waeren abgelehnt worden
In KANAELE stand "@hasidog00804". Der Account heisst "@hasidog0804".
Nachgemessen bei TikTok selbst: der richtige hat 65 Follower, der
andere liefert "Couldn't find this account".

Das war nicht kosmetisch. `kanalVonHandle` ordnet ein hochgeladenes
Video ueber genau diesen Text einem Kanal zu. Ein echtes
HasiDog-Video waere mit 403 abgelehnt worden -- und die Begruendung
haette gelautet: "ist keiner deiner Kanaele. Moeglich sind:
@dogfather0804, @hasidog00804, @dogis.modi.gang." Eine Sackgasse, die
zusaetzlich eine Adresse nennt, die es nicht gibt.

WARUM ES KEINE PRUEFUNG GEFUNDEN HAT: pruef-kanalzeile und
pruef-teilen hatten denselben Handle abgeschrieben. Zwei Abschriften
desselben Tippfehlers bestaetigen sich gegenseitig -- beide waren
gruen. Sie leiten ihn jetzt aus KANAELE ab und koennen ihn damit gar
nicht mehr eigenstaendig falsch haben.

Gefunden hat es ein Vergleich: Die oeffentliche Website verlinkt
dieselben Accounts und hatte die richtige Schreibweise. Genau das ist
jetzt Abschnitt 7 von pruef-kanaele -- alle Handles muessen auch
draussen vorkommen, mit Gegenprobe, dass eine falsche Adresse
durchfaellt. Ohne Netz, damit eine Stoerung bei TikTok nicht zu einem
roten Alarm im Haus wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:51:06 +02:00
DogFatherGitandClaude Opus 5 2a6008d699 Versionsstempel auf 202609211145
chat.css hat sich geaendert. Ohne den Stempel behaelt jeder Browser
seine alte Kopie, und die groesseren Farbkacheln kaemen bei niemandem
an. 505 Verweise in 37 Dateien.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:45:23 +02:00
DogFatherGitandClaude Opus 5 8bd6474844 Die Farbkacheln im Chat waren mit dem Daumen zu klein
30x30 ist mit der Maus bequem und am Handy zu klein; die Grenze im Haus
sind 44px. Angehoben wird nur auf Fingergeraeten (pointer: coarse),
sonst staende der Knopf am Rechner unnoetig gross neben einer Zeile,
die selbst nur 30 hoch ist. Sichtbar bleibt die Kachel gleich gross --
gewachsen ist die Flaeche, die den Finger annimmt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:45:06 +02:00
DogFatherGitandClaude Opus 5 e12074c32c Der Stempel wird mit der Uhr verglichen, nicht mit dem Commit
pruef-zwischenspeicher verlangte, dass derselbe Commit die Stilvorlage
UND die HTML aendert. Das ist der Normalfall, aber nicht die Regel:
Wird der Stempel in einem Folge-Commit nachgezogen, kommt die Aenderung
genauso an -- die Pruefung blieb trotzdem rot und beschuldigte einen
Commit, an dem nichts falsch war. Eine rote Zeile, die rot bleibt,
bringt Menschen dazu, Rot zu uebersehen.

Verglichen wird jetzt der Stempel selbst mit dem Zeitpunkt der letzten
Aenderung an assets/. Ein Stempel, der juenger ist, wurde danach
gezogen -- egal in welchem Commit. Das ist strenger als vorher, nicht
lockerer: Eine HTML-Aenderung aus einem ganz anderen Grund (ein
Tippfehler im Text) haette die alte Pruefung besaenftigt, ohne dass der
Stempel gezogen wurde.

Dazu ein Fund am Rand: anruf-probe.html trug ein handgeschriebenes
?v=202609191018 am Manifest-Link. Kein Werkzeug pflegt diese Stelle,
keine der 20 anderen Seiten hat so etwas -- sie waere still veraltet.
Entfernt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:45:06 +02:00
DogFatherGitandClaude Opus 5 200728c8e7 Der leere Ring zeigte "100 %" -- das las sich wie "alles geschafft"
Die Pruefung verlangte prozent === 100, wenn gar nichts zu tun war. Der
Gedanke war richtig (ein leerer Ring darf nicht wie Versagen aussehen),
die Umsetzung nicht: Gelesen wird zuerst die Zahl in der Mitte, und
"100 %" heisst fuer jeden Menschen "fertig". Am ersten Tag, ohne eine
einzige Aufgabe, stand das als groesstes Element der Startseite.

Seit dem 19.09. steht dort ein Strich. Ein Anteil von nichts ist keine
Null und keine Hundert, sondern nicht definiert. Die Pruefung fragt
jetzt danach -- und damit gleichzeitig schaerfer: Solange gar keine Zahl
dasteht, kann dort auch nicht versehentlich der Uhrzeitwert stehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:44:55 +02:00
DogFatherGitandClaude Opus 5 782a9116f2 Zwei Pruefungen rechneten in UTC und schlugen abends falschen Alarm
pruef-zeitraum und pruef-highlights bildeten ihren Tagesstempel mit
toISOString(). Das ist UTC. Zwischen 22:00 und Mitternacht deutscher
Zeit ist das schon der naechste Tag -- die Pruefungen verglichen dann
einen Eintrag von heute mit dem Datum von morgen und meldeten einen
Fehler, wo keiner war.

Der Zeitraum-Filter im Haus rechnet richtig; er benutzt tagLokal() aus
helfer-zeit.mjs. Nur die Pruefungen darueber hatten ihre eigene, falsche
Rechnung. Jetzt benutzen sie denselben Helfer wie der Code, den sie
pruefen -- damit koennen die beiden gar nicht mehr auseinanderlaufen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:44:55 +02:00
DogFatherGitandClaude Opus 5 acd3e1f385 Zwei Tabellenumbauten haetten 15 Spalten still geloescht
`personen` und `aufgaben` wurden beim Freischalten eines neuen
CHECK-Werts von Hand neu gebaut -- die Spaltenliste stand zweimal im
Code abgeschrieben (CREATE und INSERT). Gemessen:

  aufgaben: 23 Spalten, 18 aufgezaehlt -> vorlage, kategorie,
            aus_eintrag_id, aufwand, aus_punkt weg
  personen: 19 Spalten,  9 aufgezaehlt -> bild, ueber_mich, tiktok,
            instagram, youtube, twitch, chat_kachel, code_kennung,
            stufe, alter_bestaetigt_am weg

Bei `personen` haengen daran die Profilfotos und die
Altersbestaetigung: Alle waeren nach einem Rueckspielen still wieder
unbestaetigt gewesen, ohne Fehlermeldung, bei unveraenderter
Zeilenzahl. Die Zeilenzaehlung, die als Sicherung gedacht war, kann
einen Spaltenverlust gar nicht sehen.

Es ist derselbe Fehler wie am 11.09. an der Eintragstabelle (24 hinein,
21 heraus). Damals wurde `checkListeErweitern` gebaut, das die Spalten
aus PRAGMA table_info ABLEITET -- eine Liste, die niemand pflegt, kann
nicht veralten. Diese beiden Bloecke waren aelter und wurden bei der
Umstellung uebersehen. Jetzt gehen alle 16 Umstellungen denselben Weg,
kein Neubau zaehlt mehr von Hand.

Auf dem laufenden Server ist nichts verloren (24 Spalten, CHECK
vollstaendig) -- die Falle stand fuer den Tag, an dem jemand eine
Sicherung zurueckspielt.

Gefunden hat es nicht das Lesen, sondern pruef-abbrechen: Sie baut
absichtlich eine ALTE Datenbank und liess die Umstellung darauf laufen
-- danach meldete der Server "no such column: a.aufwand".

Neu: pruef-umstellung.mjs (18 Pruefungen) haelt die Fehlerklasse
dauerhaft zu. Sie baut eine echte alte Datenbank mit gefuellten
Spalten, laesst die Umstellung laufen und zaehlt danach Spalten UND
Inhalte. Mit Gegenprobe: ein absichtlich fehlerhafter Umbau zeigt, dass
die Zeilenzahl dabei stimmt und trotzdem Daten fehlen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 11:44:45 +02:00
DogFatherGitandClaude Opus 5 0082c74bd7 Versionsstempel nachgezogen
pruef-zwischenspeicher hat es gemeldet: Der Commit davor hat
Stilvorlagen und Skripte geaendert, aber keine HTML -- damit bleibt
der Verweis `?v=...` stehen, der Browser haelt seine alte Kopie fuer
aktuell (ein Jahr, unveraenderlich), und die Reparatur kaeme bei
niemandem an.

Genau der Fall, fuer den die Pruefung gebaut wurde: Ein Deploy, der
fehlerfrei durchlaeuft und trotzdem nichts ausliefert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 23:14:14 +02:00
DogFatherGitandClaude Opus 5 67a0eb8717 DogFather konnte einen zweiten DogFather nicht mehr herabstufen
Gefunden beim Durchsehen der schnellen Pruefungen: pruef-haus-trennung
stand auf 60 ok / 6 Fehler. Drei Ursachen, eine davon ein echter
Rueckschritt von gestern.

--- 1. DER RUECKSCHRITT ---------------------------------------------

In darfRolleAendern stand seit gestern:

  if (person.rolle === "admin") return ziel.rolle !== "admin";

Das macht aus "DogFather ist nicht mehr VERGEBBAR" ein "an einem
DogFather ist nichts mehr zu aendern". Ein zweiter Zugang liess sich
damit nie wieder zuruecksetzen -- er waere fuer immer DogFather
geblieben. Die Pruefung sagte es woertlich: "solange es zwei gibt,
darf einer wechseln (403)".

Die beiden echten Gefahren haengen woanders und bleiben unberuehrt:
Niemand KANN 'admin' vergeben, und der LETZTE DogFather laesst sich
nicht herabstufen.

--- 2. ZWEI SCHLOESSER FUER DIESELBE TUER ---------------------------

Ich hatte gestern `rollenZumAendern` mit 403 VOR die vorhandene
Pruefung gesetzt, die mit 400 "Unbekannte Rolle." antwortet. Damit war
die Luecke wieder offen, vor der der Kommentar vom 17.09. direkt
daneben warnt: Zwei verschiedene Antworten -- "gibt es nicht" gegen
"darfst du nicht" -- verraten beim Durchprobieren, WELCHE Rollen
existieren.

Jetzt eine Regel an einer Stelle. `darfAnlegen` ist dort raus, weil
Vergeben und Anlegen seit gestern verschiedene Dinge sind. Gemessen:

  admin   anlegen = aendern (sieben Rollen)
  spicy   anlegen = aendern (vier)
  hand    anlegen = —        aendern = modi, gast
  manager anlegen = creator  aendern = —

Und die eigene Zeile bekommt jetzt 400 mit einem Satz statt 403:
Es ist keine Rechtefrage, sondern eine unsinnige Bitte.

--- 3. DREI ERWARTUNGEN, DIE AELTER WAREN ALS DIE REGEL --------------

Die Pruefung verlangte 403, wo seit dem 17.09. 400 richtig ist --
ihre Zeile stammt vom 10.09., sieben Tage aelter als die Regel. Und
sie verlangte 404 fuer "die rechte Hand vergibt keine Rolle", was bis
vorgestern stimmte.

Dabei fiel auf, dass NICHTS geprueft hat, ob die rechte Hand ihre neue
Faehigkeit ueberhaupt ausueben kann -- nur, dass sie es nicht darf.
Eine Pruefung, die nur das Verbotene misst, laesst offen, ob das
Erlaubte geht. Jetzt beide Richtungen:

  an einer anderen rechten Hand aendert sie nichts (403)
  und an DogFather erst recht nicht (403)
  einen Modi macht sie sehr wohl zur Community (200)
  und es steht so in der Datenbank (gast)
  eine zweite rechte Hand ernennt sie nicht (400)

Nebenbei: `unbekannte_kachel` (gestern eingefuehrt) hatte keinen Satz
in meldung.js -- die Kennung waere woertlich auf dem Bildschirm
gelandet. pruef-meldungen hatte es gemeldet.

Und ein Absturz beim Bauen: `const anlegen = await hole(...)` weiter
unten im selben Block verdeckt die gleichnamige Funktion im GANZEN
Block, auch oberhalb seiner eigenen Zeile.

pruef-haus-trennung: 70 ok, 0 Fehler (vorher 60/6).
Dazu gruen: rollen-anlegen 11/0, personen-loeschen 40/0,
rechte-umstellen 46/0, verteilen 11/0, meldungen 8/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 23:13:27 +02:00
DogFatherGitandClaude Opus 5 445ea88f2b fetch verweigert Port 5060 -- und sagt dasselbe wie ein toter Server
Nach der Umstellung auf abgeleitete Nummern bekam pruef-chat-kanaele
die 5060 und stuerzte ab:

  TypeError: fetch failed

Der Server lief nachweislich ("Server laeuft auf http://127.0.0.1:5060"),
die Anmeldung ueber `http.request` hatte sogar geklappt, und BASIS war
sauber ("http://127.0.0.1:5060", 21 Zeichen, PORT eine Zahl). Nur die
`fetch`-Aufrufe scheiterten.

5060 ist SIP und steht auf der "bad ports"-Liste der
Fetch-Spezifikation. Node hat sie uebernommen: `fetch` baut dorthin
keine Verbindung auf, noch bevor ein Paket fliegt. Die Ursache steht
nur in `.cause` -- "bad port" statt "ECONNREFUSED". Die Meldung
obendrueber ist beide Male dieselbe, und wer sie liest, sucht am
Server.

Gegengeprueft mit einem echten Zuhoerer auf beiden Nummern:
  5060 -> fetch failed (bad port)
  5062 -> fetch failed (ECONNREFUSED)   <- also normal erreichbar

`eigenerPort` ueberspringt die gesperrten Nummern jetzt (portNummer).
Uebersprungen wird nach der REGEL, nicht nach einer Tabelle von
Sonderfaellen: die n-te brauchbare Nummer ab 5000. Eindeutig bleibt es,
weil die Reihenfolge feststeht.

pruef-portnummern (11 statt 8) prueft es doppelt: gegen die Liste UND
am echten Verhalten -- ein Zuhoerer auf 5060 muss fuer `fetch` tot
sein, einer auf einer abgeleiteten Nummer erreichbar. Ohne die zweite
Haelfte waere die Liste nur eine Behauptung ueber Node, und
Behauptungen altern.

Nebenbefund: Auch im alten, von Hand vergebenen Bereich lag eine
gesperrte Nummer -- die 4190. Sie war nie vergeben, rein zufaellig.

pruef-chat-kanaele: 79 Pruefungen, 0 Fehler -- wieder auf der
Grundlinie, die vor der Umstellung gemessen wurde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 23:06:52 +02:00
DogFatherGitandClaude Opus 5 aa8842e72e Zwei Pruefungen waren rot, weil Namen sich geaendert hatten
Beide meldeten seit Tagen einen Fehler, den es nicht gab. Eine rote
Pruefung, die rot BLEIBT, gewoehnt einem das Hinsehen ab -- ab da
uebersieht man auch die echte.

--- pruef-teilen: 14 ok / 3 Fehler -> 27 ok / 0 --------------------

Sie suchte `.teilen__brett`. Die Seite baut `.tl-brett`; die Klassen
wurden irgendwann umbenannt, und die Pruefung suchte seitdem nach
Elementen, die es nicht gibt. Gemeldet hat sie das sogar richtig --
"drei Ziele zur Auswahl (0)" --, nur hat niemand die Klammer gelesen.
Danach lief sie in einen Klick-Zeitablauf und brach ab, weswegen
DREIZEHN weitere Pruefungen nie stattfanden.

--- pruef-crew-wand-bild: 41 ok / 4 Fehler -> 45 ok / 0 ------------

Zwei feste Erwartungen aus einer Zeit, die vorbei ist:

1. `/Team Dogi/` im Reiter. Die App heisst seit dem Treff-Umzug
   "DogFather Universe". Statt den neuen Namen einzutragen -- und
   damit dieselbe Zeitbombe mit neuem Datum zu stellen -- kommt er
   jetzt aus `crew.webmanifest`. Benennt jemand die App um, folgt der
   Reiter, und beides bleibt gruen. Weichen sie auseinander, sieht der
   Mensch im Reiter einen anderen Namen als auf seinem
   Startbildschirm, und genau das soll die Pruefung finden.

2. `kacheln === 3`, seit Filipe am 10.09. sagte "3 rollen. dogfather.
   rechte hand und modis". Am 19.09. zog der Treff in Team Dogi ein
   und die Community kam als vierte dazu -- die Zahl war ab da falsch,
   die Wand richtig. Verglichen wird jetzt die MENGE der Rollen, nicht
   ihre Anzahl: Eine Zahl sagt beim Scheitern "3 erwartet, 4
   gefunden" und verschweigt, WELCHE.

Beide Male war die Seite richtig und die Pruefung veraltet -- das ist
dieselbe Krankheit wie bei den Portnummern und bei pruef-entwicklung:
ein Name oder eine Zahl, abgeschrieben an einer zweiten Stelle, die
niemand mitpflegt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 22:55:41 +02:00
DogFatherGitandClaude Opus 5 6e46a08543 Portnummern werden abgeleitet, nicht mehr vergeben
Gemessen: 165 Pruefdateien, 129 verschiedene Nummern -- NEUNZEHN
doppelt, vier davon dreifach. Niemand hatte das gewollt; jede neue
Pruefung wurde von einer vorhandenen abgeschrieben, und die Nummer kam
mit. Meine eigene Notiz sagte "sieben" -- auch eine Bestandsliste
altert.

Der Waechter faengt den Schaden ab, aber er kann nur melden, was schon
passiert ist: Zwei Pruefungen mit derselben Nummer koennen nie
gleichzeitig laufen, und ein liegengebliebener Prozess der einen laesst
die andere abbrechen mit einer Meldung, die wie ein Befund aussieht.
Genau das ist mir am 20.09. zweimal passiert.

Jetzt leitet jede Datei ihre Nummer aus ihrer STELLE IM ALPHABET ab
(eigenerPort in helfer-port.mjs), zwei je Datei. Nicht ueber eine
Pruefsumme: Bei 165 Namen in 4900 Nummern waeren nach dem
Geburtstagsproblem rund DREI Zusammenstoesse zu erwarten -- ein Hash
tauscht eine sichtbare Doppelung gegen eine unsichtbare. Die Stelle im
Alphabet ist eindeutig von der Bauart her.

--- ZWEI FEHLER AUF DEM WEG, BEIDE LEHRREICH -------------------------

1. DER ERSTE VERSUCH WAR GRUEN UND KAPUTT. Ersetzt wurde mit einem
   Muster: "([^"]*4231[^"]*)". Das hielt

     { host: "127.0.0.1", port: 4231, path: "/404.html" }

   fuer eine Zeichenkette -- ein Muster kann eine oeffnende nicht von
   einer schliessenden Anfuehrung unterscheiden. Heraus kam

     { host: "127.0.0.1`, port: ${PORT}, path: `/404.html" }

   also GUELTIGER Code ohne port-Feld. `node --check` sagte gruen fuer
   alle 164 Dateien. Aufgefallen ist es erst, weil ich vier Vertreter
   gegen eine vorher gemessene Grundlinie laufen liess: pruef-schranke
   39/0 vorher, 38/1 nachher.

   Alles zurueckgenommen und mit einem Zerleger neu gemacht, der weiss,
   ob eine Stelle Code, Zeichenkette, Vorlage, Kommentar oder
   regulaerer Ausdruck ist. In pruef-ics stand die Nummer in einem
   regulaeren Ausdruck -- der wird jetzt gebaut statt hingeschrieben.

2. EIN MODUL, DAS BEIM IMPORTIEREN ARBEITET, IST EINE FALLE. Der
   zweite Durchgang importierte den ersten, um seine Mechanik zu
   benutzen -- und fuehrte dessen Hauptlauf gleich mit aus. Die
   zweiten Nummern wurden dadurch als erste behandelt, zwei Aufrufe
   bekamen dieselbe Nummer, und in pruef-content stand `const PORT`
   zweimal.

--- WAS DAS DAUERHAFT HAELT -----------------------------------------

pruef-portnummern.mjs (neu, 8 Pruefungen) fragt nicht "welche Nummern
sind doppelt", sondern "wer traegt ueberhaupt noch eine von Hand ein"
und "wer startet einen Server, ohne seine Nummer abzuleiten". Die
zweite Frage hat sofort etwas gefunden, das in KEINER Doppelungsliste
stand: pruef-push-weg belegte 4341 und 4342, rief den Waechter aber
gar nicht auf -- dieselbe Nummer wie pruef-agentur. Eine Liste zeigt
nur, was auf ihr steht.

Mit Gegenprobe: Eine unbekannte Datei bekommt keine geratene Nummer,
sondern einen Abbruch, und eine dritte Nummer je Datei gibt es nicht.

--- NACHGEMESSEN ----------------------------------------------------

Sechzehn Pruefungen gegen ihre vorher gemessene Grundlinie, je eine
Vertreterin jeder umgestellten Bauweise (eine Nummer, zwei Nummern,
Nummer in einer Zeichenkette, in einer Vorlage, in einem regulaeren
Ausdruck, dynamische Einfuhr, Nachtlauf mit zwei Laeufen):

  crew-adresse 132/0 · schranke 39/0 · content 45/0 · entwicklung 46/0
  anruf 127/0 · ics 37/0 · push-weg 20/0 · arten 28/0 · video 67/0
  kanalzeile 14/0 · agentur 62/0 · spicy 83/0 · creator-anlegen 50/0
  push-ziel 10/0 · portnummern 8/0

Alle exakt wie vorher. Zwei waren schon vorher rot und sind es
unveraendert geblieben (crew-wand-bild 41/4, teilen 14/3) -- per
`git stash` belegt, nicht angenommen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 22:51:21 +02:00
DogFatherGitandClaude Opus 5 d79cb9196b Die Entwicklungs-Pruefung war rot, ohne dass etwas kaputt war
Sie hielt seit dem 19.09. eine Namensliste fest:

  !["Eure Aufgaben", "Talente"].includes(k.name)

Als ein Modi eine eigene Kachel bekam -- "Deine Aufgaben", weil
"Eure" aus seiner Sicht falsch ist -- wurde sie rot. Nichts war
kaputt, der Name hatte sich geaendert. Das ist die abgeschriebene
Liste zum dritten Mal in diesem Haus, und diesmal traf sie eine
Pruefung: Eine rote Pruefung, die rot BLEIBT, gewoehnt einem das
Hinsehen ab und ist damit schaedlicher als gar keine.

Erst nachgemessen, ob die Kachel ueberhaupt falsch ist: In
workspace-entwicklung.js steht

  const personen = leitung ? db().prepare(...) : [];

Ein Modi bekommt dort eine LEERE Liste -- er sieht auf der Seite nur
sich selbst. Die Kachel war also richtig, die Pruefung nicht.

An ihre Stelle treten zwei Messungen:

1. DAS VERSPRECHEN STATT DES NAMENS. Filipe hatte gemeldet, dass auf
   der Kachel "die Antworten sieht nur du" stand und sie trotzdem auf
   eine Seite mit fremden Namen fuehrte. Das ist eine Eigenschaft des
   Untertitels, nicht des Namens. Wer morgen eine Kachel "Dein Kopf"
   nennt und dasselbe verspricht, ist mitgeprueft -- die Namensliste
   haette ihn durchgelassen.

2. DIE ECHTE GRENZE, die bisher NIEMAND gemessen hat. Ob eine Kachel
   richtig zeigt, ist Beschriftung; ob die Seite dahinter fremde Namen
   herausgibt, sind Daten -- und nur das schuetzt jemanden wirklich.
   Gemessen wird jetzt beides: Ein Modi bekommt auf /entwicklung/lage
   NIEMANDEN (0), DogFather und die rechte Hand bekommen sehr wohl
   welche (2). Die zweite Zeile ist die Gegenprobe zur ersten -- waere
   der Filter einfach zu, saehe auch die Leitung nichts, und die
   Modi-Zeile waere trotzdem gruen.

Nebenbei: Beim ersten Lauf stand `lage.code === 200` statt
`lage.status` -- der Helfer heisst anders. Beide Zeilen wurden dadurch
ROT, obwohl die Zahlen (2 und 0) von Anfang an stimmten. Der richtige
Ausgang: lieber laut scheitern als still bestaetigen.

pruef-entwicklung: 46 Pruefungen, 0 Fehler (vorher 43 mit 1 Fehler).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 22:32:44 +02:00
DogFatherGitandClaude Opus 5 b0e7542507 Der Anrufkasten zeigt, WER dran ist -- nicht dreimal "Verbunden"
Filipe, zu Screen 1: "wenn ich anrufe soll das auch viel besser geiler
und spezieller aussehen aber es soll nicht raushaengen."

Erst gemessen: Es haengt nichts raus. Der Kasten ist 374 px am Handy,
340 am Rechner, 72 Teile geprueft, kein einziges ueber dem Rand. Die
Optik war also gar nicht der Mangel -- zwei andere Dinge waren es.

1. DER NAME DES ANRUFERS GING IMMER VERLOREN.
   `wer(raumName || "Anruf")` lief VOR `kastenBauen()`. Das Element
   #anruf-wer gab es zu dem Zeitpunkt noch nicht, die Zuweisung lief
   ins Leere, und oben stand bei jedem Anruf das Wort "Anruf". Die
   Reihenfolge ist umgedreht: erst bauen, dann beschriften.

2. IN EINEM ANRUF OHNE VIDEO STAND JE PERSON DAS WORT "Verbunden".
   Bei dreien dreimal dasselbe Wort -- und man sah nicht, WER dabei
   war. In einer Gruppe ist genau das die Frage: Ist Kessi schon
   drin? Jetzt steht dort ein Kreis mit den Anfangsbuchstaben und der
   echte Name; waehrend es klingelt ein wartendes Gesicht mit dem
   Namen dessen, den man anruft. Vorher war die Flaeche in dieser
   Sekunde leer, und ein leerer Kasten mit "Es klingelt ..." sieht
   aus wie einer, der haengt -- ausgerechnet im unsichersten Moment.

Der Name kommt NICHT aus einer Abfrage. Wer anruft, bekannt beim
Start nur sich selbst; alle weiteren kommen ausschliesslich ueber das
Ereignis "dabei", und genau dort fehlte das Einsammeln. Deshalb sah
der ANRUFER unter jedem Kreis "Jemand" -- die Angerufenen nicht.

UND DIE PRUEFUNG WAR ZU NACHSICHTIG. Sie verlangte einen Namen
"laenger als ein Zeichen"; der Rueckfalltext "Jemand" ist sechs
Zeichen lang und kam damit durch. Gruen, waehrend der Hauptfall
kaputt war. Die zweite Fassung verglich gegen eine abgeschriebene
Namensliste -- die nannte "Jonas, Luna, Mara, Pat", angelegt werden
aber "Filipe, Rieke, Kessi, Tili", und der Kommentar daneben
behauptete schon da, sie sei abgeleitet. Jetzt ist sie es wirklich:
Die Namen werden beim Anlegen eingesammelt, und geprueft wird, dass
jeder GENAU DIE BEIDEN ANDEREN sieht -- nicht "irgendeinen echten
Namen", denn der eigene Name im eigenen Kasten waere auch einer.

pruef-anruf: 127 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 22:25:45 +02:00
DogFatherGitandClaude Opus 5 9d086eccaf Chat: das Buehnenbild scheint durch, jeder Account bekommt seine Kachel
Hinter jeder Seite steht ohnehin eine Buehne (neun Szenen, fuer den
Chat die Lounge). Sie lag bisher hinter einer deckenden Flaeche --
vorhanden, geladen, unsichtbar. Sie durchscheinen zu lassen kostet
keine einzige Datei mehr, und auf der Adresse von Team Dogi kommt
damit von selbst deren eigene Fassung.

Das geht aber NUR, wenn der Text auf einer deckenden Kachel steht.
Sonst liegt Schrift auf einem Foto: an der dunklen Stelle lesbar, an
der hellen nicht, und beim Scrollen wechselt es. Filipes zweiter Satz
("die texte sollen immer in einer kachel sein") ist deshalb kein
Zusatzwunsch, sondern die Bedingung fuer den ersten.

Und jeder Account waehlt seinen Ton. Zwoelf Stueck, alle gleich
dunkel und gleich gesaettigt -- sie unterscheiden sich im Farbton und
in sonst nichts. Ein freier Farbwaehler klingt grosszuegiger und ist
die schlechtere Loesung: Mit ihm laesst sich Schwarz auf Schwarz
einstellen oder Neongelb, das allen anderen in die Augen sticht. Die
Kachel gehoert einem selbst, GESEHEN wird sie von allen anderen.
Gemessen: der schlechteste Kontrast liegt bei 13,9:1 (noetig 7).

Drei eigene Fehler beim Bauen, alle von der Pruefung gefunden:

1. Es gibt ZWEI Regeln fuer dieselbe Kachel (Grundform und
   Feinschliff). Ich hatte nur die erste umgestellt, die zweite gewann
   -- die eigene Kachel waere durchsichtig geblieben.
2. Die Pruefung las backgroundColor und pruefte den Alphawert. Eine
   Kachel mit einem VERLAUF hat dort rgba(0,0,0,0); sie meldete
   "durchsichtig" bei einer Kachel, die voellig deckt. Jetzt werden
   zwei Bildpunkte verglichen, einmal mit und einmal ohne Buehnenbild
   -- das misst die Sache selbst, nicht ihren Stellvertreter.
3. Dieselbe Pruefung suchte nur die rgba-Schreibweise. Chrome gibt
   das Ergebnis von color-mix als color(srgb r g b / a) zurueck; der
   Rueckfall war "Alpha 1", und sie meldete "deckt" bei einer
   Flaeche, die durchscheint. Genau das Gegenteil.

pruef-chatkachel.mjs: 27 Pruefungen, mit eingebauter Gegenprobe (auf
der freien Flaeche MUSS sich etwas aendern, sonst misst der Vergleich
nichts). pruef-chat-optik und pruef-erwaehnung unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:58:50 +02:00
DogFatherGitandClaude Opus 5 9c96612321 Am Handy lag Text auf Text -- im Satz ueber Vertraulichkeit
Auf der Befindens-Seite ueberlagerten sich bei 430 px zwei Absaetze
um 18 Pixel. Betroffen war ausgerechnet "Deine Antworten liest
niemand ausser dir" -- also der Satz, in dem das Vertrauen entsteht,
das die ganze Seite braucht.

Ursache war eine feste Zahl: -18px Abstand, gerechnet gegen die
26 px, die das Element darueber mitbringt. In einer Kopfzeile setzt
start.css dieses margin-bottom aber auf 0. Aus 26 minus 18 wurde
0 minus 18. Zwei fuer sich richtige Regeln, und dazwischen ein
Schaden, den keine von beiden verursacht.

Die Lehre ist nicht "-18 auf -8 aendern" -- das waere dieselbe Zahl
mit anderem Wert und beim naechsten Zusammentreffen wieder falsch.
Jetzt bestimmt der Absatz davor seinen Abstand selbst, und nur dann,
wenn der Zusatz wirklich folgt (:has). Acht Pixel, in jeder Umgebung.

Gefunden hat es ein Bildschirmfoto, nicht das Lesen: Beide Regeln
sehen einzeln vernuenftig aus. Die Messung steht jetzt fest in
pruef-befinden.mjs (113/0), mit Gegenprobe: Mit dem alten Wert wird
sie rot, ohne ihn gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:48:46 +02:00
DogFatherGitandClaude Opus 5 2719bd9b88 Wie geht es dir: achtzehn Fragen in sechs Feldern, eine Zusammenfassung
Sechs Fragen mehr (jetzt 18), und alle in sechs Feldern gegliedert:
Last & Erholung, Miteinander, Sinn & Anerkennung, Klarheit &
Rueckhalt, Grenzen & Sicherheit, Weiterkommen & Ausblick. Die Felder
sind nicht ausgedacht -- es sind die Gebiete, die die Forschung zu
belasteten Rollen durchgehend abfragt.

Die drei neuen Luecken, die sie schliessen: Schlaf (zeigt Erschoepfung
frueher als jede andere Frage), Widersprechen (der Kern dessen, was
psychologische Sicherheit heisst) und Mitreden (viel Anforderung bei
wenig Einfluss ist die Kombination, aus der Erschoepfung entsteht).
Jede neue Frage hat ihre belegte Einordnung -- eine Frage ohne
Grundlage ist eine Frage, die jemand gut fand.

DIE ROTATION MUSSTE NEU. Der Katalog ist nach Themen sortiert; wer
daraus drei aufeinanderfolgende nimmt, bekommt drei aus demselben
Feld. Jetzt wird der Ring vorher verzahnt -- erst je eine Frage aus
jedem Feld, dann je eine zweite. Ein Fenster trifft damit von selbst
verschiedene Felder.

Ein erster Anlauf reservierte feste Plaetze fuer die kernlosen
Felder. Begruendet mit einer Auswertung je Feld, die es gar nicht
gibt -- und er kostete: zwoelf Runden, bis jede Frage einmal gestellt
war, fast ein halbes Jahr. Gefunden hat das pruef-befinden.mjs, nicht
das Nachdenken. Mit dem verzahnten Ring und vier Plaetzen je Runde
sind es vier Runden.

DIE EINE ZUSAMMENFASSUNG AM ENDE, nicht eine je Kategorie. Sie sagt
in dieser Reihenfolge: die Lage in einem Satz, was traegt (benannt,
nicht als Zahl), hoechstens EINE Sache zum Hinschauen, ein Schluss,
der zur Lage passt. Umgekehrt waere es eine Maengelliste mit
Trostpflaster, und so etwas beantwortet man beim naechsten Mal nicht
mehr ehrlich.

ZUR FRAGE NACH DER BESTEN KOSTENLOSEN MOEGLICHKEIT: bewusst KEINE
KI. Das sind Gesundheitsdaten (wer nachts wach liegt, wer angefeindet
wird, wer ans Aufhoeren denkt) -- deshalb sind sie im ganzen Haus als
nurSelbst markiert. Kostenlose KI-Angebote bezahlt man mit den Daten.
Ein Sprachmodell erfindet ausserdem, und zwar ueberzeugend. Und ein
fremder Dienst faellt aus. Jeder Grund reicht einzeln. Die
Begruendung steht ausfuehrlich in workspace-befinden-resuemee.js.

Nebenbefund behoben: Die Zusammenfassung blieb direkt NACH einer
abgeschlossenen Runde leer -- da ist keine Antwort mehr "frisch".
Genau der Moment, in dem man sie sehen will.

Auch eine Pruefung korrigiert: Sie verbot den Text "entwicklung.js"
irgendwo in der Datei und schlug an einem Kommentar an, der die
Serverdatei benennt. Sie misst jetzt die Skript-Quellen.

pruef-befinden.mjs 112/0, pruef-resuemee.mjs 35/0 (neu).

Offener Befund, aelter als diese Aenderung: pruef-entwicklung.mjs
meldet "ein Modi: keine Kachel fuehrt mehr ersatzweise auf die
Entwicklungsseite" -- auch ohne diese Commits.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:45:14 +02:00
DogFatherGitandClaude Opus 5 1bdeccc054 Highlights: drei Accounts nebeneinander, nach Zeit geteilt
DogFather, HasiDog und DogFather Clips haben eigene Zuschauer und
einen eigenen Ton -- das steht so schon an KANAELE im Server. Eine
gemeinsame Galerie behauptete, sie waeren ein Topf; wer fuer Clips
schneidet, suchte in jeder Reihe nach den Kacheln, die ihn angehen.

Jetzt drei Spalten nebeneinander, jede zuklappbar, jede mit ihrem
Handle und ihrer Zahl. Eine vierte Spalte gibt es nur, wenn sie
gebraucht wird: Bilder ohne TikTok-Link gehoeren zu keinem Account,
und sie verschwinden zu lassen waere der schlimmere Fehler.

Die Reihenfolge kommt vom SERVER. Der Browser hatte dafuer eine
eigene kleine Liste (KANAL_WORT) -- dieselben drei Namen in anderer
Reihenfolge, ohne Handles. Beim vierten Account waere genau diese
Kopie die vergessene.

Dazu eine Zeitleiste: Aktuell (heute), Diese Woche, Dieser Monat,
Dieses Jahr, Alles. Kalenderzeitraeume, keine Rueckblicke -- wer am
Dienstag "diese Woche" fragt, meint Montag und Dienstag. Jeder
Knopf traegt seine Zahl; ohne sie klickt man ins Leere und weiss
nicht, ob es am Filter lag.

Und beim Anlegen laesst sich der Account waehlen -- fuer Bilder und
Momente ohne Link. Bei einem TikTok-Link leitet der Server ihn
weiterhin aus dem Handle ab; das ist genauer, weil niemand sich
vertippen kann.

Beim Bauen gemessen statt vermutet: Der Spaltenkasten lag IM
Galerie-Raster von #liste und bekam eine Zelle von 376 px --
Elternbreite 1160. Die drei standen untereinander. Die Galerie
gehoert jetzt in die Spalte, nicht um sie herum.

pruef-highlights.mjs: 26 Pruefungen, mit Gegenproben (Gast bekommt
die Liste nicht, erfundener Account wird abgelehnt, zweiter Klick
hebt den Filter auf). pruef-video.mjs weiterhin 67/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:28:22 +02:00
DogFatherGitandClaude Opus 5 d77dd216c5 Ein Termin von-bis belegt jeden Tag dazwischen
Zwei Fehler, nicht einer.

Der sichtbare: Die Kachel stand nur am Anfangstag. Wer im
Monatsraster auf den Mittwoch sah, sah nichts -- obwohl die Aktion
von Montag bis Freitag lief.

Der unsichtbare, und der ist der schlimmere: Der SERVER suchte
Eintraege, deren ANFANG im sichtbaren Fenster liegt. Eine Aktion vom
28.09. bis zum 05.10. kam im Oktober deshalb ueberhaupt nicht an --
nicht "nur am ersten Tag markiert", sondern gar nicht da. Wer im
Oktober plante, sah eine freie Woche, die belegt war. Jetzt
entscheidet die UEBERSCHNEIDUNG, nicht der Anfang.

Gebaut wurde es in nachTag() -- der einzigen Stelle, an der
Eintraege auf Tage verteilt werden. Monat, Woche, Liste und
Zeitstrahl holen sich alle dort; vier Ansichten einzeln
nachzuruesten waeren vier Stellen, an denen die fuenfte vergessen
wird.

Das Ende wird abgeleitet, nicht gepflegt: aus event_ende ODER aus
Uhrzeit plus Dauer. Ein Live von 22:00 ueber vier Stunden endet um
02:00 am naechsten Tag -- das stand bisher nirgends, obwohl die
Zahlen da waren.

Der Tagesdialog filterte selbst auf den Anfangstag. Im Raster war
der Mittwoch markiert, tippte man ihn an, stand da "An diesem Tag
steht nichts." Jetzt fragt er dieselbe Stelle wie das Raster.

pruef-zeitraum.mjs: 16 Pruefungen, beide Fehler einzeln, mit drei
Gegenproben (vor dem Anfang, nach dem Ende, Punkttermin).
pruef-terminregel.mjs weiterhin 35/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:20:18 +02:00
DogFatherGitandClaude Opus 5 947ea7ff49 Fertige Vorschlaege lassen sich wechseln
Bisher kamen ALLE auf einmal -- damit gab es nichts zu wechseln, die
Liste war entweder ganz da oder ganz weg. Bei 17 Vorschlaegen (Brett
"regeln") ist eine Wand aus Karten ausserdem das Gegenteil von
"uebernehmen, was passt".

Jetzt vier auf einmal, und ein Knopf holt die naechsten vier. Der
Server rechnet die Stelle mit Rest -- nach dem letzten kommt wieder
der erste. Es gibt also keinen Zustand "durchgeklickt, jetzt leer".

Bei hoechstens vier offenen Vorschlaegen erscheint der Knopf gar
nicht: Ein Knopf, der dieselben Karten noch einmal malt, ist ein
Knopf, der nichts tut.

Was es NICHT ist: Die Vorschlaege werden nicht erzeugt. Sie sind ein
geschriebener Vorrat von 113 Stueck auf 16 Brettern.

pruef-vorschlaege.mjs: 21 Pruefungen. Die entscheidende vergleicht
die Titel vorher und nachher -- ein Knopf, der nur gedrueckt werden
kann, besteht jede Pruefung, die nur nach dem Knopf sucht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:15:49 +02:00
DogFatherGitandClaude Opus 5 c4e26409b9 Die Seite laesst sich als App installieren
Das Manifest war lange vollstaendig -- die App LIESS sich
installieren. Nur bot das ausschliesslich der Browser an, versteckt
in seinem Dreipunktemenue. Wer es nicht sucht, findet es nie. Und
ohne installierte App gibt es auf dem Handy keine verlaesslichen
Benachrichtigungen; genau daran hing im September das Telefonieren.

Jetzt steht der Knopf in der Kopfleiste, auf allen Seiten, mit drei
Antworten statt einer:

  schon installiert -> gar kein Knopf
  Browser bietet an -> der Knopf fragt ihn
  Safari am iPhone  -> der Knopf erklaert den Weg

Der dritte Fall ist der gefaehrliche: Dort gibt es
beforeinstallprompt nicht und wird es nicht geben. Ein Knopf, der
am iPhone nichts tut, waere schlimmer als keiner -- man drueckt ihn
und sucht den Fehler bei sich.

pruef-installieren.mjs: 14 Pruefungen, alle drei Zustaende, mit
Gegenprobe in der installierten App.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:13:36 +02:00
DogFatherGitandClaude Opus 5 586eb51504 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]>
2026-09-20 19:07:06 +02:00
DogFatherGitandClaude Opus 5 c59517cb23 Ein Anruf faengt leise an
Filipe: "uebrigens soll man auswaehlen koennen ob man lautsprecher will
oder nicht bitte. es soll ohne lautsprecher anfangen das gespraech und
nur wenn man drauf klickt soll es laut werden ... es soll nicht
raushaengen oder so, das ist nicht cool."

DER GRUND IST DER STREAM. Ein Anruf, der beim Annehmen sofort aus den
Lautsprechern kommt, ist im schlimmsten Fall fuer alle Zuschauer zu
hoeren, bevor irgendjemand reagieren kann. Das laesst sich nicht
zurueckholen.

HIER STAND `hoeren = true` mit der Begruendung: "Wer den Ton abgestellt
hat, will ihn nicht beim naechsten Gespraech wieder an." Das war richtig
gedacht und ist jetzt umgedreht -- aus demselben Grund, nur in die
andere Richtung: Der Zustand soll NICHT ueberdauern. Eine Entscheidung
von vorhin darf nicht fuer ein Gespraech gelten, von dem man noch
nichts wusste. Zurueckgesetzt wird an BEIDEN Wegen, beim Anrufen und
beim Rangehen -- einer allein waere die Haelfte, und die andere Haelfte
faellt niemandem auf, bis es einmal zu laut war.

UND MAN SIEHT ES. Leise anfangen ohne Hinweis waere die naechste
Sackgasse: "ich hoere nichts" ohne Grund und ohne Weg. Ein Balken sagt
es, solange es gilt, und verschwindet in dem Moment, in dem man den Ton
anmacht. Er ist SELBST der Knopf -- wer liest "tippen, um den Ton
anzumachen", will genau das tun. Gedaempftes Bernstein statt Alarmrot:
Es ist kein Fehler, sondern ein Zustand.

DABEI EINEN EIGENEN FEHLER GEFANGEN: Der Balken fragte `!anruf` -- und
diese Variable wird erst gesetzt, NACHDEM der Kasten aufgeht. Beim
Aufbauen blieb er deshalb versteckt, und man sass in einem stummen
Gespraech ohne einen Satz dazu. Genau der Zustand, den er verhindern
soll. Jetzt haengt er am sichtbaren Kasten.

DIE PRUEFUNG WURDE ROT und hat damit ihre Arbeit getan -- sie hielt das
alte Verhalten fest. Umgedreht, nicht gestrichen: Die wichtigste Falle
(ueberlebt der Schalter das Neuzeichnen, wenn jemand auflegt?) bleibt,
nur der erwartete Zustand hat sich gedreht.

GEPRUEFT: pruef-anruf 117/0 (war 114) -- drei Aussagen mehr, darunter
dass der Hinweis da ist, 44 px hoch und im richtigen Moment
verschwindet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 19:01:28 +02:00
DogFatherGitandClaude Opus 5 01151574ae Die rechte Hand verteilt Aufgaben und wechselt Rollen
Filipe: "jeder soll sich selber aufgabe vergeben koennen aber nur die
rechte hand und dogfather aufgaben an andere verteilen." Und: "ich will
dass ich da auch die rollen der leute wechseln kann ohne dass ich denen
einen neuen account machen muss ... perfektionier das fuer die rolle
dogfather und rechte hand."

---- AUFGABEN VERTEILEN ---------------------------------------------

Die Regel gab es schon -- sie fragte `istLeitung`, und darin steht die
rechte Hand NICHT. Sie konnte also keine Aufgabe weitergeben.

`hand` DORT EINZUTRAGEN WAERE FAHRLAESSIG GEWESEN: `istLeitung` wird an
57 Stellen in 19 Dateien gefragt -- unter anderem im vertraulichen
Meldeweg, in der Personenverwaltung und in den Auswertungen ueber
Menschen. Das haette in einem Zug ueber Einsicht in fremde Meldungen
entschieden, und das hat niemand gewollt.

Stattdessen `darfAufgabenVerteilen` -- eine eigene Regel mit eigenem
Namen. Man sieht an der Aufrufstelle, worum es geht, und wer sie
spaeter aendert, aendert genau diese eine Sache.

Wer nicht verteilen darf, bekommt KEINE Absage: Die Aufgabe landet bei
ihm selbst. Das ist genau, was Filipe wollte ("jeder soll sich selber
aufgabe vergeben koennen") und freundlicher als ein Fehler.

---- ROLLEN WECHSELN ------------------------------------------------

Auch das gab es schon, samt dem wichtigen Satz in der Rueckfrage: "Der
Zugangscode bleibt derselbe." Es konnte nur DogFather (und Spicy
Media).

DREI GRENZEN, JEDE MIT GRUND:
  * Niemand wird zu "admin" -- unveraendert seit dem 11.09.2026.
  * Die rechte Hand ernennt keine zweite rechte Hand. Wer jemanden auf
    die eigene Ebene hebt, vergibt Vertrauen, das ihm nicht gehoert.
    Und wer eine Rolle UEBER sich aendern koennte, koennte sich selbst
    befoerdern, indem er zuerst den anderen herabstuft.
  * Niemand aendert die eigene Rolle -- sonst waere jede Grenze nur ein
    Umweg.

SPICY MEDIA BEHAELT, WAS SIE HATTE. Beim ersten Anlauf waere sie durch
die neue Regel ausgesperrt gewesen -- ein Rueckschritt, den ich selbst
verursacht haette. Sie steht jetzt ausdruecklich in der Tabelle.

---- UND DIE OBERFLAECHE RECHNET NICHT MEHR SELBST ------------------

Die Rollenwahl nahm die Knoepfe des ANLEGE-Formulars. Fuer die rechte
Hand ist das leer -- sie legt niemanden an. Die Wahl waere leer
geblieben, das Recht unbenutzbar.

Der Server schickt jetzt zwei Listen mit: wozu ich machen darf
(`rollen_zum_aendern`) und wessen Rolle ich anfassen darf
(`rollen_anfassbar`). Beide aus denselben Funktionen wie die Schranke.
Damit kann die Seite weder zu streng sein (ein Recht, das niemand
findet) noch zu grosszuegig (ein Knopf, der eine Absage bringt) -- der
Fehler vom 10.09.2026, als zwei Listen drei Zeilen auseinander
einander widersprachen.

Dabei fast hineingelaufen: `ROLLEN_REIHE` ist die SORTIERUNG, und
darin fehlt "gast" mit Absicht. Wer sie fuer eine Aufzaehlung nimmt,
verliert die Community still -- genau diese Verwechslung hat am
17.09.2026 schon einmal verhindert, dass sich jemand zu "Community"
machen liess.

---- AUSSERDEM ------------------------------------------------------

Screen 2: "Unsere Seiten" und "Regeln & Hilfe" haben die Plaetze
getauscht -- nur diese zwei.

GEPRUEFT: pruef-verteilen 11/0 (neu, inkl. der Abgrenzung "darf
verteilen, ist aber NICHT Leitung"), pruef-rollen-anlegen 11/0,
pruef-personen-formular 36/0, pruef-personen-liste 33/0,
pruef-personen-loeschen 40/0, pruef-rechtetafel 19/0, pruef-treff 72/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 18:56:03 +02:00
DogFatherGitandClaude Opus 5 e378514bb4 Einmal anmelden reicht -- und beim Zurueckgehen bleibt die Seite stehen
Filipe: "kannst du bitte machen dass die leute sich nur einmal anmelden
muessen und dan nur noch abgemeldet werden wenn sie sich selbst
abmelden. damit sie auch die benarichtigungen sofort kriegen ... und
auch sofort die anrufe annehmen koennen."

---- 1. DIE ANMELDUNG BLEIBT ----------------------------------------

VORHER: zwoelf Stunden, feste Frist ab dem Anmelden. Wer morgens um
acht anfing, flog abends um acht raus -- mitten im Betrieb. Und wer
abgemeldet ist, hat die Seite nicht offen; ein Anruf erreicht ihn dann
nur noch ueber die Benachrichtigung, und bis er sich wieder angemeldet
hat, ist das Klingeln vorbei. Genau das beschreibt Filipe.

JETZT: ein gleitendes Fenster von 180 Tagen, das sich bei jeder Nutzung
verlaengert. Wer die Seite benutzt, bleibt angemeldet -- ohne Ende.

NICHT UNENDLICH, und das ist Absicht: In diesem Haus liegen
vertrauliche Meldungen ueber Menschen. Ein Zugang, der nie ablaeuft,
ist auf einem verlorenen Handy fuer immer offen. Ein halbes Jahr ohne
Besuch schliesst das Geraet und ist niemandem zu viel zugemutet.

An EINER Stelle gebaut: `sitzungLesen` -- durch die gehen alle 26
Fachmodule. Ein Parameter mehr haette 26 Aufrufe geaendert und beim 27.
Modul vergessen werden koennen; `req.res` haengt ohnehin an der
Anfrage. Verlaengert wird erst, wenn weniger als die Haelfte des
Fensters uebrig ist -- sonst waere das ein Schreibzugriff bei jedem
Bild und jedem Herzschlag des Ereignisstroms.

Drei Texte, die noch "zwoelf Stunden" behaupteten, sagen es jetzt
richtig -- inklusive der Abmelde-Nachfrage, die jetzt dazusagt, dass
man angemeldet bleiben SOLLTE, um Anrufe zu bekommen.

---- 2. BEIM ZURUECKGEHEN BLEIBT DIE STELLE -------------------------

Filipe, zum dritten Mal und in Grossbuchstaben. Also erst gemessen:

    gescrollt auf:  900
    gemerkt:        900
    gelandet:      1054      <- 154 px daneben, zuverlaessig

Die Wiederherstellung LIEF also -- sie traf nur nicht. Ursache ist
Chromes Scroll-Verankerung: Waechst Inhalt OBERHALB der Stelle,
verschiebt der Browser den Bildlauf mit, damit das Sichtbare stehen
bleibt. Im Alltag genau richtig; beim Wiederherstellen das Gegenteil.

Sie wird jetzt fuer die Dauer des Wiederherstellens abgeschaltet und
danach wieder eingeschaltet -- nicht dauerhaft, sonst spraenge einem im
Chat der Text unter dem Finger weg. Dazu wird die Stelle nachgesetzt,
solange die Seite noch waechst, und aufgehoert, sobald sie 400 ms lang
ruhig ist. Ergebnis: 900 -> 900, und es bleibt dort.

DAZU, und das ist der groessere Teil: Der Ereignisstrom in kopf.js
laeuft auf 32 Seiten und wird jetzt beim Weggehen geschlossen. Eine
offene EventSource sperrt den Vor-/Zurueck-Speicher des Browsers aus --
deshalb wurde bisher JEDE Rueckkehr ein vollstaendiger Neuaufbau.
Filipe hat genau das beschrieben ("OHNE DASS DIE SEITE ... NEU LAEDT").

EHRLICH DAZU: Playwright schaltet diesen Speicher fuer Tests ab, und er
liess sich hier nicht einschalten. Ich kann also NICHT messen, dass er
jetzt greift -- die Aenderung ist trotzdem richtig (eine offene
Verbindung ist die dokumentierte Sperre, und ein Strom, der beim
Weggehen offen bleibt, ist ohnehin ein Zuhoerer, den niemand mehr
liest). Gemessen und abgesichert ist der Weg OHNE diesen Speicher --
also der schlechteste Fall.

---- 3. DABEI GEFUNDEN: pruef-schranke mass seit neun Tagen nichts --

Sie suchte `const GESCHUETZT = {` per Textmuster in workspace.js. Diese
Tabelle ist am 11.09.2026 nach rechte.js umgezogen -- seitdem fand das
Muster nichts, und die Pruefung meldete "0 geschuetzte Seiten", "alle 0
Seiten leiten um", "0 Schreibweisen ausprobiert". Drei rote Zeilen, die
nach einem Zaehlfehler aussahen und in Wahrheit hiessen: hier wird
nichts mehr geprueft.

Jetzt wird die Tabelle IMPORTIERT. Ein Textmuster auf fremden
Quelltext reisst beim naechsten Umzug still; ein import reisst laut.
Ergebnis: 33 geschuetzte Seiten, 363 Schreibweisen -- alles gruen.

GEPRUEFT: pruef-rollstelle 8/0 (neu, mit Spur ueber die Zeit und zwei
Gegenproben), pruef-schranke (war rot), pruef-code 17/0,
pruef-haerte 20/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 18:48:34 +02:00
DogFatherGitandClaude Opus 5 75019ec8c3 Am Handy stand nicht da, mit wem man schreibt
Gemessen in der Kopfzeile eines Gespraechs, Name "Team-Runde":

    360 px ->  0 px sichtbar (98 noetig)
    390 px -> 12 px
    412 px -> 33 px
   1280 px -> passt

Auf JEDEM Telefon stand also kein Name da -- man oeffnet ein Gespraech
und sieht nicht, mit wem. Und weil die Zeile nicht leer aussieht
(Zurueck-Pfeil, fuenf Knoepfe), wirkt sie nicht kaputt, sondern eng.

URSACHE: `flex: 1` heisst ausgeschrieben `1 1 0%` -- Grundbreite NULL.
Damit "passt" der Name rechnerisch immer, egal wie eng es ist, und es
bricht nie etwas um. Die Knopfreihe daneben hat `flex: none` und
schrumpft nie; seit die Knoepfe am Finger 44 px breit sind, bleibt bei
sechs Knoepfen nichts uebrig.

Zwei Stellen setzten dieselbe Eigenschaft, die spezifischere gewann --
die erste Reparatur wirkte deshalb nur bei 360 px und sonst nicht.
Beide nennen jetzt dieselbe Grundbreite.

KEINE NEUE SCHWELLE: `flex-wrap` bricht genau dann um, wenn der Platz
wirklich nicht reicht. Dieses Haus ist an festen Breiten schon zweimal
gescheitert (Kopfleiste, 06.09.2026); kommt morgen ein siebter Knopf
dazu, stimmt es weiter. Ergebnis: 244 / 268 / 289 px statt 0 / 12 / 33.

---- WARUM DER HANDY-RUNDGANG DAS NICHT GEFUNDEN HAT ----------------

Zwei eigene Entscheidungen, jede fuer sich vernuenftig, zusammen ein
Loch:

  1. `sichtbar()` verlangt `width > 0`. Ein auf null gequetschtes
     Element ist unsichtbar -- und "unsichtbar" hiess "nichts zu
     pruefen". Genau falsch herum: Nichts zu sehen IST der Befund.
  2. `text-overflow: ellipsis` gilt als Absicht. Das stimmt auch --
     ein langer Name soll gekuerzt werden. Es stimmt nur nicht mehr,
     wenn nichts uebrig bleibt.

Die neue Regel ist bewusst schmal: gemeldet wird nur, was unter 40 px
sichtbar ist und mindestens das Doppelte braeuchte. "Jede Kuerzung
melden" waeren die ~350 Fehlalarme, die diese Pruefung schon einmal
zugedeckt haben.

NACHGEMESSEN: 206 Seitenaufrufe, 91 638 Elemente. Die Regel schlaegt
an genau EINER Stelle an (kalender.html, sechsmal) und sonst nirgends
-- 64 -> 70 Befunde. Die Pruefung ist genauer geworden, nicht die App
schlechter.

DER KALENDER-FUND BLEIBT OFFEN: Im Monatsraster ist ein Tag am Handy
36 px breit, ein Eintrag braucht 186 bis 317. Das ist kein Versehen im
Code, sondern die Frage, ob die Monatsansicht am Telefon ueberhaupt
die richtige Vorgabe ist -- eine Entscheidung, keine Reparatur.

GEPRUEFT: pruef-chat-optik 39/0 (drei neu, mit einer Gegenprobe, die
den gemessenen Fall HERSTELLT -- fuenf Knoepfe wie in einer Gruppe;
der erste Anlauf blieb gruen, weil in einem Zweiergespraech nur drei
stehen und der Platz auch ohne Reparatur reicht: 12 px mit der alten
Angabe, 268 mit der neuen, im selben Aufbau).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 18:14:08 +02:00
DogFatherGitandClaude Opus 5 2a26a49f91 Mit "@" jemanden im Chat ansprechen
Filipe: "ich will das man die leute mit @ markieren kann im chat."

MARKIEREN IST KEINE FARBE, SONDERN EINE ANSPRACHE. Sie funktioniert
nur, wenn drei Dinge zusammen stimmen: Der Richtige ist gemeint, er
MERKT es, und man sieht es im Satz. Fehlt eines davon, ist es eine
Attrappe -- und zwar eine, die gut aussieht.

WER GEMEINT IST, ENTSCHEIDET DER SERVER. Der Browser schickt nur Text.
Damit wirkt ein von Hand getipptes "@VanVan" genauso wie eines aus der
Auswahlliste, und niemand kann jemanden ansprechen, der gar nicht im
Raum sitzt -- auch nicht ueber die Schnittstelle.

Die Regeln stehen in server/chat-erwaehnung.js, jede mit Begruendung.
Zwei davon sind keine Feinheit, sondern der Unterschied zwischen
brauchbar und laestig:

  * Das Zeichen VOR dem "@" darf kein Buchstabe sein. Sonst piepst
    jede E-Mail-Adresse im Chat jemanden an
    ("[email protected]").
  * Das Zeichen DANACH auch nicht, und der laengste Name gewinnt.
    Sonst spricht "@Tilikum" Tili an.

MAN MERKT ES AUCH OHNE OFFENEN RAUM. Eine Zahl in der Gespraechsliste
sagt "hier ist etwas" -- nicht, ob es an dich war. Wer morgens vier
Raeume mit Zahlen sieht, macht den lautesten zuerst auf, und dort
steht selten das, was auf ihn wartet. Jetzt steht ein "@" daneben.

UND DIE MELDUNG AUFS HANDY SAGT ES: "VanVan hat dich erwaehnt" statt
"Nachricht von VanVan". Als EIGENE Art, die sich getrennt abschalten
laesst -- wer den lauten Chat stumm stellt, will trotzdem wissen, wenn
ihn jemand direkt anspricht. Ohne Ausnahme von der Ruhezeit: Ein Anruf
wartet auf eine Antwort, ein "@Anna" nicht.

DIE AUSWAHL BEIM TIPPEN loest drei Dinge, die man sonst selbst wissen
muesste: wie die Person genau heisst, wer ueberhaupt im Raum ist, und
ob man sich vertippt hat. Tastatur zuerst (Pfeile, Enter, Tab, Escape).
Sie erzwingt nichts -- wer weitertippt, schreibt einfach weiter.

ZWEI RECHNUNGEN, EINE ANTWORT: Der Browser braucht dieselbe Aufloesung,
um sofort hervorzuheben. Genau dort laufen Dinge auseinander, und dann
haette die Seite jemanden hervorgehoben, den niemand benachrichtigt
hat. pruef-erwaehnung LIEST die Browserfassung aus der Datei und fuehrt
sie aus -- ein Nachbau wuerde pruefen, ob ich zweimal dasselbe
schreiben kann.

---- DABEI GEFUNDEN: "gelesen bis 999999" ----------------------------

Der Server nahm fuer den Lesestand JEDE ganze Zahl an. Wer einmal eine
Zahl hinter allem Vorhandenen schickte, sah in diesem Gespraech nie
wieder einen Zaehler und nie wieder ein @-Zeichen: Alles Kuenftige galt
als gelesen, bevor es geschrieben war. Das faellt niemandem als
Zusammenhang auf -- man merkt nur, dass "die Benachrichtigungen nicht
gehen".

Der Browser schickt heute immer die letzte gesehene Nummer, ist also
nicht der Grund. Aber eine Grenze, die nur davon lebt, dass der
Aufrufer sich benimmt, ist keine. Jetzt wird auf die juengste
Nachricht des Raums begrenzt -- abgeleitet, nicht geraten.

Gefunden hat es meine eigene Pruefung: Sie setzte zum Aufraeumen 99999
und wunderte sich danach, warum das frische "@" nicht leuchtete.

WOHER MAN ERFAEHRT, DASS ES DAS GIBT: Im Chat gibt es keinen
Hilfeknopf. Der Hinweis steht deshalb im Leersatz einer neuen Gruppe --
dort, wo man beim ersten Oeffnen ohnehin hinsieht, und nur ab drei
Leuten. In einem Zweiergespraech waere er Ballast.

GEPRUEFT: pruef-erwaehnung 67/0 (neu) -- 13 Regelfaelle ohne Server,
der Weg durch die Schnittstelle, das Zeichen in der Liste samt
Gegenprobe bei jemandem, der dabei aber nicht gemeint war, beide
Aufloesungen nebeneinander, und der ganze Ablauf am echten Bildschirm
bis "Enter waehlt und schickt NICHT ab".
Dazu pruef-chat 48/0, pruef-chat-optik 36/0, pruef-treffchat 110/0,
pruef-chat-kanaele 79/0, pruef-glocke 31/0, pruef-push 24/0,
pruef-anruf-klingelt, pruef-css-klassen, pruef-meldungen,
pruef-nachfrage, pruef-tippziele.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 17:54:16 +02:00
DogFatherGitandClaude Opus 5 409ed551f3 "Review" heisst jetzt "Zur Freigabe" -- und Datumsfelder sind so hoch wie alle anderen
Im Code stand die Begruendung selbst: "«Review» allein sagt einem Neuen
nichts." Das Wort ist englisch, ein Hauptwort ohne Handlung, und es
verraet nicht, WER jetzt dran ist. "Zur Freigabe" sagt beides: fertig
von mir, wartet auf jemanden.

Geaendert wurde nur, was ein Mensch LIEST -- der Zustandsschluessel
bleibt `review`, der gehoert der Datenbank. Betroffen: Spalte und
Weiterknopf im Aufgabenbrett, Dateien-Filter, Startseiten-Zaehler,
Kachel-Unterzeile, Hinweis "Datei wartet auf Freigabe", Report.

NICHT geaendert: der Kalender. Dort ist `review` eine TERMINART (ein
Gespraech, in dem man zurueckschaut), kein Zustand. Ich hatte das beim
Umbenennen selbst verwechselt und wieder zurueckgenommen -- ein
Kommentar an der Stelle haelt die zwei Bedeutungen jetzt auseinander.

pruef-sprung hing an der Wortwahl (`/review/i` auf der Beschriftung)
und wurde rot, obwohl der Filter richtig stand. Sie prueft jetzt
`data-status` -- den Schluessel, der sich nicht mit der Sprache aendert.

DAZU, unabhaengig gefunden: Datumsfelder waren 48 px hoch, alle anderen
Felder 44. Gemessen auf drei Seiten bei 390 px. Alle liegen auf dem
44-px-Beruehrziel -- nur das Datumsfeld drueckte sich darueber, weil
Chromium in `::-webkit-datetime-edit` eine eigene Innenpolsterung setzt,
die sogar ein gesetztes `height: 44px` ueberstimmt.

Zwei Anteile, einzeln nachgemessen (jeder allein 48->46, erst beide
zusammen 48->44): 1 px Polsterung oben und unten im Feldkasten, und
eine Zeilenhoehe von 24 statt 22. Keine feste Hoehe gesetzt -- die
Zeilenhoehe wird aus Beruehrziel und Polsterung gerechnet, damit sie
mitwandert, wenn sich eines davon aendert.

Geprueft: pruef-formulare 19/0 (war 16 mit 3 Fehlern), pruef-sprung
43/0, pruef-start-ansicht 151/0, pruef-aufgabenbrett 49/0,
pruef-uebersicht 35/0, pruef-uebersicht-browser 20/0,
pruef-deutsche-texte, pruef-css-klassen.

Ausserdem: vorlagen.js geloescht (8,2 KB). `vorlagenBlock(` wurde in
ca104799 eingebaut und in 9267797d wieder ausgebaut -- seither laedt
die Datei auf zwei Seiten, ohne dass jemand sie aufruft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-20 17:27:09 +02:00
DogFatherGit 0f5faf7ee6 Eine Seite, die nicht laedt, sagt es -- und bietet einen Weg zurueck
Fuenf Suchlaeufe parallel, ihre Funde selbst nachgemessen und behoben.

DER GROESSTE: 13 VON 21 SEITEN SCHLUCKTEN JEDEN NETZFEHLER.
Jede Seite beginnt mit `try { await hole('/api/ich') } catch { return; }`.
Faellt das Netz aus -- Aufzug, U-Bahn, Funkloch --, bricht der Block ab,
und die Seite bleibt fuer immer auf "wird geladen …" stehen. Gemessen:
0 von 32 Stellen setzten `aria-busy` im Fehlerfall zurueck, und es gab
KEINEN EINZIGEN "Nochmal versuchen" auf allen 21 Seiten.

Im Code stand der richtige Satz dazu -- an genau einer Stelle:
"Ein Platzhalter, der nie ersetzt wird, ist eine Luege mit
Fortschrittsanzeige." Er galt ueberall ausser dort.

Neu: window.ladefehler() in meldung.js. Sie ersetzt alles, was gerade
"laedt", durch drei Dinge: was los ist, was das bedeutet, und einen
Knopf, der es noch einmal versucht -- ohne die Seite neu zu laden.
21 Dateien angeschlossen. Neu: server/pruef-ladefehler.mjs, 26/0, mit
abgeklemmtem Netz im echten Browser.

UND DIE STARTSEITE WARF BEI EINEM FUNKLOCH AUF DIE ANMELDUNG.
`catch { location.assign('/workspace/') }` -- der Mensch glaubt, er sei
rausgeworfen, und tippt seinen Code neu. Dabei haelt seine Sitzung 12
Stunden; nur die Anfrage kam nicht durch. Umgeleitet wird jetzt nur
noch bei einer ANTWORT, die das sagt (401).

DER ANMELDEHINWEIS FUEHRTE MODIS IN DIE SPERRE.
Nach zwei Fehlversuchen stand: "Stimmt die Auswahl oben? Ein Code
gehoert immer zu genau einer davon." Auf der Crew-Wand ist das FALSCH
-- `stillerZugang()` sucht ueber die Codekennung, die angetippte
Kachel spielt fuer hand/modi keine Rolle. Sie probieren alle vier
durch, sammeln vier Fehlversuche, und nach acht in zehn Minuten ist
ihre Adresse gesperrt. Ein Hinweis, der die Sperre herbeifuehrt, gegen
die er helfen soll. Auf der Agenturwand stimmt der Satz weiter --
deshalb wird gefragt, auf welcher Wand man steht.
Dazu: Die Crew-Wand nannte nur der Community einen Weg ("Frag im Live
nach"). Wer zum Team gehoert und dessen Code nicht geht, fand dort
niemanden.

SACKGASSE AUF DER KERNSEITE EINES MODI.
treff-moderation sagte: "Zugaenge legst du in 'Personen & Zugaenge'
an" -- eine Seite, die ein Modi nicht oeffnen darf. Am ersten Tag, bei
leerer Community, war das der einzige Satz im Abschnitt. Jetzt fragt
die Seite ueber `window.__ich.seiten`, ob es den Weg fuer DIESEN
Menschen gibt. Und ein 404 wirft ihn nicht mehr wortlos auf die
Startseite.

TOTE KNOEPFE AN FREMDEN KARTEN.
"◀ zurueck" und "▶ In Arbeit" standen an JEDER Aufgabenkarte, auch an
fremden. Ein Modi sieht das Brett des ganzen Teams; er tippt, der
Server lehnt mit 403 ab, und die Meldung erscheint GANZ OBEN. Bei
einer Karte weiter unten sieht er nichts. Zwei Zeilen tiefer stand die
Regel im Klartext: "niemandem etwas anzubieten, das dann abgelehnt
wird." Der Server schickt jetzt `darf_aendern` mit.

13 STELLEN ROLLTEN GEGEN DEN WILLEN DES NUTZERS.
`scrollIntoView({ behavior: 'smooth' })` beachtet "Animationen
reduzieren" NICHT. Wer das eingestellt hat, hat es meist wegen
Schwindel getan. Zwei Stellen fragten vorher, dreizehn nicht.
Jetzt `window.sanft()`, einmal statt dreizehnmal.

DAS WORT UEBER DEN BRETTERN EINES MODI HIESS "BETREUUNG".
Fest im HTML, ueberschrieben nur bei Brettern mit eigenem `ober` --
sechs haben keines. Jetzt faellt es auf die GRUPPE der Kachel zurueck,
ueber die er hergekommen ist. Je Rolle richtig, ohne zweite Liste.

DER HINWEIS-ZU-KACHEL-WEG WAR DOPPELT KAPUTT.
`bereichZu` suchte nur in GRUPPEN -- der Liste der AGENTUR. Die
Kacheln von Team Dogi schickt der Server; fuer einen Modi fand die
Zeile entweder nichts oder eine fremde Kachel und uebernahm deren
Farbe. Und sie suchte ueber den NAMEN: "LIVE-Analyse" heisst auf der
Crew-Adresse "Live-Ablauf". Beim Beheben erst den Namen umgedreht --
und damit die Agenturseite kaputt gemacht (pruef-start-ansicht sofort
rot). Jetzt ueber das ZIEL, das in beiden Haeusern dasselbe ist.

UND EIN BRETT WAR SEIT GESTERN GESPERRT.
`TREFF_BRETTER` wird aus Kachelzielen abgeleitet. Als die Kachel
"Regeln & Hilfe" am 19.09. auf `treff-regeln.html` umgelenkt wurde,
fiel `regeln` heraus -- und `treff-regeln.html` verweist weiterhin
darauf ("Haeufige Fragen stehen auf dem Brett Regeln & Hilfe").
Gefunden hat es pruef-treff, die seit gestern rot war. 72/0.

NEBENBEI 7 SEITEN LEICHTER: meldung.js wird jetzt abgeleitet
eingebunden -- nur dort, wo sagWas/ladefehler/sanft wirklich
gebraucht werden. Die Anmeldewand traegt es nicht mehr.

Gruen: pruef-ladefehler 26/0, pruef-sackgassen 11/0 (582 Wege, 0 ins
Leere), pruef-start-ansicht, pruef-treff 72/0, pruef-treffchat,
pruef-community-sicht 10/0, pruef-aufgabenbrett, pruef-code 17/0,
pruef-chat-optik, pruef-nachfrage 49/0, pruef-meldungen 8/0,
pruef-css-klassen, pruef-tippziele 11/0, pruef-leerzustand 13/0,
pruef-rechtetafel.
2026-09-20 15:49:57 +02:00
DogFatherGit cc39552b4f Eine Eingabe geht nicht mehr wortlos verloren
Filipe: "Was passiert, wenn jemand eine Funktion abbricht?"

GEMESSEN: Acht Dialoge im Workspace enthalten Eingabefelder --
"Aufgabe bearbeiten" (10 Felder), der Tageseintrag in der Leistung
(8), Ziele, Netzwerk, Import, ein neuer Chat-Raum, ein Creator. Bei
allen galt: Esc, Klick daneben oder "Abbrechen" wirft ALLES weg,
wortlos. Wer zehn Felder ausgefuellt hat und mit dem Daumen den Rand
trifft, faengt von vorn an.

Neu: window.verwurfWache() in nachfrage.js.

BEIDE SCHLIESSWEGE, denn sie laufen verschieden:
  Esc / Klick daneben  loest `cancel` aus, close() wird NICHT gerufen
  "Abbrechen"-Knopf    ruft close(), loest kein `cancel` aus
Wer nur einen abfaengt, hat eine halbe Sicherung -- und die ist
schlimmer als keine, weil man ihr vertraut.

NICHT VON HAND VERTEILT: Jeder Dialog mit Feldern bekommt sie
automatisch (ausser dem Nachfrage-Dialog selbst -- er wuerde beim
Schliessen nach sich selbst fragen, in sich selbst, und haenge fuer
immer). Wer morgen einen neunten baut, hat sie, ohne daran zu denken.

UND SIE FRAGT NUR BEI WIRKLICHER AENDERUNG. Beim Oeffnen wird ein
Abbild der Felder genommen, beim Schliessen verglichen. Wer einen
Dialog aufmacht und gleich wieder zu, merkt nichts.

ZWEI SACHEN BEIM BAUEN GEMESSEN STATT VERMUTET:

  MEINE EIGENE "ROBUSTHEIT" HAT DIE WACHE STILL AUSGESCHALTET.
  Gegen den Fall "Felder werden erst nach dem Oeffnen gefuellt" hatte
  ich einen zweiten Schnappschuss beim Hineinklicken (`focusin`)
  eingebaut. Gemessen: Der entstand NACH dem Tippen -- Fokus und
  Werteingabe passieren im selben Atemzug. `beimOeffnen` war danach
  gleich dem getippten Text, und der Dialog ging wortlos zu. Die
  Sicherung sah eingebaut aus und tat nichts.
  Jetzt wird im naechsten BILD nachgetragen: Was das Skript beim
  Oeffnen nachtraegt, ist drin; getippt haben kann in derselben
  Sechzehntelsekunde niemand.
  (Nachgemessen: Alle acht Dialoge fuellen heute VOR showModal.)

  ZWEIMAL ESC HINTEREINANDER SCHLIESST TROTZDEM. Das ist Chromiums
  "close watcher": Eine Seite darf den Nutzer nicht mit Esc
  einsperren. Die Regel ist richtig; dagegen anzubauen waere falsch.
  Sie steht deshalb im Code und in der Pruefung -- festgehalten,
  nicht umgangen. Der Knopf unterliegt ihr nicht, und am Handy gibt
  es ohnehin kein Esc.

Elf Speicherwege rufen `vergessen()`, damit nach erfolgreichem
Speichern nicht gefragt wird. Eine Warnung nach dem Speichern waere
genau die, die man wegklickt -- und danach auch die echte.

pruef-nachfrage 49/0 (war 33), davon zehn am Bildschirm:
  unberuehrt geht er ohne Nachfrage zu
  nach einer Aenderung fragt Esc nach, der Dialog bleibt offen
  "Weiter bearbeiten" laesst ihn offen UND der Text steht noch da
  auch der Abbrechen-Knopf fragt -- jedes Mal
  "Verwerfen" schliesst wirklich, und der Text steht nirgends

pruef-aufgabenbrett, -leistung, -uebersicht-browser, -chat-optik,
-css-klassen gruen, pruef-tippziele 11/0.
2026-09-20 15:11:25 +02:00
DogFatherGit 285038f400 Der vertrauliche Meldeweg vergisst jetzt -- und sagt, bis wann
Zwei Entscheidungen, die offenstanden. Beide getroffen, nachdem
gemessen war, was wirklich da ist.

1. WIE LANGE BLEIBEN ABGESCHLOSSENE FAELLE?  90 Tage.

Die Entscheidung war bereits getroffen: `AUFBEWAHRUNG_TAGE = 90` steht
seit dem 19.09. in hilfe-tabellen.js, mit Begruendung ("ein Fall kommt
manchmal wieder auf"). Nur hat sie NIEMAND durchgesetzt --
`hilfeAufraeumen()` gab es, und der einzige Aufrufer war ihre eigene
Pruefung. Der Kommentar darueber behauptete "Wird beim Start
aufgerufen (siehe index.js)"; das war nie wahr.

Jetzt steht die Regel in workspace-aufbewahrung.js, dem Loeschkonzept,
das sich selbst durchsetzt -- beim Start und danach taeglich. Die
zweite Fassung in workspace-hilfe.js ist WEG, nicht doppelt: Zwei
DELETEs auf dieselben Daten waeren morgen verschieden, und der
Unterschied fiele erst auf, wenn er zaehlt.

GEMESSEN VOR DEM EINSCHALTEN:
  In der echten Datenbank steht heute KEIN einziger Fall. Der erste
    Lauf loescht nichts, und der erste Fall kann fruehestens in drei
    Monaten 90 Tage alt werden. Jetzt einschalten ist frei -- spaeter
    waere es der riskante Moment gewesen.
  PRAGMA foreign_keys steht im Dienst auf 1, und hilfe_nachrichten
    traegt ON DELETE CASCADE. An einem echten Fall mit Nachricht
    nachgemessen: vorher 1/1, nachher 0/0. Ohne diese Messung waere
    der Fall verschwunden und der eigentliche Text liegengeblieben.

2. SOLL EIN GESCHLOSSENER FALL WIEDER ZU OEFFNEN SEIN?  Nein.

Im Kopf von workspace-hilfe.js steht: "EIN GESCHLOSSENER FALL IST
GESCHLOSSEN. Auch fuer die Leitung -- sonst ist 'zugemacht' eine
Meinung und keine Tatsache." Das ist eine gute Regel, und sie bleibt.

Nachgemessen, dass sie auch traegt: Ein Melder kann seinen
geschlossenen Fall weiter LESEN, und ein geschlossener Fall zaehlt
nicht gegen das Limit von drei offenen. Wer eine Wiederholung melden
will, kann das also jederzeit -- die Bauweise ist stimmig.

NUR WUSSTE DAS NIEMAND. Dort stand ein Satz: "Dieser Fall ist
abgeschlossen (Datum)." Jetzt stehen drei -- und sie beantworten die
drei Fragen, die man in dem Moment hat:
  Kann ich noch schreiben?   Nein, und er laesst sich nicht oeffnen.
  Bleibt das hier stehen?    Bis zum TT.MM.JJJJ, dann geloescht.
  Und wenn es wieder passiert? Neu melden, der alte zaehlt nicht mit.

Das Datum kommt vom Server (`lesbar_bis`), die Frist ebenso -- sie
steht nur an EINER Stelle. Und sie steht jetzt auch im Dialog BEIM
Schliessen: Wer eine Uhr startet, soll das vorher wissen, nicht
danach.

OHNE UHRZEIT, und das ist kein Schoenheitsgrund: Ein Fall, der am
20.09. um 14:04 (Sommerzeit) geschlossen wird, verfaellt 90 Tage
spaeter um 13:04 -- die Uhr wird dazwischen zurueckgestellt. Richtig
gerechnet, sieht aus wie ein Fehler. Wer eine Stunde sucht, die es
nicht gibt, hat Zeit verloren.

UND DIE URSACHE, DAMIT ES NICHT WIEDER PASSIERT:
hilfe_faelle kam am 19.09. dazu, das Loeschkonzept ist vom 15.09., und
nichts hat die beiden je verglichen. Neue Pruefung in
pruef-aufbewahrung: Jede Tabelle mit einer Spalte, die "hier ist etwas
zu Ende" sagt, MUSS im Konzept stehen.
  Kein "jede Tabelle muss drinstehen": 46 Tabellen, 41 mit
  Personenbezug -- das gaebe 38 Meldungen, von denen fast alle falsch
  waeren (sie sind ueber personen_geloescht gedeckt). Eine Pruefung,
  die 38-mal meldet, wo einmal richtig waere, wird abgeschaltet.
  Gesucht wird das schmale Merkmal: GENAU ZWEI Tabellen im Haus tragen
  so eine Spalte. Beide jetzt im Konzept -- hilfe_faelle mit Frist,
  aufgaben ausdruecklich OHNE (erledigte Aufgaben sind
  Arbeitsdokumentation, keine Meldung ueber einen Menschen).

pruef-hilfe 84/0 (war 59) -- darunter zehn neue am Bildschirm:
"drei Saetze statt einem", "sie stehen untereinander, nicht
nebeneinander" (ein <p> in einem <p> waere ungueltig, der Container
ist jetzt ein <div>), "und WANN, mit Datum".
pruef-aufbewahrung 45/0 (war 41), mit Gegenprobe.
2026-09-20 14:10:38 +02:00
DogFatherGit 9e9ed67c4a Keine Sackgassen -- fuer JEDE Rolle, nicht nur fuer den Gast
Filipe: "Es darf keine Sackgassen geben."

pruef-community-sicht prueft genau das -- aber nur fuer den GAST.
Ein Modi hat 25 Kacheln, eine rechte Hand 30, DogFather 39. Keine
dieser drei Rollen war je darauf geprueft worden, ob ihre Seiten auf
etwas verweisen, das sie nicht oeffnen darf.

Und genau dort ist es zweimal passiert: Am 19.09. warf "Klingelt
nichts?" ALLE DREI Team-Rollen auf die Startseite zurueck, und der
Kalender-Verweis fuehrte die Community seit jeher ins Leere. Beides
hat jemand zufaellig gefunden, nicht eine Pruefung.

Neu: server/pruef-sackgassen.mjs -- 11/0.
  4 Rollen, 126 Seitenansichten, 582 sichtbare Wege, 0 ins Leere.

DREIMAL ABGELEITET STATT AUFGEZAEHLT:
  Die ROLLEN kommen aus der Anmeldewand (data-rolle), nicht aus einer
    Liste. Kaeme eine fuenfte dazu, stuende sie sonst nicht drin und
    niemand wuerde es merken.
  Die SEITEN kommen aus der Rechtetafel -- derselben, nach der der
    Server entscheidet. Keine zweite Liste, die auseinanderlaufen kann.
  Die BRETTER hinter bereich.html kommen aus den Kacheln dieser Rolle.

Die Altersbestaetigung des Gastes wird an der ANTWORT erkannt
(400 + alter_offen), nicht an der Rolle: Eine Liste "wer bestaetigen
muss" waere morgen falsch, wenn die Schranke noch woanders gilt.

Und sie braucht weder HTTPS-Front noch umgebogenen Namensdienst: Das
Haus einer Person kommt aus ihrer ROLLE, nicht aus der Adresse. Ein
Modi ist auch auf 127.0.0.1 im Crew-Haus.

GEGENPROBE: Ein erfundener Weg auf eine gesperrte Seite wird gefunden.
Ohne sie waere "0 ins Leere" auch dann wahr, wenn nichts geladen haette
-- deshalb steht die Zahl der Wege zusaetzlich in der Bedingung.
2026-09-20 12:52:51 +02:00
DogFatherGit 0a2363374c Eine Nachricht, die nicht ankommt, sieht man jetzt -- und schickt sie neu
DER KOMMENTAR STAND DA, DIE SACHE NICHT. Im Chat stand woertlich:
"NICHT STILL VERSCHWINDEN LASSEN. Wer etwas schreibt und es sieht,
glaubt, es sei angekommen." Gemessen: `markiereAlsGescheitert` setzte
`n.gescheitert = true` -- und gelesen hat das Merkmal NIEMAND, weder
das Skript noch das CSS. Eine gescheiterte Nachricht sah exakt aus wie
eine zugestellte. Im CSS stand an der Stelle eine leere Regel mit dem
Kommentar "Platzhalter, damit :has unterstuetzt bleibt".

Ein Kommentar, der eine Absicht beschreibt, erfuellt sie nicht.

Jetzt: sichtbare Kante an der Blase, blasse Darstellung solange sie
unterwegs ist, und ein Knopf "Nochmal senden" daneben. Der Satz in der
Meldezeile bat vorher ums Kopieren -- fuenf Handgriffe fuer etwas, das
die Seite in einem tun kann; den Text hat sie ja noch.

KEIN ZWEITER SENDEWEG: Der Knopf legt den Text zurueck ins Feld,
stellt das Antwortziel wieder her und ruft `abschicken`. Ein eigener
Weg waere morgen anders als dieser, und der Unterschied fiele erst
auf, wenn er zaehlt.

"ZUM NEUESTEN" STAND AUF EINER RECHNUNG VON GESTERN: `bottom: 96px` --
die Hoehe der Schreibleiste an dem Tag, an dem der Knopf gebaut wurde.
Das Textfeld waechst aber bis 160. Wer lange tippt und gleichzeitig
oben liest, hatte den Knopf HINTER der Leiste. Und darueber koennen
noch das Nachtruhe-Band und der Hochlade-Balken stehen.
Jetzt misst die Seite den ganzen Unterbau selbst -- ueber einen
Beobachter statt einer Liste von Ausloesern, denn das Band erscheint
um Mitternacht von selbst. Kommt morgen ein viertes Bauteil dazu,
rechnet es von allein mit.

NEUE PRUEFUNG FUER EINEN WEG, DEN NIE ETWAS GEPRUEFT HAT:
pruef-chat-optik faengt die Sendeanfrage jetzt einmal ab und geht den
ganzen Fehlerweg durch -- 10 Aussagen, darunter:
  der Unterschied ist auch zu SEHEN, nicht nur im Merkmal (Rand 1px)
  die Nachricht steht danach GENAU EINMAL da, nicht doppelt
  und sie ist beim Gegenueber angekommen
Der letzte ist der eigentliche: Alles davor koennte gut aussehen und
trotzdem nichts zugestellt haben.

pruef-treffchat war seit gestern rot -- 8 Fehler ueber "undefined".
Sie suchte die Kachel mit `ziel === "chat.html"`, seit dem 19.09.
heisst es `chat.html?raum=treff` (sie fuehrt direkt in den Raum). Kein
Befund ueber das Haus, sondern einer ueber sich selbst. Sie sucht
jetzt nach der SEITE und prueft statt des Wortlauts das, worauf es
ankommt: Man erkennt den Chat, und der Name kommt genau einmal vor.
110/0 statt 108 mit 8 Fehlern.

pruef-chat, -anhaenge, -kanaele, -optik, -ausbau gruen,
pruef-start-ansicht 151/0, pruef-tippziele 11/0, pruef-nachfrage 33/0,
pruef-leerzustand 13/0, pruef-meldungen 8/0, pruef-css-klassen gruen.
2026-09-20 12:44:31 +02:00
DogFatherGit 18148675a9 Die gepflegte Liste der Tippziele wird jetzt bewacht
In module.css steht ein Block, der ein Dutzend Klassen auf 44 Pixel
hebt. Diese Liste wurde von Hand gepflegt -- genau die Falle, vor der
die Hausregeln warnen: Wer einen Knopf mit `width: 34px` baut, traegt
ihn dort nicht nach und merkt es nicht.

GEMESSEN: FUENF Bedienelemente standen nicht drin.
  .nachricht__weg       24 breit   (das x an einer Nachricht)
  .antwort-leiste__weg  28 breit
  .chat__weg            34 breit   <- der unangenehmste
  .todo__weg            36 breit
  .sicht__weg           28 breit

`.chat__weg` ist der Knopf, der ein Gespraech wegraeumt -- und direkt
daneben sitzt der, der es FUER ALLE aufloest. Zwei 34-Pixel-Ziele
nebeneinander, eines davon unwiderruflich.

Neu: server/pruef-tippziele.mjs -- 11/0, ohne Browser, unter einer
Sekunde. Sie leitet die Bedienelemente aus dem CSS ab und verlangt
fuer jedes eine Abdeckung. Die Liste bleibt (CSS kann nicht rechnen),
aber sie kann nicht mehr still veralten.

DER ERSTE ANLAUF WAR ZU GROB und meldete 21 Treffer, davon 15 falsch:
`.chat__weg svg` ist 17 Pixel gross und soll das auch sein --
getroffen wird der Knopf darum herum. Eine Pruefung, die zu viel
meldet, wird abgeschaltet; das ist kein besseres Ergebnis als eine,
die zu wenig meldet. Jetzt unterscheidet sie Bedienelement und
Innenteil (svg, ::after, __punkt, __lupe, __pfeil).

UND DIE REPARATUR WAR ERST ZU KLUG. Fuer das 24-Pixel-x in einer
Chat-Nachricht hatte ich eine unsichtbare Trefferflaeche gebaut
(`::after { inset: -10px }`), um die Zeile nicht hoeher zu machen.
Dann gemessen: Die Zeile IST schon 44 hoch -- `start.css` hebt unter
760 px bereits JEDEN button. Es fehlte nur die BREITE. Die Flaeche
haette ein Problem geloest, das es nicht gibt, und dafuer einen Trick
eingefuehrt, den man beim naechsten Lesen erst verstehen muss.
Jetzt schlicht `min-width: 44px`.

Gemessen am Bildschirm, mit und ohne Finger:
  Maus    .nachricht__weg 24x24  .chat__weg 34x34   (unveraendert)
  Finger  .nachricht__weg 44x44  .chat__weg 44x44

`pointer: coarse` und nicht `max-width`: Ein Tablet ist 1024 breit und
wird trotzdem mit dem Finger bedient.

NACHTRAG ZUR PRUEFUNG SELBST: Sie verlangte kurz, dass es die
Trefferflaeche GIBT -- und fiel um, als sie wieder verschwand. Eine
Pruefung, die eine Bauweise erzwingt statt eines Ergebnisses, steht
dem Aufraeumen im Weg. Sie erkennt sie jetzt an, verlangt sie aber
nicht.

pruef-tippziele 11/0, pruef-chat-optik gruen, pruef-css-klassen gruen,
pruef-nachfrage 33/0, pruef-leerzustand 13/0.
2026-09-20 12:36:02 +02:00
DogFatherGit 2f3fb03ffe Eine Pruefung, die nach der ersten Aussage stirbt, prueft nichts
pruef-start-ansicht kam seit gestern Nachmittag ueber die ERSTE
Aussage nicht hinaus: 1 statt 151. Sie starb mit "Failed to execute
getComputedStyle: parameter 1 is not of type Element" -- und sagte
damit gar nichts mehr ueber die Startseite.

URSACHE WAR MEIN EIGENER HINWEIS VON GESTERN. "Bei dir klingelt
nichts" gehoert absichtlich zu keinem Bereich (die Anruf-Probe ist
ein Werkzeug, keine Kachel). Dadurch bekam die Zeile kein Zeichen --
und die Pruefung rief getComputedStyle auf null.

ZWEI FEHLER, ZWEI REPARATUREN:

  Die ZEILE sah kaputt aus. Sie stand als einzige ohne Zeichen
  zwischen allen anderen, der Text begann weiter links. Genau der
  stille Fehler, der wie Absicht aussieht. Sie bekommt jetzt immer
  ein Zeichen -- aber KEINE Farbe, denn sie soll keinen Bereich
  behaupten, zu dem sie nicht gehoert.

  Die PRUEFUNG durfte daran nicht sterben. Ein fehlendes Teil ist ein
  BEFUND, kein Absturz. Und sie nahm an, jeder Hinweis zaehle etwas.
  Seit gestern gibt es zwei Sorten: zaehlende ("2 Aufgaben sind
  ueberfaellig") und Zustaende ("Bei dir klingelt nichts"). Sie
  unterscheidet das jetzt und nennt beide Anzahlen -- faellt eine
  Sorte ganz weg, sieht man es. Das ist die GENAUERE Pruefung, nicht
  die schwaechere.

GEBAUT, GEMESSEN, WIEDER ENTFERNT: Auf dem Weg dahin hatte ich die
Kachelgruppen beim ersten Besuch einklappen lassen -- 25 Kacheln in
5 Gruppen sind fuer den ersten Tag eine Wand. Drei Messungen haben
es widerlegt:
  Die erste Gruppe ist nicht die wichtigste. Bei DogFather heisst
    sie "Rund um das Team" und hat GENAU EINE Kachel. Er haette eine
    Kachel gesehen und sieben zugeklappte Ueberschriften.
  Die Regel "nur wenn es nicht auf den Schirm passt" haette auch auf
    1280x900 gegriffen -- bei 30 Kacheln passt es nie.
  Es gibt keinen "ersten Besuch": Der Merker entsteht erst beim
    Klappen. Wer die Seite seit Wochen benutzt und nie geklappt hat,
    faende am Morgen seine Startseite umgebaut.
Die Begruendung steht jetzt im Code, damit es niemand ein zweites
Mal baut.

pruef-start-ansicht 151/0, pruef-nachfrage 33/0,
pruef-leerzustand 13/0, pruef-meldungen 8/0, pruef-css-klassen gruen.
2026-09-20 12:29:59 +02:00
DogFatherGit e5eed8506c Der gefaehrlichste Handgriff im Haus wird jetzt am Bildschirm geprueft
pruef-personen-loeschen gibt es seit Langem -- sie kennt aber nur die
Schnittstelle: kein Browser, kein Knopf, kein Dialog. Der Weg, den ein
Mensch geht, um eine Person zu loeschen, war nie geprueft. Und das ist
der eine Handgriff, den man nicht zuruecknehmen kann.

pruef-nachfrage hat jetzt einen Browserteil (33/0 statt 17/0):
  der Dialog geht auf und nennt den Namen im Titel
  er sagt, dass es endgueltig ist, was passiert und was bleibt
  ein FALSCH abgetippter Name schliesst ihn NICHT und sagt, warum
  der Abbruchknopf loescht nichts
  richtig abgetippt wird geloescht (Liste 2 -> 1)
  Abmelden fragt nach und nennt den Grund (Zugangscode)
  Esc bricht ab -- man bleibt angemeldet

BEIM BAUEN ZWEIMAL DANEBENGEGRIFFEN, beide Male gemessen statt
vermutet:
  Die Liste zeigte nur eine Person, obwohl vier in der Datenbank
    standen. Das sah nach einem Befund aus. Die Rollen-Abschnitte sind
    standardmaessig ZU -- nur der eigene ist offen, und das ist richtig
    so. Die Pruefung klappt ihn jetzt auf.
  Vorher wurde mit einer festen Wartezeit gearbeitet. Jetzt wird auf
    den Zustand gewartet, nicht auf die Uhr.

Neu: server/helfer-nachfrage.mjs (bestaetige/verwerfe/nachfrageText)
kennt beide Wege -- den <dialog> und den confirm()-Notnagel fuer
Safari vor 15.4. Ohne den zweiten liesse sich der Notnagel nie pruefen.
2026-09-19 20:24:28 +02:00
DogFatherGit 1207b79a33 Hochladen sieht man jetzt, Leerzustaende sagen was hingehoert
DREI BLOECKE AUS DEM PERFEKTIONSLAUF.

1. HOCHLADEN MIT FORTSCHRITT UND ABBRUCH
   Alle fuenf Wege (Dateien, Chat-Anhang, Wissen-PDF, Aufgaben-Anhang,
   Profilbild) benutzten `fetch`. Das kann beim SENDEN nicht sagen, wie
   weit es ist -- sichtbar war "wird hochgeladen …", von der ersten bis
   zur letzten Sekunde gleich. Bei 40 MB im Mobilfunknetz zwei Minuten.
   Wer das sieht, drueckt noch einmal und laedt dieselbe Datei doppelt.
   Neu: workspace/assets/js/hochladen.js (XMLHttpRequest, das Einzige,
   was `upload.onprogress` kann) samt gemeinsamer Anzeige.
   Drei Ausgaenge: fertig / abgebrochen / schiefgegangen -- und ein
   Abbruch ist KEIN Fehler und bekommt keine rote Meldung.

   DABEI AUFGEFALLEN: KEINE EINZIGE PRUEFUNG im Haus laedt eine Datei
   ueber die Oberflaeche hoch. Der ganze Umbau waere gruen gewesen,
   ohne dass ein Byte je den Weg der Nutzer gegangen waere.
   Neu: server/pruef-hochladen.mjs -- 18/0, mit echter Datei.
   Zwei Irrtuemer beim Bauen, beide gemessen statt vermutet:
     Ohne Drosselung gibt es auf localhost EINEN Fortschritt-Stand.
       Das sah nach Befund aus und war keiner. Jetzt 2 MBit/s ueber
       CDP -- derselbe Verlauf wie bei den Modis im Mobilfunk, 57
       gemessene Zwischenstaende.
     Gewartet wurde auf den Dateinamen "irgendwo im Dokument" -- der
       stand auch im Fortschrittsbalken. Die Bedingung war erfuellt,
       bevor etwas angekommen war.

2. LEERZUSTAENDE
   Elf von 18 Brettern fielen auf "Noch kein Eintrag in diesem
   Bereich" zurueck. Am ersten Tag ist ALLES leer -- wer da achtzehn
   Bretter oeffnet und achtzehnmal denselben Satz liest, lernt nichts
   ueber die Bretter, sondern dass das System kaputt ist. Jeder Satz
   sagt jetzt, was hier hingehoert UND was der naechste Schritt ist.
   Neu: server/pruef-leerzustand.mjs -- 13/0, leitet die Bretter aus
   BEREICHE ab; ein neunzehntes ohne Satz macht sie rot.

3. ABMELDEN UND KONTRASTMODUS
   Abmelden war am Handy ein 44-Pixel-Zeichen neben Glocke und Suche,
   sofort wirksam. Teurer als es aussieht: Zum Wiederanmelden braucht
   man den Zugangscode, und den gibt es EINMAL. Jetzt mit Rueckfrage,
   die genau das sagt -- und dazu, dass Zumachen reicht (12 Stunden).

   Kontrastmodus: 68 Regeln zeigen einen Zustand NUR ueber Farbe
   (35x aria-pressed, 33x data-an). Der Modus ersetzt alle Farben und
   entfernt box-shadow -- gedrueckt sah aus wie nicht gedrueckt.
   14 CSS-Dateien hatten gar keinen Block. Statt 14 Bloecke zu pflegen
   eine Regel in gate.css, die den ZUSTAND trifft statt die Datei.
   Gemessen mit forcedColors: active -- vorher ununterscheidbar,
   jetzt `solid 2px Highlight`.
   Was seinen Zustand als WORT traegt (.marke-status, .t-stufe,
   .spalte), braucht nichts -- nachgesehen, nicht vermutet.

PRUEFUNGEN, DIE AUF confirm() WARTETEN: Fuenf Dateien benutzten
`seite.once("dialog", d => d.accept())`. Playwright faengt confirm()
selbst ab, einen <dialog> nicht -- pruef-chat-anhaenge meldete acht
Fehler, keiner davon im Code. Neu: server/helfer-nachfrage.mjs, der
beide Wege kennt (auch den Notnagel fuer Safari vor 15.4).
pruef-chat-anhaenge, -ausbau, -optik und pruef-code wieder gruen.

hilfeAufraeumen bleibt ausgeschaltet -- das loescht echte Daten und
ist Filipes Entscheidung.
2026-09-19 20:16:23 +02:00
DogFatherGit c516aad4ed Nichts verschwindet mehr ohne eine Nachfrage, die sagt was passiert
Filipe: "Es darf vor allem keine Stellen geben, an denen ein Benutzer
etwas falsch machen kann, nur weil die Seite es nicht verstaendlich
genug erklaert."

Gemessen: 30 Stellen in 16 Dateien benutzten confirm() oder prompt().
Das Haus hatte die richtige Bauweise laengst -- einen <dialog>, in
aufgaben.html sogar ausfuehrlich begruendet -- aber sie stand IN EINER
SEITE. Wer anderswo etwas loeschen liess, hatte sie nicht.

confirm('Wirklich loeschen?') stellt die falsche Frage: Es fragt, ob
man sicher ist, und nennt nicht, WAS passiert, was BLEIBT und ob es
ZURUECK geht. Jetzt beantwortet jeder der 41 Dialoge alle drei.

Neu: workspace/assets/js/nachfrage.js -- window.frageNach() mit
Pflichtgrund, Zahlenfeld, einzeiliger Eingabe und Abtippsicherung.
Drei Ausgaenge: <dialog> / confirm()-Notnagel fuer Safari vor 15.4 /
Abbruch (Esc, Klick daneben, "Doch nicht" -- immer false).

DREIMAL DERSELBE FALLSTRICK, dreimal nachgemessen statt vermutet:
  .dialog stand in aufgaben.css und leistung.css -> auf dateien.html
    waere der Dialog ein weisser Systemkasten gewesen. 14 Regeln
    klammergenau nach module.css verschoben (Klammern gezaehlt, nicht
    per Muster geschnitten -- heute frueh hat ein nicht-gieriges
    Muster schon einmal CSS zerrissen).
  Das Formular trug .neu neu--blank -- und .neu gibt seine Abstaende
    nur in aufgaben.css. Gemessen: padding 0px, und die Felder
    verloren ihre height:44px. Jetzt steht alles unter
    .nachfrage__form in module.css; der Dialog borgt nichts mehr.
  Die erste Fassung der Pruefung zaehlte nachfrage.js SELBST als
    Nutzer -- damit war jede Seite trivialerweise "Nutzer" und die
    Pruefung gruen ohne Inhalt. Jetzt ausdruecklich ausgenommen.

ZWEI FUNDE NEBENBEI:
  hilfeAufraeumen() wird im Betrieb NIE aufgerufen. Der Kommentar
    behauptete "wird beim Start aufgerufen (siehe index.js)" -- das
    war nie wahr; einziger Aufrufer ist die eigene Pruefung. Folge:
    geschlossene vertrauliche Faelle bleiben unbegrenzt stehen. NICHT
    eingeschaltet (das loescht echte Daten und ist Filipes
    Entscheidung), sondern der Kommentar richtiggestellt.
  Einen Hilfe-Fall zu schliessen ist endgueltig -- es gibt keine
    Route, die ihn wieder oeffnet. Vorher stand darueber nur die
    Frage nach einem Schlusswort. Jetzt sagt der Dialog es.

pruef-struktur hat meine eigene Pruefung von heute Nachmittag
erwischt: Sie bildete ihr Datum aus UTC. Beim Beheben erst
heuteLokal(datum) genommen -- die Funktion nimmt gar kein Argument
und haette still "heute" statt "+3 Tage" geliefert. Jetzt tagLokal(3),
nachgerechnet: Abstand 3 Tage.

Am Bildschirm angesehen (Rechner 1280, Handy 390): passt rein, Esc
ergibt false, Fokus liegt auf dem harmlosen Knopf, Knoepfe 44px auf
Touch. Der Platzhalter im Abtippfeld zeigte den erwarteten Namen --
das sah aus wie ein schon ausgefuelltes Feld, entfernt.

Neu: server/pruef-nachfrage.mjs -- 17/0, mit sechs Gegenproben und
beiden Richtungen (wer fragt, laedt die Datei; wer nie fragt, laedt
sie nicht -- sonst truege die Anmeldewand 4,8 KB fuer nichts).

pruef-meldungen 8/0, pruef-css-klassen gruen, pruef-struktur gruen,
pruef-leistung gruen.
2026-09-19 19:57:43 +02:00
DogFatherGitandClaude Opus 5 26937dda16 Ein klingelndes Telefon haengt nicht mehr an einem einzigen Kanal
Filipe: "wenn vanvan rangeht und redet klingelt es immer noch bei mir
weiter, der anruf verbindet nicht richtig."

=== WAS DAS PROTOKOLL SAGT ===

    17:04:52  anruf_start  Person 1 (Filipe)
    17:05:25  anruf_ende   Person 4 (VanVan)  24 s
    17:05:31  anruf_ende   Person 1 (Filipe)  39 s

Sie WAR im Gespraech -- der Server hat sie 24 Sekunden als
Teilnehmerin gefuehrt. Das Ereignis "dabei" ist also verschickt
worden. Bei Filipe kam es nicht an: `tonAus()` ist das Erste im
`dabei`-Zweig, noch vor jeder Pruefung, und das Tuten lief weiter.

=== GEPRUEFT UND AUSGESCHLOSSEN ===

  Raumzugehoerigkeit   beide in Raum 1, bei keinem `raus_am` gesetzt
  Verkabelung          Server sendet mit `art: "anruf"`, chat.js reicht
                       an window.anrufEreignis weiter, anruf.js nimmt
                       entgegen -- alle drei Stellen stimmen
  Tonsteuerung         ein einziger Taktgeber, `tonAus` raeumt ihn;
                       kein zweiter Weg, der ihn neu startet
  Ereignisstrom        Keep-alive vorhanden, Kopfzeilen richtig
                       (no-transform, X-Accel-Buffering: no)
  Service Worker       hat gar keinen fetch-Handler, kann also kein
                       altes Skript ausliefern
  teilnehmerVon vs.
  teilnehmerFuerAnruf  reicht nur durch, dieselbe Abfrage

Es geht unterwegs verloren, auf einem Weg, der von hier aus nicht
messbar ist: Ereignisstrom ueber Cloudflare, ein schlafender Reiter,
ein Neustart im falschen Moment.

=== ALSO NICHT WEITERSUCHEN, SONDERN DIE ABHAENGIGKEIT BESEITIGEN ===

Ein klingelndes Telefon darf nicht an einem einzigen, zerbrechlichen
Kanal haengen. Solange es klingelt, fragt der Anrufer jetzt SELBST
nach: "ist schon jemand dran?" -- alle zwei Sekunden an
`/workspace/api/anruf/:raum`, das es laengst gibt.

Der Ereignisstrom bleibt der erste Weg, er ist schneller. Das hier ist
das Netz darunter. Kommt das Ereignis an, hat die Nachfrage nichts
mehr zu tun und haelt von selbst an (sie prueft `anruf.beginn` und die
bekannten Teilnehmer).

Sie hoert an JEDEM Ende auf: beim Auflegen, wenn die Verbindung steht,
wenn das Ereignis doch ankommt, wenn der Anruf vorbei ist. Eine
Schleife, die weiterlaeuft, fragt sonst auf jedem Geraet, das je
telefoniert hat, alle zwei Sekunden nach einem Anruf, den es nicht
mehr gibt.

Alle zwei Sekunden und nicht jede halbe: Es klingelt hoechstens zwei
Minuten, das sind sechzig Abrufe.

=== ZWEI DINGE, DIE DIESE SUCHE ERST SO MUEHSAM GEMACHT HABEN ===

DAS PROTOKOLL KANNTE ANFANG UND ENDE, ABER NICHT DEN MOMENT DAZWISCHEN.
Die wichtigste Frage -- "ist sie ueberhaupt rangegangen?" -- war nur
ueber einen Umweg zu beantworten (ein `anruf_ende` mit ihrer Nummer).
Das ist eine Schlussfolgerung, keine Auskunft. `anruf_dabei` steht
jetzt drin, mit der Zahl der Beteiligten.

UND EINE PRUEFUNG WAR GRUEN, OHNE ETWAS ZU PRUEFEN. In chatEreignis
stand `(zuschauer.get(personId) || []).length` -- `zuschauer` haelt
aber Mengen, und eine Menge hat kein `length`. Der Ausdruck war IMMER
undefined, also immer falsch, also wurde nie uebersprungen: Wer die
Seite offen hatte, bekam zusaetzlich zur Nachricht auf dem Bildschirm
noch eine Meldung aufs Handy.

Der Kommentar drei Zeilen darueber warnt woertlich davor ("der
schnellste Weg, dass er Benachrichtigungen abschaltet"), und
`siehtZu()` weiter unten macht es mit `.size` richtig. Die Absicht
stand da, die Zeile tat das Gegenteil.

Meine eigene Pruefung hat das mitgetragen: Sie bestaetigte den alten
WORTLAUT statt sein VERHALTEN und war deshalb gruen. Genau die
Hausregel vom 01.09. -- ein gruener Haken sagt nur, dass die Bedingung
erfuellt war, nicht dass sie das Richtige geprueft hat. Jetzt prueft
sie auf `.size`.

GEMESSEN: pruef-anruf-klingelt 24/0 (vorher 17), pruef-anruf 114/0,
pruef-turn-wege 15/0, pruef-meldungen 8/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 19:15:51 +02:00
DogFatherGitandClaude Opus 5 9a1287aa0e Es hat nie geklingelt -- und die Vermittlung war nie das Problem
Filipe: "irgendwas klappt mit dem telefonieren nicht."

=== WIE DER FEHLER GEFUNDEN WURDE ===

Ich habe zuerst wieder die Vermittlung verdaechtigt. Stattdessen das
Protokoll des Servers gelesen -- und dort stand es die ganze Zeit:

    24x anruf_start, jeder nach 7 bis 39 Sekunden beendet
    im Chat danach jedes Mal: "Verpasster Anruf"
    die Gegenseite schrieb: "Hab keinen Anrufeingang gehabt und
    keine Benachrichtigung"

Es ging nie um Ton oder Verbindung. Es hat bei der anderen Person
schlicht nicht geklingelt.

Dieselbe Lehre wie am 06.09. ("kommt keine Mail an" -- erst fragen, OB
gesendet wurde) und am 14.09. (zwei Tage Audiowege verfolgt, waehrend
die CPU bei 98 % stand). Eine halbe Minute in der richtigen Tabelle
haette Stunden gespart.

Nebenbefund zur Messbarkeit: Das coturn-Protokoll kann die Frage gar
nicht beantworten -- es schreibt Zuteilungen bei dieser Stufe nicht
mit. Meine eigene Zuteilung von 16:35 taucht dort ebenfalls nicht auf.
Wer daraus "null Zuteilungen, also kaputt" liest, sucht am falschen
Ende. Das ist der dritte Ausgang: nicht "in Ordnung" und nicht
"kaputt", sondern "kann ich hier nicht sehen".

=== WAS WIRKLICH DEFEKT WAR ===

Die Benachrichtigung WURDE zugestellt -- `zuletzt_ok` am Geraet stand
auf genau die Anrufminute. Sie hat nur nicht geklingelt:

1. `Urgency: "normal"` STAND FEST IM TRANSPORT, fuer jede Meldung.
   Auf Android entscheidet dieser Kopf, ob sofort zugestellt wird oder
   bis zum naechsten Aufwachen gewartet. Im Stromsparmodus werden
   daraus Minuten -- bei einem Anruf, der 120 Sekunden klingelt, ist
   das ein verpasster Anruf mit Zeitstempel.

2. `renotify: false` UND `tag: d.art`. Eine zweite Meldung mit
   derselben Kennung ersetzt die erste LAUTLOS. Wer ein zweites Mal
   anruft, WEIL nicht abgehoben wurde, loest damit gar keinen Ton mehr
   aus -- genau im wichtigsten Moment.

3. KEIN vibrate, KEIN requireInteraction. Ein stiller Kasten, der von
   selbst verschwindet. In einer Hosentasche unsichtbar.

Fuer "Aufgabe ueberfaellig" ist all das genau richtig, und der
Kommentar daneben stimmte auch ("eine Meldung, die stehen bleibt, ist
eine Zumutung"). Fuer ein klingelndes Telefon ist es das Gegenteil.

Jetzt unterscheidet das Haus beides:
  - eigene Kennung je Anruf, damit der zweite den ersten nicht
    stillschweigend ersetzt
  - renotify, vibrate (zweimal lang, wie ein Telefon),
    requireInteraction
  - Urgency: high und eine TTL von 150 Sekunden -- ist der Anruf
    vorbei, verfaellt auch die Meldung, statt eine Stunde spaeter
    nachtraeglich aufzuploppen
  - alle ANDEREN Meldungen bleiben unveraendert ruhig. Das ist kein
    Nebensatz: Wuerde alles vibrieren und stehenbleiben, schaltet es
    nach drei Tagen jemand ab -- und dann klingelt auch der Anruf nie
    wieder.

Die Dringlichkeit haengt an derselben Bedingung wie die Nachtruhe
(`art === "test" || art === "anruf"`). "Darf das nachts stoeren?" und
"darf das warten?" haben dieselbe Antwort; zwei Bedingungen waeren die,
die beim naechsten Nachschaerfen auseinanderlaufen.

=== ERREICHT ES AUCH JEMANDEN? ===

Der Service Worker ruft skipWaiting() und clients.claim() -- die neue
Fassung greift beim naechsten Oeffnen der App, ohne dass jemand etwas
tun muss.

ABER: Nachgemessen haben NEUN von fuenfzehn aktiven Zugaengen KEIN
Geraet angemeldet -- darunter eine rechte Hand und zwei Modis. Bei
ihnen kann keine Benachrichtigung ankommen, so laut sie auch waere.
Das ist kein Codefehler; das muessen die Leute einmal selbst tun.

=== GEMESSEN ===

pruef-anruf-klingelt 17/0 (neu, mit drei Gegenproben), pruef-anruf
114/0, pruef-turn-wege 15/0, pruef-meldungen 8/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 18:51:43 +02:00
DogFatherGitandClaude Opus 5 5c3bfcb47d Der Handy-Rundgang, den es fuer die Modis nie gab
Filipe: "mach einen kompletten check dass die app auf dem handy perfekt
funktioniert ... weil die modis haben schon probleme." Auf die
Rueckfrage: "einfach ALLES ABCHECKEN ALLES MOEGLICHE."

=== DER BEFUND, DER ALLES ERKLAERT ===

Es gibt seit dem 02.09. einen grossen Rundgang (pruef-grosscheck). Er
geht ueber jede Seite, zwei Bildschirmgroessen und VIER Rollen:

    admin . manager . scout . creator

Vier von acht. Es fehlen modi, hand und gast -- also genau die drei
Rollen, die auf crew.dogfather-universe.com leben, und genau die, von
denen die Beschwerden kommen. Ihre Seiten waren nie im Ganzen auf einem
Handy durchgemessen worden.

Kein Vorwurf an den Rundgang: Er wurde fuers Agenturhaus gebaut, und
Team Dogi kam spaeter dazu. Aber es erklaert, warum Fehler dort
ueberleben konnten.

pruef-handy-teamdogi.mjs schliesst die Luecke: 4 Rollen x 2 Breiten x
bis zu 32 Seiten = 206 Seitenaufrufe, 91 052 Elemente, 3 880
Bedienelemente. Gemessen wird: kommt die Seite an, stuerzt etwas ab,
laeuft etwas ueber den Rand, ist Text abgeschnitten, kann man es
treffen, liegt etwas uebereinander, weiss man was es tut.

=== WAS ES GEFUNDEN HAT ===

DIE KOPFLEISTE WAR AUF JEDER SEITE ZU KLEIN. Bei Breiten bis 400 px
schrumpften alle Knoepfe auf 34x34, bis 560 px auf 36x36. Das sind zehn
Pixel unter dem, was ein Daumen sicher trifft -- und es betraf jede
Seite, jede Rolle, jeden Aufruf. Genau das erlebt man als "der Knopf
geht nicht".

Die Verkleinerung war nie noetig. Am echten Aufbau nachgemessen:

    Breite   belegt   bei 44px noetig   verfuegbar
    360 px    237          284             328
    390 px    237          284             358
    412 px    245          284             380

Es passt ueberall, mit Luft. Jetzt 44x44 -- und dazu `flex-wrap: wrap`
als Regel statt einer dritten festen Zahl: Die Reihe bricht genau dann
um, wenn der Platz wirklich nicht reicht.

DER ZURUECK-KNOPF war 38x44 -- die Hoehe stimmte, die Breite nicht. Der
Rundgang hat ihn 192-mal gemeldet. Er ist der Knopf, den man auf jeder
Unterseite am haeufigsten trifft.

DIE KLEINEN UMSCHALTER (38 px) waren eine begruendete Ausnahme --
begruendet fuer die Maus. Auf Geraeten, die mit dem Finger bedient
werden, gilt jetzt 44. Gefragt wird `pointer: coarse` und nicht die
Breite: Ein schmales Browserfenster am Rechner braucht keine 44 px, ein
1200 px breites Tablet sehr wohl.

DIE KALENDERPILLEN waren 26 px hoch, das Rechtefeld 34 px breit, die
Kalenderpfeile 38 px. Alle auf 44.

EINE BESCHRIFTUNG HING NICHT AM FELD. In checkliste.js stand ein
<label> ohne `for` neben einem <select> ohne `id`. Optisch richtig --
fuer ein Vorleseprogramm ein namenloses Feld. Und weil wahl.js das
Systemmenue durch einen eigenen Knopf ersetzt und dessen Namen AUS DEM
LABEL holt, blieb auch der Knopf namenlos.

=== DREI FEHLER IN MEINER EIGENEN PRUEFUNG ===

Und sie sind der lehrreichere Teil.

(1) DER ERSTE LAUF MELDETE EIN 1647 px BREITES BILD auf einem 390 px
    breiten Schirm. Das sah nach dem Fund des Tages aus. Es war einer
    in MEINER Pruefung: `dogfather-universe.com` steht in der fest
    eingebauten HSTS-Liste von Chromium, der Browser schaltet
    unabaenderlich auf https um, und mein Testserver sprach http.
    Ergebnis: JEDE Stilvorlage schlug fehl. Gemessen wurde eine Seite
    ganz ohne CSS.

    Haette ich den Befund gemeldet statt nachzusehen, waere ein halber
    Tag in eine Reparatur geflossen, die nichts repariert. Die Pruefung
    spricht jetzt selbst https, mit eigenem Zertifikat und einem
    winzigen Vorbau.

(2) 350 FEHLALARME. `span.zurueck-knopf__text` wurde 192-mal als
    abgeschnitten gemeldet, `span.teilen__text` 154-mal -- beide sind
    ABSICHTLICH 1 px gross und weggeschnitten, damit ein
    Vorleseprogramm sie liest und das Auge nicht. Dazu 24-mal
    `-webkit-line-clamp` (gewolltes Kuerzen auf zwei Zeilen), 14-mal
    Textfelder MIT Beschriftung (ich fragte `labels` nur bei input und
    select, nicht bei textarea) und 26-mal Zierrat mit
    `aria-hidden="true"`.

    Eine Warnung, die immer kommt, ist keine Warnung mehr -- und diese
    haetten jeden echten Fund zugedeckt.

(3) DIE UEBERLAUF-MESSUNG WAR BLIND. Sie rechnete
    `scrollWidth - clientWidth`; `body { overflow-x: hidden }` macht
    beide Werte immer gleich. Die Pruefung fand nichts und meldete
    trotzdem gruen. Gefunden hat das die GEGENPROBE -- sie ist genau
    dafuer da. Jetzt zaehlt, ob ein sichtbares Element ueber den
    rechten Rand ragt.

=== UND EIN FEHLER BEIM AUFRAEUMEN ===

Beim Verschieben der Touch-Regeln von start.css nach module.css hat ein
NICHT-GIERIGES Suchmuster am ersten `}` am Zeilenanfang aufgehoert und
dabei mehr mitgenommen als gemeint: die Schriftgroessen-Regeln fuer
schmale Fenster. Die haetten danach nur noch auf Geraeten mit Finger
gegolten.

Gefunden hat es wieder der Rundgang, nicht das Lesen: `.k-pille` blieb
26 px hoch, obwohl die neue Regel 44 sagte -- die alte stand weiter
unten und gewann. Zurueckgeholt aus HEAD, an ihren Platz gesetzt.

Nebenbei kam dabei heraus, WARUM eine Regel nicht ankam: Jede Seite
laedt gate -> start -> seite -> module -> haus. `aufgaben.css` setzt
`.schnitt { min-height: 38px }` mit derselben Staerke, kommt aber
spaeter. Eine Regel, die man geschrieben hat und die nicht wirkt, sieht
im Editor genauso aus wie eine, die wirkt.

=== STAND ===

Befunde: 120 -> 64.

Weg sind: alle abgeschnittenen Texte (0), alle namenlosen
Bedienelemente (0), alle zu kleinen Knoepfe in Kopfleiste, Zurueck-Weg,
Filterreihen, Kalender.

Es bleiben 64, und sie sind alle von derselben Sorte: 48-mal der
Ersatzknopf eines Auswahlfeldes (34-42 px breit, aber 44 hoch), 8-mal
Kalenderpillen (36-39 breit, 44 hoch), 8 Ueberstaende. Alle sind in der
HOEHE gross genug und nur in der Breite knapp -- die komfortable
Empfehlung, nicht die Mindestanforderung. Sie stehen namentlich im
Prueflauf und sind der naechste Schritt.

GEMESSEN: pruef-css-klassen ALLES IN ORDNUNG, pruef-meldungen 8/0,
pruef-rechtetafel 19/0, pruef-turn-wege 15/0, und beide Gegenproben des
neuen Rundgangs schlagen an.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 17:16:49 +02:00
DogFatherGitandClaude Opus 5 d6df590224 Telefonieren ging nur ueber UDP -- und die Seite sprang immer hoch
=== 1. WARUM TELEFONIEREN NICHT GING ===

Filipe: "es klingelt erscheint auch alles bei jedem aber telefonieren
klappt immer noch nicht."

GEMESSEN, BEVOR ETWAS GEAENDERT WURDE -- und alles war gruen:

  coturn laeuft                 aktiv
  STUN von aussen               antwortet, nennt meine oeffentliche Adresse
  echte Zuteilung von aussen    7/7, Testpaket kam an (Port 49183)
  Dreier-Anruf im Prueflauf     verbindet, alle hoeren alle

Vier Messungen, vier Mal in Ordnung -- und das Telefon ging trotzdem
nicht. Der Grund: Der Prueflauf faehrt BEIDE Seiten auf demselben
Rechner. Dort finden sie sich ueber die direkte Adresse, und die
Vermittlung wird nie gebraucht. Draussen sitzen sie in verschiedenen
Netzen.

DER FUND: Eingetragen war eine einzige Adresse --

    turn:159.195.212.167:3478

Ein `turn:` OHNE `?transport=` heisst UDP, und nur UDP. Nachgemessen
hoert coturn aber auf beidem: 3478/UDP offen, 3478/TCP offen (5349/TLS
ist zu). Angeboten wurde nur der halbe Server.

Wer in einem Netz sitzt, das UDP nach draussen sperrt -- Mobilfunk mit
strengem Profil, Gast-WLAN, Firmennetz --, bekam damit KEINEN
Vermittlungsweg. Es klingelt (das laeuft ueber die Website, also ueber
443), und danach passiert nichts. Genau das gemeldete Bild.

Aus einem Eintrag werden jetzt drei Wege:
  stun:host:port                die eigene Adresse finden, ohne Vermittlung
  turn:host:port?transport=udp  der schnelle Weg
  turn:host:port?transport=tcp  der Weg durch fast jede Sperre

ABGELEITET, NICHT EINGETRAGEN: Drei Zeilen von Hand waeren drei
Stellen, an die beim naechsten Serverumzug jemand denken muesste --
die abgeschriebene Liste, die hier schon zweimal teuer war. Ein
Eintrag MIT `?transport=` bleibt unangetastet, ein fremder Dienst mit
eigenem Passwort sowieso.

pruef-turn-wege (neu, 15/0) sichert beides: dass jeder Weg herauskommt
UND dass jeder turn:-Weg Zugangsdaten traegt. Das Zweite ist das
wichtigere -- auffaechern ohne anmelden haette den Fehler nur
verschoben.

=== 2. DIE SEITE SPRANG BEIM ZURUECKGEHEN IMMER HOCH ===

Filipe: "das nervt man muss dan immer wieder runter scrollen bis man
da ist wo man vorher war."

Der Browser versucht es sogar -- scrollRestoration steht ab Werk auf
"auto". Nur: Jede Seite hier kommt fast leer an und holt ihren Inhalt
danach per Abruf. In dem Moment, in dem der Browser die alte Position
wiederherstellen will, ist das Dokument ein paar hundert Pixel hoch.
Er kann nicht auf Zeile 900 springen, die es noch nicht gibt -- und er
versucht es kein zweites Mal.

Jetzt macht es kopf.js selbst (gilt damit auf allen 21 Seiten): Stelle
merken beim Verlassen, beim Oeffnen zurueckholen und jeden Bildaufbau
lang versuchen, bis das Dokument hoch genug ist. Nach drei Sekunden
wird aufgegeben.

Drei Dinge sind Absicht:
  - NUR beim Zurueckgehen, nicht bei jedem Oeffnen. Wer eine Kachel
    anklickt, will oben anfangen.
  - WER SELBST SCROLLT, GEWINNT. Rad, Wisch oder Taste beenden das
    Nachspringen sofort.
  - Nach einer Stunde vergessen -- auf Zeile 900 zu landen, weil man
    gestern dort war, ist keine Hilfe.

=== 3. DIE LISTE IST NACH ROLLE GETRENNT ===

Filipe: "die rechte hand rolle immer zuerst und dan die modis. die
sollen auch schoen getrennt sein und verschieden aussehen also die
rechte hand viel spezieller."

Die Reihenfolge macht der Server ueber ROLLEN_SORTIERUNG -- dieselbe
Konstante wie ueberall sonst im Haus, nicht eine zweite. Eine
Sortierung nach ROLLE ist ausdruecklich keine Rangliste: Sie sagt
nichts darueber, wie gut jemand ist, nur welche Aufgabe er hat.
Deshalb steht ueber jeder Gruppe ein Satz und keine Zahl.

"Spezieller" heisst hier Material, nicht Groesse: eigener Farbton als
Kante und Schimmer, hellere Flaeche, kraeftigerer Name. Beide Karten
sind GLEICH GROSS und tragen dieselben Zeilen -- zwei Sorten Aufgabe,
keine Rangfolge. Im Kontrastmodus traegt eine doppelte Kante die
Unterscheidung, weil dort keine Farbe mehr wirkt.

=== 4. DER ANRUFKASTEN ===

Vorher: vier gleich aussehende Pillen nebeneinander, darunter eine
Geraeteauswahl, die das breiteste Element war. Kein Name, keine
Ordnung, und der einzige Knopf mit Folgen sah aus wie die anderen.

  - MAN SAH NICHT, MIT WEM. Der wichtigste Satz eines Telefonats fehlte.
    Der Chat kennt den Namen und gibt ihn jetzt mit; wer rangeht, sieht
    den Anrufer.
  - "MIKRO AN" WAR ZWEIDEUTIG -- "ist an" oder "schalt an"? Wer falsch
    raet, sitzt stumm da. Jetzt traegt ein durchgestrichenes Zeichen
    den Zustand, das Wort nur die Sache. aria-pressed bleibt die
    Wahrheit, auch fuer Vorleseprogramme.
  - DIE GERAETEAUSWAHL liegt hinter einem kleinen Knopf, der nur
    erscheint, wenn es ueberhaupt etwas zu waehlen gibt.
  - AUFLEGEN ist als einziger Knopf farbig und steht immer rechts.
  - Ein ruhiger Puls atmet, solange die Verbindung aufbaut, und haelt
    an, sobald sie steht. Bei prefers-reduced-motion steht er still.

=== NEBENBEFUND, DEN DIE PRUEFUNG GEFUNDEN HAT ===

pruef-anruf wurde durch die Auffaecherung an vier Stellen rot: Sie
griff `adressen[0]` und erwartete dort Zugangsdaten. Das ist jetzt der
STUN-Weg, und der hat richtigerweise keine. Gesucht wird nicht mehr
nach PLATZ, sondern nach ART -- ein Index ist eine Annahme darueber,
wie die Liste aussieht, und die hat sich gerade geaendert.

Dazu angepasst: Die Pruefung "die Uhr laeuft" verlangte, dass die Uhr
schon beim Klingeln zaehlt. Seit heute frueh beginnt sie beim
Rangehen (sonst standen im Kasten und im Chat zwei verschiedene
Zahlen). Sie prueft jetzt das Gegenteil -- statt sie zu streichen,
denn eine Zeile weniger haette den Fehler beim naechsten Umbau wieder
durchgelassen.

GEMESSEN: pruef-anruf 114/0 (vorher 111 -- drei MEHR, weil die
Auffaecherung mitgeprueft wird), pruef-turn-wege 15/0,
pruef-meldungen 8/0, pruef-css-klassen ALLES IN ORDNUNG,
pruef-rechtetafel 19/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 15:23:15 +02:00
DogFatherGitandClaude Opus 5 18a5231b70 Die Tuer ohne Klingel, der Anruf ohne Ende, die Glocke ohne Liste
Siebter Durchgang durch die Team-Dogi-Seiten aus Benutzersicht. Alles am
Code belegt, die Groessenangaben nachgerechnet.

=== DIE ANMELDUNG ===

WOHER BEKOMMT MAN EINEN CODE? Stand nirgends. Vier Kacheln, ein Feld,
ein Knopf -- wer keinen Code hatte, fand keinen einzigen Satz dazu. Fuer
die Community besonders teuer: Sie ist die einzige Rolle, die von
aussen kommt und niemanden im Haus kennt.

"BITTE KURZ WARTEN" SIND BIS ZU ZEHN MINUTEN (VERSUCHE_FENSTER_MIN).
Wer nach zwanzig Sekunden nachsieht und dieselbe Meldung liest, haelt
die Seite fuer kaputt. Jetzt steht die Zahl da.

EIN RICHTIGER CODE AN DER FALSCHEN KACHEL fiel in dieselbe Absage wie
ein erfundener -- der Server sucht nur unter der gewaehlten Rolle. Wer
aus der Community kommt und auf "Modi" tippt (das klingt ja danach),
tippt seinen richtigen Code dreimal Buchstabe fuer Buchstabe. Ab dem
zweiten Fehlversuch kommt jetzt ein Hinweis auf die Auswahl -- ohne zu
sagen, welche die richtige waere.

=== DER ANRUF: VIER FEHLER, EINE ERFAHRUNG ===

DAS FREIZEICHEN LIEF UNENDLICH. Es gab keinen Zeitgeber, der aufhoert.
Wer niemanden erreichte, sass vor einem piependen Kasten mit "02:47"
darauf, als telefoniere er laengst. Der Server schickt den Verfallszeit-
punkt sogar mit (`laeuft_bis`) -- benutzt hat ihn nie jemand.

DER KLINGELKASTEN VERSCHWAND NACH 46 SEKUNDEN, waehrend der Server 120
gibt. Wer beim Klingeln das Handy aus der Tasche holt und in Sekunde 50
hinsieht, fand nichts mehr -- kein Kasten, keine Knoepfe -- waehrend der
Anrufer noch siebzig Sekunden Freizeichen hoerte. Die 120 Sekunden sind
im Server ausdruecklich damit begruendet, dass man Zeit zum Entsperren
braucht; eine Zeile im Browser hat diese Entscheidung aufgehoben.

DAS FREIZEICHEN PIEPTE WEITER, waehrend daneben "Keine Verbindung."
stand. Ton sagte "es klingelt noch", Text sagte "vorbei".

DIE UHR ZAEHLTE AB DEM WAEHLEN. Wer 30 Sekunden klingeln liess und 12
Sekunden sprach, las im Kasten "00:42" und danach im Chat "Anruf . 12
Sekunden". Der Server rechnet es richtig; der Kasten hat es wieder
kaputtgemacht.

Dazu: Die Mikrofon-Absage verwies auf "das Schloss-Symbol neben der
Adresse" -- in der installierten App gibt es weder Adresszeile noch
Schloss. Das Haus kennt diesen Fehler und hat ihn beim Weg zur
Anruf-Probe schon behoben; hier stand er noch.

Und die Anruf-Probe: Ihr einziger Punkt ohne Handlungsanweisung war
"Antwort 503." -- auf einer Seite, die ausdruecklich fuer jemanden
gebaut ist, der nicht technisch ist. Ihr Rueckweg fuehrte ausserdem
immer in den Chat, auch wenn man von der Startseite kam.

=== DER TREFF ===

EIN EINZEILER MACHTE SECHS ERKLAERTEXTE UNSICHTBAR. bewerben.js las
`g.unter`, der Server schickt `g.text` -- also immer undefined. Damit
fehlten ALLE SECHS Gruppeneinleitungen des Fragebogens ("Kein Test mit
richtigen Antworten"), und die CSS-Regel dafuer lief ins Leere. Uebrig
blieben sechs nackte Ueberschriften ueber fuenfzehn Fragen.

DIE EINZIGE "SO LAEUFT DAS HIER"-SEITE WAR FAST UNERREICHBAR. Die
Kachel "Regeln & Hilfe" zeigte auf ein Brett, das am ersten Tag leer
ist. Die Regeln, die es wirklich gibt (Begruessung, fuenf Regeln, drei
Stufen, Mindestalter), stehen auf treff-regeln.html -- erreichbar ueber
genau einen kleinen Textlink auf einer Brettseite. Die Kachel zeigt
jetzt dorthin.

FIEL /api/treff/lage AUS, versprach die Seite einem Zuschauer
Schreibrechte, die der Server ablehnt: Die Pruefung fiel bei `lage ===
null` auf `true` durch -- von "darf auf keinem Brett" auf "darf
ueberall". Formular auf, getippt, 403.

Dazu: hilfe.js hatte eine eigene kleine Fehlertabelle fuer zwei
Kennungen und endete sonst bei "Ging nicht." -- ausgerechnet die Seite,
auf der jemand mit einem Problem sitzt, hatte die inhaltsleerste Absage
im Haus. Und der gesperrte "Neue Meldung"-Knopf erklaerte sich nur im
Maus-Tooltip; die Community kommt von TikTok, also vom Handy.

=== DIE STARTSEITE ===

DIE COMMUNITY BEKAM EIN WORT. Unter dem Titel steht bei jeder Rolle ein
Satz -- beim Community-Mitglied stand "Community". Woertlich derselbe
Mangel, den der Kommentar bei MODI_ROLLENTEXT beschreibt und fuer den
Modi behebt.

DER RING MELDETE 100 %, bevor man irgendetwas getan hat. Am ersten Tag,
ohne eine einzige Aufgabe, stand das groesste Element der Seite auf
"100 % -- HEUTE NICHTS OFFEN". Gelesen wird zuerst die Zahl, und 100 %
heisst fuer jeden "fertig", nicht "leer".

UND BEI EINER STOERUNG BLIEB "wird geladen" FUER IMMER STEHEN -- der
fruehe `return` liess den Platzhalter unberuehrt.

=== DIE ZUGANGSVERWALTUNG ===

Der Code-Kasten sagte "jetzt weitergeben" und gab die Haelfte nicht
mit, die man weitergeben muss: WO sich die Person anmeldet. DogFather
ruft den Code durchs Zimmer, der andere fragt "und wo?". Die Adresse
kommt jetzt vom Server (anmeldeAdresseFuer, abgeleitet aus derselben
Weiche), dazu ein Knopf "Code und Adresse kopieren".

Er verschwieg ausserdem den Rettungsweg: "danach nicht mehr abrufbar"
stimmt fuer DIESEN Code -- man kann jederzeit einen neuen vergeben. Wer
das nicht weiss, glaubt, er habe einen Menschen angelegt, der nie
hereinkommt. Und das Fenster liess sich wortlos schliessen, waehrend
der Code offen stand.

=== OPTIK: NACHGERECHNET, NICHT VERMUTET ===

DIE GLOCKE STAND NICHT IN DER LISTE. Sie ist ein echtes <button> und
wurde von der 44-px-Regel erfasst, waehrend ihre vier Nachbarn durch
einen staerkeren Selektor auf 36 px gehen. Zwischen 401 und 560 px --
also bei 412 px (haeufigste Android-Breite) und 430 px (iPhone Pro Max)
-- stand eine 44 px hohe runde Pille zwischen fuenf 36-px-Quadraten.
Der 400er-Block listet sie korrekt; genau dieses Band fiel durch beide
Rechnungen. Dasselbe Muster wie am 06.09.

DIE 9,6-px-REPARATUR IM KALENDER WAR SEIT WOCHEN WIRKUNGSLOS.
kalender.css wird NACH start.css geladen, beide Selektoren sind gleich
stark -- also gewann `.6rem` auf jeder Breite unter 760 px. Genau der
Wert, den start.css als behobenen Fehler protokolliert.

Und die Hebung selbst unterschritt ihre eigene Grenze: Die Regel, die
zu kleine Schrift hochziehen soll, zog `.k-pille` auf 11,2 px -- 0,3 px
unter die 11,5, die 33 Zeilen darueber aufgestellt werden.

Weitere nachgerechnete Groessen: Spaltenkopf und KW-Spalte im Kalender
(10,56 px), Kalenderwoche am Balken (9,92 px), Wecker-Knopf (30 px --
der kleinste im Haus, 14 unter der Vorgabe), Chat-Zurueck auf dem
Tablet (34x34, 40 % weniger Flaeche als noetig, und der einzige Weg
zurueck in die Liste), Emoji-Knoepfe (34 px bei 2 px Abstand -- wer
danebentippt, verschickt ein anderes Zeichen, und das ist sofort
abgeschickt).

IM WINDOWS-KONTRASTMODUS HATTE DIE STARTSEITE KEINE UEBERSCHRIFT.
`.ztitel` und der Team-Dogi-Schriftzug sind mit `background-clip: text`
gesetzt; faellt der Verlauf weg, bleibt durchsichtiger Text. Beide
haben jetzt den Rueckfall, den gate.css schon lange hat.

UND MEIN EIGENES STREIFENRASTER rechnete die Spaltenzahl aus der Breite
statt aus den Daten (`auto-fit`): Bei 390 px passten sechs, alles
darueber fiel in eine zweite, unbeschriftete Zeile. Das `overflow-x`
daneben konnte nie greifen -- ein auto-fit-Raster wird nie breiter als
sein Kasten. Der Kommentar beschrieb ein Verhalten, das es nicht gab.

GEMESSEN: pruef-meldungen 8/0, pruef-css-klassen ALLES IN ORDNUNG,
pruef-rechtetafel 19/0, alle Module laden, keine doppelten
Kachelnamen/-ziele/-farben in allen vier Rollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 15:07:31 +02:00
DogFatherGitandClaude Opus 5 273318dd9c Vier Sackgassen, zwei Kacheln namens "Chat" -- und eine Seite ohne Kopf
Durchgang durch die Team-Dogi-Seiten aus der Sicht von jemandem, der
sie zum ersten Mal sieht. Alles hier ist am Code belegt und nachgemessen.

1. "KLINGELT NICHTS?" WARF ALLE DREI TEAM-ROLLEN AUF DIE STARTSEITE.

anruf-probe.html erklaert, WARUM das Telefon stumm bleibt. Sie steht in
der Rechtetafel offen, und aus dem Chat zeigen zwei Knoepfe darauf. Nur
hatte sie nie eine Kachel -- absichtlich, sie ist kein Bereich. Seit die
Adressregel vom 15.09. eine Kachel VERLANGT, landete jeder Klick wortlos
auf start.html.

Das ist die schlimmste Sorte Sackgasse: Man ruft sie auf, WEIL schon
etwas nicht geht, und sie wirft einen hinaus.

Mit derselben Zeile geheilt: Die Hinweisleiste wirft jeden Hinweis weg,
dessen Ziel es auf dieser Adresse nicht gibt -- "Bei dir klingelt nichts"
wurde auf crew deshalb NIE angezeigt. Ausgerechnet der Hinweis, der acht
von elf Leuten betrifft.

2. UND DIESE SEITE HATTE GAR KEINE GESTALTETE KOPFLEISTE.

.kopfleiste, __zurueck, __mitte, __titel stehen in KEINER Stilvorlage --
sie leben in start.css, die diese Seite absichtlich nicht laedt. Die
Leiste war nackter Text. Auf einer Seite, die man im Stoerfall aufruft,
sieht unfertig aus wie kaputt. Jetzt im <style>-Block der Seite, aus
demselben Grund wie ihr uebriges CSS.

3. EIN MODI KAM NICHT AN SEINE EIGENE AUSWERTUNG.

entwicklung.html und werdegang.html haben BEIDE eine ausgearbeitete
Eigensicht, und die Rechtetafel laesst ihn hinein. In seiner Kachelliste
stand keine von beiden -- der Weg existierte fuer ihn nicht. Die ganze
Eigensicht war toter Code, ausgerechnet fuer den, fuer den sie ist.
Mein eigener Fehler vom Vortag.

Zwei eigene Kacheln in "Fuer dich", aus den Leitungskacheln abgeleitet.
Sie loesen zugleich eine Namenskollision: Bis heute setzten BEIDE Seiten
fuer ihn die Ueberschrift "Deine Entwicklung".

4. DER KALENDER-LINK WAR FUER DIE COMMUNITY EINE SACKGASSE.

Auf jeder Brettkarte mit Termin stand "Im Kalender am 24.09." als Link.
kalender.html steht auf ALLE -- und ALLE ist ausdruecklich ohne "gast".
Jetzt fragt der SERVER die beiden Schranken (kalender_offen) und die
Karte zeigt den Termin als Text statt als Link. Die Auskunft bleibt, nur
der Weg ins Leere faellt weg. Die Regel im Browser nachzubauen waere die
vierte Stelle fuer dieselbe Frage gewesen.

5. EIN MODI KAM AN DIE TALENTE-NOTIZEN, DIE IHM VERWEHRT SIND.

BRETTER_UEBER_SEITEN war eine feste Liste ("wer die Seite darf, muss
auch dorthin kommen") und fragte nie, WER fragt. Ueber
bereich.html?b=talente kam er an Notizen zu Zuschauern, obwohl
talente.html fuer ihn gesperrt ist -- Begruendung dort: "Hier stehen
Namen von Menschen, die nichts davon wissen."

Aus der Liste wurde eine Zuordnung Brett -> Seite, gefragt wird
darfSeite(). Nachgemessen: modi/talente 404, modi/entwicklung darf,
hand+admin unveraendert.

Dazu stand in workspace-bereiche.js ein Kommentar, der das GEGENTEIL des
Codes behauptete ("entwicklung, talente bleiben 404"). Ein falscher
Kommentar an einer Rechtestelle ist schlimmer als keiner.

6. ZWEI KACHELN "CHAT", BEIDE AUF DIESELBE SEITE.

Seit dem Treff-Chat von gestern sahen Modi und rechte Hand zweimal
"Chat" mit demselben Ziel. Jetzt "Treff-Chat" mit ?raum=treff, das den
Raum direkt oeffnet -- gesucht an denselben zwei Merkmalen, an denen ihn
der Rest der Datei erkennt.

7. VERTRAUEN: "WIE GEHT'S DIR?" VERSPRACH MEHR, ALS ES HALTEN KANN.

Dort stand: "Niemand aus dem Team sieht deine Antworten -- auch
DogFather nicht." Punkt. Fast wahr und deshalb gefaehrlich: Aus
denselben Antworten entsteht eine namenlose Ampel fuer die Leitung.

Der ehrliche Satz war laengst geschrieben und wurde vom Server sogar
mitgeliefert (block.text) -- nur hat ihn nie jemand angezeigt. Er steht
jetzt im HTML, nicht im Skript: Wer die Seite oeffnet, soll ihn lesen,
BEVOR er tippt.

8. DIE NEUE AUSWERTUNG, AUS BENUTZERSICHT NACHGEBESSERT.

- Der Streifen hatte keine Zeichenerklaerung. Im Dateikopf stand "wer
  Farben schlecht unterscheidet, liest dasselbe Zeichen" -- das stimmt
  nur, wenn irgendwo steht, was die Zeichen heissen. Jetzt eine Legende,
  aus `stufen` gebaut statt abgeschrieben.
- "nie gesetzt" war ein Mittelpunkt, "Kann ich nicht sagen" ein
  Halbgeviertstrich. Zwei kurze Striche nebeneinander fuer den
  Unterschied zwischen "niemand hat hingesehen" und "jemand hat
  hingesehen und konnte es nicht sagen". Leer ist jetzt wirklich leer,
  mit gestricheltem Rahmen.
- Die Aufschluesselung der Balken stand nur im Mausueberfahren -- am
  Handy also nie, und dort steht jemand damit im Stream. Jetzt als Text.
- Die Modi-Sicht bekam Balken ohne Erklaerung, ein "Frag danach" ohne
  Adressaten und bei fehlender Bewegung ein LEERES Element. Jetzt
  Lesehilfe, ein Leerkasten mit Satz und zwei Wege weiter.

9. NEBENBEFUNDE, DIE DIE PRUEFUNG GEFUNDEN HAT.

pruef-css-klassen war schon VOR dieser Arbeit rot (nachgemessen mit
git stash). Alle drei Befunde behoben:
  - hilfe.html und unsere-seiten.html luden ihre Seitendatei NACH
    module.css und haus.css und ueberschrieben damit das Haus.
  - Zwei Schriftgroessen unter 11,5 px aus dem gestrigen Bau
    (.71rem Monatsbeschriftung, .68rem Marke) auf .75 und .72 gehoben.
  - Die Pruefung selbst war blind fuer <style>-Bloecke in der Seite und
    meldete deshalb dauerhaft drei Fehler an einer Seite, die ihre
    Stile mit Absicht selbst traegt. Eine Warnung, die immer kommt, ist
    keine Warnung mehr -- jetzt sieht sie hin, statt die Seite
    auszunehmen.

Kleinkram nebenbei: "die Antworten sieht nur du" -> "siehst nur du" auf
der Kachel zur empfindlichsten Seite des Hauses. "Bewertet wird dort" ->
"Eingeschaetzt wird dort" in teamlage.html, zwei Zeilen unter "keine
Bewertung von Menschen". "1 Aufgabe(n) angelegt" ausgeschrieben.

GEMESSEN: pruef-css-klassen ALLES IN ORDNUNG (vorher 3 Fehler),
pruef-meldungen 8/0, pruef-rechtetafel 19/0, alle Module laden,
keine doppelten Kachelnamen/-ziele/-farben mehr in allen vier Rollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 14:57:55 +02:00
DogFatherGitandClaude Opus 5 461d41943a Keine Maschinensprache mehr auf dem Bildschirm
Filipe: "keine kryptischen oder technischen fehlermeldungen, sondern
klare aussagen darueber, was passiert ist und wie man das problem
loesen kann."

DAS PROBLEM, NACHGEMESSEN.

Der Server antwortet im Fehlerfall mit { fehler: "..." }. Darin stehen
ZWEI verschiedene Dinge, und von aussen sehen sie gleich aus:
Maschinenkennungen (nicht_verfuegbar, nicht_gefunden, ungueltig -- 43
verschiedene) und fertige deutsche Saetze.

An 84 Stellen stand `textContent = d.fehler` -- ungefiltert. Wer beim
Hochladen einer Datei Pech hatte, las woertlich "nicht_verfuegbar" auf
dem Bildschirm und wusste nicht einmal, ob er selbst schuld war.

Gezaehlt: 474 Antworten mit "nicht_verfuegbar", 392 mit
"nicht_gefunden", 125 mit "ungueltig".

DREI AUSGAENGE, NICHT ZWEI.

`sagWas()` in workspace/assets/js/meldung.js:
  bekannte Kennung   -> ihr Satz
  unbekannte Kennung -> der Ersatzsatz der Stelle, NIE die Kennung
                        (sie geht in die Konsole, wo sie jemandem
                        auffaellt, der sie beheben kann)
  fertiger Satz      -> unveraendert durch

Erkannt wird eine Kennung daran, dass sie nur aus Kleinbuchstaben,
Ziffern und Unterstrichen besteht. Ein deutscher Satz hat immer
Leerzeichen; eine Kennung nie. Die Unterscheidung ist entschieden,
nicht geraten.

UND WARUM DIE TABELLE NICHT ALTERN KANN.

Eine von Hand gepflegte Liste ist hier schon zweimal teuer geworden
(die abgeschriebene Spaltenliste, die feste Umbruchschwelle). Deshalb
rechnet pruef-meldungen.mjs die Kennungen AUS DEM SERVER aus statt sie
zu kennen -- eine neue ohne Satz macht sie rot. Man kann es nicht mehr
vergessen.

Sie prueft drei Dinge und beweist zu jedem, dass sie auch "nicht in
Ordnung" sagen kann:
  1. vollstaendig -- jede Kennung hat einen Satz
  2. angeschlossen -- keine Rohanzeige, und jede Seite, deren Skript
     sagWas benutzt, laedt auch meldung.js
  3. lesbar -- kein Satz enthaelt Kennung, Zahl oder englisches Wort

GEFUNDEN HAT SIE SOFORT EINEN ECHTEN FEHLER: leistung.html laedt seine
Skripte ohne `defer` und fiel damit durch meinen Einbau. Dort waere
sagWas nicht definiert gewesen -- aus einer Fehlermeldung waere ein
Absturz geworden, also schlimmer als vorher.

NEBENBEFUND, DER MICH FAST EINE FALSCHE MELDUNG GEKOSTET HAETTE:
"alter_offen" heisst NICHT "etwas Aelteres ist offen", sondern
"Altersbestaetigung steht noch aus" (workspace.js:4864). Geraten
haette ich es falsch uebersetzt.

GEMESSEN: pruef-meldungen 8/0, alle 46 Skripte syntaktisch in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 14:46:13 +02:00
DogFatherGitandClaude Opus 5 7be85c265b Der Treff bekommt einen Chat -- mit Nachtruhe, ohne Telefon
Filipe, auf die Frage ob die Community einen Chat bekommen soll:
"eine geile mischung von punkt 2 und drei. mach es perfekt so das quasi
nach mitternacht bis morgens 6 uhr keiner schreiben kann damit auch die
privatsphaere beruecksichtig wird ueber nacht ... und die sollen nicht
anrufen koennen. nur schreiben."

Zur Auswahl standen "gar kein Chat", "nur mit Oeffnungszeiten" und
"offen wie im Team". Seine Antwort ist eine vierte, die nicht auf dem
Zettel stand, und sie ist die bessere.

1. WARUM DIE NACHTRUHE MEHR IST ALS EINE EINSTELLUNG

Sein Grund war Privatsphaere -- und zwar die der Leute, die moderieren.
Die Forschung zu ehrenamtlichen Moderatoren sagt genau das: Die beiden
meistgenannten Gruende fuers Aufhoeren sind ZU WENIG ZEIT und STREIT IM
TEAM. Ein Chat, der nachts um drei weiterlaeuft, erzeugt beides.

SIE GILT FUER ALLE, AUCH FUER DIE LEITUNG. Das ist die unbequeme
Entscheidung: Der bequeme Weg waere, DogFather auszunehmen. Aber wenn er
um halb vier schreibt, liest es jemand -- und wer liest, fuehlt sich
zustaendig. Eine Nachtruhe, von der die Leitung ausgenommen ist, ist
keine, sondern eine Bitte.

MODERIEREN GEHT WEITER. Verbergen, loeschen, herausnehmen sind keine
Nachrichten. Wer nachts etwas Schlimmes sieht, kann es wegnehmen -- er
kann nur nicht darueber diskutieren. Und der vertrauliche Meldeweg
bleibt offen: Er ist ein Fall mit einer Zustaendigkeit, kein Raum mit
dreissig Leuten.

GERECHNET IN ORTSZEIT, nicht in UTC. `getHours()` auf einem UTC-Server
haette den Chat im Sommer von 2 bis 8 geschlossen -- zwei Stunden
daneben, und nur denen sichtbar, die um diese Zeit wach sind. Dieses
Haus ist mit der Rechnung schon zweimal hereingefallen.

DER RIEGEL SITZT IM SERVER, nicht im Browser. Ein ausgegrautes Feld ist
eine Hoeflichkeit; wer die Adresse kennt, spricht die Schnittstelle
direkt an. Nachrichten UND Anhaenge werden abgelehnt -- ein offener
Anhangweg waere der Umweg, den jeder findet, der es einmal versucht.

2. KEIN TELEFON -- UND WARUM DAS EINEN EIGENEN RIEGEL BRAUCHT

Ein Anruf haengt in diesem Haus an der RAUMMITGLIEDSCHAFT, nicht an der
Rolle. Solange die Community keinen Raum hatte, war die Frage muessig.
Seit sie einen hat, waere Telefonieren erlaubt -- nicht, weil es jemand
entschieden haette, sondern weil es niemand verboten hat.

Der Riegel steht ganz vorne am Anruf-Router, nicht in den neun Routen
dahinter. Alle sieben Wege sind geprueft, einzeln.

3. DER FUND, DER DIE GANZE NACHTRUHE UMGANGEN HAETTE

Ein Gast konnte ein PRIVATES ZWEIER-GESPRAECH mit DogFather aufmachen.
Die Route antwortete mit 200 und legte den Raum an.

`ohneAussen` nimmt die Community aus den Listen ANDERER heraus -- damit
kein Creator einen Zuschauer anschreibt. Die Gegenrichtung kam nie vor,
weil die Chatseite fuer 'gast' gar nicht offen war. Seit heute ist sie
offen, und damit war die Erlaubnis da.

Ein Zweier-Gespraech ist kein Kanal: keine Nachtruhe, kein Modi liest
mit, niemand koennte moderieren. Aus "die Community bekommt einen Chat"
waere ungewollt "jeder Zuschauer bekommt eine Standleitung zu
DogFather" geworden.

GEFUNDEN HAT ES DIE PRUEFUNG, NICHT DAS LESEN -- und zwar in dem Moment,
in dem ich zwei Dateien weiter selbst vor genau dieser Sorte Erlaubnis
gewarnt hatte.

4. ZWEI TOTE WEGE, EINER DAVON MEINER

pruef-community-sicht sucht nach sichtbaren Wegen, die ins Leere
fuehren. Sie fand zwei:

  a) "Bei dir klingelt nichts" -> anruf-probe.html. Der Hinweis von
     heute Vormittag, und die Seite steht einem Gast ausdruecklich NICHT
     offen. Mein Fehler, und einer, der jedem naechsten Hinweis genauso
     passiert waere.

     AN DER WURZEL BEHOBEN: Die Hinweise pruefen jetzt auch die ROLLE
     (`darfSeite`), nicht nur die Adresse. Das ist der 15.09. noch
     einmal, eine Ebene tiefer -- damals die Adresse, diesmal die Rolle,
     und dieselbe Lehre: Die Hinweise sind eine DRITTE Stelle neben
     Seiten und Schnittstellen.

  b) Der Verweis "Kalender" im Tagesblick. Steht fest im HTML, fuehrt
     fuer die Community ins Leere -- und zwar SCHON VOR den Aenderungen
     dieses Tages. Aufgefallen nur, weil (a) daneben stand. Der Weg
     wird jetzt abgeleitet: Wer die Kachel hat, hat den Weg.

5. DIE PRUEFUNG LAEUFT ZWEIMAL

Die Nachtruhe laesst sich nicht in EINEM Lauf in beiden Zustaenden
pruefen -- die Zeiten werden beim Laden gelesen, und ein zweiter Server
braeuchte denselben Port. pruef-treffchat ruft sich deshalb selbst noch
einmal auf, mit einem Fenster, das jetzt gilt. Dieselben Pruefungen,
andere Lage.

DIE UHR WIRD NICHT GEFAELSCHT. Verschoben wird die GRENZE, nicht die
Zeit -- eine Pruefung, die an der Systemzeit dreht, faelscht danach auch
anderes mit und ist nur nachts gruen.

6. WAS SICH NEBENBEI GEAENDERT HAT

- pruef-treff war SCHON VORHER ROT (8 Fehler): Sie erwartete sieben
  Kacheln fuer die Community, es waren gestern Nacht schon zehn. Feste
  Zahlen, Rechnung von gestern. Jetzt abgeleitet -- 72 Pruefungen statt
  66, alle gruen.
- Ein 404 bei jedem Seitenaufruf der Community: `anruf.js` holte die
  Verbindungsadressen, bevor es wusste, wer fragt. Der Browser
  protokolliert das, BEVOR JavaScript abfangen kann -- also darf die
  Anfrage gar nicht erst gestellt werden. `/api/ich` sagt es jetzt
  vorher. Ein Fehler, der immer kommt, macht den naechsten echten
  unsichtbar.
- Reaktionen (Daumen) bleiben nachts erlaubt. Ausdruecklich, mit
  Begruendung im Code: Ein Daumen ist keine Nachricht, er loest keine
  Meldung aus und kann keinen Streit anfangen. Eine Luecke ohne
  Begruendung wird beim naechsten Durchsehen entweder geschlossen oder
  uebersehen -- beides falsch.

GEMESSEN: pruef-treffchat 108/0 (neu, laeuft zweimal), pruef-treff 72/0
(vorher 66 mit 8 Fehlern), pruef-chat gruen, pruef-rechtetafel 19/0,
pruef-community-sicht gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 11:47:31 +02:00
DogFatherGitandClaude Opus 5 790b77a73d Bei dir klingelt nichts -- und 49 Pruefungen, die blind waren
1. SIEBEN VON ELF HATTEN KEIN GERAET ANGEMELDET.

Gemessen am echten Server, nicht geschaetzt (die Notiz von heute Nacht
sagte acht -- Tamy hat inzwischen eins). Bei ihnen kommt nichts an,
solange die Seite zu ist: keine Aufgabe, kein Termin, kein Anruf.

Die Glocke sagt das seit jeher korrekt und kennt sogar den
iPhone-Sonderfall ("erst zum Home-Bildschirm"). Nur tippt sie niemand
an -- sie ist ein stiller Schalter in einer Leiste.

Jetzt steht es dort, wo man hinsieht: als Hinweis in "Was ist dran?",
mit Weg auf anruf-probe.html. Als OFFENER PUNKT, nicht als Warnung --
eine Warnung, die bei sieben von elf Leuten dauerhaft oben steht, ist
nach einer Woche unsichtbar, und mit ihr die echten daneben. Er
verschwindet von selbst, sobald ein Geraet da ist (Gegenprobe in
pruef-glocke).

Und ohne die "1" davor: Er zaehlt nichts, er beschreibt einen Zustand.

FUENF DER SIEBEN DURFTEN DIE SEITE GAR NICHT OEFFNEN. anruf-probe.html
stand nur Leitung und Modis offen. Das war die falsche Einschraenkung:
Die Seite prueft die ganze Kette bis zur Geraete-Kennung, und die
traegt auch jede Aufgaben- und Terminerinnerung. Jetzt alle Team-Rollen,
ohne "gast" (die Community bekommt keine Erinnerungen).

2. 49 PRUEFUNGEN KONNTEN "BELEGT" NICHT VON "KAPUTT" UNTERSCHEIDEN.

Aufgefallen beim Nachsehen, warum ein Lauf rot war: Es war mein eigener,
haengengebliebener Lauf, der den Port hielt. Kein Befund.

Dabei gemessen: Von 130 Pruefungen hatten 49 keinen Portwaechter, und
SIEBEN Portnummern sind doppelt vergeben (4186, 4188, 4189, 4193, 4198,
4321, 4345). Bei belegtem Port startet der eigene Server STILL nicht --
und alles Weitere misst gegen einen fremden Stand. Das hat in diesem
Haus schon zweimal Stunden gekostet (27.08. und 05.09.).

Der Waechter existierte seit dem 05.09., er war nur nie ausgerollt.
Jetzt haben ihn alle 130. Gegenprobe gemacht: Port belegt ->
Rueckgabewert 3 mit Begruendung statt stillem Messen.

pruef-content bekommt BEIDE Ports -- sie startet zwei Server, und der
zweite gehoert zur Gegenprobe. Nur den ersten zu schuetzen hiesse,
ausgerechnet den Teil ungeschuetzt zu lassen, dem man glaubt.

Die sieben doppelten Nummern bleiben vorerst. Mit dem Waechter ist eine
Kollision jetzt laut statt still; Umnummerieren ist ein eigener Schritt.

3. pruef-rollen IST ABGESTUERZT, SEIT WANN WEISS NIEMAND.

"Target crashed" bei der fuenften Rolle, nach 234 gruenen Pruefungen.
Kein Fehlschlag -- ein toter Browser.

NACHGEMESSEN GEGEN DEN STAND VOR HEUTE (0b73fbb): dort genauso, an
derselben Stelle. Es lag also nicht an den Aenderungen dieses Tages.
Aufgefallen ist es nie, weil ein abgestuerzter Browser von aussen wie
ein Programmfehler aussieht und die 234 gruenen Zeilen davor sich wie
ein fast bestandener Lauf lesen.

Ursache ist die Menge: fuenf Rollen mal sechzehn Seiten in EINEM
Browserprozess. Die Kontexte wurden je Rolle geschlossen, der Prozess
darunter lief durch. Jetzt bekommt jede Rolle ihren eigenen Browser,
und ein Absturz meldet sich selbst statt als Zeitueberschreitung
irgendwo weiter unten aufzuschlagen.

Ergebnis: 321 Pruefungen, alles in Ordnung -- statt Absturz bei 234.

4. DAS SYMBOL FUER TIKTOK.

assets/img/app-symbole/workspace-1024.png, frisch gerendert statt
hochskaliert (das Huskygesicht lebt von harten Kanten) und als VOLLES
Quadrat ohne Rundung: Die Aufnahme hat keinen Alphakanal, die Ecken
waeren sonst weiss. App-Portale wollen ohnehin das volle Quadrat, die
Rundung macht das Betriebssystem.

Die sechs vorhandenen Groessen sind dabei bitgleich geblieben --
gepruefte Nebenwirkung, nicht gehofft.

GEMESSEN: pruef-glocke 31/0 (neu: 5 zum Hinweis), pruef-rollen 321/0
(vorher Absturz), pruef-rechtetafel 19/0, pruef-struktur 0 Fehler,
pruef-betreuung und pruef-werdegang gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 11:14:18 +02:00
DogFatherGitandClaude Opus 5 6c10ef0600 Wie geht's dir?: fester Kern, wechselnde Fragen -- und die leere Runde
Dein Auftrag von vorher, zusammen mit zwei Saetzen, die sich zu
widersprechen schienen: "viel mehr Fragen" und "kurz und knapp".

1. DER FEHLER, DEN ICH DABEI GEFUNDEN HABE, WAR GROESSER.

Eine Runde galt als vollstaendig, sobald zu jeder Frage IRGENDEIN Stand
vorlag. Nach der ersten Runde ist das immer der Fall -- die Antworten
bleiben ja stehen. Ab da liess sich jede weitere Runde abschliessen,
OHNE eine einzige Frage anzufassen: Die alten Antworten wanderten mit
neuem Datum ein zweites Mal in den Verlauf.

Der Verlauf zeigte dann eine gerade Linie, und die bedeutete nicht "es
ist gleich geblieben", sondern "niemand hat gefragt". Genau die Sorte
Zahl, die hier verboten ist: eine, die etwas Falsches behauptet, und
der man glaubt. Bei DIESEM Gegenstand -- dem Befinden eines Menschen --
waere das der schlechteste denkbare Ort dafuer.

DIE VORHANDENE PRUEFUNG HAT DEN FEHLER NICHT GEFUNDEN, SIE HAT IHN
FESTGESCHRIEBEN. Dort stand woertlich `ok(zweite.code === 201, "eine
zweite Runde geht auch sofort")` -- gruen, und ein Beleg fuer genau das
Gegenteil dessen, was sie pruefen sollte. Sie aenderte eine Antwort von
zwoelf und war zufrieden.

Ab jetzt zaehlt nur, was NACH der letzten Runde gesetzt wurde. Die alte
Antwort bleibt sichtbar -- sie ist nicht falsch, nur alt -- und traegt,
solange eine Runde faellig ist, den Hinweis "Das war deine Antwort beim
letzten Mal". Der Knopf zum Abschliessen ist weg, bis bestaetigt wurde.

2. FUENF FESTE FRAGEN, DREI WECHSELNDE.

Kern sind die, bei denen ein Ausfall teuer waere: die beiden
meistgenannten Gruende fuers Aufhoeren (zu wenig Zeit, Streit im Team),
die Erholung, die Sicherheit vor Anfeindung und der beste
Fruehindikator ("kann ich mir vorstellen, in ein paar Monaten noch
dabei zu sein"). Eine davon nur jede dritte Runde zu fragen hiesse, die
Antwort im Schnitt sechs Wochen spaeter zu bekommen.

Alle anderen rotieren, drei je Runde. Damit bleibt eine Runde bei acht
Fragen -- die Quellen sagen fuenf bis fuenfzehn, unter zwei Minuten --
und der Katalog kann WACHSEN, ohne dass eine Runde laenger wird. Das
ist der eigentliche Gewinn und die Aufloesung deines Widerspruchs.

Gerechnet, nicht gewuerfelt: aus der Zahl der bisherigen Runden. Zufall
hiesse, dass bei jedem Neuladen etwas anderes dasteht. Und weil sieben
Zusatzfragen und drei Plaetze nicht glatt aufgehen, wird der Versatz
erhoeht, falls er je einen gemeinsamen Teiler mit der Laenge haette --
sonst kaemen nur zwei feste Haelften dran, und der Rest nie.

3. WAS DARAUS FOLGTE, OHNE DASS ES IM PLAN STAND.

- `rhythmus()` zaehlte gegen ALLE Fragen. Mit der Rotation waere das nie
  wieder erfuellt gewesen: Jede Runde haette sich selbst fuer
  unvollstaendig erklaert und die Seite haette taeglich gefragt.
  Jetzt gegen den Kern, der in jeder Runde enthalten ist.
- Die Auswertung sieht ALLE zwoelf Fragen, nicht die acht dieser Runde.
  Der Verlauf hoert nicht auf, wenn eine Frage pausiert.
- Der Verlauf zeigt jede Frage MIT Geschichte (nach zwei Runden elf von
  zwoelf), nicht die der aktuellen Runde. Leere Felder heissen jetzt
  ausdruecklich "war nicht dran", nicht "keine Antwort".
- "seit 2 Runden" heisst jetzt "die letzten 2 Male". Mit der Rotation
  war die alte Formulierung eine Behauptung ueber eine Runde, in der
  gar nicht gefragt wurde.

4. ZWEI DINGE, DIE KEIN ZAHLENVERGLEICH GEFUNDEN HAT -- nur das
   Ansehen des Bildschirmfotos, und beide waren wahr und trotzdem
   irrefuehrend:

- Der Satz "diese Runde sind 8 von 12 dran" stand nur, solange etwas
  offen oder faellig war. Im Ruhezustand -- dem, den man am haeufigsten
  sieht -- fehlte er. Wer acht Fragen zaehlt, wo zwoelf im Katalog
  stehen, haelt vier fuer verschwunden.
- "Das war deine Antwort beim letzten Mal" stand an JEDER Frage,
  unmittelbar nachdem man sie beantwortet hatte.

Beide haben jetzt eine Pruefung, inklusive Gegenprobe ueber eine
zurueckdatierte Runde.

GEMESSEN: pruef-befinden 100/0 (vorher 75 -- die Zahl ist gestiegen,
nicht gefallen), pruef-entwicklung 43/0, pruef-push-ziel 10/0,
pruef-werdegang 95/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 10:33:07 +02:00
DogFatherGitandClaude Opus 5 19e9f471d3 Entwicklung: die Auswertung je Person -- und elf Seiten ohne Farbe
Filipe: "dan perfektionierst du eine neue wo diagramme texte und so zu
jedem modi gemacht wird und diese kategorie kannst du entwicklung nenen."

1. DAS EIGENTLICHE PROBLEM WAR, DASS ES KEINE VERGANGENHEIT GAB.

`entwicklung_stand` hat den Schluessel (person, punkt, beurteiler) und
wird bei jeder Aenderung UEBERSCHRIEBEN -- dort richtig, eine Beobachtung
ueber einen Menschen soll aktuell sein. Nur: Damit existierte nichts,
woraus sich ein Verlauf zeichnen liesse. Nachgemessen: 43 Zeilen Stand,
NULL Zeilen Geschichte. Ein Diagramm ueber einen einzigen Zeitpunkt ist
kein Diagramm, sondern ein Balken.

Neu: `entwicklung_lauf` haengt jede Aenderung an, statt zu ueberschreiben.
Sie steht in workspace-entwicklung.js, bei der Tabelle, zu der sie
gehoert -- die Auswertung liest nur. Andersherum gaebe es einen Ring
zwischen zwei Modulen, und Ringe halten in JavaScript genau so lange,
bis jemand eine Konstante auf oberster Ebene benutzt.

KEIN ANLASS, NIE. Neben jedem "da hakt es" steht ein Satz, woran man es
gemerkt hat -- fuer ein Gespraech aufgeschrieben. Eine Chronik dieser
Saetze waere das Belastendste, was dieses Haus speichern kann. Die Spur
hat gar keine Spalte dafuer, und die Pruefung liest die TABELLE, nicht
die Ausgabe: Eine Spalte, die es gibt, wird eines Tages gefuellt.

Die Startaufnahme uebernimmt den heutigen Stand mit seinen ECHTEN Daten,
damit die Seite am ersten Tag nicht leer ist -- und zaehlt ausdruecklich
NICHT als Bewegung. Der Tag, an dem die Spur entstand, war kein Tag, an
dem 43 Dinge gleichzeitig passiert sind.

2. WAS GEZEIGT WIRD: BEWEGUNG, KEINE NOTE.

Keine Punktzahl, kein Prozentwert, kein Durchschnitt, keine Rangliste,
kein Vergleich zwischen zwei Menschen. Das ist die Recherche, nicht
Vorsicht: Ueberrechtfertigung (Deci), sozialer Vergleich senkt die
Leistung derer, die schlechter dastehen, Schwaechenfokus ebenso.

Stattdessen das progress principle (Amabile/Kramer, ~12 000
Tagebucheintraege): Sichtbarer Fortschritt ist der staerkste einzelne
Treiber. Deshalb Diagramm 1 "Was sich bewegt hat" -- zwei Richtungen um
eine Nulllinie, ein Massstab fuer beide. Diagramm 2 der Streifen (Punkt
x Monat), fortgeschrieben, aber nach 90 Tagen sichtbar verblasst.
Und die Texte in dieser Reihenfolge: was sich bewegt hat, was traegt,
erst danach was liegt.

Selbst gezeichnet, kein Diagrammpaket: 60 kB ueber die Leitung von
jemandem, der mit dem Handy im Stream steht -- und es braechte eigene
Farben neben die Hausfarben. Jede Zelle traegt ihr Zeichen als Text,
jeder Balken seine Zahl, darunter eine Legende: Die Farbe ist nie die
Auskunft.

Zwei Gesichter: Die Leitung sieht die Karten, ein Modi ausschliesslich
die Bewegung in der eigenen -- ohne Namen, ohne Anlass, ohne Streifen.

3. NEBENBEFUND, GROESSER ALS ERWARTET: ELF SEITEN OHNE FARBE.

Der Umbau von heute frueh heisst "Jede Seite traegt die Farbe ihrer
Kachel". Nachgemessen traf das auf 18 von 34 Seiten zu. Elf Seiten mit
echter Kachel gingen leer aus -- ausgerechnet die von Team Dogi:
befinden, bewerben, bewerbungen, entwicklung, hilfe, rechte, talente,
teamlage, teilen, treff-moderation, treff-regeln, unsere-seiten.

Der Grund: `zuSeite()` sucht nur in `Bereiche.GRUPPEN`, und dort stehen
ausschliesslich die Kacheln der Agentur. Die von Team Dogi liefert der
Server (`ich.bereiche`, `ich.bereiche_zusatz`). Auffallen konnte das
nicht -- eine Seite ohne Farbe sieht aus wie eine, die eben keine hat.

kopf.js faerbt jetzt zweimal: sofort aus GRUPPEN (Agenturseiten ohne
Flackern wie bisher), und noch einmal aus den Serverkacheln, sobald
`werZeigen` sie bringt. Nur, wenn beim ersten Mal nichts gefunden wurde.

pruef-buehne misst den Kontrast an echten Bildpunkten und kannte diese
zwoelf Seiten nicht. Jetzt stehen sie in der Liste; ihre Frist waechst
mit der Laenge, statt als feste Zahl irgendwann zu reissen. Gemessen
fuer werdegang.html: 4,83:1 am Computer, 6,22:1 am Handy.

4. TON 38 SAH FREI AUS UND WAR ES NICHT.

Erster Anlauf war Ton 38, weil 37 die hoechste Nummer in workspace.js
ist. Gezaehlt in start.css sind es 39, alle vergeben. Genau davor warnt
das Farbwerkzeug im eigenen Kopf ("Ton 22, weil er frei AUSSAH").

Dabei aufgefallen: Die zwei Kacheln von heute Nacht wurden ohne das
Werkzeug gesetzt. Ton 39 lag 0,0362 von Ton 15 entfernt -- der engste
Abstand im ganzen Haus, zwei praktisch gleiche Cyan-Toene. Filipe dazu
mehrfach: "keine die sich irgendwie aehnlich sind".

Neues Werkzeug `tools/kachel-farbe-einzeln.mjs`: zieht EINE Farbe nach,
ohne die anderen anzufassen. Das grosse Werkzeug haette alle 40 neu
gefaerbt -- jede Kachel im Haus, ungefragt. Es bricht ab, wenn es nicht
alle Toene lesen kann: Der erste Anlauf las 31 von 40, weil einstellige
Nummern mit ZWEI Leerzeichen dastehen, und rechnete froehlich weiter.

Ergebnis: kleinster Abstand 0,0362 -> 0,0840, durch Aendern von zwei
Kacheln, die es erst seit gestern Nacht gibt.

5. anruf-probe.html lud `basis.css` und `kopf.css` -- beide gibt es
nicht. Ausgerechnet dort faellt es nicht auf, weil die Seite ihre eigene
Stilangabe im Kopf hat. pruef-struktur war deshalb rot (5 Befunde) und
ist jetzt gruen.

GEMESSEN: pruef-werdegang 95/0 (neu), pruef-entwicklung 43/0,
pruef-befinden 75/0, pruef-rechtetafel 19/0, pruef-zwischenspeicher 21/0,
pruef-start-ansicht 0 Fehler, pruef-struktur 0 Fehler (vorher 5),
pruef-buehne fuer werdegang.html 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 10:22:02 +02:00
DogFatherGitandClaude Opus 5 0b73fbb501 Jede Seite traegt die Farbe ihrer Kachel -- und der alte Name ist weg
1. DIE FARBE DER KATEGORIE GILT JETZT AUF DER GANZEN SEITE.

Filipe: "die kacheln sollen auch in jeder seite die farben der
kategorie haben. ich will dass alles perfekt angepasst ist."

Vorher war jede Bereichsseite gleich blau, egal aus welcher Kachel man
kam -- beim Klick verlor man die einzige Farbe, an der man sich
orientieren konnte.

KEINE DRITTE LISTE: Der Ton steht bereits in den Kacheln, und der
Browser hat beide Quellen vorliegen (`ich.bereiche` vom Server,
`Bereiche.GRUPPEN` fuer die Agentur). `tonSetzen` sucht dort und setzt
`data-ton` am <body>; die Zuordnung Nummer->Farbe gilt ueber start.css
ohnehin schon. Gefunden wird ueber das ZIEL, nicht ueber den Namen --
der aendert sich (heute zweimal), das Ziel nicht.

Der Akzent der Seite wird daraus gemischt, nicht rein uebernommen:
Einige Toene sind sehr hell (Ton 30 fast Weissgruen, Ton 36
Zitronengelb) und wuerden als duenne Linie auf dunklem Grund blenden.
12 % ruhiges Blaugrau nehmen die Spitze, ohne die Kategorie
unkenntlich zu machen.

2. DER UMBENANNTE NAME WAR NOCH AN VIER STELLEN.

Die Kachel heisst seit heute "Eure Aufgaben" -- Titel und Kopfleiste
der Seite sagten aber weiter "Entwicklung", und zwei Pruefungen
suchten die Kachel ueber ihren alten Namen. Sie waeren beim naechsten
Lauf rot geworden, ohne dass etwas kaputt ist.

pruef-befinden sucht die Kachel jetzt ueber ihr ZIEL statt ueber den
Namen: Das ist die Angabe, die sich nicht aendert, wenn jemand den
Namen nachschaerft.

GEMESSEN: pruef-entwicklung 43/0, pruef-befinden 75/0,
pruef-community-sicht 10/0, pruef-wege-nach-draussen 64/0,
pruef-bereiche-lesend gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 02:09:02 +02:00
DogFatherGitandClaude Opus 5 b40089ff79 Testfoto aus dem Commit nehmen
server/_foto-logos.png war ein Bildschirmfoto zum Nachsehen, wie die
schwebenden Logos aussehen -- kein Bestandteil der Anwendung. Es ist
beim 'git add -A' mitgekommen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 02:04:14 +02:00
DogFatherGitandClaude Opus 5 f62ade3573 Vertraulicher Meldeweg, klappbare Abschnitte, lila Stunden, Logos
Eine Nacht voller Auftraege von Filipe. Der Reihe nach:

1. VERTRAULICH MELDEN -- der groesste neue Teil.

"es soll auch eine kategorie also eine hauptkachel geben wo die
community leute sich anonym melden koennen wenn sie probleme haben ...
rechte hand und dogfather sollen zugriff auf diese anonyme nachrichten
haben. also anonym fuer die anderen."

WICHTIG, UND ES STEHT SO AUF DER SEITE: "anonym" heisst hier
VERTRAULICH. DogFather und die rechte Hand sehen den Namen -- so
bestellt und auch richtig, ohne Namen kann man niemandem helfen.
Anonym ist es gegenueber allen anderen: kein Modi, kein anderes
Mitglied. Wer glaubt, er schreibe unerkannt, schreibt anders und fuehlt
sich hinterher getaeuscht -- deshalb steht der Satz im Formular, bevor
jemand tippt.

Der strikte Wechsel (melden -> warten -> antworten -> warten) ist im
SERVER erzwungen, nicht nur im Knopf. Ein ausgegrauter Knopf ist keine
Regel. Geschlossen wird nur von der Leitung; abgeschlossene Faelle
werden nach 90 Tagen samt Nachrichten geloescht -- hier stehen die
empfindlichsten Texte des Hauses.

Modis sind ausdruecklich AUSSEN VOR: Sehr oft geht es in diesen
Meldungen um eine Moderationsentscheidung.

2. JEDE KATEGORIE LAESST SICH ZUKLAPPEN.

"man soll auf dieser seite jede kategorie auf und zu klappen koennen
mit einem button ... ueberall wo so eine liste entstehen kann."

Das Muster gab es auf der Startseite schon; es steht jetzt als
`abschnittKlappbar` in kopf.js und wird von den Brettern und dem
Zeitstrahl benutzt. Die Koepfe sind echte <button> (fuer die Tastatur),
der Zustand haelt in localStorage, und er haengt je Brett UND Art --
sonst waere "Regel zugeklappt" ueberall gleichzeitig zu.

3. DIE SPRUNGLEISTE SIEHT AUS WIE ETWAS ZUM ANFASSEN.

Vorher unterstrichene Woerter, die aussahen wie eine Fusszeile. Jetzt
Marken mit Rahmen in einem eigenen Block.

4. DIE STUNDEN SIND LILA.

UMGERECHNET, NICHT NEU GEWAEHLT: Jeder der fuenf Verlaufsstopps wurde
nach OKLCH zerlegt, der Farbton auf 303 Grad gedreht, zurueckgerechnet.
Helligkeit und Buntheit blieben gleich -- eine frei gegriffene Palette
waere heller oder bunter geworden, und die Uhr damit unruhiger.

5. DIE KARTEN "UNSERE SEITEN": babyblau und lila, mit schwebenden Logos.

Beide Logos wurden zu MASKEN gerechnet (tools/logo-maske.mjs): Die PNG
tragen nur Alpha, die Farbe kommt aus dem CSS. Dadurch passt dasselbe
Logo in jede Kachel, egal welchen Ton sie hat -- und VanVans 378-KB-
Logo wurde dabei zu 109 KB. Vier Stueck je Karte, verschieden gross,
zwei Bahnen, 26 bis 41 Sekunden Umlauf. Der erste Versuch war mit 5-9 %
Deckkraft praktisch unsichtbar; jetzt 10-16 %.

6. "ENTWICKLUNG" HEISST JETZT "EURE AUFGABEN".

Filipe hat recht: Die Kachel fuehrt seit dem 11.09. auf den Katalog --
eine Aufgabenliste. Der Name blieb stehen, weil beim Umhaengen des
Ziels niemand ihn angefasst hat. Der Name "Entwicklung" ist damit frei
fuer das, was er darunter versteht (Auswertung je Person mit Verlauf
und Text) -- das ist noch NICHT gebaut.

DREI PRUEFUNGEN, DIE ZUFAELLIG GRUEN WAREN, sind nebenbei aufgefallen:
- pruef-kachelraster wartete feste 500 ms auf eine gestaffelte
  Einblendung und mass vier Reihen, wo drei sind. Jetzt reducedMotion.
- pruef-start-ansicht scrollte 600 px und nahm an, danach liege keine
  Kachel mehr unter dem Zeiger.
- pruef-wege-nach-draussen zaehlte das Kachelraster ueber ALLE Gruppen
  statt je Gruppe.

GEMESSEN: pruef-hilfe (neu) 55/0, pruef-wege-nach-draussen 64/0,
pruef-jeder-hat-eine-seite 65/0, pruef-community-sicht 10/0,
pruef-bereiche-lesend, pruef-steckbrief, pruef-start-ansicht,
pruef-kachelraster alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 02:04:03 +02:00
DogFatherGitandClaude Opus 5 63f2b2bc55 Jeder hat einen Steckbrief -- und die Kacheln stehen in der richtigen Reihenfolge
Filipe: "jeder soll ein steckbrief haben, jeder der ein account hat,
rechte hand, modis und community, jeder soll genau wie ich foto und so
hinzufuegen koennen." Und: "ich will das oben die sachen fuer dogfather
sind, dan die sachen fuer modis und dan community bereich."

1. JEDER HAT EINEN STECKBRIEF.

In rechte.js fehlte "gast" -- und damit ausgerechnet die groesste
Gruppe. Die Seite selbst konnte es die ganze Zeit: `/mein` fragt nach
der eigenen Nummer und kennt gar keine Rolle. Es fehlte nur die Tuer
und die Kachel.

DABEI EIN ZWEITER FUND, der schon laenger da war: In
assets/js/steckbrief.js stand eine Liste aus drei Gruppen (Management,
Scouting, Creator). Wer in keine passte, verschwand LAUTLOS aus der
Uebersicht -- betroffen waren die rechte Hand und die Modis. Ein Modi,
der die Seite oeffnete, sah seine eigenen Leute nicht. Kein Fehler,
keine leere Liste, sie waren einfach nicht da.

Die Zuordnung kommt jetzt vom Server (`abschnittFuer`). Damit kann sie
nicht mehr veralten, und in der ausgelieferten Datei steht keine Liste
von Rollennamen mehr -- was ohnehin Hausregel ist. Wer kuenftig
vergessen wird, landet sichtbar unter "Weitere" statt zu verschwinden;
die Gegenprobe dafuer steht in der Pruefung.

"Wer hier mitarbeitet" heisst jetzt "Wer hier dabei ist" -- ein
Mitglied arbeitet nicht mit, es schaut zu.

2. DIE REIHENFOLGE.

Die Moderationskachel trug dieselbe Gruppe wie die sieben Bretter und
landete deshalb HINTER ihnen: Wer moderiert, musste an der ganzen
Community vorbeiscrollen. Sie hat jetzt eine eigene Gruppe und steht
davor.

ERST ZU VIEL GEMACHT, DANN KORRIGIERT: Mein erster Entwurf schrieb auch
die Reihenfolge der Arbeitsgruppen fest. Die ist an mehreren Stellen
bewusst gewaehlt und begruendet -- pruef-start-ansicht hat es sofort
gemeldet, zu Recht. Jetzt wandern nur noch Moderation, Community und
"Fuer dich" ans Ende; alles andere bleibt, wo es war.

3. ZWEI PRUEFUNGEN, DIE ZUFAELLIG GRUEN WAREN.

pruef-kachelraster zaehlte Reihen ueber die Y-Koordinate und wartete
feste 500 ms. Die Kacheln laufen aber gestaffelt ein -- mit einer
Gruppe mehr war die Messung zu frueh und meldete vier Reihen, wo drei
sind. Das Bildschirmfoto derselben Seite zeigte ein makelloses Raster.
Jetzt misst sie mit `reducedMotion: reduce`, also den Endzustand.

pruef-start-ansicht scrollte 600 px und nahm an, danach liege keine
Kachel mehr unter dem Zeiger. Dieselbe Falle wie eine feste
Umbruchschwelle: eine Rechnung von gestern. Sie fragt jetzt, was
gemeint ist -- leuchtet die ALTE Kachel noch?

GEMESSEN: pruef-jeder-hat-eine-seite (neu) 65 Pruefungen 0 Fehler,
pruef-steckbrief, pruef-start-ansicht, pruef-kachelraster,
pruef-community-sicht alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 01:40:16 +02:00
DogFatherGitandClaude Opus 5 f30227c873 Unsere Seiten, klickbare Video-Karten -- und coturn, das nie vermittelt hat
Drei Sachen von Filipe, und eine davon war ein Fehler von mir.

1. DER VERMITTLUNGSSERVER HAT NIE EINEN ANRUF GETRAGEN.

Am 18.09. habe ich gemeldet, coturn laufe und sei "von aussen
nachgewiesen". Das war falsch. Im Protokoll: null Zuteilungen, jemals.
Beim ersten echten Versuch "check_stun_auth: Cannot find credentials"
-- in /etc/turnserver.conf fehlte `static-auth-secret`, also suchte
coturn die Zugangsdaten in seiner eigenen Datenbank und wies jeden ab.

Und mein eigenes Werkzeug meldete die ganze Zeit gruen:
"Eingetragen, Geheimnis lesbar, Server antwortet." Jedes Wort wahr --
und keins beantwortete die Frage, um die es geht. Eine STUN-Bindung
fragt "bist du da?", eine Zuteilung fragt "traegst du meinen Anruf?".

`tools/turn-sprache.mjs` (neu) versucht jetzt eine ECHTE Zuteilung und
schickt ein Paket darueber. `turn-einrichten.mjs` benutzt sie und hat
drei Ausgaenge statt zwei: traegt / traegt nicht / konnte nicht
nachsehen. Nach Filipes Reparatur auf dem Server gemessen: Zuteilung
auf Port 49199, Paket angekommen -- von Luxemburg durch Deutschland.

2. UNSERE SEITEN -- die erste Kachel, die HINAUSFUEHRT.

Website und VanVans Shop, mit dem Rabattcode DOGI10. Der Code wurde
nachgesehen, nicht abgeschrieben: partnercodes.json, 10 Prozent,
aktiv, "zum weitergeben an Community" -- und giltAufSale: false,
weshalb der Satz zu reduzierten Artikeln danebensteht. Der zweite Code
dort ist als "nur fuer Filipe persoenlich" vermerkt und steht nirgends.

Auch Name und Beschreibung des Shops stammen von der Seite selbst.
Meine erste Fassung hiess "Van's DIY Bastelbedarf" und nannte "Perlen,
Anhaenger, Werkzeug" -- ausgedacht und falsch. Er heisst mit "&" und
verkauft Haekelwerke, Plushies, Schmuck.

Der Ton der Kachel wurde GESUCHT, nicht gewaehlt: sieben geratene
Blautoene schafften den noetigen Abstand nicht, also 372 600
Kombinationen abgesucht. #087ce7, Abstand 0.310, Kontrast 4.51:1.

3. DIE GANZE VIDEO-KARTE KLICKT -- "egal wo man drauf drückt".

Und hier steckte der lehrreiche Fehler: Zuerst stand der Klick-Block
unten vor `return k`. Diese Funktion hat DREI Rueckgabepunkte, und der
erste lautet `if (!darfEintragen()) { ...; return k; }` -- also genau
fuer die Mitglieder, fuer die Filipe es wollte. Beim Team ging es, bei
der Community nicht. Jetzt haengt er dort, wo `videoWeg` entsteht.

Nicht klickbar bleiben Karten ohne Video und solche, deren Video bei
TikTok geloescht wurde -- sonst fuehrt der Klick auf eine Fehlerseite,
und wir sehen kaputt aus.

GEMESSEN: pruef-wege-nach-draussen (neu) 63 Pruefungen, 0 Fehler, auf
1400 und 412 px. Mit Gegenproben: der Kopierknopf oeffnet nichts, der
eigene Knopf wirkt genau einmal, auf einer Karte ohne Video passiert
nichts. pruef-community-sicht 10/0 auf jetzt 11 Seiten, 0 tote Wege.

Nebenbei: Der Pfeil klebte bei langen Untertiteln am Text (auf dem
Bildschirmfoto gesehen). 0.45rem Abstand.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 01:17:09 +02:00
DogFatherGitandClaude Opus 5 d766be57b6 Anruf: wer auflegt, hinterlaesst jetzt auch eine Spur
Filipe, 00:30 Uhr: „hab angerufen aufgelegt und da steht immer noch
nichts im chat vom anruf...."

Im Protokoll: vier Anrufe, je drei bis zehn Sekunden, kein einziger
Eintrag im Gespraech. Und mein Denkfehler dahinter war einfach:

„Verpasster Anruf" stand NUR in `aufraeumen()` -- also erst, wenn ein
Anruf nach zwei Minuten von selbst verfaellt. Wer vorher auflegt,
loeschte ihn spurlos. Abschnitt 5e hat damit genau den Weg geprueft,
den niemand geht: warten, bis es von allein aufhoert. Im Alltag legt
man auf.

Fuer die andere Seite ist ein Anrufer, der aufgibt, ERST RECHT ein
verpasster Anruf.

UND EINE ZWEITE FALLE, die die erste verdeckt hat: `verpasstVermerken`
nahm den Anrufer aus der Runde der Anwesenden (`a.wer`). Beim
Verfallen steht er noch darin -- beim AUFLEGEN ist sie leer. Die
Zeile waere also auch dann ausgefallen, wenn der Aufruf an der
richtigen Stelle gestanden haette. Jetzt kommt er aus `a.anrufer`,
wie beim gefuehrten Anruf auch.

Zwei Fehler, die einander gedeckt haben, und beide hat dieselbe
Pruefluecke durchgelassen: Ich hatte den Ablauf geprueft, den ich
gebaut hatte, nicht den, den ein Mensch geht.

Geprueft: pruef-anruf 106 -> 111. Der neue Abschnitt ruft an, wartet
kurz, legt auf -- und misst, dass genau EINE Zeile entsteht, dass sie
„verpasst" sagt, dass der Anrufer daran steht und dass spaeteres
Aufraeumen keine zweite schreibt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 00:32:57 +02:00
DogFatherGitandClaude Opus 5 ff09a67578 Anruf-Probe: erreichbar auch in der App
Filipe: „geht es nicht auf der app?"

Nein -- und das war mein Fehler. Ich hatte eine Seite gebaut, die
sagt, WARUM es nicht klingelt, und sie war nur ueber die Adresszeile
erreichbar. In der installierten App gibt es keine. Eine Hilfe, die
man nicht aufrufen kann, ist keine.

Zwei Wege dorthin, beide genau da, wo man hinschaut, wenn etwas nicht
stimmt:

  * Ein „?" neben den Anrufknoepfen im Chat -- dauerhaft da, auch
    ohne laufenden Anruf. Wichtig fuer die andere Seite: Wer angerufen
    wird und nichts hoert, sieht gar keinen Anrufkasten.
  * Und „Klingelt nichts?" im Anrufkasten selbst, fuer den, der gerade
    vergeblich anruft.

Beide klein und ohne Farbe: Wer telefoniert, soll sie uebersehen; wer
ratlos dasitzt, findet sie.

pruef-anruf weiterhin 106, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 00:29:41 +02:00
DogFatherGitandClaude Opus 5 4fdf08d003 Anruf-Probe: eine Seite, die sagt, WARUM es nicht klingelt
Filipe: „funktioniert nichts davon was machst du?"

Zu Recht. Ich habe an einem Abend fuenf Dinge repariert, jedes einzeln
nachgewiesen -- und bei ihm klingelte trotzdem nichts. Der Grund ist
jedes Mal derselbe gewesen: Ich kann von hier aus messen, was der
SERVER tut, aber nicht, was in SEINEM Browser ankommt. Und genau dort
lag es.

Gemessen habe ich gerade wieder: Der Server liefert die richtige Datei
aus (32616 Bytes, Klingelton enthalten), sobald sie mit Stempel
angefordert wird. Ohne Stempel kommt eine sieben Stunden alte Fassung
aus dem Zwischenspeicher. WELCHE von beiden sein Browser anfordert,
sehe ich nicht -- und das ist die Frage, an der alles haengt.

/workspace/anruf-probe.html dreht das um. Sie laeuft in SEINEM Browser
und beantwortet der Reihe nach:

  1. Ist die neue Fassung ueberhaupt geladen? Sie holt anruf.js und
     sieht nach, ob Klingelton und Nachklingeln darin stehen. Fehlen
     sie, kommt die Seite aus dem Zwischenspeicher -- und JEDE
     Reparatur ist unsichtbar, egal wie oft man neu laedt.
  2. Darf der Browser Ton abspielen? (Er erlaubt ihn erst nach der
     ersten Beruehrung -- wer ueber eine Benachrichtigung hereinkommt,
     hoert sonst nichts und haelt das Telefon fuer kaputt.)
  3. Sind Benachrichtigungen erlaubt UND ist ein Geraet beim Server
     angemeldet? Das sind zwei verschiedene Dinge, und die Luecke
     dazwischen sieht man sonst nirgends.
  4. Steht die Verbindung, ueber die das Klingeln kommt?

Dazu ein Knopf, der genau den Klingelton abspielt, den ein Anruf
macht. Wer ihn hoert, weiss, dass es an der Seite nicht liegt.

Am Ende steht EIN Satz: das Wichtigste zuerst, mit dem, was zu tun
ist. Keine Liste zum Selbstdeuten.

Sie ruft niemanden an und zeigt nichts ueber andere.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 00:14:01 +02:00
DogFatherGitandClaude Opus 5 00459f47c6 Anruf: "Anruf · 3:42" steht jetzt im Chat, nicht nur der verpasste
Filipe: „im chat soll auch stehen verpasster anruf oder anruf gehabt
und wie lange."

Die zweite Haelfte. Ein verpasster Anruf steht seit heute drin -- ein
GEFUEHRTER stand nirgends. Nach dem Auflegen war das Gespraech spurlos
weg.

Tage spaeter ist die Frage aber nicht „hat er angerufen", sondern
„haben wir das besprochen oder nur kurz telefoniert?". Drei Minuten
sind ein Gespraech, zwoelf Sekunden sind ein Verwaehlen. Eine Zeile
ohne Zahl beantwortet das nicht.

GEZAEHLT AB DEM RANGEHEN, nicht ab dem Klingeln. Sonst staende bei
jedem Anruf eine halbe Minute zu viel darin -- die Zeit, in der das
Telefon nur laeutete. Dafuer merkt sich der laufende Anruf jetzt zwei
Dinge zusaetzlich:

  * `gespraechSeit` -- gesetzt, wenn der Zweite dazukommt.
  * `anrufer`       -- wer begonnen hat. `wer` ist die Runde der
                       gerade Anwesenden; sie leert sich, und am Ende
                       laesst sich daraus nicht mehr ablesen, von wem
                       der Anruf ausging. Die Zeile steht bei ihm, wie
                       bei jedem Telefon.

Unter einer Minute steht die Sekundenzahl („7 Sekunden"), darueber
Minuten („3:42 Minuten") -- „0:07" liest sich umstaendlicher, als es
ist.

Geprueft: pruef-anruf 101 -> 106. Der neue Abschnitt fuehrt einen
echten Anruf: anrufen, rangehen, kurz warten, beide auflegen -- und
misst dann, dass genau EINE Zeile entsteht, dass sie „Anruf" sagt und
nicht „verpasst", und dass die Dauer in SEKUNDEN steht. Stuende dort
die Zeit seit dem Klingeln, waeren es Minuten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-19 00:02:58 +02:00
DogFatherGitandClaude Opus 5 c87c396ef5 Anruf: es klingelt jetzt wirklich -- vorher gab es gar keinen Ton
Filipe: „ist das normal dass es nicht mal klingelt wenn man anruft?"

Nein. Und der Grund war so einfach wie peinlich: Es gab ueberhaupt
keinen Ton. Weder beim Anrufer noch beim Angerufenen. Der Anruf zeigte
einen Kasten auf dem Bildschirm, sonst nichts -- wer nicht zufaellig
hinsah, merkte nichts, und wer anrief, wusste nie, ob ueberhaupt etwas
passiert.

Damit erklaert sich auch, warum heute Abend alles „kaputt" wirkte,
obwohl Verbindung, Raum, Anmeldung und Code stimmten: Ein stummes
Telefon ist von einem defekten nicht zu unterscheiden.

ZWEI TOENE, JE NACH SEITE:
  Angerufener  zwei weiche Toene (880/660 Hz), dann Pause -- alle
               2,4 Sekunden, dazu Vibration, wo das Geraet sie kann.
  Anrufer      ein leiseres, langsameres Freizeichen (440 Hz). Ein
               stiller Kasten mit laufender Uhr sagt nur, DASS etwas
               passiert; ein Freizeichen sagt, was.

OHNE TONDATEI. Ein .mp3 waere eine Datei mehr im Netz, eine
Lizenzfrage und ein Ladefehler, der genau dann auffaellt, wenn man ihn
braucht. Zwei Sinustoene aus dem Browser reichen. Sanft ein- und
ausgeblendet, weil ein hart geschalteter Sinus knackt -- und das
Knacken ist das Unangenehme daran.

Der Ton hoert auf, sobald jemand rangeht (`dabei`), sobald die
Verbindung steht und beim Auflegen. Drei Stellen, weil ein
Freizeichen, das waehrend des Gespraechs weiterlaeuft, das ist, was
man an Telefonanlagen hasst.

EHRLICH DAZU: Browser lassen Ton erst zu, wenn jemand auf der Seite
etwas angeklickt hat. Wer die Seite gerade erst geoeffnet hat, hoert
unter Umstaenden nichts -- dann bleibt die Benachrichtigung des
Geraets der Weg. Das ist eine Regel des Browsers, keine Entscheidung
von uns.

Geprueft: pruef-anruf 100 -> 101. Gemessen wird am Oszillator, nicht
am Lautsprecher: Ob wirklich etwas zu hoeren ist, haengt an Geraet und
Lautstaerke -- dass die Seite Toene ERZEUGT, laesst sich messen.
Gegenprobe (Freizeichen ausgebaut): „0 Toene erzeugt", rot.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 23:59:25 +02:00
DogFatherGitandClaude Opus 5 0137ced9c2 Anruf: die Ruhezeit hat ihn verschluckt
Filipe um 23:44 Uhr: „sie bekommt nur eine benarichtigung das eine
neue nachricht ist aber sonst nichts irgendwas laeuft da gewaltig
schief."

Serverseitig war ALLES in Ordnung, und das war das Verwirrende: Der
Anruf kam an, der Raum stimmte (Dogfather + VanVan), sie war
angemeldet, sie hatte ein Geraet, der neue Code lief. Trotzdem klang
nichts.

Die Ursache war eine einzige Zeile in workspace-push.js, die ich beim
Bauen des Anrufs nie gesehen hatte:

    if (art !== "test" && istRuhezeit()) return { grund: "ruhezeit" };

RUHE_AB = 22. Es war 23:44. Die Benachrichtigung wurde gar nicht erst
verschickt -- ihr Geraet konnte nicht klingeln, weil es nichts zu
klingeln gab.

Fuer eine Aufgabenerinnerung ist die Regel genau richtig: Die schickt
der Server von sich aus, weil eine Frist naeher rueckt. Ein Anruf ist
das Gegenteil -- ein Mensch drueckt gerade auf den Hoerer und wartet.
Ein Telefon, das nachts stumm bleibt, ist kein Telefon.

ANRUFE SIND JETZT EINE EIGENE ART. Zwei Dinge auf einmal:

  * Sie umgehen die Ruhezeit.
  * Und sie lassen sich getrennt abschalten. Vorher gingen sie als
    „chat_nachricht" hinaus -- wer die Benachrichtigungen fuer den
    Chat abstellt, haette damit auch Anrufe abgestellt, ohne es zu
    wissen. Das sind zwei verschiedene Entscheidungen.

Wer nachts seine Ruhe will, schaltet „Jemand ruft an" ab. Eine
Entscheidung, die man selbst trifft, statt einer Regel, die man nicht
kennt.

Geprueft: server/pruef-anruf-ruhezeit.mjs, 6 Pruefungen. Sie stellt
die Ruhezeit auf „rund um die Uhr", damit sie nicht tagsueber gruen
und nachts rot ist, und unterscheidet am RUECKGABEGRUND: "ruhezeit"
heisst haengengeblieben, "keine_geraete" heisst durchgekommen. Dazu
die Gegenprobe, dass eine erfundene Art durchfaellt -- sonst waere
„nicht ruhezeit" auch fuer etwas wahr, das nie verschickt wird.

pruef-anruf weiterhin 100, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 23:50:28 +02:00
DogFatherGitandClaude Opus 5 31906e9216 Pruefung berichtigt: die kurze Klingeldauer galt fuer den ganzen Lauf
Der Commit davor ging mit EINEM roten Test hinaus -- ich habe das
Ergebnis nicht angesehen, weil Pruefung und Commit in derselben Kette
liefen. Das war der Fehler, nicht der rote Test selbst.

Die Ursache war die Pruefung, nicht der Code: ANRUF_KLINGELT_SEKUNDEN
stand auf 2, und das gilt fuer den GANZEN Lauf. Im Browser-Teil
vergehen zwischen "anrufen" und "der Server kennt den Anruf" mehrere
Sekunden -- dort war er damit schon verfallen. Jetzt zehn Sekunden:
lang genug fuer den Browser, kurz genug, dass Abschnitt 5e nicht zur
Geduldsprobe wird.

100 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 23:32:44 +02:00
DogFatherGitandClaude Opus 5 e43fe97550 Anruf: zwei Minuten Zeit -- und ein verpasster Anruf bleibt sichtbar
Filipe: „das mit dem anruf klappt nicht … es geeeeeht einfach nicht."

NACHGEMESSEN WAR SERVERSEITIG ALLES IN ORDNUNG: Der Anruf kam an
(Protokoll), der Raum stimmte (Dogfather + VanVan), sie war angemeldet
(Sitzung bis morgen frueh), sie hat ein Geraet fuer
Benachrichtigungen, und der neue Code lief. Trotzdem ging es nicht --
und zwar aus zwei Gruenden, die beide nichts mit Technik zu tun haben,
sondern mit Zeit und Sichtbarkeit.

1. 45 SEKUNDEN SIND KEIN KLINGELN. Bei einem Telefon hebt man ab.
   Hier muss in dieselben Sekunden: Benachrichtigung zustellen,
   bemerken, Handy entsperren, antippen, App laden, Anmeldung pruefen.
   Das reicht, wenn man das Geraet in der Hand haelt -- und sonst nie.
   Jetzt zwei Minuten: lang genug, um aus der Tasche zu kommen, kurz
   genug, dass niemand vor einem Anruf sitzt, den es nicht mehr gibt.

2. UND DANACH WAR ES, ALS WAERE NIE ETWAS GEWESEN. Ein verpasster
   Anruf verschwand lautlos: keine Zeile, kein Hinweis, nicht einmal,
   DASS jemand angerufen hat. Genau das fuehlt sich an wie „geht
   nicht", auch wenn alles funktioniert hat. Jedes Telefon der Welt
   zeigt einen verpassten Anruf; jetzt steht er als Zeile im Gespraech,
   beim Anrufer, mit Uhrzeit.

Geprueft: pruef-anruf 95 -> 100. Der neue Abschnitt misst den echten
Ablauf (anrufen, niemand geht ran, Zeile erscheint) und dass sie NUR
EINMAL erscheint -- `aufraeumen()` laeuft bei jeder Anfrage mit.

Dafuer ist die Klingeldauer ueber die Umgebung einstellbar: Eine
Pruefung, die zwei Minuten wartet, wird abgeschaltet, und dann waere
der verpasste Anruf wieder ungeprueft. Im Betrieb steht die Variable
nirgends.

Und noch ein eigener Messfehler: Die Pruefung las zuerst
/api/chat/raum/:id -- die Route heisst /api/chat/raeume/:id/nachrichten.
Sie meldete „0 Nachrichten, vorher wie nachher" und sah damit aus wie
ein Befund ueber den Code.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 23:30:52 +02:00
DogFatherGitandClaude Opus 5 4ea7b37333 Anruf: "sie kriegt nur eine Benachrichtigung aber keinen Anruf"
Filipe, gerade gemeldet. Es waren ZWEI Fehler, und beide erklaeren
genau das, was er gesehen hat.

--- 1. Die Benachrichtigung sagte nicht, dass es ein Anruf ist ------

Gemessen kam bei ihr an:

    Nachricht von [object Object]
    (kein Text)

`nachricht.von` ist beim Klingeln ein OBJEKT (`{id, name}`) und keine
Zeichenkette; einen `text` gibt es bei einem Anruf gar nicht. Moeglich
wurde beides, weil die ART des Ereignisses die Benachrichtigung nie
erreichte: `chatEreignis` nimmt sie als vierten Parameter entgegen,
reichte sie aber nur in den Ereignisstrom weiter. Fuer den Push galt
jedes Ereignis als Chatnachricht -- auch das Klingeln.

Jetzt steht dort "Filipe ruft an" / "Tippen zum Rangehen", und beim
Tippen landet man im richtigen Gespraech.

--- 2. Und dort klingelte es dann trotzdem nicht --------------------

Das Klingeln lief ausschliesslich ueber den offenen Ereignisstrom. Wer
zusieht, hoert es. Wer die Seite NICHT offen hat, bekommt die
Benachrichtigung, tippt darauf, die Seite laedt -- und bleibt still.
Das Ereignis war vorbei, bevor sie da war.

Der Anruf funktionierte damit ausgerechnet fuer die nicht, fuer die
die Benachrichtigung ueberhaupt gebaut wurde.

Neu: `GET /workspace/api/anruf/offen` -- beim Laden fragt die Seite
einmal nach, ob in einem ihrer Raeume jemand wartet. Nur was noch
klingelt (45 s), nur Raeume, in denen die Person drin ist, und nicht
beim Anrufer selbst.

--- Gepruefte Wege -------------------------------------------------

pruef-anruf 80 -> 95. Zwei neue Abschnitte, beide mit Gegenprobe:
Route stillgelegt -> 3 rot; der Text ist jetzt einzeln pruefbar
(`pushTextFuer`), weil er vorher tief in einer Funktion entstand, die
nur der Push-Weg aufruft -- von aussen nicht messbar.

Nebenbei gefunden: `istDrinFuerAnruf` braucht die PERSON, nicht ihre
Nummer, und sagt das mit einem eigenen TypeError. Meine erste Fassung
uebergab die Nummer.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 23:01:13 +02:00
DogFatherGitandClaude Opus 5 2b74e40007 Startseite: der Ring zaehlte Aufgaben -- ein Zuschauer hat keine
Nach dem Aufgabenblock und der dritten Zahl war noch ein Rest da, und
zwar der auffaelligste: In der Mitte der Seite stand gross

    100 %
    HEUTE NICHTS OFFEN

Der Ring zaehlt AUFGABEN -- was heute faellig war und was davon fertig
ist. Ein Mitglied hat keine, also stand dort dauerhaft 100 %. Dieselbe
tote Zahl wie "0 betreut" daneben, nur groesser.

Was ein Mitglied an dieser Stelle wissen will, ist etwas anderes:
Laeuft heute noch etwas? Der Ring zaehlt bei ihm jetzt die TERMINE des
Tages und faerbt, was davon vorbei ist. Bei null Terminen sagt er das
in Worten ("Heute steht nichts an") statt eine Null als Prozentzahl
auszugeben -- jede Prozentangabe waere da eine Behauptung ueber
nichts.

Dafuer kann der Server jetzt `mitte` schicken: einen Text fuer die
Ringmitte. Fehlt das Feld, bleibt alles wie bisher -- fuer alle
anderen aendert sich nichts.

UND DER FUSSTEXT ERKLAERTE EINEN KASTEN, DEN ES NICHT GAB. Unten stand
"„Was ist dran" fuehrt keine eigene Liste, sondern zeigt ..." -- der
Kasten selbst erscheint aber nur, wenn er etwas zu zeigen hat, und bei
einem Mitglied nie. Eine Erklaerung fuer etwas, das nicht da ist, ist
schlimmer als keine: Man sucht danach. Sie verschwindet jetzt mit ihm.

Gemessen (Handy): Startseite 1781 -> 1634 px.
pruef-community-sicht 10, pruef-zentrale-ring 14, pruef-vorlagen 24 --
alle ohne Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 22:16:53 +02:00
DogFatherGitandClaude Opus 5 fa34017809 Community-Pruefung: auch auf dem Handy, und ohne feste Schwelle
Die Community ist ueberwiegend mit dem Telefon unterwegs -- eine
Messung auf 1400 px beantwortet fuer sie die falsche Frage. Und genau
auf dem Handy waren heute die haesslichsten Sachen: drei verschiedene
Kartenanordnungen, ein Hinweis quer ueber der naechsten Beschriftung.

Dabei fiel gleich eine feste Zahl auf: Die Pruefung verlangte
mindestens 20 sichtbare Wege. Auf dem Rechner sind es 27, auf dem
Handy 18 -- dort klappt die Kopfleiste um. Die Pruefung wurde also auf
der zweiten Breite rot, ohne dass etwas falsch war.

Sie auf 15 zu senken waere derselbe Fehler mit einer anderen Zahl.
Verlangt wird jetzt, was die Sache selbst hergibt: mindestens ein
sichtbarer Weg je Seite. Findet sich weniger, hat etwas nicht geladen
-- und dann ist "0 tote Wege" kein Ergebnis, sondern ein Messfehler.

10 Pruefungen, 0 Fehler, auf beiden Breiten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 22:10:55 +02:00
DogFatherGitandClaude Opus 5 ed8c83af09 Community: zwei Namen fuer zwei Sachen -- und ein praeziserer Satz
DIE LETZTEN BEIDEN SEITEN ANGESEHEN, die einem Mitglied offenstehen.
Sie standen bisher nur in der Messung ("keine toten Wege, keine fremde
Sprache") -- angesehen hatte ich sie nie.

1. ZWEIMAL "REGELN & HILFE". Die Seite mit den fuenf Regeln hiess
   genauso wie das BRETT, auf das sie verweist. Auf dem Brett stand
   damit ein Link "Regeln & Hilfe", der auf eine Seite namens "Regeln
   & Hilfe" fuehrte -- wer ihn drueckte, glaubte im Kreis gelaufen zu
   sein. Und dieser Link steht auf JEDEM Brett des Treffs.

   Es sind zwei verschiedene Dinge: Hier die fuenf Regeln, kurz und
   fest. Dort ein Brett, das daneben haeufige Fragen, Hilfe und die
   Folgen sammelt. Die Seite heisst jetzt "Die Regeln".

2. "GESPEICHERT WIRD ERST, WENN DU ABSCHICKST" -- daneben stand "du
   kannst zwischendurch aufhoeren und spaeter weitermachen". Beides
   zusammen kann nicht stimmen, und nachgemessen stimmt der zweite
   Satz: bewerben.js legt einen Entwurf im Browser ab (localStorage).

   Der alte Satz war also nicht falsch, aber missverstaendlich -- er
   meinte "an uns uebermittelt wird erst beim Abschicken" und klang
   nach "nichts wird gespeichert". Bei einem Formular mit sechzehn
   Feldern ist das der Unterschied zwischen "ich mache spaeter weiter"
   und "ich fange lieber gar nicht erst an". Und es ist eine
   Datenschutzauskunft: Wer an einem fremden Geraet sitzt, sollte
   wissen, dass die Antworten dort liegen bleiben.

Die Bewerbungsseite selbst ist im Uebrigen vorbildlich: jedes Feld mit
"noetig"/"freiwillig" markiert, Hilfetexte, die ehrlich sind ("Ehrlich
ist besser als beeindruckend"), und am Ende steht, wer es liest.

pruef-community-sicht: 7 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 22:04:59 +02:00
DogFatherGitandClaude Opus 5 542070e864 Community: der Chat-Knopf fuehrte auf JEDER Seite ins Leere
ERST DIE METHODE, DANN DER FUND. An einem Tag habe ich in der
Community elf Dinge gefunden, die dort nicht hingehoerten -- jedes
einzelne, weil ich zufaellig hingesehen habe. Das ist keine Methode.
Der Workspace ist fuer die Agentur gebaut worden, und die Community
hat ihn geerbt; solche Reste findet man nicht durch Nachdenken,
sondern indem man ALLE Seiten durchgeht, die ein Mitglied erreichen
kann.

server/pruef-community-sicht.mjs tut genau das. Sie leitet aus
rechte.js ab, welche Seiten offenstehen (4) und welche nicht (27) --
von Hand aufgezaehlt waere das eine Liste, die bei der naechsten Seite
niemand nachzieht --, oeffnet jede davon als Mitglied und fragt
zweierlei: Fuehrt ein sichtbarer Weg auf eine verbotene Seite? Steht
dort die Sprache eines Arbeitsplatzes?

BEIM ERSTEN LAUF: 27 sichtbare Wege, davon ZEHN ins Leere -- und alle
zehn derselbe Knopf. Der Chat steht oben rechts in der Kopfleiste, auf
jeder einzelnen Seite, mit Zaehler. `chat.html` steht einem Mitglied
aber nicht offen: Der Klick landet wieder auf der Startseite. Keine
Meldung, kein Grund, nichts passiert -- an der Stelle, die man am
ehesten drueckt.

Der Knopf haengt jetzt an `darf_chat` aus /api/ich, und das kommt aus
derselben Rechtetabelle wie die Schranke dahinter. Die Oberflaeche
vergleicht keine Rollennamen -- das waere eine zweite Wahrheit, die
bei der naechsten Rechteaenderung auseinanderlaeuft. Dieselbe
Ueberlegung steht zwei Zeilen weiter oben schon einmal.

UND DIE PRUEFUNG HAT GLEICH MEINEN EIGENEN FEHLER GEFUNDEN: Die erste
Fassung stand in `aufbauChat`, wo es die Person gar nicht gibt --
ReferenceError auf allen zehn Seiten. Ohne den Skriptfehler-Abschnitt
waere der Knopf verschwunden UND die Seite kaputt gewesen, und das
haette wie ein Erfolg ausgesehen.

Jetzt haengt es dort, wo die Person ankommt (`werZeigen`) -- ein
vorhandener Knopf laesst sich immer entfernen, auf die Reihenfolge des
Ladens zu bauen waere eine Annahme.

GEGENPROBE: DogFather hat seinen Chat-Knopf weiterhin und 24 Wege auf
andere Seiten. Ohne diesen Abschnitt saehe eine abgeschaffte Funktion
genauso aus wie eine, die richtig entscheidet.

7 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 21:59:53 +02:00
DogFatherGitandClaude Opus 5 c2a8c5f15f Zentrale: "0 betreut" war fuer die Community dieselbe tote Zahl
Im Code stand die Loesung schon -- fuer jemand anderen. Am 10.09.2026
wurde dort vermerkt:

  "BETREUT" IST FUER EINEN MODI IMMER NULL. Er betreut keine Creator.
  Auf seiner Startseite stand deshalb dauerhaft "0 betreut": eine
  Zahl, die nie etwas anderes sagen kann, und damit schlimmer als
  keine. Wer sie sieht, sucht nach dem Fehler.

Fuer ein Mitglied der Community gilt das erst recht -- und dort blieb
es stehen. Dieselbe Zahl, derselbe Grund, dieselbe Wirkung.

Jetzt steht dort, was die Community wirklich betrifft: WUENSCHE OFFEN.
Der Ort, an dem sie mitentscheidet, was als Naechstes passiert -- eine
Zahl, die zum Hingehen einlaedt, statt eine, die nichts sagt.

WORAN DIE ENTSCHEIDUNG HAENGT: `freigabeBedingung` gibt nur fuer Leute
von aussen eine SQL-Bedingung zurueck, sonst null. Damit ist die Frage
"ist das jemand aus der Community" schon beantwortet, ohne dass hier
ein Rollenname steht -- und dieselbe Bedingung sorgt dafuer, dass nur
gezaehlt wird, was diese Person auch sehen darf.

GEMESSEN, beide Seiten:
  Community : "4 Wuensche offen"
  DogFather : "2 im Team" (unveraendert)
pruef-zentrale-ring: 14 Pruefungen, 0 Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 21:44:27 +02:00
DogFatherGitandClaude Opus 5 4f5ac04bc9 Startseite: ein Zuschauer hat keine Aufgaben -- und keine toten Knoepfe
ZUM ERSTEN MAL MIT GAST-AUGEN ANGESEHEN. Gemessen wurden bisher immer
nur die sieben Bretter, nie die Seite davor -- dabei ist sie das
Erste, was ein Mitglied sieht.

Sie zeigte:
  "DEINE AUFGABEN" mit sieben Zaehlern (Ueberfaellig, Heute faellig,
  Offen, In Arbeit, Review, Erledigt, Abgebrochen), darunter "Nichts
  offen. Alles abgearbeitet - goenn dir was." und im Kopf "Nichts
  liegt an - guter Tag zum Vorarbeiten."

Das ist die Sprache eines Arbeitsplatzes. Eine Zuschauerin hat hier
keinen: Sie arbeitet nicht vor, ihr wird nichts zugewiesen, und
"Review" sagt ihr nichts.

UND JEDE DER SIEBEN ZAHLEN WAR EIN LINK auf aufgaben.html. Die
Rechtetabelle nennt dort "ALLE" -- was die Rolle der Community
ausdruecklich NICHT einschliesst. Nachgemessen: Ein Klick landet
wieder auf start.html. Sieben tote Knoepfe, und der Kommentar direkt
daneben sagt selbst: "Ein toter Knopf ist keine Antwort."

WORAN DIE ENTSCHEIDUNG HAENGT -- nicht an der Rolle. Rollennamen der
Community gehoeren nicht in eine Datei, die jeder herunterladen kann
(pruef-modi-wortleck wacht darueber, und ROLLENTEXT laesst sie aus
demselben Grund aus). Gefragt wird stattdessen nach etwas, das der
Server ohnehin beantwortet hat: Hat diese Person die Aufgaben-Kachel?
Er schickt nur, was jemand sehen darf. Keine zweite Wahrheit, kein
Rollenname -- und es bleibt richtig, wenn sich die Rechte aendern.

GEGENPROBE IM MESSWERKZEUG: ein zweiter Durchgang als DogFather auf
derselben Seite.
  DogFather : Block DA, 7 Links, "Vorarbeiten" ja
  Community : Block weg, 0 Links, keine Arbeitswoerter
Ohne diesen Durchgang saehe eine abgeschaffte Funktion genauso aus
wie eine, die richtig entscheidet.

Nebenbei: Die Startseite ist fuer die Community von 1436 auf 1231 px
geschrumpft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 21:30:23 +02:00
DogFatherGitandClaude Opus 5 e128c169b9 Community: das Handy aufgeraeumt, und leere Bretter zeigen keine Filter
BISHER HABE ICH AM RECHNER GEMESSEN. Die Community ist ueberwiegend
mit dem Telefon unterwegs -- also 412 px, alle sieben Bretter.

1. FUENF KARTEN, DREI VERSCHIEDENE ANORDNUNGEN. Am Rechner stehen
   Etikett, Titel und Zustand nebeneinander, und das ist richtig. Auf
   412 px hing es an der LAENGE des Etiketts: Bei "SONSTIGES" passte
   der Titel noch daneben und "Offen" rutschte darunter; bei "FUER DEN
   STREAM" stand das Etikett allein oben und "Offen" ploetzlich RECHTS
   vom Titel. Inhaltlich unterschied sich nichts -- man liest es als
   Unordnung.

   Unter 560 px jetzt feste Reihenfolge: die Marken oben nebeneinander,
   der Titel darunter ueber die volle Breite. Immer gleich.

2. "ERLEDIGT" STAND ZWISCHEN NAME UND ROLLE: "von Filipe · erledigt ·
   DogFather". Der Rollenname gehoert zum Namen davor, und "erledigt"
   ist eine Aussage ueber den Eintrag, nicht ueber die Person --
   dazwischen gelesen wirkt es, als sei jemand erledigt.

3. FILTER FUER NICHTS. Am ersten Tag steht auf jedem Brett ein Satz wie
   "Noch hat niemand Hallo gesagt. Sei der Erste - ein Satz reicht."
   Darueber standen fuenf Filterknoepfe. Das ist die schlechteste
   Stelle fuer Bedienelemente, die ins Leere fuehren: Wer zum ersten
   Mal hier ist, soll den Satz lesen und schreiben.

   Wie bei "Nur offene" ist `!filter` der wichtige Teil: Ist die Liste
   leer, WEIL gefiltert wird, bleibt die Reihe stehen -- sonst kaeme
   man nie wieder zu "Alle" zurueck. Gemessen: leer 0 Filter, mit
   Inhalt 5 bzw. 6.

UND DAS MESSWERKZEUG KANN JETZT LEERE BRETTER ZEIGEN (LEER=ja). Die
Texte dafuer gibt es seit Langem -- gesehen hatte sie noch niemand,
weil jede Messung vorher erst den Startkatalog uebernimmt. Genau
deshalb war der Filter dort nie aufgefallen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 20:24:10 +02:00
DogFatherGitandClaude Opus 5 447a4157a5 Community: die Koepfe sagen jetzt, wofuer das Brett da ist
DIE SIEBEN BRETTER HATTEN KEINE UNTERZEILE. Ein Mitglied sah nur:

    — TERMINE
    Was ansteht
    Hier schreibt das Team.

Die Oberzeile ist eine Kategorie, kein Satz; darunter stand
ausschliesslich, OB man schreiben darf -- auf drei Brettern sogar
wortgleich dasselbe. Was das Brett IST und was man hier tut, stand
nirgends.

Jetzt sagt jeder Satz zwei Dinge: wofuer das Brett da ist und was man
konkret tut. Zum Beispiel: "Was ihr euch wuenscht. Drueck ,Will ich
auch' - danach wird sortiert, was am meisten gewollt ist." Der Hinweis
aufs Schreibrecht haengt sich dahinter, in dieser Reihenfolge: "was
ist das hier" kommt vor "darf ich mitmachen".

--- Zwei Funde aus der Highlights-Galerie ---------------------------

1. DREI KARTEN, DREI HOEHEN. `align-items: start` liess jede Karte
   dort enden, wo ihr Text aufhoerte. Eine Galerie ist ein Raster --
   ungleiche Kanten liest man als Fehler, nicht als Absicht. Jetzt
   gleich hoch (gemessen: aus 3 verschiedenen Hoehen wurde 1).

2. "NUR OFFENE" AUF BRETTERN OHNE ZUSTAENDE. Fuenf der sieben kennen
   gar kein "offen/erledigt" -- ein Clip ist nicht erledigt. Der Knopf
   stand trotzdem ueberall und tat dort nichts. Ein Knopf, der nichts
   tut, kostet das Vertrauen in den naechsten.

   Er erscheint jetzt nur, wenn die Liste ueberhaupt etwas Erledigtes
   enthaelt -- dieselbe Regel wie bei der Kanalzeile. Das `||
   filter === 'offen'` daneben ist kein Beiwerk: Ist der Filter aktiv,
   sieht man gerade keine erledigten mehr, und der Knopf wuerde unter
   der eigenen Hand verschwinden.

   GEGENPROBE IM MESSWERKZEUG: Ein Wunsch wird auf erledigt gesetzt.
   Wunschliste 6 Filter (mit "Nur offene"), Highlights 5 (ohne).
   Ohne diesen Eintrag saehe eine abgeschaffte Funktion genauso aus
   wie eine, die richtig entscheidet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 20:16:55 +02:00
DogFatherGitandClaude Opus 5 6e062b2439 Community: ein Ton je Art -- gesucht, nicht geraten
Alle Etiketten trugen denselben blauen Ton. Auf "Regeln & Hilfe"
stehen siebzehn Karten untereinander, auf dem Treff acht -- das Auge
hatte nichts, woran es sich festhalten konnte. Man liest dann jede
Ueberschrift, statt zu ueberfliegen.

NACH BEDEUTUNG, NICHT NACH REIHENFOLGE. Lob gruen, "etwas stimmt
nicht" warmrot, Fragen blau, Regeln golden. Deshalb traegt die Art
"frage" auf drei Brettern denselben Ton: Wer das Muster einmal
gelernt hat, soll es wiedererkennen.

WARUM EIN WERKZEUG UND KEINE FARBLISTE. Der erste Versuch war von
Hand: feste Helligkeit, Buntheit nach Gefuehl. Vier Toene lagen
ausserhalb des darstellbaren Bereichs, drei Paare zu nah. Nach dem
Nachbessern waren es fuenf zu nahe Paare -- wer die Buntheit eines
Violetts senkt, schiebt es naeher an alles andere Gedaempfte. Zwei
Zahlen von Hand zu stimmen, waehrend eine dritte Bedingung mitlaeuft,
geht nicht auf. Das ist eine Suche, keine Wahl.

tools/art-farben.mjs sucht deshalb selbst: Der Farbwinkel steht fest
(das ist die Entscheidung), Helligkeit und Buntheit werden gesucht --
unter drei Bedingungen gleichzeitig: in sRGB, Kontrast mindestens
4,5:1 auf dunklem Grund, und mindestens 0,10 OKLab-Abstand zu jeder
Art, die auf DEMSELBEN Brett vorkommt. Ueber Bretter hinweg darf sich
ein Ton wiederholen -- man sieht nie zwei gleichzeitig.

UND ES SUCHT DIE LEISESTE FASSUNG, nicht die kraeftigste. Der erste
Durchlauf maximierte die Buntheit; heraus kamen #35f695 und #f584fd --
Neongruen und Neonviolett. Das widerspricht der Hausregel ("gedeckte
statt reisserisch-grelle Neon-Optik"), und bei siebzehn Karten waere
es eine Leuchtreklame. Jetzt: gerade bunt genug, um sie zu
unterscheiden. Buntheit ist eine Kostenstelle, kein Ziel.

Ergebnis: 23 Toene, 39 Paare geprueft, engstes Paar je Brett 0,100.

DAS WERKZEUG PRUEFT AUCH DAS CSS gegen seine eigene Rechnung. Ohne
das misst es nur sich selbst: Wer einen Ton von Hand aendert, bliebe
unbemerkt -- genau die Art Pruefung, die immer bestaetigt. Gegenprobe:
ein Ton von Hand verstellt -> rot mit Angabe von Soll und Ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 20:10:38 +02:00
DogFatherGitandClaude Opus 5 11c4a795e2 Community: Starthilfe beim Schreiben -- und vier Funde aus den Bildern
Filipe: "perfektioniere jede einzelne kategorie der community ... ich
will auch dass du fertige und beispiele machst fuer die community
damit die auch start hilfe haben ueberall."

STARTHILFE: Wer zum ersten Mal schreibt, steht vor einem leeren Feld
-- der haeufigste Grund, warum ein Brett still bleibt, obwohl viele
mitlesen. Im Formular stehen jetzt Beispiele: ein Klick fuellt Art,
Ueberschrift und Text. Auf treff, wunsch, highlight und mitmachen --
nicht auf anschlag, ansteht, regeln, denn dort schreibt die Community
nicht, und ein Angebot fuer eine verschlossene Tuer ist keins.

JEDE VORLAGE HAT LUECKEN. Eine, die man absenden KANN, wird
abgesendet; dann steht dort zehnmal derselbe Satz, und der elfte
Mensch merkt, dass hier niemand wirklich schreibt. Die Pruefung misst
das: keine Vorlage ohne "…".

NICHT ZU VERWECHSELN MIT DEM STARTKATALOG. Der ist fuers Team (fertige
Beitraege zum Uebernehmen), das hier fuer die Mitglieder.

--- Vier Funde, drei davon nur aus dem Bild -------------------------

1. ZWEI KNOPFREIHEN MIT DENSELBEN WOERTERN. Auf "Regeln & Hilfe"
   standen "Regel · Haeufige Frage · Hilfe · Was passiert, wenn"
   zweimal untereinander -- die eine filterte, die andere sprang zur
   Ueberschrift, und beide sahen gleich aus. Wo nach Art gegliedert
   wird, entfaellt jetzt der Filter; die Sprungmarken sind Links
   geworden, mit "Springe zu" davor und der Anzahl dahinter.

2. "MELDEN" UNTER JEDER REGEL. Siebzehn Melden-Knoepfe unter Texten
   des Teams -- man meldet keine Regel. Steht jetzt nur noch an
   Beitraegen von Mitgliedern. Die Gegenprobe im Messwerkzeug legt
   dafuer eigens einen Beitrag eines zweiten Mitglieds an: Ohne ihn
   saehe ein abgeschaffter Meldeweg genauso aus wie ein
   funktionierender.

3. DER HINWEIS LAG AUF DER NAECHSTEN BESCHRIFTUNG. Auf 412 px stand
   "Gehoert allen hier - wer Der Treff sieht ..." quer ueber
   "UEBERSCHRIFT". Der Hinweis haengt absolut unter dem Feld, und
   darunter sind 30 px Luft -- genug fuer EINE Zeile. Unter 560 px
   steht ohnehin nur ein Feld je Zeile; dort gibt es nichts
   auszurichten, und er darf einfach im Fluss stehen.

4. UND MEIN EIGENER FEHLER, der alles unsichtbar machte: `vorlagen`
   gab es hier schon -- als Checkliste fuer Creator, mit demselben
   Behaelter `#vorlagen`. Die spaetere Funktionsdeklaration gewinnt,
   zwei Elemente trugen dieselbe Kennung, und die Starthilfe erschien
   NIE. Keine Fehlermeldung, keine rote Pruefung, nichts in der
   Konsole. Gefunden nur durch einen Blick auf das Bild.
   Deshalb prueft pruef-vorlagen jetzt im Browser mit, dass keine
   Kennung doppelt vorkommt -- derselbe Fehler wie am 17.09. mit
   `.teilen`, und beim naechsten Mal soll ihn nicht der Zufall finden.

Nebenbei messbar: "Regeln & Hilfe" ist von 4569 auf 3623 px
geschrumpft, die Karten sind 54 px niedriger.

Geprueft: pruef-vorlagen (neu, 24), pruef-video unveraendert 67.
Gegenproben: unbekannte Art -> rot; Vorlage ohne Luecke -> rot.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 19:00:43 +02:00
DogFatherGitandClaude Opus 5 d4e05e460a Community: die echte Sicht messbar machen -- und die Sternchen weg
Filipe: "perfektioniere jede einzelne kategorie der community."

ERST MESSEN. tools/community-blick.mjs meldet sich als GAST an und
fotografiert alle sieben Bretter. Das war noetig, weil als DogFather
auf jedem Brett Knoepfe und Felder stehen, die ein Mitglied nie sieht
-- wer so beurteilt, beurteilt eine Seite, die es fuer die Community
nicht gibt.

Der Weg dorthin war laenger als gedacht, und jeder Umweg steht als
Kommentar im Werkzeug:
  - Die Community hat eine EIGENE Anmeldeseite (crew-index.html); auf
    der anderen gibt es die Rolle "gast" gar nicht.
  - Wer sich zum ersten Mal anmeldet, muss sein Alter bestaetigen
    (400 "alter_offen"), sonst kommt er nicht hinein.
  - Ueber die echte Adresse schickt der Server HSTS, woraufhin
    Chromium alle Unterdateien auf https umbiegt -- der Testserver
    spricht nur http. Ergebnis: eine nackte Seite ohne Stil und ohne
    Skripte, auf der kein Knopf etwas tat. Die Kopfzeile ist richtig
    so und bleibt; stattdessen wird jetzt ueber die Kopfzeile
    angemeldet und das Sitzungsplaetzchen in den Browser gelegt.
Ohne diese drei Punkte fotografiert man die Anmeldeseite und haelt
"0 Karten, kein Schreibfeld" fuer einen Befund ueber die Bretter.

ERSTER BEFUND, BEHOBEN: An zehn Stellen stand **Fettschrift** als
Sternchen im Text. Auf "Regeln & Hilfe" hiess es woertlich "Drei
Stufen: **Hinweis** ..., **Pause** ..., **Ausschluss**" -- ausgerechnet
die drei Stufen, um die es geht, sahen aus wie ein Tippfehler.

KEIN innerHTML: Gebaut wird aus einzelnen Knoten. Was nicht zwischen
zwei Sternchenpaaren steht, wird Text und kann nichts anderes werden.
Ein einzelnes Sternchen bleibt ein Sternchen -- "3 * 4" ist keine
Hervorhebung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 18:33:02 +02:00
DogFatherGitandClaude Opus 5 e933de3248 Anruf: der Lautsprecher -- und warum es kein Freisprech-Knopf ist
Filipe: "die funktion lautsprecher fehlt."

Er ist das Gegenstueck zum Mikrofon: "Mikro aus" heisst, die anderen
hoeren MICH nicht -- "Lautsprecher aus" heisst, ICH hoere sie nicht.
Beides braucht man, aus verschiedenen Gruenden: das Mikro, wenn es bei
einem selbst laut ist; den Lautsprecher, wenn nebenher etwas laeuft
oder jemand ins Zimmer kommt.

WAS BEWUSST NICHT GEBAUT WURDE: der Umschalter zwischen Hoermuschel
und Freisprechen, den ein Telefon hat. Recherchiert statt geraten --
den gibt es im Browser nicht: Auf dem iPhone entscheidet Safari
selbst, wohin der Ton geht, und Android laesst einzelne Toene gar
nicht auf ein anderes Geraet legen (setSinkId ist dort nicht
verfuegbar, weil die Plattform es nicht hergibt). Ein Knopf, der dort
nichts tut, waere schlimmer als keiner -- man drueckt ihn und sucht
den Fehler dann bei sich.

Wo es GEHT (Rechner mit Chrome, Edge, Safari), steht dafuer eine echte
Geraeteauswahl daneben. Sie erscheint nur, wenn es mehr als ein Geraet
gibt UND die Namen bekannt sind; eine Auswahl mit einem Eintrag ist
keine Auswahl, sondern eine Behauptung.

DIE PRUEFUNG, AUF DIE ES ANKOMMT: Kommt jemand dazu oder geht jemand,
werden die Toenelemente NEU GEBAUT -- und neue Elemente wissen nichts
von einem Schalter, der vorher umgelegt wurde. Genau daran scheitern
solche Knoepfe sonst: Sie wirken, bis sich die Runde aendert, und dann
hoert man ploetzlich wieder mit. Gegenprobe (Anwenden nach dem
Neuzeichnen ausgebaut) macht genau diese eine Pruefung rot, waehrend
alle anderen gruen bleiben.

Geprueft: pruef-anruf 73 -> 80, im echten Dreiergespraech im Browser.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 17:08:31 +02:00
DogFatherGitandClaude Opus 5 59c84bd248 Videos: Stufe 7 -- aus einem Wunsch wird ein Video, mit Namen
"Ein Video aus einem Wunsch zeigt den Namen." Wer sich etwas
gewuenscht hat, soll sehen, dass daraus etwas geworden ist -- das ist
der Sinn eines Wunschbretts. Ohne die Verbindung ist die Galerie eine
Sammlung, und der Wunsch von letzter Woche bleibt unbeantwortet im
Raum stehen.

DER KNOPF STEHT AM WUNSCH, nicht im Formular oben. Das ist dieselbe
Entscheidung wie bei den Kettenknoepfen daneben, aus demselben Grund
(dort woertlich): "Wer ein Formular ausfuellt, denkt nicht an den
Wunsch von letzter Woche." Hier denkt er an nichts anderes.

DAS LECK, das es nicht geben darf: Der Titel der Quelle wird auf der
Kachel ANGEZEIGT. Eine Kette in die Content-Planung waere deshalb kein
Schoenheitsfehler, sondern ein Weg, interne Arbeit in die Community zu
tragen. Die Quelle muss ein Community-Brett sein -- dieselbe Regel wie
beim "Daraus"-Knopf.

ZWEI WEGE, EIN ZIEL: "Daraus ein Highlight machen" gibt es laenger.
Wer ihn geht und DANACH das Video einfuegt, bekaeme sonst ein zweites
Highlight aus demselben Wunsch -- zwei Wege zum selben Ziel, die
nichts voneinander wissen. Das Video haengt sich jetzt an den
vorhandenen Eintrag. Der Titel bleibt dabei der des Wunsches: Er
stammt von einem Menschen, der von TikTok ist eine Bildunterschrift
mit Schlagwoertern.

Geprueft: pruef-video 51 -> 67. Gegenprobe (Brett-Pruefung und
Anhaengen ausgebaut) macht 6 rot, darunter "ein Eintrag aus der
Content-Planung kommt NICHT als Quelle durch (201)".

UND DAS BILDSCHIRMFOTO HAT ETWAS GEFUNDEN, das keine Zahl gemeldet
haette: Das Eingabefeld erschien am ENDE der Karte, unter der
Fusszeile -- getrennt von dem Knopf, den man gerade gedrueckt hatte.
Alle Pruefungen waren gruen, das Feld war da und reagierte. Jetzt
haengt es an der Knopfreihe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 17:00:16 +02:00
DogFatherGitandClaude Opus 5 fb55377e19 Videos: Stufe 5 -- fuehrt der Knopf noch irgendwohin?
Ein Video kann bei TikTok geloescht oder auf privat gestellt werden.
Bei uns blieb der Eintrag stehen -- mit Cover, Text und einem Knopf
auf eine Fehlerseite. Das faellt beim Bauen nicht auf und beim Testen
nicht; es faellt dem auf, der klickt, und das ist die Community.

DREI ANTWORTEN, NICHT ZWEI. Die naheliegende Fassung fragt TikTok und
setzt bei einem Fehlschlag "weg". Die waere an einem einzigen
schlechten Nachmittag von TikTok in der Lage, die halbe Galerie als
geloescht zu markieren -- und wer das hinterher sucht, sucht lange,
denn im Protokoll stuende sauber, dass gefragt wurde. Also:

  Daten kommen an       -> da. Zaehler zurueck, eine frueher gesetzte
                           Markierung faellt weg (privat gestellte
                           Videos kommen wieder).
  "gibt es nicht" (404) -> ein Fehlversuch. Erst der DRITTE an drei
                           verschiedenen Tagen markiert.
  niemand antwortet     -> weiss nicht. Aendert gar nichts, nicht
                           einmal den Zeitstempel: Wer ihn setzte,
                           verschoebe die naechste Nachfrage um sieben
                           Tage, obwohl nichts gemessen wurde.

Drei Geschwindigkeiten beim Nachsehen: unauffaellig woechentlich,
verdaechtig taeglich (sonst dauerte eine Loeschung drei Wochen bis zur
Anzeige), schon markiert wieder woechentlich -- taeglich nachzufragen
waere Hammern fuer eine Auskunft, die wir schon haben. Gefunden hat
das eine rote Pruefung, nicht das Nachdenken davor.

Der Knopf verschwindet nicht, er sagt "Bei TikTok nicht mehr da".
Bewusst kein Rot: Es ist kein Fehler, sondern eine Auskunft -- Titel,
Text und Cover stimmen weiter, die liegen bei uns.

Geprueft: pruef-video 37 -> 51. Gegenprobe (Stoerung als "weg" werten
plus Markieren ab dem ersten Versuch) macht 8 rot, darunter woertlich
"eine Stoerung erhoeht den Zaehler NICHT (0 -> 1)".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 16:08:15 +02:00
DogFatherGitandClaude Opus 5 88a8712638 Messung von aussen: traegt die Vermittlung wirklich?
Dass der Server auf 3478 antwortet, beweist nur, dass der Dienst
laeuft und dieser eine Port offen ist. Ein vermittelter Anruf laeuft
ueber einen ZWEITEN Port, den coturn erst bei der Zuteilung vergibt.
Ist der Bereich 49160-49260 in der Firewall zu, antwortet STUN
weiterhin brav, die Zuteilung gelingt sogar -- und es kommt trotzdem
kein Ton an. Das faellt erst im echten Anruf auf, und auch dann nur
bei denen, die die Vermittlung ueberhaupt brauchen.

Deshalb wird bis zum Schluss gemessen: zuteilen lassen, sich selbst
als Gegenstelle eintragen, ein Paket ueber die zugeteilte Adresse
schicken, nachsehen ob es ankommt. Live von aussen gelaufen:
7 Pruefungen, 0 Fehler, Relay-Port 49190.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 15:36:20 +02:00
DogFatherGitandClaude Opus 5 00f0271ea6 Probelauf prueft auch die Abfrage des Einrichtungswerkzeugs
Die STUN-Abfrage in turn-einrichten.mjs hatte noch nie einen
antwortenden Server gesehen. Eine Abfrage, die immer "keine Antwort"
sagt, laesst uns an der Firewall suchen, waehrend dort nichts falsch
ist. Jetzt gemessen: mit laufendem Server erkennt sie ihn, ohne meldet
sie ihn als nicht erreichbar.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 15:27:10 +02:00
DogFatherGitandClaude Opus 5 12b0438dc2 Auch .conf-Dateien mit Unix-Zeilenenden
deploy/turnserver.conf hatte keine Regel. Heute steht LF darin, weil
sie so angelegt wurde -- wer sie unter Windows bearbeitet und
speichert, haengt aber an jede Zeile ein unsichtbares Zeichen. Aus
static-auth-secret=abc wuerde dann ein Geheimnis, das auf CR endet,
und coturn wiese jeden Anruf ab, ohne dass die Datei falsch aussieht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 15:22:59 +02:00
DogFatherGitandClaude Opus 5 775c4b4207 Vermittlungsserver: coturn mit Zugangsdaten, die verfallen
Damit Anrufe auch in Netzen zustande kommen, die keine direkte
Verbindung zulassen (15-25 % der Faelle). coturn ist installiert,
steht aber still, bis die Konfiguration liegt -- ein coturn mit
Werkseinstellung ist ein offenes Relais.

KEIN FESTES PASSWORT. Es laege dauerhaft im Browser jedes
Team-Mitglieds und liesse sich nie entziehen. Der Server rechnet
stattdessen bei jeder Abfrage Zugangsdaten, die nach zwoelf Stunden
verfallen (server/workspace-turn.js, coturns `use-auth-secret`). Das
Geheimnis liegt in einer Datei, nicht in der Datenbank: einstellung-
Setzen() schreibt Werte ins Protokoll, und coturn braucht denselben
Wert ohnehin in /etc.

Die Oberflaeche frischt die Daten vor jedem Anruf auf. Der Chat ist
eine App, die tagelang offen bleibt -- wer nur beim Laden holt,
telefoniert am zweiten Tag ohne Vermittlung, und es faellt nicht auf:
Es scheitern nur die, die sie gebraucht haetten.

DIE WICHTIGSTE ZEILE DER KONFIGURATION ist die Sperrliste. Gemessen:
dreizehn Dienste lauschen auf diesem Server nur oertlich, darunter
Caddys Verwaltung auf 127.0.0.1:2019 -- wer sie erreicht, kann jede
Website umleiten. Ohne Sperrliste waere der Vermittlungsserver die
Tuer dorthin, und die Anfrage saehe fuer Caddy aus wie von localhost.

Geprueft: pruef-anruf.mjs 51 -> 73 Pruefungen. Gegenprobe (Geheimnis
als Passwort ausliefern + fremde Zugangsdaten ueberschreiben) macht
genau 5 rot, darunter "das Geheimnis steht NIRGENDS in der Antwort".

tools/turn-probelauf.sh beweist am echten coturn, was ein fester
Vergleichswert nicht kann: dass coturn unsere Rechnung akzeptiert.
Beide Seiten koennten sonst konsequent falsch rechnen und jede
Pruefung waere gruen. Seine eigene Gegenprobe war zweimal zu Recht
rot -- der erste Aufbau mass wegen `-y` gar nicht das Ziel, das er zu
messen behauptete, sondern coturns eingebauten Loopback-Schutz.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 15:22:14 +02:00
DogFatherGitandClaude Opus 5 5bbf1f2019 Der Anruf funktioniert wirklich -- gefunden im Dreier-Test
GEBAUT WAR NICHT BEWIESEN. Der Anruf ist fuer bis zu vier Leute
geschrieben, geprueft war er zu zweit -- und der Zweier-Test pruefte
nur, dass der Kasten erscheint und die Uhr laeuft. Ob jemals TON
ankommt, hat er nie gefragt.

Der Dreier-Test hat es gefragt. Ergebnis beim ersten Lauf:

  DogFather      0 Stroeme, "Verbunden"
  rechte Hand    0 Stroeme, "Verbunden"
  der Modi       0 Stroeme, "Verbindung ..."

DREI FEHLER, gefunden durch Messen statt Raten:

1. SIGNALE, DIE ZU FRUEH KOMMEN, WURDEN WEGGEWORFEN -- und das haette
   JEDEN Anruf getroffen, auch zu zweit.

   Wer rangeht, meldet "dabei". Der Anrufer bekommt das sofort und
   schickt sein Angebot. Der Angerufene braucht danach aber noch ein
   bis zwei Sekunden fuer das Mikrofon, und in dieser Zeit war `anruf`
   noch null. Das Angebot wurde still verworfen; danach kommt keins
   mehr. Beide Seiten zeigten "Verbindung ...", und es passierte nie
   wieder etwas.

   In der Spur war es unuebersehbar, sobald man hinsah:
     ereignis:signal inhalt=angebot     <- kommt an
     ereignis:signal inhalt=weg
     verbindung angelegt                <- erst JETZT

   Ein Signal ist keine Nachricht, die man wiederholen kann. Wer es
   wegwirft, hat den Anruf verloren -- es wird jetzt aufgehoben und
   abgearbeitet, sobald das Mikrofon steht.

2. DIE WARTESCHLANGE LAG ZUERST AN DER FALSCHEN STELLE. Eingebaut in
   `signalVerarbeiten`, verworfen wurde aber schon eine Ebene hoeher.
   Gefunden erst, als die Diagnose zeigte, dass `signalVerarbeiten` NIE
   aufgerufen wird: keine einzige Konsolenzeile, obwohl beide Zweige
   dort etwas melden. Eine Reparatur an der falschen Stelle sieht aus
   wie eine Reparatur.

3. "VERBUNDEN" STAND DA, BEVOR ETWAS VERBUNDEN WAR. Die Meldung wurde
   gesetzt, wenn jemand RANGEHT -- die Verbindung braucht danach noch
   Sekunden. Den richtigen Zeitpunkt kennt nur die Verbindung selbst
   (`onconnectionstatechange`). Eine Anzeige, die etwas Falsches sagt,
   ist schlimmer als keine.

Dazu zwei Kleinigkeiten, die dabei auffielen: Das Abarbeiten laeuft
jetzt NACHEINANDER (ein Verbindungsweg, der vor der Beschreibung
ankommt, wird abgewiesen -- parallel gewinnt oft der Weg), und die
Warteschlange wird beim Auflegen geleert, damit kein altes Signal in
den naechsten Anruf wandert.

Und die Pruefung selbst hatte einen Fehler: Abschnitt 6 setzt erfundene
STUN-Adressen und liess sie stehen. Der Browser haette im naechsten
Abschnitt gegen deren Zeitlimit gekaempft statt gegen den Code. Sie
werden jetzt wieder geleert -- eine Pruefung, die der naechsten den
Boden verstellt, macht deren Ergebnis unlesbar.

pruef-anruf 40 -> 51. Der neue Abschnitt prueft das, worauf es
ankommt: Bei drei Teilnehmern muss JEDER zwei Stroeme haben. Haette
`verbindungen` eine einzelne Variable statt einer Karte, ginge es zu
zweit gut und der Dritte ueberschriebe stillschweigend den Ersten --
man sieht sich zu dritt und hoert einen.

Gegenprobe (Warteschlange wieder ausgebaut): 4 rot, genau die
Tonpruefungen.

Gruen: anruf, chat, css-klassen, namen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 14:42:44 +02:00
DogFatherGitandClaude Opus 5 93c9788782 Telefonieren im Chat -- und die Farben nach Nachbarschaft verteilt
ZWEI SACHEN IN EINEM COMMIT, weil beide aus derselben Nacht stammen.

=== 1. DIE FARBEN: DER RICHTIGE ABSTAND ===

Filipe: "es gibt noch mehr die aehnlich aussehen von den farben also
leg los alle die sich aehnlich sind von den farben wechseln."

Er hatte recht, und mein Denkfehler laesst sich benennen: Ich hatte den
kleinsten Abstand ueber ALLE 37 Paare maximiert -- und der liegt bei 37
Farben zwangslaeufig bei 0,10. Das ist die Packungsgrenze, kein
Versaeumnis.

NUR SIEHT NIEMAND ALLE 37 NEBENEINANDER. Man sieht NACHBARN. Im Browser
gemessen, an der tatsaechlichen Lage auf dem Schirm -- 125 Paare, die
wirklich nebeneinander stehen, 15 davon unter 0,15:

  Creator-Profile / Zahlen      0,1019   beide rosa-rot
  LIVE-Analyse / Technik        0,1030   beide orange
  Wunschliste / Meldungen       0,1032   beide gelbgruen
  Wer sieht was / Entwicklung   0,1039   beide cyan
  Regeln & Hilfe / Mitmachen    0,1047   beide gruen
  Der Treff / Anschlagbrett     0,1070   beide rosa

Die Farben bleiben, ihre ZUTEILUNG aendert sich:

  Nachbarabstand     0,1047 -> 0,2133   (mehr als verdoppelt)
  Nachbarn unter 0,15     6 -> 0

Die Nachbarschaft steht in server/kachel-nachbarn.json, gemessen im
Browser -- nicht aus der Struktur im Quelltext abgeleitet. Die sagt,
was zusammengehoert, nicht was zusammen zu sehen ist.

=== 2. TELEFONIEREN IM CHAT ===

Filipe: "kann man machen dass die modis, rechte hand und ich auch
telefonieren koennen im chat?" ... "was man selbst in die app
reinsetzten kann, nicht meinen pc belastet und trotzdem vielleicht in
gruppe, mit video oder einzelnd."

DER TON GEHT NICHT UEBER DEN SERVER. Direkt von Browser zu Browser
(WebRTC); der Server reicht nur die Verbindungsdaten weiter, ein paar
Kilobyte je Anruf. Zu zweit kodiert jedes Geraet einen Strom und
dekodiert einen -- die Last eines gewoehnlichen Videoanrufs.

KEIN NEUER DIENST. Der Chat hatte bereits alles: `chatEreignis()` fuer
den Hinweg (SSE), Push fuers Klingeln, Raeume mit mehreren
Teilnehmern. Ein eigener WebSocket daneben waere eine zweite
Verbindung fuer dieselbe Frage -- und die zweite wird beim naechsten
Umbau vergessen.

Gebaut: Ton und Video, einzeln und in Gruppe bis GRUPPE_MAX (4),
Klingeln mit Annehmen/Ablehnen, Mikro und Kamera schaltbar,
Gespraechsdauer, Auflegen. Der Chat bleibt daneben benutzbar -- man
schreibt oft, waehrend man spricht.

EIN FUND, DER OHNE PRUEFLAUF LIVE GEGANGEN WAERE: Der Server sperrt
Mikrofon und Kamera per Permissions-Policy auf ALLEN Seiten. Der erste
Lauf meldete "microphone is not allowed in this document" -- der Anruf
haette bei JEDEM versagt, mit einer Meldung, die auf die falsche
Faehrte fuehrt (man sucht an den Browsereinstellungen). Die Sperre
bleibt ueberall und ist an genau EINER Stelle geoeffnet: der
Chat-Seite, und nur fuer sie selbst (`self`, nicht `*`).

NOCH NICHT GEBAUT -- und ausdruecklich nicht heimlich: coturn. Ohne
Vermittlungsserver klappen Anrufe nur im selben Netz. Die Adressen
stehen in den Einstellungen statt im Quelltext; sie lassen sich
nachtragen, ohne eine Zeile zu aendern. Ein oeffentlicher STUN-Dienst
als Standard kam nicht in Frage: Er saehe bei jedem Anruf die
IP-Adressen beider Teilnehmer, und fuer ein Team, das ueber Moderation
und Vorfaelle spricht, ist das keine Kleinigkeit.

server/pruef-anruf.mjs, 40 Pruefungen. Der wichtigste Abschnitt: Wer
nicht in den Raum gehoert, kommt an KEINE Route. Ein Anruf hinterlaesst
keine Spur -- wer mithoert, faellt nicht auf.

Gegenproben, jede zielgenau:
  Empfaengerpruefung der Signalisierung weg -> 1 rot
  Raumpruefung weg                         -> 5 rot (jede Route offen)
  Kopfzeilen-Ausnahme weg                  -> 4 rot

Gruen: anruf, chat, chat-optik, chat-kanaele, css-klassen, namen,
struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 10:10:04 +02:00
DogFatherGitandClaude Opus 5 438493c7dc Kacheln: 37 Farben neu gerechnet, und in jeder ein eigenes Universum
Filipe, zwei Wuensche: "ich will das jede kachel eine andere farbe hat
... keine die sich irgendwie aehnlich sind ... richtig geil und
speziell" und "der hintergrund ... soll noch mehr viel mehr nach
universum sein. nicht einfach so paar weisse punkte sondern richtig
geil hochwertiger geiler universum ... in den kacheln ueberall".

BEIDES WAR BERECHTIGT, und beides liess sich messen:

  kleinster Farbabstand    0,0529   (Rueckmeldung / Steckbrief)
  Paare unter 0,10         26 von 666
  schlechtester Kontrast   1,64:1   (Ton 35 -- praktisch unlesbar)
  sieben Toene unter 4,5:1
  Universum                auf GENAU EINER Kachel

WIE DAS PASSIEREN KONNTE, obwohl es ein Farbwerkzeug gab: Es kannte 21
Farben. Seit dem 08.09. waren SECHZEHN von Hand dazugekommen (Ton 22
bis 37) -- jede einzeln plausibel, keine gegen die anderen gerechnet.
Das Werkzeug meldete weiter "0,0973, alle Bedingungen erfuellt" und
meinte einen Stand, den es nicht mehr gab. Dieselbe Krankheit wie eine
abgeschriebene Spaltenliste: Die Zahl wird nicht falsch, sie wird
UNZUSTAENDIG. Es liest die Anzahl jetzt aus den Dateien.

NEU GERECHNET, alle 37 auf einmal:
  kleinster Abstand   0,0529 -> 0,1010   (fast doppelt)
  Paare unter 0,10        26 -> 0
  schlechtester Kontrast 1,64 -> 4,50:1
  Buntheit bis 0,300 statt 0,170, Helligkeit 0,58 bis 0,92

Drei Stellschrauben: Buntheitsgrenze hoch (augenschonend heisst dunkles
Schema und kein Flackern, NICHT blass), Raster von 2 Grad auf 1 Grad
und von fuenf auf zwanzig Helligkeitsstufen, und sechzehn Startpunkte
statt einem. Der Kontrast 4,5:1 bleibt hart -- eine Kachelfarbe traegt
Text.

DAS UNIVERSUM STEHT JETZT IM HINTERGRUND JEDER KACHEL, nicht in einem
Element: Beide Pseudo-Elemente sind vergeben (Leuchtschiene, Glanz),
und ein neues Element muesste an jeder Stelle nachgetragen werden, die
Kacheln baut. Eine Ebene, die man vergessen kann, wird vergessen.

Siebzehn Ebenen: drei nahe Sterne mit Hof, vier mittlere (zwei im
Kachelton), fuenf Staubkoerner, eine Milchstrasse als Schraege, drei
Nebel im Kachelton, ein kuehler Gegenpol, eine Vignette. Die Nebel
tragen `var(--ton)` -- 37 Kacheln sind damit 37 verschiedene Nebel.
Keine Bewegung: 28 driftende Felder waeren 28 Dauerlaeufer auf der
Grafikkarte.

Nach dem ersten Bildschirmfoto nachgeschaerft -- die Sterne lagen bei
6 bis 14 Prozent und waren aus der Naehe nicht zu sehen, genau die
"paar weissen punkte". Der Grund steht in der Kachel selbst: Sie ist
halbdurchsichtig, darunter liegt das Buehnenbild. Ein Sternenfeld muss
sich hier gegen ein FOTO durchsetzen, nicht gegen Schwarz.

NEU: server/helfer-png.mjs -- ein PNG-Leser (zlib, 90 Zeilen). Er
beantwortet die Frage, die aus dem CSS nicht mehr zu beantworten war:
Zwischen Textfarbe und Flaeche liegen jetzt sieben Ebenen plus das
durchscheinende Buehnenbild. Gemessen am Bildschirmfoto: schlechtester
Textkontrast 8,02:1 (Grenze 4,5).

NEU: server/pruef-kachel-universum.mjs, 12 Pruefungen.
DREI ANLAEUFE FUER DIE STERNPRUEFUNG, und die ersten zwei waren gruen
und wertlos:
  1. Ebenen im CSS zaehlen -- `0px` ist auch eine Zahl. Alle Sterne
     auf null: blieb gruen.
  2. Helle Punkte im Bildschirmfoto zaehlen -- die Kachel ist
     halbdurchsichtig, das Foto darunter hat selbst Punktstruktur.
     Gemessen: 459 Punkte mit Sternen, 441 ohne. Vier Prozent sind
     kein Nachweis, sondern Rauschen.
  3. Jetzt die GROESSEN aus dem CSS (>= 0,7 px). Schwaecher, aber
     ehrlich -- und die Gegenprobe greift: 12 -> 0.
Dabei fiel ein eigener Messfehler auf: Der Bereich wurde aus der
Textposition geschaetzt und lag OBERHALB der Kachel. Verraten hat es
die Gegenprobe, die zweimal exakt 153 lieferte -- eine Messung, deren
Ergebnis sich nicht aendert, wenn man das Gemessene entfernt, misst
etwas anderes.

Gegenproben, alle zielgenau:
  zwei gleiche Farben   -> 3 rot      Sterne auf 0px  -> 1 rot
  Nebel ohne Kachelton  -> 1 rot (nach dem Schaerfen: vorher blieb es
                            gruen, weil `--ton` auch im Grundverlauf steht)

Gruen: kachel-universum, css-klassen, start-ansicht, namen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 02:55:23 +02:00
DogFatherGitandClaude Opus 5 3d9de349ad Wer sich kuemmert -- an jeder Anfrage und an jedem Kandidaten
Ein Versprechen von frueher, nie gebaut: die Arbeit mit der rechten
Hand teilen. Gemessen: Es gab dafuer NICHTS. Weder an `bewerbungen`
noch an `talent_stufe` stand eine Zustaendigkeit -- beide sehen alles,
niemand ist benannt.

Das ist nicht "geteilt", das ist "jeder dachte, der andere macht es".
Bei einer Anfrage wartet ein Mensch darauf. Bei einem Kandidaten
bleibt er auf seiner Stufe liegen -- die Standzeit an der Karte sagt
zwar, DASS etwas liegt, aber nicht, wer es aufheben sollte.

MAN NIMMT SELBST, MAN BEKOMMT NICHT ZUGETEILT. Ein "DogFather weist
zu" waere eine Rangordnung, und die gehoert hier nicht hin (18.08.2026:
"mich bitte nie wie da hoeher stellen wie andere"). Wer Zeit hat,
uebernimmt; wer keine mehr hat, gibt ab -- mit DEMSELBEN Knopf, wie bei
den Merkmalen und den Probeschritten.

DER FALL, AUF DEN ES ANKOMMT: Eine FREMDE Uebernahme wird mit 409
abgewiesen, nicht stillschweigend ueberschrieben. Sonst nimmt einer dem
anderen die Anfrage aus der Hand, ohne dass es jemand merkt -- und
beide glauben, sie sei erledigt. Wer trotzdem will, laesst erst
abgeben.

DER UNBESETZTE ZUSTAND IST DER AUFFAELLIGE. "Ich kuemmere mich" steht
als Knopf da, "Du kuemmerst dich" als ruhige Zeile, fremdes als
gestrichelter Rahmen ohne Zeigefinger (ein Knopf, der aussieht wie
einer und nichts tut, ist eine Falle). Andersherum waere die Liste ein
Feld aus Namen, in dem die Luecke nicht auffaellt -- und genau die
Luecke ist die Auskunft.

Verglichen wird ueber die NUMMER, nicht ueber den Namen: Zwei Leute
duerfen gleich heissen.

DREI EIGENE FEHLER, alle beim Nachsehen gefunden statt beim Schreiben:

 1. `nurLeitung` HAT AN MEINER ROUTE GEFEHLT. Der Router setzt
    `angemeldet` fuer den ganzen Pfad, `nurLeitung` aber je Route --
    ich hatte nur die Nachbarzeilen ueberflogen. Ohne den Riegel haette
    sich jeder Angemeldete fuer eine fremde Anfrage zustaendig erklaert:
    kein Datenabfluss, aber ein Name an einer Anfrage, der dort nichts
    zu suchen hat -- und sie gilt als betreut, waehrend sich niemand
    kuemmert. Gegenprobe bestaetigt: ohne die Zeile 200 statt 404.
 2. `nummer()` aufgerufen, das es in dieser Datei gar nicht gibt --
    ein Absturz zur Laufzeit, den `node --check` nicht sieht.
 3. Die Pruefung benutzte `json()` und rohe Cookie-Objekte statt der
    Hausmittel `alsJson`/`holen`/`schicken` dieser Datei. Abgeschrieben
    aus der Nachbardatei, in der sie anders heissen.

Und wieder eine Zeile, die ohne Daten gruen war: "um die sich niemand
kuemmert" bestaetigte auch bei LEERER Liste -- `undefined` ist nun
einmal kein Zustaendiger. Die Anzahl gehoert in die Bedingung.

pruef-nachwuchs 244 -> 258, pruef-bewerbung 77 -> 91.
Gegenproben:
  Riegel gegen fremde Uebernahme weg -> 5 rot
  nurLeitung weg                     -> 2 rot (der eigene Fehler)

pruef-nachruesten fuehrt beide neuen Spalten mit.

Gruen: nachwuchs, bewerbung, nachruesten, namen, css-klassen, struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 01:47:11 +02:00
DogFatherGitandClaude Opus 5 1a2dfa07f3 Trichter und Entwicklungskarte kennen einander
An der Stufe "Im Team" steht seit jeher zweimal: "ab hier zaehlt die
Entwicklungskarte, nicht mehr diese". Gemessen: Es gab keinen Weg
dorthin. Wer den Satz las, musste die Seite selbst finden und die
Person dort aus einer Liste heraussuchen.

Das ist heute das DRITTE Mal dasselbe Muster -- ein Text verspricht
einen Weg, den es nicht gibt:
  "uebernehmen oder sauber beenden"  -> der Ausgang fehlte
  Kalender zeigt Brettzettel         -> zurueck fuehrte nichts
  "ab hier die Entwicklungskarte"    -> kein Link

HIN: Von der Talentkarte fuehrt ein Weg auf die Entwicklungskarte
GENAU DIESER Person -- ueber `?zeigen=person-<id>`, den Weg, den das
Haus dafuer schon hat (kopf.js), nicht ueber eine zweite Mechanik. Die
Karte ist beim Ankommen offen; ein Link, der auf einer Liste endet, auf
der man die Person wieder sucht, hat nichts erspart.

Der Sprung passiert ERST, wenn alle Kacheln stehen. Waehrend der
Schleife haengt die gesuchte noch nicht im Dokument und hat keine
Position -- ein Sprung dorthin waere einer an den Seitenanfang,
lautlos, und man haelt den Link fuer kaputt.

ZURUECK: Die Entwicklungskarte sagt jetzt, wie dieser Mensch gekommen
ist -- mit dem Namen der Talentkarte und wer ihn eingearbeitet hat.
Beim ersten Beurteilen ist genau das die Frage ("woher kommt der
eigentlich?"), und wer sie nicht beantwortet bekommt, faengt bei null
an, obwohl vier Wochen Beobachtung vorliegen.

NUR DER WEG, NICHT DIE DATEN. Die Merkmale aus dem Trichter hierher zu
kopieren waere bequem und falsch: zwei Kataloge, zwei Fragen (taugt er?
/ wie entwickelt er sich?). Eine Zahl aus dem einen sieht im anderen
aus wie eine Beurteilung und ist keine.

Moeglich wurde beides erst durch `talent_stufe.person_id` von vorhin --
ohne die Verknuepfung gibt es keine Richtung, in die man zeigen
koennte.

pruef-nachwuchs 236 -> 244. Geprueft wird nicht, ob ein Link DASTEHT,
sondern ob man am Ziel ankommt: Karte offen, richtige Person, Kachel
hervorgehoben, Herkunft da, Rueckweg da. Mit Gegenprobe an einer
zweiten Karte, die NICHT aus dem Trichter kam (sonst hiesse "kam ueber
den Trichter" nur, dass ueberall etwas steht).

Gegenproben:
  Sprung ausgebaut    -> 5 rot
  Herkunft ausgebaut  -> 2 rot, genau die beiden richtigen

Und wieder eine Schriftgroesse unter der Hausgrenze (.7rem = 11,2 px),
gefunden von pruef-css-klassen. Zurueckhaltend wird ueber FARBE
gedaempft, nicht ueber Groesse -- das ist der Unterschied zwischen
"leise" und "zusammengekniffen".

Gruen: nachwuchs, entwicklung, sprung, modi-wortleck, namen,
css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 01:01:12 +02:00
DogFatherGitandClaude Opus 5 a435e734c9 Aus dem Talent wird ein Mensch mit Aufgaben
Filipe: "wie talente bewertet werden, aufgaben bekommen, analysiert
werden von vanvan und mir, alles moegliche."

GEMESSEN VOR DEM BAU, und der Befund war groesser als erwartet: Der
letzte Schritt des Trichters legt einen Zugang an -- und die
Verknuepfung wurde NIRGENDS gespeichert. `zugangAnlegen()` gab die
Person zurueck, der Code wurde einmal gezeigt, und danach wusste die
Karte nicht mehr, wer aus ihr geworden ist.

Was dadurch nicht ging:
  - von der Karte zur Person springen
  - dem Neuen aus der Karte heraus seine ersten Aufgaben geben
  - in einem halben Jahr nachsehen, aus welchem Kandidaten eigentlich
    welches Teammitglied wurde

DREI SPALTEN WAEREN ZU VIEL GEWESEN, eine reicht: `talent_stufe.person_id`.
Kein Fremdschluessel auf `personen` -- wird ein Zugang geloescht, soll
die Karte stehen bleiben. Sie erzaehlt, wie jemand gekommen ist, und
das bleibt wahr, auch wenn er wieder geht. Ein CASCADE haette genau
diesen Verlauf mitgeloescht.

NUR SETZEN, NIE LOESCHEN (COALESCE): Sonst verloere die Karte ihren
Menschen, sobald jemand sie auf eine fruehere Stufe zuruecksetzt.

WOMIT ER ANFAENGT. Der Katalog mit 101 Aufgaben in 14 Bereichen gab es
laengst -- nur fuehrte der Weg dorthin ueber eine andere Seite, wo man
die Person heraussuchen und Bereich plus Stufe waehlen musste. Vier
Schritte, die niemand macht, waehrend er gerade jemanden aufnimmt;
dasselbe Muster hat heute schon zu einer Karte auf "Im Team" ohne
Menschen darin gefuehrt. Jetzt steht der Kasten an der Karte, ein Klick
legt einen Bereich an.

ES BLEIBT EIN ANGEBOT, KEINE AUTOMATIK -- Filipes Entscheidung bei der
Live-Checkliste gilt hier genauso: "was ungefragt Dinge anlegt, ist
schwer wieder loszuwerden". Und der Kasten ist ZU, wenn schon Aufgaben
da sind; offen wuerde er zum Nachlegen einladen, und das ist selten
gemeint. Daneben steht, wie viele schon offen sind -- ohne diese Zahl
legt man beim zweiten Hinsehen dasselbe noch einmal an.

pruef-nachwuchs 200 -> 236, davon 14 im Browser (Abschnitt 17 mit
eigenem Browser: der aus Abschnitt 15 lief, bevor es den Kandidaten
ueberhaupt gab -- ein Stand von zwei Abschnitten vorher ist keine
Messung, sondern eine Annahme).

VIER EIGENE FEHLER DABEI GEFUNDEN, drei davon durch die Gegenproben:

 1. `d.angelegt?.length` -- die Antwort ist eine ZAHL, kein Feld. Der
    Knopf haette "6 Aufgaben stehen bereit" gemeldet, auch wenn null
    entstanden sind.
 2. Der "Schritt zurueck" ging auf `probe` -- und der verlangt Buddy
    und Datum. Die Route antwortete 400, die Stufe blieb stehen, und
    die Zeile darunter bestaetigte, dass sich nichts geaendert hat:
    eine Pruefung, die immer gruen ist. Aufgefallen erst an der
    Gegenprobe (COALESCE ausgebaut -> blieb gruen). Eine Gegenprobe
    ist keine Kuer, sie prueft die Pruefung.
 3. Feldnamen `buddy`/`datum` statt `buddy_id`/`erste_schicht` --
    Fehler in der Pruefung, nicht im Code.
 4. Die Rollennamen-Zeile war ZU SCHARF und meldete prompt einen
    Treffer: "Die Modis, die mit ihm gearbeitet haben" aus dem
    Probeplan -- ein Satz, der ueber eine Schnittstelle kommt, die nur
    die Leitung erreicht, und genau dorthin gehoert. Geprueft wird
    jetzt, was hier neu ist; ueber die ausgelieferten DATEIEN wacht
    pruef-modi-wortleck (101 Dateien, mit eigener Gegenprobe).

Gegenproben, jede zielgenau:
  Nummer ungeprueft     -> "erfundene Zugangsnummer wird abgewiesen"
  COALESCE weg          -> "Schritt zurueck nimmt ihr den Menschen weg"
  Person nicht geliefert-> 4 rot

pruef-nachruesten fuehrt die neue Spalte mit -- jede neue Spalte gehoert
in diese Liste, sonst prueft die Datei den Weg von gestern.

Gruen: nachwuchs, nachruesten, modi-wortleck, namen, css-klassen,
struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-18 00:12:14 +02:00
DogFatherGitandClaude Opus 5 5e628e0078 Brett und Kalender kennen einander jetzt in beide Richtungen
Der Kalender zeigt seit heute, was auf den Brettern steht und einen
Termin hat. Die Verbindung war aber EINSEITIG, und beide Halften
fehlten:

  Beim SCHREIBEN konnte niemand wissen, dass ein Tag in der Zukunft den
  Zettel in den Kalender bringt. Das Feld heisst "Datum" und ist mit
  HEUTE vorbelegt -- die Funktion war vorhanden und unauffindbar. Eine
  Funktion, die niemand findet, ist keine.

  Beim LESEN sagte die Karte nichts. Am Fuss stand bloss ein Datum, und
  "24.09.2026" sieht aus wie "17.09.2026" -- obwohl das eine ein Termin
  ist und das andere der Tag, an dem jemand getippt hat.

EINE REGEL, ZWEI VERWENDER -> server/workspace-termin-regel.js.
Der Kalender fragt "welche gehoeren hinein?" (SQL, ganze Tabelle), die
Brettkarte fragt "stehe ICH drin?" (JavaScript, je Zeile). Beide Fassungen
stehen jetzt nebeneinander in EINER Datei, importfrei wie
treff-tabellen.js.

Das ist kein Vorsichtsprinzip, sondern Erfahrung: Zwei Fassungen
derselben Regel sind im Haus dreimal auseinandergelaufen -- die
abgeschriebene Spaltenliste (11.09., drei Spalten samt Inhalt weg), die
zweite Artenliste neben ARTNAME (ein BigMatch liess sich anlegen und
war unsichtbar) und `.teilen` heute frueh.

server/pruef-terminregel.mjs, 35 Pruefungen. Der Kern ist Abschnitt 2:
Er prueft die beiden Fassungen GEGENEINANDER, nicht jede fuer sich --
zwei Pruefungen, die je eine Seite bestaetigen, finden genau diesen
Fehler nicht. Verglichen wird beides: WELCHE Zettel und WELCHER Tag.
Neun Faelle, davon vier, die zu Recht wegbleiben.

Vier Gegenproben, jede in ihre eigene Richtung:
  JS laesst mehr durch -> "die Karte behauptet einen Termin, den der
                           Kalender nicht kennt"
  JS nennt anderen Tag -> "verschiedene Tage: Kalender 22., Karte 17."
  SQL laesst mehr durch-> "steht im Kalender, aber die Karte sagt nichts"
  Marke ausgebaut      -> 0 statt 1

EIN ECHTER FEHLER DABEI BEHOBEN, und er war aelter als diese Arbeit:
Das Formularraster gibt jedem Feld GENAU ZWEI Zeilen (Schild dehnbar,
Eingabe fest 44 px) -- deshalb sitzen die Eingaben auf einer Linie. Ein
Hinweisabsatz erzeugt eine dritte Zeile, und weil das Raster alle
Felder auf gleiche Hoehe dehnt, rutscht ausgerechnet diese Eingabe nach
oben. Gemessen: 328..372 gegen 351..395. 23 px -- genau das, was man
als "verzogen" sieht.

Mit `git stash` getrennt: aufgaben.html war dadurch SCHON VORHER rot
(ein anderes Feld hat dort ebenfalls einen Hinweis), bereich.html hatte
ich neu verursacht. Der Hinweis haengt jetzt absolut unter dem Feld --
beide sind gruen, und zwar an der Wurzel, nicht symptomatisch.
`pointer-events: none`, sonst faengt der Satz Klicks ab, die dem
Element darunter galten.

Am Handy gemessen statt geschaetzt: 0 Ueberschneidungen mit anderen
Feldern. Gegenprobe (row-gap auf 2 px): 1 Ueberschneidung.

Und noch zwei eigene Pruefungsfehler behoben, beide von derselben Sorte:
ein falscher Selektor samt `.catch(() => {})`, der den Fehlgriff
lautlos verschluckte (danach war das Hinweisfeld leer und die Zeile
darunter trotzdem gruen, weil "" nun einmal nicht "ja" ist) -- und die
Marke wurde ueber `textContent` gezaehlt statt ueber ihre Sichtbarkeit.
Aufgefallen ist das am Bildschirmfoto, auf dem ich sie fuer fehlend
hielt; deshalb macht die Pruefung jetzt zusaetzlich einen AUSSCHNITT
der Karte -- auf einem Vollbild von 2000 px ist eine Pille von 28 px
nicht zu beurteilen.

Gruen: terminregel, kalender, formulare, ueberlappung, countdown,
namen, css-klassen, struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 23:53:05 +02:00
DogFatherGitandClaude Opus 5 528ee1ecc7 Pruefung fuer den Weg, den es live allein gibt: alte Datenbank, neue Spalten
Entstanden aus einem Fehlalarm, den ich selbst verursacht habe.

Mein Deploy-Block liess vier Sekunden nach dem Neustart zaehlen, ob
`talent_stufe` die drei neuen Spalten hat. Antwort: 0. Das sah aus wie
eine fehlgeschlagene Umstellung an lebenden Daten -- und war keine.

Die Spalten entstehen beim ERSTEN angemeldeten Aufruf des Bereichs
(`tabellen()`, gesteuert ueber `bereit`), und vier Sekunden nach einem
Neustart hat sich noch niemand angemeldet. Die Pruefung verlangte eine
Aussage, die zu diesem Zeitpunkt gar nicht wahr sein KONNTE. Ein
Fehlalarm ist nicht harmlos: Er kostet Vertrauen in jede kuenftige
Zahl, die im selben Block steht.

Nachgestellt auf einer Kopie des exakten Live-Zustands (die sieben
Spalten vom Server abgelesen): erster Aufruf -> Spalten entstehen,
Seite antwortet 200. Nichts war kaputt.

DER EIGENTLICHE FUND: Der Weg „alte Datenbank bekommt neue Spalten" war
NIE GEPRUEFT. Jede Pruefung im Haus startet auf einer frischen Datei,
in der die Tabellen mit allen Spalten neu entstehen -- der
Nachruest-Pfad wurde dabei nie betreten. Gemessen: 27 Stellen in drei
Dateien ruesten Spalten so nach. Live ist das der einzige Weg, der
ueberhaupt vorkommt.

Dieselbe Sorte Luecke wie die Sicherung, die nie zurueckgespielt wurde:
Sie meldet jahrelang „in Ordnung" und sagt nichts darueber, ob sie im
Ernstfall traegt.

server/pruef-nachruesten.mjs, 11 Pruefungen:
  1. Der Ausgangszustand stimmt -- MIT Gegenprobe, dass die neuen
     Spalten wirklich fehlen (sonst bewiese der Rest nichts).
  2. Ein echter Aufruf ruestet nach, und keine alte Spalte geht dabei
     verloren (11.09.: eine abgeschriebene Liste hat genau so drei
     Spalten samt Inhalt weggeworfen, ohne Fehlermeldung).
  3. Die Karte traegt das neue Feld -- dass die Spalte existiert, heisst
     noch nicht, dass die Anwendung sie ausliefert.
  4. Und es laesst sich hineinschreiben. Eine nachgeruestete Spalte, in
     die nichts geht, waere ein halber Umbau.

Eine Zeile mit Daten ist Pflicht: Ueber eine leere Tabelle laeuft
`talentKarte` gar nicht, und ein „200" bewiese dann nur, dass der Weg
ohne Daten funktioniert.

Gegenprobe (ALTER TABLE ausgebaut): 5 rot, darunter „die Talente-Seite
antwortet mit 503" -- genau der Schaden, den das Nachruesten verhindert.
Dabei stuerzte Abschnitt 4 ab statt rot zu melden; ein Absturz
verschluckt die Zeilen danach und sieht aus wie ein Problem der
Pruefung. Jetzt hat er den dritten Ausgang.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 23:18:34 +02:00
DogFatherGitandClaude Opus 5 fabb1f94a8 Kalender: was auf den Brettern steht und einen Termin hat
Filipe, zu einer Clip-Karte: "ich will dass die auch in einer kalender
drin sind, aber ich will dass es richtig geil ist und perfektionier das
bitte."

Gemessen vor dem Bau: /workspace/api/termine lieferte `termine` und
`fristen`. Die Zettel von den achtzehn Brettern kamen nirgends vor --
obwohl `eintraege` seit langem VIER Zeitfelder hat: datum, uhrzeit,
geplant, event_ende.

WELCHE HINEINGEHOEREN, IST DIE GANZE FRAGE -- und sie laesst sich
messen statt raten. `datum` ist ein Pflichtfeld und faellt auf HEUTE
zurueck, wenn niemand eins waehlt. Alle Eintraege hineinzukippen hiesse
also: jeder je getippte Zettel steht an dem Tag, an dem ihn jemand
getippt hat. Nach einem Monat waere der Kalender ein Protokoll und kein
Plan -- und ein Kalender, in dem alles steht, sagt nichts mehr.

GEZEIGT WIRD NUR, WOFUER JEMAND EINE ZEIT BESTIMMT HAT:
  geplant        eine Zusage ("Wird gemacht -- am 24.09.")
  event_ende     ein Zeitraum
  uhrzeit        niemand tippt aus Versehen 20:00
  datum > heute  der Rueckfall ist IMMER heute oder frueher
Erledigtes bleibt draussen. Der vierte Fall ist der wichtigste und der
unauffaelligste: kein neues Feld, keine Umgewoehnung.

RECHTE: dieselbe Funktion wie die Bretter selbst (`sichtbarEintrag`),
nicht eine zweite Meinung. Im Kalender steht nur eine kleine Pille mit
einem Titel -- dass darin ein vertrauliches Vorhaben steckt, faellt
niemandem auf, der nicht danach sucht. Genau so kam am 03.09. eine
Managerin an fremde Aufgabenfristen.

DREI FEHLER AM BILDSCHIRMFOTO GEFUNDEN, nicht an einer Zahl:
  1. Der Brettname stand VOR dem Titel -- aus "Clip am Wochenende"
     wurde "Cli...". Das Etikett verdraengte, was es einordnen sollte.
     Jetzt zweite Zeile: Hoehe ist im Monatsraster der billigere Platz.
  2. Am Handy (45px Zellbreite) wurde daraus ein "Co..." -- Hoehe ohne
     Information. Jetzt eine CONTAINER-Abfrage: entschieden wird nach
     der Breite der ZELLE, nicht des Fensters. Eine Fensterschwelle
     waere wieder die Rechnung von gestern (September, Kopfleiste,
     zweimal).
  3. .64rem = 10,24px -- unter der Hausgrenze 11,5px, gefunden von
     pruef-css-klassen. Gedaempft wird jetzt ueber Farbe und Gewicht,
     nicht ueber Groesse.

EIN ECHTER FEHLER VERHINDERT: In der Listenansicht waeren die Zettel im
Termin-Zweig gelandet -- mit Wecker, "erledigt" und "loeschen". Der
Knopf haette PATCH /api/termine/b12 geschickt: eine Nummer, die es dort
nicht gibt, an eine Schnittstelle, die davon nichts weiss. Still, ohne
Wirkung, ohne Meldung.

DER WEG FUEHRT AUF DEN ZETTEL, nicht nur auf das Brett -- ueber
`?zeigen=` (kopf.js), den Weg, den das Haus dafuer schon hat. Zwischen
zwanzig Eintraegen waere der gesuchte sonst von Hand zu suchen.

pruef-kalender: +25 Pruefungen. Sieben Gegenproben, jede zielgenau:
  Schnitt weg            -> 6 rot   Erledigtes rein      -> 6 rot
  Rechteregel ausgehebelt-> 1 rot   COALESCE weg         -> 1 rot
  Termin-Knoepfe an      -> 2 rot   Container-Regel weg  -> 1 rot
  Sprung-Zweig weg       -> 3 rot

UND SIEBEN FESTE ZAHLEN ABGELEITET. Die alten Pruefungen zaehlten
"alle fünf Einträge", "vier Arten", "vier Filter" -- mit den neuen
Testdaten wurden daraus zehn, und sieben Pruefungen je Bildschirmgroesse
wurden rot, ohne dass am Kalender etwas kaputt war. Mit `git stash`
nachgemessen (ohne meine Aenderung: 0 Fehler), also nicht angepasst,
sondern gerechnet: jede Zahl kommt jetzt aus den Testdaten darueber.

Zwei eigene Pruefungsfehler dabei behoben: ein falscher Umschalter-
Selektor liess `every()` auf einem leeren Feld laufen (gruen ohne
Daten), und die Sichtbarkeit der zweiten Zeile wurde ueber
`textContent` gemessen -- das liefert auch, was `display: none`
ausblendet.

Gruen: kalender, sprung, namen, css-klassen, struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 22:48:38 +02:00
DogFatherGitandClaude Opus 5 e3e015bca4 Kopfleiste: ein Name, der zweimal vergeben war
Filipe zu einem Bildschirmfoto: "was soll das jetzt, wieso sieht das in
gewissen seiten so scheisse aus?!"

Der Teilen-Knopf stand doppelt so hoch wie seine Nachbarn, mit dem
Zeichen UEBER dem Wort statt daneben. Es war kein Gestaltungsfehler,
sondern ein Name: `.teilen` gab es ZWEIMAL --

  gate.css      Knopf der Kopfleiste   inline-flex, waagerecht
  bereich.css   Layout der Teilen-Seite  flex column, 22px, 44rem

Auf den drei Seiten, die beide Dateien laden (bereich, bewerben,
teilen), gewann die spaeter geladene. Der Knopf bekam das Layout einer
ganzen Seite. "Gewisse Seiten" war exakt richtig beobachtet.

DERSELBE NAME KOSTETE AUSSERDEM DEN KNOPF: kopf.js baut ihn nur ein,
wenn `getElementById('teilen')` nichts findet -- ein Schutz gegen
doppelten Einbau. Auf teilen.html steht `<section id="teilen">` aber
schon im HTML. Dort fehlte der Knopf ganz, ohne Spur, ohne Meldung.

REPARIERT ALS REGEL, NICHT ALS EINZELFALL:
  - Was kopf.js in die Leiste haengt, traegt jetzt `kopf-` davor
    (kopf-teilen, kopf-sicht-wahl, kopf-sicht-feld, kopf-fremd-band).
    Eine Seite darf dann heissen wie sie will -- auch "teilen", "chat"
    oder "suchen", und genau diese Woerter braucht als naechstes eine
    Seite.
  - Die Teilen-Seite bekommt eigene Klassennamen (tl-*).

NEU: server/pruef-namen.mjs (12 Pruefungen, ohne Server, <1 s).
Es ist der ZWEITE Namenskonflikt an einem Tag -- der erste war
`.t-schritt` auf der Talente-Seite, gefunden nur durch Zaehlen im
Browser. Beide waren gruen in jeder bestehenden Prueflinie.
Gemessen, um den Schnitt zu finden, der etwas taugt:
  2872 Klasse in zwei geladenen Dateien erwaehnt      -> Rauschen
  1887 davon mit eigener Blockdefinition              -> Rauschen
    12 davon mit widersprechendem `display`
     6 davon ohne `display: none`                     -> geprueft
Mit Gegenprobe, die aus den Dateien ABGELEITET wird (die erste, fest
abgeschriebene Fassung fand nichts, weil die gewaehlte Klasse dort gar
kein `display` setzt -- eine Gegenprobe, die selbst danebenliegt,
beweist nichts).

pruef-kopf-messen: 3 -> 16 Messungen, und drei eigene Fehler behoben,
die alle dieselbe Form hatten -- zu frueh hingesehen:
  1. Sie mass NUR uebersicht.html. Die laedt bereich.css nicht und war
     fuer diesen Fehler blind.
  2. Sie mass nur 320/390/430px. Unter 720px versteckt gate.css das
     Wort "Teilen"; der Knopf bleibt klein, auch falsch angeordnet.
     Filipes Bild war 1366px breit.
  3. Sie wartete 300ms. kopf.js haengt Teile erst nach `/api/ich` ein
     und hat ein Netz bei 1200ms. Zweiter Versuch: warten, bis `#wer`
     Text hat -- SOFORT wahr, dort steht `…` als Platzhalter. Dritter:
     auf Stabilitaet warten -- nach 0ms und 500ms gleich gross, also
     "fertig". Erst die Mindestwartezeit (1200 aus kopf.js plus Luft)
     davor machte die Messung echt.
Bewiesen an der Gegenprobe: mit dem alten Fehler meldet sie jetzt
"kopf-teilen ist 77px -- die anderen im Schnitt 43px", vorher blieb sie
gruen.

Statt einer festen Hoehe wird gefragt, ob EIN Teil aus der Reihe faellt
(> 1,6x der Schnitt seiner Nachbarn). Das waechst mit, wenn die Leiste
groesser wird, und muss bei keinem neuen Knopf nachgezogen werden.

Gruen: namen, kopf-messen, sicht, css-klassen, struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 18:59:19 +02:00
DogFatherGitandClaude Opus 5 e54c6829f1 Talente: der Trichter bekommt einen Ausgang
Gemessen vor dem Bau: talentNaechste kettet aufgefallen -> beobachtet ->
angesprochen -> probe -> imteam, und danach kommt nichts. Eine Suche nach
"beenden|abgesagt|verworfen|archiv" in workspace-entwicklung.js fand
nichts. Der Trichter hatte genau einen Ausgang -- obwohl der Text der
Probe-Stufe woertlich verspricht: "Nach 30 Tagen: uebernehmen -- der
Zugang entsteht dabei -- oder sauber beenden."

Wer nicht passte, blieb also auf seiner Stufe stehen, mit wachsender
Standzeit und rotem "liegt"-Zeichen. Nach einem Jahr hat die Liste mehr
Karteileichen als Kandidaten, und dann schaut niemand mehr hin.

DREI SPALTEN, KEINE NEUE STUFE. Eine neue Stufe haette einen
CHECK-Umbau auf laufenden Daten verlangt -- und eine Auskunft zerstoert:
Die Stufe haelt fest, WO es geendet hat. "Beendet in der Probe" und
"beendet nach dem ersten Hinsehen" sind zwei verschiedene Saetze, und
genau der Unterschied ist die Frage, wenn dieselbe Person in einem
halben Jahr wieder auffaellt.

DER SATZ IST PFLICHT (10 Zeichen, wie beim Ablehnen einer Anfrage) --
aus zwei Richtungen: Nach vorn, weil beim zweiten Anlauf niemand mehr
weiss, was damals war. Nach innen, weil wer schreiben muss, anders
entscheidet als wer klickt. "Passt nicht" hat neun Zeichen.

WIEDER AUFNEHMEN setzt auf "aufgefallen" zurueck -- Menschen aendern
sich, ein Urteil von damals gilt nicht weiter -- und rettet den alten
Satz in die Notiz, statt ihn zu loeschen.

AM BILDSCHIRMFOTO GEFUNDEN, nicht an einer Zahl: Auf einer Karte auf
"Im Team" stand "Nichts mehr zu tun -- der Zugang steht" und direkt
darunter "Passt doch nicht?". Ein Beenden dort haette die Karte
stillgelegt und den ZUGANG offengelassen -- eine halbe Handlung, die
sich wie eine ganze anfuehlt. Jetzt steht dort der Weg zu "Personen &
Zugaenge", und der Server weist es mit 409 ab.

pruef-nachwuchs 152 -> 200, davon 21 im echten Browser (der erste
Browserblick auf diese Seite ueberhaupt -- mit einer Messung, ob Name
und Datum bei 390 px uebereinanderliegen, statt einer Zahl im CSS).
Sechs Gegenproben, jede genau auf ihr Ziel:
  Grenze auf 0          -> 3 rot
  Beendete bleiben drin -> 2 rot
  beendete: []          -> 5 rot
  alter Grund verworfen -> 1 rot
  Serverriegel imteam   -> 5 rot
  Browserzweig imteam   -> 3 rot
Dazu gruen: css-klassen, struktur, entwicklung, uebergang.

Nebenbefund behoben: absage() im Browser warf einen erklaerenden Satz
des Servers lautlos weg und zeigte "Ging nicht." -- die Auskunft war da.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 18:39:06 +02:00
DogFatherGit 3a49e30aa4 Die Probezeit hat einen Inhalt -- und man sieht, wer was gesehen hat
Filipe: "wie talente bewertet werden, aufgaben bekommen, analysiert
werden von vanvan und mir, alles moegliche, wie gesagt ich will hoch
profissionel arbeiten."

WAS GEMESSEN FEHLTE

  Die Stufe "Probe" hatte eine Frist von 30 Tagen, einen Buddy, ein
  Datum -- und einen Satz: "Nach 30 Tagen: uebernehmen oder sauber
  beenden." Worauf diese Entscheidung sich gruenden soll, stand
  nirgends. Eine Probezeit ohne Inhalt ist keine Probe, sondern eine
  Wartezeit; am dreissigsten Tag entscheidet dann das Bauchgefuehl
  dessen, der zuletzt etwas gesehen hat.

  Und: `von_id` stand seit dem Bau in talent_merkmal und wurde nie
  ausgeliefert. Man sah, DASS ein Merkmal gesetzt ist -- nicht, von
  wem. Bei zwei Leuten, die unabhaengig beobachten, ist genau das die
  Auskunft.

DER PROBEPLAN

  Zwoelf Schritte in drei Phasen: mitlaufen -> selbst machen -> allein.
  Die Reihenfolge ist der Punkt (Discord empfiehlt sie so, in der
  Ausbildung heisst sie "see one, do one"). Wer die mittlere Stufe
  ueberspringt, hat am Tag 30 zwei Sorten Kandidaten, die man nicht
  unterscheiden kann.

  JEDER SCHRITT HAT EINEN ZUSTAENDIGEN -- sechs das Talent, drei der
  Buddy, drei die Leitung. Ohne diese Angabe wandern in jeder Probezeit
  dieselben drei an niemanden: Der Buddy denkt, die Leitung macht es.

  KEINE PUNKTZAHL. Am Ende stehen drei Fragen, die ein Mensch
  beantwortet; die Haken sagen nur, ob er genug gesehen hat. Und
  "entscheidbar" haengt an DREI Schritten, nicht an einer Anzahl: Wer
  nie allein gearbeitet hat und wen das Team nie beurteilt hat, ueber
  den weiss man nichts, egal wie viele andere Haken stehen. Neun von
  zwoelf reichen nicht, drei genuegen -- wenn es die richtigen sind.

WAS DAS HINSEHEN GEFUNDEN HAT

  `.t-schritt` gibt es auf dieser Seite schon -- es ist die Zeile mit
  dem naechsten Schritt der Trichterstufe. Meine Regeln standen
  SPAETER in derselben Datei und haetten sie ueberschrieben. Gefunden
  hat das keine Ueberlegung, sondern das Nachzaehlen im Browser: 13
  Elemente mit `.t-schritt`, obwohl der Plan zwoelf hat.

ZWEI PRUEFUNGEN WAREN SCHON VORHER ROT (gemessen mit git stash)

  pruef-schritt (6 rot) und pruef-befinden (4 rot) -- seit den
  Erweiterungen von heute frueh: aus sechs Befinden-Fragen wurden
  zwoelf, aus vier Kategorien sechs, und die Personenkachel zaehlt seit
  heute in Kaesten statt in einem Satz. Die Zahlen standen als feste
  Werte in den Pruefdateien.

  Nicht die Zahlen angepasst, sondern ABGELEITET: aus
  ENTWICKLUNG_BLOECKE und ENTWICKLUNG_PUNKTE.befinden. Eine feste Zahl
  ist eine Rechnung von gestern; wer sie nachtraegt, traegt sie beim
  naechsten Mal wieder nach.

GEPRUEFT

  pruef-nachwuchs 123 -> 152. Vier Gegenproben, jede trifft ihr Ziel:
  Liste auch vor der Probe -> 1 rot, Abhaken ohne Stufenpruefung -> 7
  rot, "entscheidbar" nach Anzahl statt nach den drei -> 3 rot, Name
  nicht mitgeliefert -> 1 rot.

  Dazu gruen: schritt 65, befinden 75, entwicklung 43, uebergang,
  neue-seiten, rechtetafel, css-klassen, struktur, deutsche-texte,
  modi-wortleck.
2026-09-17 16:15:21 +02:00
DogFatherGit 470c65a46b Anfragen fuer Modi: ein Fragebogen, vier Wege, eine Bruecke
Filipe, mit dem Bildschirmfoto des Bretts "Mitmachen": "ich will dass
die leute sich da anonym bei mir melden koennen ... wie ein fragebogen
wieso die person modi werden will warum sie sollte, positiv negative
sachen ... und dan soll ich annehmen ablehnen, in warteschlange stellen
oder sofort kommunizieren koennen. und wenn ich annehme dan soll diese
person automatisch zu talente kategorie weiter geleitet werden."

Seine zwei Entscheidungen auf Rueckfrage: "Vertraulich, aber nicht
namenlos" und "Du und die rechte Hand".

WAS ES GIBT

  15 Fragen in 6 Gruppen, 9 davon Pflicht. Vier davon standen nicht auf
  seinem Zettel und kommen aus der Recherche zu Moderator-Bewerbungen:
  Alter, frühere Sperren, "ein Freund bricht die Regeln - was machst
  du?" und "was kannst du nicht so gut?". Die letzte ist die
  aussagekraeftigste: Wer darauf "nichts" schreibt, hat sich gerade
  selbst beantwortet.

  Vier Wege: Reden - Warteschlange - Annehmen - Ablehnen. "Reden" steht
  vorne, weil die haeufigste richtige Antwort auf eine Bewerbung eine
  Rueckfrage ist und keine Entscheidung; stuende "Annehmen" oben, wuerde
  es geklickt.

  "Sofort kommunizieren" ist ein Satz, den sie liest. Kein Chat: Ein
  Zugang aus der Community steht ausdruecklich in keiner Chatliste
  (AUSSEN_ROLLEN). Der Satz ist damit der einzige Weg, dieser Person
  etwas zu sagen -- deshalb ist er bei "Reden" und "Ablehnen" Pflicht,
  und WELCHE Wege ihn verlangen, steht im Katalog und nicht zweimal.

  Nach "Annehmen" entsteht ein Talent auf der Stufe "Angesprochen". Die
  ersten beiden Stufen fragen, ob ueberhaupt Interesse besteht; wer sich
  selbst meldet, hat das beantwortet.

WAS DABEI HERAUSKAM, DAS NICHT GESUCHT WAR

  aufgaben.js entschied mit `p.rolle === 'modi' || p.rolle === 'hand'`,
  wer eine Katalogaufgabe bekommen kann. Diese Datei ist ohne Anmeldung
  aus dem offenen Netz lesbar -- damit stand der verborgene Zugang darin
  nachzulesen. Jetzt entscheidet es der Server und schickt ein Ja/Nein.
  Gefunden von der Wortleck-Pruefung, nicht vom Auge.

  pruef-struktur meldete teilen.html seit heute frueh als "von nirgendwo
  verlinkt" -- und lag falsch: Auf sie zeigt `share_target.action` im
  Manifest. Die Manifeste sind jetzt Verweisquelle, nicht die eine Seite
  eine Ausnahme.

  Und im Bildschirmfoto stand der Schriftzug der Buehne mitten im Text
  einer Anfrage: `color-mix(..., transparent)` mischt mit DURCHSICHTIG.
  Deckend ist `#ffffff 6%`, so wie es .t-karte macht. Dieselbe Stelle
  hat mich heute schon einmal erwischt.

GEPRUEFT

  pruef-bewerbung 77, davon 14 im Browser. Vier Gegenproben, jede trifft
  genau ihr Ziel: Bruecke ohne "genau einmal" -> 2 rot, Vertraulichkeit
  weg -> 5 rot, Nachricht-Pflicht weg -> 2 rot, Knopf ohne Rollenfrage
  -> 1 rot.

  Dazu unveraendert gruen: rollen 315, modi-verborgen 80, modi-katalog
  49, entwicklung 43, treff, bereiche-lesend, haus-seiten, alle-wege,
  rechtetafel, css-klassen, struktur, deutsche-texte, start-ansicht,
  sicht, aufgabenbrett, womit, kanaele.
2026-09-17 15:58:28 +02:00
DogFatherGitandClaude Opus 5 a0d9dc38e4 Teilen -> Workspace: aus fuenf Schritten wird ein Tipp
SCHRITT 4 AUS DEM VIDEO-PLAN
Filipe postet ein Video auf dem Handy. Bisher: Link kopieren, App
oeffnen, Bereich suchen, Feld finden, einfuegen. Fuenf Schritte, von
denen jeder einzelne der Grund sein kann, es "spaeter" zu machen -- und
spaeter heisst nie.

Jetzt: in TikTok auf "Teilen", DogFather waehlen, uebernehmen. Die neue
Seite workspace/teilen.html ist das Ziel dieses Tipps, eingetragen als
share_target in beiden Manifesten.

DER STOLPERSTEIN, DEN JEDE ANLEITUNG VERSCHWEIGT
Das Teilen-Ziel kennt drei Felder: title, text, url. Man baut es, testet
mit "?url=https://…" und ist fertig.

IM ECHTEN LEBEN KOMMT DER LINK IN `text`. Android-Apps -- TikTok
eingeschlossen -- teilen als reinen Text: "Sieh dir das an!
https://vm.tiktok.com/xyz/" steht dann in `text`, und `url` ist leer.
Wer nur `url` liest, hat eine Seite gebaut, die im Test funktioniert und
auf dem Handy eine leere Maske zeigt. Gesucht wird deshalb in allen drei
Feldern nach einem MUSTER, nicht nach einem Feldnamen -- und ein
Satzzeichen am Ende gehoert nicht zur Adresse.

SIE TRAEGT NICHT VON SELBST EIN. Die Seite kann nicht wissen, ob der
Griff in die Tasche gemeint war. Ein Video, das ungefragt in den
Highlights landet, muss jemand wieder loeschen -- das ist mehr Arbeit
als ein Tipp auf "Uebernehmen". Und wohin ist eine Frage, keine
Annahme: Highlights sind vorausgewaehlt, Treff und Anschlagbrett
stehen daneben.

GET UND NICHT POST. POST braeuchte einen Service Worker, der die
Anfrage abfaengt -- eine Stelle mehr, die kaputtgehen kann, und zwar
genau die unsichtbare: Man tippt auf Teilen und landet auf einer leeren
Seite. Hier wird nur ein Link geteilt, keine Datei.

GESEHEN, NICHT NUR GEZAEHLT
Das Bildschirmfoto auf 390 px zeigte einen Mangel, den keine Zahl
gemeldet haette: Das gewaehlte Ziel hob sich nur ueber Helligkeit ab.
Bei einer echten Wahl ist das zu wenig, und wer Farben schlecht
unterscheidet, sieht gar nichts. Jetzt: farbiger Streifen links,
deutlicherer Grund -- und ein HAKEN, der ohne jede Farbwahrnehmung
funktioniert.

EIN SICHERHEITSFUND NEBENBEI -- UND ER IST DER WICHTIGERE
pruef-alle-wege meldete: Von 126 schreibenden Wegen hatte genau EINER
keine Herkunftspruefung.

    POST /workspace/api/aufbewahrung/jetzt  ->  200

Eine beliebige fremde Seite kann im Browser eines angemeldeten
DogFather ein Formular dorthin abschicken; der Browser gibt das
Sitzungsplaetzchen mit, der Server fuehrt aus. Und ausgerechnet dieser
Weg: aufbewahrungLauf() LOESCHT abgelaufene Daten. Ein Aufruf zur
falschen Zeit loescht wirklich etwas, und im Protokoll sieht es aus,
als haette DogFather es selbst angestossen.

Die anderen 125 Wege hatten den Riegel -- dieser eine wurde beim
Hinzufuegen uebersehen. Genau dafuer geht die Pruefung ALLE Wege durch,
statt einer Liste zu glauben. Behoben, danach: "kein schreibender Weg
nimmt eine fremde Herkunft an".

DIE PRUEFUNG (server/pruef-teilen.mjs, 27 Pruefungen)
Auf 390 px gemessen -- diese Seite wird fast nur dort geoeffnet, eine
Messung auf 1400 px misst etwas, das niemand sieht. Geprueft wird der
Satz mit Link darin, das Satzzeichen am Ende, der Fall ohne Link
(Feld zum Einfuegen statt Fehlermeldung), das Eintragen, die Dublette,
das zweite Brett -- und dass share_target in BEIDEN Manifesten steht.
Ohne den Eintrag erscheint der Workspace gar nicht erst im Teilen-Menue,
und die ganze Seite waere unerreichbar, ohne dass eine der anderen
26 Pruefungen es merkt.

GEGENPROBE: nur `url` lesen statt aller drei Felder -- also genau die
naheliegende Fassung, die im Test funktioniert und auf dem Handy
versagt -> 8 Pruefungen rot.

Stempel 202609171416.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 14:17:16 +02:00
DogFatherGitandClaude Opus 5 d69eb34448 Die Kanalzeile -- und der Kasten, der auf dem Chili-Motiv stand
SCHRITT 3 AUS DEM VIDEO-PLAN: DIE KANALZEILE
Filipe: "fuer meinen Account, dogfather, dann dogfather clips und
hasidog." Sobald Videos aus drei Kanaelen nebeneinander liegen, ist die
erste Frage nicht "welche Art", sondern "von welchem Kanal".

ALS ZWEITE DIMENSION, nicht als weiterer Wert in derselben Leiste. Der
vorhandene Filter ist EIN Wert (Alle / Nur offene / die Arten); wer den
Kanal dort hineinpresst, kann "nur offene Clips von HasiDog" nicht mehr
fragen. Zwei getrennte Reihen zeigen ausserdem, dass es zwei Fragen
sind -- in einer Zeile klickt man das zweite und wundert sich, warum
das erste wieder aus ist.

SIE ERSCHEINT NUR AB ZWEI KANAELEN, und die Kanaele werden aus den
vorhandenen Eintraegen abgeleitet statt aufgezaehlt. Auf einem Brett
ohne Videos steht keine leere Leiste; bei einem Kanal steht kein
Filter, der nichts tut. Ein Knopf, bei dem nichts passiert, kostet das
Vertrauen in den naechsten.

Die drei Toene sind dieselben wie am Zeichen auf der Karte -- wer
"DogFather Clips" in Tuerkis filtert, findet darunter Karten mit
tuerkisem Zeichen. Ungewaehlt bleiben sie gedeckt: drei bunte Knoepfe
nebeneinander waeren eine Ampel, und eine Ampel sagt "gut/schlecht",
wo nur "welcher Kanal" gemeint ist.

DER KASTEN, DER AUF DEM CHILI-MOTIV STAND
Der leere Zustand der Talente-Seite von heute Vormittag hatte nur einen
gestrichelten Rand. Solange dort EIN Satz stand, ging das; jetzt stehen
dort drei Absaetze, fuenf Merkmale und zwei Knoepfe -- und das
Spicy-Media-Motiv mit Chilischoten und Neonlicht schien voll durch den
Text. Lesbar war das nicht, augenschonend erst recht nicht.

DIE WARNUNG STAND 70 ZEILEN WEITER UNTEN in derselben Datei, bei
.t-fuss, und beschreibt exakt diesen Fehler ("Sie stand als einziger
Text der Seite direkt auf der Buehne"). Ich habe sie gelesen und bin
trotzdem hineingelaufen. Ein Kommentar, der vor einem Fehler warnt,
verhindert ihn nicht -- gefunden hat es erst das Bildschirmfoto.

GESEHEN STATT GEZAEHLT (server/bild-stufen.mjs)
Stufenleiter und Talente-Seite waren heute Vormittag nur an Zahlen
geprueft. Das Bild zeigte: die Leiste sitzt sauber in einer Zeile
(1400 px) und in vier auf 412 px, nichts laeuft ueber den Rand, keine
Konsolenfehler -- und den Kasten ohne Grund.

DIE PRUEFUNG (server/pruef-kanalzeile.mjs, 14 Pruefungen)
Sie prueft nicht nur, DASS gefiltert wird, sondern dass das Richtige
uebrig bleibt: "weniger" allein waere auch erfuellt, wenn der Filter
irgendetwas wegwirft. Dazu der zweite Klick (hebt auf) und Abschnitt 4:
Kanal UND Art zusammen -- der eigentliche Grund fuer zwei Reihen.

ZWEI GEGENPROBEN:
  a) Kanalfilter ausgebaut       -> 3 Pruefungen rot
  b) Zeile immer anzeigen        -> 1 rot, genau der Ein-Kanal-Fall

UND ZWEI FEHLER IN DER PRUEFUNG SELBST, beide von mir:
  * Der Kartenselektor traf nichts, und die Messung meldete "0 -> 0".
    Das sah aus wie ein Ergebnis und war keins.
  * Beim Berichtigen machte String.replace aus "$$" ein "$" --
    seite.$$() wurde zu seite.$(). Der Fehler steht woertlich in den
    Hausregeln und hat trotzdem zugeschlagen. Aufgefallen ist er nur,
    weil "undefined" in der Ausgabe stand; "0" waere durchgegangen.
  * Und eine verlorene Escaping-Ebene machte aus /\s+/ ein /s+/ --
    die Pruefung ersetzte jedes "s" durch ein Leerzeichen und las
    "Ca per chläft im Wä chekorb". Sie wurde rot, und das war richtig.

Stempel 202609171407.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 14:08:15 +02:00
DogFatherGitandClaude Opus 5 8f0a184b9f Was DogFather eintraegt, sehen jetzt auch die anderen -- und 113 fertige Inhalte
Vier Bildschirmfotos, vier Auftraege. Vor dem Bauen gemessen
(server/mess-sichtbarkeit.mjs): alle Bereiche, alle vier Rollen.

ZWEI FEHLER, DIE NIEMAND GEMELDET HAETTE
Beide sahen auf DogFathers eigenem Bildschirm vollkommen richtig aus --
und das ist das Tueckische: Ein leeres Brett sieht nicht nach Fehler
aus, sondern nach "da ist eben noch nichts".

1. DIE FREIGABE. "Was ansteht" und "Highlights" zeigen der Community
   nur, was freigegeben ist. Ein aus dem Vorschlagskasten uebernommener
   Eintrag hatte keine Freigabe. Gemessen:

       Brett      DogFather  rechte Hand  Modi  Community
       ansteht        4           4         4        0
       highlight      3           3         3        0

   Filipe konnte fuellen, so viel er wollte -- fuer die Community
   blieben genau die zwei Bretter leer, auf die es ankommt. Wer aus dem
   Team uebernimmt, gibt jetzt zugleich frei: Die Freigabe fragt "hat
   das Team diesen Text gesehen?", und die Antwort ist beim Uebernehmen
   ja. Eine zweite Entscheidung daneben waere keine Sicherheit, sondern
   ein Klick.

2. TEAM_DOGI_ROLLEN IST {hand, modi} -- OHNE "admin". Die
   Sichtbarkeitsregel fuer Team Dogi lautete damit woertlich "Eintraege
   von hand oder modi". Folge: ALLES, was DogFather in Live, Technik,
   Community, Ideen, Angebote oder Rueckmeldung schreibt, war fuer sein
   eigenes Team unsichtbar. Das ist nicht erst seit dem Startkatalog so
   -- der hat es nur sichtbar gemacht, weil vorher ueberall Null stand
   und Null gleich Null aussieht, egal aus welchem Grund.

   Die Liste wird genau dort erweitert, wo es um Sichtbarkeit geht --
   NICHT in TEAM_DOGI_ROLLEN selbst: Diese Menge entscheidet auch,
   welches Haus jemand bewohnt. Ein Eintrag dort haette DogFather
   stillschweigend zur Crew umgezogen.

113 FERTIGE INHALTE IN DEN LEEREN KATEGORIEN
Gemessen waren elf Bereiche ausserhalb des Treffs komplett leer -- fuer
JEDE Rolle. Der Startkatalog kannte nur die sieben Treff-Bretter; die
Oberflaeche war die ganze Zeit bereit, es fehlten nur die Texte.
workspace-arbeit-start.js fuellt neun davon: Live, Content, Technik,
Community, Schutz, Ideen, Rueckmeldung, Angebote, Agentur.

"talente" und "entwicklung" bekommen ABSICHTLICH nichts: Dort waere ein
"fertiger Inhalt" ein erfundener Mensch -- ein Testdatensatz in einem
System, das echte Menschen bewertet. Die Talente-Seite bekommt ihre
Hilfe anders (siehe unten).

DER ENTWICKLUNGSKATALOG: 28 -> 68 PUNKTE, VIERTE STUFE
Filipe: "wieso ist da immer noch nicht perfektionniert wie bei den
anderen mit fortgeschritten und so, und VIIIIIEEEELLLLLL mehr aufgaben."
  * Neue Stufe "Fortgeschritten" zwischen "nach ein paar Monaten" und
    "wofuer man jemanden fragt" -- genau die Mitte fehlte.
  * Stufenleiter als FILTER ueber den Kategorien, wie die Checkliste es
    seit dem 10.09. vormacht. Aus r.erwartung gebaut, nicht aufgezaehlt.
  * Zwei neue Bloecke, die Filipe ausdruecklich wollte: "Clips, Schnitt
    und Kommentare" und "Waehrend der Stream laeuft" -- seine
    Wunschkategorien vom 17.09. ("videos schneide, kommentieren,
    markierungen").
  * Keine Note, keine Punktzahl, keine Rangliste. Unveraendert.

DAS BEFINDEN: 6 -> 12 FRAGEN, UND SIE MELDET SICH VON SELBST
Den 14-Tage-Rhythmus gab es schon -- er wirkte aber nur, WENN jemand die
Seite aufmachte. Wer sie vergisst, wurde nie wieder gefragt: Das war
eine Anzeige, keine Anfrage. Jetzt kommt sie ueber dasselbe Push-System
wie faellige Aufgaben, hoechstens einmal je sieben Tage, und sie fragt
rhythmus() aus workspace-befinden.js -- dieselbe Funktion wie die Seite,
keine zweite Formel daneben.
Sechs neue Fragen zu Erholung, Sinn, Klarheit, Anfeindung, Entwicklung
und dem Blick nach vorn, jede mit ihrer Einordnung.
Und an acht Stellen stand "sechs Fragen" ueber zwoelf Fragen -- wo ein
Skript den Text baut, wird jetzt gezaehlt; in den festen Seiten steht
gar keine Zahl mehr.

DIE TALENTE-SEITE, WENN NIEMAND DARAUF STEHT
Statt "Noch niemand auf der Liste" stehen dort jetzt die fuenf Gruppen
mit ihren 21 Anzeichen -- die gab es laengst, sie waren auf der leeren
Seite nur nie zu sehen. Dazu der Weg in beide Richtungen: woher ein
Talent kommt (der Treff) und wo es endet (die Entwicklung).

DIE PRUEFUNG (server/pruef-alle-sehen-es.mjs, 42 Pruefungen)
Sie prueft BEIDE Haelften von Filipes Satz. Nur zu zaehlen, ob alle
alles sehen, waere gruen, wenn man saemtliche Schranken entfernte --
Abschnitt 4 belegt, dass 19 Bereich-Rollen-Paare zu bleiben und die
Community an keinen der elf Arbeitsbereiche kommt.

ZWEI GEGENPROBEN, weil 42 von 42 im ersten Lauf kein Beweis ist:
  a) "admin" aus der Team-Sicht entfernen  -> 13 Pruefungen rot
  b) Freigabe beim Uebernehmen abschalten  ->  2 rot, genau ansteht
     und highlight
Jede trifft ihr Ziel und nicht alles.

UND EINE LUECKE IN EINER ALTEN PRUEFUNG
pruef-deutsche-texte war gruen -- und hatte die 113 neuen Texte, die 40
neuen Entwicklungspunkte und die 6 neuen Fragen nie gesehen: Sie stehen
in Dateien, die sie nicht kannte. Jetzt 391 statt 174 geprueften
Texten. (Meine erste Untergrenze stand auf 400 und war sofort rot --
geraten statt gemessen.)

Stempel 202609171318.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 13:18:45 +02:00
DogFatherGitandClaude Opus 5 f05783ebc8 Link einfuegen, Video steht in der App -- Stufe A des Video-Plans
Filipe: "damit meine videos auch da auf der app rein kommen ... sobald
ich ein video poste erscheint es sofort in der app fuer die ganze
community ... dass man das Coverbild und den Text sieht ... fuer meinen
Account, dann DogFather Clips und HasiDog."

Der Weg, der HEUTE funktioniert -- ohne Freigabe, ohne Geheimnis, ohne
Wartezeit: Adresse einfuegen, alles andere geht von allein.

  Link -> oEmbed (Titel, Cover-Adresse, Account)
       -> Cover HERUNTERLADEN und bei uns ablegen
       -> Eintrag mit Bild, Text und Knopf zum Video

DAS COVER WIRD KOPIERT, NICHT VERLINKT -- der wichtigste Satz.
TikToks Bildadresse ist signiert und laeuft ab. Heute an einem echten
Video nachgemessen: x-expires = 1789812000, also in 48 Stunden. Wer sie
nur speichert, hat uebermorgen schwarze Kacheln. Beim Bauen merkt man
das nicht und beim Testen auch nicht -- es faellt erst am uebernaechsten
Tag auf, und dann sieht die ganze App kaputt aus.

Deshalb wandert das Bild in dieselbe Ablage wie jeder Anhang und geht
durch dieselbe Bytepruefung. Ein heruntergeladenes Cover ist eine
FREMDE Datei; dass der Typ hier von einem fremden Server behauptet wird
statt vom eigenen Browser, macht ihn nicht glaubwuerdiger.

NUR SEINE EIGENEN KANAELE. Der Account aus der Antwort wird gegen
KANAELE geprueft (kanalVonHandle). Genommen wird author_url (.../@name),
nicht author_name -- der Anzeigename aendert sich, wenn jemand ihn
umstellt. Ein fremdes Video in Filipes Highlights waere nicht bloss
falsch einsortiert, es waere fremder Inhalt unter seinem Namen: 403.

DIE PRUEFUNG SCHALTET TIKTOK AB (server/pruef-video.mjs, 37 Pruefungen)
Ein nachgebauter Dienst auf 127.0.0.1 antwortet wie TikTok, mitsamt
Ablaufstempel. Im letzten Abschnitt wird er ABGESCHALTET. Danach muss
die alte Cover-Adresse ins Leere laufen und unsere weiterhin ein Bild
liefern -- beides wird gemessen, nebeneinander. Waere das Bild nur
verlinkt, waeren beide tot, genau wie uebermorgen im Betrieb.

Die Adresse des Dienstes kommt aus TIKTOK_OEMBED_BASIS. Steht sie nicht
da, gilt TikTok -- kein Verhalten, das sich still aendert. Eine
Pruefung, die das echte TikTok braucht, misst fremde Verfuegbarkeit
statt unseren Code und wird irgendwann rot, ohne dass etwas kaputt ist.

VIER GEGENPROBEN, weil 37 von 37 im ersten Lauf kein Beweis ist:
  a) Cover nicht mehr kopieren      -> 9 Pruefungen rot
  b) author_name statt author_url   -> 22 rot
  c) Bytepruefung entfernen         -> 2 rot (genau Abschnitt 5)
  d) Dublettenpruefung entfernen    -> 4 rot (genau Abschnitt 4)
Jede schlaegt dort an, wo sie soll. Und eine fuenfte Gegenprobe ist ins
Leere gelaufen: Der Patch lief ueber python3, das es hier nicht gibt --
die Datei blieb unveraendert und der Lauf war gruen. Haette ich die
Ausgabe nicht gelesen, haette ich behauptet, die Pruefung koenne rot
werden, ohne sie je rot gesehen zu haben. Der dritte Ausgang, an mir
selbst.

DAZU:
- eintraege.quelle_url / quelle_kanal / quelle_geholt_am (Umstellung)
- KANAELE bekommt handle, dazu kanalVonHandle()
- videoRouter steht VOR bereicheRouter, sonst schluckt /:bereich ihn
- Eingabefeld und Kanal-Knopf in bereich.html/.js, Farben wie bei den
  Aufgaben-Kanaelen
- Stempel 202609171249

Nicht darin: die Kanal-Filterzeile in der Galerie, die Handy-Verknuepfung
(Teilen -> Workspace) und der Zustand "nicht mehr da" fuer geloeschte
Videos. Stufe B (Display API) braucht Filipes Entwickler-Freigabe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:50:42 +02:00
DogFatherGitandClaude Opus 5 4a440e42d8 Die Community-Texte sind auf DogFather bezogen
Filipe, mit einem Bildschirmfoto der fertigen Vorschlaege im Treff:
"die sachen sollen immer auf mich bezogen sein bitte. ich, dogfather
bin der mittelpunkt immer."

Er hatte recht, und es war MESSBAR: 47 Eintraege, "DogFather" kam
FUENFMAL vor, ein namenloses "wir" sechzehnmal. Das las sich wie der
Community-Bereich von irgendwem.

Jetzt 39 von 52 (75 %) -- und die vier Bretter, die die Community
wirklich sieht, zu 100 %: Treff, Anschlagbrett, Wunschliste,
Highlights. Dazu fuenf neue Eintraege, die es vorher gar nicht gab
("Wer ist DogFather ueberhaupt?", "Was soll Casper mal machen?",
"Mehr mit Casper", "Die drei Kanaele", "Ein Ausschnitt fuer die
Clips").

Aus "Was sollen wir im naechsten Stream machen?" wird "Was soll
DogFather im naechsten Stream unbedingt machen?". Aus "Sag Hallo -- wie
bist du hier gelandet?" wird "ueber welchen Kanal bist du gekommen?"
-- und nennt die drei beim Namen.

UND ES WIDERSPRICHT DER ANDEREN REGEL NICHT.
Filipe am 18.08.2026: "mich bitte nie wie da hoeher stellen wie andere,
ich bin genau so viel wert wie die andere." Das galt dem TEAM --
Manager, Scouts, Modis. Hier geht es um die Community, und die ist
wegen seiner Streams da. Wo das Team in diesen Texten vorkommt, steht
es weiter auf Augenhoehe: Es moderiert, es entscheidet im Alltag
selbst, es wird nicht als Gefolge beschrieben. In "Wer entscheidet
das" steht beides nebeneinander.

WARUM EINE QUOTE UND NICHT "JEDER TEXT":
Bei der Telefonseelsorge oder "Melden ist kein Petzen" waere ein
eingebautes "DogFather" aufgesetzt. Ein Text, der den Namen trotz
allem traegt, ist schlechter als einer ohne. Deshalb 60 % als Grenze
und 100 % dort, wo es um seine Streams geht.

pruef-treff-start jetzt 41 Pruefungen, mit Gegenprobe in beide
Richtungen: Ein anonymer Satz MUSS erkannt werden, ein bezogener darf
nicht faelschlich anschlagen.

pruef-deutsche-texte 12 gruen -- die neuen Texte tragen echte Umlaute.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:30:32 +02:00
DogFatherGitandClaude Opus 5 4bd19a4096 Die Community-Rolle laesst sich endlich anlegen
Filipe: "und wieso kann ich immer noch keine community rolle
erstellen?"

Nachgemessen statt geraten: Die Auskunft schickte "gast/Community" als
waehlbare Rolle mit, die Oberflaeche baute den Knopf daraus -- und das
Anlegen antwortete 400 "Unbekannte Rolle." Genau so reproduziert.

DIE URSACHE: EINE LISTE, ZWEI FRAGEN
Die Pruefung las `ROLLEN`, und `ROLLEN` ist `ROLLEN_REIHE` -- die
SORTIERREIHENFOLGE. Dort fehlt "gast" mit Absicht; der Kommentar in
workspace.js sagt es woertlich ("steht mit Absicht NICHT in der Liste,
sie faellt ans Ende").

`ROLLEN_REIHE` beantwortet "in welcher Reihenfolge", nicht "welche gibt
es". Genau davor wird in diesem Haus an zehn Stellen gewarnt -- und
hier stand es vier Zeilen ueber der Stelle, an der es passiert ist.

Gefragt wird jetzt `darfAnlegen` -- dieselbe Auskunft, aus der die
Oberflaeche ihre Knoepfe baut. Damit koennen die beiden nicht mehr
auseinanderlaufen.

ZWEI NEBENBEFUNDE, beide groesser als der gemeldete Fehler:

1. DIE ALTE PRUEFUNG LIESS "admin" DURCH. `ROLLEN_REIHE` enthaelt sie.
   Filipes Regel vom 11.09. ("dogfather soll man nicht auswaehlen
   koennen, das ist die einzige die man nicht auswaehlen kann") stand
   nur in ANLEGBAR -- und die wurde hier nicht gefragt. Es liess sich
   also ein zweiter DogFather-Zugang anlegen.

2. DIESELBE ZEILE STAND EIN ZWEITES MAL, beim Rollenwechsel. Auch eine
   bestehende Person liess sich nicht zu "Community" machen. Dort stand
   die richtige Pruefung (`darfAnlegen`) schon direkt darunter -- die
   falsche davor kam ihr nur zuvor. Und sie antwortete gespraechiger
   (403 "Diese Rolle vergibst du nicht." gegen 400 "Unbekannte
   Rolle."); wer durchprobiert, haette daran ablesen koennen, welche
   Rollen es gibt. Jetzt beide Faelle wortgleich.

   Gefunden hat das nicht das Lesen, sondern die neue Pruefung: Ihre
   Suche nach der alten Zeile reichte in die Nachbarroute hinein.

NEU: pruef-rollen-anlegen (11 Pruefungen)
Sie schreibt keine Liste ab, sondern holt sich die Rollen aus
`darfAnlegen` -- derselben Quelle wie Route und Oberflaeche -- und legt
JEDE davon wirklich an. Eine eigene Liste waere eine dritte gewesen und
damit dieselbe Falle noch einmal.

Dazu die Gegenproben: eine erfundene Rolle, eine leere, und ein zweiter
DogFather -- alle drei abgelehnt.

pruef-rollen 315, pruef-personen-formular 36, pruef-personen-liste,
pruef-rechtetafel 19: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:24:11 +02:00
DogFatherGitandClaude Opus 5 79e675b846 Stufe 6 und 7: Der Treff wird ein Gespraech, jedes Brett bekommt seine Form
Damit sind alle acht Stufen des Plans gebaut.

STUFE 6 -- DAS GESPRAECH
"Der Treff -- Hallo sagen, fragen, loben" war eine Liste aus Karten.
Der einzige Bereich, in dem Menschen MITEINANDER reden sollen, zwang
sie, nebeneinander zu reden: Jeder schrieb eine eigene Karte, niemand
antwortete jemandem.

Jetzt: Antworten eingerueckt unter ihrem Beitrag, aelteste zuerst (so
liest man ein Gespraech), mit Namen und Rolle. Das Feld steht immer da
statt hinter einem "Antworten"-Knopf -- ein leeres Feld ist die
deutlichste Einladung, die es gibt. Nur EINE Stufe eingerueckt: Auf
390 px ist bei der zweiten Schluss.

Eine EIGENE Tabelle, kein Eintrag mit "antwort_auf": Eine Antwort hat
keine Art, keinen Zustand, keine Frist und gehoert in keinen Filter.
Als Eintrag gefuehrt haette sie zwanzig immer leere Spalten -- und
tauchte in jeder Zaehlung auf, die Beitraege zaehlt.

Und nicht ueberall: nur Treff und Wunschliste. Aus dem Plan, §9 -- ein
Antwortfeld unter jedem Aushang hiesse, jeder Aushang muss betreut
werden.

ZWEI FEHLER, BEIDE VON DER PRUEFUNG GEFUNDEN

1. EIN PFAD, DER AUSSAH WIE EIN BEREICH.
   `/api/bereich/antwort/:id` lief in die Middleware auf
   `/api/bereich/:bereich` -- "antwort" ist kein Bereich. Fuer
   DogFather ging es (ein frueherer Zweig liess ihn durch), fuer einen
   Modi kam 404. Ein Weg, der je nach ROLLE an voellig anderer Stelle
   scheitert, sucht man lange. Liegt jetzt unter `/api/antwort/:id`.

2. UND EIN ECHTES LOCH.
   Die Loeschregel hiess `!darfSchreiben(req.person, "treff")` -- also
   "wer schreiben darf", und das duerfen Gaeste ab der Stufe "dabei".
   JEDER GAST HAETTE JEDE FREMDE ANTWORT LOESCHEN KOENNEN.

   Gefunden hat es eine Pruefung mit einer FALSCHEN Erwartung: Sie
   verlangte, dass ein Modi keine fremde Antwort loeschen kann. Das war
   falsch -- er moderiert ja --, aber der Weg dorthin hat das echte
   Problem freigelegt. Jetzt entscheidet TREFF_TEAM_ROLLEN.

   Der Gast-Fall ist ueber HTTP nicht messbar (er kommt nur ueber die
   crew-Adresse herein, und den Host-Kopf kann fetch nicht setzen).
   Statt stillschweigend zu ueberspringen prueft die Pruefung die REGEL
   selbst -- und dass die Route wirklich diese Menge benutzt.

STUFE 7 -- JEDES BRETT BEKOMMT SEINE FORM
- "Regeln & Hilfe" ist ein DOKUMENT: Sprungmarken oben, vier
  Abschnitte (Regel, Was passiert wenn, Hilfe, Haeufige Frage). Man
  schlaegt es im Streitfall auf und will FINDEN, nicht scrollen.
  scroll-margin-top, sonst verschwindet die angesprungene Ueberschrift
  unter der Kopfleiste und der Sprung sieht aus wie ins Leere.
- "Anschlagbrett" zeigt grosse AUSHAENGE statt Zeilen -- gemessen
  21 px Titel statt 17. Ein Aushang zwischen dreissig anderen ist kein
  Aushang.
- "Mitmachen" gruppiert nach Art, die drei Schritte zuerst.

UND EINE SCHRIFT, DIE ZU KLEIN WAR: Die Rollen-Marke an einer Antwort
stand auf 11,2 px, die Hausgrenze liegt bei 11,5. Die Grenze anzuheben
waere der bequeme Weg gewesen -- und ab da haette pruef-css-klassen
nichts mehr gehalten.

NEU: pruef-gespraech (27 Pruefungen)
pruef-treff-start jetzt 34 (Stufe 7 mitgeprueft)
Alle Community-Pruefungen gruen: gespraech 27, treff-start 34,
kreislauf 23, countdown 22, wunschliste 30, galerie 26, bremse 16,
treff 66, bereiche-lesend, css-klassen, deutsche-texte 12.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 12:12:21 +02:00
DogFatherGitandClaude Opus 5 b396e548ab Stufe 8: Der Kreislauf -- ein Wunsch kommt als Clip zurueck
Bisher waren die acht Bretter acht Silos. Ein Wunsch wurde angenommen,
irgendwann passierte etwas im Stream, irgendwann lag ein Clip bei den
Highlights -- und nichts davon wusste voneinander. Wer den Wunsch
geschrieben hatte, erfuhr NIE, dass er erfuellt wurde.

    Wunsch  ->  Termin bei "Was ansteht"  ->  Clip bei "Highlights"

Das ist der Unterschied zwischen einem Briefkasten und einer Community.
Jemand schreibt einen Wunsch und sieht ihn vier Wochen spaeter als Clip
wieder -- mit seinem Namen daneben.

ZUM DRITTEN MAL LAG DER PLAN DANEBEN. Dort stand "`aus_eintrag_id`
gibt es in der Tabelle bereits". Gibt es -- an den AUFGABEN. Die
Eintraege hatten nichts dergleichen. Dreimal an einem Tag, und jedes
Mal hat es das Messen gefunden, nicht das Nachdenken.

EINE HANDLUNG, KEIN AUSWAHLFELD. Der Zusammenhang entsteht durch
"daraus wird ein Termin" -- als Knopf an dem Wunsch, um den es geht.
Wer ein Formular ausfuellt, denkt nicht an den Wunsch von letzter
Woche, und ein Auswahlfeld mit vierzig Eintraegen benutzt niemand.

Die Kette steht auf beiden Karten: "Aus Wunschliste: ... von Lena"
(ruhig, es ist Herkunft) und "Daraus wurde: Highlights ..." (gruen, das
ist die Nachricht, auf die jemand gewartet hat).

ON DELETE SET NULL, nicht CASCADE: Wird der Wunsch geloescht, bleibt
der Clip. Er ist ja trotzdem passiert.

UND DIE PRUEFUNG VON STUFE 2 HAT STUFE 5 ERWISCHT.
Der Startkatalog stand ueber dem Countdown und schob die Antwort auf
"wann ist der naechste Stream" von 458 px auf 1488 px -- aus dem
ersten Handybildschirm heraus. Gefunden hat das nicht das Auge,
sondern das Abnahmekriterium aus §7 des Plans, das seit heute Vormittag
in pruef-countdown steht.

  DIE REGEL DARAUS: Ein WERKZEUG (fuer das Team) draengt nie eine
  ANTWORT (fuer alle) nach unten.

Der Countdown steht jetzt ganz oben, noch vor den Filtern -- gemessen
342 px statt 458.

NEU: pruef-kreislauf (23 Pruefungen)
Lena schreibt einen Wunsch, daraus wird ein Termin, daraus ein
Highlight. Geprueft: Der Titel wandert mit, der NAME wandert mit, beide
Enden sehen die Kette, Lena sieht sie auch (ein Kreislauf, den nur das
Team sieht, ist keiner), zweimal derselbe Weg verdoppelt nichts -- und
die Gegenprobe, dass ein ANDERER Weg vom selben Wunsch sehr wohl geht.

Und wohin sie NICHT fuehrt: nicht in die Content-Planung eines
Creators. Dort steht Arbeit, die die Community nichts angeht.

pruef-countdown 22, pruef-treff-start 27, pruef-wunschliste 30,
pruef-galerie 26, pruef-treff 66, pruef-bremse 16, pruef-css-klassen:
alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:59:17 +02:00
DogFatherGitandClaude Opus 5 7701f5e5e5 47 fertige Inhalte statt acht leerer Bretter
Filipe, mit drei Bildschirmfotos nebeneinander -- Der Treff, das
Anschlagbrett, Was ansteht, alle drei mit demselben grauen Kasten:

  "ich meine alle kategorien sehen einfach so scheisse und leer aus,
   ich will fertige sachen schon drin wo auch die community und alle
   anderen benutzen koennen"

Er hat recht, und das ist mein Fehler: Es stand in MEINEM Plan, §5.1
-- "Acht leere Seiten sind schlimmer als keine." Ich habe es
aufgeschrieben und danach fuenf Stufen lang Technik gebaut.

Dreimal derselbe Satz auf drei Bildschirmen sieht nicht nach "neu" aus,
sondern nach defekt.

WAS JETZT BEREITLIEGT (47 Eintraege)
  Regeln & Hilfe   15   das Nachschlagewerk: sechs Regeln, drei
                        Folgen-Erklaerungen, drei Hilfen, drei Fragen
  Mitmachen        11   der Weg in drei Schritten, vier Aufgabengebiete,
                        vier ehrliche Fragen ("Was habe ich davon?")
  Der Treff         6   Gespraechsanfaenge, auf die man in einem Satz
                        antworten kann
  Anschlagbrett     5   Willkommen, Ablauf, wo was hingehoert, Danke
  Wunschliste       4   Beispiele, die zeigen, wie ein guter Wunsch
                        aussieht
  Was ansteht       4   Terminvorlagen
  Highlights        2   was hier hingehoert

NICHT AUTOMATISCH BEIM START. Ein Text, den niemand gelesen hat,
stuende sonst als Ansage des Teams auf einer oeffentlichen Seite.
"Bleibt fair" klingt harmlos, bis jemand fragt, was das im Streitfall
heisst -- und dann muss dahinterstehen, WER es gemeint hat. Uebernehmen
ist eine Entscheidung; automatisch fuellen waere eine Behauptung. Und
jeder Text laesst sich vorher aendern.

ZWEI BEREICHE SIND KEIN KATALOG, SONDERN FERTIGE SEITEN: "Regeln &
Hilfe" und "Mitmachen" sind Nachschlagewerke, keine Feeds. Ein leeres
Regelwerk ist schlimmer als gar keins -- im Streitfall hat dann niemand
etwas in der Hand. Die Regeln sagen ausserdem jeweils, was PASSIERT,
nicht nur was verboten ist, und die Hilfe nennt die Telefonseelsorge.

UND JEDER BEREICH SAGT JETZT SEINEN EIGENEN SATZ, wenn er leer ist:
"Gerade gilt nichts Besonderes. Das ist eine gute Nachricht." /
"Noch hat niemand Hallo gesagt. Sei der Erste -- ein Satz reicht."

DIE FALLE, DIE ICH MIR SELBST GEBAUT HATTE: Die Bremse aus Stufe 4
zaehlt zehn Beitraege je Stunde. Wer fuenfzehn Regeln uebernimmt,
haette nach der zehnten eine halb gefuellte Seite und die Meldung, er
habe zu viel geschrieben -- genau die Sorte Sicherung, die das richtige
Verhalten bestraft und deshalb abgeschaltet wird. Das Uebernehmen ist
eine einzelne Handlung des Teams und geht nicht durch die Bremse; die
Pruefung weist beides nach.

NEU: pruef-treff-start (27 Pruefungen)
Der Katalog selbst (jede Art gibt es im Bereich, jeder Text sagt mehr
als sein Titel, kein Titel doppelt, echte Umlaute), das Uebernehmen
(einzeln, alle, zweimal verdoppelt nichts), die Verborgenheit, die
sieben verschiedenen Leertexte -- und im Browser: elf Vorschlaege,
ein Klick, elf Eintraege, Katalog verschwindet.

pruef-treff 66, pruef-bremse 16, pruef-deutsche-texte 12,
pruef-bereiche-lesend, pruef-css-klassen: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:51:15 +02:00
DogFatherGitandClaude Opus 5 4b14906371 Stufe 5: Highlights als Galerie -- und ein enger Weg fuer Bilder
Aus dem Plan im Vault. "Eure Clips und Bilder" zeigte Textkarten mit
einem Anhang darunter. Ein Bild als Anhang unter einer Ueberschrift ist
kein Highlight -- dieser Bereich lebt vom Sehen. Jetzt steht das Bild
OBEN, der Text ist Bildunterschrift.

ZWEI DINGE WAREN ANDERS ALS IM PLAN

1. "Anhaenge sind schon da" stimmte nicht. Sie hingen an AUFGABEN
   (`dateien.aufgabe_id`); ein Eintrag konnte gar kein Bild tragen.
   Neue Spalte `eintrag_id`.

2. UND DER WICHTIGE, ein Sicherheitsthema: Alles in dieser Ablage geht
   bewusst als DOWNLOAD hinaus (`application/octet-stream`,
   `Content-Disposition: attachment`). Eine hochgeladene HTML- oder
   SVG-Datei wuerde sonst im Browser als Seite DIESER Domain laufen --
   mit Zugriff auf die Sitzung. Eine Galerie braucht also einen
   eigenen, engen Weg, keine Lockerung der alten Regel.

DIE FRAGE "IST DAS EIN BILD?" DARF NICHT `dateien.typ` BEANTWORTEN.
Diese Spalte traegt den vom Browser BEHAUPTETEN Typ
(`req.get("content-type")`) -- wer hochlaedt, bestimmt ihn selbst. Eine
Galerie, die ihm glaubt, liefert auf Zuruf alles inline aus. Erkannt
wird deshalb an den ERSTEN BYTES: PNG, JPEG, GIF, WEBP.

SVG IST AUSDRUECKLICH NICHT DABEI. Es ist ein Bildformat UND kann
Skript enthalten -- genau die Luecke, gegen die die Regel gebaut wurde.
Ein Format, das beides ist, gehoert nicht in die Ausnahme.

Kein Bild heisst 404, nicht 415: Eine eigene Antwort waere die Auskunft
"diese Nummer gibt es, sie ist nur kein Bild", und die laesst sich
durchzaehlen.

WESSEN REGEL GILT: Ein Bild am Community-Beitrag folgt dem BEITRAG,
nicht der Dateiablage. Deren Regel haengt an Creator-Zuordnungen, und
ein Gast hat keine -- er saehe sonst nie ein Highlight, obwohl es fuer
ihn gemacht ist.

NEU: pruef-galerie (26 Pruefungen)
Der Beweis steht in zwei Zeilen: Am Beitrag haengen VIER Dateien --
zwei echte PNGs, ein SVG und eine HTML-Datei, die sich als
"image/png" ausgibt. Im Raster stehen ZWEI. Die anderen beiden holt
der Browser, bekommt 404, und der error-Handler raeumt sie weg: kein
leerer Rahmen, kein kaputtes Symbol.

Dazu die Gegenprobe in die andere Richtung -- ein echtes PNG, das sich
als "text/plain" ausgibt, geht durch. Ohne sie hiesse "404" nur, dass
der Weg immer ablehnt. Und die Konsolenpruefung laesst genau die zwei
gewollten 404 zu und nichts sonst; ein pauschales "Konsole egal" haette
jeden echten Fehler mitversteckt.

EIN EIGENER FEHLER: Mein Test-PNG war kein dekodierbares Bild, nur ein
Dateikopf. Der Browser konnte es nicht zeichnen, der error-Handler
raeumte es weg, und die Pruefung fand im Raster nichts. Fehler in der
Pruefung, nicht im Haus -- aber ein nuetzlicher: Er hat nebenbei
gezeigt, dass ein kaputtes Bild keinen leeren Rahmen hinterlaesst.

pruef-anhaenge 37, pruef-treff 66, pruef-bereiche-lesend,
pruef-css-klassen: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:43:40 +02:00
DogFatherGitandClaude Opus 5 670940bd3a Stufe 4: eine Bremse -- und eine stille Sperre, die es nicht gibt
Aus dem Plan im Vault. Diese Stufe steht dort bewusst VOR Galerie und
Gespraech: Mehr Sichtbarkeit heisst mehr Angriffsflaeche, und ein
Bereich, der waechst und keine Bremse hat, waechst genau einmal.

DER TREFF HATTE SCHON MEHR, ALS MEIN PLAN ANNAHM
Stufen (WER schreiben darf: neu, dabei, stamm) und Massnahmen (wer
NICHT MEHR darf: Hinweis, Pause, Ausschluss). Gefehlt hat die Frage
dazwischen: WIE SCHNELL. Ein Stammgast konnte in einer Minute vierzig
Beitraege absetzen -- aus Aerger, aus Versehen oder per Skript.

DIE STILLE SPERRE IST VERWORFEN -- nach einer Messung, nicht nach
einem Gefuehl. `gast` ist eine Rolle mit Zugangscode, es gibt KEINE
Selbstanmeldung. Wer ausgeschlossen wird, kann sich nicht neu
anmelden. Damit loest ein Shadowban ein Problem, das dieses System
nicht hat; er bliebe ein Werkzeug, das Menschen taeuscht, ohne etwas
zu verhindern. Steht jetzt in §9 des Plans: was wir NICHT bauen.

DIE BREMSE: 10 Beitraege je Stunde und Person, nur auf den
Community-Brettern. Keine neue Tabelle -- die Antwort steht schon in
`eintraege`, eine Zaehlung ueber die letzte Stunde genuegt. Eine eigene
Tabelle waere ein zweiter Ort fuer dieselbe Wahrheit und muesste
zusaetzlich aufgeraeumt werden.

Die Absage sagt, WANN es weitergeht ("In 37 Minuten"). Ohne Zeitangabe
probiert jemand im Minutentakt weiter -- genau die Last, die man
verhindern wollte.

MEIN ERSTER ENTWURF BREMSTE DIE FALSCHE ARBEIT: Er zaehlte ALLE
Eintraege. Eine Creatorin mit zehn Content-Ideen haette danach im Treff
nichts mehr schreiben koennen. Eine Bremse, die das richtige Verhalten
bestraft, wird abgeschaltet -- und ist ab da wirkungslos.

DIE TEAM-SICHT: "Was hereinkommt", ganz oben auf der Moderationsseite,
vor den offenen Meldungen. Eine Meldung setzt voraus, dass jemand etwas
GESEHEN hat -- und wer acht Bretter durchklicken muss, tut das nicht
achtmal am Tag. Eine Zeile je Beitrag statt einer Karte: Hier
ueberfliegt man, man liest nicht. Der Inhalt steht auf dem Brett; eine
Vorschau waere eine zweite Stelle, an der derselbe Beitrag steht.

NEU: pruef-bremse (16 Pruefungen)
Die Grenze wird aus dem Code GELESEN, nicht abgeschrieben -- sonst
misst die Pruefung beim naechsten Anpassen etwas anderes als der
Server tut. Dazu die drei Fragen: Greift sie? Trifft sie die richtige
Arbeit (Content bleibt offen, das zweite Treff-Brett nicht)? Und laesst
sie den normalen Fall in Ruhe? Gegenprobe: Beitraege auf vorgestern
zurueckdatiert -- danach muss es sofort wieder gehen.

pruef-treff 66, pruef-wunschliste 30, pruef-countdown 22,
pruef-bereiche-lesend, pruef-css-klassen: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:35:30 +02:00
DogFatherGitandClaude Opus 5 7eec2edf3f Stufe 3: Die Wunschliste bekommt einen Rang und einen Weg
Aus dem Plan im Vault. Eine Wunschliste ohne sichtbare Erfuellung ist
ein Briefkasten ohne Postbote -- nach dem dritten unbeantworteten
Wunsch schreibt niemand mehr.

ZWEIMAL LAG MEIN PLAN DANEBEN, beide Male zu pessimistisch:
- Die Sortierung nach Stimmen GAB es schon, seit dem 11.09.
- Die Datenbank erlaubte 'angenommen' und 'abgelehnt' laengst in ihrer
  CHECK-Regel; nur die Pruefung im Server liess sie nicht durch. Die
  Tabelle war der Logik voraus.

Auch ein Plan von gestern Nacht ist eine Bestandsliste und altert.

WAS DAZUGEKOMMEN IST
- Vier Zustaende JE BEREICH statt zwei global: Offen -> Wird gemacht
  -> Gemacht, dazu "Diesmal nicht". Eine gemeinsame Liste haette
  "Diesmal nicht" auch an einem Schutzvorfall erlaubt, und dort
  bedeutet es nichts.
- Ein geplanter Tag dazu: "Wird gemacht" allein ist ein Versprechen,
  "Wird gemacht -- am 24.09." ist ein Termin.
- Der Rangbalken. Eine Rangfolge sieht man erst, wenn der ABSTAND
  sichtbar ist: 12 Stimmen neben 14 sehen sonst aus wie 1 neben 40.
  Fuer ein Vorleseprogramm spricht er in Worten.
- Entschiedenes rutscht nach unten, wird aber NICHT geloescht. Gerade
  der erfuellte Wunsch ist der Beweis, dass sich Schreiben lohnt.

"DIESMAL NICHT" IST DER WICHTIGSTE DER VIER, und es ist bewusst nicht
rot. Ein Nein ist eine Antwort, Schweigen ist keine -- aber wer ein
rotes Schild an seinem Wunsch sieht, schreibt keinen zweiten.

UND AUF DEM BILDSCHIRMFOTO STAND "WAS IHR EUCH WUENSCHT".
Die Umlaut-Pruefung von gestern Nacht sah es nicht: Sie kannte die
Kataloge und die festen Seitentexte, aber nicht die
Bereichseinstellungen, aus denen JEDE Ueberschrift und jede
Art-Beschriftung kommt. Sechs Stellen ("Fuer den Stream", "Wie es hier
laeuft", "Haeufige Frage", "Ich haette Lust" ...).

Gefunden hat sie kein Gedankengang, sondern ein Blick auf das fertige
Bild. Die Wortliste hatte ausserdem Loecher -- "wuensch" fehlte
schlicht; 23 Stuecke nachgetragen. pruef-deutsche-texte deckt jetzt
auch die 120 Beschriftungen der Bereiche ab (9 -> 12 Pruefungen), mit
einer Gegenprobe auf genau den Satz, der heute Morgen durchrutschte.

NEU: pruef-wunschliste (30 Pruefungen)
Der aelteste Wunsch bekommt die meisten Stimmen -- genau der Fall, der
eine Sortierung nach Datum entlarvt. Dazu: alle vier Zustaende setzen,
ein erfundener nicht, "abgelehnt" am Anschlagbrett ABGELEHNT, der
geplante Tag, die Balkenbreiten (100/33/0 %), und dass der gemachte
Wunsch weiter in der Liste steht -- nur nicht mehr oben.

pruef-countdown 22, pruef-treff 66, pruef-bereiche-lesend,
pruef-deutsche-texte 12: gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:28:37 +02:00
DogFatherGitandClaude Opus 5 77db1bcc2e Stufe 2: "Wann ist der naechste Stream?" steht jetzt oben
Aus dem Plan im Vault. Bei "Was ansteht" gibt es genau EINE Frage, die
ein Zuschauer hat -- und sie stand in Zeile vier einer Liste wie jede
andere Angabe auch.

Jetzt ganz oben, gross:

    ALS NAECHSTES
    in 12 Std 15 Min
    Abendstream
    17.09.2026 um 23:30 Uhr
    2 weitere Termine danach

Darunter wird die Liste zum ZEITSTRAHL: Heute und morgen · Diese Woche
· Spaeter · Ohne Datum · Vorbei. Vergangenes steht unten, nicht
dazwischen -- ein abgelaufener Termin zwischen kommenden liest sich wie
ein Fehler.

DER PLAN VERSPRACH ETWAS, DAS DIE DATEN NICHT HERGABEN.
"in 3 Std 12 Min" -- aber `eintraege.datum` ist ein TAG, und die
Pruefung im Server lehnte eine Uhrzeit ausdruecklich ab
(`^\d{4}-\d{2}-\d{2}$`). Ein Stundencountdown war unmoeglich.

Das ist die uebliche Sorte Planungsluecke: Sie steht nicht im Plan, sie
steht in der Datenbank. Neue Spalte `uhrzeit`, OPTIONAL -- viele
Termine haben keine ("diese Woche", "im Oktober"), und ein Pflichtfeld
haette dafuer eine erfundene erzwungen. Ohne Uhrzeit zaehlt der
Countdown in Tagen, und "morgen" ist eine ehrliche Antwort.

Der Ton folgt der NAEHE, nicht der Wichtigkeit: Was gleich anfaengt,
ist waermer. Das ist die einzige Information, die eine Farbe hier
tragen kann, ohne zu behaupten, ein Termin sei "besser" als ein
anderer. Kein Blinken, keine Animation -- auf dieser Seite steht
niemand unter Zeitdruck, er will es nur wissen.

NEU: pruef-countdown (22 Pruefungen)
Das Abnahmekriterium aus dem Plan, in Pixeln gemessen: Die Antwort MUSS
im ersten Bildschirm stehen (gemessen 458 px von 844) und groesser sein
als jede Fliesstextzeile (27 px). Dazu: Uhrzeit setzen, wiederfinden
und wieder ENTFERNEN; vier unmoegliche Zeiten; der Zeitstrahl mit
"Vorbei" ganz unten; und der leere Fall, in dem ein SATZ dasteht statt
einer leeren Flaeche.

UND EIN EIGENER FEHLER, gefunden von der eigenen Gegenprobe: Der
Testtitel war "X" -- ein Zeichen, der Server verlangt zwei. Vier
"wird abgelehnt"-Haken waren damit halb aus dem falschen Grund gruen.
Aufgefallen ist es nur, weil die Gegenprobe ("der gueltige Fall muss
durchgehen") danebenlag. Ohne sie haette die Pruefung vier Haken
gesetzt und nichts geprueft.

pruef-treff 66, pruef-bereiche-lesend, pruef-css-klassen gruen -- die
anderen sieben Bretter teilen sich diese Datei.

Der Plan im Vault fuehrt jetzt einen Abschnitt 12: "Was beim Bauen
herauskam, das im Plan nicht stand". Plaene altern, Befunde nicht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 11:17:01 +02:00
DogFatherGitandClaude Opus 5 e4d11caeb0 Community-Kacheln: das Loch, die Zwillinge, die unsichtbaren Farben
Filipe, mit einem Bildschirmfoto: "das wie es jetzt ist ist es einfach
total scheisse ... gerade einfach nur dahin geknallt und drauf
geschissen". Er hatte in allen drei Punkten recht, und alle drei sind
messbar.

1. DAS LOCH IM RASTER -- eine Zeile Reihenfolge
Drei Spalten, "Der Treff" doppelt breit -- aber an DRITTER Stelle. Nach
zwei normalen Kacheln war noch EINE Spalte frei, er passte nicht und
rutschte eine Reihe tiefer. Genau das ist die Luecke auf dem Foto.

  DIE REGEL, und sie gilt fuer jedes Raster im Haus: Eine breite Kachel
  gehoert an den ANFANG. Steht sie hinten, faellt die Luecke in die
  MITTE -- und eine Luecke in der Mitte sieht kaputt aus, eine am Ende
  sieht grosszuegig aus.

Jetzt: Treff (2 Spalten) + Anschlagbrett fuellen Reihe 1, drei weitere
Reihe 2, der Rest Reihe 3. Fuer DogFather und die Modis geht es genau
auf, 3 x 3. Und es stimmt auch inhaltlich: Der Treff IST das Herz
dieses Bereichs.

2. ZWEI KACHELN, EIN SYMBOL
"Regeln & Hilfe" und "Meldungen & Massnahmen" trugen beide `schutz` --
im Quelltext zweimal, nebeneinander, auf dem Schirm nicht zu
unterscheiden. Meldungen bekommt `startcheck`, die abgehakte Liste:
Bei Regeln steht, was GILT. Hier steht, was daraus WURDE.

3. DIE FARBEN WAREN DA UND KAMEN NICHT AN
Die sieben Toene sind laengst klar verschieden (#cc9451, #668e6e,
#cc92c6, #656a9e ...). Der Grund stand direkt daneben:
`.kachel:hover::before` und ein ausfuehrlicher Kommentar sprechen von
einer Schiene, die "heller wird und weiter in die Platte strahlt" --
nur hatte `.kachel::before` ausser einem Uebergang KEINEN Inhalt. Das
Element wurde beim Umbau am 07.09. entfernt, seine Hover-Regeln blieben
stehen. Seither trug den Ton nur ein Verlauf, der bei 58 % verschwunden
ist; unter dem Buehnenbild reicht das nicht.

Das hier ist deshalb kein neuer Einfall, sondern das Wiedereinsetzen
dessen, womit der Rest der Datei ohnehin rechnet. Drei Pixel, oben,
nach rechts auslaufend -- Farbe an der Kante unterscheidet, Farbe auf
der Flaeche blendet.

NEU: pruef-kachelraster (15 Pruefungen)
Ein Loch wird nicht angesehen, sondern gerechnet:

  belegte Zellen = Kacheln + 1 je doppelt breiter
  kleinstmoegliche Reihen = aufgerundet (Zellen / Spalten)

Mehr Reihen als das heisst: irgendwo liegt eine Zelle leer, die es
nicht muesste. Eine Luecke am ENDE faellt bewusst heraus. Dazu: jedes
Zeichen genau einmal (erkannt am SVG-Pfad, nicht an einem Namen -- den
gibt es im DOM nicht), jede Kachel mit Schiene, acht verschiedene
Toene. Und die Gegenprobe in beide Richtungen: die ALTE Reihenfolge
MUSS ein Loch melden, die neue nicht.

ZWEI EIGENE FEHLER DABEI, beide durch Messen gefunden:
- Ich hielt ein Vollbild-Foto fuer den Beweis, dass keine Kacheln da
  sind -- sie blenden sich beim Hereinscrollen ein. Die Pruefung
  scrollt jetzt erst hin.
- Ich erwartete sieben Kacheln fuer einen Modi. Er moderiert, also
  sieht er acht. Der Code hatte recht, meine Annahme nicht.

pruef-treff hat die Reihenfolge festgehalten und ist rot geworden --
genau ihre Aufgabe. Erwartung nachgezogen, mit dem Grund daneben.
pruef-kachel-universum 37, pruef-haus-seiten 34, pruef-treff 66,
pruef-css-klassen und pruef-start-ansicht: gruen.

Der ausfuehrliche Plan fuer den ganzen Bereich liegt im Vault:
"02 Projekte/Community-Bereich - Plan zur Perfektion" (fuenf
Durchgaenge).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 10:25:04 +02:00
DogFatherGitandClaude Opus 5 3ebe87611e Dreizehn fortgeschrittene Aufgaben -- und die ersten, die es ohne den Kanal nicht geben konnte
Filipe: "ich will auch dass es fortgeschrittene aufgaben gibt."

88 -> 101 Aufgaben, Stufe "Erfahren" von 29 auf 42. Kein doppelter
Schluessel, kein Text unter der Laenge, die `pruef-modi-katalog`
verlangt (der Text muss BEGRUENDEN, nicht den Titel wiederholen).

DER PUNKT IST NICHT DIE ZAHL, sondern dass mehrere davon vorher gar
nicht formulierbar waren. Erst seit es Kanaele gibt, kann eine Aufgabe
lauten:

  "Denselben Moment fuer zwei Kanaele verschieden schneiden --
   was auf dem Hauptkanal als Rueckblick funktioniert, braucht bei
   Clips einen haerteren Einstieg."

  "Einen Monat lang nichts vom Hauptkanal spiegeln -- erst wenn der
   Nebenkanal sich allein traegt, weiss man, ob er ein Kanal ist oder
   ein Echo."

  "Die Kanaele in einer Tabelle nebeneinanderstellen -- einzeln
   angesehen waechst jeder irgendwie."

Dazu Sachen, die eine erfahrene Person von einer eingearbeiteten
unterscheiden: messen, was ein Ausschnitt an ZEIT kostet; denselben
Ausschnitt zweimal mit anderem Anfang veroeffentlichen; eine Woche
planen, in der DogFather nicht da ist; jedem Kanal einen festen Kopf
geben.

Die feste Zahl in pruef-modi-katalog ist mitgezogen (88 -> 101). Sie
bleibt bewusst fest: Eine Zahl, die sich selbst nachzaehlt, merkt
nicht, wenn etwas herausfaellt.

pruef-modi-katalog 49 und pruef-deutsche-texte 9 gruen -- die neuen
Texte tragen echte Umlaute, nicht ae/oe/ue.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 03:08:24 +02:00
DogFatherGitandClaude Opus 5 b66fc379c8 Drei Accounts, eine Aufgabenliste: der Kanal
Filipe: "ich hab ja auch 2 neben account, hasidog und dogfather clips."
Der Arbeitsplatz wusste davon nichts -- es gab genau eine Welt, und die
hiess nirgends.

DAS WAR KEIN FEHLENDES FELD, SONDERN EINE MEHRDEUTIGKEIT.
"Schneide drei Ausschnitte" ist bei drei Accounts keine Aufgabe,
sondern eine Frage. Wer sie bekommt, muss nachfragen -- oder raet.
Raet er falsch, ist die Arbeit nicht halb getan, sondern am falschen
Ort, und das faellt erst auf, wenn jemand hinsieht.

WAS DAZUGEKOMMEN IST
- KANAELE in workspace.js (DogFather, HasiDog, DogFather Clips), jeder
  mit einem Satz, der ihn erklaert. Ein Auswahlfeld mit drei Namen und
  ohne ein Wort dazu ist eine Ratefrage fuer jemanden, der neu ist.
- Spalte `kanal` an den Aufgaben, per ADD COLUMN: kein Tabellenneubau,
  keine CHECK-Regel, alte Zeilen bleiben leer.
- Auswahl in beiden Formularen, ein farbiges Zeichen auf der Karte
  (gedeckte Toene -- auf dem Brett stehen bis zu vierzig Karten).

LEER IST EIN GUELTIGER ZUSTAND, kein fehlender. Vieles gilt fuer alles:
eine Absprache im Team, ein Zugang, eine Auswertung. Ein Pflichtfeld
haette dafuer einen falschen Kanal erzwungen, und ein falscher Eintrag
ist schlechter als ein leerer. Deshalb steht dort "Für alle" und kein
Strich.

WARUM EINE LISTE IM QUELLTEXT UND KEINE TABELLE
Sonst gilt hier: Eine abgeschriebene Liste altert. Diese ist keine
Abschrift -- sie laesst sich aus nichts ableiten, weil sie eine
Tatsache ueber Filipes Betrieb ist. Einen Kanal dazuzunehmen ist eine
Zeile. Sobald sich das oefter aendert als ein paarmal im Jahr, gehoert
sie in die Verwaltung; vorher waere das eine Oberflaeche fuer drei
Zeilen.

NEU: pruef-kanaele (21 Pruefungen)
Vier Fragen, und die dritte wird gern vergessen: Kann man ihn setzen?
Faellt ein erfundener auf? Erfaehrt jemand, der ihn nicht benutzen
darf, dass es ihn gibt? Und laesst er sich wieder ENTFERNEN -- ein
Feld, das `""` als "unveraendert" behandelt, macht aus einem
Loeschversuch ein Nichts-Tun, ohne Fehlermeldung.

Abschnitt 6 fragt die Datenbank selbst. Ohne ihn koennte alles gruen
sein, obwohl der Wert nur durch die Auskunft zurueckgereicht wird.

pruef-aufgabenbrett, pruef-modi-katalog 49, pruef-modi-kategorien 25
und pruef-css-klassen unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 03:01:27 +02:00
DogFatherGitandClaude Opus 5 fa8e86ad81 Die Personenkacheln der Entwicklung im Hausstil
Filipe, mit zwei Bildschirmfotos nebeneinander: "wieso ist diese seite
noch nicht im stil und perfektioniert wie die auf screen2 ... aber so
dass ich die leute in einer kachel aussuchen kann alle einzel."

Der Unterschied lag NICHT im Aufbau -- der stimmte -- und auch nicht
am Inhalt: Die 28 Punkte sind laengst ganz auf Modi-Arbeit gebaut (Im
Chat 8, Wenn es eng wird 7, Im Team 7, Wie viel von selbst 6, dazu
sechs Fragen an einen selbst). Es waren zwei andere Dinge:

1. DIE ZAHLEN WAREN GRAUE TEXTZEILEN
Drueben stehen sie als abgesetzte Kaesten mit grosser Ziffer und
eigenem Ton. `bilanz-zahl` liegt in start.css und gehoert dem ganzen
Haus -- es wird jetzt benutzt statt nachgebaut. Ein Nachbau laeuft
auseinander, sobald jemand eins von beiden anfasst.

Aus "0 von 28 angesehen" werden drei Kaesten wie auf der Checkliste:
angesehen / noch offen / verschieden gesehen. Die ersten beiden teilen
dasselbe Ganze, die dritte ist das Ergebnis dieser Seite -- wo zwei
Leute dasselbe sehen, gibt es nichts zu besprechen.

2. EINE ANGEKLICKTE PERSON SAH AUS WIE EINE NICHT ANGEKLICKTE
Die Kachel war ein Knopf ohne Zustand. Man klickte jemanden an, die
Karte ging auf -- und oben blieb alles gleich. Wer scrollte, wusste
nicht mehr, wen er offen hat. Jetzt `aria-pressed`, damit es auch ein
Vorleseprogramm sagen kann, und eine gedaempfte Umrandung. Die Reihe
heisst "Person waehlen" wie auf dem Aufgabenbrett.

Nebenbei: Der Ton des ersten Kastens springt auf gruen, sobald nichts
mehr offen ist -- sonst saehe eine fertig angesehene Person aus wie
eine halbe.

NEU: pruef-entwicklung-kacheln (15 Pruefungen)
Nicht "sieht gleich aus" -- das laesst sich nicht messen -- sondern
was das Aussehen traegt: Benutzt die Kachel den Hausbaustein oder
einen Nachbau (und steht nichts Selbstgebautes daneben)? Ergibt
angesehen + noch offen die Gesamtzahl, die die Auskunft selbst nennt?
Und die Gegenprobe zur Auswahl: VOR dem ersten Klick darf keine
Kachel gewaehlt sein, danach genau eine, und beim naechsten Klick
wandert sie, statt sich zu sammeln.

pruef-entwicklung 43 und pruef-css-klassen unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 02:41:41 +02:00
DogFatherGitandClaude Opus 5 3a86b13de1 Drei Zahlen, die etwas anderes zaehlten, als sie sagten
Weiter an derselben Stelle wie der Ring: Nicht umbauen, was gut ist --
suchen, wo eine Beschriftung etwas anderes behauptet, als darunter
gerechnet wird. Drei Funde, alle auf der Startseite.

1. "HEUTE" WAR ZWEIDEUTIG
Die erste Zahl unter dem Ring heisst "heute" und zaehlt TERMINE.
Solange der Ring die Uhrzeit zeigte, fiel das nicht auf. Seit er
"Heute geschafft" heisst und AUFGABEN zaehlt, standen zwei
verschiedene "heute" uebereinander -- ein Widerspruch, den der
vorherige Commit erst erzeugt hat. Heisst jetzt "Termine heute".

2. "KOMMT NOCH" ZAEHLTE STUNDEN, NICHT TERMINE
`mitTermin` ist eine Menge von STUNDEN -- fuer den Ring richtig, er
faerbt Stundensegmente. Als Zahl daneben war es falsch: Drei Termine
um 20 Uhr ergaben "1 kommt noch". Eine zu kleine Zahl meldet niemand;
man verlaesst sich darauf und wundert sich spaeter.

3. DIE KACHELZAHL SAGTE VORLESEND "OFFENE PUNKTE"
Sie summiert HINWEISE: bei Aufgaben "2 ueberfaellig" + "2 heute
faellig" = 4. Im Block darunter steht "6 Offen". Beides richtig -- nur
das Wort "offen" machte daraus einen Widerspruch, und wer die Seite
vorgelesen bekam, hoerte eine Zahl offener Aufgaben, die es nicht
gibt. Jetzt: "Aufgaben: 4 Sachen liegen an".

NICHT GEAENDERT, OBWOHL ICH ES VORGESCHLAGEN HATTE:
Die sieben Zaehler bleiben, auch wenn mehrere Null sind. Im Code steht
Filipes Anweisung vom 08.09. daneben ("diese beiden kategorien sollen
bei jedem in jeder rolle gleich sein"), samt der Erfahrung, dass das
Ausblenden schon einmal dazu fuehrte, dass Spicy Media als Einzige
etwas anderes sah. Der leere Zustand wird bereits gedaempft statt
entfernt -- das ist die bessere Loesung und sie war schon da.

pruef-zentrale-ring jetzt 14 Pruefungen (vorher 10), darunter drei
Termine in DERSELBEN Stunde -- der Fall, der 1 statt 3 ergab. Dazu die
Gegenprobe, dass jemand ohne Termine dort auch null sieht.
pruef-start-ansicht und pruef-tagesblick unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 02:28:46 +02:00
DogFatherGitandClaude Opus 5 b57b9cebb5 Der Ring oben zeigt Arbeit statt der Uhrzeit
Auf der Startseite von Creator, rechter Hand und Modis ist der Ring das
groesste Element, ganz oben. Er rechnete:

    prozent = (aktuelle Stunde - 6) / 18

...und nannte das "Tag geschafft". Um 9 Uhr also 17 %, um 23 Uhr 94 %
-- unabhaengig davon, ob jemand etwas getan hatte.

Aufgefallen auf einem Bildschirmfoto: Bei einer Modi stand "0 % TAG
GESCHAFFT", waehrend sie ueberhaupt nichts offen hatte. Beide Angaben
waren fuer sich richtig und zusammen Unsinn -- und es war das Erste,
was sie sah.

JETZT ZAEHLT ER ARBEIT. Nenner ist, was heute auf dem Tisch liegt:
heute faellig ODER laenger offen. Die naheliegende Rechnung ueber "nur
heute faellig" waere derselbe Fehler noch einmal gewesen -- bei drei
ueberfaelligen Sachen haette der Ring "nichts faellig" gemeldet.
Zaehler ist, was HEUTE fertig wurde (erledigt_am), nicht was irgendwann
abgehakt wurde. Liegt nichts an: voller Ring, und der Titel sagt es in
Worten statt nur eine 100 zu zeigen.

Gemessen danach, dieselbe Seite: "33 % Heute geschafft", darunter
"2 Sachen sind ueberfaellig -- das zuerst". Die Seite erzaehlt jetzt
eine Geschichte statt zweier.

NEU: pruef-zentrale-ring (10 Pruefungen)
Drei Lagen, drei Menschen: etwas anliegend und teils fertig / nichts
anliegend / drei ueberfaellige und nichts fertig. Dazu zwei
Abgrenzungen (morgen faellig und vorgestern erledigt duerfen nicht
mitzaehlen) und die Gegenprobe: zwischen zwei Abfragen wird eine
Aufgabe fertig gemacht, der Ring MUSS springen -- er tut es, 0 % -> 33 %.
Der letzte Abschnitt rechnet die alte Uhrzeit-Formel mit und meldet,
falls der Ring je wieder auf ihren Wert faellt.

NEU: mess-startseite -- ein Messwerkzeug, kein Pruefwerkzeug
Es sagt nicht richtig/falsch, sondern wie viel da ist: Seitenlaenge in
Handy-Bildschirmen, Bedienelemente, Woerter, Ring, je Rolle, mit
echten Aufgaben statt im leeren Zustand. Gemessener Stand:

    admin 7,0 Schirme / 58 Bedienelemente   hand    5,7 / 43
    modi  5,0 / 37                          manager 4,9 / 38
    scout 4,5 / 34                          creator 4,3 / 32

pruef-sicht, pruef-verborgen, pruef-modi-verborgen und
pruef-haus-trennung laufen unveraendert durch -- die neue Abfrage
folgt der fremden Sicht ueber dieselbe Variable wie der Rest.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 02:21:12 +02:00
DogFatherGitandClaude Opus 5 78b64f6eca Auf dem Brett steht jetzt Deutsch, nicht ASCII
Unter jeder Kategorie stand eine Erklaerung ohne Umlaute:
"Was im Livechat passiert, waehrend gesendet wird. Loeschen,
stummschalten, begruessen, deeskalieren." Elf der vierzehn Kategorien
und alle drei Stufen waren betroffen, dazu vier Stellen mit zwei
Bindestrichen statt eines Gedankenstrichs.

Entstanden ist es beim Schreiben ueber Hilfsskripte, die an Umlauten
scheitern -- fuer einen Kommentar gleichgueltig, fuer einen Satz, den
ein Mensch liest, ein Fehler. Gesehen hat es keine Pruefung: Der Text
war inhaltlich richtig, der Katalog vollstaendig, alles gruen.
Aufgefallen ist es auf einem Bildschirmfoto.

NEU: pruef-deutsche-texte (9 Pruefungen)
Sieht 174 Katalogtexte und 28 ausgelieferte Seiten durch. Bewusst eine
Liste von Wortstuecken statt eines Musters aus Buchstabenfolgen: "ue"
ist in "Feuer" und "neue" richtig, "ss" in jedem zweiten Wort. Die
Liste ist ein Netz, kein Beweis, und der Kopf der Datei sagt das.

Die Skripte bleiben absichtlich aussen vor. Ausprobiert: Dieselbe
Liste schlaegt dort 71 Mal an und kein einziges Mal zu Recht -- es
sind Feldnamen, Stilklassen und Adressen, die ASCII sein MUESSEN.
Eine Warnung, die immer kommt, ist keine Warnung mehr. Ihr sichtbarer
Text wird deshalb am fertigen Bildschirm geprueft, ueber innerText.

AUSSERDEM, auf demselben Bildschirmfoto gefunden:
Die Fusszeile der Vorlagenkarten war eine starre Flex-Zeile. Bei einer
schon uebernommenen Aufgabe stehen dort drei Dinge statt zwei, und
"Frist: in 2 Tagen" brach mitten im Wort auf drei Zeilen um. Keine
neue feste Breite dagegen, sondern flex-wrap plus nowrap -- eine
Regel, die misst, statt einer Zahl, die beim naechsten Element wieder
faellig waere.

UND EINE LEHRE ZUM MESSEN: Die erste Fassung dieser Pruefung zaehlte
element.getClientRects(). Sie blieb gruen, auch mit dem Fehler wieder
eingebaut -- ein Flex-Kind wird zum Block und liefert immer genau ein
Rechteck. Gefunden hat das nur die Gegenprobe. Gemessen wird jetzt
ueber einen Bereich um den Textknoten.

Das Bildschirmfoto landet ausserdem dort, wo die Zeile darunter es
ansagt (server/), nicht im Arbeitsverzeichnis.

pruef-modi-katalog 49 (vorher 45), pruef-deutsche-texte 9,
pruef-css-klassen, pruef-struktur, pruef-vorlagen,
pruef-aufgaben-vorlagen: alle ohne Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 23:22:05 +02:00
DogFatherGitandClaude Opus 5 76fa8b95fc Beim Verteilen sehen, wer schon wie viel hat
Weiter an derselben Sache: die Kategorien, aus denen Aufgaben an das
Team gehen.

ZWEI DINGE WAREN UNBEQUEM:

Die Person kam aus dem Formular GANZ OBEN auf der Seite. Man waehlt
sie dort, scrollt herunter zum Vorlagenbrett und drueckt "Uebernehmen"
-- und wer das nicht weiss, bekommt "Bitte zuerst eine Person waehlen"
und sucht, wo.

Und beim Vergeben sah man nicht, wer schon wie viel offen hat. Das ist
die wichtigere Haelfte: Zu wenig Zeit ist in den Untersuchungen zu
Moderatoren der meistgenannte Grund fuers Aufhoeren, und die Person,
die verteilt, ist die einzige, die das verhindern kann. Dafuer muss
die Zahl dort stehen, wo entschieden wird -- nicht auf einer
Auswertung, die man hinterher aufruft.

Jetzt steht ueber den Aufgaben eine Reihe mit den Namen des Teams und
der Zahl daneben. Ein Klick, und die uebernommenen Aufgaben gehen
dorthin; das Formular oben bleibt als Rueckfall, damit der bisherige
Weg weiter funktioniert.

KEINE SCHWELLE, KEINE WARNFARBE AUF DER ZAHL. Was "zu viel" ist, haengt
vom Menschen ab -- eine feste Grenze waere geraten, und geraten ist bei
dieser Frage schlimmer als nichts. Was NICHT geraten ist: dass etwas
ueberfaellig liegt. Nur das wird markiert, und zwar gedeckt. Ein
Warnton an einem Namen liest sich sonst wie ein Vorwurf gegen die
Person, dabei ist es eine Auskunft ueber die Verteilung.

Ohne eine einzige neue Abfrage: Die Personen und ihre Aufgaben liegen
im Browser ohnehin schon. Ein zweiter Abruf waere ein zweiter Weg, auf
dem eine andere Liste herauskommen kann.

  server/pruef-modi-katalog.mjs   45 Pruefungen (vorher 36), 0 Fehler

  Der neue Abschnitt meldet sich als DogFather an -- der bisherige
  Browserteil ist ein Modi, und der sieht diese Auswahl gar nicht. Er
  drueckt wirklich: Marina waehlen (9 offen), eine Aufgabe uebernehmen,
  nachsehen ob sie bei ihr liegt (9 -> 10). Ein Knopf, den niemand
  betaetigt hat, ist kein geprueter Knopf.

  Und er prueft die Gegenrichtung mit: Ein Creator und eine Managerin
  stehen NICHT zur Auswahl -- sie arbeiten im anderen Haus.

  pruef-aufgabenbrett, pruef-sicht, pruef-womit 41, pruef-css-klassen
  -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 19:21:38 +02:00
DogFatherGitandClaude Opus 5 4802954263 Der Aufgabenkatalog fuers Team: Kategorie mal Stufe, 88 Aufgaben
Filipe: "perfektionniere die kategorien wo ich aufgaben an die modis
verteile und so, ich will dass du alles was es gibt auf der welt durch
gehst und wie bei den aufgaben wo sie fuer mich haben auch mit
kategorien und vielen aufgaben."

ERST GEZAEHLT, WAS DA WAR. Es gab einen Katalog: 60 Eintraege in neun
Phasen. Wem sie gehoerten:

  DogFather                13
  DogFather & rechte Hand  12
  rechte Hand              14
  --------------------------------
  zusammen                 39 von 60

Zwei Drittel des "Modi-Katalogs" waren Aufbauarbeiten fuer Filipe
selbst. Nur 20 Eintraege waren wirklich Arbeit fuer jemanden im Team.
Und die Verteilung ueber die vierzehn Kategorien war schief: Planung
10, Events 1, Wachstum 1, Branding 1, Sonstiges 0.

Der Aufbauplan ist nicht falsch, nur etwas anderes -- er bleibt unter
`aufbauplan` erhalten. Ihn zu loeschen hiesse, 60 durchdachte Schritte
wegzuwerfen, weil sie am falschen Platz standen.

NEU: 88 Aufgaben in KATEGORIE mal STUFE, dieselbe Form wie bei den
Creator-Vorlagen. Wer eine Aufgabe vergibt, denkt "Frida macht Chat"
und nicht "wir sind in Phase 3".

  Chat 11, Team 8, Community/Events/Clipping/Technik je 7,
  Social/Planung/Organisation je 6, Kommunikation/Analyse/Wachstum/
  Branding je 5, Sonstiges 3 -- keine Kategorie mehr leer.

  Drei Stufen: neu dabei (24), eingearbeitet (35), erfahren (29).
  Eine Aufgabe der Stufe "erfahren" an einen Neuen zu geben ist kein
  Kompliment, sondern ein Ueberfallen.

UND DIE VIERZEHN KATEGORIEN HABEN JETZT EINEN SATZ. Vorher standen da
vierzehn nackte Namen -- "Organisation" und "Planung" nebeneinander,
ohne dass jemand sagt, was worin gehoert. Dann landet dieselbe Aufgabe
beim einen unter Planung, beim anderen unter Organisation, und jede
Auswertung darueber ist wertlos. Jetzt: Planung ist, was NOCH NICHT
ist; Organisation, was bereits ist, in Ordnung zu halten.

RECHERCHIERT, NICHT AUSGEDACHT (Quellen im Kopf des Katalogs):
Twitch und Discord zu dem, was ein Moderator tatsaechlich tut; TikTok
LIVE im Besonderen (gefilterte Kommentare, Gaesteverwaltung, Regeln zu
Beginn, Matches, Geschenke ohne Betteln); Community-Arbeit zu Rhythmus,
Vertretung und Monatsrueckblick. Dazu die Burnout-Forschung, die schon
in "Wie geht's dir?" steht -- deshalb stehen unter "Team" Aufgaben, die
zu wenig Zeit und Streit frueh sichtbar machen.

WAS DABEI BEINAHE SCHIEFGEGANGEN WAERE, und was es gefunden hat:

  Das Uebernehmen griff noch auf MODI_KATALOG zu -- die alten Phasen.
  Der Browser schickt die Nummer aus der AUSGELIEFERTEN Liste zurueck.
  Ein Klick auf "Uebernehmen" haette damit eine voellig andere Aufgabe
  angelegt, und zwar eine, die es gibt: keine Fehlermeldung, nichts
  Rotes, nur die falsche Aufgabe auf dem Brett. Gefunden hat das
  pruef-modi-katalog, die an der verschwundenen Phase abgestuerzt ist.

  Der Knopf "Alle N uebernehmen" schickte die Stufe nicht mit. Er sagte
  "Alle 4 uebernehmen" und haette elf angelegt -- das merkt man erst
  auf dem Brett.

  Und der Satz ueber dem Brett sagte weiterhin "Nach Etappen sortiert".
  Gesehen im Bildschirmfoto der Pruefung, nicht im Code.

  server/pruef-modi-katalog.mjs   36 Pruefungen, 0 Fehler
  Neu darin: jede Kategorie muss belegt sein (mindestens drei), jede
  Stufe auch, keine Kennung doppelt -- und JEDER TEXT MUSS BEGRUENDEN.
  Die letzte Zeile hat zwei meiner eigenen Texte als zu duenn erwischt.

  pruef-modi-kategorien 25, pruef-aufgabenbrett, pruef-vorlagen,
  pruef-css-klassen, pruef-struktur -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 19:05:34 +02:00
DogFatherGitandClaude Opus 5 99f96553c5 Eine Benachrichtigung muss irgendwohin fuehren
Der letzte offene Punkt aus dem Umbau vom 15.09.: Seitdem entscheidet
die Adresse, welche Seiten es gibt -- fuer Seiten, Hinweise und
Suchtreffer ist das umgesetzt, fuer Push war es das nicht. Und der
Grund stimmte: Eine Benachrichtigung entsteht, wenn NIEMAND auf einer
Adresse steht. Sie geht an ein Geraet, und das oeffnet die Adresse, als
die es installiert wurde.

DIE FRAGE LAESST SICH TROTZDEM BEANTWORTEN -- nur nicht ueber die
Adresse, sondern ueber den MENSCHEN. Wer im Team ist (rechte Hand,
Modi), kommt NUR auf crew. herein; das steht in
sitzungPasstZurAdresse und gilt in beide Richtungen. Fuer ihn gibt es
die Agenturseiten nirgends -- auf keinem Geraet, in keiner
installierten App.

Erst gemessen, welche Ziele es ueberhaupt gibt und wer sie bekommt:

  aufgaben.html   an den Verantwortlichen -- kann ein Modi sein, und
                  die Seite gibt es auf crew.           in Ordnung
  calls.html      an die TERMIN-TEILNEHMER              <- der Fall
  kalender.html   dieselben Empfaenger, Seite gibt es   in Ordnung
  scouting.html   nur an Scouts                         in Ordnung
  start.html      ueberall                              in Ordnung

Ein Modi, der als Teilnehmer in einem Call steht, bekam also einen
Hinweis auf eine Seite, die es fuer ihn nicht gibt.

UND DIE BENACHRICHTIGUNG WIRD NICHT UNTERDRUECKT. Das ist die
eigentliche Entscheidung: Er SOLL erfahren, dass der Call gleich
anfaengt -- er soll nur nicht auf einer Seite landen, die ihn
weiterleitet. Statt der Seite kommt die Startseite; dort steht, was
ansteht. Eine Weiterleitung ins Leere sieht aus wie ein Fehler, eine
Startseite nicht.

An EINER Stelle, durch die jede Benachrichtigung geht. DogFather und
Spicy Media arbeiten in beiden Haeusern -- fuer sie bleibt jedes Ziel,
das es in einem der beiden gibt; welches Geraet sie in der Hand
halten, weiss hier niemand, und die Seitenschranke faengt den Rest ab.

`benachrichtige` gibt jetzt zurueck, WOHIN wirklich geschickt wurde.
Sonst muesste eine Pruefung die verschluesselte Nachricht aufmachen,
um es zu erfahren -- das beweist pruef-push-weg mit einem nachgebauten
Browser bereits, und zweimal dieselbe Maschinerie waere die zweite,
die veraltet.

  server/pruef-push-ziel.mjs   10 Pruefungen, 0 Fehler (Port 4423/4424)
  Mit Gegenprobe in beide Richtungen: aufgaben.html und befinden.html
  bleiben stehen (sonst hiesse "wird zur Startseite" nur, dass jedes
  Ziel dorthin faellt), eine Managerin wird weiterhin zu den Calls
  geschickt, und ein echter Push-Dienst zaehlt mit, dass die acht
  Nachrichten auch wirklich rausgegangen sind.

  pruef-push, pruef-push-weg, pruef-glocke -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 18:43:08 +02:00
DogFatherGitandClaude Opus 5 12d4d48975 pruef-struktur: von zehn Fehlern auf null -- vier davon waren keine
Die dritte und letzte rote Pruefung. Sie meldete zehn Fehler, und
sechs davon waren Fehlalarm.

1. SECHS SEITEN "VON NIRGENDWO VERLINKT"

Gemeldet wurden crew-index, entwicklung, rechte, talente, teamlage und
treff-moderation. Keine davon war verwaist -- man kommt auf jede, indem
man eine KACHEL antippt. Die Kacheln stehen im Server (`ziel:
"talente.html"`), und der wurde nie durchsucht. Der blinde Fleck lag in
der Pruefung.

Abgeleitet statt nachgetragen: Statt die sechs von Hand auszunehmen,
kommen workspace.js und crew-adresse.js als Quellen dazu. Wer morgen
eine Kachel anlegt, ist damit automatisch abgedeckt.

2. FALSCHE ZEILENNUMMERN

Die Ortszeit-Pruefung schnitt Blockkommentare heraus und ersetzte sie
durch EIN Leerzeichen -- ab da zaehlte split("\n") falsch. Gemeldet
wurde "pruef-eskalation.mjs:43", dort steht eine Zeile ueber Kekse. Wer
dem nachgeht, findet nichts, haelt die Pruefung fuer kaputt und sieht
beim naechsten Mal nicht mehr nach.

Mit richtigen Zeilen waren sechs der sieben Funde echt: Sie bauen ihr
Tagesdatum aus toISOString(), also aus UTC. Zwischen Mitternacht und
zwei Uhr liefert das den Vortag -- die Pruefungen waeren tagsueber
gruen und nachts rot gewesen.

Der siebte (pruef-eskalation.mjs:70) rechnet von einem FESTEN Mittag
aus und ist damit sicher; das Muster kann es nur nicht unterscheiden.
Auch umgestellt, damit es nicht beim naechsten Lesen wieder auffaellt.

Neu: server/helfer-tag.mjs -- heuteLokal, tagLokal, tagVon. Nicht aus
workspace.js importiert, weil eine Pruefung, die nur ein Datum
braucht, dafuer keinen Server hochfahren soll. pruef-backstage-import
hatte die Rechnung sogar schon richtig stehen -- und benutzte sie 1270
Zeilen weiter unten trotzdem nicht.

3. TOTES CSS

`.rolle__zeichen .nase` war tot. Beim Nachsehen: `.auge` und `.hell`
daneben auch -- sie wurden nur davon verdeckt, dass die Pruefung den
Klassennamen als TEILZEICHENKETTE gegen den Quelltext haelt, und
"auge" steckt in "Auge", "hell" in "hell". Dutzende Treffer im
Fliesstext deutscher Kommentare. `.fuell` bleibt, die wird benutzt.
Die Schwaeche der Suche steht jetzt an der Stelle notiert.

4. start.css MIT 347 KB

Die Grenze soll verhindern, "dass eine Seite unnoetig viel laedt". Auf
der echten Seite nachgemessen:

  start.css        auf der Platte 346 KB   uebertragen 110 KB (br)
  chat.css                         59 KB                16 KB
  entwicklung.css                  33 KB                 8 KB

Caddy packt unterwegs. Von start.css sind ausserdem 227 KB KOMMENTAR
(64 %) -- die Pruefung bestrafte genau das, was dieses Haus absichtlich
tut, und haette eine Datei mit 199 KB dichtem CSS durchgewunken.
Dasselbe Argument steht drei Absaetze hoeher schon fuer gestufte
Bilder.

Jetzt zwei Zahlen, weil es zwei Fragen sind: was der BESUCHER laedt
(brotli Stufe 4 -- bei 4 liefert node 111 KB, Caddy 110, jede andere
Stufe waere eine erfundene Zahl) und was ein MENSCH pflegen muss (ohne
Kommentare). Sonst koennte man die erste Zahl klein halten, indem man
immer mehr Prosa schreibt.

MIT GEGENPROBE, in drei Faellen: 281 KB dichtes CSS faellt durch,
404 KB Kommentar gehen durch, und 246 KB sich WIEDERHOLENDES CSS
faellt ebenfalls durch -- sonst koennte man die erste Grenze mit
Wiederholung unterlaufen.

  pruef-struktur          0 Fehler (vorher 10)
  pruef-eskalation 40, pruef-modi-livecheck 16, pruef-treff-werkzeuge 70,
  pruef-backstage-import 160, pruef-css-klassen, pruef-crew-adresse 132
  -- alle 0 Fehler

Damit sind alle drei roten Pruefungen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 18:03:50 +02:00
DogFatherGitandClaude Opus 5 0852723493 Der Nebel lag dort, wo der Text steht
pruef-kachel-universum war rot mit drei Meldungen. Die zweite rote
Pruefung von dreien.

ERST DIE FRAGE, OB ES DRIFT IST ODER VON ANFANG AN SO WAR: Die Pruefung
und das Sternenfeld kamen im selben Commit (ad47fc2). Dort laufen
lassen -- alles gruen, Kachelzeile 0,017 % auf 11610 Bildpunkten. Heute
2,372 % auf 6282. Die gemessene Flaeche hat sich HALBIERT.

Das war der Hinweis: Es wird eine andere Kachel gemessen. Der Waehler
nimmt die erste (`.kachel .kachel__unter`), und die war damals die
grosse Dashboard-Kachel (645 px breit), heute ist es "Team-Lage" (349
px). Die Reihenfolge hat sich zwischendurch geaendert.

WARUM DAS EINEN UNTERSCHIED MACHT: Die beiden Nebel sind auf
`100% 100%` skaliert, sie wachsen also mit der Kachel. Der babyblaue
sass bei `at 12% 88%` -- unten links. Auf einer schmalen Kachel liegt
genau dort die Unterzeile; auf der doppelt so breiten verteilt sich
derselbe Nebel ueber die ganze Breite und faellt nicht auf.

Der Kern ist jetzt tiefer in die Ecke geschoben (`at 10% 104%`, Ellipse
etwas flacher). Der Verlauf laeuft weiterhin quer durch die Kachel, die
Sterne sind unveraendert -- nachgesehen im Bild, nicht nur gemessen.

  Kachelzeile   2,372 %  ->  0,000 %   (Mittel 6.93 -> 7.28)
  Personenzeile 0,253 %  ->  0,253 %   (unveraendert, nichts kaputt)

UND EINE PRUEFUNG, DIE SEIT WOCHEN GAR NICHT LIEF. Die Zeile "dort
steht kein Stern" hing an `if (zwischenraum)`, und `zwischenraum` war
`null`, seit die grosse Kachel an Platz zwei steht: Sie faengt eine
Zeile tiefer wieder bei x=140 an, also gab es keinen Spalt zwischen
den ersten beiden. Ein uebersprungener Test beweist nichts -- und
gemeldet hat er nur, dass er nichts messen konnte.

Beim Wiederbeleben stellte sich heraus, dass er die falsche Frage
stellte: Er verlangte, dass der Grund zwischen den Kacheln "ruhig" ist
(Spanne <= 12). Das ist eine Aussage ueber das HINTERGRUNDFOTO der
Seite, und ein Foto darf helle Stellen haben -- gemessen 27, ohne dass
etwas kaputt war. Die eigentliche Frage ist eine andere: Liegt das
Sternenfeld wirklich nur auf den Kacheln?

Jetzt wird derselbe Fleck zweimal gemessen, mit und ohne Sternenfeld:

  Mittel 42,7,12 -> 42,7,12   hellster 69,14,17 -> 69,14,17

Bildpunkt fuer Bildpunkt identisch. Das beantwortet die Frage
unabhaengig davon, was auf dem Foto zu sehen ist.

  pruef-kachel-universum   37 Pruefungen, 0 Fehler (vorher 3)
  pruef-css-klassen, pruef-neue-seiten 97 -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 17:24:48 +02:00
DogFatherGitandClaude Opus 5 8e140724f2 Der Rollenname steht in keiner ausgelieferten Datei mehr
pruef-modi-wortleck war rot und meldete 17 Fundstellen -- seit Wochen,
bei jedem Lauf. Eine Warnung, die immer kommt, wird ueberlesen, und
dann auch die echte.

ERST GEMESSEN, OB DIE REGEL UEBERHAUPT NOCH GILT. Seit dem 11.09. gibt
es die eigene Adresse crew. mit einem offenen Modi-Knopf an der Wand --
es waere gut moeglich gewesen, dass die Pruefung etwas bewacht, das es
nicht mehr gibt. Sie gilt: pruef-modi-verborgen setzt mit 80 Pruefungen
durch, dass ein Manager keinen Modi sieht.

UND DABEI KAM ETWAS SCHLIMMERES HERAUS. Auf der echten Seite gemessen:

  /workspace/start.html                 302   (Anmeldung noetig)
  /workspace/assets/js/talente.js       200   25 KB Quelltext
  /workspace/assets/js/chat.js          200   85 KB
  /workspace/assets/css/entwicklung.css 200   34 KB

Jede Datei unter workspace/ ist OHNE JEDE ANMELDUNG aus dem offenen
Netz abrufbar. Der verborgene Zugang stand also nicht in einer Datei,
die "jeder herunterlaedt, der angemeldet ist" -- sondern in einer, die
man einfach abrufen kann.

Die Rollentabelle in workspace.js sagt seit dem 11.09. genau das
Richtige dazu: "Der Name steht hier und NICHT in einer Datei, die jeder
herunterlaedt -- ausgeliefert wird er nur an den, der ihn selbst
traegt, und an die, die ihn sehen duerfen." Danach ist jetzt gebaut,
ueberall:

  - talente.js hatte `rolle: 'modi'` fest im Text, dazu den Namen im
    Codekasten und im Rechtevergleich. Die Seite FRAGT ihn jetzt ab;
    /talente/lage liefert ihn, und die Route geht nur an DogFather und
    die rechte Hand.
  - Der Regeltext des Treffs nennt den Namen weiterhin -- Filipe hat am
    11.09. ausdruecklich gewaehlt, dass die Community ihn sieht. Er
    kommt jetzt als DATEN mit der Antwort, nicht als fester Text.
  - Das Feld hiess selbst `modi_frist_tage`. Das Muster \bmodi\b trifft
    das nicht, weil danach ein Unterstrich folgt -- ein Leck durch eine
    Luecke im Muster, nicht durch eine Entscheidung. Heisst jetzt
    `pause_frist_tage`.
  - Die uebrigen elf Fundstellen waren Kommentare. Umformuliert, ohne
    dass sie weniger erklaeren.

Ergebnis: 17 -> 0. Ohne Ausnahmeliste, ohne die Pruefung zu entschaerfen.

ZWEI LOECHER, DIE ICH DABEI SELBST GERISSEN HAETTE:

  darfAnlegen wurde aus `lage` gerechnet -- aber ichHolen() laeuft VOR
  laden(), also war `lage` noch null. Der Wert waere dauerhaft falsch
  gewesen und der Knopf nie erschienen. Jetzt ist es eine Frage statt
  eines Wertes, beantwortet beim Zeichnen. Gefunden beim Nachsehen der
  Reihenfolge, nicht im Testlauf -- deshalb steht die Frage ab jetzt in
  pruef-uebergang.

  Und im HTML des Treffs steht als Ersatzfassung "jemandem aus dem
  Team". Kommt der Name nicht an, bleibt sie stehen, die Seite sieht
  vollkommen richtig aus, und niemand merkt es. Ein Platzhalter "…"
  waere aufgefallen; eine richtige Ersatzfassung faellt nicht auf.
  pruef-neue-seiten prueft jetzt, dass wirklich der Name dasteht.

  pruef-modi-wortleck        0 Fehler (vorher 17 Fundstellen)
  pruef-uebergang 65 (vorher 61), pruef-neue-seiten 97 (vorher 93)
  pruef-modi-verborgen 80, pruef-nachwuchs 123, pruef-treff 66,
  pruef-treff-werkzeuge 70, pruef-css-klassen -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 16:59:34 +02:00
DogFatherGitandClaude Opus 5 8fc1ac7a7a Alles aus der Excel-Datei -- und der Fund, der alles blockiert haette
Filipe: "ich will dass alles von der excel datei genommen wird.
perfektionnier das, aber wenn ich dir runter lade soll alles notiert
und angezeigt werden." Dazu eine echte Ausgabe als Vorlage.

DER SCHWERSTE FUND STECKTE VOR DEN DATEN, NICHT IN IHNEN.

Seine Ausgabe "Creator_innendaten" hat DREI Spalten, die nach Person
aussehen: "Creator*in-ID", "Creator*innen-Anmeldename" und "Agent".
`personSpaltenRaten` nahm die erste mit dem Wort "creator" darin --
die ID. Danach wurde nach einem Creator namens "700001" gesucht.
Nachgemessen an seiner echten Kopfzeile: handle = KEINE, name =
"Creator*in-ID". Diese Datei haette KEINE EINZIGE Zeile zugeordnet,
mit einem Hinweis ("steht bei keinem Creator im Feld TikTok"), der in
die voellig falsche Richtung zeigt.

Jetzt ist "Anmeldename" der Handle, eine Kennnummer ist fuer beide
Spalten ausgeschlossen, und "creator" allein reicht nicht mehr als
Namensspalte -- sonst haette weiter hinten "Neue*r LIVE-Creator*innen"
(Wert: "Nein") die Stelle uebernommen. An fuenf Kopfzeilen gemessen.

UND DANN: NICHTS FAELLT MEHR WEG.

41 Spalten in der Datei, acht werden gedeutet. Die restlichen 33 --
letzter Monat, fuenf Prozentwerte, Matches, Multi-Gast-LIVEs, Fanclub,
Graduierungs- und Stufenstatus -- wurden lautlos weggeworfen.

KEINE 33 NEUEN SPALTEN, sondern eine Zeile je Spalte mit dem NAMEN als
Schluessel. Eine abgeschriebene Spaltenliste hat in diesem Haus schon
zweimal Daten gekostet und waere beim naechsten Backstage-Update
falsch. Gegenprobe in der Pruefung: eine erfundene Spalte
("Sternenstaub pro Woche") kommt genauso durch -- es wird also keine
Liste gepflegt, die Datei entscheidet.

An SEINER echten Datei gemessen, ohne sie irgendwo hineinzuschreiben:
40 von 41 Spalten gespeichert (die 41. ist leer), Zeitraum 01.09.-
13.09. erkannt, 32 als Zahl, 8 als Text.

UND EIN MESSFEHLER, DER LEHRREICH IST: Meine erste Pruefung meldete
"zugeklappt ist die Liste 141 px hoch", im Bildschirmfoto war dort
nichts. An einem Miniaturfall nachgemessen: getBoundingClientRect,
offsetHeight, offsetParent und getClientRects liefern bei einem
<details> in BEIDEN Zustaenden identische Werte -- Chromium verbirgt
den Inhalt mit content-visibility:hidden, und das behaelt die letzte
Ausmessung. Nur checkVisibility() kann es unterscheiden. Die Messung
log, nicht die Seite.

pruef-backstage-import 160 (war 133), pruef-xlsx 75,
pruef-leistung-optik 59, pruef-leistung, pruef-css-klassen und
pruef-auskunft (46, DSGVO -- die neue Tabelle ist automatisch dabei,
weil die Auskunft ihre Liste aus PRAGMA foreign_key_list ableitet):
alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 01:46:07 +02:00
DogFatherGitandClaude Opus 5 984f0dd7a9 Die Zeitraeume bekommen eine Tafel -- und die Zahl, die fehlte
Filipe: "das muss viel geiler aussehen bitte. ich will dass es auch
seeeehr gut erkennbar ist, genau wie der text drueber. mach das bitte
alles so dass es mega speziell, hochwertig und lesbar ist."

DAS EIGENTLICHE PROBLEM WAR LESBARKEIT, nicht Geschmack. Im
Bildschirmfoto gemessen: Ueberschrift und Erklaersatz standen direkt
auf der Buehne -- einem Foto mit hellrotem Berg. Und die Karte griff
nach `--flaeche-tief`, einer Variablen, die es im ganzen Haus nicht
gibt; gegriffen hat der Ersatzwert mit 72 % Deckung, also kam der Berg
mit. Eine Variable, die nirgends steht, faellt nicht auf.

Jetzt sitzt alles in EINEM Koerper: vierfarbige Fassung, deckendes
Innenglas mit Messraster, die Zeitraeume als eingelassene Felder mit
dunklen Fugen. Das ist nicht neu erfunden, sondern die Rollenkachel der
Anmeldeseite -- ein Haus, eine Handschrift. Typenschild und Hauptzahl
in gebuerstetem Metall, mit vollwertigem Rueckfall.

"GUELTIGE LIVE-GEHEN-TAGE" WURDE BIS HEUTE WEGGEWORFEN. Datenbank,
Anzeigefeld und Importzeile waren da -- nur `spaltenRaten` hatte kein
Muster dafuer. Am 14.09. wurde das alte `/tag/` reparirt, das die
Spalte faelschlich zur Datumsspalte machte; die Reparatur hat den
falschen Empfaenger entfernt und keinen richtigen bestellt. Die
Pruefdatei SCHICKTE den Wert seit dem 14.09. und hat nie nachgesehen,
ob er ankommt. Jetzt steht er als Streifen da, in genau so viele
Kaestchen geteilt, wie der Zeitraum Tage hat.

ZWEI KLASSEN IM WAEHLER, mit Grund: `.spannen__schild` allein (0,1,0)
kam gegen `.inhalt .feldschild` aus start.css (0,2,0) nicht an -- im
Browser gemessen war weder `display: flex` noch die Farbe da.

UND EINE ZEITBOMBE ENTSCHAERFT: pruef-backstage-import rechnete
"morgen" mit `toISOString()` (UTC), der Server mit Ortszeit. Um 00:40
Berlin war das hier berechnete "morgen" in Wahrheit HEUTE -- die
Gegenprobe "ein Datum in der Zukunft wird abgelehnt" fiel taeglich
zwischen Mitternacht und zwei Uhr um. Alle drei Tage werden jetzt aus
einer Stelle abgeleitet.

Gemessen statt behauptet: 43 258 Bildpunkte hinter Ueberschrift und
Satz abgetastet, kein einziger rot. Gegenprobe mit weggenommenem
Innenglas: 2 857 rote -- die Messung kann Rot also sehen.

pruef-backstage-import 133 (war 127), pruef-xlsx 75 (war 67),
pruef-css-klassen, pruef-leistung-optik 59, pruef-leistung: alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-16 00:59:51 +02:00
DogFatherGitandClaude Opus 5 04f87603f6 Was dein Verlauf sagt -- die Analyse
Filipe: "mach mir auch eine analyse, mach eine perfektion draus. eine
professionelle auch mit infos und so aus aller welt was tiktok angeht.
ich will dass es perfekt ist!!!!"

SIE WIRD GERECHNET, NICHT GESPEICHERT. Kein Feld, keine Tabelle, keine
Note -- sie entsteht bei jedem Abruf neu aus dem Verlauf dieser einen
Person und verlaesst das Haus damit genauso wenig wie er.

DREI DINGE, DIE SIE TUT:

  1. Sie nennt das MUSTER, nicht den Einzelwert. "Da hakt es" in einer
     Runde ist ein schlechter Tag. Dasselbe in zwei Runden ist etwas
     anderes -- und genau das ist in der Forschung das Warnzeichen.
  2. Sie ordnet ein. Zu JEDER der sechs Fragen ein belegter Befund aus
     der Moderationsarbeit, damit niemand denkt, er sei der Einzige.
  3. Sie sagt, was hilft -- aber nur dort, wo es etwas zu tun gibt. Ein
     Rat an einer Stelle, die laeuft, ist Laerm und entwertet die
     anderen fuenf.

UND EINES, DAS SIE NICHT TUT: bewerten. Keine Punktzahl, kein Score,
kein Ampelgesicht. Eine Zahl ueber das eigene Befinden laedt dazu ein,
sie zu verbessern statt ehrlich zu antworten -- und ab da misst die
Abfrage nur noch sich selbst.

RECHERCHIERT, NICHT AUSGEDACHT. Die sechs Fragen standen schon auf der
richtigen Spur; die Quellen bestaetigen sie und liefern die Einordnung:

  "Zu wenig Zeit" und "Streit im Team" sind die zwei meistgenannten
  Gruende, warum freiwillige Moderatoren aufhoeren -- noch vor den
  Inhalten. Anschluss ans Team ist der staerkste einzelne Schutzfaktor.
  Bei bezahlten Moderatoren, auch bei TikTok, sagen ueber 80 % der
  Befragten, ihr Arbeitgeber muesse mehr fuer ihre psychische
  Gesundheit tun.

    https://news.umich.edu/online-content-moderators-likely-to-experience-burnout-u-m-study-suggests/
    https://discord.com/safety/understanding-and-avoiding-moderator-burnout
    https://restofworld.org/2025/tiktok-moderators-turkey/
    https://www.japantimes.co.jp/news/2025/07/04/world/science-health/content-moderators-mental-trauma/
    https://arxiv.org/pdf/2502.06985

Die drei wichtigsten stehen als Verweis unter der Analyse. Ein Satz
ueber "die Forschung" ohne Quelle ist eine Behauptung -- und bei diesem
Thema waere das der Moment, an dem man der ganzen Seite nicht mehr
glaubt.

Im Bildschirmfoto gesehen und behoben: Der Satz oben und die
Quellenzeile standen direkt auf der Buehne, also auf einem Foto. Die
Quellenzeile ist die kleinste Schrift der Seite. Dieselbe Antwort wie
heute Mittag bei der Entwicklungskarte -- keine hellere Schrift,
sondern etwas Deckendes darunter.

  server/pruef-befinden.mjs   75 Pruefungen (vorher 48), 0 Fehler
  Darunter: aus "neu" wird nach der dritten Runde "dauerhaft", jeder
  der sechs Befunde ist ein ANDERER (kein Satz, der zu allen passt),
  DogFather bekommt seine eigene leere Analyse, und im Protokoll steht
  weiterhin nichts davon -- weder die Analyse noch ein Anlass.

  pruef-css-klassen, pruef-entwicklung 43 -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 17:38:57 +02:00
DogFatherGitandClaude Opus 5 a919bc8720 Die Reaktionstafel landete in der Spalte des Namenskreises
Filipe, mit einem Bildschirmfoto: "was ist das den fuer eine scheisse
verbesser das sofort." Darauf ein dreissig Pixel schmaler Streifen,
sechs Zeichen untereinander, ein Rollbalken daneben.

.chat-nachricht ist ein RASTER aus zwei Spalten: dreissig Pixel fuer
den Kreis mit den Initialen, der Rest fuer die Blase. Ein Kind ohne
Spaltenangabe wird automatisch in die naechste freie Zelle gesetzt --
und das ist die Spalte des Kreises. `width: min(330px, 100%)` machte
daraus brav 30 Pixel, und die Zeichen stapelten sich.

UND WARUM ES NIEMANDEM AUFGEFALLEN IST: Bei der EIGENEN Nachricht
entfaellt der Kreis, das Raster hat dann nur eine Spalte, die Tafel
bekam die volle Breite. Die Pruefung vom 14.09. hat genau diesen Fall
gemessen -- nachgemessen heute: selbst=ja, eine Spalte, 611 px. Sie
war gruen, waehrend es bei JEDER fremden Nachricht kaputt war.

Und sie hat ausserdem nur Anwesenheit geprueft ("gibt es die
Elemente", "sucht die Suche") -- nie Geometrie. Eine dreissig Pixel
breite Tafel besteht jede dieser Zeilen.

Jetzt gemessen, und zwar in BEIDEN Faellen: Breite, ob die sechs
Vorschlaege auf EINER Zeile stehen, und ob die Tafel neben dem Kreis
steht statt darunter. Dafuer schreibt der Testraum jetzt auch eine
Nachricht von jemand anderem -- ohne die gab es dort nur eigene.

GEGENPROBE (Reparatur kurz entfernt, gemessen, wieder eingesetzt):

  ohne  30 px, 6 Zeilen, +0 px   <- genau das Bildschirmfoto
  mit   330 px, 1 Zeile, +39 px

  server/pruef-chat-aufloesen.mjs   125 Pruefungen (vorher 119)
  pruef-chat-optik, pruef-chat, pruef-css-klassen -- alle in Ordnung

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 17:31:35 +02:00
DogFatherGitandClaude Opus 5 5707e22b45 Die Seite springt nicht mehr -- und die Kachel zaehlt mit
Zwei Meldungen von Filipe, und sie gehoeren zusammen: Er hat beides am
selben Klick gemerkt.

  "immer wenn ich auf was drücke dan geht das fenster wieder hoch. die
   seite soll sich nicht immer wieder bewegen wenn ich auf was drücke."

  "und wieso steht bei vanvan 0 von 28 obwohl ich alle durch habe."

DER SPRUNG: In karte() stand ein scrollIntoView OHNE Bedingung -- und
die Funktion wird an vier Stellen gerufen. Beim Oeffnen einer Person
ist es richtig; nach dem ersten Klick auf einen Punkt, beim Aufklappen
aller Kategorien und nach dem Anlegen eines Schritts ist es falsch. Man
tippt unten auf "Läuft" und steht wieder ganz oben. `springen` ist
jetzt Vorgabe NEIN, und genau eine Stelle sagt ja.

Und selbst ohne Sprung bewegte sich die Seite: Der Neuaufbau aendert
die Hoehe der Karte (eine Zeile "Schritt läuft" kommt dazu), der
Browser behaelt nur die Pixelzahl. Die Hoehe wird deshalb gehalten.

"Alle aufklappen" holt die Karte gar nicht mehr neu -- Aufklappen ist
eine Sache der Anzeige, dafuer braucht es den Server nicht.

DIE NULL: Die Kachel kommt aus /entwicklung/lage -- EINMAL, beim Laden
der Seite. Die Karte holt ihren Stand bei jedem Oeffnen neu. Wer 28
Punkte durchklickt, sieht in der Karte 28 von 28 und auf der Kachel
darueber die Zahl von vorhin. Zwei Wahrheiten auf einem Bildschirm, und
die falsche steht oben.

Die Liste NICHT neu zu holen ist Absicht -- jeder Neuaufbau bewegt die
Seite, und darueber ging die andere Meldung. Stattdessen wandert die
Zahl mit, zusammen mit dem Kopf der Karte und den Koepfen der
Kategorien ("3 / 7", "2 x hakt").

WAS DIE PRUEFUNG AN MIR SELBST GEFUNDEN HAT, dreimal:

  - Sie mass nach dem Sprung aufs Aufgabenbrett weiter und verglich
    zwei leere Texte. Zwei leere Texte sind gleich und beweisen nichts
    -- gemeldet hat es die Zahl in der Bedingung daneben.
  - Danach verglich sie Fridas Kachel mit Riekes Karte und meldete
    einen Unterschied zwischen zwei verschiedenen Menschen. Beinahe
    haette ich einen Fehler gesucht, den es nicht gab.
  - Und "wo etwas hakt, steht es im Kopf" waere ab heute auch ueber
    vier VERSTECKTEN Hinweisen gruen gewesen: Der Hinweis steht jetzt
    immer im Baum, damit er nachgezogen werden kann, ohne den Kopf neu
    zu bauen. Jetzt wird auf sichtbar geprueft, nicht auf vorhanden.

  server/pruef-schritt.mjs   65 Pruefungen (vorher 57), 0 Fehler
  Beide Meldungen werden am selben Klick nachgestellt: Hoehe und Zahl
  vorher merken, EINMAL druecken, beides nachsehen. Mit Gegenprobe --
  auf eine Person zu druecken DARF springen, sonst hiesse "springt
  nicht" nur, dass gar nichts mehr scrollt.

  pruef-css-klassen, pruef-entwicklung 43, pruef-neue-seiten 93 -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 17:25:29 +02:00
DogFatherGitandClaude Opus 5 45f5a35afe Die Kategorien lassen sich auf- und zuklappen
Filipe: "mach das viel geiler alles bitte, ich will auch dass man die
kategorien von den fragen, also die liste auf und zu druecken kann mit
einem button."

ACHTUNDZWANZIG PUNKTE OFFEN SIND RUND ZWEI METER SEITE. Man scrollt,
verliert die Stelle und macht es beim naechsten Mal gar nicht mehr.

  - Jede Kategorie hat einen Knopf. Ein Klick wechselt nur DIESEN
    Abschnitt; die Karte wird nicht neu geholt, sonst springt die Seite
    bei 28 Punkten unter den Fingern weg.
  - Der Zustand liegt im Skript, nicht an den Elementen: Nach dem
    ersten Klick auf einen Punkt zeichnet die Karte sich neu (erst
    danach darf der Stand der anderen ausgeliefert werden). Am Element
    klappte dabei alles wieder zu -- mitten in der Arbeit.
  - Welche zuerst offen steht, ist die eigentliche Entscheidung: die
    erste, in der noch etwas fehlt. Alle zu hiesse jedes Mal suchen,
    alle auf waere der Zustand von vorher.
  - Der Kopf sagt ZUGEKLAPPT, was drin ist: "2 / 8" und, wenn etwas
    hakt, "1 x hakt". Eine zugeklappte Kategorie, die nichts sagt,
    klappt man einmal auf und danach nie wieder zu.
  - Daneben "Alle aufklappen" / "Alle zuklappen" fuer den Durchgang.

WAS DAS BILDSCHIRMFOTO AUSSERDEM GEZEIGT HAT, und was ich im Code nicht
gesehen haette: Die Karte hatte gar keine eigene Flaeche. "Frida · Modi
· 2 von 28 angesehen" lag quer ueber dem Spicy-Media-Schriftzug, der
Knopf darunter ueber einer Chilischote. Genau der Fall, fuer den die
Kontrastmessung ihren dritten Ausgang hat ("konnte nicht nachsehen") --
ueber einem Foto laesst sich Lesbarkeit nicht ausrechnen. Die Antwort
darauf ist keine hellere Schrift, sondern eine deckende Flaeche.

Und der Hinweis "(bei 'Da hakt es' noetig)" stand bisher 28 Mal da,
auch an Punkten, an denen nichts hakt. Ein Satz, der ueberall steht,
wird nirgends gelesen. Jetzt meldet sich das Feld erst, wenn es
gebraucht wird -- mit Rahmen in derselben Farbe wie die Antwort, und
der Mauszeiger springt hinein.

Beim Nachsehen im Bild gefunden: "2 von 28 angesehen" stand danach
zweimal auf demselben Bildschirm. Zweimal dieselbe Zahl laesst einen
ueberlegen, ob es zwei verschiedene sind.

  server/pruef-schritt.mjs   57 Pruefungen (vorher 46), 0 Fehler
  Der Knopf wird wirklich gedrueckt -- ein Knopf, den niemand betaetigt
  hat, ist kein geprueter Knopf.

  pruef-css-klassen, pruef-entwicklung 43, pruef-neue-seiten 93,
  pruef-nachwuchs 123 -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 14:40:11 +02:00
DogFatherGitandClaude Opus 5 418b6211e2 Ein Hinweis auf eine Seite, die es hier nicht gibt, ist kein Hinweis
Filipe, mit dem Bildschirmfoto auf crew.: "wieso steht es noch da?" --
"1 Punkt im Start-Check braucht Handlung", mit einem Pfeil auf eine
Seite, die seit einer Stunde dort gesperrt ist.

MEIN FEHLER VON HEUTE MITTAG. Ich hatte die Seiten gesperrt und
ausdruecklich dazugeschrieben "nur die Seiten, nicht die
Schnittstellen" -- und dabei uebersehen, dass es eine DRITTE Stelle
gibt. Die Hinweise auf der Startseite sind keine Seite und keine
Schnittstelle, sondern eine Liste von VERWEISEN. Der Satz im Kommentar
klang vollstaendig und war es nicht.

Nachgesehen, wer sonst noch Seitenziele ausliefert, statt zu raten:

  workspace-hinweise.js   alle 16 Hinweise, ueber dazu()   -> behoben
  workspace-suche.js      jeder Treffer traegt ein Ziel    -> behoben
  workspace-push.js       Benachrichtigungen tragen eines  -> OFFEN

Die ersten beiden bekommen dieselbe Regel wie die Seiten, nicht eine
zweite: gehoertAufDieseAdresse(). Was hier keine Seite hat, bekommt
hier auch keinen Hinweis und keinen Treffer. Bei der Suche fallen leere
Gruppen mit weg (eine Ueberschrift ohne Treffer sieht aus, als waere
etwas kaputt) und `gesamt` wird danach abgeleitet, sonst nennt die Zahl
Treffer, die gar nicht dastehen.

DIE ADRESSE IST IMMER DIE ECHTE: Beide Stellen benutzen `req.sicht ||
req.person`. Der Sicht-Umschalter aendert, WESSEN Zahlen dastehen --
nicht, auf welcher Wand man steht. Das Haus kommt deshalb aus
req.person.

PUSH BLEIBT OFFEN, und zwar bewusst: Eine Benachrichtigung entsteht,
wenn niemand auf einer Adresse steht. Sie geht an ein GERAET, und das
oeffnet die Adresse, als die es installiert wurde. Das ist eine andere
Frage als diese hier, und eine halbe Antwort waere schlechter als
keine. Gehoert eigens angesehen.

Was die Gegenprobe gefunden hat -- an mir selbst, zweimal:

  Der erste Entwurf der Pruefung legte die Tabelle `startcheck` mit
  erfundenen Spalten selbst an. Die echte war laengst da, das
  IF NOT EXISTS schwieg, der INSERT scheiterte. Die Pruefung haette
  gemeldet, der Hinweis stehe nirgends -- richtig und wertlos.

  Und "kein Suchtreffer zeigt dorthin" stand ueber NULL Treffern. Jetzt
  wird erst nachgewiesen, dass die Suche denselben Menschen auf der
  Agenturadresse wirklich findet (1 Treffer -> profil.html).

  server/pruef-haus-seiten.mjs   34 Pruefungen (vorher 24), 0 Fehler
  pruef-sicht, pruef-haus-trennung 66, pruef-betreuung,
  pruef-manager-sicht 43 -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 14:30:31 +02:00
DogFatherGitandClaude Opus 5 44a6b7cb83 Auf der Team-Adresse gibt es die Agenturseiten nicht
Filipe, mit dem Bildschirmfoto des Start-Checks auf crew.: "das gibt
es in der app nicht, dass ist nur auf der workspace app aber nicht
hier."

ES WAR GROESSER ALS DIESE EINE SEITE. Gemessen, bevor gebaut:

  DogFather    12 Seiten ohne Kachel erreichbar, 10 davon Agentur
               (Automationen, Content, Scouting, Reports, Zahlen,
               Team, Calls, Creator-Profil, Dashboard, Start-Check)
  rechte Hand   5, davon 3 Agentur
  ein Modi      6, davon 3 Agentur -- auch der Start-Check

Die Haustrennung vom 10.09. entscheidet, WAS jemand sieht: sie filtert
Daten und Kacheln. Sie entschied nie, welche SEITEN es auf einer
Adresse gibt. Die Rechtetafel wiederum kennt nur Rollen, keine
Adressen. Zwischen beidem lag das Loch -- und der Start-Check sagte
dort "Es gibt noch keinen Creator", weil ihm die Haustrennung alle
Daten wegnimmt. Eine Seite, die laedt und leer ist, sieht aus wie ein
Fehler.

DIE REGEL WIRD ABGELEITET, NICHT GEPFLEGT: Welche Seiten zu dieser
Adresse gehoeren, steht schon in den KACHELN, die dieselbe Adresse
dieser Person zeigt. Dazu drei Seiten, die in jedem Haus dazugehoeren
und keine Kachel haben (start, treff-regeln, entwicklung). Sie altert
sicher -- eine neue Agenturseite ist dort automatisch zu, eine neue
Crew-Seite ohne Kachel faellt beim ersten Klick auf.

UND SIE AENDERT KEINE RECHTE. Was jemand DARF, steht weiter allein in
rechte.js; diese Regel beantwortet, ob es das hier ueberhaupt gibt.
Nur die Seiten, nicht die Schnittstellen -- die filtern seit dem 10.09.
selbst ueber person.haus.

DREI PRUEFUNGEN, DIE VORHER SCHON ROT WAREN, nachgemessen gegen den
Stand von heute frueh (2712473), damit ich sie nicht mir selbst
zuschreibe -- und zwei davon repariert:

  pruef-treff       Sie fragte "enthaelt die Antwort irgendein
                    gefuelltes Feld" und wurde rot, als das
                    Aufgabenbrett die drei Aufwandsstufen mitzuliefern
                    begann. Die sagen ueber niemanden etwas. Eine
                    Warnung, die immer kommt, wird ueberlesen -- also
                    praeziser statt lauter: Ein Datensatz hat eine id,
                    ein Vokabular einen schluessel und keine.
  pruef-neue-seiten War gruen und wurde durch MEINE Arbeit rot: Mit
                    dem Umzug der sechs Fragen blieben bei 390 px noch
                    14 Textstuecke statt der geforderten 15 -- alle
                    lesbar. Die Zahl auf 14 zu setzen waere derselbe
                    Fehler mit einer anderen Zahl gewesen; die Aufgabe
                    ("die Seite hat wirklich gerendert") erledigt zwei
                    Zeilen hoeher schon die Zeichenzahl.
  pruef-kachel-universum, pruef-struktur, pruef-modi-wortleck
                    unveraendert rot, nicht von hier -- offen.

Ausserdem: "wenn alle 1 sie gesetzt haben" auf der eigenen Karte. Das
ist keine Auskunft, sondern eine Rechnung -- derselbe Fall wie "vor 0
Tagen" heute frueh. Zwei Lagen, zwei Saetze.

  server/pruef-haus-seiten.mjs   24 Pruefungen, 0 Fehler (Port 4422)
  pruef-crew-adresse 132, pruef-modi-verborgen 80, pruef-haus-trennung 66,
  pruef-treff 66, pruef-treff-werkzeuge 70, pruef-neue-seiten 93,
  pruef-befinden 48, pruef-schritt 46 -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 14:19:15 +02:00
DogFatherGitandClaude Opus 5 c615eab236 Entwicklung: aus einer Beobachtung wird ein Schritt
Filipe: "ich will die noch viel besser, perfektionniert, viel geiler
und krasser. es soll so einfach wie moeglich sein fuer jeden."

Die Karte konnte bisher genau eines: festhalten, dass etwas hakt --
mit Anlass, das war schon richtig. Danach passierte nichts. Beim
naechsten Oeffnen stand dieselbe Beobachtung da, nur aelter.

Die Quellen zur laufenden Entwicklungsbegleitung sagen zweierlei: weg
von der Bewertung, hin zum Gespraech -- und ein Entwicklungsplan wirkt
dann, wenn er an einer ECHTEN Aufgabe haengt. Nicht "daran arbeiten
wir", sondern etwas mit Verantwortlichem und Frist.

Also: An einem Punkt, der hakt, steht ein Knopf. Er legt eine Aufgabe
auf dem Brett an -- Titel = der Punkt, der Anlass wandert in die
Beschreibung (ohne ihn waere es ein Vorwurf), verantwortlich ist der
Mensch selbst, Frist in 14 Tagen. Die Karte zeigt danach, dass ein
Schritt laeuft, und verweist auf ihn.

UND DANN SCHLIESST SICH DER KREIS: Ist der Schritt erledigt, sagt die
Karte das und bittet, noch einmal hinzusehen. Das ist der Rhythmus,
den die Quellen meinen -- keine Bewertung einmal im Jahr, sondern eine
Runde, die zu Ende geht. Danach geht derselbe Punkt wieder.

Die Riegel: nur aus dem EIGENEN "da hakt es" (aus dem eines anderen
hiesse, in seinem Namen zu handeln), nur ein offener Schritt je Punkt,
nur Leitung, und ein Punkt aus Block 5 sieht von aussen aus wie ein
erfundener. Im Protokoll steht, DASS -- nie der Anlass.

NEBENBEFUND, beim Uebernehmen der Schreibweise gefunden: aufgaben.html
#a<nummer> stand an DREI Stellen im Haus (bereich.js, report.js, jetzt
die Entwicklungskarte) und wurde von keiner gelesen -- das Brett kannte
nur ?zeigen=, und eine Karte mit ihrer Nummer als Anker gab es nicht.
Wer draufdrueckte, landete auf dem Brett und suchte von Hand. Jetzt
tragen die Karten ihre Nummer, und das Brett hebt genau die eine
hervor. Alle drei Verweise funktionieren damit.

Und was die Pruefung an sich selbst gefunden hat: Ich habe die rechte
Hand ueber die Adresse von DogFather gerufen. Sie bekam 401 -- und WEIL
sie nichts setzen konnte, ging ein zweiter Test aus dem falschen Grund
durch. Ein gruener Haken ueber einer Leere.

  server/pruef-schritt.mjs    46 Pruefungen, 0 Fehler (Port 4421)
  pruef-uebergang 61, pruef-nachwuchs 123, pruef-entwicklung 43,
  pruef-uebernahme 39, pruef-aufgabenbrett, pruef-css-klassen -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 14:03:03 +02:00
DogFatherGitandClaude Opus 5 b85740dc20 Talente: der Uebergang, an dem die meisten verlorengehen
Filipe: "ich will dass du die 2 kategorien perfektionnierst. ich will
die noch viel besser, perfektionniert, viel geiler und krasser. es
soll so einfach wie moeglich sein fuer jeden."

Die AUSWAHL war der gut gebaute Teil dieser Seite: 21 Merkmale, sechs
Warnzeichen, ein Trichter mit Standzeiten. Die Stelle, an der Teams
tatsaechlich Leute verlieren, liegt dahinter -- zwischen dem "ja" und
der ersten echten Schicht. Wer zusagt und danach zwei Wochen nichts
hoert, hat innerlich schon abgesagt, und auf der Karte steht weiter
"angesprochen".

In der Beschreibung der Stufe "Probe" stand seit dem ersten Tag
"fester Buddy". Ein Feld dafuer gab es nicht. Ein Versprechen im Text
ist keine Eigenschaft des Systems -- erst eine Regel, die NEIN sagen
kann, ist eine.

Ab jetzt:

  - Auf die Probe kommt niemand ohne einen Namen und ein Datum. Die
    Absage sagt, welches von beiden fehlt, und die Karte bleibt dabei
    stehen, wo sie war.
  - Die Karte zeigt beides: wer einarbeitet, wann die erste Schicht
    ist -- in einem Satz, den man laut vorlesen kann ("Erste Schicht
    ist morgen."). Ein Termin weiter als 14 Tage ist erlaubt, wird
    aber benannt.
  - Drei Dinge fuer den ersten Tag stehen auf der Probekarte: was
    gilt, was du darfst, wen du fragst. Keine Haken -- der Buddy soll
    sie lesen, nicht abarbeiten.
  - Buddy und Termin lassen sich spaeter aendern, OHNE die Standzeit
    zurueckzusetzen: Sie ist die Auskunft ueber uns, nicht ueber den
    Kandidaten.
  - Wer geht, ist kein Buddy mehr -- stillgelegt wie geloescht. Die
    Karte sagt dann "bitte neu bestimmen" und ist am Rand markiert.

Recherche (Quellen im Kopf von workspace-talent-punkte.js): Discord
nennt Buddy und Mentoring als die beiden Trainingswege, die
funktionieren; aus der Freiwilligenarbeit kommt dieselbe Aussage mit
Zahlen. Und: Am ersten Tag braucht jemand drei Dinge, nicht dreissig.

Was die Pruefung gefunden hat: buddy_weg fragte "buddy_id gesetzt UND
Person weg" -- damit war der zweite Weg blind. Wird ein Mensch
geloescht, setzt ON DELETE SET NULL die Spalte auf NULL, die Karte sah
unauffaellig aus, und eine laufende Probe stand ohne jeden Buddy da.

  server/pruef-uebergang.mjs   61 Pruefungen, 0 Fehler (Port 4420)
  pruef-nachwuchs 123, pruef-entwicklung 43, pruef-css-klassen -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 13:55:26 +02:00
DogFatherGitandClaude Opus 5 d4730deb30 Wie geht's dir? bekommt eine eigene Seite
Filipe, zum Bildschirmfoto der Kachel: "ich will dass du diese seite
perfektionnierst den gerade wenn ich drauf druecke geht die
entwicklungsseite auf."

Der Fehler war schlimmer als ein falscher Verweis. Auf der Kachel
steht "die Antworten sieht nur du" -- und sie oeffnete eine Seite
voller Namen und Beobachtungen ueber ANDERE Menschen. Wer ihr glaubt
und drauftippt, sieht im ersten Moment das Gegenteil dessen, was
draufsteht.

Jetzt: eine Seite, ein Zweck.

  workspace/befinden.html + assets/js/befinden.js   die eigene Seite
  server/workspace-befinden.js                      Rhythmus + Verlauf
  entwicklung.html                                  nur noch ein Verweis

Was die Recherche zu Puls-Abfragen ergeben hat (Quellen im Kopf des
Moduls): kurz halten (fuenf bis fuenfzehn Fragen -- sechs bleiben
sechs), WIEDERHOLEN (zweiwoechentlich), und der VERLAUF ist die
Auskunft, nicht der Einzelwert. Bisher beantwortete man die sechs
Fragen einmal, und die Antwort stand fuer immer -- ein Befinden von
vor drei Monaten ist keine Auskunft mehr, sondern ein Andenken.

Der Verlauf gehoert ihr allein: eigene Tabelle, kein von_id, kein
anderer Weg im Haus liest sie. Im Protokoll steht nur, DASS eine
Runde war, nie was darin stand. Die Ampel zaehlt weiterhin nur den
aktuellen Stand und kennt keine Namen.

Zwei Dinge, die erst die Pruefung gefunden hat:

  - Wer die neue Seite oeffnete, ohne dass vorher jemand die
    Entwicklungsseite besucht hatte, bekam "no such table" und eine
    503. entwicklung_stand wird beim ersten Aufruf angelegt, nicht
    beim Start. Die Tabelle wird jetzt angefordert, nicht ein zweites
    Mal abgeschrieben.
  - pruef-entwicklung suchte die Kachel ueber ziel ===
    "entwicklung.html" und hat den gemeldeten Fehler damit
    mitgetragen. Sie sucht jetzt die eigene Seite -- und prueft
    zusaetzlich, dass keine Kachel mehr ersatzweise dorthin fuehrt.

Ausserdem weg: die tote Funktion meins() in entwicklung.js (sie
zeichnete in drei Stellen, die es nicht mehr gibt) und der Titel
"Wie geht's dir?", den diese Seite fuer einen Modi trug -- er
versprach etwas anderes als die Seite zeigt, also derselbe Fehler
wie an der Kachel.

  server/pruef-befinden.mjs   48 Pruefungen, 0 Fehler (Port 4419)
  pruef-entwicklung           43 (vorher 40), 0 Fehler
  pruef-nachwuchs 123, pruef-rechtetafel 19, pruef-rechte-umstellen 46,
  pruef-css-klassen -- alle 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 13:45:56 +02:00
DogFatherGitandClaude Opus 5 2712473f16 Womit anfangen? -- Stufe 9 ist damit vollstaendig
Letztes Stueck aus dem Plan zur Perfektion: "Wichtig-vs-Aufwand im
Report".

DIE FRAGE, DIE EINE AUFGABENLISTE NICHT BEANTWORTET

Ein Brett mit dreissig offenen Karten sagt, WAS zu tun ist. Es sagt
nicht, WOMIT man anfaengt. "Wichtig" allein hilft dabei nicht: Sind
acht Karten wichtig, ist keine davon die erste.

Die zweite Angabe, die dafuer fehlte, ist der AUFWAND -- eine Spalte,
mehr nicht. "Wichtig" gibt es schon, das ist die Prioritaet; es wird
kein zweites Feld dafuer erfunden.

VIER FELDER, UND JEDES SAGT, WAS ZU TUN IST

  wichtig + klein   SOFORT      in einer halben Stunde erledigt, und es zaehlt
  wichtig + gross   EINPLANEN   braucht einen Termin, keinen guten Willen
  normal  + klein   NEBENBEI    wenn zwischendurch Luft ist
  normal  + gross   SPAETER     ehrlich: das wird gerade nichts

Die Namen sind Handlungsanweisungen, keine Etiketten. "Quadrant 2" sagt
niemandem, was er tun soll.

OHNE SCHAETZUNG VERSCHWINDET NICHTS

Der Aufwand ist freiwillig -- und laesst sich zuruecknehmen. Aufgaben
ohne Schaetzung landen deshalb nicht stillschweigend irgendwo, sondern
in einer eigenen, klar benannten Gruppe: "noch nicht eingeschaetzt".
Eine Uebersicht, die einen Teil der Arbeit unsichtbar macht, ist
schlimmer als keine -- man verlaesst sich darauf und uebersieht genau
das, was fehlt. Die Pruefung zaehlt deshalb nach, dass die Summe der
Felder die Summe der offenen Aufgaben ist.

DREI STUFEN, NICHT FUENF. Fuenf klingen genauer und sind es nicht:
Niemand unterscheidet verlaesslich zwischen "eher mittel" und "eher
gross". Drei kann man ohne Nachdenken vergeben, und nur was ohne
Nachdenken geht, wird auch gepflegt.

KEINE CHECK-LISTE IN DER DATENBANK. Die erlaubten Werte stehen in
workspace-womit.js; eine CHECK-Liste daneben waere eine zweite
Wahrheit, die beim naechsten Wert ueber einen Tabellenneubau
nachgezogen werden muesste -- und dabei sind im Projekt schon dreimal
Spalten verlorengegangen. Geprueft wird beim Schreiben, an der Stelle,
die die Liste kennt. Die Oberflaeche baut ihre Auswahl ebenfalls aus
dieser Liste, statt drei <option>-Zeilen zu fuehren.

PRUEFUNGEN: pruef-womit neu mit 41, davon 10 im Browser. Darunter die
Zeile, die zaehlt: nichts verschwindet.

STUFE 9 IST DAMIT DURCH: Idee -> Aufgabe, Dateifassungen, Anhaenge an
Aufgaben, Eskalationsstufe, Wichtig-vs-Aufwand.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 13:29:39 +02:00
DogFatherGitandClaude Opus 5 2d5972f45f Wie lange geht das schon so -- Eskalation statt eines Schalters
Stufe 9 aus dem Plan: "Eskalationsstufe sichtbar". Damit ist Stufe 9
bis auf einen Punkt durch.

DER MANGEL, GEMESSEN

"Ueberfaellig" war ein Schalter: an oder aus. Eine Aufgabe, deren Frist
gestern lief, sah genauso aus wie eine, die seit drei Wochen liegt --
dasselbe Wort, dieselbe Farbe, derselbe Platz.

Damit verliert das Wort seine Bedeutung. Stehen auf einem Brett zwanzig
Karten "ueberfaellig", sagt keine davon mehr etwas; man ueberliest sie
alle, auch die, die seit einem Monat blockiert.

ZWEI VERSCHIEDENE FRAGEN, DIE NICHT VERMISCHT WERDEN DUERFEN

  FRIST UEBERSCHRITTEN   Es war etwas versprochen, der Termin ist
                         vorbei. Eine Tatsache.
                         faellig (ab 1 Tag) -> liegt (ab 3) -> haengt (ab 8)

  NICHTS PASSIERT        Keine Frist, aber seit 14 Tagen hat niemand
                         die Karte angefasst. Eine Beobachtung.

Die erste ist haerter und steht vorn. Eine Aufgabe ohne Frist ist nicht
"zu spaet" -- sie ist nur still. Beides in einen Topf zu werfen hiesse,
jemandem einen gebrochenen Termin vorzuwerfen, den er nie zugesagt hat.
Deshalb ist "still" auch farblos gezeichnet, gestrichelt statt gefuellt.

DAS IST KEINE MAHNUNG

Dieselbe Haltung wie bei der Standzeit im Talente-Trichter: Die Zahl ist
eine Auskunft ueber UNS, kein Vorwurf an eine Person. Deshalb steht
nirgends ein Name, und die hoechste Stufe heisst "haengt", nicht
"versaeumt".

DIE SCHWELLEN SIND GESETZT, NICHT GEMESSEN -- und das steht so im Code:
unter 3 Tagen reicht ein Wochenende; ab 3 ist es ein Zustand; ab 8 (ueber
eine Woche) kommt es ohne Hilfe auch naechste Woche nicht dazu. Aendert
sich eine Zahl, aendert sie sich an einer Stelle, und die Oberflaeche
zieht mit -- sie bekommt das WORT vom Server.

AM SERVER GERECHNET. Startseite, Brett und Uebersicht lesen dieselbe
Liste. Drei Stellen, die dieselbe Frage selbst beantworten, geben
irgendwann drei Antworten -- genau der Fehler, der im Projekt schon bei
der Rollenreihenfolge und beim Wort "Agentur" passiert ist.

DIE FARBE IST NICHT DIE AUSKUNFT: In jedem Kaestchen steht ein Wort
("liegt seit 5 Tagen"), nicht nur ein roterer Punkt.

PRUEFUNGEN: pruef-eskalation neu mit 40, davon 6 im Browser. Gemessen
wird an den GRENZEN, nicht in der Mitte -- jede Schwelle dreimal: einen
Tag davor, genau darauf, einen Tag danach. Die wichtigste ist die erste:
am Tag der Frist ist nichts ueberfaellig. Wer bis zum 15. Zeit hat, ist
am 15. puenktlich; eine Eskalation, die einen Tag zu frueh anschlaegt,
verliert genau das Vertrauen, das sie braucht.

Die Pruefung benutzt einen FESTEN Zeitpunkt als Eingabe, keine
Wanderuhr -- sonst misst sie irgendwann das Gegenteil.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 13:22:55 +02:00
DogFatherGitandClaude Opus 5 1386534051 Anhaenge an Aufgaben -- ohne eine zweite Dateiablage
Stufe 9 aus dem Plan. Eine Aufgabe "Vertrag pruefen" ohne den Vertrag
daneben ist eine Aufforderung zum Suchen.

KEIN ZWEITER HOCHLADEWEG

Dateien leben in der Dateiablage -- mit ihrer Sichtbarkeit, ihren
Freigaben, ihren Fassungen und ihrem Protokoll. Ein eigener Weg an der
Aufgabe waere eine zweite Ablage mit einer zweiten Rechtelogik gewesen,
und die zweite ist immer die, die etwas durchlaesst.

Deshalb nur eine Spalte: Die Datei WEISS, zu welcher Aufgabe sie
gehoert. Hochgeladen wird ueber denselben Weg wie immer, mit einem Kopf
mehr. Alles andere bleibt, wo es schon richtig ist -- die Anhaenge
tragen deshalb auch ihre Fassungsnummer und die Warnung "nicht mehr
aktuell" mit, ohne dass dafuer eine Zeile geschrieben werden musste.

DER RIEGEL

Waere `x-aufgabe` ungeprueft, waere der Kopf ein Weg, die Existenz
fremder Aufgaben zu erfahren -- man muesste nur Zahlen durchprobieren.
Geprueft wird deshalb gegen dieselbe Schranke wie fuer die Datei
selbst: `darfCreator`, die eine Stelle im Haus, an der diese Frage
beantwortet wird. Eine eigene Herleitung hier waere eine zweite Meinung
darueber gewesen. (Erster Anlauf: genau so eine Herleitung, mit einer
Funktion, die gar nicht importiert war.)

Gemessen: Ein Scout darf an die Aufgabe SEINER Creatorin, an die eines
fremden Creators nicht -- mit wortgleicher Absage wie bei einer
erfundenen Nummer. Der Unterschied waere sonst die Auskunft. Und es
bleibt auch keine lose Datei liegen: Die Pruefung findet vor dem ersten
Byte statt.

ON DELETE SET NULL, NICHT CASCADE

Der wichtigste Teil der Spalte: Wer eine Aufgabe loescht, will die
Aufgabe loeschen, nicht den Vertrag, der daran hing. Die Datei verliert
nur ihren Bezug und steht danach wieder in der Ablage. Gemessen.

EIN EIGENER FEHLER, GEFUNDEN BEIM MESSEN

Der Verweis am Anhang zeigte auf /workspace/api/dateien/:id -- den es
gar nicht gibt, der Weg heisst /inhalt. Die Pruefung ruft ihn jetzt
wirklich auf und erwartet 200, statt nur die Adresse zu vergleichen.

PRUEFUNGEN: pruef-anhaenge neu mit 37, davon 8 im Browser.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 13:12:41 +02:00
DogFatherGitandClaude Opus 5 478a2895b5 Dateifassungen: die alte Fassung sieht man ihr an
Stufe 9 aus dem Plan: "Dateiversionen statt Ueberschreiben".

GEMESSEN, BEVOR ETWAS GEBAUT WURDE -- DER PLAN LAG DANEBEN

Ueberschrieben wurde nie: `name_datei` ist eindeutig und zufaellig,
jedes Hochladen legt eine neue Zeile an. Der wirkliche Mangel ist ein
anderer, und er ist gefaehrlicher als Ueberschreiben:

  Zwei Dateien gleichen Namens standen BEZIEHUNGSLOS nebeneinander. Die
  alte kann "freigegeben" sein, die neue "entwurf" -- und wer die Liste
  ansieht, laedt die freigegebene herunter. Also die falsche. Kein
  Fehler, keine Meldung, nur die alte Fassung in der Hand.

WAS JETZT PASSIERT

Beim Hochladen erkennt der Server die Vorgaengerin selbst: gleicher
Originalname, gleicher Creator-Bezug, und sie darf nicht schon ersetzt
sein. An der Datei steht danach "Fassung 2"; an der alten steht "nicht
mehr aktuell".

  AUTOMATISCH, NICHT GEFRAGT -- eine Abwaegung: Wer die Verknuepfung
  vergisst, hat zwei Dateien ohne Zusammenhang, und irgendwann laedt
  jemand die alte herunter. Wer sie faelschlich bekommt, SIEHT das
  sofort und loest sie mit einem Klick. Der stille Schaden ist groesser
  als der sichtbare.

  BEI ZWEIFEL WIRD NICHT GERATEN. Gibt es zwei unersetzte Dateien
  gleichen Namens, bleibt die neue eigenstaendig.

  LOESEN GEHT NUR AN DER AKTUELLEN FASSUNG. Wer eine ueberholte loest,
  macht daraus eine zweite aktuelle -- und hat das Problem zurueck.

  DIE NUMMER IST GERECHNET, NICHT GESPEICHERT. Eine Spalte "version"
  muesste beim Loeschen einer mittleren Fassung nachgezogen werden, und
  genau das vergisst man. Faellt die erste weg, zaehlt die zweite
  wieder als erste -- richtig, denn mehr weiss das System dann nicht.

  EIN RING IN DEN DATEN HAELT DIE SEITE NICHT AN. Kann ueber die Wege
  hier nicht entstehen, aber ein Fehler anderswo koennte ihn erzeugen,
  und ein Stillstand ist schlimmer als ein Fehler. Gemessen: 1 ms.

ZWEI SITZUNGEN IM SELBEN VERZEICHNIS

Der vorige Commit (d2210fd, aus einer anderen Sitzung) hat mit
`git add -A` meine damals noch unfertige Spalte `dateien.ersetzt_id`
mitgenommen -- sie steht dort unter einer Ueberschrift, die nichts
damit zu tun hat. Niemand hat etwas falsch gemacht; die Sitzungen
konnten voneinander nicht wissen. Aufgefallen ist es, weil der
Versionsstempel ploetzlich 347 statt 372 Verweise meldete und ich dem
Rueckgang nachgegangen bin.

PRUEFUNGEN: pruef-fassungen neu mit 37, davon 6 im Browser.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 12:58:26 +02:00
DogFatherGitandClaude Opus 5 d2210fdd77 Der Erklaerkasten auf jeder Seite ist weg
Filipe, mit dem Kasten im Bild: "das muss sofort weg. ueberall das ist
scheisse."

Entfernt, nicht ausgeblendet:
  - workspace/assets/js/erklaerung.js
  - server/workspace-erklaerung.js samt Router-Einbindung in index.js
  - server/pruef-erklaerung.mjs
  - der Stilblock in start.css
  - die Skript-Zeile auf allen 25 Seiten

AUSGEBLENDET WAERE KEIN ENTFERNEN. Der Weg haette weiter geantwortet,
das Skript waere weiter geladen worden, und beim naechsten Umbau waere
der Kasten irgendwo wieder aufgetaucht. Was weg soll, wird weggenommen.

NACHGEMESSEN STATT ANGENOMMEN:
  - kein Verweis auf die geloeschten Dateien mehr im Repo,
  - der Server startet ohne Fehler (frische Datenbank, Protokoll leer),
  - keine Reste (erkl__, erklaerung.js) in Seiten oder Stilvorlagen.

Vier andere Pruefungen nennen ebenfalls "Erklaerung" -- sie meinen
ANDERE: den Satz im Neu-Fenster des Chats, die Stufen-Seite, die
Rollenkarten. Die bleiben unberuehrt; nachgesehen, nicht vermutet.

pruef-workspace-seiten, pruef-css-klassen und pruef-lesbarkeit laufen
gruen. Die Zahl der Pruefungen sinkt um die der geloeschten Datei --
das ist hier richtig: Sie prueften etwas, das es nicht mehr gibt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 12:52:13 +02:00
DogFatherGitandClaude Opus 5 d76d9aa5da Aus einer Idee wird Arbeit -- mit einem Knopf statt mit Abtippen
Stufe 9 aus dem Plan zur Perfektion: "Idee -> Aufgabe/Termin".

WARUM DAS MEHR IST ALS EINE BEQUEMLICHKEIT

Das ganze Haus steht auf einem Satz: "Was hier nicht steht, passiert
nicht." Ein Ideenbrett, aus dem keine Aufgabe werden kann, ist der eine
Ort, an dem dieser Satz nicht gilt -- dort steht etwas, und passieren
tut es trotzdem nicht. Wer eine Idee umsetzen wollte, tippte sie ein
zweites Mal ab. Und was man abtippt, tippt man irgendwann nicht mehr ab.

DREI ENTSCHEIDUNGEN

  GENAU EINMAL. Ein zweiter Versuch fuehrt nicht zu einer zweiten
  Aufgabe, sondern zum Verweis auf die vorhandene (409). Gefragt wird
  an der AUFGABE, nicht an der Idee: Dort steht die Tatsache, und sie
  kann nicht auseinanderlaufen.

  DIE IDEE BLEIBT STEHEN. Sie wird nicht verschoben und nicht geloescht
  -- wer nachsieht, was aus einem Gedanken geworden ist, soll den
  Gedanken noch finden, und daneben die Antwort.

  DIE AUFGABE WEISS, WOHER SIE KAM. `aus_eintrag_id` mit echtem
  Fremdschluessel, nicht als Text im Beschreibungsfeld. Ein Verweis, den
  nur ein Mensch lesen kann, ist kein Verweis. ON DELETE SET NULL, nicht
  CASCADE: Wird die Idee geloescht, bleibt die Arbeit.

NICHT AUS JEDEM BRETT

Aus einem Beitrag im Treff wird keine Aufgabe. Was jemand aus der
Community schreibt, gehoert ihm; daraus stillschweigend Arbeit zu
machen waere eine Verwendung, mit der er nicht rechnet. Welche Bretter
es sind, entscheidet der Server -- die Oberflaeche fragt nach, statt
eine zweite Liste zu fuehren.

WAS ABSICHTLICH NICHT MITWANDERT: die Frist. Eine Idee hat keinen
Termin; wer ihr beim Uebernehmen automatisch einen gaebe, erfaende ihn.
Die Dringlichkeit wandert dagegen mit -- dieselben drei Stufen.

ZUSTAENDIG IST, WER UEBERNIMMT, nicht wer die Idee aufgeschrieben hat.
Eine Aufgabe, die jemandem ohne sein Zutun zugeteilt wird, wird nicht
angefangen.

ZWEIMAL AM FALSCHEN ORT GELANDET

Der Knopf stand erst in `if (lage.team)`, dann immer noch innerhalb von
`if (treffBrett && lage)` -- also beide Male ausgerechnet am Treff und
an keinem Arbeitsbrett. Gefunden hat das beide Male die Pruefung im
Browser ("0 Knoepfe auf dem Ideenbrett"), nicht das Lesen. Jetzt steht
er in der allgemeinen Knopfreihe, hinter `darfEintragen()` -- eine
Uebernahme ist ein Schreibvorgang.

Und die Gegenprobe zur Brettliste lief anfangs ins Leere: Sie fragte
nach `BEREICHE[b].treff`, ein Merkmal, das es nicht gibt, und fand null
Treff-Bretter -- eine Gegenprobe, die nichts gegenprueft. TREFF_BRETTER
steht in workspace.js.

PRUEFUNGEN: pruef-uebernahme neu mit 39, davon 4 im Browser (der Klick
muss eine Aufgabe in der DATENBANK erzeugen, nicht nur eine Meldung).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 12:25:36 +02:00
DogFatherGitandClaude Opus 5 b9f261bbac Das Mindestalter wird eingeloest statt behauptet -- Stufe 8 ist damit durch
Auf der Regelseite des Treffs steht seit dem 11.09. "ab 18". Geprueft
wurde es nirgends: MINDESTALTER war ein Text auf einer Seite, sonst
nichts. Eine Regel, die nur dasteht, ist keine -- im Streitfall ist sie
sogar schlechter als keine, weil man sie versprochen hat.

DIE FRAGE STEHT AN DER TUER

Ein Community-Mitglied bestaetigt beim ERSTEN Hereinkommen, mindestens
18 zu sein. Danach nie wieder.

  An der Tuer und nicht auf einer Seite dahinter: Eine Sperre auf den
  Brettern liesse sich ueber eine andere Adresse umgehen und muesste
  auf jeder kuenftigen Seite mitgedacht werden. Die Tuer gibt es genau
  einmal.

  Ein EIGENER Fehler (400 alter_offen), nicht "ungueltig": Hier ist der
  Code richtig. Wer dieselbe Antwort bekaeme wie bei einem Tippfehler,
  tippte seinen Code immer wieder neu ein, und es wuerde nie besser.

  Und es zaehlt NICHT als Fehlversuch. Sonst sperrt sich jemand mit dem
  richtigen Code nach acht Anlaeufen selbst aus.

  Nur die Community: Wer zum Team gehoert, hat seinen Zugang von
  DogFather persoenlich bekommen -- da ist die Frage vorher geklaert.

NUR EIN ZEITSTEMPEL, KEIN GEBURTSDATUM

Gebraucht wird die Antwort auf "hat bestaetigt, und wann" -- nicht der
Geburtstag. Ein Geburtsdatum waeren mehr Daten fuer dieselbe Auskunft,
und Datenminimierung gilt auch fuer das eigene Nachweisbeduerfnis. Eine
Spalte, mehr nicht.

DIE RECHTSGRUNDLAGE FOLGT AUS DER ROLLE -- UND WIRD NICHT GESPEICHERT

Ein Modi arbeitet hier (Vertrag), ein Community-Mitglied ist freiwillig
da (Einwilligung). Was sich ableiten laesst, bekommt keine Spalte:
sonst gaebe es zwei Wahrheiten, von denen eine veraltet, sobald jemand
die Rolle wechselt. Sie steht jetzt in jeder Auskunft (Art. 15 Abs. 1
lit. a) und im Loeschkonzept.

MINDESTALTER ZIEHT INS IMPORTFREIE BLATT

Die Tuer braucht die Zahl jetzt auch, und ein Import zwischen
workspace.js und workspace-treff.js waere ein Kreis -- genau der Grund,
aus dem treff-tabellen.js existiert. Die Zahl steht weiterhin an EINER
Stelle; der Regeltext bekommt sie unveraendert.

EIN EIGENER FEHLER, GEFUNDEN VON DER PRUEFUNG

Ich hatte `export { MINDESTALTER } from "./treff-tabellen.js"` benutzt --
eine Durchreiche. Der Name ist damit fuer IMPORTEURE da, aber nicht in
der Datei selbst. Die Regelroute benutzt ihn selbst und lief in einen
ReferenceError, und zwar erst beim Aufruf. pruef-alter hat es gesehen,
nicht das Auge.

VIER PRUEFUNGEN MUSSTEN NACHZIEHEN

pruef-treff, pruef-treff-werkzeuge, pruef-auskunft und pruef-neue-seiten
melden sich als Community an. Sie schicken das Haekchen jetzt mit --
aber NUR fuer 'gast'. Ginge es immer mit, koennte keine Pruefung mehr
sehen, ob der Server es fuer das Team ueberhaupt ignoriert.

PRUEFUNGEN: pruef-alter neu mit 35, davon 7 im Browser. Darunter die,
die man vergisst: Wird beim ZWEITEN Mal wieder gefragt? (nein) -- denn
eine Abfrage, die jedes Mal kommt, wird weggeklickt, ohne gelesen zu
werden, und bestaetigt ab da nichts mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 01:09:52 +02:00
DogFatherGitandClaude Opus 5 6643e530a8 Auskunft auf Knopfdruck -- und die Quellenliste pflegt sich selbst
Zweite Haelfte von Stufe 8, Art. 15 DSGVO. Jeder Mensch hier darf
wissen, was ueber ihn gespeichert ist: DogFather, die rechte Hand,
jeder Modi, jede Creatorin -- und jedes Mitglied der Community.

DIE LISTE DER QUELLEN WIRD ABGELEITET, NICHT GEPFLEGT

Eine Auskunft, die eine Tabelle vergisst, ist schlimmer als keine: Sie
ist eine falsche Aussage ueber die Daten eines Menschen. Eine
handgeschriebene Liste "wo Personendaten liegen" waere in dem Moment
falsch, in dem jemand eine Tabelle dazubaut -- und genau diese Bauart
ist im Projekt schon dreimal schiefgegangen.

Deshalb fragt das Modul die Datenbank selbst: `PRAGMA foreign_key_list`
liefert jede Spalte, die auf `personen` zeigt. Gemessen: 62 Spalten in
38 von 42 Tabellen.

VIER SPALTEN ZEIGEN AUF ETWAS, OHNE ES ZU SAGEN

Es gibt genau vier Spalten im Haus, die auf `_id` enden und keinen
Fremdschluessel deklarieren:

  eintraege.saeule_id          keine Person
  treff_entfernt.eintrag_id    keine Person
  protokoll.person_id          IST eine Person
  treff_entfernt.autor_id      IST eine Person

Beide Personenspalten haben denselben Grund, keinen Fremdschluessel zu
haben: Sie sollen eine geloeschte Person ueberdauern. Sie stehen
namentlich im Modul -- und pruef-auskunft schlaegt an, sobald eine
fuenfte dazukommt, die niemand eingeordnet hat. Die Liste ist damit
klein genug, um richtig zu sein, und kann nicht heimlich veralten.

ZWEI DINGE STEHEN NIE DRIN

  Zugangsgeheimnisse (Hash, Salt, Kennung) -- Risiko ohne Nutzen.
  Andere Menschen -- wer eine Massnahme gesetzt hat, ist dessen Datum,
  nicht meines. Eine Regel fuer alle Tabellen, keine Ausnahmeliste:
  Steht in einer Zeile ueber mich die Nummer eines anderen, wird daraus
  "eine andere Person". Meine eigene bleibt stehen, sonst waere die
  Auskunft unbrauchbar -- und genau das ist die Gegenprobe dazu.

DER KNOPF STEHT AUF ZWEI SEITEN

Steckbrief und Treff-Regeln -- die beiden Seiten, die einem Menschen
selbst gehoeren. Die Community hat keinen Steckbrief; ohne die zweite
Stelle haette ausgerechnet die groesste Gruppe mit den wenigsten
Rechten auch dieses nicht. Die Pruefung liest das aus der Rechtetafel
nach, statt es zu behaupten.

Die Datei entsteht im Browser aus der Antwort -- es bleibt also nichts
auf dem Server liegen. Wer ueber wen Auskunft gezogen hat, steht im
Protokoll: Eine vollstaendige Sammlung der Daten eines Menschen ist das
Empfindlichste, was dieses Haus herausgibt.

NEBENBEI GEFUNDEN

Ich hatte `.block__kopf` und `.block__frage` geliehen -- die stehen in
automation.css, und keine der beiden Seiten laedt die. Der Kasten waere
ohne Abstaende dagestanden. Gefunden von pruef-css-klassen, nicht vom
Auge. Jetzt eigene Klassen in start.css.

PRUEFUNGEN: pruef-auskunft neu mit 46.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 01:00:11 +02:00
DogFatherGitandClaude Opus 5 e975983ad1 Das Loeschkonzept ist kein Dokument, sondern eine Tabelle, die sich durchsetzt
Stufe 8 aus dem Plan zur Perfektion: "Loeschkonzept je Datenart ·
IP-Adressen im Protokoll nach 30 Tagen weg. Je mehr Daten, desto teurer
das Nachholen."

WARUM NICHT ALS NOTIZ

Ein Loeschkonzept als Dokument ist nach dem ersten neuen Feld falsch,
und niemand merkt es. workspace-aufbewahrung.js ist beides: die
Uebersicht, was wie lange aufgehoben wird -- UND das Programm, das es
tut. Was dort nicht steht, wird nicht geraeumt; was dort steht, wird
geraeumt.

GEMESSEN, BEVOR ETWAS GEBAUT WURDE

42 Tabellen durchgesehen. Drei halten IP-Adressen:

  versuche.ip    wird beim Anmelden im Fenster geraeumt        ok
  sitzungen.ip   nur beim Abmelden -- ABGELAUFENE Sitzungen
                 standen ewig da, samt IP und Browser          Luecke
  protokoll.ip   wurde nirgends geraeumt, wuchs ewig           Luecke

Zwei echte Luecken also, nicht fuenf vermutete.

DREI SORTEN EINTRAG, UND DIE DRITTE IST DIE WICHTIGSTE

  raeumen   Diese Datei loescht selbst.
  fremd     Eine andere Stelle loescht -- hier wird nur GEZAEHLT.
            Bricht die andere Stelle, steht die Zahl trotzdem da.
  bleibt    Wird absichtlich aufgehoben, mit Begruendung.

Ein Loeschkonzept, das nur Loeschungen auffuehrt, ist ein halbes: Die
begruendete Aufbewahrung ist der Teil, nach dem gefragt wird. Jede
Zeile nennt Frist, Zweck, Rechtsgrundlage und Wirkung.

SICHTBAR, NICHT NUR WIRKSAM

Auf automation.html -- dort steht alles, was ohne Zutun laeuft, und
genau das ist es. Bei jeder Zeile die Zahl, wie viele Datensaetze sie
gerade betrifft, und ein Knopf "Jetzt aufraeumen", damit es kein
schwarzer Kasten ist. Die Sorte steht als WORT daneben, nicht nur als
Farbe.

BEI ETWAS, DAS LOESCHT, IST DIE WICHTIGERE HAELFTE: WAS ES NICHT LOESCHT

Zu jeder Loeschung eine Gegenprobe:

  IP nach 30 Tagen weg        -> und die von vor 29 Tagen bleibt
  IP weg                      -> und die ZEILE bleibt (nur das Feld)
  abgelaufene Sitzung weg     -> und die gueltige bleibt
  abgelaufene Sitzung weg     -> und ich bin danach noch angemeldet

Die letzte ist die unbequemste und die wichtigste: Ein Aufraeumlauf,
der die eigene Anmeldung mitnimmt, wirft im Betrieb alle hinaus -- und
zwar einmal taeglich. Dazu: ein zweiter Lauf muss NICHTS mehr finden
(sonst waere "aufgeraeumt" nicht von "nichts getan" zu unterscheiden),
und eine Zaehlung ueber eine fehlende Tabelle ergibt `null`, nicht 0.

NEBENBEI: EINE EIGENE DOPPLUNG VON GESTERN

Drei der Seitenerklaerungen sagten in "Wofuer" und "Du tust" fast
dasselbe (report 80 %, treff-regeln 67 %, startcheck 50 %). Gestern
hatte ich nur den Fall geprueft, an dem ich mich verbrannt hatte --
"Wofuer" gegen die Unterzeile -- und die naheliegendere Dopplung
uebersehen. Jetzt gemessen, schlechtester Wert 25 %.

PRUEFUNGEN: pruef-aufbewahrung neu mit 41, davon 7 im Browser
(der Knopf muss eine Zahl wirklich fallen lassen, und die IP muss
danach in der Datenbank weg sein). pruef-erklaerung 44 -> 47.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 00:36:57 +02:00
DogFatherGitandClaude Opus 5 4571b15494 Die Wochenzahlen erklaeren sich -- und die Zeitraum-Karte bekommt eine Rangfolge
Zwei Bildschirmfotos, zwei Sachen.

1) "wieso werden die zahlen oben nicht ausgefuellt von der excel datei?"

Weil kein einziger Tag erfasst ist -- die Backstage-Ausgabe enthielt
einen Zeitraum, und aus einer Summe ueber dreizehn Tage laesst sich
nicht ablesen, wie ein einzelner Tag lief.

Das stand nirgends. Stattdessen standen dort sieben Karten mit "0" und
"wie in der Vorwoche": Das sieht aus wie ein Fehler, und die Frage
entsteht genau an dieser Stelle. Also steht die Antwort jetzt auch
dort -- nicht in einer Notiz, nicht in einem Hilfetext.

UND SIE NENNT DEN WEG, nicht nur den Grund: "In Backstage den Zeitraum
auf EINEN Tag stellen, herunterladen, hier einlesen -- je Tag einmal."
Ein Hinweis ohne Ausweg ist eine Sackgasse mit Erklaerung.

Sobald EIN Tag da ist, verschwindet der Kasten und die Karten kommen
zurueck. Genau das ist die Gegenprobe; ohne sie hiesse alles andere
nur, dass die Karten jetzt immer weg sind.

2) "das muss viel geiler aussehen und viel klarer."

Er hatte recht: Die erste Fassung war eine Liste ohne Rangfolge --
Spanne, Diamanten, LIVE, Follower, alles gleich gross, nichts sprang
heraus. Wer draufschaut, will ZWEI Dinge in einer halben Sekunde
wissen: WELCHER Zeitraum und WIE VIELE Diamanten.

Jetzt: die Spanne als Ueberschrift, die Zahl der Tage als Marke
daneben, die Diamanten gross mit dem Schnitt direkt darunter, alles
Uebrige unter einem Strich. Links eine Kante in der Hausfarbe -- sie
sagt "andere Sorte Zahl", ohne dass ein Wort dafuer noetig waere. Das
ist wichtig: Wer einen Zeitraum fuer einen Tageswert haelt, rechnet mit
ihm weiter.

GEMESSEN IN PIXELN, NICHT NACH GEFUEHL: Die Hauptzahl muss mindestens
1,6-mal so gross sein wie ein Nebenwert (gemessen: 30 px zu 15 px),
sonst ist es wieder eine Liste. Eine Pruefung, die "sieht gut aus"
sagt, sagt nichts.

pruef-backstage-import 118 -> 127. Der leere Zustand wird HERGESTELLT
und nicht abgewartet -- eine Pruefung, die auf einen Zustand hofft,
prueft irgendwann gar nichts mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 20:05:06 +02:00
DogFatherGitandClaude Opus 5 0d3a4b78cd Zwei Befunde aus dem Handy-Lauf -- und eine Regel, die ihre eigene Ausnahme nicht kannte
Filipe hat die beiden breiten Sichtpruefungen freigegeben. pruef-handy
meldete vier Fehlschlaege, pruef-lesbarkeit war gruen.

BEIDE BEFUNDE WAREN NICHT VON MEINER AENDERUNG -- gemessen, nicht
vermutet: crew-index.html laedt weder kopf.js noch erklaerung.js, und
mein Commit hat dort nur die Versionsnummer angefasst. Die betroffene
Regel steht seit dem 27.08.2026 so da.

1. ZU KLEINE SCHRIFT AUF DER ZUGANGSWAND VON TEAM DOGI

   `.marke` stand auf schmalen Bildschirmen auf .68rem = 10,88 px und
   damit unter der Hausuntergrenze von 11,5 px -- betroffen waren die
   Woerter "DogFather" und "Team Dogi". Das ist die erste Seite, die ein
   neuer Modi ueberhaupt sieht, und sie wird mit dem Daumen bedient.
   Jetzt .72rem = 11,52 px, dieselbe Hebung wie seinerzeit in heim.css.

   Die Grundlinie in pruef-css-klassen wird MITGEZOGEN (43 -> 42):
   Sonst duerfte der Fortschritt lautlos wieder verlorengehen, und eine
   Grundlinie, die nur nach oben nachgibt, ist keine.

2. DIE BERUEHRZIEL-REGEL ZITIERTE WCAG 2.5.8, ABER NICHT IHRE AUSNAHME

   Gemeldet wurden die zwei Verweise im Fliesstext der Treff-Regeln
   ("Der Treff", "Regeln & Hilfe", je 20 px hoch). 2.5.8 nimmt genau das
   aber ausdruecklich aus: "Inline: The target is in a sentence or its
   size is otherwise constrained by the line-height of non-target text."

   Sie auf 24 px zu bringen hiesse, die Zeilenhoehe eines Absatzes zu
   sprengen -- also einen Text kaputtzumachen, um eine Regel zu
   erfuellen, die diesen Text gar nicht meint. Die Ausnahme ist eng
   gefasst: nur <a>, nur wirklich inline, und nur wenn im selben Absatz
   auch Text steht, der nicht zum Link gehoert. Ein allein stehender
   Link bleibt ein Beruehrziel.

   UND DIESE DATEI HATTE BIS HEUTE GAR KEINE GEGENPROBE. Sie konnte
   also nie zeigen, dass sie ein zu kleines Ziel ueberhaupt bemerkt --
   erst recht nicht, seit die Regel eine Ausnahme hat. Jetzt in beide
   Richtungen: ein allein stehendes 20x20-Ziel MUSS auffallen, ein
   gleich grosser Verweis im Satz darf es NICHT.

PRUEFUNGEN: pruef-handy 136 -> 138 (vier Fehlschlaege behoben, zwei
Gegenproben dazu), keine einzige weniger. pruef-lesbarkeit gruen
(12 s). pruef-css-klassen, pruef-erklaerung und pruef-neue-seiten nach
der gate.css-Aenderung noch einmal gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 19:49:41 +02:00
DogFatherGitandClaude Opus 5 de19684883 Jede Seite erklaert sich selbst -- drei Zeilen, und die dritte rechnet sich aus
Filipe: "ich will in jeder seite auch eine kleine detaillierte aber
schnelle erklaerung kurz und knapps noch zu jeder seite."

DREI ZEILEN AUF JEDER DER 25 SEITEN

  WOFUER    was auf dieser Seite steht
  DU TUST   was man hier konkret macht
  MERKE     nur dort, wo es etwas gibt, das man falsch versteht
  SIEHT     wer diese Seite ueberhaupt oeffnen kann

Offen sichtbar und nicht hinter einem Aufklapper: "schnell" war seine
Bedingung, und eine Erklaerung, die man erst aufklappen muss, ist
genau dann nicht da, wenn man sie braucht.

DIE ZEILE "SIEHT" IST GERECHNET, NICHT GESCHRIEBEN

Sie kommt aus der Rechtetafel -- aus derselben, aus der auch die
Schranke ihre Entscheidung holt. Haette ich sie danebengeschrieben,
waere sie beim ersten Umstellen in "Wer sieht was" still falsch
geworden, in einem Satz, der behauptet, wer etwas sieht. Die Pruefung
stellt die Tafel deshalb wirklich um und sieht nach, ob der Satz
mitwandert.

Die Erklaerung haengt hinter derselben Schranke wie die Seite: Wer sie
nicht oeffnen darf, bekommt 404 -- nicht 403, sonst waere dieser Weg
eine Landkarte des Hauses.

Eingebunden ist sie nicht ueber eine Liste von Dateinamen, sondern
ueber "wer kopf.js laedt": die 26. Seite ist damit automatisch dabei.
Fuenf Seiten haben keine Kopfzeile (Chat, Kalender, Start, Team,
Teamlage) -- dort haengt der Kasten an <main>, sonst waeren
ausgerechnet die haeufigsten Seiten lautlos leer geblieben.

ZWEI EIGENE MAENGEL, GEFUNDEN DURCH HINSEHEN, NICHT DURCH DIE PRUEFUNG

Die erste Fassung war gruen -- und stand mitten auf dem Buehnenbild,
mit einem Lichtfleck hinter "SIEHT". Und "Wofuer" sprach fast woertlich
die Unterzeile darueber nach. Beides misst die Pruefung jetzt: Kontrast
mit dem dritten Ausgang ("steht auf der Buehne" ist kein Ergebnis) und
die Wortueberschneidung mit der Unterzeile.

ZWEI BEFUNDE, DIE SCHON VORHER ROT WAREN

1. pruef-tempo-workspace verglich die UNKOMPRIMIERTE Groesse gegen eine
   Grenze, die fuer die Leitung gedacht war -- waehrend der Kommentar
   daneben "das ist, was wirklich ueber die Leitung ging" behauptete.
   Live steht Caddy davor. Nachgemessen an der echten Adresse:
   start.css 345 KB -> 111 KB zstd. Die Pruefung wog also 1,2 MB, wo
   Filipe 500 KB bekommt. Jetzt wird Komprimierbares im Pruefstand
   gzip-gepackt (115 KB gegen 111 KB live -- auf vier Prozent genau),
   geurteilt wird ueber die uebertragene Groesse, berichtet werden
   beide. Dabei prompt in die dokumentierte Falle getappt: `body()` auf
   einen Ereignisstrom endet nie, der Lauf blieb stehen. Jetzt
   ausgenommen, plus Notbremse je Koerper.

2. pruef-ueberlappung konnte seit Tagen nicht mehr zeigen, dass sie
   eine Ueberlappung ueberhaupt findet: Ihre Gegenprobe legt einen Knopf
   auf einen anderen, traf aber 6 px daneben. Zwei Ursachen in einer
   Zeile -- `position: fixed` bezieht sich auf einen Vorfahren mit
   `transform`, und die `transition` der Knoepfe liefert beim sofortigen
   Messen die Lage von vorher. Jetzt `transform` + `transition: none`:
   34x36 px erkannt, 20 Seiten-Breiten-Paare, 0 Befunde.

PRUEFUNGEN: pruef-erklaerung neu mit 44, davon 8 im Browser (Seite mit
und ohne Kopfzeile, Handy, Kontrast, Echo). Mein Schild stand auf
10,88 px und lag unter der Hausgrenze von 11,5 -- gefunden von
pruef-css-klassen, nicht vom Auge.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 18:20:30 +02:00
DogFatherGitandClaude Opus 5 0cce22c08c Der Einzel-Import kennt den dritten Ausgang jetzt auch
Nach dem Umbau von heute Nachmittag habe ich nachgesehen, WER
tagAusZelle() sonst noch ruft -- und genau dort die naechste Luecke
gefunden, bevor sie jemanden getroffen hat.

DIE FUNKTION HAT SEIT HEUTE DREI AUSGAENGE (Tag, Zeitraum, Grund).
Gekannt hat den dritten nur der Backstage-Weg. Im Einzel-Import stand
weiterhin `gelesen.tag` -- bei einem Zeitraum `undefined`:

  VORSCHAU:    `undefined > heute` ist false, die Zeile faellt durch
               und landet mit `tag: undefined` in der Liste.
  SCHREIBWEG:  `if (!tag)` greift, die Zeile wird still uebersprungen.

Die Vorschau haette also eine Zeile versprochen, die danach nirgends
steht. Zwei Aussagen ueber dieselbe Datei, die einander widersprechen,
und beide sehen fuer sich plausibel aus -- das ist der Unterschied, den
niemand bemerkt.

Das ist an diesem Tag die FUENFTE Wiederholung derselben Sache: eine
Regel, mehrere Aufrufer, und einer kennt sie nicht. Ein dritter Ausgang
taugt nur, wenn ihn ALLE Aufrufer kennen.

Jetzt legt auch der Einzel-Import einen Zeitraum in leistung_zeitraum
ab -- dieselbe Tabelle, dieselbe Regel, dieselbe Anzeige. Und die
Dauer-Einheit gilt dort ebenfalls; sie fehlte in der Vorschau noch.

DIE MELDUNG SAGT JETZT, WAS ANGEKOMMEN IST: "1 Zeitraum uebernommen"
statt "1 Tage uebernommen". Bei einer Backstage-Ausgabe ueber zwei
Wochen haette man sie sonst in der Tagesliste gesucht und nicht
gefunden.

pruef-backstage-import 106 -> 118. Die Pruefung, auf die es ankommt,
vergleicht VORSCHAU UND ERGEBNIS: Was die Vorschau verspricht, muss
danach dastehen -- genau die Aussage, die vorher falsch gewesen waere.
Dazu, dass in der Vorschau die Spanne steht und kein leerer Tag, und
die Gegenprobe, dass eine echte Tagesdatei weiterhin als Tage durchgeht.

ZWEI EIGENE FEHLER DABEI: Ich habe `.length` auf eine Zahl angewendet
(`fehlerhaft` ist eine Anzahl, keine Liste) -- immer `undefined`, immer
rot. Und zum zweiten Mal heute den Absolutwert gemessen, wo die
Veraenderung gehoert: Lumi hatte aus einem frueheren Teil der Pruefung
schon eine Tageszeile in derselben Spanne.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 16:34:42 +02:00
DogFatherGitandClaude Opus 5 e82bf45f0d Ein Zeitraum geht jetzt durch -- als Zeitraum, nicht als Tag
Filipe: "verbesser das, also ich will dass das auch so geht, mach dass
es funktioniert, ich will es so einfach und perfekt wie moeglich. also
sieh zu dass die excel auch so durch geht."

Backstage gibt eine Ausgabe fuer einen ZEITRAUM heraus --
"2026-09-01 ~ 2026-09-13", eine Zeile je Creator, alle Zahlen
aufsummiert. Am Vormittag wurde so eine Zeile abgewiesen. Jetzt geht
sie durch.

DREI WEGE WAEREN MOEGLICH GEWESEN, ZWEI DAVON WAEREN
ZAHLENFAELSCHUNG:
  * auf den ersten Tag schreiben -> dreizehn Tage auf einem Tag; die
    Zahl steht da, sie ist gross, sie sieht richtig aus, und niemand
    kann spaeter sagen, was darin steckt;
  * gleichmaessig verteilen -> erfundene Tage, die es nie gab.
Der dritte ist dieser: den Zeitraum ALS Zeitraum ablegen. Was drinsteht,
ist dann wahr -- und was er nicht sagt (welcher Tag wie lief),
behauptet er auch nicht.

EIGENE TABELLE UND NICHT EIN FELD IN `leistung`: Dort ist der
Schluessel (creator, tag). Ein Zeitraum ab dem 1. September wuerde mit
dem ECHTEN 1. September zusammenstossen, und eine der beiden Zahlen
waere weg. Getrennt kann keines das andere ueberschreiben -- und die
Wochenzahlen bleiben, was sie sind: aus Tagen gerechnet.

Der Schluessel ist (creator, von, bis): Dieselbe Datei zweimal
einzulesen ersetzt denselben Zeitraum, statt ihn zu verdoppeln.

AUF DER SEITE steht ein eigener Block zwischen Woche und Tageszeilen:
die Spanne vorn, die Zahl der Tage als Marke daneben, die Werte
darunter. Dazu EINE Umrechnung, und nur diese: "Ø 4.129 Diamanten pro
Tag" -- als Durchschnitt bezeichnet, nirgends gespeichert. Wer eine
Woche vergleichen will, braucht sie; wer sie fuer einen echten Tag
haelt, hat das Wort nicht gelesen. Darueber steht woertlich, dass diese
Zahlen nicht in die Wochenzahlen eingehen.

MIT DER ECHTEN DATEI GEMESSEN: alle 8 Zeilen gehen durch, 8 als
Zeitraum, 0 abgelehnt. Spanne 01.09.-11.09. = 11 Tage, Diamanten
53.679, Dauer 5171 Minuten.

pruef-backstage-import 86 -> 106. Die Pruefung, auf die es ankommt, ist
nicht "es wird gespeichert", sondern "es wird NICHT in die Woche
gemischt": kein Tag kommt hinzu, die Wochenzahl bleibt Ziffer fuer
Ziffer dieselbe. Dazu die Gegenprobe, dass ein Zeitraum von EINEM Tag
weiterhin ein Tag bleibt -- sonst hiesse alles andere nur, dass jetzt
alles als Zeitraum abgelegt wird.

DREI PRUEFUNGEN GEDREHT, KEINE GELOESCHT: Zwei behaupteten noch die
Ablehnung vom Vormittag. Und tagAusZelle() hat jetzt DREI Ausgaenge
statt zwei (Tag, Zeitraum, Grund) -- geprueft wird, dass nie zwei davon
gleichzeitig kommen. Gaebe es zwei, entschiede jeder Aufrufer selbst,
was Vorrang hat, und der zweite entschiede anders als der erste. Genau
daran ist heute frueh der Zeitraum-Schutz gescheitert.

ZWEI EIGENE MESSFEHLER, beide von der Pruefung gefunden: Ich verlangte
"kein einziger Tag in der Spanne" und uebersah, dass weiter oben schon
ein Tag geschrieben worden war, der hineinfaellt -- gemessen wird jetzt
die VERAENDERUNG. Und ich mass den Zeitraum-Block, waehrend ein anderer
Creator geoeffnet war: keine Frage an die Seite, sondern an die falsche
Person.

Nebenbei zum zweiten Mal heute: eine Versalzeile mit 10,88 px. Auf
.72rem angehoben, bevor pruef-css-klassen sie findet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 16:23:16 +02:00
DogFatherGitandClaude Opus 5 0207b05da6 Die Rechte Hand steht ueber den Modis -- sortiert statt geschrieben
Filipe, mit dem Bildschirmfoto: "rechte hand soll immer ueber modi
stehen bitte."

DIE REIHENFOLGE STAND AN ZWEI STELLEN, und die zweite war falsch
herum: ROLLEN_REIHE hatte die Rechte Hand laengst vor den Modis (und
die SQL-Sortierung leitet sich daraus ab) -- aber `zusatzrollen` in
workspace-personen.js schrieb sie von Hand, und dort kam Modi zuerst.
Genau diese Liste baut die Abschnitte auf der Personenseite und die
zusaetzlichen Knoepfe im Anlegen-Formular.

Das ist an diesem Tag das VIERTE Mal dieselbe Sache: eine Aussage,
zwei Listen, und die zweite ist die, die abweicht. Vorher: der
Zeitraum-Schutz (an einer von drei Stellen), die Dauer-Einheit
(dieselbe), das Recht zum Aufloesen (Liste kannte es, Nachrichtenweg
nicht).

Deshalb wird jetzt SORTIERT und nicht geschrieben: Die Liste geht durch
ROLLEN_REIHE. Wer die Reihenfolge aendern will, aendert sie dort --
und alles andere zieht nach, statt nachgezogen werden zu muessen. Was
in ROLLEN_REIHE nicht vorkommt (heute "gast"/Community), wandert ans
Ende statt stillschweigend nach vorn.

pruef-haus-trennung 63 -> 66. GEPRUEFT WIRD DIE REIHENFOLGE, NICHT DIE
ANWESENHEIT: "beide sind da" waere auch dann gruen gewesen, wenn sie
vertauscht sind -- und genau das war der Fall. Dazu eine Zeile, die
nachweist, dass die Reihenfolge wirklich aus ROLLEN_REIHE kommt und
nicht nur zufaellig stimmt; sonst haette jemand sie auch von Hand
andersherum schreiben koennen: richtig im Ergebnis, falsch im Aufbau,
und beim naechsten Mal wieder auseinander.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 14:28:06 +02:00
DogFatherGitandClaude Opus 5 9f277435a5 Reaktionen: Vorschlaege, ganzer Katalog, eigene Favoriten
Filipe: "soll viel besser und geiler sein und man soll auch auswaehlen
koennen, also paar als vorschlaege mit der moeglichkeit andere
auszuwaehlen und als favoriten zu speichern."

Aus einem Streifen mit sechs Zeichen ist eine Karte geworden:
Vorschlaege oben, Suchfeld, darunter der Katalog in sechs Gruppen --
82 Zeichen, jedes mit deutschen Suchwoertern. Wer "feuer" tippt, muss
nicht scrollen.

DREI LISTEN, DREI FRAGEN, und sie werden gern verwechselt:
  KATALOG    Was gibt es?              fest, workspace-reaktionen.js
  VORSCHLAG  Was steht vorn, solange   fest -- bis jemand eigene
             ich nichts gewaehlt habe? Favoriten hat
  FAVORITEN  Was hat DIESER Mensch     in der Datenbank
             sich gemerkt?

Nur der Katalog entscheidet, was ANGENOMMEN wird. Vorschlag und
Favoriten sind Reihenfolge, keine Erlaubnis -- sonst koennte man sich
ueber einen Favoriten etwas erlauben, das im Katalog nicht steht. Die
erlaubte Menge wird aus dem Katalog ABGELEITET; eine zweite Liste
daneben waere die, in der ein Zeichen fehlt, das die Oberflaeche
anbietet.

FAVORITEN HAENGEN AM MENSCHEN, NICHT AM GERAET. Im Browser abgelegt
waeren sie am Handy andere als am Rechner und beim naechsten Loeschen
der Seitendaten weg.

DER STERN SCHALTET EINEN MODUS, statt an jedem Zeichen einen zweiten
Knopf zu haben: Am Handy gibt es kein "daneben zeigen". Im Merk-Modus
faerbt sich die ganze Tafel, damit niemand reagiert, wenn er merken
wollte. Die Tafel bleibt dabei offen -- acht Favoriten waeren sonst
acht Mal Aufmachen -- und die Vorschlagszeile aendert sich sofort mit.

DIE GRENZE SAGT BESCHEID, statt still den aeltesten wegzuwerfen: Wer
einen neunten merken will, bekommt "nimm erst einen weg". Ein Favorit,
der ohne Ansage verschwindet, sieht wie ein Fehler aus.

Eine Selbstpruefung beim Laden meldet doppelte Zeichen im Katalog und
Vorschlaege, die nicht darin stehen -- beides waere in der Tafel still.

pruef-chat-aufloesen 85 -> 115. Gemessen wird, was PASSIERT, nicht dass
es Elemente gibt: dass die Suche wirklich eingrenzt (1 statt 82) und
das Richtige findet, dass ein Fehlgriff "Nichts zu ... gefunden" sagt
statt eine leere Flaeche zu zeigen, und vor allem, dass im Merk-Modus
KEINE Reaktion entsteht -- an der Zahl der Reaktionen gemessen, nicht
an der Absicht.

NEBENBEFUND AUS DER EIGENEN PRUEFUNG: pruef-css-klassen hat meine
Gruppenueberschrift mit 10,56 px abgelehnt (Grenze 11,5). Richtig so --
eine gesperrte Versalzeile ist ohnehin schwerer zu lesen, die darf
nicht auch noch die kleinste sein. Auf .72rem angehoben, statt die
Grundlinie zu verschieben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 14:04:57 +02:00
DogFatherGitandClaude Opus 5 47269bda21 Chat: auf eine Nachricht reagieren, ohne zu antworten
Filipe: "ich will dass man auf die nachrichten auch reagieren kann mit
einem emoji, die nachricht selbst ohne zu antworten."

Neben "antworten" steht jetzt "reagieren". Ein Klick klappt sechs
Zeichen auf, ein zweiter Klick setzt es -- und unter der Nachricht
steht, wer mit was reagiert hat.

EINE FESTE AUSWAHL, KEIN FREIES FELD (👍 ❤️ 😂 😮 🔥 🙏). Drei Gruende,
der erste ist der wichtigste: Eine feste Liste laesst sich pruefen --
was dort nicht drinsteht, kommt nicht in die Datenbank, kein beliebiger
Text, keine 4-KB-Zeichenketten. Zweitens sehen alle dasselbe. Drittens
kann man sechs Zeichen ueberfliegen; eine volle Tafel ist eine
Suchaufgabe, und dann tippt man doch wieder "ok".

DIE LISTE STEHT AUF DEM SERVER und wird an die Oberflaeche geliefert.
Stuende sie im Browser, gaebe es sie zweimal -- und die zweite Fassung
waere die, in der ein Zeichen fehlt, das der Server noch annimmt. Faellt
der Abruf aus, erscheint KEINE Auswahl statt einer mit erfundenen
Zeichen.

DER PRIMAERSCHLUESSEL BEANTWORTET "WIE OFT?": (nachricht, person,
zeichen). Eine Person darf verschiedene Zeichen geben, jedes aber nur
einmal -- und zwar durchgesetzt von der Datenbank, nicht von einer
Abfrage davor, die man vergessen kann. Derselbe Klick noch einmal nimmt
es zurueck; das erspart einen zweiten Weg, den man auch absichern
muesste.

KEIN ZAEHLER IN chat_nachrichten. Eine mitgefuehrte Zahl muesste bei
jedem Hin und Her stimmen und ist genau die Art Angabe, die irgendwann
nicht mehr stimmt und die niemand nachrechnet. Gezaehlt wird beim
Lesen -- in EINER Abfrage fuer alle 200 Nachrichten, nicht je Zeile
eine.

WER ES WAR, STEHT IM TITEL. "Drei Daumen" sagt weniger als "Ayla, Ben
und Cem", und es sind Leute aus demselben Raum.

KEINE BENACHRICHTIGUNG AUFS HANDY. Wer im Raum ist, sieht es sofort;
wer nicht, bekommt nichts. Ein Daumen ist keine Nachricht -- wer dafuer
geweckt wird, schaltet Meldungen ab.

Was NICHT geht: wer nicht im Raum ist (404), ein erfundenes Zeichen
(400), eine zurueckgenommene Nachricht (409). Und mit der Nachricht
verschwinden die Reaktionen (CASCADE).

pruef-chat-aufloesen 59 -> 85. Gemessen wird der BESTAND, nicht die
Antwort -- und im Browser der KNOPF, nicht nur das Recht: dass die
Auswahl aufklappt, sich nach dem Klick von selbst schliesst, die
Reaktion darunter erscheint, als die eigene erkennbar ist und ein Klick
darauf sie wieder wegnimmt.

EINE EIGENE PRUEFUNG WAR ZU SCHWACH: "bei Cem ist ueberall selbst=true"
war trivial wahr, weil es nur EINE Sorte gab. Jetzt bekommt eine andere
Person ein drittes Zeichen, und in derselben Antwort muss eines auf
true und eines auf false stehen. Eine Angabe, die nie `false` sein kann,
sagt nichts.

Im CSS keine vierte Abschrift: "reagieren" haengt an derselben Regel
wie "antworten" -- neben anheften und kopieren waere es die vierte fast
gleiche gewesen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 13:46:31 +02:00
DogFatherGitandClaude Opus 5 6ed61a6b3d Die Zeitraum-Regel galt nur an einer Stelle -- Filipe fand die andere
"jetzt hab ich eine hochgeladen ber sehe sie nicht."

WAS PASSIERT IST, aus der Datenbank gelesen und nicht vermutet: Seine
Backstage-Ausgabe lief durch den EINZEL-Import ("Aus Datei einlesen")
und schrieb genau eine Zeile -- creator_id 2, Tag 2026-09-01, alle
Werte 0, Quelle "import", erfasst 11:52. Unsichtbar war sie aus zwei
Gruenden: Der 1. September liegt 13 Tage zurueck (die Liste zeigt
sieben), und es stand nichts darin.

DREI FEHLER AUF EINMAL, und alle drei waren meine:

1. DER ZEITRAUM-SCHUTZ STAND NUR IM BACKSTAGE-WEG. Ich hatte ihn heute
   frueh gebaut, gemessen, geprueft -- und an genau einer von drei
   Stellen eingesetzt. "2026-09-01 ~ 2026-09-11" wurde im Einzel-Import
   weiterhin zum 1. September.

   Das ist an diesem Tag das DRITTE Mal dieselbe Sache: eine Regel,
   zweimal aufgeschrieben, und die zweite Abschrift ist die
   unvollstaendige. Jetzt steht sie EINMAL in `tagAusZelle()` und wird
   dreimal benutzt. Sie liefert immer genau eines von beidem: Tag oder
   Grund -- nie beides, nie keines.

2. DIE DAUER-EINHEIT FEHLTE DORT EBENFALLS. Auch das hatte ich nur im
   Backstage-Weg eingesetzt.

3. DIE DATEI GEHOERTE GAR NICHT DORTHIN. Sie enthaelt ALLE
   Creator:innen; der Einzel-Import schreibt auf EINE Person. Es gab
   keine Fehlermeldung -- es passierte nur nichts Sichtbares, und das
   ist die schlechteste aller Antworten.

   Jetzt erkennt der Weg eine Namensspalte mit mehreren verschiedenen
   Eintraegen und sagt: "In dieser Datei stehen 3 verschiedene Creator
   (Spalte ...). Dieser Weg schreibt auf EINE Person. Nimm
   'Backstage-Tabelle einfuegen'." Mit Gegenprobe, dass eine Datei mit
   EINEM Creator weiterhin durchgeht.

pruef-xlsx 60 -> 67, pruef-backstage-import 82 -> 86.

NEBENBEFUND AUS DER EIGENEN PRUEFUNG: Mein Testfile fuer den
Einzel-Import hatte selbst zwei verschiedene Creator -- die neue Sperre
hat es sofort abgewiesen. Das war ihr erster echter Treffer, und es
zeigt, dass ich den Weg beim Schreiben der Pruefung selbst falsch
verstanden hatte. Jetzt steht dort, wofuer er da ist: eine Person,
mehrere Tage.

Die Zeile vom 1. September steht noch in der Datenbank. Sie zu
entfernen ist Filipes Entscheidung, nicht meine.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 12:01:49 +02:00
DogFatherGitandClaude Opus 5 58932ece8c Excel-Dateien werden gelesen -- und drei Fallen dahinter entschaerft
Filipe: "mach doch bitte so dass man alle dateien hoch laden könne auch
excel dateien. gib gas und krieg das hin."

server/workspace-xlsx.js liest .xlsx mit Bordmitteln: Eine .xlsx ist ein
ZIP mit XML darin, und Node kann beides (`zlib.inflateRawSync`). Kein
zusaetzliches Paket fuer eine Datei mit neun Zeilen.

GEMESSEN AN ZWEI ECHTEN BACKSTAGE-AUSGABEN vom 11. und 12.09.2026, die
auf dem Rechner lagen -- nicht an der Dokumentation. Sie haben mir an
drei Stellen widersprochen, und JEDE davon waere sonst ein stiller
Fehler geworden:

1. DER ZEITRAUM. In "Datenzeitraum" steht `2026-09-01 ~ 2026-09-11`.
   `datumLesen` griff sich davon den ersten Tag -- elf Tage Diamanten
   waeren auf den 1. September gebucht worden. Die Zahl steht da, sie
   ist gross, sie sieht richtig aus, und niemand kann spaeter sagen,
   dass elf Tage darin stecken. Neu: `zeitraumLesen`; eine Zeile mit
   einem Zeitraum ueber mehrere Tage wird abgelehnt UND begruendet
   ("Stell in Backstage den Zeitraum auf EINEN Tag"). Ein Zeitraum von
   einem Tag geht durch.

2. DIE EINHEIT. "LIVE-Dauer" enthaelt `86Std. 10Min. 52Sek.`.
   `zahlLesen` ergab daraus `null` -- die Dauer fiel weg. Bei einem
   anderen Trennzeichen waere es schlimmer gewesen: 86 statt 5171,
   Faktor 60 daneben und plausibel. Neu: `dauerLesen`, versteht die
   deutsche und englische Schreibweise, die Uhrzeitform und weiterhin
   die blosse Zahl.

3. DIE DATUMSSPALTE. `/datum|date|tag|day/i` erklaerte "Tage seit dem
   Beitritt" zur Datumsspalte (Wert "65") und traf in der
   Leistungstabelle "Gueltige LIVE-Gehen-Tage" genauso. Jetzt nur noch
   als ganzes Wort, dafuer mit "zeitraum" -- Backstages Spalte wurde
   bisher nur zufaellig gefunden, weil in "Daten" die Silbe "date"
   steckt.

Gefunden hat das keine Ueberlegung, sondern der ganze Weg einmal mit
der echten Datei durchlaufen.

WEITER GEBAUT:
- Titelzeilen werden uebersprungen: "Creator:innen verwalten" hat in
  Zeile 1 nur "Exportiert am :…", die Ueberschriften stehen darunter.
  Die Regel misst (drei gefuellte Felder UND halb so breit wie die
  breiteste Zeile), statt eine feste Zahl zu nehmen.
- Fehlende Zellen verschieben nichts: Eine leere Zelle steht in der
  Datei gar nicht; wer der Reihe nach liest, verrutscht ab dort jede
  Spalte, und die Zeile sieht voll aus.
- Datums-Seriennummern werden nur umgerechnet, wenn das FORMAT es sagt
  (sonst stuende 46271 in der Vorschau). Der Nullpunkt ist an zwei
  nachschlagbaren Werten festgenagelt.
- Der Backstage-Dialog nimmt die Datei jetzt AUCH -- dort gehoert sie
  hin, denn Filipes Ausgabe enthaelt alle Creator auf einmal. Sie fuellt
  das Einfuegefeld; ab da laeuft derselbe Weg wie beim Einfuegen. Keine
  zweite Fassung derselben Regeln.
- Die alte .xls (BIFF, kein ZIP) wird erkannt und bekommt einen Weg
  gezeigt, statt "ging nicht" zu sagen.

NEU: pruef-xlsx.mjs (60) -- baut seine Dateien selbst (ZIP-Schreiber in
helfer-xlsx-bauen.mjs), damit keine Creator-Daten ins Repo wandern und
auch Faelle pruefbar sind, die es als Datei nicht gibt: kaputtes
Verzeichnis, fehlendes Blatt, abgeschnittene Datei. Jeder davon mit
Gegenprobe, dass die heile Datei durchgeht.

pruef-backstage-import 77 -> 82, dabei zwei Pruefungen GEDREHT: Die
.xlsx bekommt keine Absage mehr, sondern eine Vorschau.

DREI EIGENE FEHLER DABEI, alle von einer Messung gefunden:
- Ich hielt Seriennummer 46264 fuer den 06.09.; es ist der 30.08. Der
  Code hatte recht. Deshalb stehen jetzt zwei nachschlagbare Anker drin.
- Eine Zeile war gruen, weil mein Muster den SPALTENNAMEN
  "Datenzeitraum" traf statt der Begruendung. Jetzt wird auf den Text
  der Ablehnung geprueft.
- Beim Umbau habe ich pruef-backstage-import beschaedigt (ein
  Suchtreffer weiter oben als gemeint) und aus Git zurueckgeholt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-14 11:35:21 +02:00
DogFatherGitandClaude Opus 5 6973eda30b Notiz an der Rollenliste: die drei Team-Dogi-Rollen stehen dort bewusst
Beim Messen der neuen Auswahl fiel auf, dass in DogFathers Liste auch
"hand", "modi" und "gast" stehen -- Rollen aus dem anderen Haus. Wer
damit auf workspace. jemanden umstellt, schiebt ihn dorthin: Er faellt
aus der Agenturliste und kommt an dieser Adresse nicht mehr herein.

Filipe wurde ausdruecklich gefragt und hat entschieden: so lassen.

Nur ein Kommentar, keine Codeaenderung. Er steht da, weil der Fall
sonst beim naechsten Aufraeumen wie ein Versehen aussieht -- und weil
der symmetrische Filter (wie er fuer das Crew-Haus schon existiert)
die naheliegende "Verbesserung" waere. Zwei Pruefungen halten den Stand
fest; wer ihn aendert, macht dort rot.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-12 00:28:52 +02:00
DogFatherGitandClaude Opus 5 e3aeeb01cd Rollen wechseln: auch Spicy Media -- und DogFather ist nicht mehr vergebbar
Filipe: "ich will dass die rolle spicy und dogfather, auch die rollen
wechseln koennen wenn die personen schon drin sind. von alle
kategorien, creator, scouts, manager spicy. dogfather soll man nicht
auswaehlen koennen. das ist die einzige die man nicht auswaehlen kann
bitte."

ZWEI AENDERUNGEN, BEIDE IN EINER LISTE (ANLEGBAR):
  admin: alles AUSSER der eigenen Rolle
  spicy: spicy, manager, scout, creator   (vorher ohne spicy)

Weil die Oberflaeche ihre Knoepfe aus derselben Auskunft baut
(`darf_anlegen` in /api/ich), verschwindet DogFather damit von selbst
aus JEDER Auswahl -- beim Anlegen wie beim Wechseln, bei Spicy Media
wie bei DogFather. Eine Liste, zwei Formulare, kein Nachziehen.

WAS DAS BEDEUTET, damit es niemand spaeter sucht: Es laesst sich kein
zweiter DogFather-Zugang mehr anlegen und niemand mehr zu einem
befoerdern. Der bestehende ist durch Sicherung 3 geschuetzt (nie den
letzten herabstufen) und kann nicht versehentlich verschwinden.
Zurueckdrehen laesst sich das nur in ANLEGBAR.

DIE TUER: /verwaltung haengt an nurAdmin, und dort steht jetzt eine
DRITTE enge Ausnahme -- PUT auf genau /personen/<Ziffern>/rolle, fuer
genau die Rollen aus darfRollenWechseln(). Gleiche Bauweise wie die
beiden davor (Liste fuer Spicy Media, Liste fuer die rechte Hand). Was
NICHT mitgeht: Codes, Sperren, Loeschen, Zuteilung, Protokoll.

EINE NEUE SICHERUNG, weil sich die Tuer geoeffnet hat: An einer
DogFather-Zeile aendert nur DogFather. Die bestehenden Pruefungen sehen
auf die ZIEL-Rolle ("darfst du 'manager' vergeben?") -- dass die
BETROFFENE Person DogFather ist, kam darin bis heute nicht vor.
Sicherung 3 haette es heute zufaellig abgefangen, weil es genau einen
gibt; eine Sperre, die nur wegen einer Zahl im Bestand haelt, ist
keine.

DIE OBERFLAECHE: "Rolle aendern" und "Loeschen" hingen an EINER Zeile
(`ich.rolle === 'admin'`). Sie gehoeren nicht zusammen -- Loeschen
bleibt bei DogFather. Und die CSS-Regel, die fuer Spicy Media die ganze
Knopfreihe ausblendete, ist weg: Welche Knoepfe es gibt, entscheidet
jetzt personen.js, und was nicht entsteht, muss man nicht verstecken.

pruef-spicy 62 -> 83. Gemessen wird jede der vier Kategorien EINZELN
(waere nur eine offen, saehe "geht" genauso aus), dazu: admin weder von
Spicy Media noch von DogFather vergebbar, an DogFathers Zeile aendert
sie nichts (und er ist danach nachweislich noch admin), ein Manager
kommt an den Weg nicht, loeschen bleibt zu -- und im Browser, dass der
KNOPF da ist, nicht nur das Recht. Genau daran war heute frueh im Chat
eine Stunde draufgegangen.

Dabei zwei eigene Messfehler gefunden: Die Knoepfe entstehen erst in
einer AUFGEKLAPPTEN Kategorie (vorher zu frueh gemessen), und /api/ich
wird jetzt als Vorbedingung geprueft.

DREI PRUEFUNGEN GEDREHT, KEINE GELOESCHT:
- pruef-personen-formular: 7 Karten, `admin` fehlt (eigene Aussage).
  Die Zeichenpruefung verglich die rechte Hand gegen die Admin-KARTE --
  die es nicht mehr gibt; sie lief gegen `undefined`. Ersatz ist das
  Zeichen selbst, und der Kommentar sagt, dass das schwaecher ist.
- pruef-haus-trennung: Der zweite DogFather entsteht jetzt im Bestand
  statt ueber die Schnittstelle, und DASS die Schnittstelle ihn
  ablehnt, ist der erste Prueffall geworden. Sonst waere "nie den
  letzten DogFather" ab heute ungeprueft -- weil ihre Voraussetzung
  schwerer herzustellen ist.
- pruef-creator-anlegen: aus einer Aussage zwei (die vier sind da UND
  admin fehlt).

Gruen: personen-liste, personen-kachel, verborgen, manager-sicht,
creator-anlegen, haus-trennung, personen-formular, spicy, rollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-12 00:25:47 +02:00
DogFatherGitandClaude Opus 5 1ab2729e47 Die rechte Hand steht ueberall an zweiter Stelle - und im Kalender ueberhaupt
Filipe, mit Bildschirmfoto der Liste "Wen gehst du durch?" (Diene, Dogi,
VanVan - alphabetisch, die rechte Hand ganz rechts): "rechte hand soll
immer als erstes sein. ueberall. wie in dem sinne soll sie ganz links
sein. ausser bei personen und zugaenge soll sie ueber jedem aber unter
dogfather sein. ich will dass auch ueberall immer nach der hirarchie
gearbeitet wird."

EINE REIHENFOLGE, NICHT ZWEI REGELN

ROLLEN_REIHE in workspace.js ist jetzt:
  Spicy Media > DogFather > Rechte Hand > Manager > Scout > Creator > Modi

Er hat zwei Faelle beschrieben, aber es braucht nur eine Reihenfolge: In
den Team-Listen kommt DogFather gar nicht vor (er beurteilt, er wird
nicht beurteilt) - dort steht sie dadurch automatisch ganz vorn. In
"Personen & Zugaenge" steht er drin, also steht sie dort hinter ihm.
Zwei Sonderfaelle waeren zwei Stellen, an denen es auseinanderlaeuft.

Dass Spicy Media davor bleibt, ist seine ausdrueckliche Entscheidung auf
Nachfrage. 'gast' steht bewusst nicht in der Liste und faellt ans Ende.

ROLLEN_SORTIERUNG (der SQL-Ausdruck) wird jetzt aus ROLLEN_REIHE
ABGELEITET statt danebengeschrieben. Bis heute stand die Reihenfolge
zweimal da; beim Hochziehen der rechten Hand haetten beide geaendert
werden muessen. Eine Liste, die niemand pflegt, kann nicht veralten -
derselbe Grundsatz wie beim Spaltenverlust vom 06.09.

WAS DABEI AUFFIEL, OHNE DASS JEMAND DANACH GESUCHT HAT

Der Server sortierte laengst richtig. DREI Auswahllisten im Browser
haben seine Reihenfolge wieder verworfen und nach einer eigenen Liste
mit fuenf Agentur-Rollen neu gezeichnet - Team Dogi kommt darin nicht
vor und DARF es nicht (bereiche.js laedt jeder herunter).

  - Chat-Auswahl und Sicht-Umschalter: Team Dogi landete in einem
    Nachzuegler-Block ganz unten, hinter jedem Creator.
  - Teilnehmerwahl im Kalender: dort gab es nicht einmal einen
    Nachzuegler-Block. Die rechte Hand und die Modis standen GAR NICHT
    zur Auswahl. DogFather konnte sein eigenes Team zu keinem Termin
    einladen, und auf dem Bildschirm sah das vollkommen normal aus.

Das ist derselbe Fehler zum vierten Mal (Chat 10.09., Personenliste
10.09., Sicht-Umschalter 11.09., Kalender 11.09.). Deshalb keine vierte
Einzelreparatur, sondern eine Stelle: window.Bereiche.gruppieren()
gruppiert in genau der Reihenfolge, in der der Server die Menschen
schickt - ohne einen einzigen Rang zu kennen. Fehlt der Helfer, wird
eine Gruppe mit allen gezeichnet: nicht schoen, aber sichtbar, und
niemand verschwindet. Der Kalender-Weg schickt die Ueberschrift jetzt
mit, wie der Chat es laengst tut.

PRUEFUNGEN

  pruef-nachwuchs   109 -> 123 (Abschnitt 12: die Reihenfolge, mit der
                    Gegenprobe, dass sie NICHT alphabetisch ist -- Rieke
                    steht alphabetisch hinten, mit "Anna" waere jede
                    Zeile gruen ohne etwas zu messen)
  pruef-dabei-optik misst die Wahl jetzt im Browser: ist Team Dogi
                    ueberhaupt da, und steht es vorn
  pruef-rollen      315 (vorher 312), 423 s gemessen. Die Notbremse lag
                    bei 480 s und hat angeschlagen - kein Haenger,
                    sondern zu wenig Luft, seit die rechte Hand vier
                    Kacheln mehr hat. Jetzt 900 s, mit der Messung
                    daneben und dem Hinweis, beim naechsten Mal nicht
                    die Zahl zu erhoehen, sondern nachzusehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 23:58:50 +02:00
DogFatherGitandClaude Opus 5 bba3642664 Aus der Probe wird ein Zugang - und die Seite sagt nicht mehr "Agentur"
Die drei offenen Punkte aus Abschnitt 9 des Plans, plus Filipes zweite
Ansage: "auf dieser seite soll nichts stehen von agentur, diese seite
hier ist nur fuer mich meine modis und meine community."

1. PROBE -> ZUGANG (ein Knopf statt eines Satzes)

Auf der Stufe "Probe" stand bisher "Zugang in Personen & Zugaenge
anlegen, Rolle Modi" - und wer das vergass, hatte eine Karte auf "Im
Team" und keinen Menschen darin. Jetzt haengt das Anlegen am Schritt
selbst.

Ueber DENSELBEN Weg wie in "Personen & Zugaenge", nicht ueber einen
zweiten: POST /workspace/api/verwaltung/personen, mit ihrer
Rechtepruefung, ihrem Protokolleintrag und ihrem genau einmal
angezeigten Code. Der Talente-Server legt selbst keinen einzigen Zugang
an, und die Pruefung zaehlt nach, dass es bei einem Weg bleibt.

Der Code steht im gleichen Kasten wie dort - die Gestaltung ist aus
personen.css nach start.css umgezogen, weil talente.html sie sonst nicht
laedt. Ein Geheimnis sieht im ganzen Haus gleich aus. Er steht
ausserhalb der Liste, sonst waere er in dem Moment weg, in dem er
entsteht: wenn die Karte auf "Im Team" springt.

Die rechte Hand bekommt an dieser Stelle KEINEN Knopf, sondern einen
Satz. Ein Knopf, der ihr jedes Mal "darfst du nicht" antwortet, waere
schlechter als gar keiner - er verspricht etwas.

2. DIE EIGENE KARTE (Abschnitt "Deine Karte")

Wer beschrieben wird, darf es lesen - aber erst, wenn ALLE gesetzt
haben (sonst waere die erste Einschaetzung eine Vorgabe fuer die
zweite), und ohne Namen und ohne Anlasstext. Gemessen in beide
Richtungen: vorher nicht sichtbar, nachher sichtbar.

3. DER VORLAGENTEXT

Gebaut aus den angeklickten Merkmalen, in einem Feld zum Aendern, nicht
zum Abschicken. Ohne Merkmale steht auch keines drin.

4. "GILT FUER" SAGT DER SERVER

In bereich.js stand woertlich "Agentur" - richtig auf der
Agenturadresse, falsch auf jeder anderen. Jetzt liefert der Server
`gehoert` ("Der Treff" / "Team Dogi" / "Agentur"); gemessen mit einem
einzigen Menschen auf zwei Adressen.

PRUEFUNGEN: treff 58 -> 66, nachwuchs 69 -> 109, neue-seiten 70 -> 93.
Die Katalogseiten werden jetzt auch mit den Augen der rechten Hand
angesehen - ohne das waere "Deine Karte" nie auf einem Bildschirm
gewesen. Und pruef-neue-seiten wartet nicht mehr 900 ms, sondern bis
sich der Text nicht mehr aendert: Die Karte stand da und wurde
trotzdem als fehlend gemeldet, weil zu frueh gelesen wurde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 23:13:50 +02:00
DogFatherGitandClaude Opus 5 44e5ace109 "Wer sieht was" auf beiden Adressen — und die Tafel lässt sich umstellen
Filipe: "ich will die kategorie auch auf der team dogi seite für die
dogfather und rechte hand rollen ... und wenn man drauf drückt,
perfektionieren so dass ich die da auch manuell wechseln und speichern
kann."

DIE KACHEL STAND NUR AUF DER AGENTURSEITE. Auf der Team-Dogi-Seite
arbeitet ihr aber täglich; dort nicht nachsehen zu können, wer was darf,
hieße, die Frage an dem Ort zu stellen, an dem man gerade nicht ist. Sie
steht jetzt auf beiden — einmal beschrieben, zweimal benutzt.

ANSEHEN BEIDE, UMSTELLEN NUR DOGFATHER. Die rechte Hand bekommt
dieselbe Tafel und keine Knöpfe; nicht weil das Skript sie versteckt,
sondern weil der Server darf_aendern: false schickt. Wer Rechte vergeben
kann, kann sich Rechte vergeben — diese eine Tür bleibt bei ihm.

WAS GESPEICHERT WIRD, IST NUR DER UNTERSCHIED. In der Datenbank steht
eine Zeile nur, wenn sie vom Grundstand in rechte.js abweicht. Damit
bedeutet der Code weiterhin etwas: Man sieht, was gedacht war, und
daneben, was jemand daraus gemacht hat. "Zurück auf Grundstand" ist ein
DELETE, und eine neue Seite erbt automatisch den Grundstand — eine
vollständige Kopie in der Datenbank hätte sie nicht gekannt und sie wäre
für alle zu gewesen, ohne dass es jemand entschieden hätte.

DREI FELDER SIND FEST: DogFather kann sich die Rechte-, die Personen-
und die Startseite nicht selbst wegnehmen. Eine Einstellung, aus der man
sich aussperren kann, ist keine Einstellung, sondern eine Falle — und
sie wäre genau einen Fehlklick entfernt gewesen.

GESPEICHERT WIRD SOFORT, mit jedem Klick. Kein "Speichern" am Ende: Bei
zweihundert Feldern ist das die Stelle, an der eine halbe Änderung
verlorengeht, und eine halbe Änderung an Rechten ist die gefährlichste
Lage von allen. Rückfrage gibt es nur beim ÖFFNEN — etwas wegzunehmen
sieht sofort jemand, etwas aufzumachen unter Umständen lange niemand.

DER BEFUND, DEN DIE PRÜFUNG GEFUNDEN HAT: Nimmt man einem Modi eine
Seite weg, greift die Schranke sofort — und die KACHEL blieb stehen. Ein
Knopf, der auf die Startseite zurückwirft. Der Satz "Kachel und Tür
gehören zusammen" steht seit dem 06.09. im Code; bis heute war er eine
Bitte an den, der beides pflegt. Jetzt ist er eine Rechnung: Beide
Kachellisten — die des Servers und die im Browser — werden gegen
dieselbe Tafel gefiltert, aus der die Schranke ihre Entscheidung holt.

Geprüft wird nicht, ob die Antwort 200 lautet, sondern ob sich das
VERHALTEN ändert: Der Modi kommt danach wirklich nicht mehr hinein —
mit Gegenprobe davor. Und eine Umstellung überlebt einen Neustart; ohne
tafelLaden() beim Start hätte wieder der Grundstand gegolten, und es
hätte ausgesehen wie vorher.

Geprüft: rollen 315 · start-ansicht 147 · crew-adresse 132 · sicht 84 ·
modi-verborgen 80 · neue-seiten 70 · treff-werkzeuge 70 · nachwuchs 69 ·
treff 58 · rechte-umstellen 46 · entwicklung 40 · css-klassen 30 ·
zwischenspeicher 21 · alle-wege 19 · rechtetafel 19 — alles grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 22:42:21 +02:00
DogFatherGitandClaude Opus 5 dfd951861a Entwicklung & Nachwuchs: zwei Kataloge zum Anklicken statt zwei leerer Formulare
Filipe: "ich will dass diese zwei kategorien perfektionniert werden, ich
will dass fertige aufgaben da stehen und so ... so dass dogfather und
rechte hand es so einfach wie möglich haben aber so professionell wie
auch nur möglich."

Bis heute waren beide Kacheln ein leeres Formular: Titel tippen, Art
wählen, Text schreiben. Ein leeres Feld beantwortet keine Frage — es
stellt sie noch einmal.

ENTWICKLUNG: 34 Beobachtungen in fünf Blöcken, vier Antworten je Zeile
(Läuft · Wächst gerade · Da hakt es · Kann ich nicht sagen). Es sind
BEOBACHTUNGEN, keine Eigenschaften — "Absagen kommen rechtzeitig" statt
"ist zuverlässig". Eine Eigenschaft kann man nur bestätigen oder
bestreiten; ein Verhalten kann man gesehen haben oder nicht.

TALENTE: 21 Merkmale in fünf Gruppen, 6 Warnzeichen getrennt geführt,
fünf Trichterstufen mit je GENAU EINEM nächsten Schritt. Eine Liste
wächst und wird nie wieder angesehen; ein Trichter fragt bei jeder Karte
"und jetzt?". Die Standzeit steht dabei — "seit 41 Tagen beobachtet"
ist eine Auskunft über uns, nicht über den Kandidaten.

VIER RIEGEL, JEDER MIT GEGENPROBE:
 · Block 5 ("Wie geht es dir damit?") gehört der Person — lesend UND
   schreibend, auch vor DogFather. Er kommt gar nicht erst aus dem
   Server; Schreiben gibt dasselbe 404 wie ein erfundener Schlüssel.
   Nach außen dringt eine Ampel OHNE Namen, und die schweigt, solange
   das Team so klein ist, dass "jemandem geht es zu viel" dasselbe wäre
   wie ein Name.
 · Der Stand des anderen kommt erst nach dem eigenen Klick — sonst
   klickt man dasselbe. Sichtbar ist nur, DASS es einen gibt: sonst
   sähen "noch niemand" und "du darfst es nicht sehen" gleich aus.
 · "Da hakt es" ohne Anlass wird abgelehnt. "Läuft" nicht — 28
   Pflichtfelder je Person wären das Gegenteil von "so einfach wie
   möglich".
 · Talente gehört DogFather und der rechten Hand. Ein Modi bekommt 404
   auf Seite UND Schnittstelle.

WAS NICHT GEBAUT IST, UND WARUM: keine Punktzahl, kein Durchschnitt,
keine Rangliste, keine Gesamtnote. Eine Zahl über einem Menschen wird
gelesen, verglichen und weitererzählt. Und kein Rot — "da hakt es" ist
eine Beobachtung, kein Alarm.

DER PLAN LAG AN EINER STELLE FALSCH, gemessen statt vermutet: Er sagte
"keine neue Tabelle, der Stand liegt in punkt_stand". Dort ist der
Schlüssel (bereich, schluessel, creator_id) — genau EIN Stand je Punkt
und Person. Zwei unabhängige Augenpaare passen da nicht hinein, ohne
eine lebende Tabelle neu zu bauen. Also eine eigene.

EIN RÜCKSCHLAG, DEN NUR DIE PRÜFUNG GEFUNDEN HAT: Die Liste der
Bretter, die ein Modi oder die rechte Hand öffnen darf, wird aus den
KACHELZIELEN abgeleitet. Als die Kacheln auf die neuen Seiten zeigten,
fielen beide Bretter heraus — und die Seite verlinkte auf ein 404. Kein
Fehler im Riegel, sondern in seiner Quelle.

Dazu zwei kleinere Funde vom Hinsehen statt vom Messen: Die Ampel sagte
"Solange ihr zu 1 seid" (jetzt drei Sätze für drei Lagen), und die
Fußzeile der Talente-Seite lag auf der Bühne — die Kontrastprüfung hatte
sie übersprungen, weil ein Link darin steht. Beide behoben, und die
Prüfung hat den stillen Aussetzer gleich mit verloren.

Geprüft: rollen 314 · start-ansicht 147 · crew-adresse 132 · neue-seiten
70 · nachwuchs 69 · entwicklung 40 · css-klassen 30 · zwischenspeicher
21 · alle-wege 19 · rechtetafel 19 — alles grün.

Was noch fehlt, steht in der Notiz, Abschnitt 9: die eigene Karte für
die Person, der Übergang "Probe" → Zugang, der Vorlagentext zum
Ansprechen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 22:20:09 +02:00
DogFatherGitandClaude Opus 5 93ba881b18 Entwicklung & Nachwuchs steht auf der Team-Seite über "Rund ums Live"
Filipe, mit zwei Bildschirmfotos: "mach nur die kategorie auf screen1
über die kategorie von screen2."

gruppeNach half hier nicht -- das gilt nur für die Zusatzkacheln der
Agenturseite. Auf der Team-Adresse kommen die Kacheln aus der Hauptliste,
und dort ist die Reihenfolge der Gruppen die Reihenfolge der Kacheln.

Eingefügt wird deshalb VOR der ersten Kachel der Gruppe "Rund ums Live"
-- nach dem Namen, nicht nach einer Position. "An Stelle 7 einfügen"
wäre beim nächsten Umsortieren still falsch, und still falsch heißt
hier: eine Kategorie rutscht irgendwohin, ohne dass es jemand merkt.
Findet sich die Gruppe nicht, wird angehängt statt weggelassen.

Auf der Agenturseite ändert sich nichts: Dort bleiben die beiden
Kacheln ganz unten, weil dort private Aufzeichnungen über Menschen
stehen. Zwei Adressen, zwei Plätze, beide entschieden.

Geprüft: start-ansicht 147, unverändert grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 18:44:02 +02:00
DogFatherGitandClaude Opus 5 39dd666b17 Der Treff zieht in Team Dogi ein — die dritte Adresse ist wieder weg
Filipe, nachdem er die dritte Wand gesehen hatte: "das soll keine app
für sich sein, dass soll in der crew seite adaptiert werden, da rein
perfektionniert."

WAS VERSCHWINDET: treff.dogfather-universe.com samt Weiche
(treff-adresse.js), Zugangswand, Manifest und acht Bühnenbildern. Kein
DNS-Eintrag, kein zweiter Caddy-Block, kein zweites App-Symbol.

Die Gründe, die DAFÜR sprachen, stehen jetzt als Kommentar in
crew-adresse.js statt als Code -- sie gelten weiter, und beim nächsten
Mal wird jemand dieselbe Idee haben: eine App je Ursprung, und ein
Schloss mehr zwischen der Community und den Daten der Agentur.

WAS DER VERZICHT KOSTET, benannt statt übersehen:
 · Die Community steht vor derselben Wand wie das Team und liest dort
   die Namen der drei Team-Rollen. Filipes Entscheidung auf die Frage:
   vierte Kachel "Community" statt gar keiner Kacheln.
 · Ein Schloss weniger. Was vorher die Adresse getrennt hat, muss jetzt
   jede einzelne Regel halten -- deshalb prüft pruef-treff-werkzeuge
   seit heute zehn Dinge mehr (70 statt 60).

EINE LÜCKE, DIE DABEI AUFGEFALLEN IST -- und die es schon vorher gab:
Ein Mitglied der Community stand in der Auswahl, wen man zu einem
Termin einlädt, wem man eine Aufgabe gibt und mit wem man einen Chat
anfängt. Für DogFather bedeutet fast jede Liste "alle". Jetzt zu, über
eine Hülle (ohneAussen) um die fünf Listen, die von Zusammenarbeit
handeln -- damit sie auch für die Listen gilt, die es noch nicht gibt.
Die Verwaltungsliste in "Personen & Zugänge" zeigt sie weiterhin, sonst
legt er einen Zugang an und der verschwindet im selben Moment.

DREI BEFUNDE AUS DEN PRÜFUNGEN, wieder keiner vom Lesen:
 · Mein eigener Kommentar auf der Wand nannte eine Rolle der Agentur --
   in einer Datei, die jedes Community-Mitglied im Quelltext liest.
   Zum zweiten Mal an einem Tag, und zum zweiten Mal ausgerechnet in
   einem Kommentar, der erklärt, warum man das nicht tut.
 · Die Prüfung "der Satz nennt die Modis" durchsuchte den QUELLTEXT und
   wäre grün geblieben, obwohl der Satz auf dem Bildschirm längst ein
   anderer ist -- sie fand ihn in einem Kommentar. Sie misst jetzt die
   sichtbare Unterzeile.
 · Der erste Entwurf der Adressregel sperrte die Community auch auf
   localhost aus -- eine Bedingung durch AUSSCHLUSS, zum dritten Mal an
   einem Tag. Jede Zeile nennt jetzt die Adresse, FÜR DIE sie gilt.

Und zwei feste Zahlen weniger: Die Kachelreihe wird nicht mehr gezählt,
sondern beim Namen genannt (admin, hand, modi, gast) -- eine Zahl war
dort schon zweimal rot, ohne dass etwas kaputt war. Der App-Name wird
nicht nur geprüft, sondern der UNTERSCHIED zur Agenturadresse.

Die App heißt auf crew. jetzt "DogFather Universe" statt "Team Dogi" --
sie gehört ab heute beiden (Entscheidung Filipe).

Geprüft: rollen 312 · crew-adresse 132 · kalender 104 · sicht 84 ·
modi-verborgen 80 · chat-kanaele 79 · treff-werkzeuge 70 · haus-trennung
62 · treff 58 · chat 48 · treff-seiten 42 · bereiche-lesend 37 ·
start-ansicht 147 · css-klassen 30 · zwischenspeicher 21 · alle-wege 19 ·
rechtetafel 19 -- alles grün.

Die 58 bei pruef-treff sind elf weniger als gestern: Mit der dritten
Adresse fallen ihre 26 Weichen-Prüfungen weg, ersetzt durch 10 für die
eine Wand plus die neuen in 7b.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 18:38:05 +02:00
DogFatherGitandClaude Opus 5 1ebaf8a864 Die drei neuen Seiten angesehen — und die Bühne lag hinter der Rechtetafel
Sie waren geprüft und nie ANGESEHEN. pruef-treff-seiten.mjs (42
Prüfungen, 1440 px und 390 px) holt das nach: Steht Text da, sind die
Platzhalter ersetzt, liegt etwas übereinander, schiebt die Seite
seitwärts, ist alles lesbar.

DER BEFUND, DEN KEINE ZAHL GESEHEN HAT: Hinter der Rechtetafel lag die
Bühne — Spicy-Media-Motiv, Neonlicht, Chilischoten — und die Zeilen der
Tabelle standen mitten darin. Die Kontrastmessung war grün, weil sie
gegen #07060f rechnete: Sie hatte den Grund nicht gemessen, sondern
angenommen. Ein grüner Haken über einer falschen Voraussetzung.

Behoben an beiden Enden:
 · Die Abschnitte bekommen eine DECKENDE Fläche — kein Kartenauftritt
   (keine Fase, kein Kantenlicht), nur ein Blatt Papier unter dem Text.
   Der Einwand von vorher (Karten zerteilen einen langen Text) bleibt
   damit gewahrt, die Bühne bleibt ringsum sichtbar.
 · Die Messung bekommt einen DRITTEN AUSGANG: Findet sie über einem Text
   keine deckende Fläche, ist das jetzt ein Fehler ("konnte nicht
   nachsehen") und kein stilles Grün.

Zwei weitere Meldungen waren Messfehler und sind als solche behoben,
nicht weggeklickt:
 · "Meine Sicht" überlappt sich selbst — das ist das <select> für
   Vorleseprogramme, das UNTER dem eigenen Bedienelement liegen MUSS.
   Ausgelassen wird jetzt, was ausdrücklich fürs Auge weggenommen wurde.
 · Die Rechtetafel ragt auf 390 px über den Rand — sie steht in einem
   Schiebekasten, und genau so soll eine Tabelle mit neun Spalten sich
   auf einem Handy verhalten. Gemessen wird jetzt, ob die SEITE schiebt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 18:04:33 +02:00
DogFatherGitandClaude Opus 5 7b21f247eb Der Treff: eine eigene Tür für die Community, und sie sieht nur, was dasteht
Filipe: "eine community rolle und community kategorie, wo die community
auch dann nur die sieht" · "wieso nur eine kachel — ich will mehrere,
mit mehreren optionen" · "egal welche rolle hinzugefügt wird soll immer
nur das sehen was ich erlaube".

DIE DRITTE ADRESSE. treff.dogfather-universe.com bekommt eine eigene
Weiche (treff-adresse.js), eine eigene Zugangswand, ein eigenes Manifest
und acht eigene Bühnenbilder. Ohne sie stünde dort die Wand der Agentur:
Spicy-Logo, "Creator Workspace", fünf Rollenkacheln mit den Namen Admin,
Manager, Scout, Creator — die komplette Struktur des Unternehmens, vor
der Anmeldung, für jeden mit der Adresse.

Welche Wand zu welcher Tür gehört, steht jetzt in EINER Tafel
(istFremdeWand) statt als Sonderfall im Code. Bei zwei Wänden war ein
Sonderfall richtig; bei drei wären es drei geworden, bei vier sechs.

SIEBEN BRETTER UND EIN ACHTES NUR FÜRS TEAM. Anschlagbrett, Was ansteht,
Der Treff, Wunschliste, Highlights, Regeln & Hilfe, Mitmachen — dazu
"Meldungen & Maßnahmen", das ausdrücklich NICHT in TREFF_BEREICHE steht:
dort wäre es lautlos bei der Community gelandet und hätte ausgesehen wie
die anderen sieben.

WAS AUF DEN BRETTERN PASSIERT: "Will ich auch" (eine Stimme je Person,
erzwungen durch den Schlüssel, nicht durch eine Prüfung) · Anheften,
höchstens drei, gezählt IN der Transaktion · Freigabe vor Sichtbarkeit
für Termine und Highlights, wobei Abwesenheit der Ruhezustand ist ·
Melden mit Pflicht-Grund (DSA Art. 16) · Entfernen mit Grund, der den
Beitrag ÜBERLEBT (DSA Art. 17) · drei Stufen, gerechnet statt
gespeichert · die Bannleiter: Modi bis 7 Tage, dauerhaft nur DogFather
(seine Entscheidung) · "Mitmachen" wird zum Talent, genau einmal.

Der Ausschluss wirkt in sitzungLesen() — also nicht nur beim Schreiben.
Wer ausgeschlossen ist, ist weg, nicht stumm.

ZWEI SEITEN MEHR. treff-regeln.html holt seine ZAHLEN vom Server
(Mindestalter 18, Fristen, Anschläge) — ein Regeltext, der eine andere
Zahl nennt als die Regel, ist schlimmer als keiner. rechte.html rechnet
"Wer sieht was" aus derselben Tafel aus, aus der die Schranke ihre
Entscheidung holt. Die Community steht dort bei 3 von 23.

SECHS BEFUNDE, KEINEN HAT DAS LESEN GEFUNDEN:
 · Ein Modi kam über den verborgenen Zugang in den Treff — die Bedingung
   war durch Ausschluss formuliert und nahm die neue Wand automatisch mit
 · /api/personen gab einem Mitglied Namen und Rolle von DogFather
 · Ein DELETE mit Körper wird von Nodes HTTP-Parser mit einem leeren 400
   abgewiesen, bevor Express ihn sieht (gemessen). Der Grund reist jetzt
   in der Adresse
 · Der Kommentar, der erklärt, warum die Zugangswand keine Rollennamen
   nennt, nannte selbst einen — in einer ausgelieferten Datei
 · Zwei Listen für "welche Seiten sind ohne Anmeldung offen". Sie
   stimmten, weil beide am selben Tag entstanden
 · Ein Portkonflikt, den ich selbst gebaut hatte (4391 gehört
   pruef-chat-aufloesen)

Dazu zwei feste Zahlen abgeschafft (die 20 in pruef-rechtetafel, die
Kachelzahl in pruef-treff) und zwei Werkzeuge, die jetzt SUCHEN statt
aufzuzählen: Der Versionsstempel findet seine Manifeste selbst — das
dritte hätte sonst keinen bekommen, und die neue App hätte bis zu vier
Stunden lang das falsche Zeichen getragen. Das Bildwerkzeug baut beide
Zugangswände aus einer Vorlage mit zwei Werten.

Zwei neue Kacheltöne, gemessen statt gewählt: #2f2f7f (Abstand 31,4 in
Lab) und #7c2771 (29,7). Das schwächste Paar der vorhandenen 34 liegt
bei 24,9.

Geprüft: treff 69 · treff-werkzeuge 60 · rollen 312 · start-ansicht 147 ·
crew-adresse 129 · sicht 84 · modi-verborgen 80 · haus-trennung 62 ·
bereiche-lesend 37 · css-klassen 30 · zwischenspeicher 21 · alle-wege 19 ·
rechtetafel 19 — alles grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 17:58:34 +02:00
DogFatherGitandClaude Opus 5 47a91e9708 Die goldene Regel: was nicht in der Tafel steht, ist verboten
Filipe: "egal welche rolle oder person hinzugefuegt wird soll immer nur
das sehen wass ich erlaube. mehr nicht. soll nichts so sein dass wenn
mann eine rolle oder jemanden hinzufuegt dass er dan alles sieht."

DER BEFUND -- GEZAEHLT, NICHT GESCHAETZT

NEUN von zwanzig Seiten standen auf `null`, und `null` hiess "jede
angemeldete Rolle": Start, Uebersicht, Aufgaben, Chat, Kalender,
Dateien, Calls, Start-Check, Wissen. Eine neue Rolle erbte sie alle,
ohne dass jemand etwas erlaubt haette.

UND EIN ZWEITES LOCH, das ich vorher nicht gemessen hatte: Die Schranke
las `const erlaubt = GESCHUETZT[pfad]` und prueffte `if (erlaubt && ...)`.
Eine Seite, die GAR NICHT in der Tabelle stand, ergab `undefined`, fiel
durch dieselbe Bedingung und war damit ebenfalls fuer jede angemeldete
Rolle offen. Am 11.09.2026 betraf das keine einzige Seite (nachgezaehlt:
22 Dateien = 20 Eintraege + 2 Zugangswaende) -- aber jede NEUE waere so
entstanden.

Die Rolle wird im Haus an 74 Stellen in 20 Modulen abgefragt, und die
Endzweige widersprechen einander: Aufgaben enden mit `default: 0=1`
(sieht nichts), Bereiche und Dateien fallen in "eigene plus betreute".
Drei Module, drei Antworten auf dieselbe Frage.

WARUM NICHT "DIE LISTE DURCHGEHEN"

Das waere die naheliegende Antwort und die falsche. Im Code stand seit
dem 10.09. genau dieser Satz -- "Wer eine Rolle hinzufuegt, muss diese
Liste durchgehen" -- und einen Tag spaeter standen immer noch neun
Seiten auf `null`. Ein Satz, der sich auf ein Gedaechtnis verlaesst, ist
keine Sicherung. Dazu: eine vergessene Erlaubnis MELDET SICH NIE. Die
Seite laedt ja. In der anderen Richtung ist es schlimmer -- eine Seite,
die zu viel zeigt, sieht aus wie eine Seite, die funktioniert.

WAS JETZT GILT

server/rechte.js traegt die Tafel, `darfSeite()` liest sie, und sie
kennt zwei Antworten: Seite in der Tafel UND Rolle darin -> ja. Alles
andere -> nein. Kein `null`, kein `undefined`, kein Zweig, der etwas
durchlaesst.

DIE TABELLE IST UMGEZOGEN, NICHT NEU GESCHRIEBEN. In ihren Kommentaren
steckt das Gedaechtnis des Hauses -- jede Zeile traegt ein Datum und
einen Satz von Filipe ("nimm die kategorie zahlen bei jedem weg", "die
manager sollen diese kategorien garnicht sehen", "ich will dass die
rechte Hand auch alle sieht"). Die wegzurefactoren waere der teuerste
Fehler dieses Umbaus gewesen.

VERHALTENSGLEICH FUER DIE SIEBEN VORHANDENEN ROLLEN. Die neun
`null`-Seiten tragen jetzt alle sieben Namen. Eine Umkehrung, die
nebenbei Rechte entzieht, waeren zwei Aenderungen in einer -- und man
wuesste hinterher nicht, welche etwas kaputtgemacht hat. Enger stellen
ist ein eigener Schritt.

pruef-rechtetafel.mjs (NEU, 19 Pruefungen, Port 4397) macht daraus eine
Garantie statt einer Absicht:

  * Jede Rolle braucht einen Eintrag -- sonst rot. Man kann eine Rolle
    nicht mehr hinzufuegen, ohne zu entscheiden, was sie sieht.
  * Jede Seite braucht einen Eintrag -- verglichen gegen das
    DATEISYSTEM, nicht gegen eine zweite Liste. Eine neue Seite ist
    damit erst einmal fuer NIEMANDEN offen statt fuer alle.
  * Eine Phantomrolle kommt auf keine der zwanzig Seiten.
  * Gegenprobe: jede ECHTE Rolle kommt irgendwo hin (spicy 18, admin 20,
    manager 17, scout 16, creator 15, hand 13, modi 11) -- sonst waere
    die Zeile darueber auch gruen, wenn schlicht alles zu waere.
  * Am Server: eine Seite ohne Eintrag wird abgewiesen statt
    ausgeliefert, und alle 20 Seiten der DogFather-Rolle liefern wirklich.
  * Zerstoerende Probe ganz am Ende (die Lektion vom 09.09.: in der
    Mitte verbiegt sie alles danach).

ZWEI EIGENE FEHLER UNTERWEGS. `node --check` meldete "Syntax in
Ordnung", das Modul lud aber nicht -- beim Umzug war eine Konstante
verlorengegangen. Syntax ist kein Beweis. Und ein Kommentar behauptete
danach noch das Alte ("eine neue Seite ist mindestens nur fuer
Angemeldete"); der Rueckfall ist jetzt "fuer niemanden", und das steht
da auch so.

Gruen: pruef-rechtetafel 19 (neu), pruef-rollen 287, pruef-sicht 84,
pruef-crew-adresse 129, pruef-modi-verborgen 80, pruef-haus-trennung 62.
Stempel 202609111617.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 16:18:09 +02:00
DogFatherGitandClaude Opus 5 4219ac3f9d Backstage-Fenster: Arbeit zuerst, Anleitung dahinter
Filipe, mit dem Fenster im Bild: "perfektionnier auch diese kachel die
sieht so scheisse aus."

Er hatte recht, und der Grund war nicht die Farbe, sondern die
REIHENFOLGE. Vor dem Feld, in das man einfuegt, standen fuenf lange
Schritte und zwei Absaetze -- rund 1400 px Text, bevor die eigentliche
Arbeit anfing. Wer das Fenster zum zwanzigsten Mal oeffnet, scrollt
jedes Mal an einer Anleitung vorbei, die er laengst kennt; wer es zum
ersten Mal oeffnet, liest eine Wand, bevor er weiss, worum es geht.

Das habe ich selbst gebaut, heute Vormittag, auf den Wunsch "ich
brauch auch eine erklaerung immer dabei". Die Erklaerung war richtig --
ihr Platz war falsch.

JETZT: ein Satz oben, sofort das Feld, dann Tag und Vorschau. Die
ausfuehrliche Anleitung liegt unter einer aufklappbaren Zeile, die
zugeklappt 37 px braucht statt 560.

DIE UEBERSCHRIFTENZEILE BLEIBT OBEN, ausserhalb des Aufklappers. Sie
ist die einzige Angabe, ohne die es gar nicht geht -- den haeufigsten
Fehlgriff hinter einen Klick zu legen waere genau der falsche Tausch.

Nebenbei: Der Erklaersatz zum Tag stand IN der Feldbeschriftung und
machte sie zweizeilig -- eine Beschriftung, die man lesen muss, ist
keine mehr. Er steht jetzt darunter. Das Datumsfeld erbt die Schrift
des Hauses (ohne Angabe nimmt der Browser seine eigene, und das sah
aus wie ein vergessener Rest) und ist auf die Breite gedeckelt, die
ein Datum braucht. Und das Fenster rollt INNEN, damit "Uebernehmen"
immer erreichbar bleibt.

pruef-backstage-import 72 -> 77. Die neuen Zeilen messen die POSITION
in Pixeln, nicht den Text: Die bestehenden Pruefungen lesen
`textContent` des ganzen Dialogs und waeren auch dann gruen, wenn die
Anleitung wieder nach vorn rutscht. Dazu: zugeklappt beim Oeffnen,
Ueberschriftenzeile trotzdem sichtbar, die Zeile nimmt unter 90 px,
und der Aufklapper klappt wirklich auf (ein Aufklapper, der klemmt,
versteckt die Anleitung endgueltig).

Mit SCHIRM=1 legt die Pruefung drei Bilder ab: leer, zugeklappt,
aufgeklappt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 15:54:25 +02:00
DogFatherGitandClaude Opus 5 a04748b82f Excel-Dateien: keine Sackgasse mehr im Auswahlfenster
Filipe: "wenn ich auf screen1 druecke geht mein ordner auf aber meine
excel datei kann ich nicht auswaehlen wieso??"

Im Feld stand accept=".csv,text/csv,text/plain". Die .xlsx war damit
ausgegraut -- ohne ein Wort dazu. Eine Sackgasse ohne Wegweiser ist
schlimmer als eine Absage mit Begruendung: Man sucht den Fehler bei
sich.

WARUM SIE NICHT EINFACH GELESEN WIRD: Der Leser dahinter (csvZerlegen)
versteht Text -- Komma, Semikolon, Tabulator. Eine .xlsx ist in
Wahrheit ein ZIP-Archiv. Als Text gelesen ergibt sie Zeichensalat, und
der schlimmste Ausgang waere nicht "geht nicht", sondern eine Vorschau
mit Zahlen aus dem Dateikopf. Das Feld einfach zu oeffnen, ohne den
Fall zu behandeln, haette aus einer klaren Sperre einen unklaren
Fehlschlag gemacht.

Jetzt laesst sich jede Datei waehlen, und WAS sie ist, sagt der INHALT
-- die ersten Bytes, nicht die Endung. Eine umbenannte Datei ist keine
andere Datei. .xlsx beginnt mit "PK" (ZIP), die alte .xls mit dem
OLE-Kennzeichen D0 CF 11 E0.

Und dann steht da, was stattdessen zu tun ist, mit ZWEI Wegen:
  1. In Excel markieren, Strg+C, und den Knopf "Backstage-Tabelle
     einfuegen" nehmen -- der versteht TAB-getrennte Zeilen, also genau
     das, was beim Kopieren aus Excel in der Zwischenablage liegt. Das
     geht sofort und ohne Umspeichern.
  2. Oder in Excel als "CSV UTF-8" speichern.

Der erste Weg funktionierte schon vorher -- er stand nur nirgends.

Nebenbei: Eine leere Datei meldet jetzt "Die Datei ist leer" statt
durch die Vorschau zu laufen, und eine abgewiesene Datei bleibt nicht
im Feld stehen.

pruef-backstage-import 66 -> 72. Geprueft wird an einem echten
ZIP-Kopf, nicht an der Endung: Die Testdatei heisst .xlsx UND traegt
das Kennzeichen -- eine Pruefung ueber den Namen waere gruen, ohne die
Erkennung je zu beruehren. Mit Gegenprobe, dass eine echte CSV
denselben Weg weiterhin durchlaeuft; sonst hiesse das nur, dass gar
nichts mehr eingelesen wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 15:45:16 +02:00
DogFatherGitandClaude Opus 5 f23260dcbb Chat: Gruender duerfen ihre Gruppe oder ihren Kanal aufloesen — und der Umschalter erklaert sich
Zwei Wuensche von Filipe, beide am Neu-Fenster.

1) "ich will eine bessere erklaerung dafuer bitte."
Neben dem Umschalter "Gespraech | Kanal" stand ein Satz ueber das
ANTIPPEN von Personen -- also ueber den naechsten Schritt, nicht ueber
die Wahl, die gerade ansteht. Wer die beiden Woerter zum ersten Mal
sieht, erfuhr nirgends, was sie bedeuten.

Der Unterschied ist nicht "wenige/viele Leute", sondern WONACH der Raum
benannt ist: ein Gespraech nach den Menschen darin, ein Kanal nach
einem Thema. Daran haengt alles Weitere -- dass es einen Kanal je
Zustaendigkeit nur einmal gibt (eindeutiger Index, nachgesehen), dass
sein Name festliegt, dass die Teamleitung immer dabei ist
(kanaeleAngleichen, nachgesehen) und dass Leute wechseln koennen, ohne
dass der Raum ein anderer wird. Genau das steht jetzt da, und nichts
davon ist behauptet.

2) "die person die ihn oeffnet soll auch das recht haben das zu
loeschen und so dass es dan fuer jeden geloescht ist. aber nur die
person die es gruendet."

Ein EIGENER Weg (/ganz), kein Zusatzfeld am bestehenden. Es gibt jetzt
zwei Loeschknoepfe nebeneinander, und sie tun etwas sehr Verschiedenes:
Wegraeumen ist nur bei mir, Aufloesen ist fuer alle und endgueltig. Ein
vergessenes Feld waere genau dieser Unterschied gewesen. Aus demselben
Grund ein anderes Zeichen und eine eigene Warnfarbe -- zwei gleich
aussehende Papierkoerbe waeren eine Falle.

Nur der Gruender, woertlich: nicht die Teamleitung, nicht DogFather,
nicht wer `leitung` in der Gruppe hat. Nicht bei Zweier-Gespraechen --
dort gibt es keinen Gruender, und "niemand nimmt einem anderen die
Unterhaltung weg" gilt weiter.

Reihenfolge beim Loeschen ist nicht beliebig: erst das Live-Ereignis
(chatEreignis liest die Teilnehmer aus der Tabelle -- danach waere die
Liste leer), dann die Zeilen in EINER Transaktion, dann die Anhaenge
von der Platte. Umgekehrt haetten wir bei einem Ruecklauf Nachrichten,
die auf geloeschte Dateien zeigen.

WAS DIE PRUEFUNG GEFUNDEN HAT, BEVOR ES JEMAND GEMERKT HAETTE: Der
Knopf blieb unsichtbar, obwohl das Recht stimmte. Die Oberflaeche holt
den offenen Raum aus dem Nachrichten-Weg, nicht aus der Raumliste --
zwei Wege, ein Raumobjekt, und nur einer kannte das neue Feld. Die
Regel steht jetzt in darfAufloesen() und wird von allen dreien
benutzt: Liste, Nachrichten-Weg und der Loeschweg selbst.

Gefunden hat das die Pruefung, weil sie den KNOPF misst und nicht das
Recht dahinter. Haette sie nur `darf_aufloesen` geprueft, waere sie
gruen gewesen und der Knopf nie erschienen.

NEU: server/pruef-chat-aufloesen.mjs (59 Pruefungen). Sie misst am
BESTAND, nicht an der Antwort: ob der Raum wirklich aus der Datenbank
weg ist, ob keine Teilnehmerzeile liegen blieb, ob der Anhang von der
Platte verschwand -- und mit Gegenprobe, dass der Anhang-Ordner selbst
stehen bleibt. Ohne die waere "Datei ist weg" auch dann gruen, wenn es
sie nie gab; genau das ist beim ersten Lauf passiert (der Upload lief
ins 415, weil ich ihn als Formular statt roh geschickt hatte).

Dazu: Wegraeumen ist NICHT Aufloesen (Ben raeumt weg, Cem hat alles
noch), ein Zweier-Gespraech laesst sich gar nicht aufloesen, ein
Aussenstehender bekommt 404 statt 403, ein zweiter Versuch findet
nichts, und die Zustaendigkeit eines aufgeloesten Kanals wird wieder
frei (sonst haette der eindeutige Index sie dauerhaft blockiert).

Nebenbei: Die drei Kopfknoepfe schoben sich jeder einzeln mit
`margin-left: auto` nach rechts. Bei zwei sichtbaren teilen sich zwei
auto-Raender den freien Platz und reissen sie auseinander -- und WELCHE
sichtbar sind, entscheidet der Server. Jetzt schiebt ein Behaelter
einmal, die Knoepfe stehen beieinander, egal wie viele es sind.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 15:22:09 +02:00
DogFatherGitandClaude Opus 5 14ed467928 Der Weg ueber die TikTok-Datei des Creators ist entfernt
Filipe, mit den drei Knoepfen im Bild: "ich will nur dass wir manager
scouts, dogfather oder spicy sachen eintragen koennen und nicht die
creator. ich will keine daten von denen kriegen, nur wir."

Gebaut am Vormittag, am Nachmittag wieder ausgebaut. Der Weg war
technisch in Ordnung -- und er war der einzige, bei dem ein CREATOR uns
etwas gibt: seine eigene Datenkopie aus der TikTok-App. Genau das soll
nicht sein. Es bleiben die beiden Wir-Wege: die eigene Datei und die
Backstage-Tabelle der Agentur.

VOLLSTAENDIG ENTFERNT, NICHT VERSTECKT:
- beide Schnittstellen (/tiktok-datei und /tiktok-datei/vorschau)
- der Leser workspace-tiktok-datei.js (263 Zeilen)
- Knopf, Fenster, Dateiauswahl, Vorschau, Stilregeln
- der fertige Text, der einen Creator um seine Daten bittet
- der Erklaersatz unter der Knopfreihe

Ein Weg, der nur unsichtbar ist, ist weiterhin ein Weg -- wer die
Adresse kennt, benutzt ihn. Und eine Bitte an einen Creator um seine
Daten soll in diesem Haus nirgends mehr stehen, auch nicht in einem
Fenster, das niemand oeffnet.

GEPRUEFT WIRD JETZT DIE ABWESENHEIT, an drei Stellen: Knopf weg,
Fenster weg, und die Schnittstelle antwortet DOGFATHER mit 404 -- dem
staerksten Zugang, den es gibt. Bekommt er 404, bekommt ihn jeder.
Daneben die Gegenprobe, dass der Backstage-Weg weiterhin mit 200
antwortet; sonst bewiese das 404 nur einen Tippfehler.

pruef-tiktok-datei.mjs (47 Pruefungen) faellt mit dem Weg weg. Die
Zahl sinkt dadurch, und das ist hier richtig: Sie pruefte etwas, das
es nicht mehr gibt. Was bleibt, sind sechs Pruefungen, die das
Fehlen sichern -- pruef-backstage-import 63 -> 66.

NEBENBEI GEDREHT, NICHT GELOESCHT: pruef-leistung-optik behauptete
noch die Regel vom 07.09. ("beim Manager fehlt die Kachel", "die Seite
weist den Creator ab"). Beide Aussagen sind jetzt umgekehrt und messen
zusaetzlich, was vorher niemand gemessen hat: dass die Creatorin auf
der Zahlen-Seite ihre EIGENEN Zahlen sieht und trotzdem keinen
einzigen Knopf zum Eintragen hat -- beides zusammen, denn "keine
Knoepfe" waere auch auf einer leeren Seite wahr. 56 -> 59.

Nicht von mir, nachgemessen gegen den Stand ohne diese Aenderungen:
pruef-struktur meldet dieselben 6 Fehler (crew-index/teamlage nicht
verlinkt, start.css 348 KB, totes CSS .nase, UTC-Datum).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 15:02:21 +02:00
DogFatherGitandClaude Opus 5 b34586be91 Die Agentur-Umstellung schreibt den Bauplan nicht mehr ab
Sie baute `eintraege` mit einer von Hand abgeschriebenen Spaltenliste
neu. 24 Spalten gingen hinein, 21 kamen heraus: einsatz, nur_leitung
und gesendet_am wurden vom Spalten-Nachtrag angelegt und unmittelbar
danach weggeworfen -- mit Inhalt, ohne Fehlermeldung, bei
unveraenderter Zeilenzahl.

DAS WAR DAS ZWEITE MAL. Am 07.09.2026 fehlten an derselben Stelle die
drei Event-Spalten; sie wurden nachgetragen, und daneben kam ein
Kommentar, der woertlich vor genau dieser Verlustart warnt. Seither
kamen drei neue Spalten dazu, und die Liste wurde still falsch. An
einer anderen Stelle im selben Modul steht sogar schon der Satz: "Eine
vierte Abschrift waere die vierte Gelegenheit dazu."

Jetzt uebernimmt checkListeErweitern -- dieselbe Funktion, die alle
spaeteren Bereiche umstellt. Sie holt den Bauplan aus sqlite_master
und die Spalten aus PRAGMA table_info: eine Liste, die nicht gepflegt
wird, kann nicht veralten. Sichern, Zeilen innerhalb der Transaktion
zaehlen, Indizes mitnehmen, Verweise pruefen -- alles, was der Block
auch tat. 90 Zeilen weniger.

NACHGEMESSEN, in dieser Reihenfolge:
- pruef-agentur: 31 Fehler + Absturz -> 62 Pruefungen, alle gruen.
- Die Umstellung meldet jetzt 24 Spalten statt 21.
- Der echte Fall ist durchgespielt: Auf einer Datenbank, die 'agentur'
  schon kennt, laeuft sie GAR NICHT mehr an. Neue Pruefung dazu, die
  die Sicherungsdateien zaehlt (genau eine, trotz mehrerer Neustarts)
  -- gemessen an der Spur, die ein Umbau hinterlaesst, nicht an der
  Absicht.
- Die Datenbank auf dem Server hat alle drei Spalten und kennt
  'agentur' bereits. Sie war nie in Gefahr; gefaehrlich war das
  Zurueckspielen einer Sicherung von vor dem 06.09.2026.

ZWEI ALTE PRUEFFEHLER LAGEN DAHINTER, beide bisher von einem Absturz
verdeckt:
- "der Wochenbericht kennt 6 Bereiche" -- eine feste Zahl, inzwischen
  sind es elf. Verglichen wird jetzt gegen die CHECK-Regel der
  Datenbank; damit stimmt sie auch beim zwoelften Bereich.
- Die Meldung wurde am Satzbau erkannt statt an der Aussage.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 14:43:14 +02:00
DogFatherGitandClaude Opus 5 c98aa06554 pruef-agentur kann jetzt sagen, woran sie scheitert
Sie meldete 31-mal "FEHL" und HTTP 503 -- und kein einziges Wort dazu,
warum. Die Serverausgabe hat sie immer schon mitgeschrieben, aber nur
gezeigt, wenn der Server gar nicht erst hochkam. Faellt er spaeter mit
einem Datenbankfehler um, war sie weg.

Dazu kam: Playwright wirft bei einem fehlenden Knopf eine Ausnahme, der
Prozess stirbt, und mit ihm die Zusammenfassung. Genau dann braucht man
sie am dringendsten. Deshalb haengt die Ausgabe jetzt auch an
uncaughtException und unhandledRejection.

Mit SERVERLOG=<datei> kommt das Protokoll vollstaendig heraus -- die
letzten 1800 Zeichen zeigen den Schaden, nicht immer seine Ursache.
Genau daran lag es hier: Der Verlust stand ganz oben, der Fehler ganz
unten.

WAS DAMIT IN EINEM LAUF SICHTBAR WURDE (Befund, noch nicht repariert):

  [workspace] Spalte 'einsatz' in eintraege ergaenzt.
  [workspace] Bereich 'agentur' freigeschaltet, 5 Eintraege
  [workspace] Bereich lesen: no such column: e.einsatz

Die Spalte wird angelegt und unmittelbar danach wieder verworfen. Die
einmalige 'agentur'-Umstellung baut `eintraege` mit einer FEST
EINGETRAGENEN Spaltenliste neu -- 24 Spalten gehen hinein, 21 kommen
heraus. Verloren gehen einsatz, nur_leitung und gesendet_am: die drei,
die nach dem 07.09.2026 dazukamen.

Der Kommentar an genau dieser Stelle warnt woertlich vor dieser
Verlustart -- damals fuer die drei Event-Spalten, die deshalb
nachgetragen wurden. Die Liste war am 07.09. richtig und ist seither
still falsch geworden. Dieselbe feste Zahl, dieselbe Falle, drittes
Mal.

DIE ECHTEN DATEN SIND NICHT BETROFFEN, nachgemessen statt vermutet: Die
Datenbank auf dem Server hat alle drei Spalten, und ihr CHECK kennt
'agentur' bereits -- die Umstellung laeuft dort nie wieder. Gefaehrlich
wird es erst beim Zurueckspielen einer Sicherung von vor dem
06.09.2026: Dann werden die drei Spalten angelegt und sofort samt
Inhalt weggeworfen, ohne Fehler, bei unveraenderter Zeilenzahl.

Die Reparatur waere, die Liste nicht zu schreiben, sondern aus
PRAGMA table_info abzuleiten -- so wie es checkListeErweitern fuer alle
spaeteren Bereiche schon macht. Das ist ein Eingriff in einen
Wanderungsweg auf echten Daten und wartet auf Filipes Wort.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 14:36:09 +02:00
DogFatherGitandClaude Opus 5 915a4ae07c Spicy Media sieht die Zahlen wieder -- und eine Creator-Liste enthaelt nur Creator
Zwei Dinge, das zweite habe ich nur gefunden, weil das erste eine
Pruefung rot gemacht hat.

1) DIE SPICY-SPERRE IST AUFGEHOBEN.
Filipe: "jetzt soll jede rolle diese kachel sehen. spicy, dogfather,
manager, scout und creator ... der manager scout dogfather oder spicy
koennen eintragen."

Kachel und Tuer hatte ich schon geoeffnet -- es reichte nicht. In
workspace-leistung.js sass eine dritte Schranke, die Spicy Media mit
404 abwies (Rest des Wunsches vom 07.09.). Folge: Die Seite lud, das
Auswahlfeld blieb leer, und es sah aus wie ein Fehler. Drei Schichten
mussten zustimmen, und die dritte stand woanders als die beiden
ersten.

Nebenwirkung, ausdruecklich: Damit stehen im Dashboard wieder
Diamanten, LIVE-Tage und Verweildauer je Creator-Karte. Das war der
zweite Teil der damaligen Entscheidung und faellt mit ihr weg.

Die Pruefung in pruef-spicy wurde nicht geloescht, sondern GEDREHT --
sie schlaegt jetzt an, wenn jemand die Sperre versehentlich wieder
einbaut.

2) EINE LISTE VON CREATOR-NUMMERN ENTHIELT KEINE CREATOR.
Beim Drehen fiel auf: Spicy Media bekam "Agentur, Filipe, Luna, Max,
NeuerCreator, NeuerManager" -- DogFather nur "Luna, NeuerCreator".

Ursache: `ohneVerborgene` schreibt ein `null` ("sieht alles") zu einer
echten Liste aus, sobald es etwas zu verbergen gibt -- zur Liste ALLER
Personen, weil sie nicht wissen kann, wovon "alles" gerade handelt.
Bei DogFather greift das nie (er verbirgt nichts vor sich selbst), bei
Spicy Media schon. Der Aufrufer baut daraus ein `IN (...)` OHNE
Rollenfilter, und damit wurden Manager und Scouts zu Creators.

Repariert an der Wurzel, nicht beim Aufrufer: Es gibt zehn Aufrufer,
und neun richtig plus einen vergessen sieht man nie. Der Name der
Funktion ist das Versprechen -- es wird jetzt dort eingeloest, wo der
Name steht.

AUFGEFALLEN IST ES, WEIL EINE PRUEFUNG DIE BEIDEN LISTEN VERGLICHEN
HAT, statt bei jeder einzeln "ist nicht leer" zu sagen. Genau dieser
Unterschied steht jetzt als eigene Aussage drin.

Gemessen: pruef-backstage-import 50 -> 63 (Manager und Spicy Media
kamen dazu, inklusive der Aussage, dass Spicy Media MEHR Creator sieht
als ein Manager), pruef-spicy 60 -> 62. Dazu gruen: betreuung,
manager-sicht, verborgen, haus-trennung, sicht, aufgabenbrett,
schulung, steckbrief, uebersicht, leistung, tiktok-datei,
fremde-sicht, personen-liste, creator-anlegen, ampel, tagesblick.

NICHT von mir: pruef-agentur meldet 31 Fehler (HTTP 503). Gegen den
Stand ohne meine Aenderungen nachgemessen -- dort dieselben 31. Ein
aelterer, eigener Befund, unangetastet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 14:19:43 +02:00
DogFatherGitandClaude Opus 5 8d3a79ed2a Zahlen-Seite: wieder fuer alle fuenf Rollen
Filipe, mit der Kachel im Bild: "jetzt soll jede rolle diese kachel
sehen. spicy, dogfather, manager, scout und creator. aber die creator
kriegen dan quasi nur ihre daten zu sehen und der manager scout
dogfather oder spicy koennen eintragen."

Damit ist die Sperre vom 07.09.2026 aufgehoben. Geaendert sind genau
zwei Zeilen -- die Kachel in bereiche.js und die Tuer in workspace.js.
Ausdruecklich als Liste der fuenf Rollen, NICHT als `null`: `null`
hiesse auch jede Rolle, die es noch nicht gibt.

WER WAS DARF, musste ich nicht bauen -- es stand schon da und konnte
nur niemand benutzen: sichtbareCreatorIds() gibt einem Creator genau
seine eigene Nummer, darfEintragen() ist Leitung plus Scout. Das ist
exakt Filipes Satz, ohne eine einzige Aenderung am Server.

WAS DER UMBAU AUFGEDECKT HAT: "Aus Datei einlesen" hatte als einziger
Knopf NIE eine Rechteregel -- folgenlos, solange nur DogFather
hereinkam, ab heute haette ein Creator ihn gesehen und eine Absage
bekommen. Alle drei Eintrag-Knoepfe stehen jetzt in EINER Liste mit
ihrer Regel daneben, und der Knopf startet `hidden`, damit er nicht
kurz aufblitzt.

Gefunden hat das nicht das Nachdenken, sondern die Gegenprobe von
heute Mittag: Sie wurde rot, weil der Test-Scout auf der Startseite
landete -- waehrend ich nebenan eine Erklaerung "fuer Scouts und
Manager" schrieb fuer eine Seite, die beide gar nicht oeffnen konnten.

pruef-backstage-import: 36 -> 50 Pruefungen. Gemessen wird der
UNTERSCHIED zwischen den Rollen, nicht die Anwesenheit von irgendetwas:
jeder Knopf einzeln, bei Scout und Creator, dazu die Kachel auf der
Startseite und die Gegenprobe, dass die Zahlen des Creators trotzdem
dastehen. Sonst waere "der Creator sieht keinen Knopf" auch dann gruen,
wenn seine Seite leer bliebe.

Mit SCHIRM=1 legt die Pruefung zwei Bilder ab, eins je Rolle.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 14:05:03 +02:00
DogFatherGitandClaude Opus 5 f171d0cffd Workspace: Anleitung neben beiden Import-Knoepfen
Scouts und Manager sollen nicht raten muessen, woher die Zahlen kommen.

Unter der Knopfreihe steht jetzt dauerhaft (sobald einer der beiden Knoepfe
sichtbar ist), was die beiden Quellen sind: Backstage-Tabelle = Agenturzahlen
fuer alle auf einmal, TikTok-Datei = die Datei, an die nur der Creator selbst
kommt.

Backstage-Dialog: fuenf nummerierte Schritte. Der wichtigste davon ist
"Ueberschriftenzeile mitmarkieren" -- ohne sie kann der Server die Spalten
nicht benennen, und genau das war beim Testen der haeufigste Fehlgriff.
Dazu zwei stille Absaetze: woher die Zuordnung kommt (TikTok-Name im
Steckbrief) und warum das nicht automatisch geht.

TikTok-Dialog: der fertige Text zum Weiterleiten an den Creator, mit
Kopierknopf. Nennt JSON statt TXT (eine TXT-Datei laesst sich nicht
auswerten), die 1-4 Tage Wartezeit, und dass die Datei nur gelesen und
nicht gespeichert wird.

Bewusst KEIN erfundener Klickpfad durch Backstage: TikTok dokumentiert die
Menuenamen nirgends oeffentlich, und eine erfundene Beschriftung ist beim
naechsten Umbenennen schlimmer als keine. Beschrieben wird deshalb, WORAUF
zu achten ist ("die Tabelle mit den Zahlen"), das bleibt wahr.

Der Kopierknopf meldet einen Fehlschlag, statt Erfolg vorzutaeuschen.

pruef-backstage-import: 29 -> 36 Pruefungen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 13:51:00 +02:00
DogFatherGitandClaude Opus 5 5487b94f73 Die fremde Sicht kam nur auf der halben Seite an
Gefunden beim Nachmessen von Filipes Meldung "die dogfather rolle sieht
die creator nicht mehr". Nichts war kaputt -- er war in einer fremden
Sicht. Dabei fiel aber etwas anderes auf:

DREI ENDPUNKTE LASEN `req.person`, WO IHRE NACHBARN `req.sicht ||
req.person` LESEN.

  /workspace/api/report/creator      (workspace-reports.js)
  /workspace/api/startcheck/creator  (workspace-startcheck.js)
  /workspace/api/uebersicht/creator  (workspace-aufgaben.js)

Folge: Die Zahlen einer Seite folgten der angesehenen Person, die
Creator-Auswahl daneben zeigte die EIGENEN. Zwei Antworten auf eine
Frage, und beide sahen fuer sich richtig aus. In reports.js stehen die
beiden Zeilen keine zwanzig auseinander.

Gemessen vorher/nachher in der Sicht von Miesmuschel:
  report/creator      6 Eintraege  ->  2 (Alle Creator + sie)
  startcheck/creator  5 Eintraege  ->  kein Umschalter, ihr eigener
  uebersicht/creator  alle         ->  nur sie

DER START-CHECK ZEIGT JETZT GAR KEINEN UMSCHALTER MEHR, und das ist
richtig: Bei `eigen: true` blendet die Seite ihn aus und zeigt den
Start-Check der angesehenen Person direkt -- genau das, was sie selbst
saehe. Mein erster Messwert las "0 Eintraege" und sah nach Fehler aus;
er hiess "kein Umschalter". Eine Zaehlung, die Verstecktes und Leeres
nicht unterscheidet, misst hier das Falsche.

WAS ABSICHTLICH NICHT MITGEAENDERT WURDE
/workspace/api/personen bleibt beim Angemeldeten. Diese Liste fuellt
die Auswahl "zu wem gehoert dieser Eintrag" -- also eine SCHREIB-
Auswahl. Die Regel steht seit dem 02.09. in workspace.js:

  "WER BIN ICH (fuer alles, was SCHREIBT) und WESSEN ARBEITSPLATZ SEHE
   ICH (fuer das, was gezeigt wird). Die beiden zu vermischen waere der
   sichere Weg dazu, dass irgendwann etwas unter fremdem Namen
   gespeichert wird."

Wuerde sie der Sicht folgen, koennte DogFather in einer fremden Sicht
nur noch Eintraege fuer diese eine Person anlegen -- ein stiller
Verlust von Handlungsfaehigkeit an einer Stelle, an der man ihn nicht
vermutet. Damit sind auch content.html und bereich.html zu Recht
unveraendert: Das sind Eingabeformulare, keine Ansichten.

NEUE PRUEFUNG (pruef-fremde-sicht, 12 Pruefungen)
Sie haelt beide Haelften der Regel fest -- Anzeigen folgt der Sicht,
Schreiben nicht -- und hat drei Gegenproben: dass dieselbe Abfrage mit
und ohne Sicht wirklich Verschiedenes liefert, dass eine Sicht auf
jemand anderen auch jemand anderen zeigt (sonst waere "Nova" nur
zufaellig der erste Eintrag), und dass eine erfundene Nummer keine
Sicht oeffnet. Drei Creator statt einem: Mit einem einzigen saehen
"alle" und "nur dieser" gleich aus.

Nebenbei geprueft: pruef-verwaltung-app, das im Sommer mit
MODULE_NOT_FOUND scheiterte, gibt es nicht mehr -- der Punkt ist
erledigt. Alle 132 Pruef- und Werkzeugdateien sind syntaktisch heil.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 13:24:17 +02:00
DogFatherGitandClaude Opus 5 027c372afd Die TikTok-Datei des Creators -- ohne Entwicklerkonto
Filipe: "tiktok entwicklerkonto hab ich nicht und werd ich nicht
bekommen."

Damit sind zwei der drei Wege aus dem Plan vom 10.09. erledigt: Login
Kit und die Datenportabilitaets-API haengen beide an einer App auf
developers.tiktok.com. Sie sind nicht verschoben, sie sind weg.

DER DRITTE BRAUCHT KEINES. Jeder TikTok-Nutzer kann seine eigenen Daten
selbst herunterladen (Profil -> Einstellungen -> Konto -> Deine Daten
herunterladen, Format JSON). Die Datei enthaelt laut TikToks eigener
Datentypen-Liste einen Abschnitt "TikTok LIVE" mit dem Go-LIVE-Verlauf.
Der Creator gibt sie her, mit eigenen Haenden -- legitimer wird es
nicht, und es ist jetzt der einzige verbliebene Weg an TikTok-Daten.

ICH KENNE DAS FORMAT NICHT -- UND BAUE TROTZDEM.
TikTok dokumentiert, DASS es den Verlauf gibt, nicht wie die Schluessel
heissen. Der naheliegende Weg waere, Namen zu raten. Das waere die
schlechteste Loesung: Er fiele bei der ersten echten Datei auseinander,
und zwar STILL -- "0 Eintraege gefunden" sieht aus wie "war nicht live".

Deshalb wird gesucht statt geraten. Der Leser geht die Datei durch,
sammelt ALLE Listen, deren Eintraege ein Datum tragen (gemessen am
INHALT, nicht am Feldnamen), schlaegt eine Zuordnung vor und legt sie
zur Auswahl vor -- mit Anzahl, Zeitraum, Beispielzeile und dem, was
dabei herauskaeme. Bestaetigt wird von Hand. Damit ist der Leser
unabhaengig davon, wie die Felder heissen.

DIE EINHEIT IST DIE FALLE. "83" kann Sekunden, Minuten oder Stunden
sein. Geraten wird NICHT aus der Zahl, sondern aus dem Schluesselnamen
-- und wo der schweigt, aus der Form ("01:23:45" ist eindeutig).
Schweigen beide, kommt null zurueck. Eine Dauer, die um Faktor 60
danebenliegt, sieht richtig aus und ist es nicht.

MEHRERE LIVES AN EINEM TAG SIND EIN TAG: Dauer und Diamanten addiert,
bei den Zuschauern gewinnt die hoehere Spitze -- ein Durchschnitt aus
zwei Streams waere eine Zahl, die es nie gegeben hat.

DIE DATEI UEBERSCHREIBT NICHTS. Anders als der Backstage-Import, der
die Wahrheit der Agentur bringt, ist diese Datei die ZWEITE Quelle. Wo
schon eine Zahl steht -- von Hand oder aus Backstage --, bleibt sie
stehen (COALESCE statt REPLACE). Sonst wuerde ein Dateiupload
stillschweigend die offiziellen Zahlen ersetzen, und niemand wuesste
hinterher, welche gilt.

UND SIE WIRD NICHT GESPEICHERT. Gelesen, ausgewertet, verworfen. In
derselben Datei stehen Direktnachrichten, Such- und Ansehverlauf; die
haben auf diesem Server nichts zu suchen. "Income and Wallet" bleibt
ebenfalls liegen: Diamanten sind Leistung, Auszahlungen sind Gehalt.

GEPRUEFT OHNE ECHTE DATEI -- MIT DREI ERFUNDENEN (47 Pruefungen):
  A  englisch, flach, Dauer in Sekunden
  B  deutsch, verschachtelt, Dauer als "01:23:45"
  C  Sekundenstempel, Dauer in Minuten, andere Namen
  +  eine Datei ganz ohne Verlauf -> muss abgelehnt werden

Eine Pruefung gegen EINE ausgedachte Form wuerde nur beweisen, dass
mein Leser meine eigene Erfindung liest. Drei verschiedene zeigen, dass
er das Prinzip kann und nicht eine Form.

EIN EIGENER FEHLER, von der Pruefung gefunden: Der Nachrichtenverlauf
in Form A hatte nur EINEN Eintrag und fiel damit unter die
Mindestgroesse von zwei. Die Pruefung "der LIVE-Verlauf steht oben"
hatte danach nur einen Kandidaten und bewies gar nichts -- eine
Rangfolge laesst sich nur an mindestens zwei Dingen zeigen. Jetzt sind
es drei Nachrichten, und die Rangfolge ist wirklich gemessen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 12:01:49 +02:00
DogFatherGitandClaude Opus 5 017375d333 Backstage: eine Tabelle einfuegen, alle Creator auf einmal
Filipe: "mach diesen ganzen plan jetzt sofort auf einen schlag fertig."

Das ist Stufe 0 des Plans vom 10.09. -- der Teil, der ohne TikTok
auskommt und deshalb sofort baubar war.

WARUM EINFUEGEN UND NICHT ABRUFEN. Die Recherche vom 10.09. ergab:
TikTok LIVE Backstage hat keine Schnittstelle und keinen Export (zwei
unabhaengige Quellen), und in der offiziellen Scope-Liste von TikTok
gibt es nichts zu LIVE, Diamanten oder Netzwerkdaten. Was es gibt, ist
eine Tabelle im Browser. Also: markieren, kopieren, einfuegen. Kein
Token, kein Zugangsdatum, keine Erweiterung, die Backstages interne
Abfragen mitliest -- letzteres waere ein Verstoss gegen die
Nutzungsbedingungen und riskiert ausgerechnet das Netzwerkkonto.

DER UNTERSCHIED ZUM VORHANDENEN IMPORT ist genau eine Frage: Zu wem
gehoert diese Zeile? Der alte Weg nimmt eine Datei fuer EINEN Creator,
Backstage zeigt ALLE. Zugeordnet wird ueber `personen.tiktok` -- den
oeffentlichen Namen ohne @, den es im Steckbrief laengst gibt. Ohne @,
ohne Gross-/Kleinschreibung, ohne unsichtbare Zeichen aus der
Zwischenablage; faellt das aus, ueber den angezeigten Namen. Beides
ergebnislos -> die Zeile wird GEMELDET, nicht geraten. Eine falsch
zugeordnete Zahl ist schlimmer als eine fehlende, weil die fehlende
auffaellt.

DER TABULATOR WAR DER GANZE KNACKPUNKT. `csvZerlegen` kannte nur Komma
und Semikolon. Eine aus dem Browser kopierte Tabelle ist aber
TAB-getrennt -- ohne diese Zeile waere alles in Spalte 1 gelandet und
die Vorschau haette "keine Datumsspalte" gemeldet: eine richtige
Meldung auf eine falsche Faehrte. Gewaehlt wird jetzt das HAEUFIGSTE
der drei Zeichen, nicht das erste gefundene.

WAS NICHT PASSIERT, und genau das ist geprueft:
  - unbekannte Person -> gemeldet mit Namen, nicht geraten
  - Zeile ohne eine einzige Zahl -> uebersprungen (sie wuerde sonst
    einen echten Tag mit Nullen ueberschreiben)
  - Datum in der Zukunft -> abgelehnt
  - dieselbe Tabelle zweimal -> ersetzt, verdoppelt nicht
  - eine von Hand geschriebene Notiz -> ueberlebt den Import
  - es wird niemand nebenbei angelegt
  - kein Datum in der Tabelle und keines angegeben -> es wird GEFRAGT

NEUE PRUEFUNG (pruef-backstage-import, 29 Pruefungen) mit einer echten,
tab-getrennten Backstage-artigen Tabelle: drei Creator, einer davon
ohne Handle, einer mit abweichender Schreibweise, einer gar nicht im
Haus.

DREI EIGENE FEHLER, alle von der Pruefung gefunden:
  * Die Spaltenerkennung nahm nur EINE Personenspalte. Ein Creator ohne
    Handle fiel als "keine Person in der Zeile" durch, obwohl sein Name
    danebenstand. Jetzt werden beide Spalten gemerkt und je Zeile
    nacheinander versucht.
  * Ein Scout bekam 400 statt 403 -- er kam durch `darfEintragen`
    (das Scouts einschliesst) und scheiterte erst daran, dass er keinen
    der Creator sieht. Richtige Antwort aus dem falschen Grund. Der
    Netzwerk-Weg haengt jetzt an `istLeitung`, genau wie der Knopf.
  * Die Vorschau meldete "2 von 3" statt "3 von 4" -- Folge des ersten
    Fehlers.

Der Fusstext der Seite nannte zwei Wege, es sind jetzt drei. Ein Text,
der etwas anderes sagt als die Software tut, ist schlimmer als keiner.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 11:26:14 +02:00
DogFatherGitandClaude Opus 5 a9dcb8f59a Die Scout-Pipeline: 13 Felder statt 5, und getrennt von Team Dogi
Filipe: "perfektionnier diese kategorien wie die aussehen und was man
da noch alles immer in jeder kategorie eintragen kann. weil man kan da
nichts machen ... und das soll getrennt von der team dogi seite sein."

"MAN KANN DA NICHTS MACHEN" -- MAN KONNTE, UND DAS WAR DAS PROBLEM.
Der ganze Editor lag hinter einem stillen Textknopf namens "Details".
Ein Wort, das Lesen verspricht, an der einzigen Stelle, an der man
aendert. Er heisst jetzt "Bearbeiten", hat eine Kante und ein
aria-expanded. Aktivitaet und Potenzial waren dort ausserdem nur
ANZEIGE -- eintragen liessen sie sich ausschliesslich beim Anlegen.
Jetzt sind es Felder wie alle anderen.

SIEBEN NEUE FELDER, und keines davon ist Schmuck:
  netzwerk      schon bei einer Agentur? Die teuerste Frage der ganzen
                Pipeline -- wer unter Vertrag steht, kann nicht
                uebernommen werden. Steht auf der Karte VOR der
                Prioritaet, rot. "unbekannt" ist eine eigene Antwort und
                nicht dasselbe wie "nein".
  land          DE/AT/CH/LU/andere -- die vier Laender, in denen betreut
                wird, und die Schweiz liegt rechtlich anders als die
                drei EU-Laender (TikTok-Recherche vom 10.09.).
  follower      Reichweite. "12,4k" aus der Zwischenablage wird zu
                12400 -- sonst stuende da eine 12, und das faellt
                niemandem auf.
  woher         wie gefunden
  kontaktweg    wo angeschrieben
  live_zeiten   wann die Person ueblicherweise live ist
  absage_grund  erscheint NUR bei "Abgelehnt" -- ein "warum nicht" an
                einem Kontakt, der gut laeuft, ist eine Frage, die
                niemand gestellt hat.

Gemessen: 13 Felder im Editor statt 5.

DIE STUFEN ERKLAEREN SICH SELBST. Was "Interessiert" von "Gespraech"
unterscheidet, stand bisher nur im leeren Zustand der Seite -- also
genau so lange, bis der erste Kontakt da war. Der Satz steht jetzt an
der Stufe, und beide lesen aus derselben Liste (STUFE_WAS). Dazu eine
Kante im Ton der Stufe; die Farben gab es laengst, benutzt wurde nur
die Zahl.

GETRENNT VON TEAM DOGI -- und das war keine Formsache. `sichtbar()`
gibt fuer jeden mit `siehtAlles` schlicht `1=1` zurueck, und DogFather
hat `siehtAlles` auch auf der crew-Adresse. Die komplette Pipeline des
Workspace waere dort mitgekommen. Jetzt 404 fuer das ganze Modul,
sobald `haus === "crew"` -- nicht gefiltert, sondern nicht vorhanden.
Die Absperrung haengt an der gemeinsamen Schranke und gilt damit auch
fuer jeden Weg, der spaeter dazukommt.

NEUE PRUEFUNG (pruef-scouting-felder, 28 Pruefungen)
Sie misst alle drei Behauptungen: dass die Felder ankommen und
zurueckkommen, dass der Server Unsinn ablehnt (Land ausserhalb der
Liste, erfundene Netzwerk-Angabe, negative Follower) -- mit Gegenprobe,
dass das Richtige durchgeht -- und dass es die Pipeline auf crew. nicht
gibt. Dazu die Oberflaeche: Knopfname, Stufentext, die Fakten auf der
Karte, die Warnung, und die Zahl der Felder im Editor.

ZWEI EIGENE FEHLER AUF DEM WEG, beide von der Pruefung gefunden:
  * `notbremse(240)` -- der Wert ist in MILLISEKUNDEN. Die Pruefung
    brach nach einer Viertelsekunde mit "HING" ab, bevor sie anfing.
  * Der crew-Test meldete 200 und sah wie ein Befund aus. Tatsaechlich
    verwirft `fetch` einen selbst gesetzten `Host`-Kopf (verbotener
    Header) -- die Anfrage war nie auf der crew-Adresse. Jetzt ueber
    node:http, mit Gegenprobe, dass derselbe Weg ohne crew-Kopf
    weiterhin 200 liefert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 11:17:37 +02:00
DogFatherGitandClaude Opus 5 0ffb9e8781 Die Kategorien in Filipes Reihenfolge -- und das Band jetzt ueberall
Vier Meldungen von Filipe, drei davon erledigt.

1. "DIE DOGFATHER ROLLE SIEHT DIE CREATOR NICHT MEHR" -- NICHTS KAPUTT.
   Nachgestellt mit frischer Datenbank und fuenf Creator: DogFather
   sieht auf allen sechs Seiten mit Creator-Umschalter alle fuenf. In
   der SICHT VON MIESMUSCHEL dagegen steht auf leistung.html und
   profil.html genau einer -- ihr Name. Genau das zeigt sein
   Bildschirmfoto. Er ist noch in der fremden Sicht von gestern.

   MEINE SCHULD, NICHT SEINE. Gestern habe ich das Hinweis-Band
   ausdruecklich nur aufs Handy gelegt, mit der Begruendung, am Rechner
   stehe der Name ja im Umschalter und zwei Anzeigen fuer dieselbe
   Sache seien eine zu viel. Einen Tag spaeter ist er am RECHNER darauf
   hereingefallen, mit sichtbarem Namen im Umschalter UND goldenem
   Rahmen. Damit ist die Begruendung widerlegt -- nicht durch ein
   Argument, sondern durch den Fall. Das Band steht ab jetzt ueberall.

   NEBENBEFUND, NICHT ANGEFASST: Die fremde Sicht greift nur auf der
   Haelfte der Seiten. leistung und profil folgen ihr, bereich, content,
   report und startcheck zeigen weiter alle Creator. Halb umgesetzt ist
   schlechter als gar nicht -- das gehoert entschieden, nicht nebenbei
   geaendert.

2. "RUND UM DAS TEAM UEBER TAEGLICH" -- verschoben, mitsamt dem Absatz,
   der die alte Stelle begruendet hat.

3. "TEAM DOGI UND ENTWICKLUNG GANZ UNTEN, NUR DOGFATHER UND VANVAN".
   `gruppeNach: "Täglich"` -> `"Team & System"`, der letzten Gruppe der
   Liste. Als NAME und nicht als Position: Eine Zahl waere beim
   naechsten Umsortieren still falsch, und still falsch hiesse hier,
   dass privates Material wieder nach oben rutscht.

   DIE SICHTBARKEIT WAR SCHON RICHTIG -- nachgesehen statt angenommen:
   Auf der Workspace-Adresse bekommt die Kacheln nur `admin`. VanVan
   traegt die Rolle `hand` und kann sich dort gar nicht anmelden
   (sitzungPasstZurAdresse weist Team-Dogi-Rollen ab); sie sieht
   dieselben Kacheln auf der crew-Adresse ueber HAND_BEREICHE. Die
   Modis sehen sie nicht -- Entwicklung und Talente stehen nicht in
   MODI_BEREICHE. Am Livesystem geprueft: genau ein admin, eine hand.

   Gemessen kommt fuer DogFather heraus:
     Rund um das Team | Taeglich | Rund um den Creator | Team & System
     | Team Dogi | Entwicklung & Nachwuchs
   Spicy Media sieht dieselbe Folge ohne die letzten beiden, Manager
   und Creator wie bisher.

UND EINE PRUEFUNG, DIE DAS FALSCHE GEMESSEN HAT
pruef-start-ansicht wurde durch die neue Reihenfolge rot -- ohne dass
eine Kachel kleiner geworden waere. Sie las
`querySelector(".kachel__zeichen")`, also die ERSTE Kachel der Seite.
Solange "Taeglich" oben stand, war das zufaellig die grosse
Dashboard-Kachel. Die Pruefung hat damit nie belegt, was ihr Kommentar
behauptet ("die Kacheln sollen spuerbar groesser sein"), sondern nur
"die erste ist die grosse".

Jetzt misst sie die grosse Kachel ausdruecklich UND die kleinste aller
Kacheln, mit eigenen Untergrenzen. Das ist strenger als vorher: Vorher
konnte jede Kachel ausser der ersten beliebig schrumpfen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 11:04:39 +02:00
DogFatherGitandClaude Opus 5 ad47fc2b00 Team Dogi: Sternenfeld auf jeder Kachel, und die Sicht zeigt endlich, was sie verspricht
DER GRUND JEDER KACHEL IM HAUS VON TEAM DOGI

Filipe: "ich will dass die hintergrunde von den kacheln immer unviersum
artig ist, es muss richtig geil sein aber immer so dass man alles noch
gut erkkent. und das IN DER GANZEN WEBSITE VON TEAM DOGI. nur die
kacheln. [...] wichtig ist die form der kacheln soll gleich bleiben."

module.css hat eine kanonische KACHELLISTE -- 48 Klassen, siebenmal in
der Datei, von pruef-css-klassen gegeneinander gehalten. Eine achte
Abschrift in crew-haus.css waere die Sorte Fehler, die nicht auffaellt:
heute vollstaendig, bei der naechsten neuen Kachel lautlos nicht mehr.
Deshalb faerbt crew-haus.css keine einzige Kachel. module.css baut den
Grund jetzt aus vier Werten (--sternenfeld, -mass, -lage,
--modul-schleier), und das zweite Haus setzt nur diese vier um. Damit
hat jede Kachel der ganzen Adresse den Himmel -- auch die, die es noch
nicht gibt. Im Agenturhaus steht `none`: kein Pixel aendert sich.

ZWEI DINGE HAT ERST DIE MESSUNG GEFUNDEN, NICHT DAS NACHDENKEN:

1. Die Nebel standen zuerst oben links. Dort ist aber JEDE Kachel dieses
   Hauses schon von sich aus am hellsten -- ihr eigener Lichtverlauf
   laeuft bei allen aus derselben Richtung (155/150/158 Grad) --, und
   genau dort stehen ueberall die Ueberschriften. Hinter der leisesten
   Textzeile lagen dadurch 2,09 % der Bildpunkte unter 4,5:1; im
   Agenturhaus sind es an derselben Stelle 0,115 %. Nach dem Umzug in
   die beiden gegenueberliegenden Ecken: 0,22 % -- und der Nebel durfte
   dabei KRAEFTIGER werden (.80 statt .62), weil er nicht mehr auf dem
   hellsten Punkt liegt. Besser lesbar und deutlicher zu sehen; das ist
   selten und war hier umsonst zu haben.

2. Kleinere, dafuer hellere Sternkerne waren der falsche Weg: Der
   hellste Punkt blieb fast gleich, der Stern wurde nur unschaerfer.
   Entschieden hat die Deckkraft, nicht die Groesse.

Form unangetastet: Fase, Silhouette und die drei Eckwinkel werden vor
und nach dem Hauswechsel Zeichen fuer Zeichen verglichen.

pruef-kachel-universum.mjs (NEU, 37 Pruefungen, Port 4391) misst an
echten Bildpunkten und fragt nicht nach Durchschnitt allein, sondern
nach dem ANTEIL der Punkte unter 4,5:1 -- das unterscheidet einen Punkt
von einer Flaeche. Zwei Gegenproben: ein zu dunkler Text UND ein zu
heller Nebel muessen durchfallen.

MEINE SICHT -- "GENAU SO WIE SIE ES SEHEN"

Filipe: "oben bei meine sicht soll ich auch die sicht von allen jeden
moment sehen koennen und das genau genau so wie sie es sehen alles.
ausser die kalender daten oder chat daten wo ich nicht mit drin bin.."

Gemessen wurde nicht "mit Umschalter gegen ohne" -- das ist bei duenner
Datenlage ueberall gleich und beweist nichts. Gemessen wurde die
Antwort mit Umschalter gegen die Antwort, die die Person SELBST bekommt.
Das hat sechs Stellen gefunden:

* workspace-zentrale.js las `req.person.sicht` -- ein Feld, das es nicht
  gibt. Der Ausdruck war immer `undefined || req.person`, daneben ein
  ausfuehrlicher Kommentar, der genau das Richtige beschrieb. Die grosse
  Kachel zeigte verlaesslich die eigene Lage, waehrend die Zahlen
  darunter der fremden folgten -- zwei Wahrheiten in einer Kachel. Ein
  Tippfehler in einem Variablennamen macht nichts kaputt; er tut nur
  nichts, und genau deshalb faellt so etwas nie von selbst auf. Die
  Route hatte ausserdem ZWEI Personenvariablen; jetzt hat sie eine.
* sichtPerson() gab die angesehene Person ohne Feld `haus` zurueck --
  und nurHaus()/hausBedingung() fangen beide mit `haus !== "crew"` an.
  Jede fremde Sicht war damit eine Agentursicht: In der Sicht auf einen
  Modi kamen die Dateien, Personen und Berichte des anderen Hauses.
  Das Haus haengt jetzt an der ROLLE, nicht an der Adresse.
* leistung, profil, schulung, fruehwarnung, report und teamlage lasen
  weiterhin den Angemeldeten. Nur LESEN ist umgestellt, nie ein Recht --
  und weil DogFather ohnehin alles sehen darf, kann das nichts oeffnen,
  nur weniger zeigen.

Der Sicht-Umschalter zeichnete ausserdem nur die fuenf Rollen aus
bereiche.js; wer eine sechste hat, stand nicht darin. Dieselbe Luecke
wie in der Chat-Auswahl und der Personenliste, zum dritten Mal. Die
Ueberschrift kommt jetzt vom Server (`gruppe`), der Browser zeichnet,
was ankommt -- auch eine Rolle, deren Namen er nicht kennen darf.

DREI STELLEN FOLGEN BEWUSST NICHT: die Personenliste (aus ihr wird der
Umschalter gebaut -- folgte sie der Sicht, kaeme man aus einer fremden
nicht mehr heraus), die Auswahllisten beim Anlegen (Kategorien,
Empfaenger) und steckbrief/mein (ein Formular, das fremd liest und
eigen speichert, zerstoert Daten).

KALENDER UND CHAT BLEIBEN PRIVAT, auch mit Umschalter -- Termine,
Calls und Wiederholungen lesen ab jetzt immer die eigene Person. Eine
Pruefung musste dafuer umgedreht werden: pruef-sicht verlangte bis
heute das Gegenteil ("dafuer gibt es den Umschalter"). Die Gegenprobe
bleibt dieselbe Frage, nur andersherum -- Patrick selbst MUSS seine
Termine sehen, sonst hiesse "DogFather sieht sie nicht" nur, dass sie
niemand sieht. Dabei fiel auf, dass die Managerin gar keinen Call
hatte: Die Pruefung "bleibt privat" war nicht bestanden, sondern nicht
durchfuehrbar. Antwort darauf sind Daten, keine weichere Bedingung.

Gruen: pruef-sicht 84 (vorher 53), pruef-kachel-universum 37 (neu),
pruef-rollen 282, pruef-crew-adresse 129, pruef-start-ansicht 143,
pruef-kalender 104, pruef-haus-trennung 62, pruef-team-ampel 32,
pruef-team-stufen 26, pruef-css-klassen. Stempel 202609110209.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 02:10:15 +02:00
DogFatherGitandClaude Opus 5 9b47bd3ca0 Entwicklung & Nachwuchs -- zwei Bretter fuer DogFather und die rechte Hand
Filipe: "ich will dass ich genau so eine kategorie habe in der dogfather
und rechten hand rollen, wo wir aufgaben oder bewertungen ueber modis
eingeben koennen. auch fuer zuschauer die vielleicht modis werden
koennten waere auch geil. mach dich schlau informier dich so krass wie
es nur geht, hol die besten der besten und krassesten sachen,
perfektionnier die dan auch alle und dan erst setzt du alles um."

=== WAS DIE RECHERCHE ERGEBEN HAT ===

DREI BEFUNDE HABEN DAS DESIGN BESTIMMT, und der erste hat es fast
umgedreht:

  WARUM MODERATOREN AUFHOEREN (Schoepke-Gonzalez u. a., New Media &
  Society 2024): zwei Hauptgruende -- zu wenig Zeit, und Konflikte im
  Team beziehungsweise schaedliches Verhalten der Leitung. Eine
  Bewertungsfunktion ist damit genau das Werkzeug, mit dem man ein Team
  verliert, wenn man sie als Ueberwachung baut. Das ist kein Bauchgefuehl
  und keine Zimperlichkeit -- es ist der haeufigste gemessene Grund.

  WAS HAELT: Anerkennung. Dank und Rueckmeldung erhoehen die
  Verweildauer messbar; Rollenklarheit senkt Burnout.

  WORAN MAN GUTE MODERATOREN ERKENNT (ModSquad, Kitfox Games,
  Discord-Leitfaeden): nicht an Zahlen. Ruhig bleiben, wenn es hitzig
  wird; von selbst helfen; die Regeln UND die Leute kennen; regelmaessig
  da sein. Ausdruecklich NICHT: "schreibt viel" -- angenehm im Chat zu
  sein ist nachweislich etwas anderes. Und der treffsicherste Weg
  ueberhaupt ist die Empfehlung aus dem Team, gefolgt von einer
  Probezeit.

=== WAS DARAUS GEBAUT WURDE ===

ENTWICKLUNG. Keine Note, sondern eine Aufzeichnung ueber die Zeit, je
Person. Fuenf Arten, und ihre REIHENFOLGE ist Absicht: "Das laeuft gut"
und "Danke dafuer" stehen vorn. Wer ein Formular oeffnet, dessen erstes
Feld "Problem" heisst, schreibt Probleme auf.

"ZU VIEL GERADE" IST DIE WICHTIGSTE ART und die, die es sonst nirgends
gibt. Der haeufigste Grund zu gehen ist Zeitmangel, und der zeigt sich
frueh -- nur schreibt ihn niemand auf, weil es kein Feld dafuer gibt.

TALENTE. Die vier Merkmale sind die aus der Literatur, nicht
ausgedacht, dazu die Empfehlung aus dem Team. Der Status IST die
Probezeit: `offen` heisst beobachtet, `angenommen` heisst angesprochen
-- und was daraus wird, entscheidet sich in "Personen & Zugaenge" mit
einem Zugang auf Stufe "Probe". Eine eigene Kandidatentabelle waere ein
zweiter Ort fuer dieselbe Frage.

DIE BRUECKE. Die Person sieht den Entwicklungs-Bereich NICHT -- eine
halb sichtbare Akte ist schlimmer als eine geschlossene, weil niemand
mehr weiss, was der andere gerade liest. Damit Anerkennung trotzdem
ankommt, laesst sich jeder Eintrag EINMAL als Nachricht in den Chat
schicken, mit Art, Titel und dem, was daraus folgen soll. Danach steht
im Eintrag, wann es geschehen ist: Die Frage "habe ich ihr das
eigentlich schon gesagt?" beantwortet man nach zwei Wochen falsch.

ZWEI KACHELN UND NICHT DREI: Aufgaben an das Team gibt es laengst, mit
Person, Frist und Status. Eine zweite Stelle dafuer waere ein zweiter
Ort, an dem man nachsehen muesste, welche Aufgabe wirklich gilt.

DIE GRUPPE HEISST NICHT "TEAM FUEHREN". Das waere der bequeme Name und
der falsche: Im Haus gilt, dass DogFather nicht ueber seinem Team steht.
"Entwicklung & Nachwuchs" sagt, was drinsteht.

=== KEIN NEUER BAUKASTEN ===

Beides sind BEREICHE wie das Ideen-Board: dieselbe Tabelle, dieselbe
Seite, dieselben Regeln fuers Anlegen, Aendern und Loeschen. Neu sind
eine Spalte (`gesendet_am`) und eine Route. Die Sendefunktion selbst
steht im Chat-Modul und nicht daneben: Ein Zweier-Gespraech darf es nur
einmal geben, die Leseraender muessen mitwandern, Live-Strom und
Benachrichtigung haengen daran -- wer das nachbaut, hat zwei Fassungen,
und die zweite ist die, in der jemand eine Nachricht nicht bekommt.

=== WAS DIE PRUEFUNG GEFUNDEN HAT ===

"Zugeordneter Creator existiert nicht" -- beim Anlegen eines Eintrags
ueber ein Teammitglied. Die Regel verlangte einen Creator; bei
Entwicklung geht es um Menschen aus dem Team. Die Meldung war dabei
selbst irrefuehrend: Die Person existiert sehr wohl, sie ist nur kein
Creator. Beides behoben.

Und meine EIGENE Pruefung von vor einer Stunde wurde rot: Sie verlangte,
dass jede Zusatzkachel in der Gruppe "Team Dogi" steht. Die naheliegende
Reparatur waere gewesen, die Gruppe gar nicht mehr zu pruefen -- das
haette die Aussage weggeworfen. Jetzt steht die erlaubte Liste
ausgeschrieben da: Eine Kachel fuer zwei Menschen darf nicht in einer
Gruppe landen, die alle sehen. Kommt eine dritte Gruppe, wird die Zeile
rot, und das ist Absicht.

Die zwei neuen Farbtoene trennen ueber Saettigung und Helligkeit statt
ueber den Farbwinkel -- bei 25 Toenen ist der Kreis voll, und die
groessten Luecken waeren ein drittes Gruen zwischen zwei vorhandenen.
Bei einer achtundzwanzigsten Kachel brauchen die Kacheln Gruppenfarben
statt Einzelfarben; das steht als Notiz im Quelltext.

pruef-entwicklung 33 (neu) · pruef-start-ansicht 27 Kacheln, sechs
Gruppen · pruef-rollen 278 -> 282 · pruef-modi-checkliste 70 ·
pruef-haus-trennung 62 · pruef-rueckmeldung 30 · pruef-modi-ideen 30 ·
pruef-modi-verborgen 80 · pruef-css-klassen gruen · pruef-modi-wortleck 5.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 01:11:30 +02:00
DogFatherGitandClaude Opus 5 bea1bb7194 Die rechte Hand meldet wie das Team, die Leiste wird ein Universum, sein Kalender bleibt ganz
Drei Wuensche aus zwei Bildschirmfotos und einem Satz.

=== 1. SIE DARF SAGEN, WAS PASST UND WAS NICHT ===

Filipe: "die rechte hand soll bei diesen aufgaben auch wie die modis
sagen koennen ob es passt oder nicht ... die rechte hand ist da um mir
zu helfen aber auch wie die modis um mir zu sagen was passt und nicht
wo die denken bedarf oder nicht. perfektionier das alles."

SIE KONNTE ES NICHT, UND ZWAR AN DREI STELLEN GLEICHZEITIG -- die
zweite und dritte kamen erst zum Vorschein, nachdem die erste behoben
war. Genau deshalb steht "perfektionier das alles" ueber diesem Commit
und nicht "eine Zeile geaendert":

  ERSTENS: Die Frage "an wessen Liste arbeitest du?" kannte nur Creator
  und Modis (dann die eigene). Sie fiel durch beide Zweige und konnte
  ueberall antworten, nirgends urteilen.

  ZWEITENS: Nach der Reparatur durfte sie -- und bekam den KATALOG DER
  CREATOR. Ihre Meldung trug einen Schluessel, den der Eingang gar
  nicht kennt, und wurde dort stillschweigend uebersprungen. Die
  Pruefung meldete "sie darf urteilen (200)" und eine Zeile spaeter
  "ihre Meldung steht NICHT in DogFathers Eingang". Beides stimmte.

  DRITTENS: Der Eingang sammelt aus der Liste der Teammitglieder, und
  die hiess `rolle = 'modi'`. Sie war die Empfaengerin dieser Seite und
  kam auf ihr selbst nicht vor. Wer nicht in der Liste steht, kann
  melden, so viel er will -- es erreicht niemanden.

Jetzt steht sie in derselben Liste (aber `id <> ich`: eine Karte ueber
sich selbst ist kein Ueberblick, sondern ein Spiegel), bekommt
denselben Beobachtungskatalog wie die Modis und meldet in denselben
Eingang. Alle Rollenvergleiche kommen dabei aus der vorhandenen Menge
TEAM_DOGI_ROLLEN statt als zwei Vergleiche danebengeschrieben -- sonst
steht dort beim naechsten Mal einer zu wenig.

=== 2. DIE LEISTE ===

Filipe: "der hintergrund dieser leiste soll extrem speziell aussehen
wie ein universum und soll von lila auf babyblau wechseln, von links
nach rechts ... der husky links soll auch babyblau strahlen und nicht
rot und der rechts lila. dan brauch ich auch noch einen teilen button."

DIE RICHTUNG IST DIE EIGENTLICHE AENDERUNG: Der Schein lief von UNTEN
nach oben (die Glut der Agenturseite, nur in Lila). Jetzt von LINKS
nach rechts, mit zwei Nebeln und sieben Sternen -- als Verlaufslagen
und nicht als Elemente: Sieben Punkte waeren sieben Knoten im Baum auf
jeder der zwanzig Seiten, nur fuer Zierde.

DIE ZEICHEN TAUSCHEN DIE SEITEN. Links stand ein warmes Rot, fest
hingeschrieben in start.css; rechts strahlte der zweite Husky babyblau.
Jetzt umgekehrt -- so hat jede Seite der Leiste beide Farben, statt
dass jede nur eine hat. Beim rechten wird die FUELLUNG mitgetauscht,
nicht nur der Schein: Ein lila Schein um ein blaues Zeichen waere ein
Rand, keine Farbe.

"UEBERTRIEBEN GEIL" HAT EINE GRENZE, und sie ist gemessen, nicht
geschaetzt. Erster Anlauf: .30 -- der Verlauf war zu ahnen, nicht zu
sehen, Kontrast 5,26:1. Zweiter: .40 -- sichtbar, aber 4,79:1 in der
Mitte, bei einer Grenze von 4,5 zu knapp. Jetzt kraeftige Enden und
eine zurueckhaltende Mitte: 5,92 / 5,26 / 7,06:1 an drei Stellen des
Verlaufs, gemessen an echten Bildpunkten. Die Farbe liest das Auge an
den Enden; in der Mitte gewinnt die Lesbarkeit.

DER TEILEN-KNOPF fehlte, weil `DARF_TEILEN` Leitung und Scouts kennt --
die rechte Hand ist keins von beidem. Gefragt wird jetzt nicht nach der
Rolle, sondern nach `ich.marke`: Die setzt der Server genau dann, wenn
jemand zu Team Dogi gehoert. Der Rollenname bleibt damit aus einer
Datei heraus, die jeder herunterlaedt -- und die Frage lautet ohnehin
"gehoert diese Person hierher?".

=== 3. SEIN KALENDER BLEIBT GANZ ===

Filipe: "mein kalender (dogfather) auf dieser seite hier soll komplett
verbunden sein mit dem kalender in der workspace seite ABER NUR IN DER
DOGFATHER ROLLE BEI DOGFATHER: NICHT BEI VANVAN."

Bei Aufgaben, Bereichen und Dateien ist die Haustrennung eine Hilfe --
man will das andere Haus dort gerade nicht sehen. Beim Kalender waere
sie eine Falle: Wer auf der Team-Seite einen Termin eintraegt und die
Haelfte seines Tages nicht sieht, legt ihn auf eine Zeit, in der er
schon woanders sitzt. Ein Kalender, der nur die halbe Wahrheit zeigt,
ist schlimmer als keiner.

Geprueft wird die ROLLE und nicht der Name -- ein Name waere die
Stelle, an der es beim naechsten Menschen bricht.

=== WAS DIE PRUEFUNGEN GEZEIGT HABEN ===

Eine Erwartung war seit Stunden stumm rot: pruef-modi-checkliste
verlangte GENAU EINE Zusatzkachel, und seit dem Ideen-Board sind es
drei. Ich hatte sie nach der Aenderung nicht noch einmal laufen lassen.
Sie zaehlt jetzt nicht mehr auf eine feste Zahl, sondern prueft die
AUSSAGE: Wer welche bekommen soll, bekommt welche -- und jede gehoert
in die Gruppe "Team Dogi". Eine Pruefung, die bei jeder neuen Kachel
rot wird, erzieht dazu, ihr Rotwerden zu ignorieren.

Zwei weitere Erwartungen haben sich gedreht und sind im Quelltext
begruendet: Der Kalender auf crew. zeigt DogFather jetzt alles (die
Pruefung unterscheidet dafuer ER-ja/SIE-nein statt einer einzelnen
Antwort -- das ist mehr, nicht weniger), und "aus dem Eingang
verschwunden" fragt jetzt nach Schluessel UND Person: Seit die rechte
Hand denselben Katalog benutzt, koennen zwei Menschen denselben Punkt
melden, und die Pruefung meldete einen Fehler, den es nicht gab.

Und eine war wertlos: "die rechte Hand sieht den Agenturtermin nicht"
lief gegen einen leeren Kalender -- sie sah ueberhaupt nichts. Sie hat
jetzt zwei eigene Termine, einen aus jedem Haus; erst damit sagt die
Messung etwas.

pruef-modi-checkliste 59 -> 70 · pruef-team-stufen 24 -> 26 ·
pruef-team-ampel 32 · pruef-haus-trennung 61 -> 62 · pruef-rollen 278 ·
pruef-css-klassen gruen · pruef-modi-wortleck 5.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 00:51:56 +02:00
DogFatherGitandClaude Opus 5 a16e4cb337 "Dein Team": neuer Name, ein falsches Schild weniger und ein eigener Grund
Filipe, drei Bildschirmfotos: den Namen der Kachel aendern, "diese zwei
kacheln noch mehr perfektionieren", "veraender den hintergrund von
diesen kacheln komplett", "perfektionnier diese seite einfach komplett".

DER NAME, DRITTE FASSUNG. Zuerst "Team-Lage" -- das klang nach Bericht
UEBER Menschen. Dann "Eingang" -- das beschrieb nur die eine Haelfte
(was hereinkommt) und liess die groessere weg: wer da ist, wer heute
kann, wer was offen hat. "Dein Team" sagt beides und stellt niemanden
ueber jemanden.

DREI SACHEN WAREN NICHT GESCHMACK, SONDERN FEHLER -- und alle drei hat
erst das Nachmessen am fertigen Bildschirm gezeigt:

  UEBER SIEBEN TAGEN STAND "Kann heute". Im Singular, ueber einer
  ganzen Woche. Wer nur die Ueberschrift liest -- und das tut man bei
  einer Zeile in Versalien --, haelt den ganzen Streifen fuer den
  heutigen Tag und liest sechs Kaestchen falsch. Der Satz DARUNTER war
  immer richtig; zwei Aussagen ueber demselben Bild, und die
  auffaelligere war die falsche.

  DIE VIER ZAHLEN BRACHEN 3 + 1. Gemessen: Die Karte ist innen 536 px
  breit, die Regel verlangte je Spalte mindestens 130 px, vier Spalten
  braeuchten 544. Acht Pixel zu wenig. Die Lehre ist NICHT "130 auf 122
  senken" -- das waere dieselbe Rechnung mit einer anderen Zahl. Vier
  Dinge sehen nur in 1x4, 2x2 oder 4x1 richtig aus; 3+1 ist die eine
  Anordnung, die immer falsch wirkt, und eine `auto-fit`-Regel kann
  jederzeit dort landen. Zwei feste Spalten koennen es nicht.

  DER WEG IN DEN CHAT war ein unterstrichener Satz ueber die volle
  Kartenbreite -- er sah aus wie eine Ueberschrift, nicht wie ein Knopf.

DER GRUND DER KARTEN, und hier hat mich das erste Ergebnis widerlegt:
Der Schein aus der oberen Ecke nahm `var(--r)`, die Farbe der STUFE.
Das war logisch und unsichtbar -- bei "Probe" ist sie ein gedaempftes
Grau, und ein Grauschein auf fast Schwarz ist kein Schein. Nach der
Aenderung sah die Karte auf dem Bildschirmfoto genauso aus wie davor.
Jetzt tragen die beiden Ecken die Hausfarben (Lila oben links, Babyblau
unten rechts), dazu ein Lichtstreifen quer und ein Kantenlicht oben.
Die Stufe bleibt, wo sie hingehoert: im Kantenlicht und am Schild.

AUGENSCHONEND BLEIBT PFLICHT: Keine Lage geht ueber 26 %, der
Lichtstreifen liegt bei 3 %, und die hellsten Stellen sitzen in den
ECKEN -- nicht hinter dem Text. Ein Schein hinter einer Zahl macht sie
schwerer lesbar, egal wie schoen er ist.

Dazu: HEUTE ist im Wochenstreifen markiert (sieben gleich aussehende
Kaestchen zwingen sonst dazu, den Wochentag im Kopf auszurechnen), ein
freier Tag hat eine Andeutung statt gar nichts (sieben leere Rahmen
sahen aus wie "noch nicht geladen"), und der Erklaerkasten im Kopf darf
68 statt 44 Zeichen breit sein -- auf einem breiten Bildschirm stand er
als schmale Saeule mit sechs Zeilen zu je vier Woertern neben viel Bild.

WARUM DIE FALSCHE UEBERSCHRIFT UEBERLEBEN KONNTE: pruef-team-ampel
prueft seit dem ersten Tag, dass SIEBEN Tage kommen und der erste heute
ist. Was sie nie angesehen hat, ist der Text darueber -- die Zahl
stimmte ja. Sie prueft ihn ab jetzt, an derselben Stelle wie die Zahl,
damit beide zusammen gelesen werden. Mit Gegenprobe: Die Suche muss das
Wort "heute" auch finden koennen, sonst waere sie gruen, weil sie nie
etwas liest.

pruef-team-ampel 28 -> 32 · pruef-team-stufen 24 · pruef-css-klassen
gruen · pruef-start-ansicht 143 · pruef-rollen 278 · pruef-modi-wortleck 5.

OFFEN GEBLIEBEN und ihm gemeldet: Auf einem 1920er Bildschirm steht der
Inhalt in einer Saeule von rund 1150 px, links und rechts bleibt Bild.
Das ist die Breite ALLER zwanzig Seiten; sie hier allein zu aendern
hiesse, eine Seite anders zu bauen als die anderen neunzehn.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 00:30:18 +02:00
DogFatherGitandClaude Opus 5 da7ddf7b5e Alle Kategorien in der Personenliste -- und die rechte Hand liest mit
Filipe, mit Bildschirmfoto der Team-Seite: "ich muss alle kategorien da
sehen. und ich will dass die rechte hand auch alle sieht."

AUF DEM BILD STAND EIN EINZIGER ABSCHNITT: DogFather. VanVan war in
derselben Minute zur rechten Hand geworden (im Protokoll darunter zu
sehen: "#4 VanVan: admin -> hand") -- und damit aus der Liste
VERSCHWUNDEN.

Nicht aus der Antwort des Servers. Der schickte sie die ganze Zeit mit.
`assets/js/personen.js` gruppiert nach einer Liste mit fuenf Rollen, und
wer dort nicht steht, wurde nicht gezeichnet: kein Fehler, keine
Luecke, kein Hinweis. Dieselbe stille Lücke wie vorgestern in der
Personenauswahl des Chats, an einer anderen Stelle -- und dieselbe
Ursache: Die Namen der verborgenen Rollen duerfen in keiner
ausgelieferten Datei stehen, also kannte der Browser sie nicht.

DIE LOESUNG IST DIESELBE: Der Server schickt die Ueberschriften mit
(`zusatzrollen` -- es gab sie schon, sie waren bisher nur die Auswahl
beim Anlegen). Der Browser braucht dafuer keinen Rollennamen zu kennen,
er bekommt einen Text.

UND DARUNTER EIN AUFFANGBECKEN, das ist der eigentliche Fortschritt:
Kaeme morgen eine siebte Rolle und niemand daechte an diese Stelle,
stuenden ihre Leute trotzdem auf der Seite -- unter ihrem Rollennamen,
sichtbar, statt lautlos zu fehlen. Ein Abschnitt mit einer unschoenen
Ueberschrift ist tausendmal besser als ein Mensch, den es auf dem
Bildschirm nicht gibt.

DIE RECHTE HAND LIEST MIT -- LESEND. Das ist sein eigenes Wort
("sieht"): Codes, Sperren, Loeschen, Rollen vergeben und das Protokoll
bleiben bei DogFather. Die Ausnahme im Server ist Wort fuer Wort so
gebaut wie die, die Spicy Media schon hat: eine Methode, eine Adresse,
eine Rolle. Zwei Fassungen derselben Ausnahme waeren zwei Regeln, und
die zweite laesst irgendwann mehr durch als gedacht.

DREI SCHICHTEN MUSSTEN ZUSTIMMEN, und die dritte hatte ich uebersehen:
die Kachel, die Schnittstelle -- und die SEITE selbst. In der
Rollentabelle in workspace.js stand personen.html fuer spicy, admin und
manager; die rechte Hand flog von der Seite auf die Startseite zurueck,
obwohl Kachel und Daten schon stimmten.

Gefunden hat das nicht das Auge, sondern pruef-rollen. Sie geht jede
Kachel jeder Rolle ab und schaut nach, wo man landet: "Rechte Hand
Kachel personen.html LANDET AUF start.html". Das ist der Wert dieser
Pruefung -- der Fehler war unsichtbar, solange man nicht selbst als
rechte Hand auf die Kachel drueckt.

EINE ERWARTUNG HAT SICH GEDREHT, und das steht jetzt im Quelltext:
pruef-haus-trennung verlangte vor einer Stunde noch, dass die Kachel
bei ihr NICHT steht und die Seite sie abweist -- richtig, solange sie
die Seite nicht durfte. Die Pruefung ist dadurch nicht schwaecher
geworden: Sie verlangt weiterhin, dass Kachel und Zugang DASSELBE
sagen. Sie sagen jetzt beide ja statt beide nein.

DIE NEUE MESSUNG VERGLEICHT ZAHL GEGEN ZAHL: wie viele Menschen der
Server liefert, wie viele Zeilen auf dem Bildschirm stehen. Nicht
"steht VanVan da" -- das waere ein Name, den man beim naechsten Umbau
so lange anpasst, bis die Pruefung wieder passt. Eine Pruefung, die nur
die Antwort des Servers ansieht, waere hier uebrigens gruen gewesen.

Beim Schreiben dieser Messung ist sie zuerst viermal falsch
angeschlagen: Die Abschnitte stehen zugeklappt da, und zugeklappt sind
ihre Zeilen gar nicht im Dokument. Vier Fehler, die es nicht gab -- die
Pruefung klappt jetzt erst auf, dann liest sie.

pruef-personen-formular 27 -> 35 · pruef-haus-trennung 53 -> 61 ·
pruef-rollen 277 -> 278 · pruef-modi-verborgen 80 · pruef-start-ansicht
143 · pruef-css-klassen gruen · pruef-modi-wortleck 5.

ANMERKUNG ZUR TEAM-ADRESSE: Dort zeigt die Liste weiterhin nur Team
Dogi -- so, wie er es eine Stunde vorher verlangt hat ("bitte nur
basiert auf diese seite"). "Alle Kategorien" heisst also: alle des
Teams. Wenn er dort auch die Agentur sehen will, ist das eine Zeile,
aber es waere eine andere Entscheidung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-11 00:11:36 +02:00
DogFatherGitandClaude Opus 5 670ce4a5c1 Personen & Zugaenge auf der Team-Seite -- und eine Rolle laesst sich endlich aendern
Filipe wollte VanVan die Rolle "Rechte Hand" geben. Auf die Frage nach
ihrem Code: "die kategorie personen & zugaenge fehlt also muss das
hinzugefuegt werden und bitte nur basiert auf diese seite."

BEIM NACHSEHEN KAMEN ZWEI DINGE HERAUS, und das zweite war das
eigentliche:

  Die Kachel fehlte, weil ich sie mit den Agenturkacheln entfernt hatte
  -- ausgerechnet die, mit der man jemandem eine Rolle gibt. Die
  Team-Adresse war damit eine Seite, auf der man das Team nicht
  verwalten kann.

  UND ES GAB DIE FUNKTION GAR NICHT. Im ganzen Server aendert keine
  einzige Stelle `personen.rolle`. Anlegen ja, sperren ja, loeschen ja
  -- aendern nirgends, seit dem ersten Tag. Wer jemandem eine andere
  Aufgabe geben wollte, musste ihn loeschen und neu anlegen, und daran
  haengen seine Aufgaben, seine Nachrichten, seine Eintraege, sein
  ganzer Verlauf. Kapitel 4 des Pflichtenhefts verlangt ausdruecklich
  das Gegenteil.

  (Nebenbefund aus derselben Messung, ihm gemeldet: Auf dem Server gibt
  es KEINE Rolle 'hand'. VanVan ist ein zweiter DogFather-Zugang. Die
  Rueckmeldungen mit "nur an DogFather" wuerde sie deshalb heute
  mitlesen -- die Regel fragt "ist das DogFather?", und ihre Rolle
  antwortet ja.)

DIE KACHEL traegt Namen, Zeichen und Farbton der Agenturseite. Es ist
dieselbe Seite mit demselben Zweck; ein zweiter Name dafuer waere ein
zweites Ding, das es nicht gibt.

SIE STEHT NUR DORT, WO SIE AUCH FUNKTIONIERT. Die Personenseite haengt
serverseitig an `nurAdmin`. In der Kachelliste der rechten Hand haette
sie auf eine 404 gefuehrt -- ein Knopf, der eine Absage bringt, ist
schlimmer als kein Knopf. Wenn sie das duerfen soll, ist das eine
eigene Entscheidung und gehoert an dieselbe Stelle wie nurAdmin.

"NUR BASIERT AUF DIESE SEITE" steht nicht in der Kachel, sondern im
Server: Auf crew. liefert die Liste nur Team Dogi, und angelegt werden
koennen nur Team-Rollen. Beides kommt aus Funktionen, die es schon gab
(hausBedingung, darfAnlegen) -- und `darfAnlegen` baut auch die Knoepfe
in der Oberflaeche, weshalb die anderen Rollen dort von selbst
verschwinden statt eine Absage zu bringen.

DER ROLLENWECHSEL HAT FUENF SICHERUNGEN, und jede hat ihren Grund:

  NUR DOGFATHER -- wer Rollen vergeben kann, kann sich selbst zum
  DogFather machen.

  NIE DIE EIGENE. Wer sich selbst herabstuft, sperrt sich aus; die
  Funktion zum Zurueckdrehen haengt an der Rolle, die er gerade
  abgegeben hat. Das ist keine Warnung wert, das ist eine Tuer, die
  zubleibt.

  NIE DEN LETZTEN AKTIVEN DOGFATHER. Gezaehlt werden die AKTIVEN: Ein
  gesperrter kann niemanden hereinlassen, ihn mitzuzaehlen waere eine
  Sicherung, die sich selbst beluegt.

  ALLE SITZUNGEN DIESER PERSON ENDEN. Eine Sitzung gehoert seit dem
  10.09.2026 zu einer ADRESSE, und welche das ist, entscheidet die
  Rolle. Wer eben noch DogFather war und jetzt rechte Hand ist, saesse
  sonst mit einer Sitzung da, die auf der Agenturadresse laeuft und
  dort nicht mehr hingehoert -- ein halb gueltiger Zustand, der erst
  beim naechsten Klick auffaellt.

  DER CODE BLEIBT. Er haengt am Menschen, nicht an der Rolle. Ihn
  mitzutauschen waere bequem und falsch: Dann muesste jede
  Rollenaenderung von einem Gespraech begleitet sein, und wer das
  vergisst, sperrt jemanden aus, ohne es zu merken.

Und es steht im Protokoll, mit beiden Rollen im Klartext.

DIE AUSWAHL IM BROWSER wird nicht noch einmal gebaut, sondern aus dem
Anlege-Formular gelesen. Dort stehen genau die Rollen, die der Server
dieser Person zugesteht -- einschliesslich derer, die in keiner
ausgelieferten Datei stehen duerfen und erst nachtraeglich dazukommen.
Eine zweite Liste waere die, in der eine Rolle fehlt oder eine zu viel
steht, und beides faellt erst auf, wenn jemand sie braucht.

EINE PRUEFUNG WAR WERTLOS UND IST ES NICHT MEHR: "ihre Sitzungen sind
beendet" lief gegen einen leeren Bestand -- ein gruener Haken ueber
einer Null. Jetzt meldet sich die Person vorher an, und die Zahl davor
muss groesser als null sein.

pruef-haus-trennung 32 -> 53 · pruef-rollen 277 · pruef-personen-formular
27 · pruef-css-klassen 30 · pruef-start-ansicht 143 ·
pruef-modi-verborgen 78 · pruef-modi-wortleck 5.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 23:47:13 +02:00
DogFatherGitandClaude Opus 5 9c99a5b9c3 Zwei Haeuser auf einer Datenbank -- die Team-Adresse zeigt nur das Team
Filipe, mit Bildschirmfoto der Zentrale: "die daten von dieser seite
sollen nichts mit den daten am hut haben von der workspace seite bitte,
die hier soll ihre eigene daten haben und komplett von der anderen
getrennt sein. dogfather soll die daten auch auf der anderen seite
sehen in der team dogi kategorie aber auch nur er und vanvan."

GETRENNT WIRD DER AUSSCHNITT, NICHT DER BESTAND. Eine zweite Datenbank
haette den zweiten Satz unmoeglich gemacht -- er will dieselben Daten
auf beiden Adressen sehen. Es bleibt also alles an einem Ort, und die
ADRESSE entscheidet, welcher Ausschnitt davon herauskommt.

ALLES HAENGT AN EINEM WERT: `person.haus`, gesetzt in sitzungLesen()
aus dem Hostnamen. Von dort reist er mit der Person durch jede
Sichtbarkeitsregel im Haus. Der Grund ist ein praktischer: Die Regeln
bekommen ueberall dieselbe Person gereicht -- sichtbar(person),
sichtbareCreatorIds(person), bereicheFuer(person). Ein zusaetzliches
Argument haette an ueber dreissig Aufrufstellen mitgeschleift werden
muessen, und die eine vergessene waere das Loch gewesen.

RECHTE AENDERT ES NICHT. Es entscheidet, WAS jemand sieht, nicht, was
er darf -- wie die Sicht eines anderen (sichtPerson) das auch nicht tut.

DER FILTER IST DER SPIEGEL EINES VORHANDENEN. Es gab schon
`ohneTeamDogi` ("alles ausser dem Team") fuer Spicy Media. Dazu kommt
jetzt `ohneAgentur` -- gleiche Bauweise, andere Rollenmenge, GEMEINSAME
Implementierung. In der steckt die NULL-Falle (`IS NULL OR NOT IN`,
denn `NULL NOT IN (...)` ist weder wahr noch falsch), und die sieht man
einer Abschrift nicht an.

WARUM NICHT "MINDESTENS EINE SPALTE ZEIGT AUF TEAM DOGI": Das waere die
naheliegende Formulierung und sie waere falsch. Eine Aufgabe, die
DogFather fuer einen Creator anlegt, haette ueber `erstellt_von` (er
gehoert zum Haus) trotzdem gepasst und stuende auf der Team-Seite.
Andersherum stimmt es: Sobald IRGENDEINE Spalte auf Creator, Scout,
Manager oder Spicy Media zeigt, gehoert die Zeile ins andere Haus.

VIER TUEREN, EINE FORM. Aufgaben, Bereiche, Dateien und der Kalender
haben je eine eigene sichtbar()-Funktion. Alle vier bekommen dieselbe
Bedingung an derselben Stelle, in derselben Schreibweise -- damit keine
davon anders aussieht als die anderen. Beim Kalender steht sie in
termineSichtbar() in workspace.js und nicht im Kalendermodul: Sonst
haetten Termine, Wiederholungen und der ICS-Abruf sie einzeln
gebraucht, und der ICS-Abruf ist der, den man vergisst -- er laeuft
ohne Bildschirm.

ZWEI ABFRAGEN GEHEN ABSICHTLICH NICHT DURCH DIE LISTENFUNKTIONEN, und
genau die standen im Bildschirmfoto: der Ring der Zentrale ("9 IM
TEAM", obwohl das Team drei Leute hat -- gezaehlt wurde das ganze Haus)
und die Hinweiszeile darunter ("Creator-Profile sind noch leer"). Im
Quelltext der Zentrale steht sogar ausdruecklich, dass sie die einzige
solche Stelle ist; gefunden habe ich sie trotzdem erst, weil ich der
Zahl im Bild nachgegangen bin. Beide bekommen die Bedingung jetzt aus
derselben Funktion (`hausBedingung`), nicht aus einer zweiten
Rollenliste.

Die Hinweis-Bedingung sitzt am BLOCK und nicht an den vier Abfragen
darin: Wer eine fuenfte hinzufuegt, bekommt sie dadurch mit, ohne daran
zu denken.

DIE KACHELN: Auf crew. liefert der Server dieselbe Liste wie der
rechten Hand -- nicht eine dritte. Fuenfundzwanzig Kacheln, von denen
zwei Drittel Creator und Agentur betreffen, waeren dort Fenster in ein
Haus, in dem er gerade nicht ist, und hinter jedem stuende seit heute
eine leere Liste. Auf workspace. bleibt alles, wie es war: Dort schickt
der Server weiterhin `bereiche: null` ("nimm die Liste aus der Datei").

JEDE MESSUNG STEHT ZWEIMAL DA. Die Trennung kann auf zwei Arten falsch
sein: Sie greift nicht (dann steht die Agentur weiter auf der
Team-Seite, und niemand merkt es, weil alles funktioniert), oder sie
greift zu weit (dann verschwindet auf der Agenturseite etwas -- der
gefaehrlichere Fall, denn eine zu kurze Liste sieht aus wie "nichts zu
tun"). Deshalb folgt auf jede Messung auf crew. dieselbe Messung auf
workspace., mit DERSELBEN Sitzung; der einzige Unterschied ist der
Host-Kopf. Dazu zwei Gegenproben zur Regel selbst: 127.0.0.1 bleibt
unberuehrt (sonst waeren alle Pruefungen im Haus stillschweigend blind
geworden), und eine erfundene Adresse oeffnet kein drittes Haus.

NEBENBEI ZWEI EIGENE FEHLER BEHOBEN: pruef-chat-kanaele und
pruef-rueckmeldung liefen auf Ports, die schon vergeben waren (4359
neben pruef-modi-verborgen, 4371 neben pruef-crew-adresse). Beide sind
umgezogen. Fuenf weitere Doppelungen zwischen fremden Pruefdateien
(4186, 4188, 4189, 4193, 4198) bleiben stehen und sind gemeldet -- an
Dateien zu greifen, an denen gerade eine zweite Sitzung arbeitet, waere
genau der Fehler, den diese Doppelungen ohnehin schon zeigen.

pruef-haus-trennung 32 (neu) · pruef-rollen 277 · pruef-modi-verborgen
78 · pruef-chat gruen · pruef-rueckmeldung 30 · pruef-modi-ideen 30 ·
pruef-crew-adresse 129 · pruef-start-ansicht gruen ·
pruef-zwischenspeicher 21 · pruef-modi-wortleck 5.

BERICHTIGUNG zum vorigen Commit: Dort steht "pruef-rueckmeldung 34".
Es sind 30. Ich hatte die Zeilen geschaetzt statt sie zu lesen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 23:24:34 +02:00
DogFatherGitandClaude Opus 5 be121a483e Rueckmeldung in beide Richtungen (Kapitel 5 und 6)
Filipe: "Nicht nur ich soll meine Modis bewerten oder ihnen Feedback
geben koennen. Auch die Modis sollen mir Feedback geben koennen. Sie
sollen mir beispielsweise sagen koennen: Was koennte ich verbessern?"
Und der Schlusssatz seines Pflichtenhefts: "Es soll nicht nur dazu
dienen, Leistungen zu kontrollieren. Es soll vor allem dabei helfen,
als Team besser zu werden."

EIN BRETT FUER BEIDE KAPITEL, NICHT ZWEI. Kapitel 5 (gegenseitiges
Feedback) und Kapitel 6 (gemeinsame Reflexion) stellen dieselben
Fragen -- "was laeuft gut, was laeuft schlecht, was fehlt" --, einmal
an eine Person und einmal an das Team. Zwei Bretter haetten bedeutet,
dass man beim Schreiben zuerst entscheiden muss, an WEN es geht, bevor
man weiss, WAS man sagen will. Hier ist es umgekehrt: erst die Sache,
dann die Richtung.

DIE NEUN FRAGEN SIND SEINE, wortwoertlich aus dem Pflichtenheft
zusammengezogen: laeuft gut · laeuft nicht gut · unbedingt behalten ·
an DogFather · was dem Team fehlt · Regel aendern · besser organisieren
· Idee · Wunsch fuer spaeter. Sie stehen als feste Faecher da und nicht
als freies Feld -- genau das ist der Unterschied zwischen einer
Sammlung und einem Haufen: Neun Faecher kann man auswerten, tausend
Formulierungen nicht.

KEIN NEUER BAUKASTEN. Die Rueckmeldung ist ein BEREICH wie das
Ideen-Board: dieselbe Tabelle, dieselbe Seite, dieselben Regeln fuers
Anlegen, Aendern und Loeschen, dieselbe Zugangssperre. Ein eigenes
Modul haette all das ein zweites Mal gebraucht -- und die zweite
Fassung waere die gewesen, in der eine Regel fehlt.

DIE EINE NEUE SACHE IST DIE RICHTUNG. Beim Schreiben waehlt man
zwischen "fuers Team" (Vorgabe) und "nur an DogFather". Ohne diese Wahl
haette man eines von beidem verloren: Wer "was koenntest du besser
machen" vor versammelter Mannschaft sagen muss, sagt es nicht -- wer
alles nur unter vier Augen sagen kann, hat kein Team-Gespraech.

UND "NUR DOGFATHER" HEISST NUR DOGFATHER -- die rechte Hand
ausdruecklich nicht. Sie sieht sonst ueberall dasselbe wie er; hier
nicht, weil das Etikett sonst nicht stimmen wuerde. Eine Zusage mit
einer Ausnahme im Kleingedruckten ist keine. Sie schreibt selbst
genauso -- auch ueber ihn.

DIE ZUSAGE STEHT IN sichtbarEintrag(), also in derselben Funktion, durch
die auch das Lesen einer einzelnen Zeile, das Aendern und das Loeschen
gehen. Eine Regel, die nur die Liste filtert, laesst die Zeile ueber
ihre Nummer trotzdem heraus; die Pruefung klopft deshalb auch von
hinten (PATCH und DELETE auf die vertrauliche Zeile: 404, auf die
offene: 200).

`COALESCE(nur_leitung, 0)`: Jede Zeile, die es vor heute gab, hat dort
NULL, und in SQL ist `NULL = 0` nicht falsch, sondern UNBEKANNT. Ohne
den Ersatzwert waere der gesamte alte Bestand von einer Minute auf die
andere unsichtbar gewesen -- und niemand haette es gemeldet, denn ein
leeres Brett sieht nicht nach Fehler aus. Beide Richtungen sind
gemessen.

KEINE ANONYMITAET, und das ist eine Entscheidung, keine Luecke. In
einem Team dieser Groesse waere sie ohnehin keine: An drei Saetzen
erkennt jeder jeden. Ein Versprechen, das nicht haelt, ist schlimmer
als keines.

DER FARBTON DER KACHEL IST AUSGERECHNET, NICHT AUSGESUCHT. Bei 24
vorhandenen Toenen landet ein neuer fast zwangslaeufig neben einem
alten, und zwei Kacheln in FAST derselben Farbe sind schlimmer als in
derselben -- bei gleicher merkt man den Fehler, bei fast gleicher sucht
man ihn. Alle 24 wurden in Farbwinkel umgerechnet; die groesste Luecke
liegt zwischen 90 und 160 Grad und ist 70 Grad breit, mehr als doppelt
so viel wie die naechste. Der neue Ton sitzt in ihrer Mitte, 8,9 zu 1
auf dunklem Grund.

pruef-rueckmeldung 34 (neu) · pruef-rollen 274 -> 277 ·
pruef-start-ansicht zaehlt jetzt 25 Kacheln und 25 Farben (sie zaehlt
selbst, statt eine Zahl festzuhalten -- deshalb blieb sie gruen) ·
pruef-modi-ideen 30 · pruef-modi-verborgen 78 · pruef-css-klassen gruen
· pruef-modi-wortleck 5.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 22:54:04 +02:00
DogFatherGitandClaude Opus 5 72b36d1c31 Ein eigenes Haus fuer Team Dogi -- Lila und Babyblau statt Rot
Filipe, screen1: "die leiste da und alles andere was noch rot ist auf
team dogi seite soll lila werden. richtig geiles lila und babyblau
mischung ueberall."
Und screen2: "ich will doch dass der eingang hier getrennt ist von der
workspace seite ... aber es soll trotzdem so bleiben dass ich die daten
hier und da sehe."

GETRENNT WIRD DAS AUSSEHEN, NICHT DER BESTAND. Dieselbe Datenbank,
dieselben Seiten, dasselbe Programm -- und zwei Haeuser, die man nicht
verwechseln kann. Filipe und die rechte Hand sehen ihre Zahlen
weiterhin auf beiden Adressen.

EINE ZEILE JE SEITE, EINE REGEL IM SERVER. Jede Seite laedt als LETZTE
Stilvorlage `haus.css`. Auf der Agenturadresse ist die leer -- das Haus
dort IST der Grundzustand. Auf crew.dogfather-universe.com biegt die
Weiche genau diesen Dateinamen auf `crew-haus.css` um.

Drei Wege habe ich dafuer verworfen, und jeder hat einen Grund:
  * `data-haus` per JavaScript -> die Seite laedt erst im falschen Ton
    und faerbt sich um. Sichtbar, auf jeder Seite, bei jedem Aufruf.
  * dasselbe Attribut serverseitig in den HTML-Text schreiben -> jede
    HTML-Antwort muesste durch einen Umschreiber statt als Datei
    ausgeliefert zu werden, nur wegen einer Farbe.
  * zwanzig zweite <link>-Zeilen -> die muesste jemand bei jeder neuen
    Seite mitschreiben, und wer sie vergisst, bekommt eine Seite, die
    still zum falschen Haus gehoert.

DAS HAUS SIND FAST NUR VARIABLEN. Wer zwei Dutzend Farbwerte tauscht,
tauscht jede Kachel, jeden Rand, jeden Knopf und jedes Leuchten auf
einmal -- auch an Stellen, die man beim Nachbauen uebersehen wuerde.
Eine Datei, die stattdessen Regel fuer Regel umfaerbt, waere beim
naechsten neuen Bauteil sofort unvollstaendig, ohne dass es auffiele.

WO KEINE VARIABLE STAND, HAT DAS MESSEN SIE GEFUNDEN. Ich habe nicht
im Quelltext gesucht, sondern am fertigen Bildschirm jedes Element nach
Farben abgefragt, bei denen der Rotkanal deutlich ueber den anderen
liegt -- ueber alle Farbquellen, nicht nur `color` und
`background-color`. Erst das brachte die eigentliche Stelle ans Licht:

  DIE KOPFLEISTE HAT EINEN ROTEN VERLAUF. Genau die Leiste aus Filipes
  Bildschirmfoto. Sie glimmt im Agenturhaus wie Feuer -- sein eigener
  Wunsch von screen36, und dort bleibt das auch so. Hier schimmert sie
  jetzt lila, in derselben Bauweise: unten waermer, nach oben dunkel,
  in der Mitte kraeftiger, alles unter 30 % Deckkraft.

Dazu die Fassung der Zentrale (rot->lila, Silber und Babyblau
unberuehrt, Prozentzahlen auf den Punkt gleich -- sie sind am 08.09.
eigens nachgerechnet worden), die Uhr an vier Stellen, das Universum
dahinter, Glocke und Tagesruf, der Schriftzug, und auf der Zugangswand
Knopf, Kachelreihe, Innenglas und Karte.

ZWEI FEHLER, DIE ERST DER BILDSCHIRM ZEIGTE:

  Der Schriftzug wurde zu einem ausgefuellten Balken. `background` ist
  eine Kurzschreibweise und setzt `background-clip` mit zurueck -- und
  genau darueber wird der Text in die Buchstaben ausgestanzt. Jetzt
  `background-image`. Im Quelltext sah die Zeile voellig richtig aus.

  Zwei Regeln wurden geladen und taten nichts: Die Originale stehen
  unter `.kopfleiste .marke__haupt` und `.willkommen > .zuniversum`.
  Wer nur die halbe Kette schreibt, verliert gegen zwei Klassen.

DIE MARKE HAENGT JETZT AN ZWEI DINGEN. `markeFuer()` kannte nur die
Rolle -- und DogFather gehoert nun einmal zur Agentur. Ueber der
Zentrale stand deshalb auch auf der zweiten Adresse gross "SPICY
MEDIA". Jetzt entscheidet auch der Hostname, an EINER Stelle.

WAS WARM BLEIBT, UND WARUM: Warnungen. Eine Warnung ist keine
Verzierung, sondern eine Bedeutung -- faerbt man sie ins Lila der
Seite, sieht "etwas stimmt nicht" aus wie alles andere. Sie wird nur
ins Rosa gezogen, damit sie neben Lila kein Fremdkoerper ist. Ebenso
bleiben die 24 Kachelfarben: dass jede Kachel ihre eigene hat, ist
gepruefte Absicht.

Weisse Schrift auf dem Anmeldeknopf haelt jetzt 6,23 zu 1 statt 5,1 --
an echten Bildpunkten gemessen, nicht an der Farbangabe.

pruef-crew-adresse 123 -> 129 · pruef-crew-wand-bild 45 ·
pruef-css-klassen gruen (prueft ab jetzt das PAAR module.css/haus.css,
nicht mehr eine Datei) · pruef-modi-wortleck 5 · pruef-rollen 274 ·
pruef-start-ansicht gruen · pruef-chat-kanaele 79.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 22:35:14 +02:00
DogFatherGitandClaude Opus 5 bcc1c70f4a Spicy Media legt Manager UND Scouts an -- eine Liste statt vier
Filipe, mit Bildschirmfoto der Zugaenge-Seite: "die spicy rolle soll
auch manager und scouts hinzufuegen koennen."

DER MANAGER-KNOPF FEHLTE NICHT AUS RECHTEGRUENDEN. Serverseitig war die
Tuer /workspace/api/manager-anlegen fuer Spicy Media die ganze Zeit
offen. Es gab nur nichts zum Draufdruecken -- wegen ZWEIER Listen in
derselben Funktion, drei Zeilen auseinander (personen.js):

  const darf = ... spicy ? ['manager', 'creator'] : ['creator'];
  ...
  if ((r.wert === 'admin' || r.wert === 'manager') && ich.rolle !== 'admin') continue;

Die erste erlaubt den Manager, die zweite nimmt ihn wieder weg. Uebrig
blieb ein einziger Knopf: Creator. Nichts war kaputt, nichts wurde rot,
es fehlte einfach -- die Sorte Fehler, die nur jemandem auffaellt, der
davorsitzt.

FUER SCOUTS GAB ES UEBERHAUPT KEINE TUER. Nur DogFather konnte welche
anlegen. Und die Wegwahl in der Oberflaeche war eine Kette mit
Auffangbecken (`rolle === 'manager' ? ... : creator-anlegen`): Ein Scout
waere im else gelandet, und creator-anlegen legt IMMER einen Creator an.
Der Knopf haette Erfolg gemeldet und das Falsche getan.

DIE ANTWORT STEHT JETZT AN EINER STELLE. `darfAnlegen` in workspace.js
sagt, wer wen anlegen darf. Daraus lesen:

  - die beiden Team-Tueren (Manager, Scout)
  - die allgemeine Verwaltungs-Tuer von DogFather
  - die Oberflaeche, ueber `darf_anlegen` in /workspace/api/ich

Die Oberflaeche hat damit gar keine eigene Liste mehr und kann deshalb
auch nicht mehr abweichen -- weder zu streng noch zu grosszuegig.

ZWEI TUEREN, NICHT EINE MIT EINEM ROLLENFELD. Der Absatz an der
Manager-Tuer raet davon ab, und der Rat gilt: Eine Tuer, die NICHTS
anderes kann, als eine bestimmte Rolle anzulegen, ist sicherer als eine,
die vorher nachfragt. `teamTuer(rolle)` baut beide aus demselben Text --
die Rolle wird beim Einhaengen festgelegt und kommt nie aus dem Aufruf.
Geprueft: ein mitgeschicktes "rolle: admin" bleibt wirkungslos.

GEPRUEFT (pruef-creator-anlegen, 33 -> 49 Pruefungen)
  - Spicy Media legt Manager an       -> 201, Rolle stimmt
  - Spicy Media legt Scout an         -> 201, Rolle stimmt
  - "rolle: admin" mitgeschickt       -> wirkungslos, es wird ein Scout
  - ein Manager durch die Scout-Tuer  -> 404
  - ein Scout durch die Scout-Tuer    -> 404
  - Personenliste lesen               -> 200 (die eine gewollte Ausnahme)
  - darueber anlegen                  -> 404, und es entsteht niemand
  - /api/ich nennt Spicy: manager, scout, creator -- und keinen DogFather
  - ein Manager bekommt genau eine Rolle genannt, ein Scout keine
  - die Knoepfe auf der Seite stimmen mit alldem ueberein
  - DogFather sieht unveraendert alle -- gemessen, nicht geglaubt

Der erste Anlauf der Pruefung behauptete, Spicy Media komme gar nicht an
/workspace/api/verwaltung. Falsch, und sie wurde zu Recht rot: nurAdmin
laesst genau einen Fall durch, das LESEN der Personenliste. Diese
Trennung ist jetzt festgenagelt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 21:56:45 +02:00
DogFatherGitandClaude Opus 5 5f270c96c5 Beim Umbau einer Tabelle gehen ihre Indizes nicht mehr verloren
GEFUNDEN BEIM NACHDENKEN DARUEBER, WAS DIE NAECHSTE AUSLIEFERUNG AUF
DEM ECHTEN SERVER TUT -- nicht im Betrieb, nicht von einer Pruefung.

checkListeErweitern() baut eine Tabelle neu, wenn eine CHECK-Regel
erweitert werden muss: neue Tabelle, Daten hinueber, alte weg,
umbenennen. Sechs Aufrufe gehen durch diese Funktion. `DROP TABLE`
nimmt aber JEDEN Index der Tabelle mit, und der Bauplan aus
sqlite_master beschreibt nur die Tabelle -- die neue stand danach blank
da.

Gemerkt haette es niemand: Die Abfragen laufen weiter, sie lesen nur
die ganze Tabelle. Beim naechsten Neustart waere der Index wieder da
(er steht oben im Bauplan). "Bis zum naechsten Neustart falsch" ist
trotzdem kein Zustand, den man einbaut -- und bei einem EINDEUTIGEN
Index waere es keine Frage der Geschwindigkeit mehr, sondern der
Richtigkeit: Die Zusage "einen Kanal je Zustaendigkeit" haette bis zum
Neustart still ausgesetzt.

Beim Ausliefern der Kanaele wird `chat_raeume` genau so umgebaut. Der
Lauf sagt jetzt selbst, was er getan hat:

  'kanal' in chat_raeume.art freigeschaltet, 1 Zeilen, 7 Spalten,
  1 von 1 Indizes uebernommen, Verweise geprueft.

Und er meldet es als ACHTUNG, wenn nicht alle zurueckkommen.

DIE PRUEFUNG LAEUFT JETZT AUF EINER ALTEN DATENBANK. Bisher legte
pruef-chat-kanaele eine frische an -- dort steht 'kanal' schon im
Bauplan, die Umstellung tut nichts, und der gefaehrlichste Weg im Haus
blieb ungeprueft. Die Datenbank wird deshalb VOR dem Start in die alte
Form gebracht, mit Index und einer Zeile darin. Geprueft wird danach,
dass die Regel erweitert ist, die Spalte dazugekommen, die Zeile noch
da und der Index zurueck.

GEGENPROBE GEFAHREN: Wiederherstellung stillgelegt, Lauf wiederholt --
"FEHL der Index hat den Umbau ueberlebt (idx_chat_kanal_kategorie)".
Sie kann also auch nein sagen.

Der zweite, aeltere Umbauweg im selben Haus (die Artenumstellung fuer
'bigmatch') hat dieselbe Luecke. Er bleibt hier unangetastet: Das ist
eine dritte Abschrift derselben gefaehrlichen Prozedur, und sie ohne
eigene Pruefung anzufassen waere genau der Handgriff, der Daten
kostet. Notiert, nicht nebenbei erledigt.

pruef-chat-kanaele 73 -> 79 · pruef-spicy 60 · pruef-modi-ideen 30 ·
pruef-rollen 274.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 20:21:42 +02:00
DogFatherGitandClaude Opus 5 d92ba76e33 Kategorie-Kanaele und angeheftete Ankuendigungen (Kapitel 7.2)
Die vier Saetze aus dem Anforderungsdokument, der Reihe nach: Team-
Gruppenchat, Kategorie-Kanaele mit Zugriff fuer Owner und rechte Hand,
private 1:1-Chats OHNE diesen Zugriff, und Pin-Nachrichten an alle.

EIN KANAL IST KEINE VIERTE TABELLE, sondern eine dritte Art Raum
(`art = 'kanal'` neben 'direkt' und 'gruppe'). Damit gilt fuer ihn ohne
eine einzige neue Zeile alles, was schon da ist: Verlauf, Anhaenge,
Suche, Ungelesen-Zaehler, Live-Strom, Wegraeumen. Eine eigene Tabelle
haette all das ein zweites Mal gebraucht -- und die zweite Fassung waere
die gewesen, in der die Zugriffsregel fehlt.

Welche Zustaendigkeit, kommt aus MODI_KATEGORIEN -- derselben Liste, aus
der auch die Aufgaben ihre Kategorie nehmen. Der NAME kommt aus der
Kategorie und ist kein freies Feld: "Clipping" neben "Clipping-Team"
waeren zwei halbe Verlaeufe, und man merkt es erst, wenn jemand die
Antwort im falschen sucht. Ein eindeutiger Teilindex haelt das auch
dann fest, wenn zwei Anfragen im selben Augenblick ankommen.

DIE ZUGRIFFSREGEL STEHT IN istDrin() -- der Funktion, durch die alle
sieben lesenden und schreibenden Wege gehen. In den Routen stuende sie
in sechs davon und in der siebten nicht. Sie gilt AUSDRUECKLICH nur
fuer 'kanal': Zweier-Gespraeche bleiben zu, auch fuer DogFather (so
steht es im Dokument), und Gruppen ebenfalls -- wer eine Gruppe
aufmacht, hat sich fuer einen geschlossenen Kreis entschieden, und den
nachtraeglich still zu oeffnen waere das Gegenteil dessen, was er getan
hat. Wenn Filipe das anders will, ist es eine Zeile -- aber es waere
seine Entscheidung und muesste fuer die Beteiligten SICHTBAR sein.

istDrin() nimmt dafuer die PERSON statt ihrer Nummer und wirft bei
einer Nummer einen Fehler, statt stillschweigend "nein" zu antworten.

HOECHSTENS DREI ANKUENDIGUNGEN je Raum. Nicht eine (Regeln, Live-Plan
und Frist muessen gleichzeitig oben stehen koennen) und nicht beliebig
viele -- eine Pinnwand, die scrollt, ist ein zweiter Verlauf. Der
Aushang hat eine EIGENE Abfrage, weil der Verlauf nur 200 Zeilen
liefert: Eine Ansage von vorletzter Woche waere sonst genau dann weg,
wenn sie am laengsten oben stehen sollte. Wird die Nachricht
zurueckgenommen, faellt sie ab UND gibt den Platz frei.

DREI DINGE, DIE ERST DAS HINSEHEN GEZEIGT HAT:

  Der frisch angelegte Kanal hatte zwei Leute statt vier. Die
  Personenauswahl zeichnete nach der Rollenfolge aus bereiche.js -- wer
  dort nicht steht, wurde NICHT GEZEICHNET. Team Dogi steht dort nicht
  und darf es auch nicht (der Rollenname gehoert in keine Datei, die
  jeder herunterlaedt). Folge: DogFather konnte ueber die Auswahl
  niemandem aus seinem Team schreiben. Der Server schickt die
  Ueberschrift jetzt mit; der Browser braucht dafuer keinen
  Rollennamen. Der Kommentar, der genau davor warnte, stand die ganze
  Zeit darueber.

  Dieser Fehler war nebenbei ein Netz: Was nicht gezeichnet wird, kann
  auch nicht falsch gezeichnet werden. Deshalb ist jetzt gemessen, dass
  ein Manager und Spicy Media Team Dogi gar nicht erst geschickt
  bekommen -- und dabei fiel auf, dass Spicy Media in der EIGENEN
  Auswahl stand: Sobald es jemanden zu verbergen gibt, schreibt
  ohneVerborgene() aus "sieht alles" eine echte Liste, und darin steckt
  man selbst.

  Am Fuss jeder Nachricht stehen jetzt vier Handgriffe statt drei. Bei
  390 px -- der haeufigsten Handybreite -- stand "kopieren" 18 px ueber
  der Blase, bei 320 px 75. Behoben mit `flex-wrap: wrap` und nicht mit
  einer Schwelle: Eine Regel, die misst, bleibt beim fuenften Handgriff
  richtig; eine Zahl nicht. pruef-chat-optik misst es ab jetzt.

NACHGEZOGEN, was pruef-css-klassen an MEINEM letzten Commit fand:
teamlage.html lud kopf.js ohne wahl.js (der Sicht-Umschalter sah aus
wie aus einem anderen Programm -- kaputt war nichts, und genau deshalb
faellt es niemandem auf), und .tampel__tag stand auf 11,2 px. Beides
war schon gepusht, weil ich die Pruefung nicht laufen liess.

pruef-chat-kanaele 73 (neu) · pruef-chat 48 · pruef-chat-ausbau 64 ·
pruef-chat-anhaenge 60 · pruef-chat-optik 24 -> 26 · pruef-css-klassen
gruen · pruef-rollen 274 · pruef-modi-verborgen 78 · pruef-team-ampel 28
· pruef-start-ansicht gruen · pruef-modi-wortleck 5 ·
pruef-zwischenspeicher 21.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 20:18:04 +02:00
DogFatherGitandClaude Opus 5 6b2f34d105 Verfuegbarkeits-Ampel im Eingang -- und eine eigene Gruppe fuer Team Dogi
Filipe: "ich will dass die kacheln von den modis bei der rolle dogfather
eine eigene kategorie haben. damit ich nicht zwischen den kacheln
suchen muss."

DIE AMPEL (Blueprint 7.1). Der Eingang zeigt je Person sieben Tage:
gruen frei, gelb belegt, rot voll ab 180 Minuten. Die Abfrage sammelt
Termine ueber VIER Wege (creator_id, teilnehmer_id, erstellt_von und
die Tabelle termin_teilnehmer) -- ueber nur einen davon waeren die
meisten Termine unsichtbar geblieben und die Ampel dauerhaft gruen.
Sie waehlt NIE titel, beschreibung oder ort: Filipe soll sehen, WANN
jemand kann, nicht WAS die Person vorhat. Belegung ist Arbeitslage,
Inhalt ist privat.

DIE GRUPPE. Die zwei Team-Kacheln standen zwischen einundzwanzig
anderen. Jetzt tragen sie `gruppe: "Team Dogi"` und `gruppeNach:
"Täglich"`; start.js setzt eine so markierte Gruppe direkt HINTER die
genannte statt ans Ende. Ohne das waere sie unten gelandet -- richtig
gruppiert und trotzdem zum Suchen.

Das Ideen-Board ist dabei aus workspace/assets/js/bereiche.js
ausgezogen. Es stand dort mit `rollen: ['admin']` in einer Datei, die
jeder Modi herunterlaedt: die Kachel war unsichtbar, ihr Name nicht.
Jetzt liefert der Server sie, wie den Eingang auch.

DREI FEHLER, DIE DER BILDSCHIRM GEZEIGT HAT, NICHT DER CODE:

  Das Profilbild sprengte die Karte. teamlage.js baute ein blankes
  <img> in `.tperson__zeichen` -- ohne die Klasse `tperson__bild`, die
  es auf 44 px begrenzt. Gemeldet hat es Filipe mit einem Bildschirm-
  foto, nicht eine Pruefung.

  Der Eingang hatte ueberhaupt keine Buehne. `zuSeite()` sucht nur in
  bereiche.js, und die Eingangs-Kachel kommt vom Server -- der Rueck-
  fall war ausgerechnet der Spicy-Wasserfall. Jetzt haengt das Bild an
  `data-buehne="eingang"` im CSS, wo kein Skript daran vorbeikommt.

  Pausierte Mitglieder verschwanden. `WHERE aktiv = 1` versteckte sie
  samt ihrer offenen Meldungen. Jetzt stehen sie hinten, sichtbar
  gekennzeichnet.

DIE ERWARTUNG IN pruef-start-ansicht steht auf FUENF Gruppen, in
ihrer Reihenfolge -- die Position ist hier die eigentliche Aussage.
Eine Gruppe, die ans Ende rutscht, faellt auf dem Bildschirm kaum auf.
Die Kachelzahl blieb bei 24: umgezogen, nichts hinzugefuegt.

pruef-team-ampel 28, pruef-team-stufen 24, pruef-rollen 274,
pruef-crew-adresse 123, pruef-modi-ideen 30, pruef-modi-wortleck 5,
pruef-zwischenspeicher 21, pruef-start-ansicht gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 18:08:27 +02:00
DogFatherGitandClaude Opus 5 241b408edc Eigene Buehnen fuer die Modi-App -- und die Kopfleiste dazu
Filipe: "auch die hintergrund bilder vom crew espace sollen anderes
aussehen, der community angepasst wie die zugangscode seite die ist
mega."

UMFAERBEN HAETTE HIER NICHT GEREICHT. Bei der Zugangswand war Rot das
Problem; innen zeigen die neun Buehnen das SPICY-MEDIA-LOGO selbst, in
`halle` und `arena` vielfach nebeneinander. Ein blaues fremdes Logo
waere schlimmer gewesen als ein rotes.

Die Motive gibt es laengst -- auf der oeffentlichen Dogfather-Seite:
  studio/lounge  "Team Dogi -- Familie. Treue. Zusammenhalt."
  halle          TEAM DOGI mit den Menschen des Teams
  skyline/portal "Streamplan": Dogi und HasiDog auf der Buehne
  arena          "DogFathers Galerie": Filmrollen, ein Archiv
  garage         "Der Streamer": Filipe an seinem Platz

Fuer `garage` stand zuerst der Holo-Kontrollraum da -- grossartiges
Bild, aber darauf steht "WERDE MODI". Eine Einladung hinter dem
Aufgabenbrett von Leuten, die laengst dabei sind, liest sich falsch.
Ein Bild sagt etwas, auch wenn es nur Hintergrund ist.

DIE ABDUNKLUNG IST GERECHNET, NICHT GEWAEHLT
Mein erster fester Wert haette 18 von 27 Fassungen HELLER gemacht als
die, die sie ersetzen (114 gegen 67) -- ueber ihnen steht derselbe
kleine Text. Das Werkzeug misst jetzt jede Fassung gegen die bestehende
Buehne derselben Szene und senkt sie genau auf deren Wert.

Ueber eine KURVE statt eines schwarzen Schleiers: v' = 255*(v/255)^g
senkt die Lichter viel staerker als die Tiefen -- das Bild wird dunkler
und behaelt seine Zeichnung. Ein Schleier haette bei den hellsten
Motiven ueber 80 % gebraucht, und darunter liegt dann Nebel statt Bild
(derselbe Fehler wie beim Tresorbild).

Der erste Anlauf mit einer geschlossenen Formel war falsch: Die Kurve
wirkt auf jeden FARBKANAL, die Helligkeit ist eine gewichtete Summe der
drei, und L(v^g) ist nicht L(v)^g. Die Rechnung sagte 61,5 und heraus
kamen 67. Jetzt wird genaehert und nachgemessen, hoechstens sechsmal.

Beim Hochkant-Ausschnitt wird zusaetzlich das FENSTER GESUCHT: fuenf
Kandidaten, erst "dunkel genug", dann "am meisten Motiv". Die Mitte --
die das Haus sonst nimmt -- ist bei diesen Bildern das Hellste.

ZWEI FUNDE AUS DEM BILDSCHIRMFOTO, die nichts mit den Buehnen zu tun
hatten:

1. DIE KOPFLEISTE sagte "SPICY & DOGI · CREATOR WORKSPACE". Reitertitel,
   Begruessung und Symbol waren laengst richtig -- nur die Zeile, die
   man als Erstes ansieht, nicht. Der Grund: Auf Unterseiten traegt die
   Leiste einen Rueckweg-Verweis, auf der Startseite blossen Text; mein
   Code kannte nur die erste Bauform.

2. DAS CHILI-ZEICHEN kommt aus dem CSS als Bild, an drei Stellen
   (Kopfleiste, Siegel im Ring, die schwebenden Wasserzeichen). Auf
   crew. wird die Datei serverseitig durch den Husky ersetzt -- alle
   drei auf einmal, und ohne Flackern, weil schon der erste Abruf das
   richtige Bild bekommt.

GEMESSEN
pruef-crew-adresse  123 (statt 117): Fuer JEDE Buehne aus start.css --
                    die Namen werden dort GELESEN, nicht abgeschrieben --
                    gibt es auf crew. ein eigenes Motiv, auf workspace.
                    das alte, und die beiden sind nachweislich
                    verschiedene Dateien.
pruef-rollen        274   pruef-start-ansicht, pruef-zwischenspeicher 21
pruef-modi-wortleck   5 -- er hat wieder angeschlagen, zweimal auf
                    Kommentare, die ich selbst geschrieben hatte.

27 Fassungen, 3,5 MB (die bisherigen neun Szenen brauchen 7,1).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 17:02:54 +02:00
DogFatherGitandClaude Opus 5 449fe35c0a Der Eingang: Mitglieder-Kachel, drei Stufen -- und lesbar statt leer
Zwei Auftraege in einem Zug: "mach weiter" (Blueprint Kapitel 4/4.1)
und, zum Bildschirmfoto der Seite, "das muss viel krasser sein".

KAPITEL 4 -- DIE MITGLIEDER-KACHEL
Der Blueprint nennt: "Name & Foto · Rolle(n)/Kategorie(n) · Status
(aktiv/pausiert) · Anzahl offener Aufgaben · Datum 'Modi seit' ·
Schnellaktionen". Name, Foto und Zahlen standen schon; Status, "dabei
seit", Stufe und ein Knopf zum Schreiben kommen dazu.

KAPITEL 4.1 -- DIE DREI STUFEN
Probe, Standard, Senior. Sie sind eine ARBEITSEINTEILUNG, keine
Rechtegrenze -- was ein Modi darf, haengt an der Rolle; die Stufe sagt,
wo er im Team steht. Gesetzt werden sie nur von DogFather: Der
Blueprint gibt der rechten Hand den gleichen UEBERBLICK, aber
"Verwaltungsrechte optional durch Owner freischaltbar", also aus.
NULL heisst "Probe" und nicht "unbekannt" -- ein dritter Zustand waere
eine Frage, die niemand beantworten kann.

ZWEI ECHTE FEHLER, BEIDE VON DER NEUEN PRUEFUNG GEFUNDEN

1. PAUSIERTE VERSCHWANDEN KOMPLETT. In der Abfrage stand `AND aktiv =
   1`. Wer jemanden pausierte, bei dem verschwand er samt seiner
   OFFENEN RUECKMELDUNGEN aus dem Eingang -- die warteten weiter auf
   eine Antwort, nur sah sie niemand mehr.

2. DER EINGANG HAETTE AUF FRISCHER ANLAGE 503 GELIEFERT. Die
   Checklisten-Tabellen entstehen beim ersten Aufruf einer Checkliste;
   diese Seite liest sie aber auch. Wer sie oeffnete, bevor je jemand
   eine Checkliste angesehen hatte, bekam einen Fehler ohne Erklaerung
   -- auf einer neuen Anlage also beim allerersten Blick. Das Schema
   hat jetzt einen Besitzer, der es herausgibt; ein zweites CREATE
   TABLE waere der Anfang von zwei Schemata gewesen.

"VIEL KRASSER" -- UND ZWAR MIT INFORMATION, NICHT MIT LAERM

  * ZWEI REIHEN STATT EINER. Alle fuenf Kaesten lagen in EINEM Raster
    mit 150 px Mindestbreite: Im Bildschirmfoto stand "Community 12
    von" -- abgeschnitten mitten in der Zahl -- und die laengste Liste
    machte die ganze Reihe so hoch wie sich selbst. Jetzt oben, was
    eine Antwort braucht, darunter das Team; 300 px Mindestbreite.
  * DIE KARTE WAR FAHL, und das war ein Fehler: `--r` fiel auf ein
    helles Grau zurueck, aus dem das Kantenlicht einen Nebel ueber die
    ganze Karte legte. Sie traegt jetzt die Farbe der Stufe -- kein
    Nebel, und man sieht am Rand, wer wo steht.
  * SECHS ZAHLENKAESTEN WURDEN DREI BALKEN. "40 offen" beantwortet
    nicht, wie weit man ist: 40 von 40 ist etwas anderes als 40 von
    100. Gruen (in Ordnung) und Bernstein (zu besprechen) fuellen den
    Balken; die ganze Zeile ist der Weg dorthin.
  * DIE DREI ZAHLEN DER SEITE stehen oben als Zahlen statt in einem
    Satz. Die Warnfarbe erscheint NUR, wenn wirklich etwas wartet --
    eine Null in Bernstein waere ein Alarm ohne Anlass, und ab dem
    dritten Mal sieht man ihn nicht mehr.

GEMESSEN
pruef-team-stufen (neu)  24, mit Gegenprobe: hoch- und zurueckstufen,
                         und dieselbe Stufe zweimal zu setzen darf
                         keine zweite Protokollzeile erzeugen
pruef-rollen            274   pruef-modi-checkliste  59
pruef-zwischenspeicher   21
Ansicht: Rechner 1440 und Handy 412 -- keine Skriptfehler, nichts
ragt seitlich heraus (0 px).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 16:27:44 +02:00
DogFatherGitandClaude Opus 5 cdddf32183 Husky bei DogFather und der Rechten Hand, Pfote bei den Modis
Filipe mit Bildschirmfoto: "bei rechte hand soll der husky sein und bei
modis soll die pfote sein."

DAS DREHT EINE FRUEHERE VORGABE UM, und der Grund gehoert in den Code:
Am 09.09. hiess es "das modi symbol soll das gleiche sein wie bei
dogfather" -- damals gab es dort zwei Rollen, und der Satz bedeutete
"die Modis gehoeren zu Dogi, nicht zur Agentur". Mit drei Rollen sagt
dieselbe Absicht etwas anderes: Der Husky steht bei den beiden, die den
Ueberblick haben, die Pfote bei denen, die taeglich unterwegs sind.
Zwei gleiche Zeichen und ein anderes lesen sich als Gruppe, nicht als
Reihe.

GEPRUEFT WIRD DIE ZUORDNUNG, NICHT DAS AUSSEHEN
An beiden Stellen -- Zugangswand und Rollenauswahl in der
Personenverwaltung -- wird gegen die DogFather-Karte verglichen, nicht
gegen "#r-husky": Waere dort morgen ein anderes Zeichen, muesste die
rechte Hand mitwandern. Gewollt ist "dasselbe wie er".

DAZU DIE GEGENPROBE, die vorher fehlte: Der Modi muss sich davon
UNTERSCHEIDEN. Ohne sie waere die Zeile darueber auch dann gruen, wenn
alle drei Karten dasselbe truegen -- und genau so sah es bis heute
Nachmittag aus.

Nebenbei hat der Wortleck-Test wieder angeschlagen: Meine eigene
Begruendung fuer die Pfote nannte zum Vergleich eine Rolle der anderen
Wand. In einer Datei, die auf crew. ausgeliefert wird, hat die nichts
verloren.

GEMESSEN
pruef-crew-adresse      117 (statt 115 -- die neue Zuordnungspruefung)
pruef-personen-formular  27   pruef-crew-wand-bild  45

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 16:03:04 +02:00
DogFatherGitandClaude Opus 5 d36f122926 Die alte Wand schweigt: ein Modi-Code zaehlt dort wie ein erfundener
Filipe: "auf der workspace seite fuer die agentur und so sollen die modis
von mir nicht mehr rein kommen." Das war seit dem Deploy schon so -- ein
Modi bekam dort keine Sitzung. Offen war nur, WIE die Wand reagiert:
Bis eben zeigte sie ihm den Weg zur neuen Adresse. Seine Entscheidung:
"gar nichts -- Code stimmt nicht."

WARUM DAS EIN ANDERER WEG IST UND NICHT NUR EINE ANDERE ANTWORT

Ein schlichtes `return 401` haette die richtige Meldung gezeigt und
trotzdem eine Spur hinterlassen: Der verborgene Zugang waere weiterhin
befragt worden -- ein Suchschluessel-Treffer und EIN scrypt-Durchlauf
statt der Kandidatenschleife der gewaehlten Kachel. Das ist messbar, und
Zeitunterschiede sind genau die Spur, die dieser Zugang vermeiden soll.

Deshalb wird stillerZugang() auf den drei alten Adressen ueberhaupt
nicht mehr aufgerufen. Der Code faellt danach durch den gewohnten Weg
wie jeder unbekannte: dieselbe Schleife, derselbe Eintrag in `versuche`,
dieselbe Antwort, dieselbe Dauer. Die alte Wand verhaelt sich exakt so
wie an dem Tag, bevor es diese Rollen gab.

GEPRUEFT WIRD DIE UNUNTERSCHEIDBARKEIT, NICHT DER STATUSCODE
Eine 401 waere leicht zu erfuellen und truege trotzdem eine Spur, wenn
Rumpf oder Koepfe anders aussaehen. Die Pruefung schickt deshalb einen
echten Modi-Code und einen frei erfundenen an dieselbe Wand und
vergleicht Zeichen fuer Zeichen:

  ok  workspace.: der Modi-Code wird abgewiesen wie ein erfundener (401)
  ok  workspace.: und die Antwort ist Zeichen fuer Zeichen dieselbe
  ok  workspace.: die neue Adresse wird nicht genannt

DER PREIS, und er gehoert genannt: Ein Modi mit der alten Verknuepfung
sammelt dort jetzt Fehlversuche wie jeder andere. Acht in zehn Minuten
sperren seine IP -- auch fuer die neue Adresse, denn die Sperre haengt
an der IP, nicht am Hostnamen.

GEMESSEN
pruef-crew-adresse    115 (statt 114 -- die neue Gegenprobe)
pruef-rollen          274   pruef-modi-verborgen  78

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 15:44:18 +02:00
DogFatherGitandClaude Opus 5 63b3ace3fa Die rechte Hand -- drei Rollen auf der Adresse des Teams
Filipe: "3 rollen. dogfather. rechte hand und modis. perfektionier das."

DIE RECHTE MUSSTE ICH NICHT ERFINDEN. Sie stehen im Blueprint V3.0,
Kapitel 3.1 und in der Sichtbarkeitsmatrix 3.2: "Gleicher Ueberblick wie
Owner. Kann Modis im Alltag koordinieren. Verwaltungsrechte optional
durch Owner freischaltbar." Also: alle Aufgaben, Ideen und Angebote des
Teams, der Eingang samt Entscheidungen, die Checklisten der Modis zum
Ansehen -- aber keine Personenverwaltung (laut Blueprint "optional",
also standardmaessig aus) und keine privaten Kalender oder Einzelchats.

DER EIGENTLICHE UMBAU WAR NICHT DIE ROLLE, SONDERN EINE MENGE.
Bis heute hiess "verborgen" im Code `rolle === "modi"` -- an acht
Stellen. Bei ZWEI verborgenen Rollen ist das genau die Sorte Stelle, die
man an sieben von acht Orten nachzieht; die achte faellt niemandem auf,
weil dort dann einfach jemand sichtbar ist, der es nicht sein sollte.
Ein vergessener Rechteschutz meldet sich nie.

Jetzt lesen alle Regeln aus TEAM_DOGI_ROLLEN: die SQL-Ausblendung
(ohneModi heisst deshalb jetzt ohneTeamDogi), die verborgenen Nummern,
die Marke, die Adressregel, die Schranke beim Anlegen. Eine dritte
verborgene Rolle waere eine Zeile.

Die Menge wohnt in crew-adresse.js und nicht bei den uebrigen Rollen:
workspace.js importiert jene Datei. Andersherum waere es ein Kreis --
Node loest ihn auf, aber mit halb gefuellten Modulen, und das faellt
erst zur Laufzeit auf.

ZWEI LOECHER, GEFUNDEN BEIM SYSTEMATISCHEN NACHLESEN
1. Die Bereichsschranke griff nur bei Modis -- die rechte Hand waere
   ueber die Adresszeile in die Agentur-Ablage gekommen.
2. Ihr Ideen-Board und ihr Angebote-Brett waeren LEER geblieben: Sie
   fiel durch den Team-Zweig hindurch in die Betreuungsregel, die fuer
   sie nichts findet. Derselbe Fehler wie am 01.09. beim Manager und am
   09.09. beim Modi -- und er meldet sich nie, weil ein leeres Brett
   nicht nach Fehler aussieht.

NEBENBEI EINE ALTE SCHWACHSTELLE WEG
gate.js hatte eine zweite Namensliste fuer die Rollen, mit dem Kommentar
daneben, sie sei "genau die Stelle, die beim naechsten Mal wieder
vergessen wird" -- was schon passiert war. Mit zwei Zugangswaenden
haette sie die Namen BEIDER tragen muessen, in einer Datei, die jeder
bekommt. Sie liest den Namen jetzt aus der Kachel, wo er ohnehin steht.

Die Zugangswand hat drei Kacheln: DogFather (Husky), Rechte Hand
(Pfote, neu) und Modi (derselbe Husky, Wunsch vom 09.09.). Die Pfote
liegt am naechsten an "rechte Hand", ohne eine Hand zu sein.

GEMESSEN
pruef-rollen           274 (statt 245; 128 statt 112 Durchgaenge)
pruef-crew-adresse     114   pruef-modi-verborgen     78 (statt 75)
pruef-modi-checkliste   59   pruef-crew-wand-bild     45
pruef-modi-ideen        30   pruef-personen-formular  27 (statt 25)
pruef-modi-katalog      29   pruef-modi-kategorien    25
pruef-zwischenspeicher  21   pruef-modi-livecheck     16
pruef-modi-wortleck      5   pruef-start-ansicht, pruef-bereiche-lesend

Jede gestiegene Zahl hat einen Grund: Die neue Rolle laeuft in DENSELBEN
Listen mit wie die Modis, nicht in eigenen. pruef-modi-verborgen war
vorher gruen, ohne sie ein einziges Mal angesehen zu haben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 15:18:26 +02:00
DogFatherGitandClaude Opus 5 8bcbd83061 Die Modi-Seite gehoert Dogi und den Modis -- Wand, Zeichen, Reiter
Filipe zum Bildschirmfoto der Zugangswand auf crew.: "alles soll auf
dogfather und die modis perfektionniert werden auf der neuen modi seite."

Dort stand bis eben die gewohnte Wand: Spicy-Media-Logo, "Creator
Workspace", der Satz ueber Manager, Scouts und Creator, fuenf
Rollenkacheln. Fuer einen Modi war davon nichts richtig.

DIE KACHELREIHE FAELLT WEG, und das ist eine Verbesserung: Eine Reihe mit
genau einem Eintrag ist keine Auswahl, sondern eine Huerde -- man muesste
erst daraufdruecken, bevor das Codefeld etwas annimmt. gate.js prueft
jetzt, OB es Kacheln gibt, statt sie vorauszusetzen.

DIE BUEHNE IST AUS DEM VORHANDENEN MOTIV GEBAUT, nicht neu erfunden, und
das ist kein Sparen: Die Anmeldeseite ist eine MECHANIK. Rechts steht im
Bild eine leere Tafel, und gate.css setzt die Karte auf Hundertstel genau
dort hinein. Ein frei erfundenes Bild haette diese vier Zahlen
mitgenommen. Also dieselbe Szene, ueber den Mischmodus "color" ins Blau
umgefaerbt (hue-rotate haette Rot nach Cyan UND Blau nach Gelb gedreht),
Dogi anstelle des Spicy-Medaillons, "TEAM DOGI" darunter.
Gemessen: rote Bildpunkte 18,1 % -> 0,0 %, Karte auf 0 px genau.

NACH DER ANMELDUNG geht es weiter: kopf.js zieht Reitertitel und Zeichen
aus `ich.marke` nach -- "Aufgaben · Team Dogi" statt "· Spicy & Dogi", mit
dem eigenen Symbol. An einer Stelle statt in 30 HTML-Dateien.

DREI FUNDE, DIE NICHT AUS DEM KOPF KAMEN

1. DER KNOPF WAERE SCHLECHTER LESBAR GEWORDEN. Mein erstes Blau endete
   bei #4aa4cf -- weisse Schrift darauf: 2,8 zu 1. Der rot-blaue Verlauf,
   den er ersetzt, haelt ueber seine GANZE Laenge 4,65; er war offenbar
   genau darauf gebaut. Jetzt 5,10 zu 1, am fertigen Bildschirmfoto
   gemessen statt aus einer einzelnen Farbe hergeleitet.

2. DIE NEUE WAND WAR AUCH AUF workspace. ABRUFBAR. Sie liegt als Datei im
   selben Ordner. Aufgefallen ist das, weil der Wortleck-Test sie ueberhaupt
   las -- die Frage WARUM war die Antwort. Ausserhalb von crew. antwortet
   sie jetzt mit 404; auf den Pruefadressen bleibt sie erreichbar, sonst
   koennte die Pruefung sie nicht mehr oeffnen und waere gruen ohne etwas
   zu messen.

3. ZWEI GLEICHE KACHELN AUF DER STARTSEITE, seit dem letzten Deploy live.
   Die Team-Lage-Kachel von heute Mittag hatte Name, Zeichen, Ton UND
   Gruppe einer schon vorhandenen -- fuehrte aber woandershin. Gefunden
   von "jede Kachel hat ihre eigene Farbe (23 Farben auf 24 Kacheln)".
   Jetzt "Eingang", Gruppe Taeglich, neuer Ton 24 (#8a20cf, Abstand 38,5
   im CIELAB-Raum; reines Blau haette 52 gehabt und waere auf dunklem
   Grund am schlechtesten zu fokussieren). Eine Fehlermeldung zeigte
   dadurch auf die falsche Seite -- ebenfalls behoben.
   Und die Pruefung, die es fand, zaehlte nur bereiche.js: Vom Server
   angehaengte Kacheln kannte sie nicht. Sie fragt jetzt beide Quellen.

Der Wortleck-Test meldete ausserdem sieben Fundstellen -- allesamt
Kommentare, die ich beim Bauen selbst geschrieben hatte.

GEMESSEN
pruef-crew-adresse     103   pruef-crew-wand-bild    43 (neu)
pruef-modi-checkliste   59   pruef-modi-verborgen    75
pruef-rollen           245   pruef-zwischenspeicher  21
pruef-modi-wortleck      4   pruef-start-ansicht     gruen

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 13:59:54 +02:00
DogFatherGitandClaude Opus 5 3cda64568d Die Modi-App bekommt ihre eigene Adresse: crew.dogfather-universe.com
Filipe: "ich will dass es eine eigene app wird" -- und dann "subdomain
machen jetzt sofort". Name von ihm gewaehlt: crew. (unauffaellig).

Auf einem Ursprung laesst sich genau EINE App installieren (w3c/manifest
Nr. 1180). Derselbe Grund, aus dem der Workspace am 06.09. umgezogen ist.
Getrennt wird ueber den HOSTNAMEN: ein Dienst, eine Datenbank, ein
Verzeichnis wie bisher.

DIE REGEL STEHT AN EINER STELLE
crew-adresse.js beantwortet: Darf diese Rolle auf dieser Adresse
angemeldet sein? Eingehaengt in sitzungLesen() -- durch die Funktion geht
jedes der 26 Fachmodule und jede Seitenschranke. Eine Middleware daneben
kann man in einem neuen Modul vergessen, und ein vergessener Rechteschutz
faellt nicht auf, weil dann alles geht.

  crew.      nur Modis; jeder andere bekommt 401 wie bei einem Tippfehler
  workspace. keine Modis mehr; sie bekommen den Weg zur neuen Adresse
  localhost  UNVERAENDERT

Die dritte Zeile ist der Kern: Die Regel ist eine AUFZAEHLUNG der drei
echten Adressen, nicht "alles ausser crew". Sonst wuerden sieben andere
Pruefdateien ab sofort messen, dass ein Modi nirgends hereinkommt -- gruen,
weil sie nichts mehr finden.

ZWEI APPS, ZWEI NAMEN
Beide Adressen liefern dieselben HTML-Dateien. Auf crew. wird
/workspace/app.webmanifest serverseitig auf crew.webmanifest umgebogen --
so braucht keine der 30 Seiten eine zweite Zeile, die man bei der 31.
vergisst. "Team Dogi" statt "Creator Workspace", eigenes Zeichen:
derselbe Husky, aber ohne Chili (die gehoert zu Spicy Media, nicht zu
ihnen) und im Modi-Ton #5f8a9f.

tools/crew-symbol.mjs erzeugt die sechs Symbole und bricht ab, wenn sie
sich zu weniger als 10 % vom Workspace-Symbol unterscheiden. Gemessen:
43 bis 53 %.

GEMESSEN
pruef-crew-adresse    74 Pruefungen, 0 Fehler -- mit Gegenprobe: der Modi
                      bekommt in der Datenbank die Rolle 'manager', danach
                      MUSS dieselbe Sitzung auf crew. ins Leere laufen
pruef-rollen          245, unveraendert (die Regel ist lokal wirkungslos)
pruef-workspace-umzug 31 Faelle
pruef-zwischenspeicher 21 -- ein Stempel im Haus, jetzt ueber 23 Dateien

Der Server kennt die Adresse damit. DNS und Caddy bleiben Filipes Schritt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 13:07:12 +02:00
DogFatherGitandClaude Opus 5 05f262eb61 Modis verteilen Aufgaben statt sie zu bekommen -- und Angebote zur Entscheidung
Die drei Beurteilungs-Bereiche liefen bisher in die falsche Richtung: Sie
bewerteten die Modis. Filipe: "die modis sind ja da um mir zu helfen."
Also umgedreht.

WAS SICH GEDREHT HAT
- Alle 101 Punkte sind jetzt Beobachtungen ueber den Stream, nicht
  Pflichten des Modis ("Der Ton blieb verstaendlich" statt "Ton geprueft").
- Nur der Modi selbst drueckt auf seiner Liste. Wer sonst darauf zeigt,
  bekommt 403 und den Weg zur Team-Lage -- bewerten wird hier niemand.
- "Verbessern" landet als Eingang bei DogFather. Ein Klick macht daraus
  eine Aufgabe mit dem Satz des Modis im Text, oder eine Absage mit Grund.
  Beides schreibt eine Nachricht zurueck, damit der Modi sieht: angekommen.

ANGEBOTE
Neuer Bereich, in dem Modis planen und vorschlagen: Nutzen und Aufwand
statt Bewertung und Dringlichkeit, dazu ein Feld "was DogFather danach
tun muss". Wird ein Angebot angenommen, entstehen zwei Aufgaben -- eine
beim Modi zum Umsetzen, eine bei DogFather aus genau diesem Feld.

GEMESSEN
pruef-modi-checkliste  59 Pruefungen, 0 Fehler (neu geschrieben)
pruef-rollen          245 statt 244 -- der Zuwachs ist die neue
                      Angebote-Kachel, alle 11 Modi-Kacheln kommen an
pruef-modi-ideen       30, pruef-modi-verborgen 75, pruef-bereiche-lesend: gruen

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 12:52:45 +02:00
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
DogFatherGitandClaude Opus 5 fb45072d25 Die Live-Checkliste am Termin -- ein Knopf, keine Automatik
KAPITEL 5.7 UND 11: "Wird pro Live-Termin als Checkliste erzeugt und den
eingeteilten Modis zugewiesen."

DAS DOKUMENT SAGT "AUTOMATISCH", FILIPE HAT SICH FUER EINEN KNOPF
ENTSCHIEDEN (10.09.2026). Vierzehn Aufgaben, die bei jedem Termin von
selbst erscheinen, ueberrumpeln -- und was ungefragt Dinge anlegt, ist
schwer wieder loszuwerden. Wer einen Termin nur zum Merken eintraegt,
haette danach aufzuraeumen.

Ein Druck erzeugt die vierzehn Punkte aus Kapitel 11 (fuenf vorher,
fuenf waehrend, vier danach), mit dem TERMINTAG als Frist -- eine
Vorbereitung, die nach dem Live faellig wird, ist keine -- verteilt auf
die eingeteilten Modis, jede mit ihrer Kategorie.

DREI STELLEN, AN DENEN SO ETWAS ERFAHRUNGSGEMAESS KIPPT. Alle drei
vorher benannt, dann gemessen:

  * ZWEIMAL DRUECKEN. Der zweite Druck legt nichts an. Und der Knopf
    zeigt die Zahl ("Checkliste (14)") -- sonst drueckt man ihn zur
    Sicherheit noch einmal und weiss hinterher nicht, ob doppelt
    angelegt wurde.
  * DAS ZWEITE LIVE. Hier waere der Fehler teuer: Die Kennung, an der
    "schon uebernommen" erkannt wird, traegt jetzt die TERMINNUMMER
    (`mk-vor-technik#42`). Ohne sie stuende beim zweiten Live alles als
    erledigt da, und niemand bekaeme seine Liste. Geprueft mit zwei
    echten Terminen.
  * EIN TERMIN OHNE EINGETEILTE MODIS. Vierzehn herrenlose Aufgaben
    waeren schlimmer als keine -- stattdessen kommt eine Rueckfrage.

KEIN ROLLENNAME IM BROWSER, wie ueberall: Der Server schickt ein Ja/Nein
("gehoert der Knopf hierhin") und eine Zahl ("wie viele stehen schon").
Aus einer Zahl laesst sich nichts schliessen. Ein Manager bekommt den
Knopf gar nicht erst -- und wenn er es ueber die Schnittstelle versucht,
wortgleich dieselbe Absage wie fuer eine erfundene Art.

DIE ZAEHLUNG LAEUFT IN EINER ABFRAGE fuer alle Termine im Blick, nicht
je Zeile eine. Bei dreissig Terminen waeren das dreissig Abfragen -- den
Fehler hat das Haus bei den Teilnehmern schon einmal gemacht und drei
Zeilen darueber ausdruecklich vermerkt.

DIE TERMINE IN DER PRUEFUNG LIEGEN RELATIV in der Zukunft (+3 und +10
Tage). Ein festes Datum holt der Kalender irgendwann ein, und dann ist
die Pruefung rot, ohne dass etwas kaputt ist -- genau so ist es am
06.09.2026 bei der Oeffnungsschranke des Shops passiert.

GEPRUEFT: pruef-modi-livecheck (16, neu), pruef-kalender, pruef-serien
(69), pruef-vorlagen, pruef-modi-katalog (29).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 02:40:51 +02:00
DogFatherGitandClaude Opus 5 e1608ee783 Das Ideen-Board -- und fuenf Kacheln, die ins Leere fuehrten
KAPITEL 5.6: "Sammelstelle fuer Content-, Live- und Community-Ideen mit
Priorisierung." Fast nichts davon musste neu gebaut werden: `eintraege`
hat Titel, Text, Status und `dringlichkeit` (hoch/mittel/niedrig) -- und
das IST die Priorisierung. Eine eigene Tabelle daneben waere eine VIERTE
Sichtbarkeitsregel gewesen; genau deren Vervielfaeltigung hat heute
schon ein Leck verursacht.

Der Bereich gehoert niemandem einzeln (`ohneCreatorBezug`) -- eine Idee
gehoert der Runde. KEIN `fuerAlle`: Das waere der naheliegende Griff
gewesen und der falsche, denn es heisst woertlich JEDER. Wer die
Sammlung sieht, entscheidet dieselbe Regel wie ueberall.

DER RISKANTE TEIL WAR DIE DATENBANK. Die erlaubten Bereiche stehen als
CHECK-Regel, und SQLite kann die nicht aendern -- die Tabelle muss neu
gebaut werden. Die alte Umstellung fuer 'agentur' schreibt dafuer den
ganzen Bauplan von Hand ab; im Kommentar dort steht, dass dabei schon
einmal drei Spalten vergessen wurden. Statt einer vierten Abschrift ist
die Fassung von heute Morgen jetzt tabellenunabhaengig
(checkListeErweitern): Spaltenliste aus der Tabelle, Sicherung vorher,
Zaehlung innerhalb der Transaktion.

UND DABEI WAERE EIN STILLER TOTALAUSFALL PASSIERT. Das Muster fuer den
Tabellenkopf stand in einem Template-Literal -- dort verschluckt
JavaScript den Backslash, aus `\s` wird `s`, das Muster hiess
"CREATE TABLEs+..." und traf nie etwas. Die Umstellung haette
SCHWEIGEND nichts getan: kein Fehler, kein Hinweis, nur ein Bereich, den
es nie gegeben haette. Im Quelltext war das nicht zu sehen; gefunden hat
es eine Messung. Jetzt steht dort gar kein Muster mehr -- alles vor der
ersten Klammer IST der Tabellenkopf, und das kann man nicht falsch
maskieren.

Die Pruefung baut deshalb eine ECHTE ALTE Tabelle und laesst die
Umstellung darauf laufen. Eine frische Datenbank bringt den Bereich
schon mit -- die Umstellung liefe gar nicht erst an, und alles waere
gruen, ohne das Riskante angesehen zu haben.

=== DER GROESSERE FUND ===

FUENF VON ZEHN MODI-KACHELN FUEHRTEN INS LEERE. Der Server hat eine
Liste, welche Rolle welche Seite oeffnen darf; bereich.html und
profil.html schlossen 'modi' aus. Vier Bereichs-Kacheln und das eigene
Profil leiteten wortlos auf die Startseite zurueck.

Der Rollen-Rundgang meldete sie trotzdem als "ok", und zu Recht: Eine
Umleitung ist kein Fehler. Die Seite laedt, keine rote Konsole, keine
4xx-Antwort. Sie ist nur eine ANDERE. Das ist eine eigene Fehlerklasse
-- nicht "kaputt", sondern "fuehrt woandershin" -- und sie faellt nur
dem auf, der die Anwendung benutzt und merkt, dass ein Knopf nichts tut.

Beinahe waere meine eigene Pruefung darauf hereingefallen: Sie fand auf
der zurueckgeleiteten Startseite das Wort "Ideen-Board" -- den Text der
KACHEL -- und hielt sie fuer das Board. Jetzt steht die Adresse in der
Bedingung.

DIE SPERRE DAGEGEN GILT AB SOFORT FUER ALLE: pruef-rollen klickt fuer
JEDE Rolle jede Kachel durch, die sie angeboten bekommt, und verlangt,
dass sie dort ankommt. Geprueft wird die Zusage der Startseite, nicht
eine Liste daneben -- eine Liste koennte selbst veralten. 113 -> 243
Pruefungen; der Zuwachs ist genau das.

Er hat im ersten Anlauf zwei weitere Loecher gefunden:

  * "Mein Profil" war die falsche Seite. profil.html ist der
    Creator-Entwicklungsplan und antwortet mit 404, wenn die Person kein
    Creator ist. Die eigene Seite heisst steckbrief.html.
  * content.html stand auf `null` ("jede angemeldete Rolle") -- mit der
    neuen Rolle also auch sie. Die Seite laedt, ihre Schnittstelle gibt
    404. Das ist die Kehrseite von "geschuetzt ist die Regel, nicht die
    Ausnahme": Eine NEUE ROLLE erbt jedes `null` automatisch.

Und ein Modi kommt nur in SEINE Bereiche -- sonst waere er ueber die
Adresszeile in der Agentur-Ablage gelandet. Welche erlaubt sind, wird
aus seinen Kacheln abgeleitet statt danebengeschrieben.

=== KLEINERES, ABER SICHTBARES ===

Ueber dem Board stand "Betreuung" -- die Beschriftung fuer Akten, die
UEBER jemanden gefuehrt werden. Eine Sammelstelle ist das Gegenteil.
Aufgefallen auf dem Bildschirmfoto, wie so oft heute.

Der Farbton der Kachel ist nicht nach Gefuehl gewaehlt: Alle 22
vorhandenen waren belegt, also wurde der Abstand zu jedem ausgerechnet
und der genommen, der sich am deutlichsten unterscheidet, ohne grau zu
wirken (#5f8a9f, Abstand 127).

BEINAHE HAETTE ICH EIN LOCH REPARIERT, DAS ES NICHT GIBT: Meine Pruefung
meldete, die Suche verrate die Ideen an Spicy Media. Tatsaechlich fand
sie null Treffer -- die Pruefung hatte ihren EIGENEN Suchbegriff
wiedergefunden, weil die Antwort ihn im Feld `frage` zurueckspiegelt.
Gezaehlt wird jetzt, was gefunden wurde.

pruef-spicy erwartete den alten Wortlaut der Umstellungsmeldung. Sie
nennt jetzt Tabelle und Spalte statt "Rolle"; geprueft wird der Sinn,
nicht der Satz.

GEPRUEFT: pruef-modi-ideen (30, neu), pruef-rollen (243 statt 113),
pruef-modi-verborgen (75), pruef-modi-katalog (29), pruef-spicy (60),
pruef-css-klassen, pruef-start-ansicht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 02:19:06 +02:00
DogFatherGitandClaude Opus 5 138bcce80b Spicy Media sah die Zeilen der Modis -- drei Tabellen, ein Loch
GEMESSEN, NICHT VERMUTET, und es war live: Aufgaben, Bereichs-Eintraege
und Dateien eines Modis waren fuer Spicy Media sichtbar. Die NAMEN der
Modis waren ueberall sauber verborgen -- ihre ZEILEN nicht. Eine halbe
Verborgenheit ist keine.

WARUM ES PASSIEREN KONNTE: Fuer Personen gibt es die Regel EINMAL
zentral (verborgeneIds). Fuer Zeilen gibt es sie DREIMAL -- in
workspace-aufgaben.js, workspace-bereiche.js und workspace-dateien.js --
und alle drei geben Spicy Media dasselbe: "alles ausser dem, was
DogFather gehoert" (ohneDogFather). Ein Modi-Eintrag gehoert ihm nicht,
also fiel er durch.

Manager, Scout und Creator waren nie betroffen, ihre Regeln sind enger.
Der Kalender auch nicht: termineSichtbar() gibt jedem nur Eigenes.
Beides nachgesehen, nicht angenommen.

GEFUNDEN HAT ES KEINE UEBERLEGUNG, sondern eine Pruefung, die etwas
ANLEGT und danach mit fremden Augen nachsieht. Vorher hatte ich nur
Namenslisten geprueft -- und die waren die ganze Zeit gruen. Der Anlass
war nicht einmal Misstrauen gegen diese Stelle: Ich wollte ein
Ideen-Board auf die Eintraege setzen und dabei wissen, wer sie sieht.

BEHOBEN mit ohneModi() als Gegenstueck zu ohneDogFather -- und zwar als
UMHUELLUNG um die drei Regeln, nicht als Flicken darin. Ein Flicken
haette den einen bekannten Zweig geschlossen und den naechsten
Rollenzweig wieder offen gelassen; gemerkt haette es niemand, weil an
der geaenderten Stelle nichts davon steht.

Dazu die `fuerAlle`-Ausnahme bei den Eintraegen: Sie haengt ein ODER an
und haette die Bedingung sonst wieder aufgemacht. Heute hat kein Modi
eine Kachel in einen solchen Bereich -- ein Aufruf an der Oberflaeche
vorbei braucht sie aber nicht. Eine Regel, die nur im Formular gilt,
ist keine Regel.

Nachgesehen, dass die Umhuellung nirgends das falsche Tabellenkuerzel
setzt: Alle Aufrufstellen in workspace-hinweise.js und workspace-suche.js
fuehren die Tabellen als a, d und e -- genau so, wie es dasteht.

NEBENBEI: Das Modi-Team teilt sich jetzt auch die Bereichs-Eintraege,
nicht nur die Aufgaben (Entscheidung Filipe, 09.09.2026: "sie sind
untereinander ein Team"). Ohne diesen Zweig saehe jeder Modi nur, was er
selbst geschrieben hat -- eine gemeinsame Sammlung waere keine.

ZWEI EIGENE FEHLER AUF DEM WEG DAHIN, beide festgehalten:

  * Die neue Messung stand HINTER der Gegenprobe. Die macht eine Person
    absichtlich zur Creatorin -- die Messung bekam 403 und meldete
    "kann nichts anlegen". Gemessen wurde ein Zustand, den es im
    Betrieb nicht gibt. Genau davor warnt der Kommentar, den ich selbst
    zwei Tage vorher an diese Gegenprobe geschrieben hatte.
  * Das "konnte nicht nachsehen" nannte KEINEN Grund. Damit ist der
    dritte Ausgang nur dem Namen nach da -- man weiss danach so wenig
    wie vorher. Erst mit der Fehlermeldung im Text kam ich auf die Spur.

GEPRUEFT: pruef-modi-verborgen (75, davon 18 neu ueber drei Tabellen und
fuenf Rollen), pruef-spicy (60), pruef-bereiche-lesend,
pruef-aufgabenbrett, pruef-modi-katalog (29).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 01:34:02 +02:00
DogFatherGitandClaude Opus 5 390f592967 Der Modi traegt denselben Husky wie DogFather
Wunsch Filipe (Bildschirmfoto, 10.09.2026): "das modi symbol soll das
gleiche sein wie bei dogfather".

Vorher stand dort das Schild, und das war doppelt falsch: Es gehoert
schon dem Scout, und es stellte die Modis neben die Agentur statt zu
DogFather. Sie sind SEIN Team -- das Zeichen sagt das jetzt auch.

Kein neues Zeichen dafuer: `#r-husky` steht in personen.html laengst.
Ein eigenes waere eine Zeile mehr in einer Datei, die jeder bekommt --
und eine, die nur bei einer einzigen Rolle benutzt wird.

DIE PRUEFUNG VERGLEICHT GEGEN DIE ADMIN-KARTE, nicht gegen "#r-husky".
Waere dort morgen ein anderes Zeichen, muessten beide mitwandern --
der Wunsch war "dasselbe wie", nicht "der Husky".

AUF DEMSELBEN BILDSCHIRMFOTO stand "Sichtbar nur fuer die
DogFather-Rolle". In Kommentaren schreibt das Haus ASCII, in TEXT, den
jemand liest, nicht -- dort sieht es aus wie ein Fehler, weil es einer
ist. Berichtigt und mitgeprueft.

NEBENBEFUND, NICHT ANGEFASST: Im Creator-Katalog stehen zehn weitere
sichtbare Texte mit ASCII-Ersatz ("dafuer", "zaehlt", "spaet",
"groesser", "uebersteuert"). Sie stehen live auf den Bildschirmen der
Creator. Nachgemessen: In meinem eigenen Katalog aus Teil 2 sind es
0 von 120 sichtbaren Texten. Die zehn gehoeren berichtigt, aber nicht
nebenbei in einem Commit ueber ein Symbol.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 01:24:26 +02:00
DogFatherGitandClaude Opus 5 60e875814b Die 60 Aufgaben aus Teil 2 -- und kein Wort zu viel im Browser
Kapitel 14 des Anforderungsdokuments: "Alle Aufgaben dieses Katalogs
koennen 1:1 als Vorlagen in die App importiert werden -- inklusive
Kategorie, empfohlener Rolle und Frequenz. So ist das Aufgaben-Board ab
dem ersten Tag vollstaendig befuellt, statt leer zu starten."

DER KATALOG. 60 Aufgaben, Verteilung wie im Dokument: 12 Aufbau, 9
Alltag, 5 vor / 5 waehrend / 4 nach dem Live, 8 Content, 5 Woche, 5
Monat, 7 Community. Neun Etappen statt sechs Phasen -- Phase 3 zerfaellt
in Vor/Waehrend/Nach und Phase 5 in Woche/Monat, und das sind fuer den,
der davorsitzt, verschiedene Momente. "Waehrend des Lives" sucht man
nicht in derselben Liste wie "einmal im Monat".

Die TEXTE sind neu. Das Dokument nennt nur die Titel, und ein Titel
allein ("Eskalationsregeln definieren") sagt nicht, woran man erkennt,
dass man fertig ist. Jeder Satz nennt das EINE, was zaehlt -- nicht
drei, denn wer sich fuenf Dinge vornimmt, macht keines.

Uebernehmen legt eine ganz normale Aufgabe an, einzeln oder eine ganze
Etappe. Die Kategorie wandert mit: Ohne sie muesste man 60-mal von Hand
einsortieren, was im Dokument bereits danebensteht -- und niemand
merkte es, weil die Aufgabe ja da ist. Genau das prueft die neue
Pruefung ausdruecklich.

KEINE NEUE ADRESSE, kein neuer Feldname mit dem Rollennamen darin: Der
Katalog kommt unter "katalog" in der vorhandenen Antwort, das
Uebernehmen ueber die vorhandene Route mit einer neuen Art. Wer ihn
nicht bekommt, sieht `null` -- und ein Manager, der die Art trotzdem
schickt, bekommt WORTGLEICH dieselbe Absage wie fuer eine erfundene.

ZWEI SELBSTKORREKTUREN, beide von derselben Sorte:

  * Die Kategorien waren auf ACHT zusammengefasst, begruendet damit,
    dreizehn Knoepfe seien auf einem Handy unbedienbar. Gebaut ist aber
    ein AUSWAHLFELD, keine Knopfleiste -- die Begruendung passte nicht
    zu dem, was ich getan hatte, und haette eine Uebersetzungstabelle
    noetig gemacht ("Branding gehoert zu Planung"), die spaeter niemand
    nachvollzieht. Jetzt sind es die vierzehn des Dokuments, und jede
    Aufgabe traegt genau die Kategorie, die danebensteht.
  * Zwei Erwartungen in meiner eigenen Pruefung waren veraltet, beide
    durch Aenderungen, die ich absichtlich gemacht hatte. Die eine
    suchte woertlich nach "Clipping & Schnitt" -- nach dem Umbenennen
    haette sie nach etwas gesucht, das es nicht mehr gibt, und waere
    gruen gewesen, ohne etwas zu pruefen. Die Namen kommen jetzt aus
    derselben Quelle wie die Oberflaeche.

UND WIEDER HAT ES DAS BILDSCHIRMFOTO GEZEIGT, nicht der Code: Die
Kopfleiste sagte auf jeder Seite "Creator Workspace" -- fuer jemanden,
der moderiert statt einen Kanal aufzubauen, der falsche Name. Sie folgt
jetzt demselben Weg wie die Zierzeile auf der Startseite. Nur der
Verweis wird umgeschrieben, der Seitenname dahinter bleibt; das
geschuetzte Leerzeichen ebenfalls, sonst faellt die Leiste auf schmalen
Handys in zwei Zeilen.

BEWUSST NICHT ANGEFASST: Im Hintergrundbild steht schwach "SPICY
MEDIA". Es ist kein Element im HTML, sondern in die buehne-*.webp
eingebacken -- dafuer braeuchte es einen zweiten Bildersatz. Nachgesehen
statt vermutet: Im DOM der Seite kommt der Text nicht vor.

GEPRUEFT: pruef-modi-katalog (29, neu), pruef-modi-kategorien (25),
pruef-modi-wortleck (4), pruef-rollen (113), pruef-kopf-messen,
pruef-vorlagen, pruef-aufgabenbrett.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 01:20:24 +02:00
DogFatherGitandClaude Opus 5 ede34fe386 Der Rollenname stand in zwei Dateien, die jeder bekommt
SELBST EINGEBAUT, EINE STUNDE VORHER. Beim Bau der Kategorien habe ich
SECHS Vergleiche und VIER Kommentare mit dem Rollennamen nach
assets/js/aufgaben.js und assets/js/start.js geschrieben -- waehrend ich
an anderer Stelle penibel darauf achtete, ihn herauszuhalten.

Alles unter workspace/ geht an JEDEN, der die Seite oeffnet. Ein Blick in
den Quelltext, und der ganze verborgene Zugang waere gefunden gewesen:
nicht wer ein Modi ist, aber dass es die Rolle ueberhaupt gibt -- und
genau das war Filipes Bedingung ("damit die von der workspace auch nicht
mal sehen dass die modis von mir einen eigenen zugang haben").

Gefunden habe ich es durch Nachsehen, nicht durch Nachdenken. Nachgedacht
hatte ich vorher schon, und zwar richtig -- beim Anzeigenamen und bei der
Rollenauswahl habe ich es sauber ueber den Server geloest. Eine Stunde
spaeter habe ich dieselbe Regel dreimal gebrochen, ohne es zu merken.

WAS AN DIE STELLE TRITT, dreimal derselbe Gedanke:

  * Das Vorlagenbrett: /workspace/api/vorlagen liefert den Katalog jetzt
    schlicht nicht an die Betroffenen. `if (!vorlagen) return` laesst das
    Brett dann verborgen -- dieselbe Wirkung, ohne eine Zeile, die
    verraet, fuer wen sie gilt.
  * Das Kategorie-Feld: statt `ich.rolle === '...'` kommt vom Server
    `kategorie_fuer` -- NUMMERN statt eines Rollennamens. Aus Nummern
    laesst sich nichts schliessen; wer keine bekommt, sieht eine leere
    Liste, und eine leere Liste sagt nichts. `null` heisst "gilt immer"
    und muss `null` bleiben: Ein `|| []` daraus zu machen waere der
    stille Fehler, aus "gilt immer" wuerde "gilt nie".
  * Die Kommentare sagen jetzt, WAS gilt, ohne zu sagen, FUER WEN.

UND EINE SPERRE DAGEGEN: pruef-modi-wortleck durchsucht alle 73
ausgelieferten Dateien nach dem Rollennamen. Die Regel ist damit kein
Vorsatz mehr, sondern ein Werkzeug -- wer ihn dort hineinschreibt,
bekommt einen roten Lauf statt eines erhobenen Zeigefingers im Kommentar.
Mit Gegenprobe in beide Richtungen: Eine eingebaute Fundstelle MUSS
erkannt werden, und "modifiziert", "Modul", "Modus" duerfen NICHT
anschlagen -- eine Pruefung, die staendig Fehlalarm gibt, wird
abgeschaltet und faengt dann auch den echten Fall nicht mehr.

Die Dateizahl steht in der Bedingung, nicht nur im Meldetext: Faende die
Suche keine einzige Datei, waere sonst alles gruen, ohne dass etwas
angesehen wurde.

AUSSERDEM BELEGT statt behauptet: Dass das Kategorie-Feld bei DogFather
nur erscheint, wenn er wirklich einen Modi eintraegt, steht jetzt in der
Pruefung -- erst ein Creator (Feld bleibt weg), dann ein Modi (Feld
kommt). Ohne den zweiten Schritt waere "bleibt weg" auch dann gruen,
wenn es NIE kaeme.

GEPRUEFT: pruef-modi-wortleck (4, neu), pruef-modi-kategorien (25),
pruef-modi-verborgen (57), pruef-vorlagen, pruef-aufgabenbrett.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 01:05:01 +02:00
DogFatherGitandClaude Opus 5 114a00eed5 Der Modi bekommt seine eigene Seite -- und sein Brett zurueck
DER WICHTIGSTE FUND, und er kam nicht aus dem Nachdenken: Ein Modi sah
auf dem Aufgabenbrett GAR NICHTS -- nicht einmal seine eigenen Aufgaben.
sichtbar() endet mit `default: 0=1`, und 'modi' stand nicht darin.

Genau dieser Fehler ist am 01.09.2026 schon dem Manager passiert; der
Kommentar zwei Zeilen darueber warnt woertlich davor ("Ein leeres Brett
sieht aus wie 'nichts zu tun', nicht wie ein Fehler; deshalb ist das
vermutlich lange niemandem aufgefallen"). Der Rollen-Rundgang meldete
fuer den Modi trotzdem brav "aufgaben.html ok" -- die Seite laedt ja,
sie war nur leer. Gefunden hat es erst eine Pruefung, die eine Aufgabe
ANLEGT und sie danach wiederzufinden versucht.

Ein Modi sieht jetzt die Aufgaben des ganzen Modi-Teams (Filipes
Entscheidung "sie sind untereinander ein Team"), aendern darf er
weiterhin nur seine eigenen. Die Nummern werden bei jeder Abfrage frisch
gelesen -- eine beim Serverstart gebaute Liste waere ab dem naechsten
neuen Modi falsch, und niemand wuesste warum.

DIE STARTSEITE. Ein Modi hatte keine einzige Kachel: Jede traegt eine
feste Rollenliste, und 'modi' darf dort nicht stehen -- bereiche.js
bekommt jeder ausgeliefert, der die Seite oeffnet. Die Kacheln kommen
deshalb vom Server (MODI_BEREICHE), samt Beschriftung. Nur die Ziele zu
schicken haette nicht gereicht: Unter "Dashboard" stuende sonst "Alle
Creator auf einen Blick" -- fuer jemanden ohne Creator. Die Worte
gehoeren zum Empfaenger, nicht zum Ziel.

Neun Kacheln in drei Gruppen: Aufgaben, Chat, Kalender, Dateien /
Live-Ablauf, Community, Technik / Profil, Wissen. Nichts aus der
Agentur -- diese Seiten drehen sich um betreute Creator oder um Rechte.

`null` heisst "nimm deine eigene Liste", eine LEERE Liste hiesse "keine
Kacheln". Verwechselte man die beiden, haetten die fuenf bekannten
Rollen ab sofort eine leere Startseite.

ZWEI DINGE HAT DAS BILDSCHIRMFOTO GEZEIGT, NICHT DER CODE:

  * Ueber der Modi-Startseite stand "Spicy Media" -- die Marke einer
    Agentur, mit der er nichts zu tun hat. Jetzt "Team Dogi", wie auf
    der oeffentlichen Seite. Ersetzt wird nur der Textknoten: In dem
    Element sitzen zwei Zierrauten, ein textContent haette sie lautlos
    geloescht.
  * Auf seinem Aufgabenbrett stand das Creator-Vorlagenbrett, 80
    Aufgaben fuer den Aufbau eines Kanals. Fuer einen Moderator ist
    davon nichts gedacht. Ausgeblendet, bis sein Katalog aus Teil 2 des
    Anforderungsdokuments da ist -- nichts ist ehrlicher als etwas
    Fremdes.

Dazu: "0 betreut" stand dauerhaft auf seiner Startseite, eine Zahl, die
nie etwas anderes sagen kann. Jetzt zaehlt sie, wie viele im Modi-Team
sind. Und der Satz unter der Begruessung war nur das Wort "Modi", neben
fuenf Rollen mit einem ganzen Satz -- das sah nicht verborgen aus,
sondern unfertig.

KATEGORIEN (Kapitel 6.1), nach Filipes Entscheidung nur bei den Modis.
Acht Stueck; hier steht, wohin die dreizehn aus Teil 2 fallen
(Branding/Team/Kommunikation -> Planung, Wachstum -> Community).

Der heikelste Fall ist nicht das Setzen, sondern das SCHICKEN durch
jemanden, der es nicht darf: Eine Absage ("Unbekannte Kategorie") waere
die Auskunft, dass es das Feld gibt. Also faellt der Wert lautlos weg
und die Aufgabe entsteht ganz normal. Wer die Kategorien benutzen darf,
bekommt bei einem Tippfehler dagegen sehr wohl eine Absage.

Das Feld erscheint nur, wenn die Aufgabe wirklich zu einem Modi gehoert
-- bei DogFather also erst, wenn er einen als Person auswaehlt. Sonst
stuende es auch an jeder Creator-Aufgabe. Verborgen heisst dabei auch
"nichts mitschicken": Ein Wert in einem unsichtbaren Feld wandert sonst
beim naechsten Speichern mit.

KEINE NEUE CSS-KLASSE fuer die Kategorie auf der Karte. Sie muesste in
sieben gleichlautenden Kopien der Modulliste gepflegt werden -- sieben
Gelegenheiten fuer einen Unterschied, fuer eine Zeile Text.

AUSSERDEM BERICHTIGT, UND ES WAR SCHON VORHER ROT: pruef-start-ansicht
erwartete drei Kachelgruppen. Seit b45de94 gibt es vier ("Rund um das
Team"). Bevor ich die Zahl angefasst habe, habe ich meine Aenderungen
beiseitegelegt und den Lauf wiederholt -- schon auf dem unveraenderten
Stand rot, also nicht von mir. Geprueft werden jetzt die NAMEN: Vier
Gruppen koennten auch drei richtige und eine doppelte sein.

GEPRUEFT: pruef-modi-verborgen (57), pruef-modi-kategorien (22, neu),
pruef-rollen (113 statt 97 -- der Modi laeuft jetzt ueber jede der 16
Seiten), pruef-start-ansicht, pruef-aufgabenbrett, pruef-sicht,
pruef-verborgen, pruef-personen-formular (24), pruef-personen-liste,
pruef-css-klassen, pruef-spicy (60).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 00:52:06 +02:00
DogFatherGitandClaude Opus 5 7be488e0ca Ein Zugang, den ausser DogFather niemand bemerkt
Aus dem Anforderungsdokument (Master-Blueprint V3.0) fehlte die Rolle
"Modi" ganz -- es gab nur spicy, admin, manager, scout, creator. Filipes
Bedingung dazu: "dass die keine neue eingangs kachel bekommen wie spicy
dogfather und so sondern einfach einen code. damit die von der workspace
auch nicht mal sehen dass die modis von mir einen eigenen zugang haben."

DER EINGANG. Es gibt keine sechste Kachel und es laesst sich auch keine
erzwingen: Wer von aussen `rolle: "modi"` schickt, bekommt wortgleich
dieselbe Antwort wie bei einer erfundenen Rolle. Ein Modi tippt auf
irgendeine vorhandene Kachel -- welche, ist gleichgueltig -- und gibt
seinen Code ein. Der Code allein entscheidet.

Moeglich macht das eine neue Spalte `code_kennung`: ein HMAC ueber den
Code, in Mikrosekunden nachgeschlagen. Zwei naheliegende Wege wurden
verworfen, weil man sie finden kann: ein Merkmal im Code ("M-...") waere
ein sichtbares Kennzeichen auf dem Zettel des Modis, eine eigene Adresse
(/modi.html) eine Seite, die man aufrufen kann. Der Suchschluessel steht
VOR dem gewohnten Weg, nicht dahinter -- ein Rueckfall nach einem
Fehlversuch haette genau die Fehlversuche verlaengert, und daran waere
es zu erkennen gewesen.

Unbedenklich, weil nachgemessen: Ein Code hat 16 Zeichen aus einem
32er-Alphabet, also 80 Bit Zufall. Der Suchschluessel sagt ausserdem nur,
WEN man pruefen soll -- ob der Code stimmt, sagt weiterhin scrypt.

DIE UNSICHTBARKEIT sitzt in verborgeneIds(), also an derselben einen
Stelle wie die Regel fuer den zweiten Admin-Zugang, und nicht in den
rund 170 Abfragen, die Personen lesen. Sie haengt dabei an der ROLLE und
nicht an einer Nummer -- die Schwachstelle, die im Kommentar der alten
Regel offen dasteht (wird Zugang 1 geloescht, rueckt der naechste nach),
kann einer Rolle nicht passieren.

Nach Filipes Entscheidungen: Die Modis sehen sich untereinander (Kapitel
7.2 des Dokuments), VanVan sieht sie mit (Kapitel 3, sie traegt dieselbe
Rolle), Codes gibt Filipe selbst weiter -- kein Einladelink, der in einem
Verlauf landen kann.

ZWEIMAL WAERE DAS WORT "MODI" BEINAHE IN EINER DATEI GELANDET, DIE JEDER
BEKOMMT: in den Rollenlisten von start.js und personen.js. Ein Blick in
den Quelltext haette genuegt. Der Anzeigename kommt jetzt aus
/workspace/api/ich (beschreibt immer nur den Angemeldeten selbst), die
Rollenauswahl aus der Antwort des Servers und nur an die DogFather-Rolle.

GEPRUEFT mit pruef-modi-verborgen.mjs (45 Pruefungen): fuenf Kacheln
fuehren mit dem Modi-Code hinein, ein Manager-Code auf fremder Kachel
weiterhin nicht (sonst waere nebenbei die Rollenpruefung abgeschafft),
und ueber fuenf Schnittstellen sieht ausser DogFather, VanVan und den
Modis niemand etwas -- auch nicht die ZAHL daneben.

Die Gegenprobe steht bewusst ganz unten, weil sie eine Person absichtlich
aus der Regel aushaengt: Weiter oben haette sie jeden Abschnitt danach
verfaelscht. Beim ersten Anlauf stand sie in der Mitte, und prompt tauchte
die Person in einer spaeteren Managerliste auf.

Abschnitt 5 prueft den Weg durch die Anwendung selbst (DogFather legt an,
der Modi meldet sich an). Die Abschnitte davor tragen die Personen von
Hand ein und rechnen den Suchschluessel selbst aus -- damit waere NICHT
bewiesen, dass personAnlegen() ihn im Betrieb schreibt. Ohne ihn kaeme
kein einziger echter Modi herein, und oben waere trotzdem alles gruen.

Die Umstellung der Rollenliste in der Datenbank steht ab jetzt einmal in
rollenRegelUmstellen() statt zum dritten Mal abgeschrieben. Jede Abschrift
waere eine Gelegenheit, eine der vier Absicherungen zu vergessen: Sicherung
vorher, Zaehlung innerhalb der Transaktion, Spaltenliste aus der Tabelle,
Pruefung auf verwaiste Verweise danach.

pruef-personen-formular erwartet jetzt sechs Rollen statt fuenf und prueft
die Liste statt nur die Anzahl -- sechs Karten koennten auch fuenf richtige
und eine doppelte sein. Dass die sechste dort auftaucht, ist gleichzeitig
der Nachweis, dass der Weg ueber den Server funktioniert.

Unveraendert bestanden: pruef-spicy (60), pruef-rollen (97),
pruef-verborgen, pruef-personen-liste, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-10 00:11:39 +02:00
DogFatherGitandClaude Opus 5 88e2b5cd5d Der Wecker: das Zeitfeld ging auf -- nur ausserhalb des Bildschirms
Filipe: "wenn ich am handy auf den wecker drücke dan sieht man nichts."

Er hat woertlich recht. Der Knopf tut, was er soll, und das Zeitfeld
klappt auf -- es steht nur nicht im Bild. Aufgeklappt gemessen, fuenf
Breiten:

  320 px  Feld bei -127 .. -8    komplett draussen
  360 px  Feld bei -107 .. 12
  390 px  Feld bei  -92 .. 27
  412 px  Feld bei  -81 .. 38
  430 px  Feld bei  -72 .. 47

DER GRUND IST EIN ANKER, DER GEWANDERT IST. `.tagesruf__feld` steht mit
`right: 56px` da -- "56 px nach links vom Knopf". Am Rechner ist das
richtig: Dort sitzt der Knopf am rechten Rand einer breiten Kachel, und
links davon liegt die Luecke zwischen Text und Uhr. Auf dem Handy wird
derselbe Knopf aus dem Fluss genommen und neben die zentrierte Uhr
gehaengt -- er steht dann ganz LINKS, und 56 px weiter links ist kein
Raum mehr, sondern der Bildschirmrand.

Der Abstand stimmte also noch, der Bezugspunkt nicht mehr. Dieselbe
Sorte Fehler wie die feste Umbruchschwelle und die 62 px Kopfhoehe: eine
Zahl, die fuer eine Anordnung ausgerechnet wurde und in der zweiten
still falsch ist.

Es oeffnet jetzt auf dem Handy nach RECHTS statt nach links -- in die
Richtung, in der dort der Platz ist. Das ist keine zweite Zahl, sondern
dieselbe Regel andersherum ("ins Freie oeffnen"). Der linke Rand des
Knopfes ist nie kleiner als 0, das Feld 119 px breit, der schmalste
Bildschirm 320 -- damit liegt es auf jeder Breite im Bild, ohne dass
eine Schwelle stimmen muss. `max-width: calc(100vw - 24px)` als
Sicherung, falls das Feld je breiter wird.

Die Regel steht in heim.css direkt neben der Regel, die den Knopf
verschiebt. Sie gehoeren zusammen: Wer den Anker bewegt, sieht die
Folge in derselben Medienabfrage.

GEPRUEFT WIRD ES JETZT AUCH (pruef-handy, 99 -> 115 Pruefungen). Das
Feld wird dafuer aufgeklappt gemessen, nicht zugeklappt -- ein
verstecktes Feld hat keine brauchbare Lage, und genau die ist die
Frage. Gegenprobe ist die Messung von vorher: Mit demselben Messmittel
lag das Feld bei -92..27, die Bedingung waere rot gewesen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 21:57:11 +02:00
DogFatherGitandClaude Opus 5 6c48579f66 Die Kopfleiste bleibt auch in einer fremden Sicht in EINER Reihe
Filipe, mit Bildschirmfoto aus der installierten App: "es ist noch
nicht alles in einer zeile und irgendwie funktionieren nicht alle
knoepfe."

DER GRUND WAR NICHT DIE BREITE SEINES GERAETS, SONDERN DER ZUSTAND.
In der eigenen Sicht klappt der Umschalter auf 36 px zusammen; sobald
man die Sicht einer anderen Person uebernimmt, stand der Name darin und
er war 152 px breit. Gemessen waren es dann zwei Zeilen bei 320, 360,
390, 412 UND 430 px -- ausnahmslos. Auf seinem Bild stand "Miesmus..."
im Umschalter und der goldene Rahmen um die Seite: er war in einer
fremden Sicht.

MEINE PRUEFUNGEN HABEN DEN FALSCHEN ZUSTAND GEMESSEN. pruef-handy lief
ausschliesslich in der eigenen Sicht und war deshalb gruen, waehrend
es beim Nutzer zweizeilig war. Ein gruener Haken sagt nur, dass die
Bedingung erfuellt war -- nicht, dass sie den Zustand geprueft hat, in
dem der Nutzer ist. Die Pruefung wechselt jetzt selbst in eine fremde
Sicht (92 -> 99 Pruefungen).

WAS SICH AENDERT
- Auf dem Handy ist der Umschalter auch in fremder Sicht ein
  Zeichenknopf: Auge + Anfangsbuchstabe, 46-48 statt 152 px, in der
  ROLLENFARBE der Person, deren Sicht laeuft. Die Farbe kommt aus
  `data-rolle` -- dieselbe Zuordnung, die gate.css ohnehin hat, keine
  zweite Farbliste.
- Der volle Name wandert in ein Band unter die Leiste, zusammen mit
  "Zurueck zu meiner Sicht" als ganzem Satz statt als 28-px-Kreuz. Er
  steht dort GANZ statt als "Miesmus...". Am Rechner bleibt alles wie
  bisher; dort ist Platz.
- Der Rahmen um die Seite nimmt dieselbe Farbe an. Man sieht damit
  nicht nur DASS eine fremde Sicht laeuft, sondern WESSEN.
- Das `:not([data-fremd="ja"])` faellt an beiden Stellen weg. Es war
  der ganze Fehler: eine Regel, die den wichtigeren Fall ausnahm.

UND DER BLOCK FUER SCHMALE GERAETE STAND AN DER FALSCHEN STELLE
Er galt bis 340 px und stand 3600 Zeilen VOR dem 560er-Block -- bei
gleicher Spezifitaet verliert er damit. Gewirkt hat er nur, weil sein
Selektor zufaellig ein `:not()` trug. Jetzt steht er direkt hinter dem
560er und gilt bis 400 px (34 px je Knopf, 4 px Abstand). Damit bleibt
auch bei 360 px auf den UNTERSEITEN alles in einer Reihe -- dort stehen
zusaetzlich der Zurueck-Knopf und die Glocke.

Gemessen nach dem Umbau, eigene und fremde Sicht, Start- und
Unterseite: 360, 390, 412 und 430 px alle einzeilig. Offen bleibt
320 px (iPhone SE 1. Generation bzw. Anzeige-Zoom) -- dort passt es
ohne das Weglassen einer Funktion nicht, das ist eine Entscheidung
und kein Handgriff.

DER SICHERE BEREICH (auf Filipes Zusage)
Jede der 20 Seiten sagt `viewport-fit=cover`, aber im ganzen Workspace
stand kein einziges `env(safe-area-inset-*)`. Sein Android ist NICHT
betroffen (im Bildschirmfoto nachgesehen), ein iPhone waere es: Von
einem 36-px-Knopf blieben unter einer 47 px hohen Statusleiste
rechnerisch 5 px zum Antippen. Einmal zentral benannt (gate.css) und an
den vier Stellen angewandt, wo etwas am Rand klebt: Kopfleiste (oben und
seitlich), Inhalt (seitlich und unten), Speichern-Leiste im Profil,
Chat-Eingabe. Auf Geraeten ohne Aussparung sind alle vier Werte 0.

Nebenbei: chat.js misst die Hoehe ueber der Chatflaeche jetzt
einschliesslich des Bandes -- sonst stuende das Eingabefeld genau um
dessen Hoehe unter dem Bildschirmrand. Derselbe Fehler wie mit den
festen 62 px, nur mit einem anderen Element.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 19:44:25 +02:00
DogFatherGitandClaude Opus 5 d0ac8ee8d1 Das Logo: aus dem Fleck wird wieder ein Hund
Filipe: "kannst du bitte das logo wenn man es installiert auf pc oder
handy und oben rechts in der leiste noch perfektionnieren."

Beide Stellen hatten denselben Fehler, und er war derselbe wie an
mehreren Stellen davor: Der Husky lag als MASKE auf einer Farbflaeche.
Von einer Maske zaehlt nur der Alphakanal, und die Vorlage ist rundum
freigestellt -- uebrig blieb eine geschlossene Flaeche in Hundeform.
Kein Auge, keine Schnauze, kein Ohrinneres. Ein Fleck.

Jetzt liegt an beiden Stellen dieselbe Zeichnung im Mischmodus "screen"
ueber einer stahlblauen Silhouette: Schwarz laesst das Fell dunkel,
Weiss hebt Gesicht, Ohren und Auge heraus. Gleiche Farben, gleicher
Daempfer (.88) -- ein Zeichen, zwei Orte.

App-Symbol ausserdem:
- Die Chili lief mit ihrem Stiel quer ueber den Fang. Sie ist jetzt
  gespiegelt, kleiner und liegt hinter dem Hals.
- Der Hals endete in einer geraden Kante (die Vorlage ist unten
  angeschnitten). Eine zweite Maske blendet ihn aus, statt ihn
  abzuschneiden.
- Der Grund war matschig: Rot und Blau trafen sich diagonal genau dort,
  wo der Kopf steht. Jetzt kaltes Licht oben, warmes unten.
- Unter 64 px faellt die Gesichtszeichnung weg, die Chili aber NICHT --
  klein erkennt man ein Zeichen zuerst an der Farbe.
- Alle Masse haengen an einer Zahl (Groesse der Gruppe), nicht an sechs.

Kopfleiste ausserdem:
- Die Chili links hatte einen BLAUEN Schein -- aus der Zeit, als dort
  der Husky stand. Der Schein ist nie mitgewandert. Jetzt warm.
- `filter` ersetzt, es ergaenzt nicht: Beim Ueberfahren wurde der Schein
  geloescht und das Zeichen dabei flacher statt heller. Behoben.

Damit die Aenderung auch ankommt:
- Der Stempel gilt jetzt auch fuer die App-Symbole und fuer das
  Manifest. Bilder werden einen Tag zwischengespeichert, das Symbol der
  INSTALLIERTEN App gar nicht neu geholt -- ohne Stempel haette niemand
  das neue Zeichen gesehen.
- pruef-zwischenspeicher prueft das (18 -> 21 Pruefungen).

Werkzeuge:
- tools/ausschnitt.mjs (neu): schneidet aus einem Bildschirmfoto ein
  Stueck heraus und vergroessert die PNG-Datei. Noetig, weil eine
  Vergroesserung per CSS-transform den Browser NEU rechnen laesst --
  ich habe damit 264 px beurteilt und geglaubt, es seien 22, und daraus
  den falschen Schluss gezogen, ein Gesicht trage bei 22 px nicht.
- tools/ansicht.mjs: AUSSCHNITT=<selektor> nimmt nur ein Element auf.
- workspace-symbol.mjs: SYMBOL_ZIEL lenkt die Ausgabe um (Entwuerfe
  ansehen, ohne die sechs echten Dateien zu ueberschreiben), und zwei
  Gegenproben pruefen jetzt, dass Gesicht und Chili wirklich zu sehen
  sind -- die alte Pruefung sagte nur "es steht etwas drauf" und haette
  den Fleck anstandslos durchgewunken.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 18:24:20 +02:00
DogFatherGitandClaude Opus 5 5881f9ce2d Der Versionsstempel wird jetzt geprueft -- daran haengt das Update
Filipe: "ich hoffe der update passiert bei den benutzern alle immer
automatisch mit."

Nachgesehen statt behauptet. Die Kette lautet:

  HTML geht mit `Cache-Control: no-cache` hinaus (live bestaetigt,
  Cloudflare laesst sie durch: cf-cache-status DYNAMIC)
    -> der Browser holt bei jedem Aufruf die neueste HTML
    -> darin stehen die Versionsstempel der Stilvorlagen
    -> neuer Stempel = neue Adresse = neue Datei.

Das funktioniert. Es haengt aber an EINEM Glied, und das setze ich von
Hand: dem Stempel. Vergesse ich ihn, bekommt der Benutzer die neue HTML
mit den ALTEN Adressen -- und die sind seit heute Mittag ein Jahr lang
gueltig zwischengespeichert. Er saehe die Aenderung monatelang nicht,
und niemandem fiele auf, warum.

--- WIE ERNST DAS IST, HAT SICH HEUTE GEAENDERT ---

Nachgezaehlt in den letzten vierzig Commits an workspace/assets: DREI
haben Stilvorlagen geaendert, ohne eine HTML anzufassen -- 4c0ff5c,
0a0dbff und 7c00e76, letzterer von heute Frueh.

Sie waren harmlos, und zwar aus einem Grund, den ich heute selbst
beseitigt habe: Bis Mittag bekam JEDE Datei `no-cache`, auch jede
Stilvorlage. Ein vergessener Stempel fiel damit nicht auf, weil der
Browser ohnehin bei jedem Aufruf nachfragte.

Seit die Stilvorlagen ein Jahr liegenbleiben duerfen (was richtig ist
-- sie tragen ja einen Stempel), ist derselbe Fehler kein Schoenheits-
fehler mehr, sondern ein stiller Ausfall. Wer eine Sicherung
wegnimmt, muss die Bedingung absichern, unter der sie ueberfluessig
war. Genau das fehlte.

--- DIE BEIDEN NEUEN PRUEFUNGEN ---

1. ALLE Seiten tragen DENSELBEN Stempel. Der wahrscheinlichste Fehler
   ist nicht "gar nicht gesetzt", sondern "auf einer Seite vergessen"
   -- und dann ist genau diese eine Seite kaputt, waehrend alles andere
   stimmt. Mit Gegenprobe.

2. Wer eine Stilvorlage aendert, aendert auch den Stempel. Geprueft am
   letzten COMMIT an assets/, nicht am Arbeitsverzeichnis: Waehrend des
   Bauens ist die Datei immer neuer als der Stempel, und eine Warnung,
   die dauernd kommt, wird weggeklickt.

   Mit dem DRITTEN AUSGANG: Ohne Git-Arbeitsverzeichnis ist die Frage
   nicht zu beantworten, und das wird als "konnte nicht nachsehen"
   gemeldet statt als "in Ordnung" verbucht.

18 Pruefungen in pruef-zwischenspeicher, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 17:36:45 +02:00
DogFatherGitandClaude Opus 5 bec46ed991 Team-Seite: Kopf und Karten sind jetzt echte Kacheln
Filipe, mit Bildschirmfoto: "perfektionnir das in einer kachel in der
farbe von der kategorie bitte. und die kacheln unten in der seite auch
perfektionnieren und geil machen bitte."

--- DER KOPF ---

Er war eine freistehende Ueberschrift auf dem Buehnenbild. Jetzt ist er
eine Kachel wie jede andere im Haus: gefraeste Fase, Kantenlicht,
Eckwinkel, Raster -- alles aus der Modulliste in module.css, wo
`.t-kachel` seit diesem Commit steht.

DIE FARBE IST NICHT ABGESCHRIEBEN. Die Kachel traegt `data-ton="22"`,
und die Regel dazu steht in start.css -- dieselbe, aus der die Kachel
auf der Startseite ihre Farbe zieht (#ffd166). Es gibt weiterhin genau
EINE Stelle, an der die Farbe dieser Kategorie steht; wer sie dort
aendert, aendert beides. Eine zweite Hexzahl in team.css waere die
naechste gewesen, die auseinanderlaeuft.

Der Grenzsatz ("Termine, Chats und Dateien kommen hier nicht vor")
wechselt von Gruen in denselben Ton: In einer Kachel, die schon eine
Farbe hat, ist eine zweite Farbe daneben eine zweite Aussage.

--- DIE KARTEN UNTEN ---

`.tperson` und `.tl` stehen ebenfalls in der Modulliste. Ein
Manager-Kasten leuchtet damit lila, ein Scout-Kasten gruen, ein
Lueckenkasten rot -- ueber `--ton`, ohne dass eine einzige Farbe hier
ausgeschrieben stehen muss.

DER STREIFEN LINKS IST DAFUER WEG, und das ist kein Verlust: module.css
belegt ::before und ::after selbst (Kantenlicht und Eckwinkel) und
laedt NACH team.css -- ein eigenes ::after waere ohnehin wirkungslos
gewesen. Das Kantenlicht traegt die Rollenfarbe jetzt rund um die ganze
Karte statt auf drei Pixeln links.

DIE KENNZAHLEN BLEIBEN SCHLICHT, und das ist eine Entscheidung: Sie
stehen zu acht in einer Karte. Jede davon mit Fase, Kantenlicht und
Eckwinkel waere ein Schaufenster voller Rahmen und keine Auskunft mehr
-- eine Kachel in der Kachel in der Kachel liest niemand. Sie bekommen
nur die abgeschnittene Ecke aus derselben Formel, damit sie erkennbar
zur Familie gehoeren.

--- EIN FEHLER, DEN NUR DAS HANDY GEZEIGT HAT ---

Der Grenzsatz-Kasten hat `flex: 1 1 300px`. Am Rechner ist das richtig:
Dort ist die Hauptachse waagerecht, und er teilt sich die Breite mit
dem Titel. Am Handy dreht die Reihe auf eine SPALTE -- und derselbe
Wert liess ihn in die HOEHE wachsen. Auf dem Bildschirmfoto stand
danach die halbe Kachel leer.

Ein Flexwert gilt fuer eine Richtung, nicht fuer ein Element. Wer die
Richtung dreht, muss ihn mitdrehen.

--- Pruefung ---

pruef-css-klassen: die Modulliste steht weiterhin siebenmal und
Zeichen fuer Zeichen gleich (jetzt 48 Klassen).

pruef-team, 51 Pruefungen: darunter acht Kontrastmessungen an der
WIRKLICHEN Flaeche -- die Hintergruende haben sich durch den Umbau
geaendert, und eine Kachel mit Raster und Verlauf ist etwas anderes als
ein flacher Kasten. Gemessen jetzt 6,71 bis 15,12:1.

Ausserdem gruen: pruef-handy, pruef-lesbarkeit, pruef-buehne.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 16:26:57 +02:00
DogFatherGitandClaude Opus 5 b45de940e8 Rund um das Team -- die Arbeitslage von Managern und Scouts
Filipe: "so eine kategorie wie ueber die creator will ich dass nur fuer
die spicy und dogfather rolle auch ueber manager und scouts gibt ...
ich will dass es so ultra krass gut ist dass die spicy und dogfather
rolle einen kompletten teil haben mit daten ueber die arbeit von den
manager und scout. keine geheimen sachen also termine, chats und
geheime dateien soll auch so bleiben dass keiner."

--- ZUERST DIE KOPFLEISTE ---

Filipe meldete, die Kopfleiste sei bei DogFather "nicht gemacht".
Nachgemessen auf ALLEN 18 Seiten, in allen fuenf Rollen, bei drei
Breiten: einzeilig, Spanne 4 px. Und die neuen Dateien liegen
nachweislich auf dem Server (a70bc4f, `abmelden__zeichen` in der
ausgelieferten kopf.js). Das Bild war vor dem Ausliefern entstanden.

Die Messung hat aber zwei echte Sachen gefunden, die vorher niemand
gesehen hatte -- beide bei 320 px auf UNTERseiten, wo links der
Zurueck-Knopf und rechts zusaetzlich die Glocke steht: 305 px
gebraucht, 294 verfuegbar. Eine Stufe kleiner (34 px je Knopf, 4 px
Abstand) macht 283 und passt; 34 px bleiben weit ueber den 24 px
Mindestmass fuer ein Beruehrziel.

Ausserdem die Auslieferung geordnet: HTML wird immer nachgefragt,
Dateien mit Versionsstempel duerfen ein Jahr liegenbleiben (vorher
bekam ALLES `no-cache`, also auch jede Stilvorlage bei jedem Aufruf).
sw.js ausgenommen -- er wird ohne Stempel geladen, ein Fehler darin
bliebe sonst ein Jahr stehen.

--- DIE NEUE SEITE ---

workspace/team.html, nur fuer `spicy` und `admin`. Aufbau:

  DIE LUECKEN ZUERST. Creator ohne Betreuung, Scouts ohne Manager,
  Leute ohne einen einzigen Creator -- mit NAMEN, nicht nur als Zahl.
  Eine Kennzahl sagt, wie es laeuft; eine Luecke sagt, wo etwas fehlt,
  und nur das Zweite kann man heute abstellen.

  DANN DIE LAGE in fuenf Zahlen, dann JEDE PERSON EINZELN: betreute
  Creator, laufende und ueberfaellige Aufgaben, in 30 Tagen erledigte,
  Durchlaufzeit, Startcheck-Fortschritt der betreuten Creator,
  LIVE-Tage und Diamanten. Bei Scouts zusaetzlich die Pipeline mit
  Uebernahmequote und Zeit bis zur Uebergabe.

  EIN MANAGER TRAEGT DIE CREATOR SEINER SCOUTS MIT. Ohne das saehe
  einer mit fuenf Scouts aus wie jemand ohne Arbeit.

--- DREI ENTSCHEIDUNGEN, DIE ALLES TRAGEN ---

1. TERMINE, CHATS UND DATEIEN KOMMEN NICHT VOR -- weder Inhalte noch
   Zaehlungen. Ausdruecklicher Wunsch, und der richtige: Ein Kalender
   verraet, wann jemand nicht da war; ein Chatzaehler, mit wem jemand
   oft spricht.

   Das ist keine Zusicherung im Kommentar. pruef-team liest den
   Quelltext von workspace-team.js und schlaegt an, wenn eine dieser
   Tabellen darin auftaucht -- mit Gegenprobe, dass die Suche `aufgaben`
   und `leads` auch wirklich findet. Der Weg ueber die Antwort allein
   waere schwaecher: Ein leerer Testbestand kann ein Feld verstecken.

2. SEGMENTIEREN, NICHT MITTELN. Aus der Recherche zu
   Arbeitslast-Dashboards: Ein Durchschnitt versteckt genau die Person,
   bei der es klemmt. Markiert wird gegen den MEDIAN der eigenen Rolle
   -- ein Manager traegt naturgemaess mehr als ein Scout, und ihn daran
   zu messen waere unfair und nutzlos.

3. ES IST EINE ARBEITSLAGE, KEINE UEBERWACHUNG. Das steht so auf der
   Seite, im Kopf, in einem eigenen Kasten. Wer das nicht dazuschreibt,
   baut ein Kontrollwerkzeug, auch wenn er es nicht wollte. Deshalb
   zeigen die Kennzahlen auf ZUSTAENDE (unbetreute Creator,
   liegengebliebene Kontakte) und nicht auf Anwesenheit oder Fleiss.

--- WAS DIE MESSUNG UNTERWEGS GEFUNDEN HAT ---

* Die Lead-Status hiessen anders, als ich angenommen hatte: "kontakt"
  gibt es nicht. Die CHECK-Bedingung der Datenbank hat es sofort
  abgelehnt -- ohne sie waere "offen" still zu klein gewesen.

* Die Pruefung fand ihr eigenes Hinweisschild: Die Antwort traegt ein
  Feld `ausgenommen: ["Termine","Chats","Dateien"]`, aus dem die Seite
  den Satz baut. Es wird jetzt herausgenommen UND eigens geprueft --
  ignorieren waere bequem gewesen und haette kuenftig jedes Feld unter
  diesem Namen durchgelassen.

* Die Lektion vom Vorlagenbrett gleich mitgenommen: alle Karten haben
  einen DECKENDEN Grund. Eine Karte mit sieben Prozent Farbe auf
  durchsichtigem Grund laesst das Buehnenfoto durch -- dort waren es
  3,61:1. Gemessen jetzt: 6,61 bis 14,80:1. Eine der Regeln hatte den
  deckenden Grund selbst wieder aufgehoben (zwei Regeln, die spaetere
  gewinnt) -- gefunden, bevor es jemand sehen musste.

* "1 Scouts" statt "1 Scout". Eine Kleinigkeit, und das Erste, was
  auffaellt: Eine Seite, die ihre eigene Sprache nicht beherrscht, wird
  auch bei den Zahlen nicht geglaubt.

--- Pruefung ---

server/pruef-team.mjs, neu, 51 Pruefungen, alle gruen. Darunter: alle
fuenf Rollen an Schnittstelle UND Seite (Manager, Scout und Creator
bekommen 404 bzw. eine Umleitung), Spicy sieht VanVan nicht (mit
Gegenprobe an der Personenliste), die Zahlen an einem gebauten
Bestand, acht Kontrastmessungen an der wirklichen Flaeche, Handy.

server/pruef-zwischenspeicher.mjs, neu, 15 Pruefungen: was liegenbleiben
darf und was nicht -- an echten Kopfzeilen gemessen, nicht am
Quelltext. Sie meldete zuerst drei Fehler, und das war sie selbst: Sie
fragte unangemeldet und bekam Umleitungen. Eine Pruefung braucht ihre
Voraussetzung, bevor sie misst.

Ausserdem gruen: pruef-handy (das Handy fand die 320-px-Sache),
pruef-workspace-seiten, pruef-alle-wege, pruef-sicht, pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 15:42:14 +02:00
DogFatherGitandClaude Opus 5 a70bc4f235 Kalender: blaettern direkt ueber dem Raster, rot und gruen
Filipe, mit Bildschirmfoto: "ich will dass genau da ueber dem kalender
auch noch buttons sind um den monat zu wechseln, tage wechseln.
perfektionnier mir das bitte. und mach auch die buttons die schon da
sind noch viel klarer bitte und die neuen auch. lass die neuen auch
richtig geil aussehen, die einen rot und die anderen gruen."

--- WARUM DAS EINE ECHTE LUECKE WAR ---

Die Pfeile gab es schon -- oben neben der Ueberschrift, einen halben
Bildschirm ueber dem Raster, das sie bewegen. Wer durch Monate
blaettert, sieht auf das Raster und nicht auf die Ueberschrift; der Weg
dorthin war jedes Mal ein Blicksprung.

Die neuen Knoepfe rufen DIESELBE Funktion (`springen`), sie kopieren sie
nicht. Zwei Fassungen desselben Schritts waeren zwei Gelegenheiten,
dass die eine spaeter anders springt als die andere.

--- BESCHRIFTET, NICHT NUR BEPFEILT ---

Ein Pfeil sagt nicht, WIE WEIT er springt. In der Monatsansicht ist ein
Schritt ein Monat, in der Wochenansicht eine Woche, in Liste und
Zeitstrahl sechs Wochen. Genau das steht jetzt drauf und wird beim
Umschalten mitgefuehrt -- steht "Monat vor" und es springt eine Woche,
ist das schlimmer als gar keine Beschriftung.

"Heute" ist ausgegraut, solange man schon dort steht. Ausgegraut und
nicht versteckt: Sonst springen die drei Knoepfe beim Blaettern in der
Breite. Ein Knopf, der nichts tut, wird sonst einmal gedrueckt und
danach nicht mehr ernst genommen.

--- ROT UND GRUEN, ABER NICHT SIGNALROT ---

Diese beiden Knoepfe stehen den ganzen Tag auf dem Bildschirm. Genommen
sind die Haustoene: das gedeckte Rot der Warnfarbe, das Gruen der
Scout-Rolle. Beide hell genug fuer Schrift auf dunklem Grund, keins
leuchtet.

Die Richtung steckt zusaetzlich in der FORM: Der Pfeil steht links beim
Zurueck und rechts beim Vor. Wer Rot und Gruen nicht unterscheidet --
etwa acht Prozent der Maenner --, liest die Richtung trotzdem.

--- UND DIE VORHANDENEN KNOEPFE ---

Der Ansichts-Umschalter: Die drei nicht gewaehlten Knoepfe waren nackte
Schrift auf dunklem Grund -- sie sahen aus wie Beschriftungen, nicht wie
Schaltflaechen. Wer nicht weiss, dass "Woche" anklickbar ist, klickt
nicht darauf. Sie haben jetzt eine eigene Flaeche; die gewaehlte bleibt
das gebuerstete Metall und hebt sich dadurch sogar deutlicher ab.

Die Filterknoepfe standen auf --text-still, der leisesten Schrift der
Seite -- ausgerechnet an einem Bedienelement. Und "aus" unterschied
sich nur am hohlen Punkt.

--- EIN EIGENER FEHLER UNTERWEGS ---

Am Handy verschwindet das Wort, damit die Leiste nicht umbricht. Der
erste Anlauf liess die Polsterung stehen: Uebrig blieb ein 30 px
breites Pillchen mit einem winzigen Pfeil -- kleiner als das, was man
mit dem Daumen sicher trifft, und die Farbe war darauf kaum noch zu
sehen. Jetzt ein rundes Ziel von 44 px mit einem Pfeil, der die Flaeche
fuellt. Gesehen habe ich das erst auf dem Bildschirmfoto, nicht beim
Schreiben.

--- Pruefung ---

pruef-kalender, elf neue Messungen: beide Knoepfe blaettern wirklich,
die Beschriftung nennt die Schrittweite und folgt der Ansicht
("Monat vor" -> "Woche vor"), "Heute" graut sich richtig aus und wird
wieder anklickbar.

Rot und Gruen werden an ECHTEN Farbwerten geprueft (ueber ein Canvas
zurueckgelesen, weil color-mix() als "color(srgb ...)" herauskommt und
ein Muster ueber die Ziffern Unsinn liest -- derselbe Fehler wie heute
Mittag bei der Personenkachel). Dazu die Gegenprobe, dass die beiden
sich wirklich unterscheiden: Abstand 187.

Ausserdem gruen: pruef-css-klassen, pruef-lesbarkeit, pruef-handy.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 15:05:49 +02:00
DogFatherGitandClaude Opus 5 f3acfab10a Aufgaben: die Bedienung, nicht die Kacheln
Filipe: "ich will dass du dass system jetzt wie die vier kategorien
bedient werden, perfektionnierst ... ich red von den aufgaben. das
system von den aufgaben, die bedienung ... die hauptkachel von der
kategorie nicht veraendern oder anfassen, die bleiben so."

Die vier Kacheln sind unberuehrt. Geaendert ist, was danach kommt.

--- 1. DAS VORLAGENBRETT WAR IM WEG ---

Gemessen am Handy: Der Vorlagenblock fuellte ANDERTHALB BILDSCHIRME,
bevor die erste eigene Aufgabe kam. Und mein eigener Ausbau von Profi
und Meister ein paar Stunden vorher hat ihn noch laenger gemacht --
aus 48 Vorlagen wurden 80.

Das ist die falsche Reihenfolge: Vorlagen holt man selten, das Brett
benutzt man jeden Tag. Der Block bleibt an seiner Stelle (dort gehoert
er hin, weil daraus Aufgaben auf das Brett darunter wandern), ist aber
zugeklappt. Zugeklappt steht dort, WIE VIEL darin liegt -- sonst sieht
er aus wie eine Ueberschrift ohne Inhalt und niemand macht ihn auf.

Wer ihn aufmacht, findet ihn beim naechsten Mal offen: Wer Vorlagen
holt, holt meistens mehrere. Und zugeklappt werden die achtzig Karten
GAR NICHT ERST GEBAUT, nicht nur versteckt.

--- 2. MAN SAH NICHT, WAS MAN SCHON GEHOLT HATTE ---

Dieselbe Vorlage liess sich zweimal uebernehmen, und die Aufgabe stand
dann zweimal auf dem Brett -- ohne jeden Hinweis. Bei achtzig Vorlagen
ueber vier Stufen weiss niemand auswendig, was er letzten Monat schon
geholt hat.

Die Kennung der Vorlage steht jetzt an der Aufgabe (neue Spalte
`vorlage`). Ueber den TITEL zu vergleichen waere die naheliegende
Abkuerzung gewesen -- und faellt in dem Moment um, in dem jemand den
Titel einer uebernommenen Aufgabe aendert.

Uebernommene Karten treten zurueck (nicht: verschwinden -- wer sie
ausblendet, nimmt die Moeglichkeit, sie bewusst noch einmal zu holen),
tragen "schon uebernommen" MIT ZUSTAND, und ihr Knopf heisst
"Nochmal". Darunter steht der Stand: "5 von 7 noch nicht uebernommen."
Es braucht dafuer keine zweite Abfrage -- die Aufgaben liegen ohnehin
im Browser.

--- 3. DRINGEND SCHLAEGT WICHTIG ---

Die Liste war nach PRIORITAET sortiert, dann nach Frist. Auf dem Brett
stand damit eine seit vier Tagen ueberfaellige Aufgabe mit Prioritaet
"niedrig" UNTER einer, die als "hoch" eingetragen ist und erst in
dreissig Tagen faellig wird. Wer die Spalte von oben liest, faengt
dann mit dem Falschen an.

Eine Prioritaet ist eine Einschaetzung von damals, eine
ueberschrittene Frist eine Tatsache von heute. Jetzt: erst was
faellig ist, dann nach Datum, und die Prioritaet entscheidet nur noch
bei gleichem Datum. Die Sortierung steht im SERVER -- Startseite und
Uebersicht lesen dieselbe Liste, und zwei Sortierungen fuer dieselbe
Frage laufen auseinander.

--- 4. "WICHTIG" STEHT JETZT DA ---

Die Prioritaet war ein 3 px breiter Rand links -- direkt neben der
farbigen Kante der Spalte und damit praktisch unsichtbar. Als Wort
steht sie dort, wo man sie liest. NUR bei "hoch" und nur solange
nicht erledigt: Eine Marke an jeder Karte waere keine Marke mehr.

--- Pruefung ---

pruef-aufgaben-vorlagen: zugeklappt als Vorgabe (gemessen wird, dass
die Karten gar nicht gebaut werden), Aufklappen, uebernommene Vorlage
markiert samt Zustand und "Nochmal"-Knopf, Stand darunter, Zustand
ueberlebt das Neuladen -- mit Gegenprobe, dass die uebrigen NICHT
markiert sind.

Dabei fiel eine eigene Nachlaessigkeit auf: Die Pruefung "die Karten
sind gestaltet" mass zu einem Zeitpunkt, an dem es zugeklappt gar
keine Karte gab -- getComputedStyle auf null liefert nichts, und der
Haken wurde rot, ohne dass etwas kaputt war. Sie misst jetzt nach dem
Aufklappen.

pruef-aufgabenbrett: die Sortierung an zwei absichtlich unguenstig
angelegten Aufgaben (ueberfaellig+niedrig gegen fern+hoch), plus die
Gegenprobe, dass bei GLEICHER Frist weiterhin die Prioritaet
entscheidet -- sonst waere die Prioritaet wirkungslos geworden, und
das waere die andere Uebertreibung.

Ausserdem gruen: pruef-css-klassen, pruef-start-ansicht, pruef-uebersicht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 14:56:40 +02:00
DogFatherGitandClaude Opus 5 38416962b3 Kopfleiste am Handy: alles in einer Reihe
Filipe, mit Bildschirmfoto: "ich will dass es ueberall perfektionniert
wird. ich will dass du das richtig geil machst es soll alles in einer
reihe sein." Auf dem Bild stand "Abmelden" allein in einer zweiten
Zeile, darueber Teilen, Chat, Suche und das Profilbild.

--- GEMESSEN, BEVOR ETWAS GEAENDERT WURDE ---

Bei 390 px, alle fuenf Rollen:

  verfuegbar fuer die rechte Gruppe   275 px
  gebraucht als DogFather             393 px
     (Sicht 150 · Teilen 38 · Chat 37 · Suche 47 · Bild 28 · Abmelden 93)
  gebraucht als Scout/Manager/Spicy   243 px
  gebraucht als Creator               205 px

Der Umbruch war also die richtige Antwort auf ein echtes
Platzproblem. `flex-wrap` misst und rechnet nicht -- das bleibt so.
Geaendert wird der PLATZBEDARF, nicht die Reaktion darauf. Eine
Schwelle, ab der nicht mehr umgebrochen wird, waere wieder eine
Rechnung von gestern: Beim naechsten Knopf staende alles uebereinander.

--- WAS SCHRUMPFT, UND WAS NICHT ---

Die drei Zeichen-Knoepfe waren 38, 37 und 47 px breit -- nebeneinander
sah das unruhig aus. Jetzt alle 36.

"Abmelden" wird auf schmalen Bildschirmen zum Zeichen (93 -> 36). Das
Wort bleibt im aria-label und am Rechner sichtbar: Dort ist Platz, und
ein Wort ist eindeutiger als ein Bild. Der Aufbau steht in kopf.js und
nicht in neunzehn HTML-Dateien -- neunzehn Stellen sind achtzehn
Gelegenheiten, eine zu vergessen.

Der Sicht-Umschalter wird ein Zeichen-Knopf wie die anderen (150 -> 36),
ABER NUR solange die eigene Sicht laeuft. Bei einer fremden behaelt er
den Namen, und dann darf die Leiste auch umbrechen: Dass man fremde
Zahlen ansieht, ist wichtiger als eine gerade Zeile. Das ist der
gefaehrlichste Fall dieser Funktion, und er bleibt unangetastet.

--- ZWEI DINGE, DIE ERST DIE MESSUNG GEZEIGT HAT ---

1. `max-width: 30px` am Umschalter-Kasten wirkte NICHT. Gemessen stand
   da: berechnete Hoechstbreite 30 px, tatsaechliche Breite 104. Der
   Knopf DARIN behielt seine Groesse und schob den Kasten wieder auf.
   Wer nur den Rahmen begrenzt, begrenzt nichts -- die Breite kommt vom
   Inhalt. Jetzt liegt der Knopf unsichtbar UEBER dem Auge: die ganze
   Flaeche ist das Ziel, der Fokusring bleibt, die Breite ist 36.

2. Bei 360 px brach es weiter um, obwohl es rechnerisch passte. Ursache
   war eine eigene Regel bei 380 px, die Marke und Bedienelemente
   ausdruecklich in zwei Zeilen zwang -- richtig, solange die
   Bedienelemente 243 bis 393 px brauchten, falsch seit sie 136 bis 238
   brauchen. Die Schwelle liegt jetzt bei 300 px; darunter gibt es
   Geraete, auf denen es wirklich nicht reicht.

--- Pruefung ---

pruef-handy, 15 neue Messungen (fuenf Rollen x 360/390/412): alle Teile
der Kopfleiste stehen in einer Reihe, Spanne 4 px.

Gemessen wird die ZEILENZAHL ueber die Oberkanten, nicht die Hoehe der
Leiste. Eine Hoehengrenze waere wieder eine Zahl von gestern -- sie
stimmt, bis jemand die Polsterung anfasst. Ob zwei Dinge in derselben
Zeile stehen, sieht man an ihrer Oberkante, und das gilt immer.

Ausserdem gruen: pruef-css-klassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 14:45:38 +02:00
DogFatherGitandClaude Opus 5 8c77995c2c Profi und Meister: aus 43 Eintraegen werden 217
Filipe, mit Bildschirmfoto der Stufenleiste (Anfaenger 7,
Fortgeschritten 9, Profi 6, Meister 4): "ich will dass die 2 kategorien
profi und meister ueberall noch mehr perfektionniert werden. ich will
dass da noch mehr aufgeben und moeglichkeiten sind. perfketionier diese
kategorien ultra ultra viel. die muessen richtig krass sein!!!!"

--- ZUERST GEZAEHLT, DANN GESCHRIEBEN ---

Er hatte an einer Zeile gesehen, was ueberall galt. Nachgezaehlt:

  LIVE  Vorbereitung  4 Profi / 3 Meister      gegen 6 Fortgeschrittene
        Mitschrift    2 / 0   <- KEIN einziger Meister-Punkt
        Auswertung    4 / 2
  COMM  Moderation    4 / 2
        Aktion        1 / 1
        Konflikt      1 / 1
  TECH  Setup         3 / 1
        Problem       2 / 1
        Loesung       1 / 2
  Content-Ideen       6 / 3   gegen 10 Anfaenger
  Aufgaben je Bereich 3 / 3

Die oberen beiden Raenge waren ueberall die duennsten. Das ist die
falsche Richtung: Anfaenger ist man ein paar Wochen, Meister bleibt man
Jahre. Wer alles abgehakt hat, was dort steht, findet nichts mehr und
hoert auf hinzusehen.

--- WAS DAZUGEKOMMEN IST ---

  Punkte und Ideen   Profi 28 -> 85, Meister 15 -> 76
  Aufgaben-Vorlagen  Profi 12 -> 28, Meister 12 -> 28

Die neuen Eintraege sind bewusst NICHT nur schwerere Fassungen der
alten. Auf den oberen Stufen aendert sich die ART: weg vom eigenen
Koennen, hin zu Zahlen, Verfahren, anderen Menschen und dem
Weitergeben. Meister-Punkte sind deshalb Saetze wie "der Ablauf ist
uebergebbar", "eine zweite Person kann es auch", "die
Wiederherstellung ist einmal geprobt".

Recherchiert statt aus dem Bauch: Tonkette nach AES-Reihenfolge
(Hochpass, Gate, Kompressor, Begrenzer -- wer den Kompressor vorzieht,
macht das Rauschen mit lauter), Bitrate mit 20 bis 30 Prozent Reserve
auf den gemessenen Upload, Ton mindestens 160 kbit, zwei Wege ins Netz
ueber getrennte Anbieter, die sechsstufige Eskalationsleiter der
Moderation, Schichten gegen das Alleinsein (nicht gegen die Menge --
Isolation zermuerbt Moderatoren mehr als Arbeit), Gruppen nach
Eintrittsmonat statt Gesamtzahlen, ein Beitrag in vier Formate.

Fristen nach Hausregel eingehalten: kein Anfaenger ueber 5 Tage, kein
Meister unter 7. Alle 80 Schluessel eindeutig (zwei Dubletten beim
Einfuegen gefunden und entfernt).

--- UND DIE PRUEFUNGEN, DIE DAS FESTHALTEN ---

Zwei feste Zahlen von gestern ersetzt, statt sie hochzusetzen:
`gesamt === 48` und `nachher === vorher + 3`. Beide wurden in dem
Moment rot, in dem etwas BESSER wurde -- eine Zahl, die Verbesserung
bestraft, erzieht dazu, sie stumpf nachzuziehen. Die erwartete Menge
kommt jetzt aus der Vorlage selbst.

Neu, in pruef-checkliste UND pruef-aufgaben-vorlagen: Profi und
Meister duerfen in KEINER Gruppe duenner sein als Fortgeschritten --
verglichen wird mit Fortgeschritten statt mit einer festen Zahl, damit
die Regel richtig bleibt, wenn alle Stufen wachsen. Mit Gegenprobe.

Diese Regel hat sofort etwas gefunden, das mir entgangen war: Der
erste Ausbau hatte fast nur die Saeule "Wert" verdoppelt. Nach Saeulen
gezaehlt stand da 10/9 bei Wert, aber 2/4 bei Community und 2/0 bei
Eigenwerbung. Die GESAMTsumme (14/13 gegen 9) sah dabei tadellos aus
-- eine Summe deckt eine leere Ecke zuverlaessig zu. 15 Ideen
nachgezogen.

Gruen: pruef-checkliste, pruef-aufgaben-vorlagen, pruef-bereiche-lesend,
pruef-aufgabenbrett, pruef-content.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 14:15:21 +02:00
DogFatherGitandClaude Opus 5 9b1826721b Handy-Mitte, Babyblau und Spicy im Umschalter
Drei Bildschirmfotos, drei Befunde -- und alle drei waren messbar.

--- SCREEN 2: RING UND UHR STANDEN SCHIEF ---

Filipe: "ich will dass auf dem handy die uhr und der kreis ganz oben mit
den erledigten aufgaben, schoen mittig, zentriert sind. die stehen sehr
verzogen von der mitte. das soll bei jedem und jeder rolle verbessert
werden."

Gemessen bei 390 und 412 px, in allen fuenf Rollen, immer dieselbe
Zahl: Ring 31 px nach links, Uhr 31 px nach rechts. Gleicher Betrag,
entgegengesetzte Richtung -- eine Ursache, nicht zwei.

`justify-content: center` zentriert den INHALT der Reihe, und in der
Reihe steht neben dem Instrument noch ein Knopf (Glocke rechts vom Ring,
Wecker links von der Uhr). Zentriert wurde also [Knopf + Abstand +
Instrument] als Block; das Instrument rutschte um die halbe Knopfbreite
zur Seite. Die Knopfbreite steht seit jeher als `--instrument-knoepfe:
62px` in derselben Datei -- 62 / 2 = 31. Die gemessene Zahl war von
Anfang an aufgeschrieben, nur an anderer Stelle.

Der Knopf zaehlt jetzt nicht mehr mit: aus dem Fluss genommen, neben das
zentrierte Instrument gehaengt. NICHT um 31 px verschoben -- das waere
dieselbe Zahl ein zweites Mal, und beim naechsten Knopf waere sie
falsch. Jetzt folgt seine Lage dem Instrument, wie gross das auch ist.

Nachher: 0 px Abweichung, alle fuenf Rollen, beide Breiten.

--- SCREEN 3: DAS BABYBLAU WAR STAHLGRAU ---

Filipe: "die rolle dogfather soll eine uebertrieben geile babyblau
haben." Zum dritten Mal -- und die ersten beiden Male habe ich das
Falsche vergroessert.

Beide Male hatte ich den Abstand zwischen Rot- und Blaukanal im HEXWERT
erhoeht (45 Stufen, dann 86). Diesmal zuerst gemessen, was am Bildschirm
ankommt:

  Die DogFather-Zeile traegt 98,7 % farbige Bildpunkte -- MEHR als jede
  andere Rolle. An der Menge lag es also nie.
  Ihr Mittelwert war rgb(43,62,78): 35 Stufen zwischen Rot und Blau.
  Das ist Stahlgrau.

Die richtige Groesse ist die SAETTIGUNG. In OKLab hatte #9ed3f4 eine
Buntheit von 0,0718 -- der blasseste Wert aller fuenf Rollen. #5fbdff
hat 0,1303, also 81 Prozent mehr. Die Zeile kommt damit auf
rgb(36,60,79), und der mittlere Kanalabstand steigt von 35,2 auf 43,0.

Nachgerechnet, was NICHT verlorengeht: Kontrast auf dem Grund 9,75:1
(vorher 12,49) -- weit ueber den 7 fuer AAA. Abstand zur naechsten
Rollenfarbe 0,1608 in OKLab, vorher 0,1466; die Hausgrenze liegt bei
0,0973. DogFather ist also SICHERER unterscheidbar als vorher.
Gemessen an der echten Flaeche: 8,84:1 und 9,60:1.

--- SCREEN 4: SPICY FEHLTE IM UMSCHALTER ---

Filipe: "ich will da auch noch die spicy rolle sehen und die leute in
der rolle wie die anderen."

Der Sicht-Umschalter fuehrte eine EIGENE Rollenliste -- vier Eintraege,
Spicy Media fehlte. Zum vierten Mal derselbe Fehler: eine zweite
Fassung einer Liste, die es zentral schon gibt. Vorher traf es die
Leitungsliste (ein Set), die Rollennamen (ein Objekt in fuenf
Skripten -- im Chat stand "UNDEFINED" ueber einem Namen) und die
Personenliste.

Jetzt steht dort keine Liste mehr, sondern eine Ableitung aus
`ROLLENFOLGE` und `ROLLEN_GRUPPE`. Kommt eine sechste Rolle, ist sie
ohne eine Zeile Arbeit dabei.

--- Pruefung ---

pruef-handy: zehn neue Messungen (fuenf Rollen x zwei Breiten), alle
0 px. Die beiden fehlenden Rollen sind dafuer in den Testdaten
ergaenzt -- eine Pruefung an drei von fuenf haette "bei jeder Rolle"
nicht belegen koennen.

pruef-sicht: Cigdem als Spicy-Media-Person ergaenzt. Ohne sie waere es
nie aufgefallen -- eine Rolle ohne Leute wird ohnehin weggelassen, und
die alte Zusicherung "Manager, Scouts, Creator" waere weiter gruen
gewesen. Dazu eine Gegenprobe, dass die Reihenfolge WIRKLICH aus der
zentralen Liste kommt und nicht wieder abgeschrieben ist.

pruef-personen-kachel: DogFather-Kontrast neu dabei.
Ausserdem gruen: pruef-css-klassen, pruef-lesbarkeit.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 13:59:53 +02:00
DogFatherGitandClaude Opus 5 d5570ee501 Personenkachel: Rollenfarben, kein Leerband, dunklerer Grund
Filipe, mit Bildschirmfoto: "mach die ganze kachel perfekter
detailliert schoenes. der hintergrund soll auch bissl dunkler sein von
der kachel."

--- 29 PIXEL NICHTS, FUENFMAL UNTEREINANDER ---

Auf dem Bild stand unter jeder zugeklappten Rolle ein leerer Streifen.
Nachgemessen: Abschnitt 74 px, Zeile darin 45 -- 29 px Leerraum.

Sie kamen aus ZWEI Quellen, und nur eine stand in personen.css:
padding-bottom: 14px am Abschnitt, plus margin-bottom: 14px an
.gruppe__kopf aus start.css Zeile 765. Letzteres ist fuer die
freistehenden Abschnitte der STARTSEITE geschrieben, wo unter der
Ueberschrift wirklich gleich Karten kommen. Zugeklappt kommt hier aber
nichts, und dann ist der Abstand Abstand zu nichts.

Beide haengen jetzt am Zustand: offen -> Luft, zu -> keine. Die Kachel
ist damit 383 px hoch statt 293 -- pardon, 293 statt 383.

--- DIE ROLLEN HABEN FARBEN, NUR HIER NICHT ---

Fuenf Zeilen sahen fuenfmal gleich aus. Das Haus fuehrt fuer jede Rolle
eine Farbe (Anmeldeseite, Marken, Bereiche); ausgerechnet in der Liste,
in der es NUR um Rollen geht, hoerten sie auf.

Jeder Abschnitt traegt jetzt `data-rolle`, setzt daraus EIN --r, und
alles Weitere liest davon: der Streifen links, die Anzahl, die
Namenszeichen, der Pfeil, das Licht beim Aufklappen. Und `--ton`, die
Variable, aus der module.css das Kantenlicht jeder Kachel zieht -- die
Personenkarten in einem Manager-Abschnitt sind damit lila statt orange.
Eine Zeile, und der Abschnitt wird ein Stueck.

NEU: WER DRINSTEHT, OHNE AUFZUKLAPPEN. Vier Namenszeichen, ab dem
fuenften "+n". Zugeklappt sagte die Zeile bisher nur, WIE VIELE es
sind; wer wissen wollte, ob Patrick dabei ist, musste aufklappen.

--- DER STREIFEN, DEN getComputedStyle NICHT SIEHT ---

Erster Anlauf: 3 px breit, left: 0, volle Hoehe. Im Bild war nichts.
getComputedStyle meldete trotzdem "3 px, sichtbar, Deckkraft 0,55".

Der Grund steht in module.css: Jede Kachel traegt auf ::before ein
Kantenlicht mit inset: 0 und z-index: 2 -- eine 1,6 px breite Linie
UEBER allen Kindern. Vom Streifen blieben 1,4 px, und die lagen genau
in der Kante. Er sitzt jetzt bei 3 px, gerundet, mit Luft oben und
unten.

Die Pruefung misst ihn deshalb an echten BILDPUNKTEN, und zwar
dieselbe Stelle zweimal: einmal wie sie ist, einmal mit
ausgeschaltetem Streifen. Was sich aendert, IST der Streifen -- und was
sich nicht aendert, ist die Gegenprobe, ohne dass man sie erfinden
muss.

--- UND EINE PRUEFUNG, DIE GRUEN GELOGEN HAT ---

Die Kontrastmessung las die Textfarbe mit
`getComputedStyle(e).color.match(/\d+/g)`. Das geht, solange dort
"rgb(148, 165, 187)" steht. Alle neuen Stellen kommen aus color-mix(),
und Chromium antwortet darauf mit "color(srgb 0.36 0.51 0.42)". Aus
dem Muster fielen "0", "510588", "0" -- die Pruefung meldete
775929299:1 und war gruen.

Die Farbe wird jetzt in ein Canvas GEMALT und als Punkt zurueckgelesen;
das versteht jede Schreibweise, die der Browser versteht. Davor steht
eine Gegenprobe mit zwei bekannten Farben: Stimmt das Messgeraet nicht,
ist alles darunter wertlos. Echte Werte jetzt: 7,95 bis 15,71:1.

--- AM HANDY STAND DER PFEIL IN EINER DRITTEN ZEILE ---

Der Zusatztext bekommt dort eine eigene Rasterzeile -- richtig, er
passt sonst nicht. Der Pfeil bekam dadurch eine dritte und stand mittig
unter dem Text wie ein vergessenes Zeichen: 106 px je Rolle. Er hat
jetzt eine eigene Spalte und ueberspannt beide Zeilen: 75 px, und er
steht da, wo die Hand ihn sucht.

--- Pruefung ---

server/pruef-personen-kachel.mjs, neu, 43 Pruefungen, alle gruen.
Ausserdem gruen: pruef-personen-liste, pruef-css-klassen (die hat die
Namenszeichen bei 10,56 px erwischt, bevor sie jemand lesen musste).
Angesehen bei 1440 px und 390 px, zu und offen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 13:37:28 +02:00
DogFatherGitandClaude Opus 5 14e9bbf7a5 Chat: Fotos und PDFs schicken, Gespraeche wegraeumen
Filipe, mit Bildschirmfoto: "man muss die chats auch geloescht
bekommen!!! am besten waere es auch wenn man da auch im chat pdfs
schicken koennte. pdfs und fotos."

Zwei Entscheidungen vorher abgestimmt, weil sie den Bau bestimmen:
Geloescht wird NUR BEI MIR. Schicken duerfen ALLE im Gespraech, auch
Creator -- anders als in der Dateiablage, wo etwas in einem Bereich
landet, den mehrere sehen. Hier bekommt es genau der, mit dem man
ohnehin gerade spricht.

--- ANHAENGE ---

Drei Wege zur selben Sache, weil Leute unterschiedlich arbeiten: die
Bueroklammer, Hineinziehen und Einfuegen mit Strg+V (der Weg fuer einen
Screenshot -- der liegt in der Zwischenablage und nirgends als Datei).
Alle drei laufen durch dieselbe Funktion; drei Fassungen waeren drei
Gelegenheiten, dass eine die Pruefung vergisst.

Ein Foto wird GEZEIGT, ein PDF wird als Karte ANGEBOTEN. Das ist kein
Schoenheitsunterschied: Ein Bild erkennt man in einer Zehntelsekunde,
ein PDF muss man ohnehin oeffnen -- eine Vorschau davon waere ein
grauer Kasten, der so tut, als koennte man etwas lesen.

DIE SICHERHEIT STEHT IN dateiErkennen(). Dateiname und Content-Type
kommen vom Absender und sind frei erfunden; der Typ wird deshalb aus
den ersten Bytes bestimmt (PNG/GIF/WebP/JPEG/PDF, mit Breite und Hoehe
im selben Durchgang). SVG steht absichtlich NICHT in der Liste -- das
ist XML, das Skripte enthalten darf, ein als Bild getarntes Programm.
Ausgeliefert wird spaeter genau der ERKANNTE Typ, nie der eingeschickte,
dazu nosniff und "default-src 'none'; sandbox".

Auf der Platte bekommt jede Datei einen erzeugten Zufallsnamen, in
einem Ordner ausserhalb des Repos. Zuruecknehmen loescht die Datei
wirklich -- sonst waere sie im Verlauf weg und ueber die Adresse noch
da, also nur der Anschein einer Ruecknahme.

--- WEGRAEUMEN ---

Zwei Spalten in chat_teilnehmer statt einer, wegen eines Randfalls: Bei
einem Gespraech ohne jede Nachricht waere die Grenze 0 -- und 0 heisst
sonst "nie geloescht". geloescht_am unterscheidet die beiden.

Die Grenze wirkt in der Liste, im Verlauf, in der Vorschau, in der
SUCHE, bei den Anhaengen und in der Ungelesen-Zahl. Die Suche ist die
Stelle, an der so etwas typischerweise durchrutscht: aus der Liste weg,
ueber die Suche noch da.

--- DER FUND: 323 PIXEL ---

Ein Bild ist spaeter fertig als der Rest der Seite. Beim Oeffnen springt
der Verlauf ans Ende, dann kommt das Foto an und schiebt alles darunter
weg -- man steht ploetzlich mittendrin, ohne etwas angeklickt zu haben.

Das width/height-Attribut am <img>, wie man es ueberall liest, hilft
hier NICHT: Es gibt nur das Seitenverhaeltnis. Damit daraus eine Hoehe
wird, muss die Breite feststehen -- bei "width: auto" und einem nicht
geladenen Bild ist sie 0. Der Platz wird jetzt am KASTEN reserviert
(aspect-ratio + max-width aus den gemessenen Massen).

Und die Pruefung dazu hatte denselben Fehler wie das Auge: Sie mass in
einem Fenster, in dem das Bild laengst im Zwischenspeicher lag, und
meldete tadellose 0 px. Sie misst jetzt in einem FRISCHEN Browser --
der Fall, um den es geht, ist der erste.

--- SICHERUNG ---

chat-anhaenge/ ist im selben Zug in tools/sicherung-holen.sh
eingetragen, nicht spaeter, wenn es auffaellt: Genau so ist die Luecke
bei den Profilbildern entstanden. tools/wiederherstellung-proben.mjs
bestaetigt: "der Server benutzt 4 Datenordner", keiner fehlt.

--- Pruefung ---

server/pruef-chat-anhaenge.mjs, neu, 60 Pruefungen, alle gruen.
Abschnitt 3 versucht ausdruecklich, hereinzukommen: HTML als bild.png,
SVG als foto.png, SVG als svg, eine Textdatei, ein PNG-Kopf ohne Inhalt
-- alle fuenf mit 415 abgewiesen, ein echtes JPEG danach mit 201
angenommen (sonst bewiese der Block nur, dass gar nichts durchkommt).
13 MB geben 413 mit lesbarem Text, nicht 500.

Konsolenfehler werden nach ZEITPUNKT getrennt, nicht nach Statusnummer:
Was waehrend eines absichtlichen Versuchs entsteht, ist gewollt. Nach
Nummer zu filtern waere bequem und wuerde ab morgen echte 404 mit
verschlucken.

Ausserdem gruen: pruef-chat, pruef-chat-optik, pruef-chat-ausbau,
pruef-css-klassen. Angesehen bei 1440 px und bei 390 px.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 12:51:54 +02:00
DogFatherGitandClaude Opus 5 e28724564a Chat: sechs Ergaenzungen -- und ein Absturz, den nie jemand gesehen hat
Filipe: "die kategorie chat, boah ich will dass du die wirklich ueberall
perfektionierst. wirklich alles was gratis ist und hinzugefuegt werden
kann ohne problem will ich drin haben bitte. ich will das es hoch
profissionel und ultra krass geil ist."

Zuerst Bestand aufgenommen, nicht gebaut: Suche, Ungelesen-Zahlen, die
"ab hier neu"-Linie, Lesestand, Live-Strom, Antworten mit Zitat,
Zuruecknehmen und Enter-zum-Senden gab es schon. Dazugekommen ist, was
gefehlt hat und ohne fremde Bibliothek geht:

1. ADRESSEN SIND ANKLICKBAR. Gebaut als echte Knoten, nie ueber
   innerHTML -- ein Chat ist die eine Stelle, an der jeder schreiben
   darf. Erkannt wird bewusst wenig (http, https, www.): Wer mehr
   erkennt, macht irgendwann aus "z.b." einen Link ins Nichts.
   Satzzeichen am Ende bleiben beim Satz. rel="noopener noreferrer".
2. KOPIEREN je Nachricht, mit Rueckfall auf "Text markieren", wenn der
   Browser die Zwischenablage nicht hergibt.
3. DER VERLAUF REISST NIEMANDEN MEHR WEG. Vorher sprang er bei JEDEM
   Neuzeichnen ans Ende -- wer weiter oben nachlas und dabei eine
   Nachricht bekam, verlor die Stelle. Jetzt bleibt er stehen, und ein
   Knopf sagt, WIE VIEL unten wartet, nicht nur DASS etwas da ist.
4. ENTWUERFE JE GESPRAECH. Wer mitten im Satz wechselt, findet ihn
   wieder. Im localStorage, nicht auf dem Server: Ein Entwurf ist
   nichts, was jemand anders sehen soll. Abgeschickt heisst geloescht.
5. EMOJI-AUSWAHL, dreissig feste Zeichen, eingefuegt an der
   Cursorstelle. Am Handy hat die Tastatur sie ohnehin -- am Rechner
   nicht, und dort sitzt die Betreuung.
6. ZEICHENZAEHLER, sichtbar ab 400 Rest. Die Grenze steht NICHT im
   Skript, sondern kommt aus dem maxlength des Feldes -- zwei Stellen
   fuer dieselbe Zahl laufen auseinander.

--- DER FUND, um den es eigentlich geht ---

Die neue Pruefung hoert auf "pageerror". Damit kam sofort neun Mal
dieselbe Meldung: "Cannot set properties of null (setting 'hidden')",
raumOeffnen, Zeile 278.

Ursache: verlaufZeichnen() leerte den Verlaufskasten mit
`textContent = ''`. Darin liegt aber #verlauf-leer, der Absatz "Links
ein Gespraech auswaehlen". Nach dem ersten Zeichnen gab es ihn nicht
mehr, und raumOeffnen faellt sechs Zeilen weiter darueber.

Die Folge ist nicht die Fehlermeldung, sondern der Abbruch: Beim ZWEITEN
Aufruf liefen history.replaceState, gelesenMelden() und raeumeZeichnen()
nie. Der zweite Aufruf ist der Normalfall -- der Ereignisstrom ruft nach
jedem Verbindungsaufbau genau das, um nachzuholen, was waehrend der
Pause geschrieben wurde. Dieses Nachholen hat nie funktioniert. Von
aussen sah alles normal aus; nur die Konsole wusste Bescheid.

Behoben, indem nur noch die Nachrichten entfernt werden und der Absatz
stehenbleibt. Abschnitt 8 der Pruefung wechselt jetzt dreimal zwischen
zwei Gespraechen OHNE Neuladen und verlangt null Abstuerze.

--- UND EIN ZWEITER, der schon laenger drin war ---

Abschnitt 9 misst den Kontrast an der wirklichen Flaeche (Text kurz
unsichtbar, Flaeche fotografiert). Die Fusszeile jeder Nachricht stand
auf --text-still: auf der eigenen Blase 3,68:1, unter den 4,5:1 fuer
Text dieser Groesse. Aufgefallen ist es nie, weil niemand nachgemessen
hat. Jetzt traegt .chat-nachricht__fuss EINE Farbe (--text-leise,
4,81:1) und Uhrzeit, antworten, zuruecknehmen und kopieren erben sie --
statt vier eigener Angaben, die beim naechsten Mal auseinanderlaufen.

--- Pruefung ---

server/pruef-chat-ausbau.mjs, neu, 64 Pruefungen, alle gruen. Zu jedem
Punkt eine Gegenprobe: kein Link ohne Adresse, keine Auszeichnung aus
<b>/<img onerror>, kein Kopier-Knopf an zurueckgenommenen Nachrichten,
kein Sprungknopf fuer den, der schon unten steht, kein Entwurf nach dem
Abschicken, ein absichtlich zu dunkler Text faellt durch, und ein
absichtlich geworfener Fehler wird bemerkt (sonst waere Abschnitt 10
auch gruen, wenn niemand zuhoert).

Ausserdem gruen: pruef-css-klassen, pruef-chat, pruef-chat-optik.
Angesehen bei 1440 px und bei 390 px.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 12:13:24 +02:00
DogFatherGitandClaude Opus 5 7c00e76d63 Uhr: jedes Glied sitzt auf seiner Zahl, statt dort zu beginnen
Filipe (screen2): "oben in der mitte ist auch mittag, die stunden sehen
bissl verschoben aus."

Er hatte recht, und es ist ausrechenbar. Ein Strichmuster beginnt bei
Position null -- der erste Balken lief also von zwoelf Uhr aus im
Uhrzeigersinn weg, statt unter der Zwoelf zu stehen. Sein MITTELPUNKT
lag damit um eine halbe Gliedlaenge daneben:

  Stunde   10 von 197,92 Umfang  ->  9,09 Grad
  Minute   1,7 von 241,90        ->  1,27 Grad
  Sekunde  0,01 von 285,88       ->  0,006 Grad

Deshalb faellt es nur bei den Stunden auf: Neun Grad sieht man,
eineinviertel nicht. Der Fehler steckte aber in allen dreien -- und so
etwas faellt beim naechsten Umbau auf die Fuesse, sobald die Glieder
laenger werden. Deshalb ist es fuer alle drei behoben, nicht nur dort,
wo es stoert.

Eine halbe Gliedlaenge zurueck, und jedes Glied steht mittig auf seiner
Zahl. Der Kopf bekommt denselben Versatz aus derselben Zahl -- zwei
Rechnungen fuer denselben Ort waren an dieser Stelle schon einmal der
Fehler.

GEMESSEN an den gezeichneten Bildpunkten, alle zwoelf Plaetze, Kanten
im 0,05-Grad-Raster gesucht und daraus die Mitte gerechnet:

  0,13 · 29,95 · 59,85 · 89,92 · 119,85 · 149,97 · 180,13
  210,23 · 240,35 · 270,32 · 300,27 · 330,35

Soll sind 0, 30, 60 ... 330. Groesste Abweichung 0,35 Grad, und die
Vorzeichen wechseln -- das ist Messrauschen bei weichen Kanten, kein
Versatz. Vorher lagen dieselben Mitten bei 9,1 · 39,1 · 69,1 ...

Geprueft: pruef-start-ansicht -- gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 11:48:49 +02:00
DogFatherGitandClaude Opus 5 50b60ebe8f Uhr: die Lichtkante leuchtet nur noch von oben
Filipe (screen1): "perfektionnier bitte die stunden. und da sind auch
noch striche die durch die stunden gehen, ist das normal?"

Nein, war es nicht.

DIE URSACHE

Die Lichtkante ist ein Kreis, der gegen seine Bahn versetzt ist -- bei
der Stunde um 2,6 Einheiten nach oben, bei einer Bandbreite von 5,8.
Das ergibt je nach Stelle am Zifferblatt etwas voellig Verschiedenes:

  oben    Der Versatz liegt QUER zum Balken -> echte Oberkante.
  seitlich Der Versatz liegt LAENGS zum Balken -> ein heller Strich
          mitten hindurch. Genau der, den Filipe gesehen hat.
  unten   Es waere eine Unterkante -- die bei Licht von oben gar nicht
          leuchten duerfte.

Mit einem Versatz ist das nicht zu loesen: Ein verschobener Kreis ist an
den Seiten zwangslaeufig tangential zur Bahn. Am 09.09. hatte ich schon
einmal an dieser Stelle nachgebessert (die Achse von seitlich auf
senkrecht gedreht) -- das hat die Kante an den richtigen Ort gebracht,
aber nicht die Frage geloest, was sie dort ueberhaupt zu suchen hat.

DIE LOESUNG

Die Kante bekommt einen Verlauf statt einer festen Farbe und wird zu
den Seiten hin ausgeblendet. Sichtbar ist sie nur im oberen Drittel --
genau da, wo Licht von oben auf einen gewoelbten Ring faellt.

RICHTUNG NACHGEMESSEN, NICHT HERGELEITET. Das SVG traegt
`rotate(-90deg)`; SVG-x zeigt auf dem Bildschirm nach oben, der Verlauf
laeuft deshalb ueber x und nicht ueber y. Dieselbe Drehung hat heute
schon einmal die gesamte Lichtrichtung verdreht -- deshalb steht der
Hinweis direkt am Verlauf.

GEMESSEN, Querschnitt durch den Stundenbalken (28,1 bis 34,9; Mitte
31,5), alle zwoelf Plaetze gezeichnet:

  oben    bei   9,1°  hellste Stelle r=34,4 (164)  Mitte 123  -> 1,33x
  rechts  bei  99,1°  hellste Stelle r=32,4 (118)  Mitte 111  -> 1,06x
  unten   bei 189,1°  hellste Stelle r=33,8 (137)  Mitte 132  -> 1,04x
  links   bei 279,1°  hellste Stelle r=32,7 (124)  Mitte 114  -> 1,09x

Oben sitzt die hellste Stelle auf der AUSSENKANTE (34,4 von 34,9) und
ist ein Drittel heller als der Balken -- eine Kante. An den drei
anderen Richtungen bleibt die Ueberhoehung unter zehn Prozent, der
Strich ist damit weg.

Die Stunde teilt sich den Verlauf mit Sekunde und Minute und ist nur
ueber die Deckkraft schwaecher gestellt. Zwei Verlaeufe fuer dasselbe
Licht waeren zwei Sachen zum Pflegen.

Geprueft: pruef-start-ansicht, pruef-buehne, pruef-css-klassen -- gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 11:43:12 +02:00
DogFatherGitandClaude Opus 5 a116b286cb Aufgaben-Vorlagen: vier Bereiche mal vier Stufen, 48 fertige Aufgaben
Filipe: "ich will dass du die vier klassen ueberall mit aufgaben
perfektionnierst ... ich will dass die 4 kategorien ueberall perfekt
angepasst sind, mit perfekt kategorien und aufgaben."

WAS GEFEHLT HAT, NACHGEMESSEN

Die Tabelle `aufgaben` kannte weder Bereich noch Stufe, und
Aufgabenvorlagen gab es keine. Die Checkliste sagt, WAS sitzen muss --
sie sagt nicht, was jemand als Naechstes TUT. Zwischen "Ton ist der
Grund Nummer eins" und einem Abend, an dem der Ton wirklich besser
wird, liegt eine Aufgabe mit Frist und Verantwortlichem. Die musste
bisher jemand von Hand tippen.

WAS JETZT DASTEHT

  live       12 Aufgaben ·  3 je Stufe
  content    12 Aufgaben ·  3 je Stufe
  technik    12 Aufgaben ·  3 je Stufe
  community  12 Aufgaben ·  3 je Stufe
  zusammen   48

Drei je Feld und nicht zehn: Wer zehn Aufgaben bekommt, macht keine.
Drei sind ein Abend, eine Woche, ein Monat -- und die Fristen sind
entsprechend gestaffelt. Jede Aufgabe bringt ihre Frist als `tage` mit;
eine Aufgabe ohne Frist ist ein Wunsch.

Die Sachaussagen stammen aus derselben Recherche wie die
Checklistenpunkte: Lautheit minus 20 bis minus 24 LUFS, Tonspur
160 kbit/s, Bitrate hoechstens 75 Prozent des Uploads, Ankuendigung
30 bis 60 Minuten vorher, Verweildauer ueber 15 Minuten, Eskalation in
vier Stufen, Intro-Retention ab 70 Prozent.

DER WEG BIS ZUR ECHTEN AUFGABE

`/workspace/api/vorlagen` liefert sie aus, `/uebernehmen` legt sie an --
als Zeile in `aufgaben`, nicht als weiterer Eintrag in `eintraege`. Eine
Aufgabe hat einen Verantwortlichen, eine Frist und einen Status, der
sich bewegt; das ist etwas anderes als eine Notiz. Zwei Orte fuer
dieselbe Sache waeren der Anfang davon, dass sie auseinanderlaufen.

Ohne Creator wird abgelehnt statt herrenlos angelegt. Ein Creator legt
sie immer fuer SICH an, auch wenn er jemand anderen angibt.

AUF DER SEITE

Ein Block ueber dem Aufgabenbrett: zwei Knopfreihen (Bereich, Stufe),
drei Karten mit Titel, Erklaerung, Frist und einem Knopf. Die
Knopfreihen benutzen `.stufenleiter` aus der Checkliste -- dieselbe
Einteilung, dieselbe Darstellung. Eine zweite Optik fuer dieselben vier
Bereiche waeren zwei Sachen zum Lernen statt einer.

ZWEI EIGENE FEHLER, BEIDE VON PRUEFUNGEN GEFUNDEN

1. Ich hatte verlangt, dass die Frist mit der Stufe waechst. Die
   Pruefung schlug fehl: Profi 6,7 Tage gegen Fortgeschritten 7,4. Beim
   Nachsehen war die ERWARTUNG falsch. Eine Profi-Aufgabe ist meist eine
   Messung -- anspruchsvoll, aber an einem Abend erledigt; eine
   Fortgeschrittenen-Aufgabe wie "Saeulen anlegen und drei Wochen
   halten" braucht zwangslaeufig Wochen. Die Stufe sagt, was man KOENNEN
   muss, nicht wie lange es dauert. Geprueft wird jetzt, was wirklich
   gilt: keine Anfaengeraufgabe ueber fuenf Tage, keine Meisteraufgabe
   unter einer Woche.

2. Der Block war zu durchsichtig. pruef-buehne mass den Untergrund als
   rgb(84, 69, 70) -- das Buehnenfoto -- und die Ueberschrift kam auf
   3,61:1 statt 4,5:1. Ein durchsichtiger Kasten hat keinen Untergrund,
   sondern den, der gerade dahinterliegt. Jetzt eine deckende Flaeche
   mit Weichzeichner: 5,21:1.

GEPRUEFT

Neu: server/pruef-aufgaben-vorlagen.mjs, 30 Pruefungen -- Vollstaendigkeit,
der Weg bis zur Aufgabe auf dem Brett des Creators, und sechs
Gegenproben (unbekannte Stufe, unbekannter Bereich, Nummer ohne
Vorlage, ohne Creator, fremder Creator, und ein Creator, der jemand
anderen angibt). Dazu ein Browserteil, der klickt statt nur zu zaehlen.

Ausserdem gruen: pruef-aufgabenbrett, pruef-buehne, pruef-css-klassen,
pruef-handy.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 11:21:54 +02:00
DogFatherGitandClaude Opus 5 5b80d7893b Checkliste: Stufen fuer die Content-Ideen, 34 neue Punkte aus der Recherche
Filipe (screen, Punkt 5): "du hast die bei der kategorie content-ideen
vergessen. und ich will dass du dich wirklich seeeehr krass informierst
ueber all diese kategorien in den 4 kategorien ... hol das beste vom
besten ... und dan perfektionnierst du diese kategorien bei anfaenger,
fortgeschrittene, profi und meister."

DER BEFUND, NACHGEZAEHLT

  live       33 Punkte, 33 mit Stufe
  community  23 Punkte, 23 mit Stufe
  technik    19 Punkte, 19 mit Stufe   <- sein Screenshot, 6/6/4/3
  content    13 Punkte,  0 mit Stufe   <- die Luecke

Die Stufenleiste erscheint nur, wenn mindestens ein Punkt eine Stufe
traegt. Bei den Content-Ideen trug keiner eine -- deshalb fehlte sie
dort, und nur dort. Nicht falsch, sondern FEHLEND: Die Seite sah
ueberall richtig aus, und aufgefallen ist es erst, als jemand alle vier
nebeneinander gesehen hat.

WAS JETZT DASTEHT

  live       40 Punkte · 12 / 13 / 10 / 5
  community  28 Punkte ·  8 / 10 /  6 / 4
  technik    26 Punkte ·  7 /  9 /  6 / 4
  content    28 Punkte · 10 /  9 /  6 / 3
  zusammen  122 statt 88

Alle 13 vorhandenen Content-Ideen haben eine Stufe bekommen; 34 Punkte
sind neu. Kein bestehender Schluessel wurde geaendert -- an ihnen
haengen gespeicherte Bewertungen, und ein umbenannter Schluessel waere
eine stillschweigend geloeschte Beurteilung.

DIE RECHERCHE, UND WAS DAVON UEBRIG BLIEB

Zuerst die eigene Notiz im Vault (TikTok-LIVE-Algorithmus, Juli 2026),
dann fuenf gezielte Recherchen nach aussen. Aufgenommen wurde nur, was
NACHPRUEFBAR ist und was man am naechsten Abend anders machen kann:

  - Ueber 70 Prozent entscheiden in den ersten zwei bis drei Sekunden.
    Plattformen messen die "Intro-Retention" inzwischen ausdruecklich.
    -> content: "Die erste Sekunde entscheidet" (profi)
  - Ankuendigungsvideo 30 bis 60 Minuten vor dem LIVE buendelt den
    Start; ein voller Start zieht neue nach.
    -> live: "Ankuendigung kurz vorher" (fort)
    -> content: "30 Minuten vorher" (anfaenger)
  - Durchschnittliche Verweildauer ueber 15 Minuten gilt als Zeichen,
    dass die Stimmung traegt.  -> live: "Verweildauer abgelesen" (profi)
  - Wiederkehr schlaegt Spitzenwert -- die Zahl, die man nicht faelschen
    kann.  -> live: "Wiederkehrer ueber vier Wochen" (meister)
  - Ton: minus 20 bis minus 24 LUFS, Begrenzer bei minus 3, Tonspur
    160 kbit/s, Mikrofon fuenf bis zehn Zentimeter leicht seitlich.
    -> technik: vier neue Punkte, davon einer auf Profi
  - Verworfene Bilder (Netz) und ausgelassene (Encoder) haben
    verschiedene Ursachen.  -> technik: "Netz oder Rechner unterschieden"
  - Moderation: eine Ausnahmeliste erlaubter Woerter verhindert, dass
    der Filter die Stammleute mitfaengt; Absprachen des Mod-Teams
    gehoeren nicht in den oeffentlichen Chat.
    -> community: zwei neue Punkte
  - Beste Kurzformate 2026: Haken-zuerst, nummerierte Liste,
    Vorher/Nachher, Selbstversuch, Vergleich.
    -> content: fuenf neue Vorlagen mit ausformuliertem Aufhaenger

ZWEI WACHEN, DAMIT DIESE LUECKE NICHT WIEDERKOMMT

  1. In den Daten: Jeder Punkt jedes Bereichs MUSS eine Stufe haben,
     und alle vier Stufen muessen vorkommen. Mit zwei Gegenproben --
     ein Punkt ohne Stufe und eine Liste mit nur einer Stufe muessen
     beide auffallen.
  2. Auf der Seite: Die Stufenleiste muss auf allen vier Seiten mit
     fuenf Knoepfen dastehen ("Alle" plus vier Stufen). Die Zahl steht
     jetzt in der Meldezeile, damit man sie nachlesen kann.

  Die zweite braucht es zusaetzlich: "jeder Punkt hat eine Stufe" ist
  nicht dasselbe wie "die Leiste ist zu sehen".

EIN EIGENER FEHLSCHLAG, FESTGEHALTEN

Zwischendurch habe ich die Content-Ideen ein zweites Mal zeichnen
lassen -- 6 Gruppen statt 3. Ich hatte nach `vorlagenBlock` gesucht,
nichts gefunden und daraus geschlossen, die Ideen wuerden nirgends
angezeigt. Tatsaechlich ruft content.js sie seit jeher auf (Zeile 427).
Eine plausible Herleitung statt einer Messung, genau die Sorte Fehler,
gegen die die Hausregel geschrieben ist. Zurueckgenommen; die Daten
allein waren die richtige Antwort.

Geprueft: pruef-checkliste (inkl. der neuen Wachen und Gegenproben),
pruef-content, pruef-css-klassen, pruef-buehne -- alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 10:53:58 +02:00
DogFatherGitandClaude Opus 5 0a0dbff384 Fuenf Punkte aus screen1-5: Babyblau, zweite Nut, Spalten, Wasserzeichen, Jadeknoepfe
screen1 -- "da muss mehr babyblau zu sehen sein. da ist ja fast nichts."

  Gemessen als Blaustich (Mittel Blaukanal minus Rotkanal ueber die
  ganze Zeile): DogFather lag bei 7,4 und damit UNTER der roten
  Spicy-Zeile (17,3). Ursache: --dogi-haupt war #c7dcf4, und das hat
  zwischen Rot und Blau nur 45 Stufen Abstand -- im Hexwert ein Blau,
  auf dem Bildschirm ein Weiss.

  Jetzt #9ed3f4 (86 Stufen), dazu eine Schiene, deren Silber nur noch
  ein Spitzlicht am oberen Ende ist, ein breiter babyblauer Schimmer
  und der Name selbst in einem Verlauf von Silber nach Babyblau.
  Blaustich 24,3 -- der hoechste aller fuenf Zeilen, und mit dem
  hoechsten Gruenanteil, also Babyblau und nicht Lila. Abstand zur
  naechsten Rollenfarbe 0,1295 in OKLab (Hausgrenze 0,0973), Kontrast
  12,4:1.

screen2 -- "mach diesen strich der nach oben geht auch links bitte."

  Die Zentrale hat drei Felder, aber nur EINE Nut. Jetzt zwei, aus
  einem Regelsatz -- "genau gleich" heisst hier wirklich gleich und
  nicht gespiegelt: Eine Fraesung in derselben Platte hat bei Licht von
  oben links ueberall dieselbe Flanke.

  Dabei ein echter Fehler gefunden: Die Nut wurde erst bei 620 px
  abgeschaltet (start.css), die dritte Spalte faellt aber schon bei
  1180 px weg (heim.css). Zwischen 621 und 780 px stand sie deshalb als
  freier senkrechter Strich im Bild -- bei 700 px nachgemessen bei
  x = 391, wo sie nichts mehr trennte. Das Abschalten steht jetzt in
  derselben Regel wie der Spaltenwechsel, je einmal fuer 1180 und 780.

screen3 -- "die sollen schön untereinander sein."

  `.gruppe__zahl` trug ein `margin-left: auto` -- geschrieben fuer die
  Startseite, wo im Kopf nur Name, Zahl und Pfeil stehen. Auf der
  Personenseite steht dazwischen noch der Zusatztext, und der Pfeil hat
  sein eigenes auto. Zwei auto-Raender teilen den freien Platz zu
  gleichen Teilen -- also stand die Gruppe [Zahl + Zusatz] mittig, und
  ihre Lage hing an der Laenge des Rollennamens.

  Jetzt vier Rasterspalten. Die Breite der Namensspalte wird an der
  fertigen Liste GEMESSEN und als `--namen-spalte` gesetzt; eine feste
  Angabe waere bis zur naechsten Rolle mit laengerem Namen richtig.
  Spanne von Zahl und Zusatztext: 0,0 px (vorher 11 px). Gegenprobe:
  ohne die gemessene Spalte laufen sie wieder 36,5 px auseinander.

screen4 -- "das symbol rechts in der kachel soll viel groesser sein."

  Zum dritten Mal gemeldet, und zum dritten Mal hatte er recht. Zweimal
  habe ich den KASTEN vergroessert; beide Male hat sich nichts geaendert,
  und ich habe es auf die Kachelhoehe geschoben, statt nachzusehen. Der
  Kasten war 124 px -- das SVG darin 39:

    .kachel[data-gross="ja"] .kachel__svg { width: 39px }   (0,3,0)
    .kachel__wasserzeichen svg            { width: 100%  }  (0,1,1)

  Die erste Regel meint das Hauptsymbol links. Beide SVG tragen aber
  dieselbe Klasse, weil sie aus derselben Funktion kommen -- und die
  fremde Regel war staerker. Dasselbe galt fuer `.kachel:hover
  .kachel__svg` und die Reduced-Motion-Regel; alle drei sind jetzt auf
  `.kachel__zeichen` eingeschraenkt.

  Und es waren WIEDER zwei Fassungen derselben Sache, 3600 Zeilen
  auseinander: Rahmen 78 gegen 70, Zeichen 36 gegen 39. Der Kommentar
  an der spaeteren Stelle behauptete sogar schon, es gebe "EINE
  Fassung". Behauptet war es, gemessen nicht. Die toten sind entfernt.

  Zweitens fuellt die Zeichnung jetzt ihren Kasten: Im 24er-Raster liegt
  sie bei x 4 bis 20, rund 38 Prozent waren leerer Rand.

  Ergebnis: Zeichnung von 26 auf 124 px, samt der 8-Grad-Drehung
  (140 px) vollstaendig in der 152 px hohen Kachel. Deckkraft
  unveraendert bei 0,14 -- er wollte groesser, nicht lauter.

screen5 -- "der abmelde button und teilen button sollen eine richtig
geile gruen haben ... aber so dass es nicht den augen wehtut."

  Teilen #45d6a6, Abmelden #33b394. Beide sind WENIGER gesaettigt als
  das Rot, das vorher dort stand (63 und 55 gegen 100 Prozent) -- die
  Leiste wird ruhiger, nicht greller. Kontrast der Schrift 15,6:1 und
  15,0:1 gegen vorher 13,6:1 und 12,6:1. Chat und Suchen bleiben rot;
  damit trennt die Farbe "das mache ich mit der Seite" von "das mache
  ich mit meinem Zugang".

  Erster Versuch verworfen: Ein Rahmen aus drei Toenen ueber zwei
  Hintergrundlagen machte beide Knoepfe FLAECHIG gruen, weil ich die
  deckende obere Lage durchsichtig gesetzt hatte -- damit deckte sie den
  Rahmenverlauf nicht mehr ab. Im Bildschirmfoto gesehen, nicht in den
  Zahlen: Die Farbwerte waren die ganze Zeit richtig.

Geprueft: pruef-start-ansicht, pruef-buehne, pruef-css-klassen,
pruef-personen-liste -- alle gruen. Jede eigene Messung mit Gegenprobe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 04:10:44 +02:00
DogFatherGitandClaude Opus 5 74ae4c292e Uhr: Stundenverlauf abgeflacht, Lichtkante auf die richtige Achse gedreht
Filipe: "kontrollier bitte nur noch einmal ab dass keine striche krum
sind, kein runder kreis der schief verlaeuft oder so, perfektionier die
stunden noch bissl auch bitte."

Nachgemessen statt nachgesehen. Drei Funde, zwei davon echt.

1. DIE LICHTKANTE LAG AUF DER FALSCHEN ACHSE.

   Das SVG `.uhr__ring` traegt `rotate(-90deg)`, damit die Ringe oben
   beginnen. Diese Drehung gilt auch fuer einen `translate` darin --
   ein `translateY` erscheint auf dem Bildschirm deshalb als "links".
   Gemessen an den Kaesten stand bei allen vier Lagen dy = 0: Kante
   nach links, Schlagschatten nach rechts, waehrend die Kachel selbst
   ihren Schatten mit `0px 14px` nach unten wirft. Zwei Lichter in
   einem Koerper.

   Sichtbar war es als heller Strich, der bei den oberen Balken LAENGS
   durchlief statt auf der Oberkante zu sitzen -- der "Kratzer", der an
   den Stunden schon zweimal gestoert hat. Die Kante war vorher
   verschmaelert worden; das hat ihn gedaempft, aber nicht beseitigt,
   weil die Ursache die Richtung war und nicht die Breite.

   Jetzt translateX. Nachgemessen: dx = 0, Kante nach oben, Schatten
   nach unten -- dieselbe Lichtrichtung wie der Kachelschatten. Die
   hellste Stelle im Querschnitt liegt bei r = 34,1; rechnerisch soll
   sie bei 31,5 + 2,6 = 34,1 liegen.

2. DIE ZWOELF STUNDENBALKEN WAREN UNTERSCHIEDLICH HELL.

   Ein Verlauf laeuft diagonal ueber die ganze Zeichnung. Auf einem
   durchgehenden Bogen ist das Material; auf zwoelf getrennten Balken
   bekommt jeder eine andere Farbe. Gemessen, beide Faehrten im selben
   Lauf:

     alt   75 bis 145, Faktor 1,93
     neu  114 bis 147, Faktor 1,29

   Der tiefe Stopp #a81f2c traf die Plaetze 0 bis 3 -- die Stunden 1
   bis 4, also genau die Balken, die als erste gezeichnet werden. Ein
   75er neben einem 145er sieht nicht nach Licht aus, sondern nach
   Ausfall. Minute und Sekunde behalten ihren vollen Verlauf: Bei 60
   Gliedern liegen die Nachbarn dicht genug, dass der Wechsel als
   Politur gelesen wird.

3. VIER TOTE BREITENREGELN, die 620 Zeilen spaeter ueberschrieben
   wurden (2,6/3/3,6 statt der gezeichneten 3,2/5/5,8). Sie haben
   nichts kaputtgemacht, aber sie haben mich beim Nachrechnen des
   Kantenversatzes in die Irre gefuehrt -- entfernt, mit Verweis auf
   die eine lebende Stelle. Dabei fiel auf, dass der Versatz der Stunde
   noch mit einer Kantenbreite von 0,9 rechnete, obwohl sie laengst
   0,6 ist: 2,05 statt 2,20.

NICHT KRUMM war der Rest, auch das gemessen: 9 runde Elemente, 0 Eier;
alle 15 Kreise der Uhr auf demselben Mittelpunkt; Kasten exakt
quadratisch; Umfaenge stimmen auf 0,01 Einheiten zum Muster. Die 30
gefundenen Drehungen sind samt und sonders gewollt (Chilis, Husky,
Wasserzeichen -8 Grad).

Geprueft: pruef-start-ansicht, pruef-css-klassen, pruef-buehne -- alle
gruen. Jede Messung mit Gegenprobe.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 03:42:00 +02:00
DogFatherGitandClaude Opus 5 6676998af8 Niemand sieht VanVan ausser DogFather -- plus vier Punkte vom Screen
--- DAS WICHTIGSTE ZUERST: die Verbergungsregel ---

Filipe, ausdruecklich und dringlich: "und noch gaaaaaanz wichtig keiner
soll vanvan sehen ausser ich, ueberall soll keiner vanvan sehen ausser
dogfather."

ES GAB DAVON NUR EINE HAELFTE. In der Personenliste wurde der zweite
Admin-Zugang fuer Spicy Media ausgeblendet (Wunsch vom 31.08.).
Ueberall sonst -- Chat, Kalender, Aufgaben, Dateien, Zentrale -- war er
sichtbar. `sichtbarePersonenIds` hat ihn sogar ausdruecklich JEDER
Rolle gezeigt, weil sie alle Admins einsammelt.

WORAN DIE BEIDEN AUSEINANDERGEHALTEN WERDEN: In der Datenbank tragen
beide die Rolle `admin`, es gibt kein unterscheidendes Feld. Der
Unterschied, den es wirklich gibt, ist das Alter -- DogFather ist der
erste Zugang. Also: der Admin mit der kleinsten Nummer ist DogFather,
alle weiteren sind verborgen. Drei Ausnahmen: DogFather sieht alle,
ein verborgener Zugang sieht sich selbst, und bei nur einem Admin gibt
es nichts zu verbergen.

WARUM AN EINER STELLE UND NICHT IN DEN ABFRAGEN: Allein
workspace-personen.js hat 23 Abfragen auf `personen`. Eine Regel, die
man 23-mal wiederholt, ist 23 Gelegenheiten, sie zu vergessen -- und
beim Vergessen faellt niemand auf die Nase, sondern jemand SIEHT etwas.
Die Regel sitzt deshalb in `verborgeneIds()` und wird ueber einen
MANTEL um die sechs Listenfunktionen gelegt: Diese haben zusammen
achtzehn Rueckgabewege; sie einzeln zu flicken waeren achtzehn
Gelegenheiten, einen zu uebersehen. Die ungefilterten Fassungen
(`...Roh`) werden nicht mehr exportiert -- niemand kann sie
versehentlich benutzen.

`null` HIESS BISHER "SIEHT ALLES". Sobald es etwas zu verbergen gibt,
gilt das nicht mehr: Die Liste wird ausgeschrieben. Das ist strenger,
nicht lockerer.

NEUE PRUEFUNG server/pruef-verborgen.mjs -- sechs Personen (darunter
ein zweiter Admin), fuenf Schnittstellen, jede Rolle einzeln. Sie hat
beim ersten Lauf sofort ein Loch gefunden, das ich sonst nicht bemerkt
haette: Die ZENTRALE holt sich das Haus selbst und ging an allen
Listenfunktionen vorbei -- Spicy Media sah VanVan dort als Segment im
Team-Ring. Und beim Korrigieren der Pruefpfade fiel ein zweites auf:
`darfEintragen` im Kalender liess die Leitung JEDEN eintragen, bevor
ueberhaupt eine Liste befragt wurde. Eine Sichtbarkeitsregel, die nur
beim Lesen gilt und nicht beim Schreiben, hat ein Loch in der Mitte.

Die Pruefung hat eine Gegenprobe: Ein Manager MUSS DogFather in
derselben Liste sehen -- sonst waere "sieht VanVan nicht" auch dann
gruen, wenn die Listen leer zurueckkaemen.

--- screen1 Punkt 1: Silber mit Babyblau ---

"ich will dass diese farbe gemischt wird mit babyblau."

#c7dcf4 statt #d8e0ec -- dieselbe Helligkeit, mit Blaurichtung.
Nachgerechnet bleibt der Abstand zur naechsten Rolle bei 0,1790, immer
noch weiter als das frueher benutzte Babyblau (0,1349). Gemischt ist es
ausserdem SICHTBAR: Die Schiene laeuft von Silber nach Babyblau, und
der Glanz traegt beide Toene. Eine Mischung, die man nur im Hexwert
findet, ist keine.

--- screen1 Punkt 2: das Wasserzeichen ---

"soll viel groesser sein und nicht so abgecuttet sondern gut zu sehen
sein."

NACHGEMESSEN war es auf der Dashboard-Kachel zu 50 Prozent
abgeschnitten, und zwar auf DREI Seiten: 36 px ueber dem oberen Rand,
44 rechts, 60 unten -- 220 px Zeichen auf einer 152 px hohen Kachel.

UND ES GAB ZUM DRITTEN MAL DIESE WOCHE EINE DOPPELREGEL: 3600 Zeilen
unter der sorgfaeltig begruendeten Fassung (156 px bei 0,14) stand eine
zweite (118 px bei 0,085) mit derselben Spezifitaet. Sie gewann, und
die Begruendung oben war wirkungslos. Am 08.09. hatte ich beim
Wasserzeichen schon einmal genau so eine Doppelung gefunden -- und
diese hier uebersehen.

Jetzt eine Fassung, und die Groesse haengt an der KACHELHOEHE: Ein um
8 Grad gedrehtes Quadrat der Seite S braucht S x 1,129 Platz, also
`min(132px, 100% - 30px)`. Nachgemessen 100 Prozent sichtbar statt 50,
bei 0,14 statt 0,085 -- die sichtbare Flaeche hat sich verdoppelt.

--- screen1 Punkt 3: die Personenliste in einer Kachel ---

Die fuenf Rollengruppen standen als fuenf lose Abschnitte frei auf dem
Hintergrundbild. Es ist aber EINE Liste mit fuenf Abschnitten. Jetzt
eine Sammelkachel aus der Modulliste, mit dunklen Fugen statt Luft --
und dunkler als die Karten darin, wie eine Vitrine.

--- screen1 Punkt 4: "Womit meldest du dich an?" ---

Der einzige Satz auf der Anmeldeseite, der eine FRAGE stellt, stand als
graue Feldbeschriftung da. Jetzt gebuerstetes Metall, ein Anschlag aus
drei Kerben in Rot und Babyblau und eine auslaufende Linie -- dieselbe
Sprache wie die Typenschilder im Workspace. Rueckfall vollwertig: Faellt
`background-clip: text` aus, steht dort heller Text.

Geprueft: pruef-verborgen (neu), pruef-rollen, pruef-start-ansicht,
pruef-css-klassen, pruef-workspace-seiten, pruef-buehne, pruef-handy,
pruef-chat, pruef-kalender -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 03:18:01 +02:00
DogFatherGitandClaude Opus 5 1ad22b55c4 Ring so gross wie die Uhr, Stunden geschaerft, Report-Karten gerade, Schutz wird Magenta
--- screen1: Glocke nach rechts, Ring so gross wie die Uhr ---

"dieser button links vom kreis soll rechts davon sein und der kreis
soll die gleiche groesse wie die uhr haben."

Die KAESTEN waren schon exakt gleich gross (248 x 248, seit gestern aus
einer Variablen). Der gezeichnete Ring aber nicht: Sein aeusserer Bogen
lag bei Radius 128 von 150, plus halbe Strichbreite also bei 132,5 --
88 Prozent des Kastens, gerendert 219 statt 248 px. Die Uhr daneben
fuellt ihren Kasten ganz aus, ihr Leuchtkranz ragt sogar 7 px darueber
hinaus. Zwei gleich grosse Kaesten mit ungleich grossem Inhalt sehen
ungleich gross aus.

Jetzt 145 statt 128 (aussen) und 120 statt 106 (die Segmente) --
dasselbe Verhaeltnis zueinander, nur bis an den Rand. 145 + 4,5 =
149,5 von 150: ein halber Pixel Luft, damit die runde Kappe nicht
abgeschnitten wird.

Die Glocke steht jetzt rechts vom Ring. Damit liegen beide Knoepfe
INNEN, zwischen den Instrumenten und dem Text -- vorher sassen sie an
den beiden Aussenkanten, so weit voneinander entfernt wie moeglich,
obwohl sie dasselbe tun: einstellen, was einen erreicht.

--- screen2: die Stunden ---

"die stunden muss noch perfektionnieren."

DIE LICHTKANTE WAR EIN KRATZER. Sie stand auf 50 Prozent Weiss bei 0,9
Breite. Auf den schmalen Sekunden- und Minutenbahnen ist das eine
Kante; auf dem 5,8 px breiten Stundenbalken war es ein zweiter,
weisser Balken auf dem roten. Der Grund ist Verhaeltnis UND Farbe:
0,9 von 3,2 sind 28 Prozent, 0,9 von 5,8 nur 16 -- aber die Stunde ist
die einzige deckende, kraeftig gefaerbte Bahn, und auf Rot faellt
dasselbe Weiss doppelt so stark auf wie auf Silber. Jetzt 22 Prozent
bei 0,6 Breite.

DER KOPF BLEIBT ROT. Er stand auf #ffd9dd, also fast weiss -- das
aktuelle Glied war zwar das hellste, hatte aber die Farbe seiner Bahn
verloren und sah aus wie ein Fremdkoerper zwischen den roten Balken.
Jetzt ein helles, deutliches Rot: Es hebt sich durch Helligkeit ab,
nicht durch eine andere Farbe.

--- screen3: die Report-Karten stehen gerade ---

"ich will dass alles passt, nicht bedeckt ist, schief steht oder zu
tief oder zu hoch."

NACHGEMESSEN, ALLE 17 KARTEN -- der Befund deckt sich genau mit dem,
was er beschreibt: Name und Zahl lagen 12 bis 28 px auf VERSCHIEDENEN
Hoehen, sie ueberlappten sich waagerecht (gemessener Abstand -183 bis
-524 px), und Karten in derselben Reihe waren verschieden hoch.

DIE URSACHE IST EINE ZEILE: `.kachel__zahl` steht `position: absolute`
bei top 13 / right 13. Auf der Startseite ist das richtig -- gleich
grosse Kacheln, einzeiliger Name. Hier bricht der Name um ("Community:
neue Eintraege"), die Karte waechst nach unten, die Zahl bleibt oben
kleben. Sie war ausserdem fuer die Hoehenrechnung unsichtbar, weshalb
es vorher schon eine `min-height` als Pflaster brauchte.

Jetzt ein echtes Raster: Name links (Zeile 1), Trend darunter, Zahl
rechts ueber beide Zeilen und mittig. `display: contents` auf dem
Wrapper -- so werden seine Kinder selbst zu Rasterfeldern, ohne dass am
HTML etwas geaendert werden muss und ohne dass die Startseite, die
dieselben Klassen benutzt, etwas davon mitbekommt.

Nachgemessen danach: 17 von 17 sauber -- nichts ragt heraus, nichts
ueberlappt, nichts abgeschnitten, kein Versatz ueber 5 px, und keine
Reihe mit ungleichen Hoehen.

--- screen4: Schutz & Regeln wird Magenta ---

"ich will dass die kategorie eine farbe bekommt die extrem krass
auffaellt. diese kategorie ist naemlich seeeehr wichtig."

MAGENTA, WEIL ES DAS EINZIGE IST, DAS ES SONST NICHT GIBT. Rot ist fuer
"ueberfaellig" und Spicy Media vergeben, Babyblau fuer DogFather, Lila
fuer Manager, Gruen fuer Scout, Bronze fuer Creator, Bernstein fuer
"dringend". #ff2fd0 stoesst mit keinem davon zusammen -- es faellt
nicht auf, weil es HELLER ist, sondern weil es einzigartig ist. Das
ist verlaesslicher: Helligkeit konkurriert mit den Nachbarn,
Einzigartigkeit nicht.

Gerechnet wie bei Ton 21: Abstand zum naechsten Nachbarn 0,1305 (die
Grenze im Satz liegt bei 0,0973), Buntheit 0,276 -- die hoechste im
ganzen Satz, das alte Gold lag bei 0,170 --, Kontrast 6,00:1. Von
sieben Kandidaten sind drei an der Abstandsgrenze gescheitert. Das
Saeuregelb #e0ff00 waere lauter gewesen (16,86:1), haette sich aber
mit dem Bernstein von "dringend" und dem Gold der Nachbarkacheln um
dieselbe Wirkung gestritten. Die Kachel bleibt gebaut wie alle
anderen; was sie heraushebt, ist die Farbe, keine Sonderform.

--- Eine Rueckwirkung, die pruef-buehne gefunden hat ---

Die Typenschilder von gestern nutzen `background-clip: text` -- dafuer
MUSS `color: transparent` sein. pruef-buehne las genau dieses `color`,
machte daraus Schwarz und meldete 1,07:1 fuer Text, der hell und gut
lesbar ist. Fuenf Fehlalarme auf drei Seiten.

Eine Warnung, die bei richtiger Arbeit anschlaegt, wird abgeschaltet.
Sie ist deshalb nicht weichgemacht, sondern GENAUER geworden: Bei
Verlaufsschrift zaehlt jetzt der DUNKELSTE Farbstopp der ersten
Hintergrundebene -- der schlechteste Punkt, den es auf dieser Schrift
wirklich gibt. Damit meldet start.html 4,74:1 (noetig 4,5), die
Pruefung findet also weiter die engste Stelle.

UND DIE GEGENPROBE HAT SOFORT EINEN FEHLER IN MEINEM EIGENEN CODE
GEFUNDEN: Ich suchte das Ende der ersten Ebene mit `"),"` -- diese
Zeichenfolge steht aber schon am Ende des ERSTEN `rgb(...)`. Die
Messung las damit immer nur den ersten Stopp und haette einen dunklen
Verlauf fuer hell gehalten. Jetzt wird ueber Klammern gezaehlt. Der
Helfer steht einmal und wird als Quelltext in beide Seiten-Aufrufe
gereicht -- zwei Kopien waeren zwei Gelegenheiten auseinanderzulaufen.

Geprueft: pruef-buehne (mit neuer Gegenprobe), pruef-start-ansicht,
pruef-css-klassen, pruef-handy, pruef-workspace-seiten -- alle in
Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 02:58:22 +02:00
DogFatherGitandClaude Opus 5 7de32a5ec7 Punkt 15: Der Chat bekommt Suche, Antworten mit Zitat und die Ungelesen-Linie
Wunsch Filipe: "ich will dass du diese seite viel krasser und
detaillierter machst, ich will dass du dich informierst und alles
reinsetzt was wir noch gebrauchen koennten."

NICHT ALLES, SONDERN WAS TAEGLICH FEHLT. Der Chat konnte schon Raeume,
Verlauf, Gelesen-Stand, Live-Zustellung, Gruppen und Zuruecknehmen.
Drei Dinge fehlten, und jedes davon kostet ohne es echte Zeit:

1. SUCHE IN DEN NACHRICHTEN. Ein Chat ohne sie ist ab dem zweiten
   Monat ein Archiv, in dem man nichts findet. Ein Suchfeld gab es --
   es durchsuchte aber nur die NAMEN der Gespraeche, also die kleinere
   Haelfte. Jetzt durchsucht dasselbe Feld beides und zeigt die
   Fundstellen UNTER der Gespraechsliste: Wer "Patrick" eingibt, will
   vielleicht das Gespraech und vielleicht die Nachricht -- ein
   Umschalter haette ihn zwingen wollen, das vorher zu wissen.

2. ANTWORTEN MIT ZITAT. Zu zweit weiss man meistens, worauf sich etwas
   bezieht. In einer Gruppe laufen drei Faeden parallel, und "ja, mach
   das" kann alles heissen. Das Zitat steht IN der Blase (es gehoert
   zur Antwort, nicht darueber) und fuehrt per Klick zur Stelle.

3. DIE LINIE "AB HIER NEU". Wer nach zwei Tagen zurueckkommt, sucht
   sonst die Stelle, an der er aufgehoert hat, indem er Uhrzeiten
   liest.

BEWUSST NICHT GEBAUT: Anhaenge (dafuer gibt es den Dateien-Bereich mit
Rechten und Ablauf), Reaktionen (eine vierte Sache, bevor die drei sich
bewaehrt haben) und Tipp-Anzeigen (dauernder Verkehr fuer eine
Auskunft, die man in zwei Sekunden ohnehin sieht).

DIE SICHERHEIT DER SUCHE STEHT IM JOIN, nicht in einer nachtraeglichen
Pruefung: `chat_teilnehmer` wird mit der eigenen Personenkennung
verbunden, und was dort nicht drinsteht, kommt gar nicht erst aus der
Datenbank. Ein Filter, der erst hinterher aussortiert, ist eine Zeile
davon entfernt, vergessen zu werden. Ebenso beim Zitat: Worauf
geantwortet wird, muss im SELBEN Raum liegen -- sonst koennte jemand
die Kennung aus einem fremden Gespraech mitschicken, und beim
Empfaenger stuende ein Zitat aus einem Raum, den er nie gesehen hat.

DREI FEHLER, DIE DER DURCHLAUF GEFUNDEN HAT:

1. `ESCAPE '\'` IN EINEM TEMPLATE-LITERAL. Dort ist `\'` eine
   Fluchtsequenz fuer das Anfuehrungszeichen -- SQLite bekam ein
   LEERES Fluchtzeichen und antwortete "ESCAPE expression must be a
   single character". Die Suche war damit komplett tot. Kein
   Syntaxfehler, kein Warnhinweis: Erst der Aufruf mit echten Daten
   hat es gezeigt.

2. DIE MASKIERUNG KANNTE ZWEI VON DREI ZEICHEN. `%` und `_` waren
   dabei, der Backslash nicht -- ausgerechnet das Fluchtzeichen selbst.
   Geprueft wird das jetzt an der ZEILE AUS DER DATEI, nicht an einem
   Nachbau: Mein erster Test hat die Maskierung nachgebaut und dabei
   die Shell-Maskierung mitgeschleppt -- er meldete einen Fehler, den
   nur er hatte.

3. DIE UNGELESEN-LINIE SCHIEN NICHT ZU FUNKTIONIEREN. Sie tat es --
   mein Testaufbau war falsch: Filipes Seite war noch offen, die neuen
   Nachrichten kamen ueber den Live-Strom an und wurden sofort als
   gelesen gemeldet. Es gab schlicht nichts Ungelesenes. Erst als er
   die Seite verlaesst, bevor Patrick schreibt, steht die Linie da --
   und zwar genau vor "Neu von Patrick, eins", und beim zweiten
   Oeffnen ist sie weg.

Der Gelesen-Stand wird deshalb beim OEFFNEN mitgeschickt, bevor er
gesetzt wird -- eine Zeile spaeter waere er immer die letzte Nachricht,
und die Linie staende nie irgendwo.

Ohne Volltextindex, mit Absicht: `LIKE` liest die Tabelle, und bei
einem Team dieser Groesse sind das einige tausend Zeilen. Ein
FTS5-Index waere eine zweite Tabelle, die synchron gehalten werden
muss -- genau daran gehen solche Sachen kaputt. Wenn der Verlauf
sechsstellig wird, ist das der Zeitpunkt dafuer, nicht heute.

Geprueft: pruef-chat, pruef-chat-optik, pruef-css-klassen,
pruef-workspace-seiten, pruef-handy -- alle in Ordnung. Dazu im
Browser durchgespielt: Zitat gesetzt und gelesen, Suche nach
"Bitrate" (1 Treffer), nach "100 %" (1 Treffer -- die Maskierung
haelt), nach Unsinn (0), einbuchstabige Suche (zu kurz), Antwortleiste
mit dem richtigen Namen, Ungelesen-Linie an der richtigen Stelle und
beim zweiten Oeffnen weg.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 02:18:59 +02:00
DogFatherGitandClaude Opus 5 e616d88a30 Punkt 7: Vier Koennensstufen in den Bereichslisten -- Anfaenger bis Meister
Wunsch Filipe: "ich will dass es in diesen kategorien ... kategorien
gibt wie jetzt, aber fuer anfaenger, fortgeschrittene, profis .... falls
es noch eine kategorie gibt fuege ruhig hinzu. informiere dich so krass
wie es nur geht ... und dan will ich dass du das perfekt alles aufbaust
mit aufgaben und so."

VIER STUFEN, UND DIE VIERTE IST NICHT AUSGEDACHT. In den gaengigen
Kompetenzmodellen (Dreyfus) folgt auf "kompetent" eine Stufe, auf der
es nicht mehr um das eigene Koennen geht, sondern darum, dass es OHNE
einen weiterlaeuft. Genau daran haengen die elf Punkte der obersten
Stufe: Vorlagen, eingewiesene Vertretung, abgelegte Loesungen.

  Anfaenger        was von Anfang an sitzen muss
  Fortgeschritten  Routine statt Zufall
  Profi            gemessen statt geschaetzt
  Meister          laeuft auch ohne dich

DIE STUFE HAENGT AM PUNKT, NICHT AN DER GRUPPE. Eine Gruppe ist ein
ABLAUF ("Vor der Sendung"), eine Stufe ist ein KOENNEN. Als Gruppen
gebaut waeren es zwoelf Abschnitte statt drei, und dieselbe Frage
stuende viermal da. So bleibt der Ablauf die Gliederung und die Stufe
ein Filter darueber.

DIE INHALTE SIND RECHERCHIERT, NICHT AUSGEDACHT. 47 vorhandene Punkte
haben eine Stufe bekommen, 28 neue sind dazugekommen -- ueberwiegend
auf Profi und Meister, weil der Bestand dort duenn war. Was jetzt
drinsteht und vorher fehlte, unter anderem:

  * Bitrate hoechstens 70-80 % des GEMESSENEN Uploads; der Rest ist
    der Puffer gegen verworfene Bilder.
  * Keyframe-Abstand zwei Sekunden -- alles andere kann beim
    Zuschauer zu Puffern oder gar nicht erst zum Abspielen fuehren.
  * Tonfilter in der Reihenfolge Rauschunterdrueckung, Kompressor,
    Rauschsperre: Ein Kompressor davor hebt das Rauschen mit an.
  * Hardware-Encoder statt Prozessor -- der groesste Einzelgewinn an
    Stabilitaet.
  * Verworfene Bilder ABLESEN: Leitung und Kodierung sind zwei
    verschiedene Fehler mit zwei verschiedenen Loesungen.
  * Eskalationsleiter in vier Stufen (ansprechen, loeschen, Auszeit,
    Sperre) -- vorher festgelegt, weil Ungleichbehandlung das ist, was
    Communitys spaltet.
  * Moderatoren EINGEWIESEN, nicht nur ernannt: Regeln schriftlich,
    Eskalationsleiter, Werkzeuge einmal gezeigt.
  * Privater Probelauf statt Programmvorschau -- erst der zeigt, was
    beim Zuschauer ankommt.

Zahlen: LIVE 33 Punkte (11/10/8/4), Community 23 (7/7/5/4), Technik 19
(6/6/4/3). Jeder Punkt hat genau eine Stufe -- nachgemessen, nicht
angenommen.

DIE VORGABE IST "ALLE". Ein Filter, der beim Oeffnen schon etwas
versteckt, laesst einen Punkte suchen, die man gestern noch gesehen
hat. Die Gruppenzahlen zaehlen mit dem Filter mit; eine Gruppe, in der
nichts uebrigbleibt, sagt das in einem Satz statt leer dazustehen.

Die vier Stufenfarben sind GELIEHEN, nicht ausgesucht: dieselben, die
auf der Uebersicht schon "offen / dringend / laeuft / erledigt"
tragen. Wer die eine Seite kennt, liest die andere ohne Legende.

ZWEI EIGENE FEHLER UNTERWEGS:

1. NAMENSKOLLISION. Ich habe die Marke `fest-punkt__stufe` genannt --
   den Namen gibt es dort laengst fuer den BEARBEITUNGSstand (Offen /
   Passt so / Verbessern). Gemessen standen danach 66 Marken an 33
   Punkten, und mein neues CSS faerbte den alten Behaelter mit. Heisst
   jetzt `__koennen`. Zwei verschiedene Dinge unter einem Namen ist
   derselbe Fehler wie zwei Regeln fuer dieselbe Sache, nur eine Ebene
   frueher.

2. SCHRIFTGROESSE. Die Marke stand auf 0,66 rem = 10,56 px.
   pruef-css-klassen hat es sofort gemeldet (44 statt 43 Stellen unter
   11,5 px). Jetzt 0,72 rem.

Geprueft: pruef-checkliste, pruef-css-klassen, pruef-workspace-seiten,
pruef-schulung -- alle in Ordnung. Dazu alle drei Bereiche im Browser
durchgefiltert.

Quellen der Recherche: obsproject.com (NVENC/Encoder), dacast.com und
obs-versions.com (Bitrate, Keyframe, Tonfilter), switcherstudio.com
(Probelauf), help.twitch.tv und sendbird.com (Moderation,
Eskalation), jeffbullas.com (Einweisung von Moderatoren).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 02:05:30 +02:00
DogFatherGitandClaude Opus 5 6815ba89ba screen1/2/3: Zahlen werden Ziele, Titel werden Typenschilder, DogFather wird Silber
--- screen1: die sieben Zahlen fuehren zu ihren Aufgaben ---

"wenn ich auf die druecke soll ich auf zu denen punkten gebracht
werden."

Der Weg dahin gab es laengst: `aufgaben.html?zeigen=<schluessel>`
springt zu den passenden Karten und legt eine Zeile darueber, was
gezeigt wird. Nur waren die sieben Karten `<li>` ohne Link -- die
Auskunft war da, der Weg dorthin nicht.

Zwei Schluessel fehlten und sind nachgetragen: "heute" (die Karten
tragen dafuer jetzt `data-heute`, denn "heute faellig" ist ein eigener
Zustand und kein Sonderfall von "ueberfaellig") und "abgebrochen" --
das klappt zusaetzlich den Kasten auf, in dem die Abgebrochenen
stehen. Ein Sprung in einen zugeklappten Kasten laesst einen glauben,
der Knopf sei kaputt.

EIN <a> IM <li>, NICHT DAS <li> KLICKBAR: Ein Listenpunkt mit einem
Klick-Zuhoerer ist fuer Tastatur und Vorleseprogramm kein Ziel. Die
Trefferflaeche wird ueber ein durchsichtiges `::after` auf die ganze
Kachel gestreckt -- im ersten Anlauf stand dort `padding: inherit`,
was die 14/16 der Kachel ein zweites Mal aufgetragen und sie siebenmal
um 28 px verbreitert haette.

DIE NULL BLEIBT EIN LINK. Der Sprung zeigt dann eine leere Spalte mit
der Zeile "Aufgaben, die offen sind" -- das ist eine Antwort. Ein
toter Knopf ist keine.

--- screen2: die Kategorietitel werden Typenschilder ---

"die titel von den kategorien sollen spezieller und geiler sein."

Fase statt Rundung (die Pille war das einzige Rund auf einer Seite aus
abgeschraegten Platten), ein gepraegter Anschlag aus drei Kerben
statt eines Strichs, gebuerstetes Metall in der Schrift und eine
auslaufende Linie nach rechts.

UND DABEI EIN FUND: Der "leuchtende Strich" vor "Was ist dran" und
"Deine Aufgaben" wurde NIE GEZEICHNET. `.zahlen-block .feldschild`
setzt `display: flex`, damit das Pseudoelement eine Box bekommt --
rund 1200 Zeilen spaeter steht `.inhalt .feldschild { display: block }`
mit derselben Spezifitaet, und die spaetere gewinnt. Das Schild war
`block`, das Pseudoelement damit `inline`, und ein Inline-Kasten
ignoriert `width` und `height`. Aufgefallen ist es nur, weil mein
neuer Anschlag ebenfalls unsichtbar blieb und die Messung sagte: Der
Text beginnt bei x=12, also genau an der Polsterung -- davor belegt
nichts Platz.

Die Gegenprobe hat mich dabei vor einer falschen Reparatur bewahrt:
Ich hatte den Textverlauf (`background-clip: text`) im Verdacht.
Einmal mit und einmal ohne gemessen -- in beiden Faellen x=12. Damit
war die Ursache ausgeschlossen, bevor ich an der falschen Stelle
gearbeitet habe.

--- screen3: DogFather wird Silber, der Husky wird das echte Logo ---

"dieses husky symbol soll ersetzt werden durch den husky oben in der
leiste. und die farbe von der rolle und die barre soll so richtig geil
silber sein ... und der husky soll eine geile babyblau [Auge] haben."

Damit kehrt die Rolle zu dem zurueck, was im allerersten Auftrag stand
("husky: silber und blaue augen").

DAS ZEICHEN war eine geometrische Eigenkonstruktion -- ein Fuenfeck mit
zwei dreieckigen Ohren. Ordentlich gebaut, aber nicht DER Husky: Oben
in der Leiste steht die richtige Marke, und zwei verschiedene Huskys
auf einer Seite sind einer zu viel. Jetzt das echte Logo als <image>,
eingefaerbt mit `feComponentTransfer` -- eine zweistufige Tabelle
bildet Schwarz auf dunklen Stahl und Weiss auf Silber ab. Ein
`feColorMatrix` koennte das nicht; er mischt nur linear und zoege die
Mitteltoene flach.

DAS AUGE IST GEMESSEN, NICHT GESETZT: Ein Durchlauf ueber die
Bildpunkte hat die Pupille als einzige dunkle Insel gefunden, die
ringsum von Hellem umgeben ist -- bei 165/258 von 512, also 32,2 % und
50,4 %.

DIE ROLLENFARBE NACHGERECHNET, weil Silber gefaehrlich ist: Es hat
kaum Buntheit und koennte neben einer anderen Rolle verschwinden. In
OKLab liegt #d8e0ec 0,1901 von seinem naechsten Nachbarn (Scout)
entfernt -- das bisherige Babyblau lag bei 0,1349. Die fuenf Rollen
sind dadurch BESSER auseinanderzuhalten als vorher. Kontrast 14,41:1.

"wie mit sternen" ist als GLANZ gebaut, nicht als Funkeln: ein
schmales schraeges Spitzlicht und drei winzige Lichtpunkte, alles
still. Ein wanderndes Glitzern auf der Anmeldeseite waere genau das,
was die Hausregel verbietet.

Nebenbei: `rs-silber` faerbte den alten Husky und wird jetzt nirgends
mehr benutzt -- entfernt statt liegengelassen.

--- Aufraeumen ---

`ruf.png` (ein Messbild von mir) war ueber `git add -A` ins Repo und
bis auf den Server gewandert -- die Loeschung kam eine Zeile zu spaet.
Entfernt, und `.gitignore` sperrt jetzt das Praefix `zz-`, das solche
Dateien ab sofort tragen. Eine Regel im Werkzeug ist besser als eine,
an die ich mich erinnern muss.

Geprueft: pruef-rollen (97), pruef-start-ansicht, pruef-css-klassen,
pruef-workspace-seiten -- alle in Ordnung. Dazu die sieben Links und
beide neuen Sprungziele im Browser durchgeklickt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 01:55:07 +02:00
DogFatherGitandClaude Opus 5 cccafd2c31 Sechs Wuensche: Hintergruende, Knopfverteilung, Universum, Uhrkoepfe, Knallrot
--- screen3 + screen1: die Hintergruende draengeln nicht mehr ---

"die hintergrunde sollen ueberall so sein dass die sich nicht in den
vordergrund draengeln." / "mach den hintergrund von dieser kachel
dunkler, so dass die die kacheln drin viel mehr auffallen."

`--raster` stand auf .26 Deckkraft -- auf dunkler Flaeche kein Hauch
mehr, sondern ein gezeichnetes Gitter. Im Tagdialog lief es sichtbar
durch die Ueberschrift, in den Sammelkacheln stand es VOR den Karten
darin. Jetzt .09: Man sieht eine Struktur, man zaehlt keine Linien.
Eine Zahl fuer das ganze Haus -- sie steht einmal in module.css und
wird an fuenf Stellen benutzt.

Die Anlasskachel im Kalender lag mit rgba(19,26,38,.88) auf demselben
Helligkeitsniveau wie die Karten darin: keine Vitrine, sondern eine
dritte Flaeche gleicher Lautstaerke. Jetzt fast schwarz. An den Karten
musste dafuer nichts geaendert werden -- der Abstand entsteht von
selbst.

--- screen2: ein Knopf wandert nach links ---

"eins von diesen buttons soll links bei dem anderen kreis sein."

Die GLOCKE geht nach links zum Ring, der WECKER bleibt rechts bei der
Uhr. Das ist nicht ausgewuerfelt: Der Wecker ist eine Uhrzeit. Die
Glocke entscheidet, ob man ueberhaupt etwas ueber sein Team erfaehrt --
und der Ring links zeigt genau das.

Die Kachel ist damit spiegelsymmetrisch belegt: 48 px Knopf + 14 px
Abstand + 248 px Instrument auf beiden Seiten. Genau das rechnet
`--spalte`. Die Zentrierung des Rings ist weggefallen -- sie war noetig,
solange er allein in einer fuer Instrument PLUS Knopf bemessenen Spalte
stand. Der reservierte Platz schrumpft von 104 auf 48 px je Seite; die
Begruendung fuer das Reservieren bleibt: Ein Platz, der erst mit der
Antwort entsteht, laesst die Zeile springen.

--- screen4: zwei Chilis und zwei Huskys dazu ---

"setz in den hintergrund noch 1-2 peperonis und dan das logo von
dogfather, also nur den husky."

DER HUSKY IST EINE MASKE, KEIN BILD. Die Datei ist schwarz-weiss und
freigestellt (nachgemessen: 49 % durchsichtig). Als Hintergrundbild bei
15 % verschwaenden die schwarzen Flaechen im dunklen Grund und uebrig
blieben die hellen -- ein zerrissener Umriss, kein Hund. Als Maske
ueber einer Farbflaeche wird daraus eine geschlossene Silhouette in
DogFathers Babyblau. Im Universum schweben jetzt beide Marken in ihren
beiden Farben: sieben Chilis rot, zwei Huskys blau.

--- screen5: die Punkte sind ersetzt, das letzte Glied leuchtet ---

"ich will dass du die punkte ersetzt und immer der letzte soll mehr
strahlen oder so." / "alles ist mega ausser die stunden muss du noch
perfektionnieren."

DIE DREI UMLAUFENDEN PERLEN SIND WEG -- samt 60 Zeilen Rechnung. Sie
waren ein zweites Ding an einer zweiten Stelle: eigene Uhr ab dem
ersten Takt (weil die volle Unixzeit `rotate(1.07333e+10deg)` ergab),
eigener Startwinkel je Bahn, drei Winkel, die die kleineren Einheiten
anteilig mittragen mussten. All das war noetig, WEIL der Kopf neben der
Reihe herlief statt Teil von ihr zu sein. Genau deshalb trugen sie am
08.09. noch die alten Farben, als die Bahnen getauscht wurden.

Jetzt zeichnet eine zweite SVG-Lage genau EIN Glied heller -- dasselbe,
das die Reihe darunter zuletzt gesetzt hat, aus denselben Zahlen. Sie
kann gar nicht danebenstehen. Heller statt groesser: Waere der Kopf
groesser, waere er ein Fremdkoerper in der Reihe.

DIE STUNDEN WAREN BREITER ALS LANG -- 5,5 lang bei 7 breit, also 0,79:1.
Ein Segment, das breiter ist als lang, liest sich als Klotz quer auf
der Bahn statt als Balken entlang. Und weil die Kantenlage nur 0,4
versetzt ist, lief der 0,9 breite Lichtstrich MITTEN DURCH jeden Balken
statt an seiner Kante. Jetzt 10 lang bei 5,8 breit (1,7:1), und der
Kantenversatz ist nach Bandbreite gestaffelt: (Breite - 0,9) / 2, also
0,75 / 1,65 / 2,05 zusaetzlich zur Gruppe.

--- screen6: die Scout-Pipeline wird knallrot ---

"die farbe von dieser kategorie soll knall rot sein."

Die anderen zwanzig Kachelfarben sind gerechnet (OKLab, groesstmoeglicher
Abstand). Diese eine ist gewuenscht -- und wurde deshalb GEGEN den Satz
geprueft statt eingetragen: Der engste vorhandene Abstand liegt bei
0,0973. #ff1f2e kommt seinem naechsten Nachbarn auf 0,1228 nahe, ist
also weiter entfernt als das engste vorhandene Paar. Kontrast 5,01:1
(noetig 4,5). Von sechs geprueften Rottoenen der mit dem groessten
Abstand UND genug Kontrast.

tools/kachel-farben.mjs weiss jetzt davon: Ein kuenftiger Lauf wuerde
wieder Rosa vorschlagen, und das waere eine stille Ruecknahme einer
ausdruecklichen Entscheidung.

--- Ein Messfehler, der festgehalten gehoert ---

Beim Pruefen von screen4 meldete meine Foto-Methode vier Beschriftungen
unter 4,5:1 -- bei einem Verlust von 0,00 bis 0,15 durch das Universum.
Dass die Ursache nicht das Universum sein konnte, stand damit schon in
den Zahlen. Exakt gerechnet (Vordergrundfarbe gegen die tatsaechliche
Flaeche darunter) liegen dieselben Texte bei 9,13:1 bis 10,76:1.

Die Foto-Methode mittelt ueber alle helleren Bildpunkte, und bei
duenner Grossbuchstabenschrift ist die Haelfte davon halb
ausgeleuchtete Kantenpunkte. Fuer grosse Schrift taugt sie, fuer kleine
Versalien meldet sie systematisch zu wenig. Haette ich ihr geglaubt,
haette ich vier Farben "repariert", die in Ordnung sind.

Geprueft: pruef-start-ansicht, pruef-css-klassen, pruef-kalender,
pruef-buehne, pruef-handy, pruef-workspace-seiten, pruef-tagesruf --
alle in Ordnung. Dazu Ring und Uhr auf 248/248 nachgemessen, die
Kopf-Muster gegen die Uhrzeit nachgerechnet (01:24:59 -> Sekunde bei
281,115, Minute bei 96,76, Stunde bei 16,493) und die Kachelfarbe gegen
alle zwanzig anderen in OKLab geprueft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 01:33:59 +02:00
DogFatherGitandClaude Opus 5 ef6bf0d011 screen1 (neu): Aus dem Siegel wird eine Urkunde
Filipe: "wenn die kachel da ist soll die viel spezieller und geiler
sein. wirklich speziell machen bitte."

In der Nacht ist aus dem unsichtbaren Kasten ein Siegel geworden --
Flaeche, gruene Stempelschiene, gepraegte Muenze. Das war die halbe
Antwort. "Wirklich speziell" heisst: Es soll nicht nur ANDERS aussehen
als die Kacheln daneben, sondern nach etwas Bestimmtem.

ES IST EINE QUITTUNG. Alles auf dieser Seite ist eine Aufgabe -- etwas,
das noch zu tun ist. Dieses eine Feld sagt das Gegenteil. Die
Formensprache dafuer gibt es seit dreihundert Jahren und sie ist
ueberall dieselbe: Urkunde, Quittung, Wertpapier. Drei Merkmale machen
sie aus, alle drei sind jetzt gebaut:

  1. GUILLOCHE -- das feine, sich kreuzende Linienwerk auf
     Wertpapieren. Zwei Scharen in flachen gegenlaeufigen Winkeln.
  2. DIE RAENDELUNG der Muenze -- der gekerbte Rand echter Geldstuecke,
     28 Kerben, nur am Rand.
  3. DIE PERFORATION rechts -- die Reisskante eines abgetrennten
     Abschnitts. Sie sagt im Bild, was der Satz sagt: abgeschlossen.

KEIN EINZIGES NEUES ELEMENT: alles auf Pseudoelementen, die es schon
gab. Fuer eine Zierde gehoert nichts in den Dokumentbaum.

DREI ANLAEUFE, WEIL ICH ES DREIMAL ZU LAUT HATTE -- und jedes Mal hat
erst das Bild es gezeigt, nie eine Zahl:

  * Die Raendelung lag mit `z-index: -1` HINTER der Muenze. Deren
    Flaeche ist halbdurchsichtig, also schienen die Kerben ueber die
    ganze Scheibe durch: eine Sonne mit Strahlen statt einer Muenze.
    Jetzt liegt sie davor und wird maskiert.
  * Das Maskenband war mit 70..74 % rund 0,6 px breit -- rechnerisch
    ein Ring, auf dem Bildschirm ein Hauch. Jetzt 60..100 %, also
    6,4 px, dasselbe Verhaeltnis wie an einem echten Geldstueck.
  * Die Guilloche stand bei 4,5 % in Gruen: kein Material mehr,
    sondern ein sichtbares Rautennetz, das die ganze Kachel nachfaerbte.
    Jetzt 2 % in Silber und mit 9 statt 7 px Abstand -- dichte Linien
    erzeugen mit dem Pixelraster ein Moiré, und das flimmert beim
    Rollen.

Und noch ein Ausschnitt-Fehler wie gestern: Ich habe den ersten
Nachweis auf 640 px beschnitten und mich gewundert, wo die
Reisskante bleibt -- sie liegt am rechten Ende der Kachel, also
ausserhalb. Muenze und Perforation werden jetzt in ZWEI Ausschnitten
geprueft, weil sie an entgegengesetzten Enden liegen.

Kontrast unveraendert bei 14,47:1 (fett) und 7,39:1 (still).

Geprueft: pruef-start-ansicht, pruef-css-klassen, pruef-buehne -- alle
in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 01:13:35 +02:00
DogFatherGitandClaude Opus 5 8c7dc1fa94 Uhr und Ring sind jetzt gleich gross -- aus EINER Variablen
Wunsch Filipe: "die uhr und der [ring] sollen noch bissl groesser sein
und ... dan auch am ende die selbe groesse haben bitte. sehr wichtig."

WARUM SIE ES VORHER NICHT WAREN: Der Ring stand in heim.css
(232 / 220 / 190), die Uhr in start.css (164 / 118). Zwei Dateien,
zwei Zahlensaetze, und keine Stelle, an der jemand beide zugleich
gesehen haette. Nachgemessen lagen sie am Rechner 68 px auseinander.
Das war kein Versehen an einer Zahl, sondern die zwangslaeufige Folge
davon, dass es zwei gab.

Jetzt entscheidet `--instrument` ueber beide -- und ueber die Spalten,
in denen sie sitzen. Gemessen: 248/248 am Rechner, 224/224 am Tablet,
196/196 am Handy. Ein Auseinanderlaufen ist nicht mehr moeglich,
sondern muesste absichtlich geschrieben werden. Die alte Angabe in
start.css ist ENTFERNT, nicht ueberschrieben: eine wirkungslose Zahl,
die richtig aussieht, ist genau die Falle.

ZWEI FOLGEN, BEIDE ERST IM BILD SICHTBAR:

1. DIE UHR HING 32 px UEBER DIE KACHELKANTE. Die rechte Spalte war auf
   das Instrument bemessen (248), braucht aber auch die Knopfreihe
   daneben (48 + 14 Abstand = 310). Die Seite liess sich trotzdem
   nicht seitlich schieben -- der Ueberstand lag INNERHALB der Kachel,
   also hat keine vorhandene Pruefung angeschlagen. Jetzt ist die
   Spaltenbreite abgeleitet (`--spalte`), nicht getippt. Beide
   Aussenspalten bekommen sie, obwohl links keine Knoepfe stehen:
   sonst saesse der Titel nicht mehr mittig. Der Ring wird in seiner
   Spalte zentriert.

2. DIE ZIFFERN WAREN ZU KLEIN. Sie standen in `rem` -- in einer Uhr
   von 164 px richtig, in einer von 248 verloren (29,76 px in einem
   248-px-Zifferblatt, die Mitte eine leere Flaeche). Sie haengen jetzt
   ebenfalls an `--instrument`. Der Faktor ist nachgesehen, nicht
   gerechnet: 0,145 war noch zu klein, 0,168 fuellt die Mitte, ohne an
   die innerste Bahn zu stossen (Stundenbalken liegen bei Radius 31,5
   von 50).

Geprueft: pruef-start-ansicht (kein Text abgeschnitten, keine
Konsolenfehler), pruef-handy, pruef-workspace-seiten (18 Seiten,
Ueberstand 0 px), pruef-css-klassen -- alle in Ordnung. Dazu
1500/900/390 px einzeln nachgemessen: Uhr und Ring auf den Pixel
gleich, Abstand zur Kachelkante 30 bzw. 64 px.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 01:09:02 +02:00
DogFatherGitandClaude Opus 5 b1810ddbc5 screen6: Die beiden Bestaetigungen werden zu Unterschriften
Filipe, mit Bildschirmfoto der beiden Felder: "die sollen geiler sein."

WAS SIE WIRKLICH SIND, stand nur im Klassennamen. Auf einer
Unterweisung bestaetigen ZWEI Personen, dass sie sie durchgegangen
sind -- der Creator und seine Betreuung. Das ist kein Statusfeld, das
ist eine Gegenzeichnung. Gezeichnet waren sie als zwei graue Kaesten
mit runden Ecken, die man auf dem dunklen Grund kaum sah. Zwei
Rechtecke sagen "hier steht etwas". Eine Unterschriftszeile sagt "hier
fehlt jemand".

ZWEI ZUSTAENDE, ZWEI BILDER -- und beide gab es im Code laengst als
`data-da="ja"/"nein"`, nur unterschieden sie sich um einen Hauch Gruen:

  OFFEN   eine gestrichelte Linie mit einem leeren Platz darauf. Sie
          WARTET sichtbar. Der Federstrich links deutet an, wo man
          ansetzt.
  DA      eine durchgezogene gruene Linie, der Name darueber, und ein
          gepraegtes Siegel mit Haken -- wie ein abgestempeltes
          Formular.

GLEICHE HOEHE IN BEIDEN ZUSTAENDEN, und das ist keine Kosmetik: Die
Felder stehen nebeneinander in einem Raster. Waere das unterschriebene
hoeher, spraenge die Karte in dem Moment, in dem jemand unterschreibt
-- unter dem Finger dessen, der gerade gedrueckt hat.

KEINE ZWEITE FASE. Die Karte drumherum steht schon in der Modulliste.
Eine abgeschraegte Ecke IN einer abgeschraegten Ecke liest sich als
Fehler, nicht als Absicht. Das Feld traegt deshalb die andere
Formensprache des Hauses: die Linie.

DER HAKEN IST EINE MASKE, kein Zeichensatz-Haken (der sieht in jeder
Schrift anders aus und faellt weg, wenn eine fehlt) und kein Bild
(eine Datei mehr fuer fuenfzehn Pixel). Erst stand er nur im
Kommentar, waehrend im Code eine leere Muenze lag -- nachgebaut, bevor
es committet wurde. Ein Kommentar, der mehr behauptet als der Code
tut, ist schlimmer als keiner.

ZWEI ANSICHTEN NACHGEMESSEN: Auf 1400 px nebeneinander, auf 390 px
untereinander. Das Siegel sass im ersten Anlauf mit
`translate(100%)` AUSSERHALB des Feldes -- breit sah das gut aus,
schmal waere es aus der Karte gelaufen. Jetzt sitzt es innen; die
Seite laesst sich bei 390 px nicht seitlich schieben.

(Fuer die Ansicht musste ich Testdaten anlegen -- ohne Unterweisung
gibt es keine Unterschriften, und ein Bildschirmfoto von einem leeren
Bereich beweist nichts. Die Daten liegen in der Wegwerf-Datenbank der
Pruefung, nicht im echten System.)

Geprueft: pruef-schulung, pruef-css-klassen -- beide in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 01:01:13 +02:00
DogFatherGitandClaude Opus 5 77ff1a1b52 screen1: Die vier Tafeln der Calls-Seite bekommen eine Flaeche und ihre Farbe
Filipe, mit Bildschirmfoto der vier Reiter: "lass die viel geiler
aussehen bitte."

`.gruppe[data-gruppe]` steht in der Modulliste und bekommt von dort
Fase, Kantenlicht und Eckwinkel -- aber die Modulliste gibt nur die
FORM. Die Flaeche bringt jedes Bauteil selbst mit, und hier stand nur
`margin-bottom`. Die vier Reiter waren damit Silhouetten ohne Koerper:
Das Hintergrundbild lag mitten in ihnen.

DERSELBE FEHLER ZUM DRITTEN MAL IN DIESER NACHT -- beim
Entscheidungsblock auf der Report-Seite, bei der Anlasskachel im
Kalender und jetzt hier. Die Ursache ist jedes Mal dieselbe: Wer ein
Bauteil in die Modulliste aufnimmt, haelt es fuer fertig gestaltet.
Es hat dann eine Silhouette und keinen Koerper. Das gehoert in die
Uebergabe, damit es beim vierten Bauteil nicht wieder passiert.

DIE VIER FARBEN GAB ES SCHON -- an der falschen Stelle. `#f0c48a` fuer
"Protokoll fehlt" und `#79d1a2` fuer "Festgehalten" standen bereits im
Code, aber nur an den EINTRAEGEN in der aufgeklappten Tafel. Der
Reiter selbst, den man zuerst sieht und der oft der einzige ist (drei
von vier sind zugeklappt), trug sie nicht. Jetzt stehen sie einmal als
`--gton` und faerben beides: die Flaeche und ueber `--ton` das
Kantenlicht aus der Modulliste.

Die Farben sind zugeordnet, nicht ausgesucht: Bernstein "etwas ist
offen", Babyblau "kommt noch", Lila "laeuft von allein", Gruen
"erledigt".

EINE LEERE TAFEL TRITT ZURUECK -- dieselbe Ueberlegung wie bei den
Zahlen auf der Uebersicht: Null darf leise sein. Vier gleich helle
Reiter waeren vier gleich laute Rufe.

EIN IRRTUM UNTERWEGS, DER FESTGEHALTEN GEHOERT: Nach der Aenderung sah
ich im weiten Bildschirmfoto immer noch das Motiv "durch" die Tafeln
scheinen und hielt die Reparatur fuer wirkungslos. Es waren die
LUECKEN ZWISCHEN den Tafeln -- dort gehoert der Hintergrund hin. Erst
ein enger Ausschnitt einer einzelnen Tafel hat es geklaert. Ein zu
weiter Ausschnitt luegt genauso zuverlaessig wie ein zu schmaler
(heute Nacht schon einmal, beim Messstreifen am linken Bildrand).

Geprueft: pruef-call-kategorien, pruef-css-klassen, pruef-buehne --
alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:48:45 +02:00
DogFatherGitandClaude Opus 5 a4db78e937 screen2: Der Tagdialog bekommt die Silhouette des Hauses
Filipe: "die ganze kachel und button sollen geiler aussehen."

Der INHALT war schon gebaut -- Eintraege mit Schiene in ihrer Farbe,
Plaketten (TERMIN, FRIST), Knopfreihe, Akzentknopf. Nur die HUELLE
nicht: ein Rechteck mit 18 px Rundung und einem gezeichneten Rand.
Damit war der Dialog die einzige grosse Flaeche im Workspace ohne Fase
-- und ausgerechnet die, die sich ueber alles andere legt. Man sieht
es nicht als Fehler, sondern denkt "der gehoert wohl zum Browser".

Jetzt dieselbe Bauart wie die Sammelkacheln: Der <dialog> traegt nur
die Fassung (2 px Polsterung mit Farbverlauf darunter), alles Sichtbare
liegt in einer neuen Ebene `.k-dialog__glas` darin. Ohne diese zweite
Ebene muesste die Fassung ein `border` sein -- und ein Rand folgt dem
Rechteck, nicht der abgeschraegten Ecke.

ZWEI ECKEN, NICHT VIER: Bei einem Kasten, der mitten im Bild aufgeht,
wirken vier abgeschnittene Ecken unruhig -- er soll wie eine Platte
wirken, die man auflegt, nicht wie ein Achteck. Oben links und unten
rechts geben die Richtung, die anderen beiden halten die Form.

`border-radius: 0` ist dabei Pflicht und nicht Kosmetik: Bliebe der
Radius neben dem `clip-path` stehen, wuerde er die Ecken der Flaeche
INNERHALB der Silhouette runden -- an den nicht gefasten Ecken saehe
man eine doppelte Kante.

NEBENBEI EINEN WIRKUNGSLOSEN EFFEKT ENTFERNT: `backdrop-filter:
blur(14px)` stand auf dem Dialog und waere mit auf die neue Glasebene
gewandert. Die ist zu 97 Prozent deckend -- der Browser haette bei
jedem Bild einen Weichzeichner ausgerechnet, den niemand sieht. Das
Verwischen des Hintergrunds macht `.k-dialog::backdrop`, und dort
gehoert es hin. Ein Effekt, der nichts bewirkt, ist nicht harmlos: Er
kostet Rechenzeit und behauptet im Quelltext etwas ueber das Aussehen,
das nicht stimmt.

Geprueft: pruef-kalender, pruef-css-klassen, pruef-buehne -- alle in
Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:44:42 +02:00
DogFatherGitandClaude Opus 5 4c0f41762e screen18, zweite Haelfte: Die Tagesfelder werden Tasten in einer Platte
Filipe: "...und die kacheln vom kalender selber sollen viel krasser und
geiler aussehen bitte."

Die dunklen Fugen zwischen den Tagen waren die eine Haelfte des
Wunsches und stehen seit dem 08.09. Die andere Haelfte sind die Felder
SELBST: flache Rechtecke in drei Grautoenen. Eine gefraeste Platte mit
Fugen, in der flache Flaechen liegen, ist halb fertig -- die Fuge sagt
"Werkstueck", die Flaeche sagt "Tabelle".

ZWEI PIXEL MACHEN DEN UNTERSCHIED: eine Lichtkante oben, eine
Schattenkante unten. Dieselbe Rechnung wie ueberall im Haus -- Licht
faellt von oben, also ist die obere Kante hell und die untere dunkel.
Aus einer Flaeche wird ein Koerper, der in der Platte SITZT. Kein
zusaetzliches Element, keine Groessenaenderung, kein Umbruch.

DER WOCHENENDUNTERSCHIED WAR MESSBAR ZU KLEIN -- und das ist der
eigentliche Fund. Werktag lag bei `rgba(11,15,25,.74)`, Wochenende bei
`rgba(9,12,20,.8)`. Auf dem Bildschirm sind die beiden Spalten nicht
auseinanderzuhalten. Die Angabe war also da und wirkungslos, und das
ist die unangenehmste Sorte Fehler: Sie sieht im Quelltext nach einer
Funktion aus, und niemand vermisst, was scheinbar existiert.

Jetzt liegt das Wochenende sichtbar tiefer und etwas kuehler. Man
sieht den Wochenrhythmus, ohne die Spaltenkoepfe zu lesen -- das ist
keine Zierde, sondern die Information, wegen der ein Kalender
ueberhaupt in Wochen gegliedert ist.

HEUTE BLEIBT DAS LAUTESTE FELD, und das war die Bedingung fuer alles
andere: Wenn jedes Feld eine Kante bekommt, muss das eine, auf das es
ankommt, weiter herausstechen. Voller Ring plus ein leiser Schein nach
innen.

AUGENSCHONEND: Alle Werte unter 8 Prozent Deckkraft. Auf sechs mal
sieben Feldern summiert sich jede Helligkeit -- was auf einer Kachel
dezent ist, ist auf 42 Kacheln ein Raster.

Geprueft: pruef-kalender, pruef-buehne (kalender.html schlechtester
Kontrast 5,58:1 bei noetigen 4,5:1, 13 Stellen gemessen),
pruef-css-klassen -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:41:24 +02:00
DogFatherGitandClaude Opus 5 f39e4d1133 screen29: Der Titel der Anmeldekarte wird in die Platte graviert
Filipe: "sehr gut aber ich will es noch viel geiler bitte."

"Creator Workspace" stand als flaches Weiss ueber der Karte -- richtig
gesetzt, aber ohne Material. Darunter liegt eine Karte aus Glas und
Metall, darum ein Rahmen aus Rot und Babyblau; nur die Ueberschrift
selbst gehoerte zu nichts davon.

ZWEI SACHEN MACHEN AUS SCHRIFT EIN WERKSTUECK:

1. EIN VERLAUF VON OBEN NACH UNTEN, nicht von links nach rechts.
   Gebuerstetes Metall ist oben hell, in der Mitte dunkel und unten
   wieder hell -- weil es sich woelbt. Ein Verlauf, der nur von hell
   nach dunkel laeuft, ist eine Flaeche mit Farbverlauf; erst der
   WECHSEL liest sich als Metall. Dieselbe Ueberlegung wie bei der
   Fassung der Zentrale, nur hochkant.

2. EIN HARTER SCHATTEN DIREKT DARUNTER, ein Pixel. Er macht aus
   aufgelegter Schrift eingelassene: Das Auge liest die dunkle Linie
   als Kante der Vertiefung. Weich waere es ein Schlagschatten und
   damit das Gegenteil.

Dazu ein feiner Lichtstrich unter der Markenzeile -- Rot links, Silber
in der Mitte, Babyblau rechts, dieselbe Richtung wie der Rahmen der
Rollenkachel darunter.

DER RUECKFALL STEHT ZUERST UND IST VOLLWERTIG. `background-clip: text`
traegt hier die Farbe -- faellt die Technik aus, waere durchsichtiger
Text auf durchsichtigem Grund die Ueberschrift der wichtigsten Seite
des Hauses. Also bleibt `color` gesetzt, und erst ein `@supports`
schaltet den Verlauf dazu. `filter: drop-shadow` statt `text-shadow`,
weil ein Textschatten bei durchsichtigem Text DURCH die Buchstaben
scheint -- man saehe den Schatten im Buchstaben stehen.

KONTRAST NACHGERECHNET, NICHT BEHAUPTET: Der dunkelste Punkt des
Verlaufs (#9fb3c8) kommt gegen den Kartengrund auf 8,97:1 / 8,41:1 /
7,54:1 je nach angenommenem Untergrund. Grosse Schrift braucht 3:1,
normale 4,5:1. Die Zahlen stehen im Kommentar, weil ich an genau
dieser Datei schon einmal "liegt weit darueber" geschrieben hatte,
ohne zu rechnen -- und beim Anmelde-Knopf damit danebenlag (4,20:1
statt der behaupteten 4,5+). Eine Behauptung ueber Kontrast ohne Zahl
ist eine Vermutung.

Geprueft: pruef-rollen (97 Pruefungen), pruef-css-klassen -- beide in
Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:38:31 +02:00
DogFatherGitandClaude Opus 5 af40b79a8c screen30 + screen32: Der leere Zustand wird ein Siegel, die Kennung ein Ausweis
--- Und ein Fund unterwegs: Cigdems Kennung war kaputt ---

`--rollen-ton` faerbt Kennung und Rollenplakette in der Kopfleiste.
Die Liste dahinter kannte admin, manager, scout und creator -- SPICY
MEDIA nicht. Die Rolle kam am 07.09. dazu, diese Liste ist nicht
mitgegangen.

Was dabei passiert, ist schlimmer als eine falsche Farbe: Die Variable
war GAR NICHT gesetzt, und `color-mix(in srgb, var(--rollen-ton) 62%,
transparent)` ist mit einer leeren Variablen ungueltig -- der Browser
wirft die ganze Deklaration weg. Nachgemessen im Browser: Hintergrund
`none`, Rand `rgb(234,243,255)` (also currentColor, weil auch die
Randfarbe fiel), Plakette grau statt rot. Cigdems Kennung war ein
weisser Kasten in einer roten Leiste.

DESHALB STEHT JETZT EINE VORGABE DAVOR, und die ist wichtiger als der
nachgetragene Eintrag: Wer die naechste Rolle anlegt und diese Liste
wieder vergisst, bekommt eine Kennung in der Hausfarbe -- nicht mehr
eine kaputte. Ein fehlender Eintrag darf zu etwas Schlichterem
fuehren, nie zu etwas Ungueltigem.

--- screen30: der leere Zustand ---

"das muss auch viel spezieller sein und auch nicht wie alle anderen
kacheln da sondern wirklich krasser und geiler aber so dass es vom
aussehen trotzdem noch zu seite passt."

Das Gruen lief als Verlauf nach 60 Prozent ins Nichts, dahinter das
Hintergrundbild -- auf Filipes Bild scheint ein Chili mitten durch die
gute Nachricht. Eine Fassung, die nur auf der linken Haelfte
existiert, ist keine.

"Nicht wie alle anderen Kacheln" ist inhaltlich richtig: Alles andere
auf dieser Seite ist eine AUFGABE, etwas, das man noch tun muss. Das
hier ist die Quittung, dass nichts mehr offen ist. Es waere falsch,
wenn es wie eine weitere Aufgabe aussaehe. Also die Form eines
SIEGELS: die Fase sitzt rechts unten statt links oben --
spiegelverkehrt zur Kachelsprache --, links eine breite gruene
Lichtschiene wie ein Stempelrand, und der Haken ist eine gepraegte
Muenze statt eines Kreises mit einem Strich darin. Die Flaeche ist
deckend; eine gute Nachricht, durch die man das Hintergrundbild sieht,
liest sich wie ein Platzhalter.

Leise bleibt es trotzdem: gedecktes Gruen, hoechstens 14 Prozent
Flaeche, nichts pulsiert. Wer nichts offen hat, braucht kein
Feuerwerk. Kontrast gemessen: 14,47:1 (fett) und 7,39:1 (still).

--- screen32: die Kennung in der Kopfleiste ---

"das sieht schon richtig gut aus aber ich will dass es noch krasser
und spezieller aussieht."

Sie sass als flaches, abgerundetes Quadrat zwischen vier Knoepfen und
sah damit aus wie ein fuenfter Knopf, der sich nicht druecken laesst.
Sie ist aber etwas anderes: Sie sagt, WER hier ist, nicht, was man tun
kann. Jetzt die Fase des Hauses statt der Rundung (sie gehoert zur
Seite, nicht zur Knopfreihe), ein gepraegter Ring statt eines
gezeichneten Randes (Lichtkante oben, Schattenkante unten) und ein
sehr leiser Schein in der Rollenfarbe.

KEINE GROESSENAENDERUNG -- 28x28 bleibt. Die Kopfleiste ist am
06.09.2026 schon einmal an einem zusaetzlichen Element zerbrochen;
was hier waechst, drueckt dort etwas heraus.

Geprueft: pruef-workspace-seiten (18 Seiten, Ueberstand ueberall 0 px),
pruef-handy, pruef-start-ansicht, pruef-css-klassen -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:34:13 +02:00
DogFatherGitandClaude Opus 5 41108d6c3c screen14 + screen16: Der Entscheidungsblock bekommt eine Flaeche, die Zahlen bekommen Bedeutung
--- screen14: "das soll auch bitte viel geiler und spezieller sein" ---

Zwei Dinge waren falsch, und nur eines davon sieht man im Code.

1. DIE FLAECHE WAR FAST DURCHSICHTIG -- 9 und 5 Prozent Deckkraft. Auf
   einer Seite mit Hintergrundbild heisst das: Das Motiv scheint mitten
   durch den Text. Auf Filipes Bildschirmfoto liest man den Satz "Ein
   Review endet nicht mit einer Zusammenfassung" quer ueber einem
   gespiegelten SPICY-MEDIA-Schriftzug. Ein Kasten, den man nicht
   sieht, ist keine Fassung -- er ist ein Rand um nichts.

2. `border-radius` UND `border` STANDEN NOCH DA -- wirkungslos, weil
   `.entscheidung` in der Modulliste von module.css steht und die
   spaeter geladen wird. Zwei Angaben, die aussehen, als taeten sie
   etwas, und es seit dem Umbau nicht mehr tun.

Er ist die HANDLUNG der Seite, nicht einer von vier Abschnitten: Alles
darueber ist Auskunft, hier wird entschieden und sofort eine Aufgabe
angelegt. Deshalb ein eigener `--ton` fuers Kantenlicht (die Modulliste
faerbt es darueber) statt des Seitentons, und eine kraeftigere Flaeche
als die Sammelkacheln darueber. Kein Rot: Rot heisst in diesem Haus
"ueberfaellig", und eine Entscheidung ist kein Alarm. Die Eingabefelder
sind jetzt eingelassen statt aufgesetzt -- wo man etwas hineinschreibt,
ist eine Vertiefung; und `color-scheme: dark`, sonst zeichnet Chrome
den Datumswaehler als weisses Kaestchen in die dunkle Flaeche.

--- screen16: "mit mehreren farben arbeiten, damit die wichtigsten
    sachen auch auffallen" ---

Die sechs Zahlen je Creator (ueberfaellig, dringend, offen, in Arbeit,
im Review, erledigt) trugen alle dasselbe Blau -- und `data-warn`
faerbte zwei davon in DASSELBE Rot. "Ueberfaellig" ist eine versaeumte
Frist, "dringend" eine Sache, die schnell muss. Zwei verschiedene
Alarme, die gleich aussehen, sind ein Alarm.

Jetzt sechs Toene: Rot, Bernstein, Babyblau, Lila, Silber, Gruen.

DIE WICHTIGE ENTSCHEIDUNG WAR ABER NICHT WELCHE FARBE, SONDERN WANN.
Sechs dauerhaft leuchtende Felder waeren sechs gleich laute Rufe -- und
damit genau so wenig Hilfe wie sechs gleich blaue. Deshalb bleibt eine
NULL grau und still; nur was groesser als null ist, bekommt seine
Farbe. Auf einer Karte, auf der alles auf Null steht, aendert sich
nichts. Auf einer, auf der drei Sachen ueberfaellig sind, sieht man
genau die. Das ist der Unterschied zwischen Farbe als Schmuck und
Farbe als Auskunft.

Die Farbe haengt an `data-sorte` (einem Schluessel), nicht an
`:nth-child`: Wer morgen ein siebtes Feld dazwischenschiebt, soll nicht
sechs Farben verrutschen lassen. Und die Beschriftung bleibt der
eigentliche Traeger -- Farbe allein traegt in diesem Haus nie eine
Information.

KONTRAST NACHGERECHNET statt angenommen: Die Beschriftungen sind
11,2 px, also gilt 4,5:1. Gemessen gegen die Kartenflaeche liegen sie
zwischen 5,91:1 (erledigt) und 14,09:1 (im Review) -- alle sechs
deutlich darueber. pruef-barrierefrei-workspace habe ich deshalb NICHT
gestartet: Der Lauf haette 190 Sekunden gebraucht, um dasselbe zu
sagen.

Geprueft: pruef-uebersicht, pruef-uebersicht-browser, pruef-css-klassen,
pruef-buehne -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:26:48 +02:00
DogFatherGitandClaude Opus 5 8fcc9de1bb screen4: Die Anlass-Sammelkachel bekommt die Kachelsprache des Hauses
Wunsch Filipe: "ich will dass das alles in einer geilen kachel ist wie
die kacheln in der start seite. und noch geiler."

Der Umschlag um die drei Abschnitte (Als Naechstes / Im Monat / Laeuft
von allein) gab es schon -- aber die Kachelform war in kalender.css
NACHGEBAUT: eine Fase an einer Ecke, ein Raster, ein Innenschatten. Im
Bildschirmfoto sah man den Rahmen kaum, waehrend die Karten DARIN (die
seit jeher in der Modulliste stehen) Kantenlicht und Eckwinkel trugen.
Die Sammelkachel war damit schwaecher gefasst als ihr eigener Inhalt --
genau andersherum, als es sein soll.

"WIE DIE KACHELN AUF DER STARTSEITE" HEISST NICHT "AEHNLICH GEBAUT",
SONDERN DIESELBE REGEL. `.k-anlasskachel` steht jetzt in der
Modulliste von module.css -- in allen sieben Kopien, die
pruef-css-klassen Zeichen fuer Zeichen vergleicht. Damit bekommt sie
Fase, Kantenlicht, Eckwinkel und Schlagschatten aus derselben Quelle
wie 43 andere Bauteile, und ein Nachbau daneben kann nicht mehr
auseinanderlaufen.

DABEI EINEN FEHLER GEMACHT UND GESEHEN: Beim Entfernen des Nachbaus
ging der Hintergrund mit weg. Die Kachel war danach DURCHSICHTIG -- das
Motiv der Seite schien mitten durch den Text. Die Modulliste gibt die
FORM; die Flaeche bringt jede Kachel selbst mit, weil sie von Fall zu
Fall verschieden ist. Eine Fassung ohne Fuellung ist kein Rahmen,
sondern ein Loch. Gesehen im Bildschirmfoto, nicht in einer Zahl.

Geprueft: pruef-css-klassen (sieben Kopien gleich, 44 Klassen),
pruef-kalender, pruef-buehne -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:19:29 +02:00
DogFatherGitandClaude Opus 5 4e35c6f8e5 screen11: Der Chat hatte gar keinen Hintergrund -- seit jeher
Wunsch Filipe: "die hintergrund bilder sollen alle so strahlen und
schoen sein wie dieses. dieses ist wirklich mega und perfekt."
(Massstab ist die Scouting-Seite, Szene "wald".)

DER FUND: `chat.html` hat weder `.kopf-zeile` noch `.k-kopf` -- sie
traegt ihren Titel im eigenen `.chat__kopf`. In kopf.js stand ganz
oben:

    const kopf = document.querySelector('.kopf-zeile, .k-kopf');
    if (!B || !kopf) return;

Damit hing ALLES an der Frage, ob es eine Kopfzeile gibt, an die man
eine Plakette haengen kann -- auch der Farbton der Seite und ihr
Hintergrundbild, die damit nichts zu tun haben. Der Chat ist an dieser
Zeile ausgestiegen und hat WEDER Ton NOCH Buehne bekommen, obwohl in
bereiche.js seit jeher `szene: 'lounge'` fuer ihn steht. Eine
Zuordnung, die es gibt und die nie ankam.

Jetzt stehen Ton und Buehne VOR der Plakette: Sie brauchen nur den
Bereich. Die Plakette braucht zusaetzlich einen Kopf -- gibt es den
nicht, faellt eben nur sie aus.

WARUM DAS KEINE PRUEFUNG GEFUNDEN HAT, gleich zweimal:

  1. `chat.html` stand nicht in der Seitenliste von
     pruef-workspace-seiten. Eine Pruefung, die eine Seite nicht kennt,
     kann auf ihr nichts finden. Jetzt drin, zusammen mit
     leistung.html -- 18 Seiten statt 16.

  2. Die Buehnenregel lautete `r.buehne ? r.buehneBild === r.buehne :
     !!r.buehneBild` -- fehlt das Merkmal, reichte IRGENDEIN Bild.
     Gedacht war die Ausnahme fuer die Startseite, geschrieben war sie
     fuer jede Seite. Der Chat verlor sein `data-buehne`, fiel auf die
     Grundszene zurueck, und die Pruefung sagte "ein Motiv ist da,
     alles gut". Eine Bedingung, die bei fehlender Angabe MILDER wird
     statt strenger, kann den Verlust dieser Angabe nicht melden --
     sie belohnt ihn. Die Ausnahme haengt jetzt an der Startseite, nicht
     am Fehlen des Merkmals.

Die Regel ist dafuer aus der Schleife herausgeloest (`buehneRichtig`)
und hat sieben Gegenproben bekommen -- darunter genau den Chat-Fall.
Ohne sie waere "alles in Ordnung" nur die Aussage, dass die Regel
nichts gemeldet hat, nicht dass sie etwas melden koennte.

DIE AUSNAHME DES CHATS STEHT JETZT MIT NAMEN in der Pruefung, statt
dass die Seite aus der Liste faellt: Plakette und Wasserzeichen
entfallen dort, weil es den Ort dafuer nicht gibt -- Ton und Buehne
gelten. Ob der Chat eine Plakette bekommen soll, ist eine
Gestaltungsfrage fuer Filipe, keine Fehlerfrage.

ZWEI FALSCHE AUSSAGEN in tools/gate-bauen.mjs richtiggestellt:
"halle: dieselbe Sammlung, GESPIEGELT" -- nachgemessen haben beide
Dateien dieselbe Pruefsumme, es gibt in diesem Werkzeug keine
Spiegelung. Und "0,42 ist gemessen" ueber `const DUNKEL = 0.26`; der
Wert wurde gesenkt, die Zeile ist nicht mitgegangen. Ein Kommentar, der
mehr behauptet als der Code tut, ist schlimmer als keiner.

ZUM EIGENTLICHEN WUNSCH, ehrlich: Ich habe die Hintergrundhelligkeit
aller 18 Seiten nachgemessen. Die Scouting-Seite ist tatsaechlich die
hellste (0,0263), alle anderen liegen 19 bis 65 Prozent darunter --
aber der Grund ist NICHT die Bildbehandlung. Schleier und Abdunklung
sind fuer alle Seiten gleich und mehrfach nachgemessen. Der Unterschied
ist, WIE VIEL vom Bild noch zu sehen ist: Die Scouting-Seite traegt
eine schmale Karte, die anderen dichte Tabellen und Kachelraster. Das
liesse sich aendern, aber es ist eine Entscheidung ueber die
Inhaltsdichte von 17 Seiten -- die gehoert Filipe, nicht mir um zwei
Uhr nachts.

(Meine erste Messung sagte das Gegenteil. Sie nahm einen Streifen bei
x 0..150 -- ausgerechnet die dunkelste Spalte jedes Motivs. Danach
schien die Scouting-Seite fast schwarz, waehrend das Bildschirmfoto
derselben Seite hell und farbig ist. Ein Messfeld, das nicht
repraesentativ ist, misst zuverlaessig das Falsche.)

Geprueft: pruef-workspace-seiten (18 Seiten, alles in Ordnung),
pruef-buehne, pruef-css-klassen -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:14:48 +02:00
DogFatherGitandClaude Opus 5 f3d5bcf198 screen20: Die fuenf Rollen in EINER Kachel
Wunsch Filipe: "ich will dass die rollen auch alle in einer grossen
kacheln sind, die soll richtig krass sein, richtig speziell."

Vorher waren es fuenf einzelne Kaesten mit je eigenem Rand, eigenen
runden Ecken und 8 px Luft dazwischen -- der Hintergrund des Motivs
schien ueberall durch. Das las sich als fuenf Dinge, die zufaellig
untereinander stehen. Es ist aber EINE Frage mit fuenf Antworten, und
genau so sieht es jetzt aus: ein Koerper mit abgeschraegten Ecken, in
den fuenf Felder eingelassen sind.

DIE FUGE MACHT DIE KACHEL, nicht der Rand aussen. Ein Spalt, durch den
der Untergrund scheint, TRENNT; eine dunkle Fuge (#05070c) VERBINDET,
weil sie zum selben Koerper gehoert. Dieselbe Entscheidung wie beim
Kalender.

DIE FASSUNG traegt dieselben vier Farben wie der Rand der Zentrale --
links Rot, rechts Babyblau, Silber als Treffpunkt, Schwarz als Fuge.
Wer sich anmeldet, sieht damit schon hier die Handschrift der Seite
dahinter.

WAS BLEIBT, IST DIE SCHIENE. Sie war das Beste am alten Entwurf: Wer
sich als Manager anmeldet, sieht schon hier das Lila, in dem ihm gleich
seine Kacheln begegnen. Sie sitzt jetzt buendig an der Innenkante statt
am Rand einer eigenen Karte -- dieselbe Wirkung, ein Koerper weniger.

ZWEI SACHEN, DIE DABEI AUFFIELEN:

1. ES GAB ZWEI ENTWUERFE FUER DIESELBEN FUENF ZEILEN. Einen ab 1100 px
   (`.tafel .rolle`, mit Schiene und Tastenwirkung) und einen darunter
   (`.rolle`, schlicht). Mein erster Anlauf legte einen DRITTEN
   darueber -- im Bildschirmfoto standen die alten Karten unveraendert
   in meiner neuen Kachel. Statt der dritten Schicht sind jetzt beide
   vorhandenen auf Felder umgestellt: eine Aussage, zwei Groessen.

2. `transform: translateY(1px)` BEIM DRUECKEN MUSSTE WEG. Bei fuenf
   einzelnen Karten war das richtig -- eine Taste, die nachgibt. In
   einem geschlossenen Koerper schiebt sich damit ein Feld um einen
   Pixel aus der Kachel heraus, reisst die Fuge auf und sieht nach
   einem Fehler aus. Der eingelassene Schatten sagt dasselbe, ohne
   etwas zu verschieben.

Nebenbei: Die Markierung der gewaehlten Rolle stand unter 1100 px fuer
alle fuenf auf demselben Blau-Violett -- wer "Scout" waehlte, bekam
Blau, obwohl Scout gruen ist. Die Rollenfarbe `--rf` war zwei Zeilen
darueber definiert und wurde nicht benutzt. Jetzt kommt sie per
`color-mix` aus den zentralen Hausfarben.

Geprueft: pruef-rollen (97 Pruefungen, alles in Ordnung),
pruef-css-klassen (alles in Ordnung), dazu 390/320/820 px nachgemessen
-- nichts ragt heraus, nichts laesst sich seitlich schieben.

Dabei hat meine eigene Messung erst fuenf Fehler gemeldet, die es nicht
gab: Die Untertitel sind auf schmalen Geraeten ausgeblendet, ein
ausgeblendetes Element hat die Masse 0/0, und 0 liegt links von jeder
Kachel. Ohne den Blick aufs Bild haette ich einen Fehler gesucht, den
nur die Pruefung hatte.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-09 00:02:15 +02:00
DogFatherGitandClaude Opus 5 f701dae53e screen10: Der Tagesruf -- einmal am Tag, was noch offen ist
Wunsch Filipe: "ich will das neben diesem kreis auch ein kleiner button
ist fuer den wecker von den aufgaben, oder quasi eine taetige meldung
einmal am tag zu aktivieren wenn noch aufgaben auf sind."

Ein Wecker-Knopf unter der Glocke, neben der Uhr. Eingeschaltet meldet
er sich einmal taeglich zur eingestellten Zeit -- aber nur, wenn
wirklich noch etwas offen ist. Der Satz nennt die Zahl und die
Ueberfaelligen: "3 Aufgaben sind noch offen / Davon eine ueberfaellig."

ALS EINZIGE ART MIT `vorgabe: false`, und das ist keine
Nachlaessigkeit. Alle anderen Benachrichtigungen antworten auf ein
Ereignis, das gerade passiert ist. Der Tagesruf kommt ungefragt zur
selben Zeit, ob es etwas Neues gibt oder nicht -- so etwas schaltet man
sich selbst ein, sonst ist es Werbung. Bei null offenen Aufgaben kommt
nichts: Eine taegliche Meldung "du hast nichts zu tun" ist der
schnellste Weg, dass man die naechste nicht mehr liest.

EIN FENSTER VON DREI STUNDEN. Der Takt laeuft alle fuenf Minuten; ein
einfaches "jetzt >= eingestellte Zeit" wuerde nach einem Serverausfall
den Ruf fuer neun Uhr um zwanzig Uhr zustellen. Wer eine Erinnerung an
einen vergangenen Tag bekommt, schaltet sie ab. Faellt der Tag aus, ist
das die ehrlichere Antwort.

VIER DINGE, DIE ERST DAS NACHMESSEN GEZEIGT HAT:

1. DER KNOPF VERSPRACH ETWAS, DAS ER NICHT HALTEN KONNTE. Chromium
   meldet `Notification.permission === 'denied'` -- gemessen, nicht
   vermutet. Der Knopf sah einladend aus ("Einmal am Tag melden…") und
   sagte erst NACH dem Antippen ab. Ein Bedienelement, das den Grund
   erst hinterher nennt, ist die schlechtere Haelfte einer
   Fehlermeldung. Jetzt steht er im Titel, und der Knopf ist gedimmt.

2. EINE UHRZEIT IN DER RUHEZEIT WAERE EIN STILLES NICHTS. Der Server
   laesst zwischen 22 und 7 Uhr nichts durch. Wer 23:00 einstellt,
   bekaeme nie etwas und saehe nur einen Knopf auf "an". Jetzt steht
   der Hinweis dort, wo man es einstellt -- mit den Grenzen VOM SERVER,
   nicht mit hier getippten Zahlen.

3. `wert` UND `an` SIND ZWEI ENTSCHEIDUNGEN. Wer nur den Schalter
   umlegt, schickt kein `wert` -- stumpf `req.body.wert` zu schreiben
   haette bei jedem Aus- und Einschalten die Uhrzeit geloescht, und
   beim naechsten Mal staende wieder neun Uhr da. Ein Datenverlust, den
   niemand meldet, weil er wie eine Vorgabe aussieht. Genau dieser Weg
   wird jetzt geprueft.

4. pruef-css-klassen HATTE ZWEIMAL RECHT. Der Stil lag in heim.css
   (nur Startseite), die Zeichen entstehen aber in glocke.js (18
   Seiten) -- auf 17 davon waere ein nackter Knopf gestanden. Und die
   beiden neuen Schriftgroessen (10 und 11 px) haetten die Grundlinie
   von 43 zu kleinen Stellen still auf 45 gehoben. Beides behoben:
   Stil nach start.css, Schrift auf 12 px.

NEUE PRUEFUNG server/pruef-tagesruf.mjs, drei Schichten getrennt, weil
sie getrennt kaputtgehen: Oberflaeche im Browser, Schalten ueber die
Schnittstelle (aus der SEITE heraus, damit Sitzung und
Herkunftspruefung mitgehen), Zeitentscheidung als reine Rechnung. Die
Entscheidung wurde dafuer aus dem Rundgang herausgeloest -- dazwischen
steckend haette man zum Pruefen Datenbank und Push-Versand aufbauen
muessen, also haette man sie nicht geprueft.

Die Erwartung der ersten Schicht richtet sich nach der GEMESSENEN
Berechtigung statt sie vorauszusetzen: Erlaubt eine kuenftige
Chromium-Fassung Benachrichtigungen von sich aus, waere ein fest
verdrahtetes "muss blockiert sein" ein Fehlalarm ohne Fehler.
Gegenproben sind dabei: "99:99", "7:30" ohne fuehrende Null und ein
Wert an einer Art, die keinen kennt, muessen abgelehnt werden -- sonst
bewiese der Bereichstest nichts.

Der reservierte Platz waechst von 46 auf 104 px, damit der zweite Knopf
die Kachelreihe darunter nicht nach unten schiebt; das Zeitfeld schwebt
statt zu schieben. Beides derselbe Grund wie bei der Glocke: Ein
Sprung ist kein Schoenheitsfehler, sondern der Grund, warum man auf den
falschen Knopf drueckt.

Geprueft: pruef-tagesruf (neu, alles in Ordnung), pruef-push,
pruef-css-klassen, pruef-start-ansicht -- alle in Ordnung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 23:54:51 +02:00
DogFatherGitandClaude Opus 5 cad3c4c4df screen21: Universum hinter der Zentrale, Fassung neu gewichtet
Wunsch Filipe: "ich will dass du im hintergrund dieser kachel das logo
von spicy media machst ... es soll sogar paar mal zu sehen sein, es
soll sich bewegen, schweben ... der ganze hintergrund soll wie ein
universum aussehen. und der rand wie gesagt soll rot schwarz silber und
babyblau sein, rot und babyblau soll man am meisten sehen."

DER RAND HATTE ALLE VIER FARBEN -- IN DER FALSCHEN GEWICHTUNG.
Jeden Stopp mit der Haelfte des Abstands zu seinen Nachbarn gewichtet:
Schwarz 37,5 %, Babyblau 27,5 %, Silber 22 %, ROT 13 %. Die beiden
Farben, die man am meisten sehen sollte, kamen zusammen auf 40,5 % --
Silber allein hatte mehr Platz als Rot. Im Quelltext faellt das nicht
auf: Man sieht neun silberne Stopps und denkt an Spitzlichter, nicht an
ein Fuenftel der Flaeche. Jetzt Babyblau 41,5 %, Rot 33 %, Schwarz
21,5 %, Silber 4 % -- zusammen 74,5 %, und die beiden nur 8,5 Punkte
auseinander. Silber ist auf den Treffpunkt in der Mitte zurueckgenommen,
dieselbe Stelle, an der sich im Schriftzug Chili und Husky treffen.

DAS UNIVERSUM: drei Nebel (rot unten links, babyblau oben rechts, ein
Hauch Lila als Uebergang), ein Sternenfeld aus acht gekachelten
Verlaufsebenen und fuenf schwebende Chilis. Sechs Elemente insgesamt --
Sterne als Elemente waeren neunzig Knoten fuer eine Zierde. Bewegt
werden nur `transform` und `opacity`; ein animiertes
`background-position` zwingt den Browser bei jedem Bild zum Neuzeichnen
einer Kachel mit vierzehn Hintergrundebenen.

DIE ORTE SIND GEMESSEN, NICHT GESTREUT -- und das war die eigentliche
Arbeit. Im ersten Anlauf lagen die Chilis quer ueber der Mittelspalte:
einer deckte 34,5 % der Unterzeile und 45,9 % des Lagesatzes ab, der
Kontrast fiel von 6,36:1 auf 5,87:1. Das war noch zulaessig, zwang die
Deckkraft aber auf sechs Prozent -- und damit sah man die Chilis nicht
mehr, was ausdruecklich gewuenscht war. Die bequeme Antwort waere
gewesen, sie blasser zu machen. Richtig war, sie aus dem Text
herauszunehmen: Sie stehen jetzt in den Zonen ohne Text, tragen 12 bis
17 statt 6 bis 10 Prozent und decken nachgemessen NULL Text ab. Der
verbleibende Verlust von 0,49 kommt allein vom Nebel.

AUGENSCHONEND HEISST HIER VOR ALLEM LANGSAM: Die Bahnen dauern 71 bis
118 Sekunden, die Sternendrift 240. Bei einer Kachel, die stundenlang
im Bild steht, ist eine Bewegung, die man BEMERKT, eine, die stoert.
Nichts blinkt, nichts pulsiert. Bei `prefers-reduced-motion` bleibt das
Bild stehen statt zu verschwinden -- die Einstellung heisst "weniger
Bewegung", nicht "weniger Gestaltung". Unter 700 px gehen die beiden
groessten Chilis: Bei 380 px Breite naehme der grosse ein Drittel der
Kachel ein und staende hinter dem Titel.

Nebenbei zusammengelegt: Die Innenform der Kachel (das Fasen-Polygon)
stand zweimal gleich da und steht jetzt einmal in `--k-innenform`.
Genau diese Sorte Doppelung hat mich in dieser Datei heute schon
zweimal Zeit gekostet.

Geprueft: pruef-start-ansicht (alles in Ordnung), pruef-css-klassen
(alles in Ordnung), Ueberdeckung und Kontrast im Browser nachgemessen
(Foto zurueck in eine Leinwand, WCAG-Helligkeit), Bildschirmfoto bei
doppelter Aufloesung. pruef-barrierefrei-workspace bewusst NICHT
gestartet: Der Kontrast ist hier direkt gemessen (5,87:1 gegen 4,5
gefordert), der Lauf haette 190 Sekunden gebraucht, um dasselbe zu
sagen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 23:41:01 +02:00
DogFatherGitandClaude Opus 5 12c40256f7 Uhr: Stunden rot, Minuten silber, Sekunden babyblau -- alle drei als Reihen
Wunsch Filipe: "stunden soll rot sein, minuten schwarz/silber und die
sekunden babyblau. die punkte herum sollen eine mischung von rot
schwarz und babyblau sein. ich will auch dass die stunden und minuten
auch barren oder punkte sind und nicht so eine durchlaufende schleife."

ALLE DREI BAHNEN SIND JETZT REIHEN. Die Stunde bekommt zwoelf Balken
(ein Zifferblatt hat zwoelf), Minute und Sekunde sechzig. Die Glieder
sind verschieden lang -- Punkt (0,01 + runde Kappe), kurzer Balken
(1,7), langer Balken (5,5). Damit liest man die drei Bahnen auch dann
auseinander, wenn jemand Farben schlecht unterscheidet; Farbe allein
traegt eine Information nie.

VIER FUNDE BEIM NACHMESSEN, keiner davon war vorher sichtbar:

1. ABRUNDEN STATT RUNDEN. `Math.round` liess Minute und Stunde ab der
   HAELFTE einen Balken zu frueh aufleuchten: um 14:30 zeigte der
   Stundenring vier statt drei Balken, der Minutenring ab Sekunde 30
   einen zu viel. Die Uhr war damit die halbe Zeit ueber falsch --
   und ausgerechnet zur vollen Stunde, wo man hinsieht, richtig.
   Nachgerechnet: 10:30 -> 11, 14:30 -> 3, 23:59 -> 12, 00:00 -> 1.

2. DIE PERLENKOEPFE TRUGEN DIE ALTE ZUORDNUNG. Die drei Boegen waren
   getauscht, die drei Koepfe nicht: ein roter Kopf sass auf der
   blauen Sekundenreihe, ein silberner auf den roten Stundenbalken.
   Das sah nach einem Winkelfehler aus, obwohl alle drei auf die
   Zehntelgrad genau standen (354 / 161,9 / 343,0 bei 23:26:59,
   gemessen). Wer eine Farbe tauscht, tauscht sie an ALLEN Stellen:
   Bogen, Kopf, Schein, Kranz.

3. DER SCHEIN LAG DREIFACH UEBEREINANDER. Jeder Ring liegt dreimal im
   SVG (Schatten, Hauptlage, Kante); `.uhr__stunde` traf alle drei.
   Das rote Leuchten lief dadurch bis ueber die Ziffern, obwohl in der
   Regel nur 1,8 px stehen -- genau das Verschwommene, das Filipe nicht
   will. Jetzt `.uhr__ring > …`: nur die Hauptlage leuchtet, Schatten
   und Kante bleiben hart.

4. ZWEI TOTE FARBSCHICHTEN in heim.css (Sekunde rot / Minute blau /
   Stunde bronze). Sie wurden vom spaeteren Satz ueberschrieben und
   waren unsichtbar -- aber wer die Datei von oben liest, haelt sie
   fuer die geltende Regel und aendert die falsche Stelle. Entfernt
   statt stehengelassen: EINE Stelle entscheidet ueber eine Farbe.

Ausserdem: Der Kometenschweif ist raus (HTML und CSS, nicht
ausgeblendet). Eine Reihe zeigt ihre Richtung durch das letzte Glied;
ohne eigenes Muster haette er einen vollen Ring quer ueber die Punkte
gezogen. Der Punktkranz aussen mischt jetzt Rot, Babyblau und ein sehr
dunkles Blau im 18-Grad-Takt -- das Dunkel ist kein Loch, sonst zerfiele
der Ring aus dem Augenwinkel in zwei Haelften.

Gedaempft bleibt Pflicht: Die Sekunde laeuft dauernd und bekommt das
ruhigste Babyblau, die Stunde bewegt sich kaum und darf die kraeftigste
Farbe tragen. Die Auslieferungskennung ist auf allen 19 Seiten
hochgesetzt, sonst kaeme keine der Aenderungen an.

Geprueft: pruef-start-ansicht (alles in Ordnung), pruef-css-klassen
(alles in Ordnung), Segmentzahlen und Perlenwinkel im Browser
nachgemessen, Bildschirmfoto bei vierfacher Aufloesung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 23:30:56 +02:00
DogFatherGitandClaude Opus 5 e04d7afea7 Anlaesse und Report bekommen Sammelkacheln -- und die Zahlen ragten heraus
Filipe, mit zwei Bildschirmfotos: "ich will dass das alles in einer
geilen kachel ist wie die kacheln in der start seite" und "die ganzen
kacheln sollen viel geiler aussehen und spezieller. mach auch vielleicht
2 größere kacheln wo die anderen kleineren drin sind".

DER KALENDER: Drei Abschnitte standen frei auf dem Hintergrundbild --
was als Naechstes ansteht, was in diesem Monat liegt, was von allein
weiterlaeuft. Drei Ueberschriften ohne Fassung lesen sich als drei lose
Listen; zusammen sind sie EINE Auskunft. Jetzt eine Kachel in der
Sprache der Startseite.

Das Formular "Neuer Termin" stand im Quelltext ZWISCHEN den Abschnitten
und waere mitgenommen worden. Der Wiederholungs-Abschnitt ist deshalb
nach oben gewandert, das Formular steht hinter der Kachel -- inhaltlich
ohnehin die bessere Ordnung: erst lesen, was kommt, dann etwas anlegen.
Sind alle drei Abschnitte leer, verschwindet die Kachel; `:has()` fragt
das ab, ohne eine Zeile JavaScript.

DER REPORT: Die vier Abschnitte sind jetzt Sammelkacheln, die kleinen
Zahlenkarten liegen sichtbar darin. Vorher schwebten siebzehn Karten in
einer Flaeche, ohne dass man sah, welche zu welcher Frage gehoert.

UND DABEI EIN ECHTER FEHLER, DER NICHT DAS WAR, WONACH ER AUSSAH.
In Filipes Bild standen die Zahlen unter "Was blockiert?" nur zur
oberen Haelfte da -- die Aufgabenliste darunter schien sie zu
ueberdecken. Nachgemessen liegt die Liste sauber unter dem Raster
(543..594 gegen 594..802, kein Ueberlappen). Herausgeragt ist die ZAHL
SELBST: `.kachel__zahl` ist `position: absolute` und damit fuer die
Hoehenrechnung der Karte unsichtbar. Bei 27 px Schrift in einer 51 px
hohen Karte steht sie 17 px unten ueber -- und was ueber den Rand steht,
verdeckt das Naechste.

Sechs von siebzehn Karten waren betroffen: genau die in Bloecken, deren
Raster nur eine Zeile hat und deshalb niedriger ausfaellt. In den
anderen war die Zeile hoch genug, dort fiel es nie auf. Der Fehler war
immer da und nur manchmal sichtbar.

Behoben ueber eine Mindesthoehe -- sie sagt der Karte, wie viel Platz
ihr Inhalt WIRKLICH braucht. Die Zahl kleiner zu machen waere die
bequemere und die falsche Antwort: Sie ist die Aussage der Karte.
Nachgemessen: 6 -> 0 Karten mit herausragendem Inhalt.

Dazu mehr Luft: 180 px Mindestbreite statt 158. Gemessen lagen in ALLEN
17 Karten Name und Zahl unter sechs Pixel auseinander.

Beide Regeln stehen in report.css bzw. kalender.css, nicht in der
Modulliste: `.block` gibt es auch auf automation.html, dort sind es
Formularbloecke. Die Datei ist die Bedingung.

pruef-kalender EXIT=0 (84), pruef-serien EXIT=0 (69),
pruef-css-klassen EXIT=0 (28), pruef-start-ansicht EXIT=0 (143).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 23:06:53 +02:00
DogFatherGitandClaude Opus 5 7bec3ea80c Sekunden als Punkte, Ringe gestaffelt, silberner Rand weg
Filipe: "ich will aber dass die sekunden wie punkte sind, die minuten
breiter und die stunden noch breiter … den silbernen rand weg bitte den
will ich nicht … es soll nichts verschwommen aussehen oder so, im
gegenteil, richtig scharf und perfekt."

DER SILBERNE RING IST WEG. Er war die breiteste Flaeche der ganzen Uhr
und damit das Erste, was das Auge traf -- ausgerechnet der Teil, der
nichts anzeigt. Jetzt dunkles Metall; die drei Bahnen sind das Hellste
im Bild. Die Skalenstriche bleiben, sie geben Mass ohne zu fuellen.

DIE SEKUNDE IST EINE PUNKTREIHE. Sechzig Punkte, einer je Sekunde --
der schnellste Wert wird zaehlbar statt nur gewachsen. Das ist auch
ehrlicher: Die Sekunde SPRINGT, ein durchgehender Bogen behauptet einen
fliessenden Wert.

DIE BREITEN STAFFELN SICH: 3,2 / 5 / 7 statt 3 / 3,4 / 4. Die alten
Werte waren rechnerisch verschieden und im Bild nicht zu unterscheiden
-- ein Unterschied unter einem Pixel ist keiner. Jetzt liest man die
Ringe an ihrer STAERKE: je langsamer, desto schwerer.

SCHAERFE STATT NEBEL: Die weichen Scheine lagen mit 7 bis 9 px Radius
ueber den Bahnen wie Dunst. Jetzt 1,5 px -- sie liegen als KANTE an
statt als Wolke. Die Tiefe kommt aus dem Versatz der Lagen, so wie im
Rest dieser Uhr auch.

DREIMAL AN DERSELBEN STELLE DANEBEN, UND JEDES MAL IM BILD GESEHEN:

  1. Der Sekunden-Schweif stand noch im Dokument und war per CSS
     ausgeblendet -- das griff nicht, und ohne `dasharray` zeichnete er
     einen durchgehenden roten Ring um die ganze Uhr. Ein Element, das
     nie sichtbar sein soll, gehoert nicht ins Dokument. Ausblenden ist
     kein Entfernen.
  2. Dann das Punktmuster: n Paare plus Schluss-Luecke sind 2n+1 Werte.
     Bei ungerader Anzahl verdoppelt SVG die Liste und vertauscht dabei
     Striche und Luecken.
  3. Also eine Null angehaengt (`rest 0`) -- Anzahl gerade, Fehler
     blieb. Denn in `dasharray` wechseln sich Strich und Luecke ab: Nach
     2n Werten sitzt der naechste an UNGERADER Stelle und ist ein
     Strich. Der Rest wurde weiter gezeichnet. Richtig ist die Null
     ZUERST (`0 rest`), dann landet die Luecke an gerader Stelle.

UND DIE PRUEFUNG MUSSTE MIT. `pruef-start-ansicht` verglich die
REIHENFOLGE der Farbkanaele im Kachel-Licht. Das setzt voraus, dass die
Kanaele deutlich verschieden sind -- seit der neuen Palette stimmt das
nicht mehr: "Aufgaben" ist Tuerkis (G=191, B=163), gemessen 63 gegen 65.
ZWEI Stufen von 255. Die Reihenfolge kippt dort durch Rundung, und die
Pruefung meldete einen Fehler, wo keiner war.

Sie misst jetzt den FARBWINKEL -- dieselbe Frage ("ist es dieser Ton?"),
ohne die Voraussetzung. 40 Grad Toleranz; die Kachelfarben liegen nach
der Neuberechnung gut 60 Grad auseinander. Dazu eine GEGENPROBE je
Kachel: Der gemessene Ton wird gegen den Gegenton auf dem Farbkreis
gehalten und muss dort anschlagen. Eine Pruefung, die immer bestaetigt,
bestaetigt nichts.

Gemessen: Farbwinkel-Abstaende 13° / 16° / 7° von 40 erlaubten.
pruef-start-ansicht EXIT=0, 140 -> 143 Pruefungen (die drei Gegenproben
sind dazugekommen, keine ist verschwunden). pruef-css-klassen EXIT=0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 22:55:25 +02:00
DogFatherGitandClaude Opus 5 5a67ef2948 Die Rabattcodes haengen am Konto, nicht mehr am Abo
Filipe: "die partner codes sollen auch schon fuer die leute sichtbar sein
die angemeldet sind." Umgestellt, und auf Nachfrage dauerhaft: Rabattcodes
sind ab jetzt ein Konto-Vorteil, kein Abo-Vorteil.

WARUM DAS MEHR IST ALS EINE BEQUEMLICHKEIT

Der alte Riegel verlangte einen Abo-Status. Nachgesehen, statt vermutet:
Die Bezahlung auf abonnieren.html steht auf "Coming soon", bis Dogis
PayPal-Business-Zugang da ist (der Kommentar dort nennt es beim Namen).
Registrieren geht, bezahlen nicht. Der erste echte Partnercode lag damit
seit gestern hinter einer Tuer, die sich gar nicht oeffnen laesst -- er
waere fuer NIEMANDEN sichtbar gewesen ausser fuer Dogi und VanVan ueber
die Rollenvorschau.

Entschieden wird jetzt an "supporterToken" (beim Login gesetzt, beim
Logout entfernt, supporter.js). Der Abo-Stand wird als Sicherheitsnetz
weiter mitgelesen: Niemand soll Zugang verlieren, den er gestern hatte.

BEIDE STELLEN, NICHT EINE

Die Bedingung steht doppelt im Haus -- an der Kachel auf links.html und
an der Seite selbst. Nur eine davon umzustellen erzeugt einen Fehler, den
keine der beiden fuer sich zeigt: Man kaeme mit Konto auf die Seite und
saehe dort die Sperre. Beide sind umgestellt, tragen den Hinweis
aufeinander, und die Pruefung vergleicht sie in jedem Anmeldezustand
gegeneinander.

TEXTE, DIE SONST GELOGEN HAETTEN

"Nur fuer Supporter" auf einer Seite, die ein kostenloses Konto oeffnet,
schickt Leute zum Bezahlen fuer etwas, das sie umsonst bekommen. Kopf,
Vorspann, Kachelband, Beschreibung und Sperrtext sagen jetzt "Konto", in
allen fuenf Sprachen. Die Sperre bietet auf Filipes Wunsch beide Wege an:
den kostenlosen zuerst, das Abo daneben -- mit einer Zeile darunter, dass
es erst startet, wenn es offiziell live geht. Ohne die waere der zweite
Knopf eine Falle.

EIN FEHLER, DER SEIT DEM 03.08.2026 DRINSTAND

Die Pruefung meldete auf der FREIGESCHALTETEN Kachel weiter "Nur mit
Konto" statt "Freigeschaltet". Ursache: Das Skript setzte den Text
(`badge.textContent = ...`), aber applyTranslations() schreibt aus dem
data-i18n-Attribut zurueck -- und es laeuft danach noch einmal, weil
dogiSiteTexteLaden() die Texte aus der Verwaltung holt und dann neu
uebersetzt.

NACHGEMESSEN STATT HERGELEITET, und die erste Erklaerung war zu schnell:
Der Text war schon nach 50 ms falsch, also nicht "irgendwann spaeter
ueberschrieben". Der Grund ist, dass TEAM_API_BASIS auf den ECHTEN Worker
zeigt -- der Abruf gelingt selbst aus einer lokalen Testseite. Kontroll-
versuch mit blockiertem Abruf: derselbe alte Code, und das Band bleibt
korrekt. Ursache weg, Fehler weg.

Behoben, indem der SCHLUESSEL getauscht wird statt des Textes. Damit
schreibt jeder weitere Uebersetzungslauf von selbst das Richtige hin --
auch bei Sprachwechsel, wo die alte Fassung ebenfalls zurueckfiel.
Aufgefallen ist es nie, weil bis gestern niemand in den freigeschalteten
Zustand kommen konnte.

NEBENBEFUND, NICHT ANGEFASST: index.html hat dieselbe Bauart beim
Live-Status (#live-text mit data-i18n, Text per Skript gesetzt).
Gemessen ist es dort ein Wettlauf zweier Abrufe -- in meinem Lauf gewann
der Status um Haaresbreite, und ein Sprachwechsel repariert es dort
ohnehin (dogi-sprache-geaendert). Kleiner, aber echt. Auf Ansage.

pruef-rabattcodes EXIT=0 (63 Pruefungen, vorher 42). Neu darunter: drei
Anmeldezustaende statt zweier -- ausgeloggt, angemeldet ohne Abo,
angemeldet mit Abo --, jeder auf BEIDEN Seiten, dazu der Klick auf die
Kachel (fuehrt sie wirklich weiter?), die Beschriftung des Bands und als
Gegenprobe ein erzwungener Uebersetzungslauf, der den alten Fehler
zuverlaessig ausloest.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 21:49:16 +02:00
DogFatherGitandClaude Opus 5 8cdc31bd46 Der erste Partnercode steht: DOGI10 auf einer gepraegten Muenze
Die Rabattcodeseite war ein Platzhalter -- "Codes folgen in Kuerze" und
darunter eine Vorschaukachel mit dem erfundenen Code "DOGFATHER". Jetzt
steht der erste echte drauf: DOGI10 fuer Van's DIY & Bastelbedarf,
verlinkt auf vans-diy-bastelbedarf.com.

DIE KONDITIONEN SIND ABGELESEN, NICHT GERATEN.

Aus "DOGI10" auf zehn Prozent zu schliessen, waere naheliegend gewesen,
haette zufaellig gestimmt und waere trotzdem falsch gewesen. Nachgesehen
im Shop selbst (src/content/partnercodes.json):

  { "code": "DOGI10", "prozent": 10, "bis": "2026-09-30",
    "aktiv": true, "giltAufSale": false }

Zwei der drei Angaben stehen im Namen NICHT drin: dass der Code am
30.09.2026 auslaeuft und dass er auf bereits reduzierte Artikel nicht
gilt. Beides steht jetzt sichtbar auf der Karte. Eine falsche Zusage auf
einer Verkaufsseite kostet VanVan die Diskussion an der Kasse.

Gegengeprueft, dass die Datei auch wirklich gilt und kein Ueberbleibsel
ist: Sie wird an zwei Stellen ausgewertet, src/scripts/cart.ts fuer den
Warenkorb und server/lib/preis-berechnen.js fuer den Endpreis, beide mit
derselben Regel (aktiv !== false UND jetzt <= bis 23:59:59).

DAS ABLAUFDATUM IST EINE ZEITBOMBE, ALSO BEKOMMT ES EINEN ZUENDER.

Ein fest eingetippter Satz "gueltig bis 30.09.2026" stimmt, bis der
Kalender ihn ueberholt -- ab dem 01.10. verspraeche die Seite etwas, das
der Shop schon ablehnt. Genau dieselbe Falle hat am 06.09. den
Oeffnungstest im Shop umgeworfen. Das Datum steht deshalb nicht nur im
Text, sondern einmal als Zahl im Skript: Ist es vorbei, schaltet die
Karte selbsttaetig auf "abgelaufen", streicht den Code durch und sperrt
den Kopierknopf, statt weiter zu werben.

DAS LOGO: AUS EINEM SIEGEL WIRD EINE MUENZE.

Filipe hat das Logo als Bildschirmfoto aus TikTok geliefert, rundes
Siegel auf schwarzem Grund. Ungestellt waere daraus auf der dunklen
Karte ein sichtbarer schwarzer Kasten geworden -- derselbe Fehler wie
bei der Workspace-Marke, deren Zahlen damals tadellos aussahen.

Freigestellt wird per Flutfuellung vom Bildrand (tools/partner-siegel-
freistellen.mjs, 384 px WebP, 37 KB). Eine Kreismaske waere hier sogar
ausrechenbar gewesen -- Mitte 539,5/526,5, Radius 495 -- und haette
genau fuer dieses eine Bild funktioniert. Die Fuellung MISST die Form,
statt sie vorauszusetzen: Der naechste Partner ist ein Eintrag in
AUFTRAEGE und sonst nichts. Die Quelle liegt mit im Repo, sonst laesst
sich das Werkzeug genau einmal ausfuehren und ist danach Dekoration.

"Extrem speziell" fuehrt hier NICHT ueber mehr Farbe -- das Siegel ist
schwarz-weiss, jede Einfaerbung lackierte eine fremde Marke um. Es
fuehrt ueber mehr Material: sechs CSS-Lagen, kein zweites Bild.

  Aura     weicher Lichthof, atmet in 9 s
  Raendel  die geriffelte Muenzkante, 72 Zaehne. Sie steht STILL --
           eine sich drehende Riffelung flimmert bei 148 px, und das
           waere genau die grelle Optik, die die Hausregel ausschliesst
  Glanz    stattdessen wandert EIN Lichtpunkt in 22 s um die Kante.
           Das ist die Bewegung, die eine Muenze im Licht macht
  Schliff  Praegekante nach innen, oben Licht, unten Schatten
  Ablage   elliptischer Schatten, damit die Muenze auf der Karte LIEGT

Bei prefers-reduced-motion steht alles davon still.

NEBENBEFUND, DER SONST NIEMANDEM AUFGEFALLEN WAERE: Der Text auf der
Sperrkachel endete auf "sobald die ersten Kooperationen live sind".
Seit heute IST die erste live -- der Satz haette jemanden dafuer zahlen
lassen, auf etwas zu warten, das schon hinter der Sperre liegt.
Ebenfalls nachgemessen statt vermutet: die Warengruppen im
Beschreibungssatz sind die echten Kategorien des Shops.

pruef-rabattcodes EXIT=0 (42 Pruefungen), darunter beide Richtungen der
Supporter-Sperre, die Bildpunkte des ausgelieferten Siegels (Ecken
durchsichtig, Mitte deckend, 69 % Flaeche), das Kopieren gegen die echte
Zwischenablage samt Gegenprobe davor, die Ablaufschaltung mit gestellter
Uhr an beiden Seiten des Stichtags und alle fuenf Sprachen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 18:48:11 +02:00
DogFatherGitandClaude Opus 5 d694e34fcb Die Uhr nach Filipes Vorbild: LED-Kranz, Anker, rote Anzeige
Filipe hat eine Sci-Fi-Uhr geschickt (1250 px) und gesagt "so wie die".
Unsere ist 164 px gross -- Faktor 7,6. Was uebernehmbar ist, entscheidet
damit nicht der Geschmack, sondern die Groesse:

  UEBERNOMMEN    der blaue LED-Punktkranz aussen (das auffaelligste
                 Merkmal des Vorbilds), die vier Anker bei 12/3/6/9,
                 der rote Grundton der Digitalanzeige.
  NICHT MOEGLICH die Minutenzahlen 00/05/…/55 und die Stundenzahlen
                 1-12. Im Vorbild sind sie rund 30 px hoch; hier waeren
                 es VIER. Zahlen, die man nicht lesen kann, sind kein
                 Zifferblatt, sondern Rauschen -- und sie wuerden die
                 drei Boegen zudecken, die die eigentliche Anzeige sind.

Der Kranz ist ein `repeating-conic-gradient` mit 6-Grad-Takt, aus dem
eine Maske einen schmalen Ring schneidet: 60 Punkte, einer je Sekunde,
in EINER Ebene. Sechzig <span> waeren sechzig Elemente fuer eine Zierde.
Die vier Anker ebenso, mit 90-Grad-Takt.

EINE FALSCHE BEGRUENDUNG, VON DER EIGENEN RECHNUNG WIDERLEGT: Ich hatte
in den Kommentar geschrieben, reines Neonrot wie im Vorbild "reisse den
Kontrast" und liege bei 4,0:1. Nachgerechnet sind es 5,27:1 -- es haelt
die Grenze von 4,5. Die schoenere Begruendung war die falsche.

Die Entscheidung bleibt trotzdem, nur mit dem echten Grund: Diese Uhr
steht DAUERHAFT im Bild einer Seite, an der gearbeitet wird. Reines
gesaettigtes Rot auf Schwarz ermuedet bei stundenlangem
Nebenherschauen, auch wenn es messbar lesbar ist -- genau das meint die
Hausregel "augenschonend", und das deckt keine Kontrastzahl ab. Die
Ziffern sind deshalb ein sehr helles Rotweiss (15,9:1), das seinen
roten Charakter aus dem Schein im Textschatten bekommt. Man liest
"rote Digitalanzeige", ohne stundenlang in eine Leuchtreklame zu sehen.

Aus demselben Grund liegt das Blau der LEDs bei rund 53 % Deckkraft:
Die Anmutung kommt vom Aufbau, nicht von der Grellheit.

pruef-start-ansicht EXIT=0 (140), pruef-css-klassen EXIT=0 (28).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 18:21:08 +02:00
DogFatherGitandClaude Opus 5 e2bd6d4dc4 Die Uhr bekommt Kometenschweife -- und die Koepfe gleiten, statt zu springen
Filipe: "nehm diese uhr bitte und passe sie so gut wie es geht an, auch
die lichter von sekunden, minuten und stunden perfekt anpassen ...
überrasch mich."

ZWEI DINGE, DIE EINE UHR LEBENDIG MACHEN.

1. DER KOMETENSCHWEIF. Ein Bogen in gleichmaessiger Farbe zeigt einen
   STAND. Ein Bogen, der zur Spitze hin heller wird, zeigt eine
   RICHTUNG -- man sieht ohne Nachdenken, wo "jetzt" ist und wohin es
   laeuft. Bei drei Ringen uebereinander ist das der Unterschied
   zwischen Ablesen und Erkennen.

   Gebaut als zweites, kuerzeres Segment ueber dem Bogen: die letzten
   rund 40 Grad, heller, mit runder Kappe. Ein Verlauf ENTLANG der Bahn
   geht in SVG nicht -- `linearGradient` folgt einer Geraden, keiner
   Kurve. Zwei Lagen sind der ehrliche Weg dorthin.

   Die Lage wird gerechnet, nicht geschaetzt: Bei Umfang U, Fortschritt
   a und Schweiflaenge s soll das Segment von (aU - s) bis aU liegen.
   Mit `dasharray: s, U-s` beginnt das sichtbare Stueck bei (U - offset),
   also ist offset = U*(1-a) + s. Die Laenge wird bei kurzen Boegen
   mitgekuerzt -- sonst haenge der Schweif am Anfang einer Minute am
   ENDE des Kreises, sichtbar als heller Strich bei zwoelf Uhr.

2. DIE KOEPFE GLEITEN. Bisher sprangen sie einmal je Sekunde. Jetzt
   uebernimmt der Browser die Bewegung dazwischen (Ueberblendung von
   0,92 s) -- das Skript rechnet weiterhin nur EINMAL je Sekunde. Sechzig
   Bildberechnungen je Sekunde wuerden auf einer stundenlang offenen
   Seite den Rechner warm halten; diese Loesung kostet nichts.

ZWEI FEHLER DABEI, BEIDE NUR IM BILD ZU SEHEN:

  Der erste Versuch rechnete die Winkel aus der vollen Unixzeit, damit
  sie immer weiterwachsen (sonst liefe die Ueberblendung einmal je
  Minute rueckwaerts durchs Zifferblatt). Ergebnis:
  `rotate(1.07333e+10deg)` -- Exponentialschreibweise, Nachkommastellen
  weg. Die Koepfe standen sichtbar neben ihren Boegen, der rote auf der
  anderen Seite der Uhr. Jetzt zaehlt eine eigene Uhr ab dem ersten
  Takt: klein genug zum Rechnen, wachsend genug fuer die Ueberblendung.

  Und ich hatte den Schweifen `rotate(-90deg)` gegeben, damit sie bei
  zwoelf beginnen -- das SVG ist aber bereits gedreht. Sie standen
  dadurch exakt eine Vierteldrehung daneben: oben links, waehrend die
  Boegen oben rechts endeten.

NACHGEMESSEN, in Grad statt nach Augenmass:
  Kopf gegen Bogenende      Abweichung 0,00° / 0,00° / 0,03°
  Schweifende gegen Bogen   Abweichung 0,0° / 0,0° / 0,0°

pruef-start-ansicht EXIT=0 (140), pruef-css-klassen EXIT=0 (28).
Bei `prefers-reduced-motion` gleiten die Koepfe nicht -- sie springen
dann wie vorher.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 18:12:26 +02:00
DogFatherGitandClaude Opus 5 4c0ff5caa9 Die vier Call-Reiter stehen bei jeder Rolle -- und die Tagesliste bekommt die Fase
Filipe mit zwei Bildschirmfotos nebeneinander: "wieso bei den scouts so
und bei den manager so?" Bei Patrick stand EINE Tafel ueber die volle
Breite, bei Schulle vier nebeneinander.

DIE URSACHE war zweimal derselbe Satz Code an zwei Stellen in calls.js:

  `if (!liste.length) continue;`   eine leere Gruppe wurde nicht gebaut
  `... return;`                     sind ALLE leer, gab es nur einen Satz

Wer nichts Offenes hat, sah damit nicht "weniger", sondern eine anders
AUFGETEILTE Seite: Bei einer Tafel zieht sich diese ueber die ganze
Reihe. Genau derselbe Fehler wie bei den Aufgabenzahlen auf der
Startseite heute -- und dieselbe Loesung: Die Tafel bleibt stehen, wird
gedaempft und zeigt eine Null. "Protokoll fehlt: 0" ist eine Aussage,
ein fehlender Reiter ist keine. Leere Tafeln starten zugeklappt --
aufklappen wuerde nur eine leere Liste zeigen.

Der Hinweis "Noch keine Calls" bleibt, er ist nuetzlich, und steht jetzt
UEBER den vier Tafeln statt an ihrer Stelle.

DABEI EINEN ZWEITEN FEHLER GEBAUT UND GESEHEN: Der Hinweis wurde damit
zum Geschwister der Tafeln, und `.call-brett` ist ein Flex-Kasten in
EINER Reihe -- er nahm sich eine Spalte und quetschte die vier Tafeln
daneben auf je 80 px. Im Bildschirmfoto standen vier Stummel neben einem
breiten Satz. Behoben mit `flex-wrap: wrap` und voller Breite fuer den
Hinweis; nachgemessen stehen die vier jetzt bei je 280 px.

DAZU EIN BEFUND AUS DEM FORMVERGLEICH ueber alle fuenf Rollen:
`.tagesliste__punkt` (die Terminzeilen auf der Startseite) trug noch
runde Ecken -- direkt unter Kacheln mit Fase. Sie bekommt den Zuschnitt
von Hand, nicht ueber die Modulliste: `::before` traegt die Farbkante
links, die sagt, um welche Art Termin es geht, und die Modulliste
braucht dasselbe Pseudo-Element fuer ihre Eckwinkel.

NACHGEMESSEN ueber drei Rollen: scout 4 Reiter, admin 4, creator 4 --
alle mit derselben Aufteilung.
pruef-abbrechen-optik EXIT=0 (27), pruef-start-ansicht EXIT=0 (140),
pruef-css-klassen EXIT=0 (28).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 18:03:54 +02:00
DogFatherGitandClaude Opus 5 da274f7825 Die Dialoge bekommen die Fase -- und einer war ueberhaupt nicht gestaltet
Filipe: "es soll bei jedem nicht nur bei patrick sondern bei jedem die
neue stile haben wie bei mir."

Mein Durchlauf ueber 18 Seiten und fuenf Rollen hatte die DIALOGE
ausdruecklich ausgenommen -- und genau dort lag noch etwas.

1. `.dialog` trug runde Ecken (4px 20px 20px 4px). Er bekommt jetzt
   dieselbe Fase wie alles andere. NICHT ueber die Modulliste: Die
   belegt `::before` und `::after` fuer die Eckwinkel, und beide sind
   hier schon vergeben -- an die Leuchtschiene links und den Lichtsaum.
   Beides gegen zwei Winkel zu tauschen waere ein Rueckschritt, also
   nur der Zuschnitt von Hand, mit derselben Groesse `--fase`.

2. DER WECKER-DIALOG WAR GAR NICHT GESTALTET. Gefunden beim Nachsehen,
   welche Dialoge nicht `.dialog` heissen: Dieser traegt `.tagdialog`,
   und diese Klasse stand in KEINER Stilvorlage. Gemessen bekam er vom
   Browser:

     Hintergrund  rgb(18, 18, 18)   flaches Systemschwarz
     Rand         3 px              Systemrahmen
     Fase         keine
     Raster       keins

   Er sah aus wie ein Fenster des Betriebssystems mitten im Workspace --
   auf JEDER Rolle, denn den Wecker haben alle. Aufgefallen ist es nie,
   weil er nur aufgeht, wenn man die Glocke an einem Termin drueckt.
   Nebenbei stand das Schliesskreuz unter der Ueberschrift statt daneben:
   Auch `.tagdialog__kopf` war ohne Regel.

DAS IST DER GRUND, WARUM DER ERSTE DURCHLAUF "0 im alten Muster" ergab
und trotzdem nicht die ganze Wahrheit war: Meine Messung suchte
Elemente mit runden ECKEN. Ein Baustein ganz ohne Gestaltung hat keine
runden Ecken -- er faellt durch dasselbe Sieb. Eine Suche findet nur,
wonach sie fragt.

pruef-kalender EXIT=0 (84), pruef-wecker EXIT=0 (20),
pruef-css-klassen EXIT=0 (28), pruef-start-ansicht EXIT=0 (140).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 17:49:41 +02:00
DogFatherGitandClaude Opus 5 bd21062d29 Alle Seiten folgen derselben Form -- gemessen ueber 18 Seiten und fuenf Rollen
Filipe: "die seiten sollen bei jedem aussehen wie bei mir, bei patrick
zumbeispiel sieht sehr viel noch nach dem alten muster aus ... alles was
sie sehen soll dan auch nach der neuen struktur aufgebaut sein."

GEMESSEN STATT GESCHAUT. Das "alte Muster" ist praezise benennbar: runde
Ecken (border-radius 18px) statt der gefraesten Fase (clip-path polygon
mit 18px). Damit laesst es sich SUCHEN, nicht nur ahnen -- ein Durchlauf
ueber alle 18 Seiten in allen fuenf Rollen, der jedes Element ab
260x90 px meldet, das eine eigene Flaeche und runde Ecken hat.

  vorher   5 Klassen im alten Muster, 90 Seitenaufrufe
  jetzt    0 Klassen

DER GROESSTE EINZELPOSTEN war der Seitenkopf. `.kopf-zeile` trug runde
Ecken -- auf VIERZEHN Seiten das erste, was man sieht, direkt neben
Kacheln mit Fase. Dazu `.k-kopf` (Kalender), `.steckbrief`,
`.k-anlasskarte`, `.k-raster`, `.entscheidung` und die
Formulargruppen auf der Profilseite.

ZWEI SELEKTOREN MIT BEDACHT, weil derselbe Klassenname zweierlei meint:

  `.gruppe[data-gruppe]`  nur die Reiter auf der Calls-Seite. Auf der
                          Startseite heissen die Bereichsgruppen ebenso,
                          sind aber BEHAELTER fuer Kacheln und duerfen
                          selbst keine sein. `data-gruppe` setzt
                          ausschliesslich calls.js -- nachgeprueft.
  `fieldset.gruppe`       nur die Formularbloecke auf profil.html. Die
                          Startseite baut `section.gruppe`. Das Element
                          unterscheidet sie sauber, die Klasse nicht.

BEINAHE FALSCH GEMACHT: Ich war sicher, `.steckbrief` und
`.k-anlasskarte` staenden bereits in der Modulliste, und wollte
weitersuchen, warum die Regel bei ihnen nicht greift. Nachgesehen: Sie
standen gar nicht drin -- ich hatte sie mit `.k-listentag` und einer
Liste aus kopf.js verwechselt. Eine plausible Erinnerung ersetzt keinen
Blick in die Datei.

DIE MODULLISTE STEHT SIEBENMAL WORTGLEICH. Alle sieben ergaenzt;
pruef-css-klassen prueft "alle sieben Kopien sind Zeichen fuer Zeichen
gleich" und zaehlt jetzt 43 Klassen statt 36.

GEPRUEFT:
  90 Seitenaufrufe (18 Seiten x 5 Rollen) -> 0 Bausteine im alten Muster
  36 Seitenaufrufe auf 360/390/412 px      -> 0 px waagerechter Ueberstand
  pruef-css-klassen EXIT=0, pruef-start-ansicht EXIT=0 (140),
  pruef-rollen EXIT=0 (97), pruef-abbrechen-optik EXIT=0 (27)

Die Handy-Messung gezielt selbst gefahren statt pruef-handy zu starten:
Die eine Frage, die diese Aenderung aufwirft, ist der Ueberstand -- in
40 Sekunden beantwortet statt in drei Minuten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 17:21:44 +02:00
DogFatherGitandClaude Opus 5 cba46e79e6 Jede Rolle sieht dieselben Kategorien -- und die Reiter werden zu Kacheln
Filipe, mit Bildschirmfoto: "diese beiden kategorien sollen bei jedem in
jeder rolle gleich sein ... alles was kacheln ist und so soll gleich sein."

ERSTENS: DIE ZAHLENREIHE VERSCHWAND BEI EINER ROLLE.

Nachgemessen ueber alle fuenf Rollen sah Spicy Media als EINZIGE keine
Zahlenreihe, sondern einen Satz -- die anderen vier sahen sieben
Kategorien:

  spicy     0 Zahlen (Leer-Hinweis statt Zahlen)
  admin     7 Zahlen
  manager   7 Zahlen
  scout     7 Zahlen
  creator   7 Zahlen

Die Ursache war eine gut gemeinte Regel: "Sechs Nullen nebeneinander
sind kein Bericht, sondern Rauschen" -- bei Summe null wurde die ganze
Reihe geloescht. Der Gedanke stimmt, die Folge nicht: Wer zwischen zwei
Rollen wechselt, findet die Seite anders aufgebaut vor und sucht, was
fehlt.

Jetzt steht die Reihe IMMER, mit denselben sieben Kategorien fuer alle.
Ist wirklich nichts offen, wird sie GEDAEMPFT (weniger Deckkraft, kein
Warnrot, Zahlen ohne Leuchten) und der Satz steht ZUSAETZLICH darunter
statt an ihrer Stelle. Gedaempft ist auch eine Antwort, nur eine leise --
und die Form der Seite bleibt ueber alle Rollen gleich.
Nachgemessen: alle fuenf zeigen jetzt dieselben sieben.

ZWEITENS: DIE REITER AUF DER CALLS-SEITE WAREN KEINE KACHELN.

Gemessen: Eine Kachel traegt `clip-path: polygon(18px 0 …)` -- die
gefraeste Fase -- plus Innenschatten. Die Reiter hatten `clip-path: none`
und nur einen feinen Lichtrand. Sie standen als einzige Bausteine
ausserhalb der gemeinsamen Sprache.

Sie sind jetzt in der Modulliste von module.css. Der Selektor ist
`.gruppe[data-gruppe]` und nicht `.gruppe`: Auf der Startseite heissen
die Bereichsgruppen genauso, sind aber BEHAELTER fuer Kacheln und
duerfen selbst keine sein. `data-gruppe` setzt ausschliesslich calls.js
-- nachgeprueft, nicht angenommen.

DIE MODULLISTE STEHT SIEBENMAL WORTGLEICH in der Datei. Alle sieben
wurden ergaenzt; `pruef-css-klassen` prueft genau das ("alle sieben
Kopien sind Zeichen fuer Zeichen gleich") und haette einen vergessenen
Eintrag gemeldet.

UND SIE HAT NOCH ETWAS GEMELDET, einen Fehler von heute Nachmittag:
".rs-funkel -- fehlt auf 1 Seite (index.html)". Beim Verdoppeln des
Rollen-Sprites auf die Anmeldeseite hatte ich die Gestaltung dazu nicht
mitgenommen; sie lag in personen.css, die index.html gar nicht laedt.
Der Manager-Stern stand dort ohne seinen Glanz. Die Regeln liegen jetzt
in gate.css -- auf allen 19 Seiten. Derselbe Fehler wie beim Sprite
selbst, nur eine Ebene hoeher: Wer etwas verdoppelt, muss alles
mitnehmen, was daran haengt.

pruef-css-klassen EXIT=0, pruef-start-ansicht EXIT=0 (140),
pruef-abbrechen-optik EXIT=0 (27).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 16:44:22 +02:00
DogFatherGitandClaude Opus 5 2872f714f3 Ein App-Symbol aus beiden Marken: Husky in der Mitte, Chili als Sockel
Filipe: "ich will dass du da eine geile mischung machst von diesen zwei
logo ... mach was ultra krass geiles draus bitte."

DIE AUFGABE IST NICHT "zwei Bilder nebeneinander". Ein App-Symbol steht
bei 32 px im Browserreiter und bei 192 px auf dem Startbildschirm. Zwei
vollstaendige Logos nebeneinander ergeben dort zwei unlesbare Haelften.
Gebraucht wird EINE Form, in der beide vorkommen.

Der Husky steht im Zentrum -- eine Silhouette traegt bei kleiner Groesse
am besten. Die Chili liegt als Bogen darunter, wie ein Sockel. Der
Hintergrund traegt beide Farben: Chili-Rot unten links, Dogi-Blau oben
rechts, und sie treffen sich in der Mitte -- dieselbe Klammer wie im
Schriftzug "Spicy & Dogi" in der Kopfleiste.

Der Husky wird als MASKE eingesetzt und mit Silber gefuellt: Das
Original ist schwarzweiss und waere auf dunklem Grund ein dunkler Fleck.

UNTER 64 px FAELLT DIE CHILI WEG. Sie waere dort ein verwaschener Fleck
und wuerde die Husky-Silhouette anfressen. Ein Symbol, das klein noch
erkennbar ist, ist mehr wert als eins, das alle Bestandteile zeigt und
dabei zu Matsch wird.

EINMAL NACHGEBESSERT nach dem Blick aufs Bild: Die Chili sass zuerst
hoeher und schnitt dem Husky die Brust ab. Jetzt liegt sie tiefer, er
steht vollstaendig.

GEPRUEFT WIRD NICHT DIE DATEIGROESSE, sondern die Streuung der
Helligkeit. Ein Symbol, das aus einem Fehler heraus einfarbig ist, hat
dieselbe Bytezahl wie eines mit Motiv -- die beweist also nichts. Ein
leeres Feld hat keine Streuung; gemessen wurden 48 bis 69 bei einer
Untergrenze von 12, unter der das Werkzeug abbricht.

EINE FALLE MITENTSCHAERFT: `tools/app-symbole.mjs` fuehrte den Workspace
noch in seiner Liste und haette die sechs Dateien beim naechsten Lauf
stillschweigend ueberschrieben -- gleiche Namen, gleicher Ordner, kein
Fehler, nur wieder das alte Symbol. Er steht dort nicht mehr.

pruef-workspace-seiten EXIT=0 (32), pruef-assets EXIT=0.
Nebenbefund, NICHT von hier: pruef-verwaltung-app scheitert an einem
MODULE_NOT_FOUND -- gegen den alten Stand gegengeprueft, dort derselbe
Fehler. Vorbestehend, gehoert auf die offene Liste.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 14:19:08 +02:00
DogFatherGitandClaude Opus 5 25f35c1290 Die App-Leiste wird dunkel, und der Titel sagt nicht mehr alles doppelt
Filipe, mit Bildschirmfoto der installierten App: "die barre oben wenn ich
die seite als app installiere ist blau, sie soll der seite angepasst
werden auch der text oben soll jetzt der seite unten angepasst werden".

DIE LEISTE stand auf `theme-color: #0674b9` -- ein kraeftiges Blau. In
einem Browserfenster faellt das nicht auf, weil man die Angabe dort gar
nicht sieht. Als installierte App ist sie die FENSTERLEISTE, und damit
sass ueber einer durchweg dunklen Seite ein leuchtend blauer Balken.
Jetzt derselbe Ton wie die Kopfleiste darunter (#06090f): Leiste und
Seite sind eine Flaeche statt zweier. Geaendert auf allen 19 Seiten und
im Manifest -- steht die Farbe nur an einer Stelle, blitzt beim Wechsel
auf eine andere Seite kurz die alte auf.

DER TITEL stand doppelt in der Leiste, und beide Haelften sagten
dasselbe: "Creator Workspace — Dogfather Universe" (aus dem Manifest)
plus "Dogfather Universe · Creator Workspace · Anmeldung" (aus <title>).
Der Markenname kam zweimal, der Anwendungsname zweimal, und was die
Seite tatsaechlich zeigt, stand ganz hinten.

Jetzt steht vorn, WO man ist, und hinten die Marke:
  Anmeldung · Spicy & Dogi
  Kalender · Spicy & Dogi
  Personen & Zugaenge · Spicy & Dogi

"Creator Workspace" faellt dabei aus den Unterseiten heraus -- es steht
im Manifest und damit ohnehin im Fenstertitel. Neunzehn Titel, alle nach
demselben Muster; vorher folgten sie zwei verschiedenen.

Das Manifest heisst jetzt "Creator Workspace — Spicy & Dogi" und der
Ladehintergrund #0a121e statt #151e2a: Er ist das Erste, was beim
Starten der App zu sehen ist, und war heller als die Seite, die danach
kommt -- ein Aufblitzen bei jedem Start.

pruef-start-ansicht EXIT=0 (140), pruef-workspace-seiten EXIT=0 (32).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 14:13:00 +02:00
DogFatherGitandClaude Opus 5 469bbe9d07 Babyblau statt Gold, lila Stern, sichtbarer Husky -- und eine zweite Variable
Drei Ansagen von Filipe nach dem Bildschirmfoto, alle an derselben Liste.

screen2: "die hauptfarbe von der kategorie dogfather soll babyblausilber
sein bitte." -- DAS WAR EIN FEHLER VON MIR, und zwar derselbe wie schon
zweimal heute: Beim Umstellen auf die zentralen Rollenfarben habe ich
`--rf` erwischt, aber `--rton` uebersehen. Die faerbt die GEWAEHLTE
Rolle in der Tafel, und dort standen `--k-gold` (admin) und `--k-mittel`
(manager) unveraendert. Deshalb leuchteten beide goldbraun, obwohl die
Farben laengst umgestellt waren. Zwei Variablen fuer dieselbe Sache, nur
eine angefasst -- wie die doppelte Groessenangabe beim Wasserzeichen und
wie die zweite Kopie der Rollenzeichen in index.html. Jetzt kommen beide
aus derselben Quelle; nachgemessen traegt admin rgba(63,189,245).

screen3: "die hauptfarbe von denen ist lila, der stern soll so bleiben
aber was gelb ist soll lila werden." -- Die FORM bleibt, nur die Farbe
wechselt. Das ist auch stimmiger: Der Manager traegt Lila als
Rollenfarbe, ein goldener Stern daneben war die einzige Stelle, an der
Zeichen und Rolle auseinandergingen. Die Wechsel hell/dunkel im Verlauf
bleiben -- sie machen aus einer Flaeche einen Koerper.

screen1: "der husky soll viel besser aussehen und zu sehen sein." Zwei
Gruende, warum er unterging, und beide sind behoben:

  Die OHREN waren nur angedeutet und gingen in der silbernen Flaeche
  auf -- dabei erkennt man einen Husky zuerst daran. Sie sind jetzt
  dunkel ausgelegt, mit hellem Innenohr.
  Die GESICHTSMASKE fehlte ganz. Ohne sie ist der Umriss nur eine
  spitze Form mit zwei Punkten; mit ihr ist es ein Gesicht.

Dazu 21 -> 27 px fuer alle fuenf Zeichen: rund 65 % mehr Flaeche, ohne
dass die Zeile ihre Hoehe aendert. Bei 21 px lagen Ohren, Maske und
Augen auf drei bis vier Bildpunkten -- da hilft keine Zeichnung.

Beide Dateien geaendert, nicht nur eine: Das Sprite steht seit heute in
personen.html UND index.html. Genau diese Doppelung hatte den letzten
Fehler verursacht.

pruef-rollen EXIT=0 (97), pruef-start-ansicht EXIT=0 (140).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 14:07:30 +02:00
DogFatherGitandClaude Opus 5 1d0451948a Die drei Bahnen der Uhr gluehen von innen -- und die Stunde wird Bronze
Filipe: "die minuten sekunden und stunden soll viel spezieller, krasser
und geiler sein, noch vieeeel mehr."

Die Bahnen waren flache Striche in einem Verlauf -- sauber gebaut, aber
ohne Koerper. Drei Aenderungen, und alle drei arbeiten mit LICHT statt
mit mehr Farbe:

1. EIGENLEUCHTEN je Bahn, in ihrer eigenen Farbe. Auf einem schwarzen
   Zifferblatt kann man einen Strich entweder heller machen (dann
   blendet er) oder leuchten lassen (dann wirkt er wie eine Anzeige,
   die Licht abgibt). Zwei Schatten je Bahn: der enge gibt die Kante,
   der weite die Aura.

2. DIE STUNDE WIRD WARM. Sie lief in Schwarzsilber und war damit dem
   Zifferblatt am aehnlichsten -- ausgerechnet die Bahn, die man am
   haeufigsten abliest. Jetzt Bronze: warm gegen das kalte Blau der
   Minute und das Rot der Sekunde. Damit sind alle drei auf einen Blick
   zu trennen. Die Wechsel hell/dunkel im Verlauf bleiben, sie sind es,
   die aus einem Strich Metall machen.

3. DIE PERLEN sind die Spitzen -- dort schaut man hin. Sie bekommen
   denselben Schein wie ihre Bahn, nur staerker, und einen weissen
   Kern: der Unterschied zwischen einem farbigen Punkt und einem Licht.

UND EINMAL ZURUECKGENOMMEN, nach dem Blick aufs Bild: Die Sekunde bekam
zuerst denselben Schein wie die anderen beiden. Sie ist aber die
laengste Bahn, die hellste Farbe UND die einzige, die sich sichtbar
bewegt -- im Bildschirmfoto war sie ein roter Reifen, neben dem die
Uhrzeit selbst zurueckstand. Ihr Leuchten liegt jetzt eine Stufe
niedriger als das von Minute und Stunde. Gesehen, nicht gerechnet.

Kein Pulsieren: Die Uhr steht dauerhaft im Bild, ein animiertes Leuchten
am Bildrand ist genau das, was die Hausregel verbietet. Bei
`prefers-reduced-motion` entfaellt der Schein ganz -- die Bahnen bleiben
in voller Farbe stehen.

pruef-start-ansicht EXIT=0, 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 14:02:05 +02:00
DogFatherGitandClaude Opus 5 80dbb08eee Die Anmeldeseite bekommt die neuen Rollenzeichen -- sie war vergessen worden
Filipe hat es im Bildschirmfoto gesehen: Auf der Anmeldeseite standen
weiter die alten, einfarbigen Zeichen -- rosa Chili, GELBER Husky,
violetter Stern, Schild mit Haken, Person-Silhouette. Die neuen lagen zu
dem Zeitpunkt seit Stunden im Haus, nur eben ausschliesslich in
personen.html.

DER GRUND ist eine Doppelung, die man dem Code nicht ansieht: index.html
trug die Zeichen als EIGENE Kopien im Quelltext, nicht als Verweis auf
ein gemeinsames Sprite. Wer eines von beiden aendert, aendert das andere
nicht -- und merkt es nicht, weil beide Stellen fuer sich richtig
aussehen. Dieselbe Sorte Fehler wie die doppelte Groessenangabe beim
Wasserzeichen heute frueh, nur ueber zwei Dateien verteilt statt ueber
3600 Zeilen.

Gefunden hat es kein Prueflauf, sondern Filipes Blick auf die Seite. Das
ist der Grund, warum ein Bildschirmfoto mehr wert ist als eine gruene
Zahl: Die Pruefungen sagten die ganze Zeit "in Ordnung" -- sie pruefen,
dass Zeichen DA sind, nicht welche.

Jetzt traegt index.html dasselbe Sprite (aus personen.html uebernommen,
nicht abgeschrieben) und verweist mit <use> darauf. Die Zeichen gibt es
damit nur noch einmal im Haus.

DAS CSS MUSSTE MIT: Wie bei `.rollenwahl__symbol` setzte
`.rolle__zeichen` ein `fill: none` und ein `stroke` in der Rollenfarbe.
Beides wird an die Pfade vererbt -- jedes Zeichen waere von einem 1,7 px
dicken Rand ueberzogen und seine Verlaeufe uebermalt worden. Die
gewaehlte Rolle hebt sich jetzt ueber Groesse und Schein ab statt ueber
die Farbe: Die gehoert dem Zeichen.

Nachgemessen: 5 von 5 Zeichen kommen aus dem Sprite. pruef-rollen
EXIT=0 (97), pruef-start-ansicht EXIT=0 (140).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:56:36 +02:00
DogFatherGitandClaude Opus 5 bcfe0b93f9 Die Fugen im Kalender werden dunkel statt hell
Filipe, screen18: "die linien zwischen den kacheln und der rand die so
kras durchsichtig sind, ich will dass dass die viel dunkler sind und die
kacheln vom kalender selber sollen viel krasser und geiler aussehen."

WOHER DIE LINIEN KOMMEN, und das erklaert den Fehler: Sie sind gar nicht
gezeichnet. Das Raster hat `gap: 1px` und darunter eine Flaeche -- in den
Luecken zwischen den Tagen scheint diese Flaeche durch, DAS sind die
Linien. Sie trugen `var(--rand)`, einen hellen halbdurchsichtigen Ton,
der fuer Raender AUF dunklem Grund gedacht ist. Zwischen zwei ohnehin
dunklen Kacheln wirkt derselbe Ton wie ein heller Schleier -- genau das,
was Filipe "kras durchsichtig" nennt.

Jetzt ein eigener tiefer Ton (#05070c): Die Fuge ist DUNKLER als die
Kacheln daneben, nicht heller. Damit sieht sie eingefraest aus statt
aufgemalt -- dieselbe Ueberlegung wie bei den Fasen auf der Startseite.
Der aeussere Rand bekommt eine feine helle Innenkante, sonst verlaeuft
der Kalender am Rand ins Nichts.

DIE TAGE BEKOMMEN TIEFE: ein leichter Verlauf von oben nach unten und
ein Lichtsaum an der Oberkante -- Licht kommt von oben, also ist die
Oberkante hell und die Flaeche faellt ab.

BEWUSST SCHWACH (der Verlauf umfasst rund vier Prozent Helligkeit): Ein
Monatsraster hat 35 bis 42 dieser Felder nebeneinander. Was bei einer
einzelnen Kachel wirkt, wird hier vierzigfach zu Unruhe. Wochenende und
fremde Monate bleiben ruhiger und heben sich ueber WENIGER LICHT ab,
nicht ueber eine andere Farbe.

Nachgemessen am laufenden Kalender: Fugenfarbe rgb(5, 7, 12), 35 Tage im
Raster. pruef-kalender EXIT=0, 84 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:49:19 +02:00
DogFatherGitandClaude Opus 5 e282ad3b44 Der Anmelde-Knopf traegt beide Marken -- und wurde erst durch Nachrechnen lesbar
Filipe, screen28: "dieser anmelde button soll noch viel spezieller sein
bitte. und viel geiler."

NUR DIESER EINE KNOPF. Er traegt die Klasse `.knopf`, die im Workspace an
Dutzenden Stellen haengt -- wer sie aendert, aendert jeden Knopf im Haus.
Die Regel greift deshalb ueber `#knopf` und laesst alle anderen in Ruhe.

Der Verlauf laeuft vom Chili-Rot von Spicy Media in das Blau von Dogi --
dieselbe Klammer wie im Schriftzug der Kopfleiste, und hier besonders am
Platz: Dieser Knopf ist die Tuer ins Haus.

UND DANN HAT MICH DIE RECHNUNG WIDERLEGT. Der erste Entwurf nahm die
Marken-Toene direkt (#d94a3f bis #7ec8f2). Er sah gut aus -- genau das
ist die Falle. Nachgerechnet lag weisser Text darauf bei:

  #d94a3f  4,20:1     #6ca8d8  2,55:1
  #e2664a  3,37:1     #7ec8f2  1,84:1

Auf dem hellsten Punkt also nicht einmal beim halben Mindestwert. Ich
hatte im Kommentar daneben "ueber 4,5:1 an jeder Stelle" behauptet, ohne
es nachzurechnen. Der Knopf waere schoen und unlesbar gewesen.

Jeder Stuetzpunkt ist jetzt so weit abgedunkelt, bis weisser Text 4,6:1
erreicht -- knapp ueber der Grenze, damit Rundungen nicht darunter
rutschen. Die Farben bleiben erkennbar Rot und Blau, sie sind nur tiefer.
Schlechtester Wert jetzt 4,63:1.

MERKSATZ, der auch fuer jeden naechsten Verlauf gilt: Ein Verlauf ist so
lesbar wie sein HELLSTER Punkt, nicht wie sein Durchschnitt. Beim
Textverlauf in der Kopfleiste war es dieselbe Regel mit umgekehrtem
Vorzeichen -- dort zaehlt der dunkelste.

Der Glanz wandert beim Ueberfahren statt zu pulsieren (wie Manager-Stern
und Kalender-Knopf), bei `prefers-reduced-motion` entfaellt er. Waehrend
der Anmeldung wird der Knopf ruhig gestellt, damit der Ladepunkt die
Aufmerksamkeit bekommt und nicht der Glanz.

pruef-start-ansicht EXIT=0 (140), pruef-css-klassen EXIT=0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:19:47 +02:00
DogFatherGitandClaude Opus 5 c262537b89 Der eigene Name leuchtet in der eigenen Rollenfarbe
Filipe, screen35: "die begrüßungen sollen auch viel krasser und geiler
sein, so richtig auffällig. so dass die leute motivation bekommen weil es
so geil aussieht."

NICHT UEBER DIE GROESSE, und das ist der Kern. Genau die habe ich heute
frueh von 88 auf 56 px zurueckgenommen: In der Anrede-Pille steckt ein
<h1> mit Titelgroesse, dadurch standen ZWEI Ueberschriften uebereinander.
Sie jetzt wieder aufzublasen hiesse, denselben Fehler ein zweites Mal zu
machen. "Auffaellig" heisst ohnehin nicht "gross", sondern "hebt sich ab".

Der Name hebt sich ueber die FARBE ab: Er traegt einen Verlauf in
`--r-haupt`, der Farbe der angemeldeten Rolle. Jeder sieht damit seinen
eigenen Namen in seiner eigenen Farbe -- nachgemessen: DogFather #7ec8f2
(babyblau), Scout #5fc99a (gruen), Creator #c79a6d (bronze). Das ist der
Unterschied zwischen "da steht mein Name" und "das hier ist meins".

Der Gruss davor bleibt bewusst leise und farblos. Wenn beides leuchtet,
leuchtet nichts -- die Betonung gehoert dem Namen, nicht der Uhrzeit.

Mit derselben Sicherung wie beim Schriftzug in der Kopfleiste: `color`
steht zuerst und sichtbar da, Verlauf und durchsichtige Fuellung stehen
nur im @supports-Block, und bei `forced-colors: active` wird alles
zurueckgenommen. Durchsichtige Schrift ohne Rueckfallwert waere ein
Ausfall, kein Schoenheitsfehler.

Das Leuchten liegt als `drop-shadow` HINTER der Schrift -- es gibt dem
Namen Tiefe, ohne ihn zu vergroessern.

pruef-start-ansicht EXIT=0, 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:16:10 +02:00
DogFatherGitandClaude Opus 5 8b317b23e2 Der Weg in den Kalender ist ein Knopf, kein Nebensatz
Filipe, screen33: "der kalender button da in der kachel oben rechts, der
soll viel auffälliger sein und viel krasser und geiler."

Er sah aus wie ein Verweis im Fliesstext -- kleine Schrift, kein Rahmen,
keine Flaeche. Neben der fetten Ueberschrift "Heute" verschwand er,
obwohl er die einzige Handlung in dieser Zeile ist.

  vorher   Text in .78rem, ohne Fassung, rund 70x18 px
  jetzt    105x36 px, eigene Flaeche, farbiger Rahmen, Schimmer

ER TRAEGT DEN KALENDER-TON, nicht das allgemeine Blau. Der Knopf fuehrt
in den Kalender, und die Kachel dort hat genau diese Farbe (Nummer 8,
#c06ad0). Wer ihn sieht, weiss ohne zu lesen, wo er landet -- das ist
mehr wert als jede zusaetzliche Verzierung.

Beim Ueberfahren wandert ein heller Streifen darueber. Derselbe Kniff wie
beim Manager-Stern und aus demselben Grund: Glanz ist etwas, das sich
BEWEGT -- ein Auf- und Abblenden waere ein Pulsieren. Der Streifen liegt
in einem eigenen Element, damit er den Text nicht mitfaerbt, und bei
`prefers-reduced-motion` entfaellt er. Der Knopf bleibt dann trotzdem
auffaellig, er glaenzt nur nicht.

`--f` wird mitgesetzt, damit der Schein beim Ueberfahren aus gate.css
aus derselben Farbe kommt statt aus der Vorgabe.

Nachgemessen am laufenden Browser: 105x36 px, Rahmen rgb(192,106,208) bei
48 % Deckkraft, Schrift 13,12 px / 650.
pruef-start-ansicht EXIT=0, 140 Pruefungen -- diesmal GELESEN, bevor
committet wurde, nicht in derselben Befehlskette daneben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:10:16 +02:00
DogFatherGitandClaude Opus 5 80f410f5b8 Deckkraft des Wasserzeichens zurueckgenommen -- die Pruefung hatte recht
NACHTRAG ZU b808e07, und der eigentliche Fehler war meiner: Ich habe die
Pruefung laufen lassen, EXIT=1 gesehen -- und trotzdem committet und
gepusht, weil Pruefung, Commit und Push in EINER Befehlskette standen
und nur durch `;` getrennt waren. Damit lag ein roter Stand in Gitea.

Genau davor warnt meine eigene Notiz seit dem 31.08.2026, dort ging es um
`| tail` in einer &&-Kette: Ein Schritt scheitert, der naechste laeuft
trotzdem, und von aussen sieht alles nach Erfolg aus. Die Lehre gilt
unveraendert -- ein Pruefergebnis muss GELESEN werden, bevor der naechste
Schritt startet, nicht daneben.

INHALTLICH hatte die Pruefung recht und ich nicht. Ich hatte die
Deckkraft von .14 auf .17 gehoben, mit der Begruendung, dieselbe
Deckkraft wirke auf grosser Flaeche blasser. Die Grenze von .15 in
pruef-start-ansicht steht aber aus einem Grund da: Ein Wasserzeichen soll
Hintergrund bleiben und nicht mit dem Text um Aufmerksamkeit ringen.

Filipe wollte das Zeichen GROESSER, nicht LAUTER. Groesser ist es
geblieben -- 63 % mehr sichtbare Flaeche, das war der Auftrag. Die
Lautstaerke war nie gefragt und geht zurueck auf .14.

pruef-start-ansicht EXIT=0, 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 13:01:02 +02:00
DogFatherGitandClaude Opus 5 b808e072c0 Das Zeichen der grossen Kachel wird groesser -- und eine zweite Regel fiel auf
Filipe, screen34: "das symbol rechts in der kachel, was so ganz klein ist
das soll viel größer sein bitte!!!"

Nachgemessen war es gar nicht klein: 178 px gegen 133 px bei den normalen
Kacheln, also GROESSER. Es wirkt nur klein, und das ist der eigentliche
Punkt -- die grosse Kachel ist 769 px breit (ueber die volle Reihe rund
1160), die normale 379. Dasselbe Zeichen hat dort doppelt so viel leere
Flaeche um sich und verliert sich darin. Ein Zeichen wirkt nach dem
Anteil der Flaeche, den es fuellt, nicht nach seiner Pixelzahl.

DABEI KAM EINE ZWEITE REGEL ANS LICHT. Fuer dasselbe Element stand die
Groesse an ZWEI Stellen in start.css -- einmal bei den Kachelregeln
(196 px) und 3600 Zeilen spaeter noch einmal (158 px). Gleich starke
Selektoren, also gewinnt der spaetere. Meine erste Vergroesserung blieb
deshalb wirkungslos: gemessen weiterhin 178 px, obwohl im Quelltext 340
stand. Im Code sieht jede der beiden Regeln fuer sich richtig aus; erst
die Zahl am laufenden Browser verraet, dass eine nie zur Wirkung kommt.
Dieselbe Sorte Fehler wie bei `.kopfleiste .marke`, wo `flex` den
Schrumpf-Faktor still zurueckgesetzt hat. Die Groesse steht jetzt nur
noch an einer Stelle.

UND EINMAL ZU WEIT. Der erste Versuch koppelte die Groesse an die
BREITE: `min(46%, 340px)` ergab 384 px auf einer 152 px hohen Kachel.
Im Bildschirmfoto war daraufhin GAR NICHTS mehr zu sehen -- was die
Kachel nicht fasst, schneidet sie ab. Groesser ist hier nicht
automatisch besser. Jetzt an der Hoehe ausgerichtet: 220 px, unten und
rechts angeschnitten, der Grossteil im Bild.

Gemessen wird seitdem die SICHTBARE Flaeche, nicht die Elementgroesse --
das ist die Zahl, auf die es ankommt:
  vorher  rund 158x122 = 19k
  jetzt   204x152      = 31k   (+63 %)

pruef-start-ansicht EXIT=0, 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 12:59:33 +02:00
DogFatherGitandClaude Opus 5 1f7761cb69 Die Kopfleiste glueht, die Knoepfe werden rot -- und DogFather sagt, was er tut
Drei Punkte aus der Nachtliste auf einmal, weil sie alle an derselben
Leiste haengen.

screen36: "hintergrund dieser leiste soll auch eine richtig geile
mischung von rot schwarz sein, wie wenn es brennen würde."

GLUT KOMMT VON UNTEN. Ein gleichmaessig roter Balken saehe aus wie eine
Fehlermeldung. Feuer ist unten heiss und oben dunkel -- also liegt das
Rot als flacher Schein an der Unterkante, wird nach oben schwarz und ist
an den Raendern schwaecher als in der Mitte. Zwei uebereinanderliegende
Verlaeufe machen das: einer fuer die Hoehe, einer fuer die Breite. Die
Trennlinie nach unten glueht mit, sonst endet das Feuer an einer grauen
Linie.

Kein Flackern, und das ist Absicht: Diese Leiste steht auf JEDER Seite
und liegt beim Lesen dauernd im Bild. Eine Animation waere ein
Stroboskop am oberen Bildrand. Das Rot bleibt deshalb unter 30 %
Deckkraft -- es glimmt, es leuchtet nicht.

screen5: "die buttons: teilen, suchen und abmelden sollen rot, alle
andere rot töne aber rot."

Vier Knoepfe, vier verschiedene Rottoene -- "alle andere rot töne"
heisst nicht viermal derselbe. Sie laufen von warm nach tief: Teilen im
Chili-Rot der Marke, Chat ruhiger, Suchen glutorange, Abmelden am
dunkelsten. Das ist auch die Reihenfolge, in der man sie braucht, und
Abmelden soll am wenigsten locken.

Gesetzt wird nur `--f`, die Knopffarbe aus gate.css -- sie faerbt
Rahmen, Schimmer und den Schein beim Ueberfahren gleich mit. Fuenf
Eigenschaften je Knopf zu setzen waere vier Gelegenheiten gewesen, eine
zu vergessen.

GERECHNET STATT GEMESSEN: Ein roter Text auf rotem Grund waere der
naheliegende Fehler. Der Text nimmt deshalb nur 22 % der Knopffarbe an
und bleibt sonst hell. Nachgerechnet gegen die HELLSTE Stelle der Glut
(dort ist der Kontrast am schlechtesten): 10,45:1 im schlechtesten Fall,
Grenze ist 4,5. Dafuer braucht es keinen 190-Sekunden-Lauf.

screen27: Unter DogFather steht jetzt "Manager & Technik" statt
"Gesamtuebersicht & Freigaben". Die alte Zeile beschrieb ein RECHT, die
neue eine AUFGABE -- und danach sucht jemand, der vor der Rollenwahl
steht: Er fragt sich nicht, was er duerfte, sondern was er hier tut.

pruef-start-ansicht EXIT=0 (140), pruef-css-klassen EXIT=0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 12:54:13 +02:00
DogFatherGitandClaude Opus 5 f42f9a7266 21 Kachelfarben neu gerechnet -- keine zwei aehneln sich mehr
Filipe, screen24/25: "viele kacheln haben noch fast die gleiche farben,
ähneln sich sehr und ich will dass du komplett eskalierst ... alle seine
eigenen farben und so dass sie sich nicht ähneln. sehr wichtig nicht
ähneln!!!!"

Er hatte recht, und es liess sich messen statt bereden:

  kleinster Abstand zweier Toene   0,033   (Dateien gegen Creator-Profile)
  Paare unter 0,05 (kaum trennbar)  21 von 210
  Spanne der Helligkeit             0,002

DIE URSACHE WAR EINE GUTE ABSICHT. Die alte Palette lief gleichmaessig
um EINEN Farbring, mit bewusst konstanter Helligkeit und Farbstaerke --
"dadurch wirken alle gleich stark und keine draengt sich vor". Genau das
erzeugt den Fehler: Bleibt alles ausser dem Farbton gleich, ist der
Farbton der einzige Unterschied. 360 Grad auf 21 Kacheln sind 17 Grad,
und 17 Grad sieht man nicht.

Jetzt variieren Helligkeit UND Farbstaerke mit. Zwei Farben mit
aehnlichem Ton stehen trotzdem weit auseinander, weil die eine hell und
satt und die andere dunkel und ruhig ist -- der Abstand bekommt eine
zweite und dritte Dimension.

  kleinster Abstand   0,097   (dreimal so gross)
  Paare unter 0,05    0 von 210
  Helligkeitsspanne   0,242

Gerechnet in OKLab, weil dort der Zahlenabstand dem entspricht, was das
Auge als Unterschied empfindet. Die Auswahl ist eine Suche, kein
Geschmack: erst gierig den jeweils entferntesten Ton nehmen, dann so
lange tauschen, wie der KLEINSTE Abstand dadurch waechst.

Drei Bedingungen halten dabei, und alle drei stehen im Werkzeug als
Abbruch, nicht nur im Bericht:
  lesbar         mindestens 4,5:1 gegen den Grund (schlechteste: 4,50)
  augenschonend  Farbstaerke gedeckelt bei 0,17 -- satt ja, Neon nein
  trennbar       gemessen ueber ALLE Paare, nicht nur ueber Nachbarn im
                 Raster: Auf der Uebersicht stehen dieselben Kacheln in
                 anderer Reihenfolge nebeneinander.

Das Werkzeug bricht ab, wenn eine neue Palette schlechter waere als der
alte Stand (0,0328) -- sonst waere ein schlechter Lauf von einem guten
nicht zu unterscheiden.

pruef-start-ansicht EXIT=0, 140 Pruefungen. Die Farben zusaetzlich am
laufenden Browser abgelesen, nicht nur aus der Datei.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 12:06:30 +02:00
DogFatherGitandClaude Opus 5 df0e74f751 Bearbeiten zeigt jetzt, was schon eingetragen war -- und loescht es nicht mehr
Filipe, screen19: "wenn ich auf bearbeiten drücke will ich dass mir immer
die daten angezeigt werden die schon ausgewählt wurden, damit ich auch
immer sehe okee das war alles und das änder ich."

Das war nicht nur unbequem, es war ein DATENVERLUST. Das Feld "Mit wem"
wurde beim Bearbeiten nie gefuellt und stand leer da. Beim Speichern wird
`teilnehmer_extern` aber trotzdem mitgeschickt -- der leere Wert
ueberschrieb also den vorhandenen. Wer einen Termin mit einem frei
eingetragenen Namen ("BananaStift") bearbeitete und speicherte, hatte den
Namen danach verloren, ohne ihn je gesehen zu haben. Nichts stuerzte ab,
nichts meldete sich; er war einfach weg.

DIE URSACHE lag tiefer als im Kalender: `window.personenwahl` konnte
lesen (`wert`, `extern`) und leeren (`zuruecksetzen`), aber NICHT
fuellen. Ein Bearbeiten-Formular hatte gar keine Moeglichkeit, einen
freien Namen anzuzeigen. Deshalb kommt die Reparatur in zwei Teilen:

  wahl.js      neue Funktion `setzen(wert, externText)`. Sie behandelt
               die beiden Faelle als das, was sie sind: entweder eine
               Person aus der Liste ODER ein freier Name -- nie beides.
               Das eine setzt das andere zurueck.

  kalender.js  belegt das Gegenueber beim Bearbeiten vor, aus
               creator_id / teilnehmer_id / teilnehmer_extern. Nur fuer
               die Leitung, wie beim Speichern auch -- fuer die anderen
               Rollen gibt es das Feld gar nicht.

Der Server lieferte die noetigen Felder die ganze Zeit mit
(t.teilnehmer_extern, t.creator_id, t.teilnehmer_id) -- es hat sie nur
niemand abgeholt.

Nachgemessen: `personenwahl('f-teilnehmer').setzen('', 'BananaStift')`
ergibt extern="BananaStift", wert="" -- der freie Name steht im Feld,
die Personennummer ist leer. pruef-kalender EXIT=0 (84),
pruef-serien EXIT=0 (69).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 11:54:39 +02:00
DogFatherGitandClaude Opus 5 29785cc2a4 Abgebrochene Aufgaben mahnen nicht mehr -- an zwoelf Stellen, nicht an einer
Filipe, screen12: "die abgebrochenen sollen oben nicht mehr mit zaehlen
die sollen ihre eigenen kategorie kriegen".

DIE URSACHE war eine Bedingung, die harmlos aussieht: `a.status <>
'erledigt'`. Eine abgebrochene Aufgabe ist nicht "erledigt" -- also fiel
sie durch, und zwar in JEDE Zahl, die "noch zu tun" bedeutet. Eine
Aufgabe, die niemand mehr anfassen wird, mahnte weiter als ueberfaellig.

Das ist die Kehrseite einer bewussten Entscheidung: "abgebrochen" steht
absichtlich NICHT in STATUS, damit der normale Weg es nicht setzen kann.
Genau deshalb rutscht es aber durch jede Pruefung, die nur gegen
'erledigt' vergleicht.

FILIPE HAT EINE STELLE GESEHEN. Gesucht werden musste nach dem MUSTER:
Es waren zwoelf, in sieben Dateien.

  workspace-aufgaben.js   2   ueberfaellig und heute (die Zahlen "oben")
  workspace-hinweise.js   2   die Hinweiszeilen der Startseite
  workspace-kalender.js   1   Aufgaben mit Frist im Kalender
  workspace-personen.js   1   "offene_aufgaben" je Person
  workspace-profil.js     1   dieselbe Zahl im Profil
  workspace-push.js       2   ERINNERUNGEN, die verschickt werden
  workspace-reports.js    3   Berichte

Am schwersten wiegt workspace-push.js: Dort gingen Push-Nachrichten
hinaus -- fuer Aufgaben, die laengst abgebrochen waren.

`NOT IN ('erledigt', 'abgebrochen')` statt einer zweiten Ungleichung: Wer
spaeter einen dritten Endzustand einfuehrt, ergaenzt eine Liste, statt
eine Kette von `<>` zu verlaengern, bei der das Vergessen niemandem
auffaellt.

DIE EIGENE KATEGORIE, die Filipe verlangt hat, gibt es jetzt in der
Schnittstelle (`abgebrochen`) und auf der Startseite -- hinten bei
"Erledigt", weil beides dasselbe bedeutet: vom Tisch.

GEGENPROBE an einer abgebrochenen Aufgabe mit Frist von gestern:
  alte Bedingung  "<> erledigt"            -> ueberfaellig = 3
  neue Bedingung  "NOT IN (erledigt, abg)" -> ueberfaellig = 2
  Unterschied 1 = genau die abgebrochene. Die Schnittstelle liefert 2
  und abgebrochen = 1.

pruef-start-ansicht hat den Umbau bemerkt und "die Aufgabenzahlen stehen
(7)" gemeldet -- sie zaehlt die Kategorien und erwartete sechs. Die Zahl
steht in der Bedingung, nicht nur im Meldetext; deshalb faellt eine
Kategorie, die still verschwindet, sofort auf. Auf 7 nachgezogen:
EXIT=0, 140 Pruefungen. pruef-aufgabenbrett EXIT=0, 44.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 11:27:08 +02:00
DogFatherGitandClaude Opus 5 5925a61dfe Chat, Kalender, Calls -- die Reihenfolge nach Verbindlichkeit
Filipe, screen31: "die reihenfolge von denen, links der chat, mitte den
kalender und rechts calls & protokolle".

Vorher stand der Chat hinter "Calls & Protokolle", begruendet damit, dass
beides Gespraech sei. Die neue Ordnung liest sich von links nach rechts
nach Verbindlichkeit: Der Chat laeuft nebenher, der Kalender bindet an
eine Uhrzeit, das Protokoll haelt fest, was verabredet wurde.

Die Farbtoene bleiben an ihren Kacheln (Chat 4, Kalender 8, Calls 15).
Sie kennzeichnen die Kachel, nicht ihren Platz -- wer sie beim
Umsortieren mitwandern liesse, haette zwei Kacheln in derselben Farbe.

Nachgemessen am laufenden System: 0 Dashboard, 1 Aufgaben, 2 Chat,
3 Kalender, 4 Calls & Protokolle, 5 Dateien.
pruef-start-ansicht EXIT=0, weiterhin 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 05:25:23 +02:00
DogFatherGitandClaude Opus 5 e3f7826ca5 Jede Rolle sieht ihre eigene Zahl -- Schulle zaehlte das ganze Haus
Filipe (screen22), nachdem Managerin Schulle "2 Creator" angezeigt bekam,
obwohl sie einen hat: "die zahl die da angezeigt wird soll bitte immer
jedem genau zutreffend sein." Und dazu (screen23), wer was sehen soll:

  "dogfather und cigdem haben die zahl vom insgesamten. manager sehen nur
   die gesamte zahl ihrer scouts und ihren creator die ihnen zugeteilt
   sind, die scout sehen die zahl nur von ihren creator und die creator
   da termine vom tag selber"

DIE ZAHL WAR NICHT FALSCH GERECHNET, SIE BEANTWORTETE DIE FALSCHE FRAGE.
Hier stand `SELECT ... FROM personen WHERE aktiv = 1` -- alle, fuer jeden
aus der Leitung gleich. Ein Manager sah damit das ganze Haus als "sein
Team", einschliesslich Leuten, mit denen er nichts zu tun hat.

Jetzt je Rolle:
  admin/spicy  alle aktiven Personen, ohne sich selbst
  manager      seine Scouts UND die Creator (eigene wie die der Scouts)
  scout        nur seine Creator
  creator      unveraendert der eigene Tag

SCOUTS BEKOMMEN DIESEN RING NEU. Sie zaehlen nicht zur Leitung und sahen
deshalb den Stundenring des eigenen Tages -- aber ein Scout hat ein Team,
naemlich seine Creator. Genau danach hat Filipe gefragt. Der Ring heisst
bei ihm "Creator versorgt" statt "Team versorgt": Sonst liest ein Scout
"Team" und sucht die anderen vier Rollen darin.

OHNE SICH SELBST: Wer den Ring ansieht, ist die Person, die ihn liest.
Sich selbst als Segment im eigenen Team mitzuzaehlen verschiebt jede
Prozentangabe um einen Platz.

KEINE ZWEITE RECHENVORSCHRIFT. Die Zuordnung wird nicht hier nachgebaut:
`betreuteIds` kennt die Kette Manager -> Scouts -> deren Creator bereits,
`scoutsVon` die Scouts. Eine eigene Fassung derselben Frage waere genau
der Weg, auf dem zwei Wahrheiten entstehen.

Dazu screen26: "liegt liegen, keine ahnung was das bedeuten soll aber das
soll viel besser sein bitte." Gezaehlt werden Personen mit unerledigten
Terminen aus der VERGANGENHEIT -- das Schild heisst jetzt "ueberfaellig".

GEMESSEN an einer Lage, die den Fehler enthaelt: fuenf aktive Personen,
darunter ein Creator, der zu niemandem gehoert.
  DogFather        4 im Team        [Fremder, Tili, Schulle, Patrick]
  Manager Schulle  2 im Team        [Tili, Patrick]   <- ohne "Fremder"
  Scout Patrick    1 meine Creator  [Tili]
  Creator Tili     eigener Tag
pruef-start-ansicht EXIT=0 (140), pruef-rollen EXIT=0 (97).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 05:23:30 +02:00
DogFatherGitandClaude Opus 5 ff8ea38595 Die Kopfleiste wird zur Klammer: Chili links, Husky rechts, Spicy & Dogi
Filipe (Nachtliste, screen17): "wo der husky ist soll eine geile rot
gruene peperoni sein, dogfather universe ersetzen durch, Spicy & Dogi.
und der husky von links soll rechts sein. die farben von der peperoni und
von dem husky sollen ueber den text ziehen und sich dan in der mitte
treffen." Dazu screen9: die Zierzeile der Zentrale heisst jetzt
"Spicy Media" statt "Dogfather Universe".

Die Chili steht als BILD (sie ist von sich aus rot mit gruenem Stiel und
soll ihre Farben behalten), der Husky als MASKE (schwarzweiss gezeichnet
waere er auf dunklem Grund ein dunkler Fleck; von der Maske zaehlt nur
die Silhouette, gefuellt mit Silber und Babyblau). Dazwischen laeuft der
Schriftzug von Chili-Rot ueber Silber nach Babyblau -- Treffpunkt in der
Mitte, genau beim "&".

DER VERLAUF IM TEXT IST EINE AUSNAHME MIT SICHERUNG. Direkt darueber
steht seit dem 01.09. "KEIN Farbverlauf IM Text", und der Grund gilt
weiter: Durchsichtige Schrift haengt an einer einzigen Technik, und
faellt die aus, ist der Text WEG statt nur anders gefaerbt (gemessen
damals 1,05:1). Beides geht zusammen, wenn der Verlauf nur eine Zugabe
ist: `color` steht zuerst und voll sichtbar da, Verlauf und
durchsichtige Fuellung stehen NUR in einem @supports-Block (wer es nicht
kann, betritt ihn nicht), und bei `forced-colors: active` wird alles
zurueckgenommen. Die drei Stuetzstellen sind bewusst hell -- beim
Verlauf bestimmt der dunkelste Punkt den schlechtesten Kontrast.

EIN SELEKTOR, DER RICHTIG AUSSAH UND FALSCH WAR. Der Husky sollte nur
auf die Startseite; `body.start` davorzusetzen wirkte naheliegend. Diese
Klasse tragen aber ALLE 18 Seiten -- sie kennzeichnet den Grundstil,
nicht die Startseite. Folge auf den Unterseiten, wo `.marke` den Rueckweg
traegt: Die 22 px des Huskys nahmen dem Text so viel Platz, dass
"Creator Workspace" zu "CREAT…" wurde. Gesehen im Bildschirmfoto, nicht
im Code. Jetzt steht die Regel in heim.css, das ausschliesslich von der
Startseite geladen wird -- die Datei selbst ist die Bedingung.

Nachgemessen dabei, damit es nicht faelschlich mir zugeschrieben wird:
Der Schriftzug auf den Unterseiten ist AUCH IM ALTEN STAND abgeschnitten
(151 px Inhalt auf 91 px Platz). Das ist ein vorbestehender Mangel und
steht auf der offenen Liste, kein Rueckschritt aus diesem Commit.

pruef-start-ansicht angepasst: Sie prueft den Namen im Schriftzug und
erwartete "Dogfather Universe" -- sie hat ihre Arbeit getan und
angeschlagen. EXIT=0, weiterhin 140 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 04:37:51 +02:00
DogFatherGitandClaude Opus 5 963ea492b1 Die fuenf Rollen bekommen eigene Farben und echte Zeichen
Auftrag von Filipe (Nachtliste, screen3): "die farben sollen jeden rollen
angepasst werden ueber die ganze website ... diese farben sollen auch
immer danach bei den rollen benutzt werden", dazu die Zeichen "viel viel
viel realistischer und geiler".

DIE FARBEN STEHEN JETZT AN EINER STELLE. Vorher lagen dieselben Hex-Werte
ueber chat.css, personen.css, kalender.css, start.css und gate.css
verstreut -- 47 Fundstellen, allein in chat.css sechzehn. Wer eine Farbe
aendern wollte, musste sie ueberall finden; wer eine uebersah, hatte zwei
Wahrheiten auf einem Bildschirm. Sie stehen jetzt in gate.css, der
einzigen Datei, die auf allen 19 Seiten liegt, mit je drei Toenen
(haupt/zweit/tief) fuer Flaeche, Verlauf und Schatten.

  spicy    rot        #ef5f57  warmes Chili-Rot, kein Signalrot
  admin    babyblau   #7ec8f2  + Lila #a78bfa als zweiter Ton
  manager  lila       #8a76ff  bleibt
  scout    gruen      #5fc99a  bleibt
  creator  bronze     #c79a6d  + Silber #d8dee9 -- neu

Zwei davon waren inhaltlich falsch: `admin` stand auf Gold und `creator`
auf demselben Blau wie der allgemeine Akzent -- die Rolle war dadurch
nicht von "irgendein Bedienelement" zu unterscheiden. In der
Personenliste fehlten Spicy und Manager ganz, und Creator trug das Lila
des Managers: zwei Rollen sahen in derselben Liste gleich aus.

Umgeschaltet wird am <html> (kopf.js), nicht an einzelnen Bausteinen:
Wer die Farbe an jedem Element einzeln setzt, vergisst das naechste, das
dazukommt.

DIE ZEICHEN TRAGEN IHRE FARBEN SELBST. Vorher hatte jedes genau eine
Farbe (currentColor). "Peperoni rot UND gruen" oder "gruenes Schild mit
einer roten Peperoni drin" ist damit nicht darstellbar, egal wie man
mischt. Jedes Zeichen bringt jetzt eigene Verlaeufe mit: Chili rot mit
gruenem Stiel, Husky in Silber mit blauen Augen (Radialverlauf plus
Lichtpunkt -- ein flacher blauer Punkt sieht aus wie ein Loch), Stern in
Gold mit wanderndem Glanz, Schild gruen mit Chili darin, Creator als
geschliffener Kristall in Lila und Silber statt der alten
Person-Silhouette, die aussah wie ein leeres Benutzerbild.

Das Funkeln des Sterns laeuft ueber eine wandernde Maske, nicht ueber die
Deckkraft: Auf- und Abblenden waere ein Pulsieren, kein Glitzern. 4,5 s
und schwach, damit es in einer Liste aus fuenf Rollen nicht dauerhaft den
Blick zieht -- und bei `prefers-reduced-motion` steht es still.

ZWEI FEHLER, DIE NUR DAS HINSEHEN GEFUNDEN HAT:

1. `.rollenwahl__symbol` setzte `fill: none; stroke: var(--r)`. Beides
   wird an die Pfade VERERBT -- jedes neue Zeichen waere von einem
   1,55 px dicken Rand in der Rollenfarbe ueberzogen worden.

2. Das Sprite stand in einem <svg style="display:none">. Solange die
   Zeichen einfarbig waren, war das harmlos. Ein <linearGradient> in
   einem `display:none`-Teilbaum wird aber NICHT ausgewertet, und ein
   <use> darauf bekommt gar keine Fuellung: Im Bildschirmfoto standen
   fuenf Bruchstuecke -- nur Striche, keine Flaechen. Die Zahlen sagten
   dazu nichts, das Sprite war ja vorhanden. Jetzt ein Kasten ohne
   Groesse: wird gerendert, nimmt keinen Platz.

Gemessen: pruef-rollen 97 Pruefungen EXIT=0, pruef-personen-formular 23
EXIT=0, pruef-start-ansicht EXIT=0, pruef-css-klassen EXIT=0. Farb-
umschaltung am lebenden System nachgesehen: html[data-rolle]=admin ->
--r-haupt = #7ec8f2.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 04:30:12 +02:00
DogFatherGitandClaude Opus 5 863471c3df Die Mitte der Zentrale sitzt jetzt wirklich mittig -- zwei Ursachen, nicht eine
Filipe im Bildschirmfoto: "in der mitte der kachel soll auch alles perfekt
zentriert sein und nicht wie jetzt total verschoben." Gemessen waren es
zwei getrennte Fehler, die zufaellig in dieselbe Richtung zeigten.

ERSTENS: .willkommen__stand trug ein `margin-left: auto` -- ein Rest aus
der Zeit, als die drei Ablesungen RECHTS zwischen Text und Uhr standen.
In einer Flex-Spalte gewinnt ein auto-Rand immer gegen das
`align-items: center` des Elternteils. Bei 1920 px lagen Anrede,
Zierzeile, Titel und Unterzeile alle exakt auf Mitte 960 -- dieser Kasten
allein auf 1129, also 169 px daneben.

Aufgefallen war das schon einmal: In der Media-Query fuer 412 px stand
bereits `margin-left: 0`, mit dem Vermerk "im Bildschirmfoto gesehen,
nicht hergeleitet". Dort wurde das Symptom geflickt und die Ursache blieb
stehen -- auf dem grossen Bildschirm damit unbemerkt weiter. Jetzt ist
die Ursache weg und die Gegenzeile gleich mit: Eine Zeile, die nichts
mehr aufhebt, sieht aus wie Absicht und wird mitgeschleppt.

ZWEITENS, und ohne Messung nicht zu sehen: `.willkommen .unterzeile` ist
laut start.css ein FLEX-Kasten mit Umbruch, damit die Lage hinter der
Rolle stehen und auf dem Handy umbrechen kann. In einem Flex-Kasten
ordnet `text-align` die Elemente aber NICHT an -- es zentriert den Text
innerhalb jedes Elements, waehrend die Elemente selbst links kleben.
In der breiten alten Begruessung fiel das nie auf, weil beide in eine
Zeile passten; die Spalte der Zentrale ist 397 px schmal und bricht
immer um. Gemessen: Rollentext 39,7 px und Lage 58,6 px links der Achse,
auf jeder Fensterbreite gleich. Behoben mit `justify-content: center` --
`align-items` waere das falsche Werkzeug, die Richtung ist row mit
Umbruch, nicht column.

Dazu der Punkt der Lage: Er haengt in einem `padding-left: 14px`. Steht
die Lage in einer eigenen Zeile -- in dieser Spalte immer --, ist das
Element dadurch 14 px breiter als sein Text und sitzt 7 px rechts der
Mitte. Ein Ausgleich rechts macht es symmetrisch, nur hier und nicht in
start.css: nebeneinander waere ein rechter Rand ein zu grosser Abstand.

Gemessen ueber 1920/1440/1280/1100/800 px: alle sieben Elemente auf
Abweichung 0,0 px. Zusaetzlich auf 360/390/412/430 px: kein waagerechter
Ueberstand. pruef-start-ansicht EXIT=0, weiterhin 140 Pruefungen -- keine
ist dabei still verschwunden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 02:57:45 +02:00
DogFatherGitandClaude Opus 5 b2a0fb3a97 Die Zentrale bekommt die echten Marken -- und drei rote Pruefungen waren keine
Die drei Befunde in pruef-start-ansicht kamen NICHT vom Licht. Sie hingen
alle an einem boundingBox(), das einmal am Anfang ohne Vorrollen gemessen
wurde. Der Umbau zur Zentrale hatte die Begruessungskachel von 244 auf
404 px wachsen lassen, die zweite Kachel rutschte von y=971 auf y=1131,
ihre Mitte lag bei 1207 -- ausserhalb eines 1200 px hohen Fensters. Dorthin
faehrt kein Zeiger, also entstand kein Licht.

Verraten hat es die Mischung aus gruen und rot: "links" (30 % der Hoehe)
bestand, "rechts" (60 %) nicht. Eine Kachel, die nur zur Haelfte getroffen
wird, ist nicht kaputt -- sie haengt halb aus dem Bild.

Beides ist jetzt behoben, nicht nur eines:

  * Die Pruefung holt die Kachel ueber scrollIntoView({block:"center"})
    ins Bild und misst DANACH, vor jeder Benutzung. Passt sie trotzdem
    nicht ins Fenster, ist das ein harter Fehler statt einer stillen
    Fehlmessung.
  * Die Kachel selbst faellt von 404 auf 344 px. Groesster Posten war die
    Anrede-Pille mit 88 px: In ihr steckt <h1 class="titel">, und
    .willkommen .titel ist die grosse Seitenueberschrift -- es standen
    also zwei Ueberschriften in Titelgroesse uebereinander. Der Rang von
    #gruss aendert sich nicht, nur die Groesse.

Nebenbefund, den die Reparatur mit aufgedeckt hat: Die Randmessung stand
auf "nah 51 gegen fern 0". Diese 0 war kein Messwert, sondern der
Bildpunkt ausserhalb des Fensters. Jetzt "nah 43 gegen fern 7" -- dieselbe
Pruefung misst zum ersten Mal wirklich.

DIE MARKEN. marke-husky.webp war nie freigestellt (0,3 % durchsichtig,
alle vier Ecken Alpha 255) -- als Maske ergab das einen Kasten mit einem
Husky darin. Ersetzt durch das echte Original, damit repariert sich die
Kopfleiste ohne eine einzige geaenderte CSS-Zeile mit.

In der Mitte des Rings steht jetzt Spicy Media, nicht der Husky: Der Ring
zeigt DAS TEAM, ein Segment je Person. Der DogFather-Kopf in seiner Mitte
haette Filipe bildlich ins Zentrum seines eigenen Teams gesetzt.

Und davon nur die Chili: Das volle Siegel war bei 44 px unlesbarer Matsch.
Beim ersten Ausschneiden meldete das Werkzeug "60,8 % deckend, Ecken
0/0/0/0" -- klang tadellos und war ein schwarzes RECHTECK mit Chili darin.
Die Flutfuellung laeuft von aussen und kommt nie hinter den weissen Ring.
Gefunden hat das kein Kennwert, sondern das Hinsehen.

Gemessen: pruef-start-ansicht EXIT=0 (137 -> 140 Pruefungen, die drei
roten sind gruen, keine ist verschwunden), pruef-css-klassen EXIT=0
(472 Groessen), pruef-handy EXIT=0.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 02:39:32 +02:00
DogFatherGit ec55b6c8d3 WIP Zentrale-Kachel nach VanVans Werktisch — NOCH NICHT FERTIG
Aufbau steht (Ring links, Titel mittig, Uhr rechts), aber
pruef-start-ansicht meldet 3 Befunde am MAUS-LICHT der Kacheln.
Gemessen: alter Stand 0 Befunde, dieser Stand 3 — kommt also von hier.
Kein JS-Fehler (pageerror/console sind still), also Zeitverhalten:
Die zusaetzliche Abfrage /api/zentrale verzoegert vermutlich den Aufbau
der Kacheln ueber den Zeitpunkt hinaus, an dem kopf.js lichtFolgen ruft.

Ausserdem offen: 2 Schriftgroessen unter 11,5 px (pruef-css-klassen).

NICHT ausliefern.
2026-09-08 01:44:36 +02:00
DogFatherGitandClaude Opus 5 0e522181e2 Pruefungen: der Rueckgabewert 127, der "in Ordnung" meldete
pruef-call-kategorien gab dreimal von dreimal 127 zurueck -- NACH der
Zeile "ALLES IN ORDNUNG". Ursache ist eine libuv-Assertion auf Windows:

  Assertion failed: !(handle->flags & UV_HANDLE_CLOSING),
  file src\win\async.c, line 94

`process.exit()` schlaegt zu, waehrend Playwright seinen Transportkanal
noch abbaut. Das Ergebnis stimmte, der Rueckgabewert log. In einem
Sammellauf zaehlt so ein Lauf als Fehlschlag, obwohl nichts fehlschlug --
und wer sich angewoehnt, den Rueckgabewert dieser einen Datei zu
ignorieren, uebersieht spaeter den echten.

Meine Notiz sagte "sporadisch". Es war drei von drei. Auch eigene
Notizen altern.

MEIN ERSTER FIX WAR DIE ELEGANTERE LOESUNG UND DIE SCHLECHTERE.

Ich wollte keine feste Pause -- 400 ms sind eine Rechnung auf DIESEM
Rechner, und auf einem langsameren waere der Fehler still
zurueckgekommen. Also: auf das Ereignis "disconnected" warten, danach
zwoelf Runden der Ereignisschleife (setImmediate). Sauber begruendet.
Gemessen: ZWEI VON DREI Laeufen weiterhin 127. Die feste Pause, die ich
fuer schlechter hielt, war zweimal gruen.

Die Annahme war falsch: "disconnected" meldet, dass die Verbindung weg
ist, nicht dass der Kanal abgebaut ist -- und setImmediate gibt der
Schleife Durchlaeufe, aber keine ZEIT. Der Kindprozess braucht echte
Millisekunden. Eine stimmige Herleitung ersetzt keine Messung.

Jetzt beides: erst das Ereignis (richtige Ordnung), dann eine zeitliche
Reserve von 600 ms gegen gemessene 400, ueber PRUEF_ABBAU_MS
einstellbar. Fuenf Laeufe hintereinander gruen.

Neu: server/helfer-beenden.mjs (sauberBeenden) und
tools/mess-rueckgabewerte.sh -- letzteres misst alle 42 Browser-
Pruefungen mit demselben Muster daraufhin, ob noch weitere "in Ordnung"
melden und trotzdem einen Fehlercode zurueckgeben. Laeuft nacheinander,
nicht parallel: Zwei gleichzeitige Prueflaeufe sind kein Prueflauf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 01:14:57 +02:00
DogFatherGitandClaude Opus 5 a9f3212da3 Startseite: die tote Mitte der Konsole bekommt drei Ablesungen
Gemessen, nicht geschaetzt: Auf 1440 px lagen zwischen dem Ende des
Textes und der Uhr rund 300 px Leere. Dort stehen jetzt HEUTE (Termine),
ALS NAECHSTES (Uhrzeit) und OFFEN (Punkte, Farbe nach Lage).

Keine zweite Zaehlung: Die Zahlen kommen aus denselben zwei Quellen, die
die Kacheln darunter fuellen. Zwei Rechenwege fuer dieselbe Zahl laufen
auseinander, und dann stehen zwei Wahrheiten auf einem Bildschirm.

EINE Fassung mit Stegen, nicht drei Kaestchen. Der erste Anlauf gab jedem
Wert eine eigene Fraesung -- im Bild sah das aus wie aufgeklebte
Plaettchen. Ein Instrumentenblock ist EIN eingelassenes Feld, in dem
Stege trennen; das Licht laeuft dann einmal ueber eine Kante statt
sechsmal. Auf dem Handy geht der Block auf volle Breite und richtet sich
nach der Uhr, nicht nach dem Rand.

EINE ANNAHME KORRIGIERT: In meiner Merkliste stand "Werktisch-Aufbau
nach VanVans Business Hub, Prozentring links". Im Hub nachgesehen -- es
gibt dort keinen Ring und keinen solchen Aufbau, nur eine schlichte
buehne-hero. Filipes Verweis galt der UHR, und die ist laengst gebaut.
Meine eigenen Notizen altern wie jede andere Bestandsliste.

DREI BEFUNDE AUS EIGENEN PRUEFUNGEN, alle behoben:

1. pruef-css-klassen: Die Zahl der Schriftgroessen unter 11,5 px war um
   genau eine gestiegen -- .stand__schild stand auf 9,3 px. Gesperrte
   Grossbuchstaben in 9 px liest man nicht, man erraet sie. Jetzt 11,5 px
   mit etwas engerer Sperrung, damit drei Schilder bei 320 px weiterhin
   nebeneinander passen (nachgemessen: 287 px, nichts abgeschnitten).

2. pruef-struktur: pruef-arten.mjs bildete das Tagesdatum aus UTC. Nachts
   zwischen 00:00 und 02:00 waere sie rot geworden, ohne dass am Code
   etwas falsch ist. Derselbe Fehler war mir am selben Abend schon im
   Messskript passiert -- dort hatte ich "Heute=0" gemessen und den Code
   verdaechtigt, der richtig lag.

3. Beim Bauen fast eingebaut: margin-left:auto von der Uhrgruppe
   genommen, weil der neue Block sie ja schon nach rechts schiebt. Er tut
   das nur, solange er da ist -- bis zur ersten Antwort steht er auf
   hidden, und die Uhr waere sichtbar weggesprungen.

Neu: server/pruef-ueberlappung.mjs. Misst auf 5 Seiten x 4 Breiten, ob
ein Bedienelement ueber einem anderen liegt (am 06.09. lag der
Sicht-Umschalter bei 412 px auf zwoelf Seiten ueber dem Chat-Knopf).
Ueberlappungen INNERHALB eines Bedienelements zaehlen nicht -- ein
durchsichtiges select ueber seinem eigenen Schild ist die uebliche
Bauart, und eine Warnung, die immer kommt, ist keine Warnung mehr. Mit
Gegenprobe: ein absichtlich verschobener Knopf muss erkannt werden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 01:05:54 +02:00
DogFatherGitandClaude Opus 5 de06ce0227 Kalender: sechs neue Terminarten, mit zwei stillen Loechern darin
Wunsch: "kategorien wie bigmatch, turniere, Special-Live ... informier
dich was man da alles noch gebrauchen koennte und auch so dass wenn man
die sachen aussucht die ganze kachel und sachen die man eintippen muss
auch zu der jeweiligen kategorie passen."

Neu: BigMatch, Turnier, Special-Live, Collab, Raid-Train, Charity --
neben den drei internen Arten. Das Formular fragt je Art anderes:
beim BigMatch "Gegen wen?" mit 60 Minuten, beim Turnier "Welches
Turnier?" mit 120, bei Charity "Fuer wen wird gesammelt?" mit 180.

ZWEI FEHLER, DIE BEIDE NICHT ABGESTUERZT WAEREN:

1. termin_serien wurde nicht umgestellt. Die Umbauschleife laeuft ueber
   zwei Tabellen, bildete den Namen der Sicherungsdatei aber ohne die
   Tabelle -- und der Zeitstempel darin wird einmal pro Serverstart
   gebildet. Der zweite Durchlauf wollte also dieselbe Datei anlegen,
   VACUUM INTO weigerte sich, und das (richtige) "ohne Sicherung kein
   Umbau" beendete die ganze Schleife. Ergebnis: termine umgestellt,
   termin_serien nicht. Eine wiederkehrende BigMatch-Reihe waere ohne
   erkennbaren Grund abgelehnt worden.

2. Die neuen Arten waren im Kalender UNSICHTBAR. In kalender.js standen
   zwei weitere Aufzaehlungen derselben Arten: `zeigen = {call, termin,
   review, frist}` und die Schalterleiste. Gefiltert wird mit
   `zeigen[e.art]` -- fuer 'bigmatch' ist das undefined. Anlegen ging,
   der Server meldete 201, die Zeile stand in der Datenbank, und im
   Kalender war sie in keiner Ansicht zu sehen. Ohne Fehler, ohne Hinweis.

   Beide Listen werden jetzt aus ARTNAME abgeleitet. Und `sichtbare()`
   prueft `!== false` statt auf Wahrheit: Der Vorgabewert einer
   Sichtbarkeitsfrage muss "sichtbar" sein -- ein Eintrag zu viel ist
   ein Schoenheitsfehler, ein fehlender ein verpasster Termin.

Gefunden hat Nummer 2 kein Test, sondern ein Bildschirmfoto: In der
Schalterleiste standen vier Arten statt zehn. Meine eigene Pruefung war
zu dem Zeitpunkt gruen -- sie hoerte beim HTTP 201 auf.

Neu: server/pruef-arten.mjs, 28 Pruefungen. Baut eine Datenbank im ALTEN
Stand nach (samt Teilnehmer, Wecker, Serie), laesst die Anwendung
darueberlaufen und zaehlt nach; haelt CHECK und Serverliste gegeneinander;
und oeffnet zuletzt einen echten Browser, um zu sehen, ob die Eintraege
auch ankommen. Gegenprobe gefahren: mit dem alten Stand meldet sie
0 von 6 sichtbar.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 00:44:33 +02:00
DogFatherGitandClaude Opus 5 535d86d3f7 Die Termine im Tagesfenster sind Karten statt Werkzeugleisten
Filipe: "die sollen viel besser aussehen und viel geiler."

WAS WIRKLICH SCHIEFLIEF, WAR KEIN GESCHMACK, SONDERN DER AUFBAU

Zeit, Titel, Art und FUENF Knoepfe standen in EINER Zeile. Der Titel
bekam damit den Rest -- "BigMatch vs. Beanii" brach auf DREI Zeilen um,
waehrend rechts daneben Platz war. Die wichtigste Angabe der Zeile war
die gequetschteste, und die Knoepfe waren genauso laut wie der Termin
selbst.

Jetzt drei Ebenen, wie bei einer Karte:

  OBEN    Zeit und Titel, gross, ueber die ganze Breite -- der Titel
          hat keinen Wettbewerb mehr
  MITTE   die Nebendaten (Dauer, Ort, Beschreibung)
  UNTEN   die Knoepfe, rechtsbuendig in einer eigenen Reihe, durch eine
          Haarlinie abgesetzt

Die Zeit steht gross am Anfang und mit gleichen Zifferbreiten: Sie ist
das, wonach man in einem Tagesfenster sucht, und mehrere Zeilen stehen
dadurch in einer Flucht. Die Zeile traegt jetzt dieselbe abgeschnittene
Ecke wie alle Module -- ein Eintrag im Tagesfenster ist ein kleines
Modul, kein Listenpunkt.

ZWEI DINGE, DIE DABEI AN DIE RICHTIGE STELLE GERUECKT SIND

  * DIE ART GEHOERT ZUM TITEL. Sie stand als erstes Element in der
    Knopfreihe und sah damit aus wie ein Knopf, der nicht reagiert. Sie
    ist aber eine ANGABE ueber den Termin, wie Uhrzeit und Titel. Jetzt
    steht sie neben dem Titel, und die Knopfreihe enthaelt nur noch
    Dinge, die etwas tun.
  * DIE NEBENDATEN VOR DIE KNOEPFE. Im Raster bestimmt die Reihenfolge
    im Dokument, welche Zeile ein Feld bekommt -- die Knopfreihe stand
    davor und landete zwischen Titel und "30 Min · TikTok". Im ersten
    Bildschirmfoto stand die Beschreibung UNTER den Knoepfen, als
    gehoerte sie zu ihnen. Geloest ueber die Reihenfolge im Dokument und
    nicht ueber `order` im Stil: Sie gilt auch fuer Vorleseprogramme und
    die Tastatur, `order` verschiebt nur das Bild.

Auf dem Handy stehen Zeit und Titel untereinander -- bei 390 px laesst
eine 1,06-rem-Uhrzeit daneben keine zwei Woerter uebrig.

Zehn Pruefungen gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 00:18:06 +02:00
DogFatherGitandClaude Opus 5 e744f22fbc Vier Tafeln in einer Reihe -- die offene breiter als die Reiter
Filipe: "die sollen alle in einer reihe sein und nicht 3 und dann eins
drunter. perfektionier das."

DER GRUND WAR EINE RECHNUNG, DIE ICH NICHT KONTROLLIERT HABE

Dort stand `auto-fit` mit 340 px Mindestbreite -- CSS rechnet sich dann
selbst aus, wie viele nebeneinanderpassen. Bei vier Tafeln in einer
1240 px breiten Spalte reichte es fuer drei; die vierte rutschte in
eine zweite Zeile. `auto-fit` ist bequem, solange die Anzahl offen ist.
Sobald sie feststeht, ist es eine Rechnung, die man aus der Hand gibt.

Vier sind es, vier stehen nebeneinander -- und zwar mit `flex` statt
`grid`, weil damit die OFFENE Tafel breiter sein kann als die
geschlossenen. Es ist immer genau eine offen, und die bekommt den
anderthalbfachen Anteil: Dort wird gearbeitet, die anderen sind
Reiter. Das ist der Unterschied zwischen vier gleich grossen Kaesten
und einem Brett.

UND EIN VERSPRECHEN, DAS ERST NACH DEM ERSTEN KLICK GALT

Das Akkordeon griff nur beim Klicken. Beim Laden kamen die gemerkten
Staende aus der Ablage, und die konnten drei offene Tafeln ergeben --
im Bildschirmfoto standen genau so drei offen nebeneinander. Jetzt
bleibt beim Aufbau die erste Tafel offen, die etwas enthaelt; alle
weiteren klappen zu, ohne den gemerkten Stand zu ueberschreiben.

DREIMAL GEMESSEN STATT GESCHAETZT

Nach dem Umbau standen dort "LAEUFT AUTO..." und "FESTGEHALT..." --
252 px je Reiter, gemessen. Ich habe zweimal an den Pixeln gedreht
(Anteil 2,2 -> 1,8 -> 1,5, Sperrung 0,08 -> 0,035 em) und es blieb
abgeschnitten. Die richtige Antwort war nicht die dritte Zahl, sondern
der Name: Ein Reiter braucht ein Wort. Aus "Laeuft automatisch" wurde
"Wiederholungen" -- was es genau heisst, steht im Satz darunter, und
den liest man ohnehin erst, wenn die Tafel offen ist.

Gemessen am Ende: vier Tafeln, EINE Reihe, EINE offen, KEIN
abgeschnittener Titel.

Sechs Pruefungen gelaufen, alle gruen.

OFFEN, damit es nicht untergeht: pruef-call-kategorien meldet auf
Windows sporadisch Rueckgabewert 127 -- NACH "ALLES IN ORDNUNG", also
beim Beenden des Prozesses (libuv-Assertion beim Schliessen des noch
laufenden Servers). Das Ergebnis stimmt, der Rueckgabewert luegt. Wer
nur auf den Code sieht, haelt einen gruenen Lauf fuer rot.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-08 00:05:15 +02:00
DogFatherGitandClaude Opus 5 1c2e196d1d Der Wecker: mehrere Erinnerungen je Termin, jeder fuer sich
Filipe: "wie so ein wecker, den man auch in den eintraegen aktivieren
oder ausschalten kann, den soll man sogar so einstellen koennen, dass
er einen auch mehrmals informiert, einmal eine woche vorher, einmal
drei tage vorher und einmal am tag selber. das soll man auch selbst
jeder fuer sich einstellen koennen. hol die besten skills."

NACHGELESEN, NICHT GERATEN. Google Calendar erlaubt fuenf Erinnerungen
je Termin, Outlook genau eine, Apple zwei. Die verbreitete Empfehlung
fuer Wichtiges lautet "eine Woche, ein Tag, am Tag selbst" -- also
genau die Staffel, die Filipe genannt hat. Uebernommen: sechs Stufen
zur Wahl (Woche, drei Tage, ein Tag, selber Tag, Stunde, zehn Minuten),
hoechstens fuenf gleichzeitig.

EINE ZEILE IST EIN WECKER -- kein Feld am Termin mit einer Liste darin.
Mehrere Vorlaufzeiten UND "jeder fuer sich" sind zusammen eine
n:m-Beziehung; ein Feld mit kommagetrennten Zahlen waere beim ersten
"zeig mir alle faelligen Wecker" nicht mehr abfragbar.

DER ABSTAND STEHT IN DER DATENBANK, NICHT DER ZEITPUNKT. Ein Zeitpunkt
muesste bei jeder Terminverschiebung nachgezogen werden -- und genau
das vergisst man. Ein Abstand rechnet sich beim Wecken aus dem
aktuellen Beginn und ist damit immer richtig.

ZWEI GRENZEN IM WECKLAUF, und beide sind noetig: faellig (Weckzeit
erreicht) UND der Termin liegt noch vor uns. Ohne die zweite wuerde
beim ersten Lauf nach einem Ausfall jeder alte Wecker der letzten
Wochen nachtraeglich klingeln.

DER ABSTAND GEHOERT INS MERKMAL der Doppelsperre. Ohne ihn wuerde der
erste Wecker eines Termins alle weiteren sperren -- und genau das
Mehrfach-Wecken, um das es geht, faende nie statt.

DIE PRUEFUNG HAT SICH ZWEIMAL SELBST KORRIGIERT

  1. Erster Lauf um 23:42: vier Fehler, keiner echt -- der Melder
     schweigt zwischen 22 und 7 Uhr. Sie hat den Kalender gemessen,
     nicht die Software, und waere am Vormittag gruen gewesen. Dass die
     GEGENPROBE mitgefallen ist, war die eigentliche Auskunft: Waeren
     nur die Grenzen falsch, haette sie gehalten. Die Ruhezeit ist
     jetzt ueber die Umgebung einstellbar (Vorgabe unveraendert 22/7),
     damit eine Pruefung ihre Voraussetzung herstellen kann.
  2. Danach immer noch nichts: Ich hatte angenommen, der Melder trage
     den Versand nach dem VERSUCH ein. Er traegt ihn nach der
     erfolgreichen ZUSTELLUNG ein -- und das ist richtig so. Meine
     Annahme war falsch, nicht der Code. Die Pruefung hat jetzt einen
     winzigen echten Empfaenger; damit laeuft der ganze Versandweg mit,
     Verschluesselung und VAPID inbegriffen.

pruef-wecker.mjs: 20 Pruefungen. Sie stellt alle vier Fehler nach, die
bei einem Wecker moeglich sind (klingelt nicht / doppelt / nur einmal
von dreien / nachtraeglich nach einem Ausfall) -- plus die Gegenprobe,
dass ein faelliger Wecker wirklich ankommt.

Zwoelf weitere Pruefungen gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 23:51:20 +02:00
DogFatherGitandClaude Opus 5 63036fc33e Wiederholungen bekommen eine eigene Tafel -- und nur den laufenden Monat
Filipe: "ich will da auch noch eine kategorie fuer automatische
wiederholungen. die sollen dann auch nur fuer den monat selbst
angezeigt werden und nicht monate im voraus."

DAS PROBLEM WAR ECHT UND GROSS, UND ES STAND SEIT TAGEN AUF SEINEM
BILDSCHIRM

Der Nachfueller haelt einen Horizont von 180 Tagen gefuellt (siehe
workspace-serien.js). Ein woechentlicher Community-Talk ergibt darin
sechsundzwanzig Zeilen -- und alle standen unter "Steht an". Auf dem
Bild waren es siebenundzwanzig Karten, fast alle derselbe Termin. Die
Liste war damit unbrauchbar fuer genau das, wofuer sie da ist: zu
sehen, was WIRKLICH ansteht.

Jetzt sind es zwei getrennte Fragen:

  STEHT AN            was einmalig bevorsteht
  LAEUFT AUTOMATISCH  was von allein wiederkommt -- und davon nur der
                      LAUFENDE MONAT

Der Monatsschnitt ist die eigentliche Antwort auf "nicht Monate im
Voraus": Eine Wiederholung im November sagt einem heute nichts, was man
nicht schon weiss. Wer weiter schauen will, hat den Kalender -- und
genau das steht als Satz in der Gruppe.

Gerechnet wird auf dem reinen Datumstext (`beginn` beginnt mit
JJJJ-MM), nicht mit `new Date`. Kein Zeitzonenfehler, kein Nachtfehler.
Die Trennung faellt im SERVER, nicht in der Oberflaeche: Eine zweite
Regel im Browser waere die sichere Zusage, dass beide auseinanderlaufen.

DREI AUSSAGEN STATT EINER

pruef-call-kategorien saet jetzt zwei Auspraegungen derselben Serie --
eine in vier, eine in sechzig Tagen -- und misst:

  1. die Wiederholung dieses Monats steht in "Laeuft automatisch"
  2. die des naechsten Monats NICHT
  3. und unter "Steht an" steht keine von beiden

Vorher wird geprueft, dass die beiden ueberhaupt in verschiedenen
Monaten liegen. Ohne diese Zeile waere Nummer 2 an einem 1. des Monats
trivial erfuellt -- gruen, ohne etwas gemessen zu haben.

Zwei Fehler beim Bau der Pruefung, beide von ihr selbst gemeldet:
`page.evaluate` lief in "Target page has been closed" (der Block davor
schliesst seinen Browserkontext -- diese Aussage braucht ohnehin keinen
Browser, sie betrifft die Schnittstelle), und eine Hilfsfunktion stand
nach ihrer ersten Benutzung.

pruef-call-kategorien von 17 auf 22. Neun Pruefungen gelaufen, alle
gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 23:26:38 +02:00
DogFatherGitandClaude Opus 5 fc4616bb05 Immer nur eine Tafel offen -- und eine zugeklappte belegt nichts mehr
Filipe: "wenn ich eine aufklicke soll auch immer nur die aufgehen und
nicht alle 3."

DAS IST MEHR ALS GESCHMACK. Seit die drei Tafeln nebeneinander stehen
und jede ihren eigenen Lauf hat, teilen sie sich die Bildschirmhoehe:
Drei offene Tafeln heissen drei kurze Ausschnitte -- eine offene heisst
eine, in der man wirklich arbeiten kann.

Die anderen werden ZUGEKLAPPT, nicht versteckt: Ihre Koepfe bleiben mit
Namen und Anzahl stehen. Man sieht weiterhin, was es sonst gibt, und
kommt mit einem Klick hin. Der gemerkte Stand wird mitgeschrieben --
sonst waere die Seite beim naechsten Aufruf in einem Zustand, den
niemand hergestellt hat.

UND EIN FEHLER VON MIR, DEN SEIN BILD GEZEIGT HAT

Die zugeklappten Tafeln standen als LEERE KAESTEN ueber die volle Hoehe
da. `align-items: stretch` am Brett gilt eben auch fuer die, die nichts
zeigt. Drei gleich hohe Tafeln sind richtig, solange sie etwas
enthalten -- eine geschlossene enthaelt nichts und soll dann auch
nichts belegen.

Vier Pruefungen gelaufen, alle gruen.

NOCH OFFEN, und bewusst nicht angefangen: Erinnerungswecker,
Terminarten (BigMatch/Turniere/Special-Live) und der Umbau der
Begruessungskachel nach VanVans Werktisch. Jede davon ist ein eigener
Bau -- angefangen und liegengelassen waeren sie schlimmer als gar nicht
begonnen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 18:41:12 +02:00
DogFatherGitandClaude Opus 5 c5cdf686e3 Der Husky jetzt auch auf der Zugangsseite -- und fuenf Zeichen in fuenf Farben
Filipe: "bei dogfather ist immer noch die krone und da soll ja ein husky
sein. und die symbole sollen doch alle viel krasser, geiler und
spezieller sein."

Er hat recht, und der Grund ist eine Haelfte, die ich uebersehen habe:
Die Rollenzeichen gibt es ZWEIMAL im Haus -- als <use>-Bausteine in
personen.html (dort war der Husky schon) und noch einmal ausgeschrieben
in index.html, der Anmeldeseite. Getauscht hatte ich nur die erste.

DER HUSKY, zweite Ausfertigung. Bei 21 Pixeln entscheidet die
Silhouette, nicht das Detail: spitze aufrechte Ohren, breiter Kopf, der
nach unten schmal zulaeuft, Gesichtsmaske. Mehr passt nicht hinein --
und mehr braucht es nicht.

UND ALLE FUENF ZEICHEN TRAGEN JETZT IHRE EIGENE FARBE

Sie waren feine Konturen in einer Farbe, und zwar in DERSELBEN fuer
alle fuenf. Jetzt: eine gefuellte Flaeche in der Farbe ihrer Rolle, die
Zeichnung hell darauf, ein leichter Schatten darunter. Chili rot,
Husky gold, Stern violett, Schild gruen, Person blau -- dieselben
Farben wie auf der Personenseite; wer die eine Seite kennt, erkennt die
andere wieder.

Die Farbe steht am ROLLENKNOPF (`--rf`), nicht im Zeichen. Die Zeichen
wissen damit nichts von Rollen, und eine Farbaenderung passiert an
einer Stelle statt an fuenf. Gewaehlt heisst: mehr Licht auf demselben
Gegenstand -- kein anderer Gegenstand.

Zehn Pruefungen gelaufen, alle gruen, darunter Kontrast und Handy fuer
die Anmeldeseite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 18:36:04 +02:00
DogFatherGitandClaude Opus 5 af4a00dce2 Die Kopfleiste war nie klebend -- und das Call-Brett hatte eine leere Haelfte
DIE LEISTE BLEIBT JETZT OBEN (screen 3)

Filipe: "diese leiste soll immer da stehen bleiben, egal ob man die
seite runterscrollt oder nicht, auf allen seiten."

In start.css steht seit jeher `.kopfleiste { position: sticky; top: 0 }`.
Zwanzig Zeilen darueber steht aber

    body.start > .kopfleiste { position: relative; z-index: 1; }

und das ist (0,2,1) gegen (0,1,0) -- die staerkere Regel gewinnt,
unabhaengig von der Reihenfolge. Gemessen im Browser: `position:
relative`, und bei 600 px Scrollen wanderte die Leiste 600 px aus dem
Bild. Sie hat also nie geklebt, obwohl es im Code so dasteht.

Das ist heute die VIERTE Spielart derselben Falle: `:where()` zu
schwach, `body.start .willkommen` zu stark, die Kachel-Verschachtelung
zu stark -- und hier eine Regel, die etwas ganz anderes wollte (den
Stapelwert ueber der Buehne) und dabei die Positionierung mitgenommen
hat. Merksatz: Wer `position` setzt, nur um `z-index` zu bekommen,
greift jedes Mal daneben.

Nachgemessen: 700 px gescrollt, Leiste steht bei 0.

DAS CALL-BRETT: DREI TAFELN STATT ZWEIER SPALTEN (screen 2)

Filipe: "das bewegt sich immer noch mit, das ist so scheissen."

DAS PROBLEM WAR DIE AUFTEILUNG, nicht die Gestaltung. Zwei Spalten, und
"Steht an" hatte siebenundzwanzig Karten: Die rechte Spalte lief ueber
mehrere Bildschirmhoehen, die linke war nach zwei Koepfen zu Ende. Wer
scrollt, sieht dann eine leere halbe Seite mit einer Ueberschrift, die
scheinbar mitwandert -- sie steht bloss still, waehrend daneben alles
laeuft.

Jetzt bekommt jede Tafel DIESELBE Hoehe und einen EIGENEN Lauf. Alle
drei Gruppen sind damit immer gleichzeitig zu sehen, egal wie viel in
einer steckt, und die Seite selbst scrollt kaum noch. Das ist die
Bauart jedes Aufgabenbretts, und sie ist es aus genau diesem Grund.

Die Hoehe haengt am Fenster (`min(62vh, 620px)`) statt an einer festen
Zahl. Unter 900 px stehen die Tafeln untereinander und laufen wieder
frei -- auf dem Handy ist ein Kaestchen mit eigenem Balken eine Falle,
keine Hilfe. Der Balken ist selbst gestaltet; der Systembalken reisst
ein weisses Band in eine dunkle Flaeche.

NOCH OFFEN aus derselben Nachricht: der Erinnerungswecker fuer Termine
(ein-/ausschaltbar je Eintrag, mehrere Zeitpunkte, von jedem selbst
einstellbar) -- dazu will Filipe ausdruecklich Recherche, und der baut
sich nicht nebenbei.

Zehn Pruefungen gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 18:24:58 +02:00
DogFatherGitandClaude Opus 5 28a260fab2 Ein Husky statt der Krone -- und Spicy sieht DogFather, aber nur ihn
DER HUSKY (screen 1)

Filipe: "die krone bei dogfather durch einen husky ersetzen, wie mein
logo." Bei 24 Pixeln entscheidet die SILHOUETTE, nicht das Detail. Ein
Husky erkennt man an dreierlei, und mehr passt auch nicht hinein: den
spitzen aufrechten Ohren, dem breiten Kopf, der nach unten schmal
zulaeuft, und der Gesichtsmaske. Fell oder Zunge waeren bei dieser
Groesse Matsch -- genau deshalb hat die Krone davor funktioniert.

UND ALLE ROLLENSYMBOLE SIND JETZT KOERPER

Sie waren reine Konturen in einer Farbe -- daneben auf derselben Seite
die Kachelzeichen mit drei Lichtern. Jetzt tragen sie eine gefuellte
Flaeche in ihrer Rollenfarbe, die Zeichnung hell darauf, und Augen und
Nase eigens gesetzt. Beim gewaehlten Knopf leuchtet die Flaeche
staerker -- der einzige Unterschied, den es braucht: mehr Licht auf
demselben Gegenstand.

SPICY SIEHT DOGFATHER, ABER NICHT DEN ZWEITEN ADMIN (screen 2)

Filipe: "die rolle spicy soll auch die rolle dogfather sehen, aber nur
dogfather und nicht vanvan."

NACHGEMESSEN AM ECHTEN SYSTEM, nicht angenommen: In der Datenbank
tragen BEIDE die Rolle `admin` -- id 1 "Dogfather", id 4 "VanVan". Es
gibt kein Feld, das den einen vom anderen unterscheidet.

Der Unterschied, den es wirklich gibt, ist das Alter: DogFather ist der
erste Zugang des Hauses. Deshalb zaehlt die kleinste Nummer unter den
Admins -- eine Eigenschaft, die feststeht und nicht am Namen haengt.
Die Schwachstelle steht im Code, damit sie niemand sucht: Wuerde Zugang
1 je geloescht, rueckte der naechste nach; dann gehoert ein
ausdrueckliches Merkmal in die Tabelle.

Die Entscheidung faellt im SERVER, nicht in der Oberflaeche. Dort stand
vorher ein Filter, der den ganzen Abschnitt wegnahm -- zwei Regeln fuer
dieselbe Frage laufen auseinander, und eine ausgeblendete Zeile hat
noch nie etwas geschuetzt.

MEINE EIGENEN PRUEFUNGEN VON HEUTE MITTAG FIELEN DABEI

Richtig so: Sie pruefen "DogFather steht NICHT darin", und das gilt
nicht mehr. Umgeschrieben -- und dabei kam der eigentliche Prueffall
dazu: ein ZWEITER Admin-Zugang im Testbestand. Ohne ihn waere die Regel
gar nicht pruefbar, bei einem einzigen Admin ist jede Antwort richtig.
pruef-spicy von 57 auf 60.

NOCH OFFEN aus derselben Nachricht: die Terminarten (BigMatch,
Turniere, Special-Live) und der Umbau der Begruessungskachel nach dem
Vorbild von VanVans Werktisch.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 18:14:54 +02:00
DogFatherGitandClaude Opus 5 09a0c17237 Bearbeiten geht jetzt -- und zwei Bedienelemente, die keine Kacheln sind
DER SERVER LIESS DAS AENDERN DIE GANZE ZEIT ZU. IM TAGESFENSTER FEHLTE
DER KNOPF.

Filipe: "ich hab die gemacht und kann sie nicht bearbeiten." Dort
standen nur "erledigt" und "loeschen". Ein Recht ohne Knopf ist kein
Recht. Jetzt oeffnet "bearbeiten" dasselbe Formular, gefuellt -- ein
Formular, zwei Wege (POST oder PATCH), statt eines zweiten, das genauso
aussieht und beim naechsten Feld auseinanderlaeuft.

Die Wiederholung bleibt beim Bearbeiten aussen vor: Sie ist eine REGEL
und wird unter "Laeuft von allein" geaendert, nicht an einer ihrer
Auspraegungen. Wer das zulaesst, bekommt einen Termin, der aus der
Reihe faellt, ohne dass jemand weiss warum.

UND DIE REGEL DAZU IM SERVER

Filipe: "nur diese person selber." Bis hierher durfte JEDER aendern,
der den Termin ueberhaupt sah -- bei einem Termin mit mehreren
Beteiligten also alle. Jetzt: die Leitung und wer ihn eingetragen hat.
Dieselbe Regel wie beim Loeschen, die dort schon richtig stand.

AUSNAHME "erledigt": Ein Haken, dass ein Gespraech stattgefunden hat,
ist keine Aenderung am Termin, sondern eine Rueckmeldung dazu -- sonst
muesste jeder Beteiligte den Anleger bitten, den eigenen Call
abzuhaken.

Gemessen in pruef-teilnehmer, mit allen drei Faellen. Beim Bauen der
Pruefung ist mir ein Aufbaufehler unterlaufen (Bea statt Pat als
zweite Teilnehmerin -- Luna darf Bea gar nicht einladen), und die
Pruefung hat ihn korrekt als 404 statt 403 gemeldet. Der Fehler lag im
Aufbau, nicht im Code.

DER ANSICHTS-UMSCHALTER WAR VIER KACHELN

`.k-ansicht` stand in der Modulliste. Jeder der vier Knoepfe bekam
damit die volle Behandlung einer Kachel: Fase, Kantenlicht, Eckwinkel,
Raster. Auf 90 mal 32 Pixeln ist das kein Modul, sondern Gedraenge --
vier Fasen und sechzehn Eckwinkel nebeneinander.

Die Modulform ist fuer FLAECHEN gedacht, die etwas enthalten. Ein
Umschalter enthaelt nichts, er waehlt aus, und die richtige Form dafuer
ist die SCHIENE: eine vertiefte Bahn, in der ein erhabenes Stueck aus
gebuerstetem Metall sitzt. Man sieht auf einen Blick, dass die vier
zusammengehoeren und genau eines gewaehlt ist.

DIE GRUPPENKOEPFE AUF DER CALLS-SEITE

Vorher eine Textzeile mit Pfeil, und die Karten darunter begannen ohne
Uebergang -- aufgeklappt sah man nicht, wo eine Gruppe aufhoert. Jetzt
ist der Kopf ein Schalter mit Zustand, die Zahl ein gefasstes Schild,
und die Karten stehen aufgeklappt in einer eigenen vertieften Bahn mit
Farbschiene links.

14 Pruefungen gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 17:05:28 +02:00
DogFatherGitandClaude Opus 5 dd1f561f3b Vier Meldungen -- und dahinter zweimal derselbe alte Fehler
DIE SYMBOLE IN DER TAGESKACHEL WAREN DIESELBEN -- OHNE IHRE GESTALTUNG

Sie kommen vom selben Bauer wie alle anderen, bekamen aber nie dessen
Aussehen: Alle Lagenregeln waren auf `.kachel__svg` eingegrenzt, und
dieses Zeichen heisst `.dran__svg`. Uebrig blieb eine flache Kontur --
daneben, auf derselben Seite, dieselben Zeichen mit drei Lichtern,
Tiefe und Randlicht. Die Regeln gelten jetzt fuer beide Traeger, und
das Feld darum ist dasselbe gefasste Schild wie auf den Kacheln.

"UNDEFINED" IM CHAT -- DERSELBE FEHLER WIE HEUTE FRUEH, NUR ALS OBJEKT

Ueber Cigdems Namen stand woertlich "UNDEFINED". Die Rollennamen
standen als Objekt in FUENF Skripten (chat.js zweimal, dateien.js,
kalender.js zweimal), in keinem davon 'spicy'.

Heute Frueh war es dieselbe Sache als Menge (`new Set([...])`), und
seitdem sucht `pruef-css-klassen.mjs` danach. Ein Muster, das nur eine
Schreibweise kennt, findet auch nur eine -- die Pruefung sucht jetzt
auch nach Rollen-OBJEKTEN, mit Gegenprobe. Die Namen stehen an EINER
Stelle in bereiche.js.

DOGFATHER UND SPICY MEDIA SIND IM CHAT FUER JEDEN ERREICHBAR

DogFather kam bisher als Nebeneffekt ueber die Betreuungskette mit
hinein, Spicy Media gar nicht -- die Rolle steht in keiner Kette, sie
steht daneben. Beide werden jetzt ausdruecklich hinzugefuegt: Eine
Zustaendigkeit, die nur zufaellig aus einer anderen Regel herausfaellt,
faellt beim naechsten Umbau genauso zufaellig wieder heraus.
Gemessen aus der Sicht eines Creators -- wer bei ihm ankommt, kommt
ueberall an.

DIE PERSONENLISTE: SPICY MEDIA SIEHT ALLES AUSSER DOGFATHER

Der Abschnitt "Spicy Media" fehlte in der Liste komplett -- die Rolle
gibt es seit heute Frueh, die Personenseite kannte sie nicht. Und Spicy
Media selbst sah dort bisher nur das Anlegen-Formular; sie bekommt
jetzt die Liste, ohne DogFathers Zeile, und weiterhin ohne Codes,
Sperren, Loeschen und Protokoll. Ueberblick ist nicht Verwaltung.

ZWEI FOLGEFEHLER, BEIDE VON DEN PRUEFUNGEN GEFUNDEN

  * `next("route")` TUT DAS GEGENTEIL VON DEM, WONACH ES KLINGT. Mein
    erster Versuch war eine Ausnahme-Route VOR der Schranke, die mit
    `next("route")` weiterreicht -- das ueberspringt aber die restlichen
    Handler DIESER Route und geht zur naechsten Schicht, also genau zur
    Schranke. Spicy bekam weiter 404, die Oberflaeche verstand das als
    "nicht erlaubt" und sprang zur Startseite. Gemessen: Auf
    personen.html standen die Kategorien der STARTSEITE.
  * DAS PROTOKOLL WARF SIE VON DER SEITE. Es bleibt bei DogFather und
    antwortet ihr mit 404 -- und `hole()` versteht ein 404 unter
    `/verwaltung/` als "nicht erlaubt". Die Seite baute sich auf und
    sprang im naechsten Atemzug weg. Eine Abfrage, von der man weiss,
    dass sie 404 gibt, stellt man nicht.

UND EINE MEINER EIGENEN NEUEN PRUEFUNGEN WAR WERTLOS

"bei ihr fehlt der Abschnitt DogFather" -- gruen, mit dem Zusatz
"(keine Abschnitte)". Sie war gruen, weil die Liste bei ihr GAR NICHT
DA war. Genau der Haken, der nichts beweist. Er steht jetzt neben einem
Ergebnis, das etwas enthaelt: "Spicy Media | Manager | ...".

18 Pruefungen gelaufen, alle gruen. pruef-spicy von 49 auf 57.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 16:45:50 +02:00
DogFatherGitandClaude Opus 5 0ea8b27aca Aus drei Strichen werden drei Ringe aus Material
Filipe: "ich will dass der rand mit den sekunden minuten und stunden
viel krasser und geiler ist ... ultra modern, ultra speziell, ultra
profissionell, ultra phaenomenal."

EIN STRICH IST EINE LINIE. EIN RING IST EIN KOERPER.

Und ein Koerper hat drei Merkmale, die man zeichnen MUSS, sonst bleibt
es ein Strich. Jeder der drei Ringe besteht deshalb jetzt aus drei
Lagen:

  SCHATTEN   Er liegt ueber dem Zifferblatt, also wirft er einen.
             Dieselbe Bahn, schwarz, ein halbes Rastermass nach UNTEN.
  KOERPER    Der Bogen selbst in seiner Farbe.
  OBERKANTE  Duenner, hell, ein Drittel nach OBEN. Weil er versetzt
             ist, schaut er oben hervor und verschwindet unten -- genau
             das tut eine gewoelbte Kante bei Licht von oben.

Kein Weichzeichner, nirgends: Die Tiefe kommt aus dem Versatz, nicht
aus Unschaerfe.

DIE BAHNEN SIND GEFRAESTE RILLEN

Ein Zeiger laeuft bei einem guten Instrument IN einer Vertiefung. Eine
Rille erkennt man an zweierlei: dunkler als ihre Umgebung, und an ihrer
unteren Wand steht eine helle Kante. Beides steht jetzt da, und die
Breite folgt dem Ring, der darin laeuft -- eine Rille, die schmaler ist
als ihr Zeiger, ist keine.

DREI KOEPFE STATT EINEM

Minute und Stunde bekommen dieselbe polierte Kappe wie die Sekunde, auf
ihren eigenen Bahnen und in ihrer eigenen Farbe. Erst dadurch liest man
die drei Ringe als drei ZEIGER und nicht als drei Fortschrittsbalken.
Sie laufen mit ihrem Ring: die Minute nimmt die Sekunden anteilig mit,
die Stunde die Minuten -- sonst staende der Kopf neben dem Ende seines
Bogens.

ALLE LAGEN WERDEN GEMEINSAM GESETZT. Sie tragen `data-ring`; einzeln
gepflegte Verweise waeren drei Stellen, an denen man eine vergessen
kann, und ein Schatten, der stehen bleibt, sieht sofort kaputt aus.

UND EIN FUND, DEN DIE PRUEFUNG SOFORT GEMELDET HAT

Die neue helle Oberkante des Stundenrings laeuft hinter den Ziffern
durch: schlechtester Kontrast 2,98:1 -- knapp unter der Grenze, und
ausgerechnet bei der Uhrzeit selbst. Die Antwort war nicht "Kante
weg", sondern der fehlende Untergrund: Auf einer echten Uhr steht eine
Anzeige, die ueber Zeigern liegt, auf einer eigenen vertieften INSEL im
Zifferblatt. Jetzt 5,42:1, und dabei 29 statt 14 gemessene Stellen.

Merksatz: Wenn eine neue Schicht einen Text unlesbar macht, ist die
Antwort selten "Schicht weg" -- meistens fehlt dem Text sein Grund.

Zehn Pruefungen gelaufen, alle gruen. Rechner und Handy angesehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 16:23:27 +02:00
DogFatherGitandClaude Opus 5 9c7952b5a3 Drei Lichter statt einem: die Symbole bekommen Koerper
Filipe: "die symbole und der text dadrin sollen groesser und noch
spezieller sein, und die symbole sollen auch 2-3 farben haben ... sollen
mehr leben haben, auch viel realistischere effekte."

NICHT DREI AUSGEDACHTE FARBEN, SONDERN DIE DREI EINES ECHTEN AUFBAUS

So wird jedes Produktfoto ausgeleuchtet, und aus demselben Grund sieht
es plastisch aus:

  1  FUEHRUNGSLICHT, kalt, von oben links. Ein Spitzlicht ist nie
     reinweiss -- es traegt die Farbe der Lampe, und die ist kuehl.
  2  EIGENFARBE des Gegenstands: der Ton seiner Kachel.
  3  STREULICHT, warm, von unten. Licht, das vom Untergrund
     zurueckkommt, ist waermer als das Hauptlicht. Genau dieser warme
     Saum ist der Grund, warum ein Gegenstand im Bild STEHT statt zu
     schweben.

Dazu die aelteste Regel der Malerei: warmes Licht, KUEHLE Schatten. Die
Seitenwaende der Zeichen kippen jetzt ins Blaue statt nur dunkler zu
werden. Und ein RANDLICHT auf der Lichtseite -- der schmale Streifen,
in dem das Fuehrungslicht die Kante streift. Ein Gegenstand ohne diese
Kante sieht immer ein wenig flach aus, und man kann meist nicht sagen,
warum.

ZWEI FEHLER DABEI, BEIDE ERST BEI FUENFFACHER VERGROESSERUNG SICHTBAR

  * DAS WARME LICHT LAG UNTER DER FORM. Die Verlaeufe spannten ueber das
    ganze 24er-Raster (y 2 bis 22); die Sprechblase des Chats reicht
    aber nur von 5,5 bis 20,5. Der warme Stopp bei y 22 war damit
    ausserhalb -- von den drei Lichtern kam genau eines an.
    `objectBoundingBox` spannt den Verlauf jetzt ueber JEDES Teil
    einzeln: Der Kalenderkorpus bekommt sein volles Licht, seine Fuesse
    ebenfalls. So verhaelt sich ein echter Aufbau -- jedes Teil liegt im
    selben Licht, nicht im selben Ausschnitt.
  * DAS RANDLICHT WAR SCHMALER ALS DIE KONTUR DARUEBER und lag deshalb
    vollstaendig darunter: gebaut, gezeichnet, unsichtbar. Jetzt 2,7
    gegen 1,9 -- so schaut es oben links hervor.

GROESSER, WIE GEWUENSCHT

Plakette 58 -> 64 px (grosse Kachel 62 -> 70), Zeichen 29 -> 35 px
(gross 32 -> 39), Wasserzeichen 132 -> 156 px (gross 168 -> 196),
Name 1,06 -> 1,15 rem (gross 1,24 -> 1,38), Unterzeile 0,78 -> 0,845.
Auf dem Dashboard entsprechend.

UND DAS SCHILD WIRFT LICHT AUF SEINE KACHEL

Ein beleuchteter Gegenstand faerbt seine Umgebung. Ohne diesen Abfall
sieht selbst ein gut gebautes Schild aufgeklebt aus. Weit gestreut und
weit unter der Blendschwelle: Man soll ihn nicht sehen, man soll ihn
vermissen, wenn er fehlt.

Zehn Pruefungen gelaufen, alle gruen -- darunter Handy und Breiten,
weil groesserer Text der schnellste Weg zu einem Ueberlauf ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 16:01:27 +02:00
DogFatherGitandClaude Opus 5 5b6f9cef98 Rot, Schwarz, Babyblau -- und ein Glas, das entspiegelt ist
Filipe: "der rand soll auch eine mischung von rot schwarz und babyblau
haben und die kachel selbst soll einen uebertrieben krank geilen
hintergrund haben ... die einzige kachel, die komplett aus dem rudel
faellt. die uhr soll auch VIEL VIEL VIEL KRASSER sein. informier dich,
hol die besten skills von den besten skills."

NACHGELESEN STATT GERATEN -- UND DAS HAT DIE UHR VERAENDERT

Zur Frage, woran man ein hochwertiges Uhrenglas erkennt: Eine
Entspiegelung wird im Vakuum aufgedampft und senkt die Spiegelung auf
unter ein Prozent -- das Zifferblatt wirkt dadurch SCHAERFER, nicht
milchiger. Und ihr Erkennungszeichen ist kein weisser Schleier, sondern
ein TOPASBLAUER SCHIMMER, der je nach Lichteinfall ueber das Glas
laeuft.

Hier lag genau das Gegenteil: ein breiter weisser Verlauf ueber ein
Fuenftel der Scheibe -- also die Spiegelung eines UNBESCHICHTETEN
Glases, das Merkmal des billigeren Materials. Jetzt: ein schmaler,
harter Reflexbogen an der Woelbung, der topasblaue Schimmer diagonal
darueber, und die haarfeine Schnittkante oben.

DAZU ZWEI WEITERE MITTEL AUS DEM UHRENBAU

  * AUFGESETZTE INDIZES bei 3, 6 und 9. Auf einer guten Luenette sind
    die Viertelstunden keine Striche wie die anderen: Sie sind eigene
    Marken, breiter und HELL statt graviert -- weil sie aufgesetzt sind
    und deshalb Licht fangen statt Schatten zu halten. Die 12 bleibt
    die rote.
  * DAS SEKUNDENFELD IST EIN EINGELASSENES FENSTER. Eine Zusatzanzeige
    sitzt in einer Aussparung des Blatts; man erkennt das daran, dass
    der Schatten oben hineinfaellt und unten eine helle Kante steht.
    Genau diese beiden Schatten stehen jetzt darin.

DIE FASSUNG: DREI FARBEN STATT STAHL MIT TUPFERN

Links die rote Haelfte, rechts die babyblaue, dazwischen und an den
Raendern Schwarz -- und ueberall dort, wo Metall das Licht bricht, die
hellen Spitzlichter. Es sind dieselben zwei Farben wie im Motiv und auf
der Anmeldekarte.

DER HINTERGRUND: SECHS SCHICHTEN

Lichtkante, KOHLEFASERGEWEBE (zwei gegenlaeufige Schraegen, die sich
kreuzen -- bei drei Prozent sieht man kein Muster, man sieht ein
MATERIAL), das Messraster, ein HORIZONT im unteren Drittel mit Schein
darueber, die beiden Farbbecken kraeftiger als bisher, und ein fast
schwarzer Grund mit Blauschimmer oben.

Alles weit unter der Blendschwelle -- die Hausregel gilt auch fuer
"krank geil": Es darf beeindrucken, es darf nicht blenden.

Sieben Pruefungen gelaufen, alle gruen. Rechner und Handy angesehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 15:44:25 +02:00
DogFatherGitandClaude Opus 5 6e09c55002 Die Symbole hatten nie ihre Farbe -- ein Jahr lang, auf jeder Seite
Filipe: "ich will dass die symbole viel krasser, realistischer,
farbiger und spezieller sind ... ich meine wirklich alle alle alle
symbole auf der ganzen website."

DER GRUND WAR KEIN GESCHMACK, SONDERN EIN BAUFEHLER

Die Verlaeufe der Zeichen arbeiten mit `currentColor`, damit jedes
Zeichen die Farbe SEINER Kachel annimmt. Sie lagen aber alle zusammen
in EINEM versteckten SVG am Ende der Seite, und jedes Zeichen verwies
nur darauf. `currentColor` in einem Verlaufsstopp wird an dem Element
aufgeloest, das den STOPP enthaelt -- also dort, im versteckten SVG,
wo die Textfarbe das helle Grau der Seite ist.

Jedes Zeichen im ganzen Haus war deshalb grau. Der Farbton kam sauber
an der Kachel an (gemessen: rgb(62,149,231) auf der Dashboard-Kachel)
und wurde nie benutzt.

GEMESSEN, NICHT VERMUTET: Faerbt man das versteckte SVG rot, werden die
Zeichen rot (hellster Bildpunkt 43/49/61 -> 46/29/40). Faerbt man das
ZEICHEN rot, passiert nichts. Damit war die Frage entschieden.

Das Tueckische daran: Es sah nie kaputt aus. Graue Zeichen auf dunklem
Grund wirken sauber und zurueckhaltend -- man haelt es fuer eine
Entscheidung. Ein Fehler, der wie Gestaltung aussieht, ueberlebt jede
Pruefung, die auf Fehlermeldungen achtet.

DIE REPARATUR

Jedes Zeichen traegt seine Verlaeufe jetzt SELBST, in seinem eigenen
SVG und mit eigener Kennung. Damit steht `currentColor` dort, wo es
hingehoert. Die Verweise setzt das Skript als Inline-Stil, weil eine
Klassenregel die je Zeichen andere Kennung nicht kennen kann -- das
Wasserzeichen bekommt keinen, dort setzt das CSS die Farbe ausdruecklich.

UND DAS LICHT WURDE UMGEDREHT

Weiss stand vorher ueberall: die Deckflaeche begann mit 92 % Weiss, die
Kontur war bis 38 % weiss und bei 100 % wieder. Selbst mit richtiger
Farbe waere davon wenig uebrig geblieben. Jetzt ist Weiss nur noch da,
wo bei einem echten Gegenstand das SPITZLICHT sitzt -- ein schmaler
Streifen ganz oben. Darunter traegt die Eigenfarbe, unten kommt
Streulicht in einer helleren Tonung statt in Weiss: Licht, das vom
Untergrund zurueckkommt, nimmt die Farbe des Gegenstands mit, es
bleicht ihn nicht aus. Das Spitzlicht selbst wurde schmal und hart --
ein Schleier ueber zwei Drittel der Flaeche ist kein Spitzlicht,
sondern der sicherste Weg, jede Farbe blass zu machen.

DAS WASSERZEICHEN

Seine Deckkraft von sieben Prozent war ein Wert aus der Zeit, als das
Zeichen grau war -- mehr ging nicht, ohne dass es schmutzig aussah.
Eine Farbe darf lauter sein als ein Grau, weil sie zur Kachel GEHOERT.
Auf 14 Prozent verdoppelt, kraeftigere Linie, und ein leichter Schein
darunter fuer Tiefe.

15 Pruefungen gelaufen, alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 15:22:25 +02:00
DogFatherGitandClaude Opus 5 dbb19f69e9 Uhrmacherei statt Lack: guillochiertes Blatt, laufende Perle, Spiegelung auf Metall
Filipe: "ich will dass diese kachel komplett speziell ist, das
hochwertigste und geilste auf der ganzen website ... auch das gleiche
prinzip fuer die uhr, noch vieeeel spezieller. hol die besten skills
von den besten skills dafuer."

Also keine weitere Schicht Lack, sondern die Mittel, an denen man ein
teures Instrument WIRKLICH erkennt.

DIE UHR -- VIER MITTEL AUS DER UHRMACHEREI

  1. GUILLOCHIERTES ZIFFERBLATT. Guillochieren ist das Verfahren, mit
     dem seit zweihundert Jahren hochwertige Blaetter gemacht werden:
     Eine Maschine schneidet ein feines regelmaessiges Muster ins
     Metall, und weil jede Rille das Licht anders zurueckwirft, LEBT
     die Flaeche. Hier aus Strahlen vom Mittelpunkt und Ringen darum,
     beide bei vier Prozent Deckkraft -- wer das Muster einzeln
     erkennt, hat es zu laut gemacht.
  2. EIN AUFGESETZTER ZWOELF-INDEX. Auf einem echten Blatt ist die
     Zwoelf nie nur ein Strich wie die anderen: Sie ist das, woran das
     Auge sich ausrichtet. Ein Keil in Hausrot mit heller Kante.
  3. DIE PERLE AM KOPF DES SEKUNDENBOGENS. Sie laeuft einmal je Minute
     herum und ist das Einzige an der Uhr, das sich BEWEGT statt zu
     wachsen. Ein Bogen zeigt einen Stand, eine laufende Perle zeigt
     Leben. Sie springt im Sekundentakt statt zu gleiten -- ehrlicher
     (die Anzeige ist digital) und eine Bildberechnung je Sekunde statt
     sechzig.
  4. GRAVIERTE ZIFFERN. Ein dunkler Saum oben, ein heller unten -- das
     Lichtverhalten einer Vertiefung. Die Ziffern stehen damit IM Blatt
     statt darauf.

DIE KONSOLE -- DAS METALL FAENGT DAS LICHT

Auf den Kacheln leuchtet das Licht in der Farbe der Kategorie; dort ist
es ein Hinweis. Auf der Konsole waere das falsch -- ein farbiger
Schleier auf gebuerstetem Metall sieht aus wie eine Folie darauf.
Metall zeigt seine Form ueber die SPIEGELUNG: weiss, schmal, hart an
der Kante, und sie wandert mit dem Zeiger ueber die Fassung wie ein
Fenster, an dem man vorbeigeht. Erst dadurch sieht man, dass die
Fassung gewoelbt ist. Ein Standbild kann das nicht.

Dieselbe Falle wie heute Frueh dabei vermieden, diesmal vorher
bedacht: `.willkommen > *` haette dem Lichtelement wieder sein
`position: absolute` genommen -- jetzt `:not(.licht)`.

UND EIN FEHLER, DEN NUR DAS HANDY GEZEIGT HAT

Die Mulde der Uhr hing am Kasten daneben und war an dessen rechtem Rand
ausgerichtet. Am Rechner passte das; bei 412 px steht die Uhr mittig,
und die Mulde lag als dunkle Scheibe neben ihr. Sie entsteht jetzt aus
zwei Schattenringen der Uhr SELBST und ist damit konzentrisch bei jeder
Groesse -- die bessere Bauart, nicht nur die reparierte: Eine Fassung,
die man ausrichten muss, richtet irgendwann jemand falsch aus.

Zehn Pruefungen gelaufen, alle gruen. Rechner und Handy angesehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 15:00:59 +02:00
DogFatherGitandClaude Opus 5 532daa3edf Alles fertig: Konsole montiert, Tageskachel als Instrument, zwei Seiten repariert
DIE KONSOLE -- DREI STUFEN DRAUF

  1. VIER NIETEN in den vier Fasen. Das Einzige, was eine Flaeche
     endgueltig zu einem GEGENSTAND macht, ist die Frage, wie sie
     befestigt ist. Ein Gehaeuse haengt nicht in der Luft.
  2. EINE GEFRAESTE NUT trennt Text von Instrumenten -- dunkel auf der
     Lichtseite, hell auf der Schattenseite. Genau umgekehrt zu einer
     aufgemalten Linie, und deshalb sieht sie nach Material aus.
  3. DIE UHR SITZT IN EINER MULDE statt auf der Platte.

Drei Fehler dabei, alle im Bildschirmfoto gesehen: Die Nieten waren
QUADRATE (eine Hintergrundebene laesst sich nicht runden -- jetzt aus
Radialverlaeufen, die selbst rund sind). Die Mulde lag UEBER der Uhr
und hat die polierte Luenette zu mattem Grau gedaempft (`::after` wird
nach allen Kindern gezeichnet). Und das Raster musste von der
Nieten-Ebene herunter: Eine Ebene hat nur EINE Deckkraft.

DIE TAGESKACHEL "WAS IST DRAN"

Die drei Zeilen sind jetzt MODULE -- Fase, Kantenlicht in der Farbe
ihres Bereichs, Eckwinkel. Sie sind damit kleine Ausgaben derselben
Bauteile, zu denen sie fuehren, was sie ja auch sind. Die ZAHL wurde
zum gefassten Schild wie das Zeichen auf den Kacheln, und zwischen den
Haelften laeuft dieselbe gefraeste Nut wie auf der Konsole.

Ein Rueckschritt dabei, von der Pruefung sofort gemeldet: Ich hatte
die Ziffer weiss gemacht, weil das auf Metall gut aussieht -- damit
war ihre Aussage weg. Die Zahl traegt die Farbe ihres Bereichs und bei
etwas Ueberfaelligem die Warnfarbe; das ist die schnellste Auskunft der
ganzen Kachel. Die Farbe gehoert in die Ziffer, nicht ins Schild.

SPICY MEDIA SIEHT DIE ZAHLEN JETZT NIRGENDS

Vorher nur Kachel und Seite -- die Creator-Zahlen standen weiterhin im
Dashboard, weil das sie ueber eine eigene Schnittstelle holt. Die ist
jetzt zu (404 am Server, nicht in der Oberflaeche). Das Dashboard
bleibt fuer sie stehen: Es faengt den Fehlschlag ausdruecklich ab.
Mit Pruefung und Gegenprobe.

UND ZWEI SEITEN, DIE BEIM ANSEHEN AUFFIELEN

Das ist der Ertrag der Durchsicht jener zwoelf Seiten, die bisher nur
GEPRUEFT und nie ANGESEHEN worden waren:

  * chat.html und uebersicht.html luden kopf.js OHNE wahl.js. Der
    Umschalter "Meine Sicht" fiel dort auf das nackte Systemfeld
    zurueck: 92 x 19 px, grauer Kasten, Systemschrift -- auf allen
    anderen Seiten ist es ein selbst gebautes Bedienelement, hinter dem
    dasselbe Feld unsichtbar bei 2 x 2 px liegt. Kaputt war nichts. Es
    sah nur aus wie aus einem anderen Programm, und genau das findet
    keine Pruefung, die auf Fehlermeldungen achtet.
    Neue Pruefung: Wer kopf.js laedt, muss wahl.js laden -- und vorher.
  * Der Chat-Rahmen gehoerte als einzige grosse Flaeche noch nicht zum
    Modulsystem. Jetzt schon.

18 Pruefungen gelaufen, alle gruen. Rechner und Handy angesehen,
dazu Kalender, Chat, Automationen, Uebersicht, Start-Check,
Steckbrief, Bereiche, Profil, Content, Scouting und Report.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 14:31:14 +02:00
DogFatherGitandClaude Opus 5 90d5898640 Drei Stufen auf die Kacheln -- Fase, Rahmung, gefasstes Schild
Filipe: "perfektionier alle kacheln die du vorhin gewechselt hast auf
der ganzen website, mach sie alle noch geiler und geiler und noch
spezieller. sie gehen aber in eine gute richtung schon."

Alle drei Stufen sind FORM, keine neue Farbe -- das war die Lehre der
letzten Runden. Sie gelten fuer alle 35 Bauteile auf allen 18 Seiten,
weil sie in module.css stehen.

STUFE 1 -- DIE SCHRAEGE WIRD EINE ECHTE FASE

Bisher war die abgeschnittene Ecke ein Loch: Material, das fehlt. Eine
gefraeste Fase hat eine FLAECHE, und auf der liegt Schatten, weil sie
schraeg zum Licht steht. Ein Innenschatten aus der Richtung der
Schraege macht daraus ein bearbeitetes Werkstueck.

STUFE 2 -- ECKWINKEL AN DREI ECKEN STATT AN EINER

Eine einzelne Ecke liest sich als Verzierung, drei lesen sich als
RAHMUNG: Das Auge schliesst sie zu einem Ausschnitt. Die vierte bleibt
frei, dort sitzt die Fase -- ein Winkel auf einer abgeschnittenen Ecke
zeigte ins Leere.

STUFE 3 -- DAS ZEICHEN BEKOMMT EINE METALLFASSUNG

Die Plakette war ein abgerundetes Quadrat mit Farbschleier, also
dieselbe Form wie ueberall sonst im Netz. Jetzt ist sie ein gefasstes
Schild: dieselbe abgeschnittene Ecke wie ihre Karte, ein 2 px breiter
Ring aus gebuerstetem Metall, und die Kategoriefarbe INNEN. Damit
spricht die Anwendung EINE Materialsprache -- Konsole, Luenette der
Uhr und Schild sind dasselbe Metall.

ZWEI FEHLER DABEI, BEIDE GEMESSEN STATT VERMUTET

  * DIE RUNDUNG BLIEB. `.kachel[data-gross="ja"] .kachel__zeichen`
    setzt in start.css zweimal einen Radius (21 px, 18 px) und ist
    staerker als eine einzelne Klasse. Gemessen: 18 px, obwohl
    module.css 0 setzt und zuletzt geladen wird. Heraus kam ein Schild
    mit abgeschnittener Ecke UND runden Ecken. Das ist heute die
    dritte Spielart derselben Falle -- `:where()` war zu schwach,
    `body.start .willkommen` zu stark, hier ist es die
    Verschachtelung.
  * DIE FASSUNG WAR ZU GRELL. Fast weiss auf 2 px Breite las sich als
    Rahmen, der lauter ist als das Zeichen darin. Eine Fassung soll
    das Schild halten, nicht mit ihm konkurrieren -- dieselben Stopps,
    eine Blende dunkler.

18 Pruefungen gelaufen, alle gruen, keine mit gesunkener Anzahl.
Rechner und Handy (412 px) angesehen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 13:37:29 +02:00
DogFatherGitandClaude Opus 5 2acb6bc020 Das Maus-Licht ist zurueck, und die Begruessung ist keine Kachel mehr
DAS LICHT, DAS DEM ZEIGER FOLGT -- MEIN EIGENER FEHLER VON HEUTE FRUEH

Es war nicht geloescht. In module.css stand seit heute

    .kachel > * { position: relative; z-index: 1; }

damit der Inhalt ueber Raster und Kantenlicht liegt. Das Lichtelement
ist aber ein direktes KIND jeder Karte -- ihm wurde damit sein
`position: absolute` genommen. Aus einer Flaeche ueber der ganzen Karte
wurde ein leerer Inline-Span ohne Ausdehnung. Im Browser gemessen:
`display: inline`, obwohl in start.css `absolute` steht.

Merksatz dazu im Code: Eine Regel auf `> *` trifft auch das, was gar
kein Inhalt ist.

Zweiter, aelterer Fehler beim selben Thema, den erst die Pruefung
gefunden hat: Beim Wechsel von einer Kachel direkt auf die naechste
ging das Licht GANZ aus. `pointermove` der neuen Karte meldet einen
Bildaufbau an, `pointerout` der alten kommt danach und hat ihn
geloescht -- obwohl er gar nicht ihr gehoerte. Jetzt wird nur noch der
EIGENE Bildaufbau entwertet.

DIE BEGRUESSUNG FLIEGT AUS DER REIHE

Filipe: "diese hauptkachel muss komplett aus der rolle fliegen im
gegenzug zu den anderen ... AUCH MIT DER UHR RECHTS; WIE IN DER
BUISNESS HUB SEITE VON VANVAN."

Nachgesehen statt geraten: Auf VanVans Business-Hub gibt es keine Uhr.
Gemeint ist das `gate-medaillon` der Anmeldeseite -- ein runder
Kegelverlauf, der wie gebuerstetes Metall aussieht, gefasst in zwei
eingelassenen Ringen. Diese Bauart steht jetzt hier, weitergetrieben.

Die Begruessung ist keine Kachel mehr, sondern eine KONSOLE, und sie
unterscheidet sich in der FORM, nicht im Lack:

  * Sie ist BREITER ALS DIE SEITE -- sie tritt links und rechts ueber
    die Spalte hinaus, in der alle Kacheln stehen.
  * Sie ist ein ACHTECK. Die Module haben EINE abgeschnittene Ecke,
    sie hat VIER.
  * Sie hat eine METALLFASSUNG, laengs gebuerstet, mit je einer warmen
    und einer kuehlen Spiegelung.

Die Uhr ist von 124 auf 164 px gewachsen und hat eine echte Luenette:
10 px deckendes Metall, zwoelf eingravierte Stundenmarken, sechzig
feine Minutenstriche, Glaskuppe.

VIER FEHLER AUF DEM WEG DAHIN, ALLE IM BILDSCHIRMFOTO GESEHEN

  1. HALBDURCHSICHTIGES METALL ist kein Metall, sondern graues Glas.
     Stand gleichzeitig an Konsole und Uhr.
  2. KEGELVERLAUF AUF EINEM BREITEN BALKEN bewirkt nichts: Die ganze
     Oberkante liegt in wenigen Grad. Rund -> conic, lang -> linear.
     Die Verlaufsart muss zur FORM passen, nicht zum Material.
  3. DIE SKALA DER UHR WAR NIE SICHTBAR, seit es sie gibt. Ihre Maske
     rechnete Prozente auf die weiteste ECKE (116 px) statt auf den
     Radius (82 px) -- der Ring lag komplett ausserhalb der Uhr.
     `closest-side` behebt es. Eine unsichtbare Verzierung sieht aus
     wie gar keine, nicht wie ein Fehler.
  4. `body.start .willkommen` in start.css hat die neue Konsole
     ueberschrieben -- nicht ueber die Ladereihenfolge, sondern ueber
     die SPEZIFITAET (0,2,1 gegen 0,1,0). Derselbe Fehler wie mit
     `:where()` heute Frueh, nur andersherum: damals zu schwach
     geschrieben, hier zu stark stehen gelassen.

Der Ueberstand haengt an der Polsterung der Inhaltsspalte
(`min(34px, 3.6vw)`) statt an einer festen Zahl -- eine feste haette
auf dem Handy 17 px aus dem Bildschirm geragt.

UND EINE PRUEFUNG, DIE UNTER DEN BILDRAND GEZIELT HAT

pruef-start-ansicht meldete zwei Fehler am Licht. Das Licht war in
Ordnung: Die hoehere Konsole hatte Kachel 3 auf y = 1134 geschoben,
bei einem 1200 px hohen Fenster lag ihre Mitte unter dem Rand. Sie
rollt jetzt hin, misst danach neu -- und die Zahl der wirklich
gemessenen Kacheln steht in der Bedingung. 140 statt 137 Pruefungen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 13:03:16 +02:00
DogFatherGitandClaude Opus 5 ac432d85e1 Spicy Media: sieben stille Luecken -- und der Kalender zeigt wirklich nur noch Eigenes
Filipe hat drei Sachen gemeldet. Zwei davon waren nicht das, wonach sie
aussahen.

1. "BEI DER SPICY ROLLE IST DA EIN PROBLEM" (Creator-Profil laedt nicht)

Nicht diese Seite war kaputt. In NEUN Skripten stand dieselbe Zeile

    const LEITUNG = new Set(['admin', 'manager']);

und in keinem davon 'spicy'. profil.js nahm deshalb den Creator-Zweig
und lud das EIGENE Profil -- ein Spicy-Zugang ist kein Creator, also
404. Acht der neun sind nicht kaputtgegangen; sie haben sich still
falsch verhalten.

Die Liste steht jetzt EINMAL in bereiche.js. Beim Aufraeumen kamen mit
derselben Suche sechs weitere Luecken heraus, alle vom selben Typ:

  * Aufgaben abbrechen -- Server UND Knopf ohne 'spicy'
  * Teilen-Knopf in der Kopfleiste -- ohne 'spicy'
  * Chat: die Gespraechsliste laeuft ueber eine feste Rollenfolge.
    Wer nicht darin steht, taucht gar nicht auf -- eine Person, die es
    fuer die anderen nicht gibt.
  * Kalender: dieselbe Rollenfolge, dort landete Spicy Media durch
    indexOf() === -1 ganz oben statt an ihrem Platz.
  * Dashboard: "Creator anlegen" nur fuer admin/manager -- der Server
    haette sie gelassen, den Knopf hat sie nie gesehen.
  * Personenliste: ROLLENNAME ohne 'spicy'. Der Auffangwert
    `|| p.rolle` schrieb "spicy" statt "Spicy Media" -- plausibel
    genug, um jahrelang zu bleiben.

`pruef-css-klassen.mjs` verlangt jetzt, dass kein Workspace-Skript sich
wieder eine eigene Rollenliste baut. Mit Gegenprobe, dass der Sucher so
eine Liste auch wirklich findet.

2. "DIE ZAHLEN DIESE KATEGORIE NICHT SEHEN"

Kachel und Seite waren beim Anlegen der Rolle auf ["spicy","admin"]
gesetzt worden -- "dieselben Rechte ausser Automationen". Beides jetzt
auf DogFather allein.

3. "IN CIGDEMS KALENDER STEHT IMMER NOCH MEIN MANAGER MEETING"

Das war MEIN Denkfehler von heute Frueh, nicht ein vergessener Fall.
Ich hatte "geht alle an" als "kein Teilnehmer eingetragen" definiert --
also entschied der Server, was alle angeht, und nicht der, der den
Termin anlegt. Wer niemanden eintraegt, meint aber meistens nicht
"alle", sondern "mich".

Der Fall ist entfallen. Sichtbar ist ein Termin jetzt nur noch fuer
den, der ihn angelegt hat, dem er zugeordnet ist, der das Gegenueber
ist -- oder der in der Teilnehmerliste steht. Damit ist das Markieren
im Termin die einzige Antwort auf "wen geht das an": eine sichtbare
Entscheidung im Formular statt einer unsichtbaren Regel im Server.

Calls & Protokolle rufen dieselbe Funktion auf und koennen deshalb gar
nicht auseinanderlaufen -- das war Filipes vierter Wunsch, und er ist
mit derselben Zeile erledigt.

Am laufenden System als Cigdem nachgemessen: Profil laedt ("Profil:
Luna"), Zahlen-Kachel weg und Seite gesperrt, im Kalender NUR der
Termin, bei dem sie markiert ist, Calls zeigt genau denselben.

Fuenf Pruefungen auf die endgueltige Regel umgeschrieben statt
geloescht (sicht, spicy, teilnehmer, scout-zuteilung, css-klassen).
Die dritte Drehung bei scout-zuteilung steht mit allen drei Staenden
in der Akte -- eine geloeschte Pruefung hinterlaesst keine Spur davon,
dass hier einmal etwas anderes galt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 07:36:59 +02:00
DogFatherGitandClaude Opus 5 4eab64bd20 Eine neue Form fuer jedes Modul -- und der Kalender zeigt nur noch, was einen angeht
Filipe: "DU HAST WIEDER EINE KLEINE AENDERUNG UEBERALL GEMACHT ANSTATT
EINE RIESEN AENDERUNG." Er hatte recht, und der Grund war jedes Mal
derselbe: Ich habe das MATERIAL getauscht (Mattglas, Leuchtschiene,
Verlauf) und die FORM gelassen. Ein abgerundetes Rechteck bleibt ein
abgerundetes Rechteck -- und die Silhouette ist das Einzige, was man aus
fuenf Metern erkennt.

Jetzt ist die Form eine andere: abgeschnittene Ecke oben links
(clip-path, echte Silhouette), ein Kantenlicht in der Kategoriefarbe
darauf, Eckwinkel unten rechts, ein feines Raster statt Koernung.
35 Bauteile auf allen 18 Seiten, in einer eigenen Datei (module.css).

DREI DINGE, DIE DABEI SCHIEFGINGEN UND JETZT ABGESICHERT SIND

1. Die Regeln standen in :where() -- Spezifitaet null, also gewann jede
   aeltere .kachel::before-Regel. Jetzt :is().
2. module.css stand an DRITTER Stelle im Ladeweg. Auf Calls,
   Automationen, Bereich und Dateien hat sie damit gar nichts bewirkt:
   Die Seitendateien setzen dort selbst border-radius und box-shadow und
   kommen spaeter. Genau das ergab wieder "ueberall ein bisschen". Sie
   wird jetzt als LETZTE geladen, geprueft auf allen 18 Seiten.
3. Die Klassenliste steht siebenmal in der Datei (CSS kennt keine
   Variable fuer Selektoren). Eine vergessene Kopie faellt niemandem
   auf -- pruef-css-klassen vergleicht sie deshalb alle, mit Gegenprobe.

DER KALENDER: NUR NOCH, WAS EINEN ANGEHT

Filipe: "calls oder termine soll jeder nur sehen die er selber macht
oder jeden betrifft." Das gilt auch fuer DogFather, und das ist die
eigentliche Aenderung -- er bekam bisher 1=1. "Jeden betrifft" heisst:
ohne Gegenueber und ohne Teilnehmerliste. Wer niemanden eintraegt, meint
alle. Die Rollenfrage entfaellt im Kalender damit vollstaendig.

SECHS PRUEFUNGEN, DIE EINE WELT GEMESSEN HABEN, DIE ES NICHT MEHR GIBT

Alle sechs wurden auf die neue Regel umgeschrieben, keine geloescht --
loeschen haette die Zahl gesenkt und den neuen Weg ungeprueft gelassen:
ics, serien, sicht, spicy, teilnehmer, tagesblick, team.

UND VIER ECHTE FUNDE, DIE DABEI HERAUSFIELEN

* pruef-workspace-seiten war seit dem Bildumbau von heute Frueh auf
  ALLEN 32 Seiten rot: Sie verlangte noch das eine Motiv. Die neue
  Bedingung ist schaerfer als beide alten -- das geladene Bild muss zu
  dem Merkmal passen, das die Seite selbst traegt. Und die Meldung sagt
  jetzt, WELCHE Bedingung gefallen ist.
* pruef-leistung-optik hat sich selbst ausgesperrt (meldete sich als
  Manager an, der die Zahlen seit Filipes Anweisung nicht mehr sehen
  darf) und stuerzte danach ab: 2 Pruefungen statt 56. Der Absturz hat
  verdeckt, dass sie sieben Fingerziele als "zu klein" meldete -- es
  waren die unsichtbaren Knoepfe der zugeklappten Woche, 0x0.
* personen.html beim Manager: Der Erklaersatz ("Codes, Sperren und das
  Protokoll bleiben bei DogFather") kam nie an -- das Element gab es
  nicht, und das && davor hat den Fehlgriff verschluckt. Die Liste stand
  ausserdem dauerhaft auf aria-busy="true": fuer einen Screenreader lud
  die Seite fuer immer.
* pruef-schranke hielt personen.html noch fuer DogFather-only. Die Seite
  wechselt jetzt die Erwartung, statt aus der Pruefung zu verschwinden:
  Seite auf fuer die Leitung, Verwaltungsdaten dahinter weiterhin zu.

Die Anmeldeseite wurde nicht angefasst (nur ihr Versionsstempel).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 07:12:48 +02:00
DogFatherGitandClaude Opus 5 e8478c9cae Spicy sieht DogFathers Sachen nicht mehr -- und sechs Fehler dazu
VIER DINGE AUS DEN BILDSCHIRMFOTOS, jedes ein echter Fehler:

1. SPICY MEDIA SAH DOGFATHERS DATEN. Beim ersten Anlauf bekam die Rolle
   dieselbe Regel wie DogFather (`1=1`) -- damit stimmte der Ueberblick
   ueber Manager, Scouts und Creator, und nebenbei standen seine eigenen
   Termine, Aufgaben, Dateien und Eintraege mit drin. Jetzt gibt es
   ohneDogFather() als EINE Stelle dafuer: Zwei Spalten werden geprueft,
   `creator_id` (um wen geht es) und `erstellt_von` (wer hat es
   geschrieben) -- ein Termin, den er sich selbst anlegt, haengt nur an
   der zweiten. `IS NULL OR NOT IN` und nicht bloss `NOT IN`: In SQL ist
   `NULL NOT IN (...)` weder wahr noch falsch, die Zeile fiele
   stillschweigend heraus.

2. "PERSOENLICHER ZUGANGSCODE · undefined" auf der Anmeldeseite. Eine
   zweite Namensliste im Browser, die beim Hinzufuegen der Rolle
   niemand gepflegt hat. Ein unbekannter Schluessel faellt jetzt auf
   sich selbst zurueck statt auf `undefined` -- haesslich, aber
   sichtbar.

3. SPICY KAM NICHT IN DIE PERSONENVERWALTUNG. Der Server liess sie
   herein, das Skript warf sie wieder hinaus: zwei Listen fuer dieselbe
   Frage, gepflegt wurde nur die erste.

4. DIE ANMELDEKARTE WAR ZU KLEIN FUER FUENF ROLLEN. Der Kommentar an
   genau dieser Stelle warnt woertlich davor -- und ich habe getan,
   wovor er warnt: eine Rolle eingefuegt und die Zahl daneben nicht
   angefasst. Gemessen: Inhalt 573 px in einer 526 px hohen Tafel, die
   Fusszeile stand unter dem Rahmen. Schrift kleiner half nicht (sie lag
   schon auf dem Anschlag), also sind die Abstaende an neun Stellen
   enger. Nachgemessen auf fuenf Groessen: passt ueberall.

DIE ZEIT WAR WIRKLICH FALSCH. Nicht nur in meinem Satz: `datum()` in
personen.js schnitt die ISO-Zeichenkette ab -- und die ist UTC. Im
Protokoll stand 03:00, wo 05:00 war. Das Tueckische daran ist, dass es
nie kaputt aussieht: Eine Uhrzeit ist immer plausibel.

PROFILBILDER WERDEN JETZT GEZEICHNET. Der Server lieferte sie seit
gestern mit, gezeichnet wurden sie nirgends -- deshalb aenderte sich
nichts. Jetzt in der Personenauswahl (Aufgaben, Termine, Dateien,
Bereiche), in der Gespraechsliste und an jeder Nachricht. Der
Anfangsbuchstabe bleibt als Unterlage LIEGEN: Faellt das Bild aus, steht
dort weiter etwas Sinnvolles.

DER CHAT: Gesichter mit Rollenfarbe, Blasen mit Richtung (die erste
einer Folge eckig, die naechsten rund -- so sieht man, wo ein Gedanke
anfaengt), das offene Gespraech mit Schiene, Ungelesenes hervorgehoben,
und das Eingabefeld in einer eigenen Leiste, die sich beim Schreiben
hebt.

ZWEI EIGENE PATZER, beide von Pruefungen gefunden:
  - `o is not defined`: Mein Suchmuster hat die zwei Zeilen fuer das
    Bild ans DATEIENDE gesetzt statt in die Schleife -- und in
    kalender.js an einen <span> statt ans <option>. Gemeldet von
    pruef-sicht, das die Browserkonsole mitliest.
  - Ein Kommentar mit `bild` in schraegen Anfuehrungszeichen stand INNEN
    in einer Vorlagenzeichenkette und hat sie geschlossen. Die halbe SQL
    wurde zu Programmtext.
Dazu: `.chat-neu` gibt es nicht (heisst `.chat__eingabe`), und der
Rollenknopf hatte fuer den Manager keinen sichtbaren Fokus -- ein
box-shadow wird von `overflow: hidden` abgeschnitten, ein outline nicht.

Gruen: spicy (43), creator-anlegen (29), personen-liste (33), sicht (48),
chat (48), chat-optik (24), buehne (38), struktur (32), css-klassen (15),
handy (59), breiten (23), formulare (19), start-ansicht (136),
lesbarkeit (14), barrierefrei (18), tempo (8), kopf-messen (3),
glocke (26), haerte (20), manager-sicht (43), alle-wege (19),
aufgabenbrett (44), kalender (84).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 05:46:19 +02:00
DogFatherGitandClaude Opus 5 3b356d6eef Ein Material fuer die ganze Website -- und die Uhr wird zum Chronographen
DIE UHR: Sekunde nach AUSSEN, Minute in die Mitte, Stunde nach innen
(Wunsch Filipe). Das ist die Anordnung eines Chronographen und nicht die
eines Fortschrittsbalkens: Der schnellste Zeiger laeuft auf der
laengsten Bahn, weil man Bewegung dort am besten sieht -- der langsamste
innen, wo eine kleine Drehung viel bedeutet. Die drei Umfaenge sind
mitgewandert; ein vertauschter Ring ohne vertauschte Zahlen endet nie
dort, wo er soll.

EIN MATERIAL FUER ALLE SEITEN. Die Startseite hatte seit heute
beleuchtete Platten, die anderen sechzehn Seiten flache Rechtecke -- man
wechselte die Seite und fiel aus einer Oberflaeche in eine andere. Ich
habe das bisher Seite fuer Seite nachgezogen, und genau deshalb war es
nie fertig: Es sind FUENFUNDVIERZIG Stellen.

Jetzt EINE Regel. Die Klassenliste ist nicht erfunden, sondern gemessen
-- es sind genau die, die `var(--flaeche)` als Kartenflaeche benutzen.
`:where()` ist der Kniff dabei: Spezifitaet null, also ueberschreibt die
Regel nichts, was eine Seite selbst festlegt. Eine Warnkarte bleibt rot,
eine Spalte behaelt ihre Statusfarbe. Ohne das haette ich an dreissig
Stellen `!important` gebraucht.

DREI FUNDE DER PRUEFUNGEN, alle berechtigt:

1. `.profil-gruppe` gibt es nicht -- ich hatte den Namen aus dem Kopf
   geschrieben statt aus der Datei. pruef-struktur meldete totes CSS.
   Die Karten auf profil.html heissen `.gruppe`, und genau der Name darf
   NICHT in die Liste: Auf der Startseite heissen die Kachelgruppen
   ebenso und haetten ploetzlich eine Kartenflaeche.

2. Der erste Verlauf war HELLER als das, was er ersetzt. Ein Material,
   das die ganze Website aufhellt, hellt auch jeden Text darauf auf --
   und das faellt an der leisesten Schrift zuerst auf.

3. `.gruppe__unter` stand auf 4,21:1. Und das ist der interessante Fall:
   Die Farbe war nicht schuld, eine VERSCHIEBUNG war es. Mit der fuenften
   Rolle rutschte auf personen.html alles eine Zeile nach unten, und die
   Zeile landete auf einer helleren Stelle des Buehnenbilds. Sie ist die
   einzige Beschriftung ohne Karte -- ein Text, dessen Untergrund ein
   FOTO ist, bekommt nicht den leisesten Ton. Jetzt 5,51:1.

Der zweite Fund fiel nur auf, weil die Zahl sich nach meiner ersten
Korrektur KEIN Stueck bewegte (zweimal exakt 4,21) -- dasselbe Zeichen
wie schon zweimal heute: falsche Stelle, nicht zu wenig.

Gruen: buehne (38), css-klassen (15), struktur (32), handy (59),
breiten (23), start-ansicht (136), lesbarkeit (14), tempo (8),
personen-liste (33).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 05:14:01 +02:00
DogFatherGitandClaude Opus 5 68bc116c36 Die Rolle "Spicy Media" -- und drei Fehler, die nur ihre Pruefung fand
DIE PERSONENTABELLE WURDE NEU GEBAUT. Eine Rolle ist ein erlaubter Wert
in einer Spalte, und der steckt in einem CHECK -- den kann SQLite nicht
aendern. Auf `personen` zeigen ZWEIUNDFUENFZIG Fremdschluessel.

Deshalb wird der Bauplan NICHT abgeschrieben, sondern gelesen: Der
CREATE-Text kommt aus sqlite_master, darin wird ausschliesslich die
Rollenliste ersetzt, und die Kopierliste kommt aus PRAGMA table_info.
Die beiden aelteren Umstellungen schreiben ihre Spalten von Hand ab --
`personen` hat seit damals SIEBEN dazubekommen (bild, ueber_mich,
tiktok ...). Wer hier abschreibt, verliert alle Profilbilder.

ZWEI FRAGEN, DIE MAN AUSEINANDERHALTEN MUSS:
  siehtAlles()   = DogFather ODER Spicy Media -> Listen, Uebersichten
  istDogFather() = nur DogFather              -> loeschen, Rollen, Codes
Es waere weniger Arbeit gewesen, istDogFather() um "spicy" zu erweitern
-- und genau das waere der Fehler: Spicy Media koennte dann DogFather
loeschen.

DER CHAT BRAUCHTE NICHTS. Er haengt allein an der Teilnehmerliste und
kennt kein "das Management sieht alles". Spicy Media sieht fremde
Gespraeche nicht, weil es dafuer keinen Weg gibt -- nicht, weil eine
Abfrage es verbietet.

DREI ECHTE FEHLER, alle von pruef-spicy gefunden, keiner vorher sichtbar:

1. MEIN EIGENER KOMMENTAR STAND IM BAUPLAN. SQLite hebt den CREATE-Text
   woertlich auf, samt Kommentaren. Ich hatte "'spicy' steht HIER mit
   drin" hineingeschrieben -- und die Erkennung suchte genau dieses Wort
   im ganzen Text. Ergebnis: Die Umstellung hielt die Tabelle fuer
   erledigt, obwohl die CHECK-Regel noch die alte war. Jetzt wird die
   Regel herausgeschnitten und NUR darin gesucht; der Kommentar steht
   ausserhalb des SQL.

2. DER SICHERUNGSNAME HATTE NUR MINUTEN. `VACUUM INTO` weigert sich, eine
   vorhandene Datei zu ueberschreiben -- zu Recht. Zwei Umstellungen in
   derselben Minute wollten in dieselbe Datei, die zweite scheiterte, und
   weil ohne Sicherung nicht umgestellt wird, blieb sie aus. Es sah nach
   "lief" aus (die Datei lag ja da) und war keine. Jetzt mit Sekunden.

3. EINE FRISCHE DATENBANK LEGTE DIE ALTE ROLLENLISTE AN und stellte beim
   allerersten Start sofort um -- Tabelle neu bauen, Sicherung schreiben,
   fuer nichts. Ein Bauplan, der sofort umgebaut werden muss, ist der
   falsche.

Und ein vierter in der Pruefung selbst: Der Chat-Aufbau benutzte einen
falschen Weg, das Gespraech entstand gar nicht -- "Spicy Media sieht 0
Gespraeche" war trotzdem gruen, weil es keine gab. Jetzt ist das Anlegen
selbst eine Pruefung, und eine Gegenprobe zeigt, dass Max es sehr wohl
sieht.

DAZU: Manager sehen die Kachel "Personen & Zugaenge" -- die SEITE geht
auf, die Schnittstellen nicht. Alles unter /verwaltung haengt weiter an
`nurAdmin` und antwortet 404; sie sehen genau den Teil, fuer den es
einen Weg gibt. Spicy Media legt Creator UND Manager an (zweite enge
Tuer, Rolle steht auch dort nicht im Aufruf; ein Manager kommt durch
sie nicht). Der Rollentext des Managers stimmte nicht mehr -- er legt
jetzt Creator an.

pruef-spicy: 36 Pruefungen, alle gruen. Ausserdem gruen: personen-liste
(33), creator-anlegen (29), sicht (48), css-klassen (15), alle-wege (19),
haerte (20), manager-sicht (43).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 04:56:07 +02:00
DogFatherGitandClaude Opus 5 4bb5afc942 Drei Ringe, klappbare Gruppen -- und die Calls-Seite endlich wirklich umgebaut
DU HATTEST RECHT (Bildschirmfoto 3). Beim letzten Mal habe ich an der
Calls-Seite nur das MATERIAL der Karten getauscht und die Aufstellung
gelassen. Drei Gruppen untereinander, und weil "Steht an" 27 Eintraege
hat, lagen die beiden anderen ausserhalb des Bildes -- man SAH die
Aenderung gar nicht, weil man nie so weit kam. Das war Lackieren, kein
Umbauen.

JETZT EIN BRETT AUS ZWEI SPALTEN. Die Gruppen sind eigenstaendige Tafeln
in einem Raster; "Protokoll fehlt" (kurz, dringend) und "Festgehalten"
(Archiv) liegen NEBEN der langen Liste statt darunter. `align-items:
start` ist dabei der Punkt: Ohne ihn waeren alle Tafeln so hoch wie die
hoechste, und neben der langen Liste stuenden zwei fast leere Kaesten.
Welche Tafel wo landet, entscheidet die Breite und nicht das Skript --
eine festgeschriebene Spalte waere eine Zahl, die beim naechsten Fenster
falsch ist.

Jede Tafel klappt zu, und der Zustand wird gemerkt. Vorgabe: "Festgehalten"
ist zu -- es ist das Archiv; wer die Seite oeffnet, will wissen, was
ansteht.

DIE GRUPPEN AUF DER STARTSEITE genauso. Der Kopf IST der Schalter, nicht
ein Dreieck daneben: Die ganze Zeile ist ein Ziel von 40 Pixeln statt
eines von vierzehn. <button> statt <div>, damit Tastaturbedienung und
Ansage nicht mit tabindex und role nachgebaut werden muessen. Gemerkt
wird je Gruppe UND je angesehener Rolle -- DogFather, der sich einen
Creator ansieht, hat dort eine andere Aufteilung im Kopf.

DIE UHR: drei Ringe statt zwei. Aussen die Stunde in Schwarzsilber, in
der Mitte die Minute in Blau, innen die Sekunde in Rot -- von aussen nach
innen immer schneller, so liest man eine Uhr ohne nachzudenken.

UND SIE IST SCHARF. Kein blur(), kein drop-shadow mehr auf den Boegen --
an der alten lag beides drauf, und der Vorwurf stimmte. Der Glanz kommt
jetzt aus dem VERLAUF: Echtes Metall glaenzt nicht, weil es leuchtet,
sondern weil es das Licht abwechselnd hell und dunkel zurueckwirft. Fuenf
Stopps statt zwei -- ein zweifarbiger Verlauf waere ein Farbverlauf,
erst der Wechsel ist Metall. Dazu `shape-rendering="geometricPrecision"`
(sonst rastert der Browser duenne Boegen grober) und Kappen auf `butt`
statt `round`: Eine runde Kappe steht ueber das Ende hinaus, bei null
Sekunden saehe man trotzdem einen Punkt.

Minute und Stunde laufen WEICH mit: die Minute bekommt die Sekunden
anteilig, die Stunde die Minuten. Ein Minutenring, der einmal pro Minute
springt, sieht aus wie eine haengende Anzeige.

Gruen: css-klassen (15), call-kategorien (17), start-ansicht (136),
handy (59), breiten (23), buehne (38), struktur (32).

NOCH OFFEN: der neue Kachelstil fuer die ganze Website und die Rolle
"Spicy Media".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 04:39:32 +02:00
DogFatherGitandClaude Opus 5 49bd4a7cec Manager legen Creator an -- eine neue Tuer statt eines Schluessels fuer die alte
Filipe: "wieso greift das in die rechte rein? ist doch ok, die sollen
einfach paar leute selber hinzufuegen koennen." Er hat recht, und ich
hatte zwei Dinge in einen Topf geworfen: Das hier braucht KEINE
Datenbankaenderung -- nur die Rolle "Spicy Media" braucht eine.

WARUM EIN EIGENER WEG UND NICHT DIE ALTE TUER

Alles unter /workspace/api/verwaltung haengt an EINER Schranke
(nurAdmin). Dahinter liegen acht Wege: Rollen aendern, Codes neu setzen,
sperren, loeschen, Protokoll lesen. Einen Manager dort hineinzulassen und
danach in jedem der acht einzeln zu pruefen, was er darf, ist genau die
Bauweise, durch die am 31.08.2026 ein Loch entstanden ist -- zwei von
drei Stellen abgesichert, die dritte vergessen.

Deshalb bleibt die Tuer zu, und daneben steht eine neue mit genau einem
Zweck: POST /workspace/api/creator-anlegen. Sie kann nichts anderes, als
einen Creator anzulegen -- nicht weil eine Abfrage es verbietet, sondern
weil es hier keinen anderen Weg gibt. Unterschied zwischen "darf nicht"
und "kann nicht".

DIE ROLLE STEHT NICHT IM AUFRUF, sie wird im Server gesetzt. Ein Feld
`rolle` im Koerper waere die naheliegende Loesung und die falsche: Dann
muesste eine Abfrage sie pruefen, und eine vergessene Abfrage ist ein
zweiter Zugang mit vollen Rechten. Geprueft wird deshalb nicht, dass ein
mitgeschicktes `rolle: "admin"` abgelehnt wird, sondern dass es
WIRKUNGSLOS ist.

DIE ZUTEILUNG PASSIERT SOFORT. Ein Creator ohne Betreuung ist fuer alle
ausser DogFather unsichtbar -- der Manager haette ihn angelegt und
danach nicht mehr gesehen. Wer anlegt, betreut; ein eigener Scout kann
mitgegeben werden. Eine FREMDE Scout-Nummer wird abgelehnt (403) und
nicht stillschweigend auf den Anleger zurueckgesetzt: Sonst glaubte der
Manager, er haette zugeteilt.

Der Knopf sitzt auf dem Dashboard, nicht in der Personenverwaltung --
dort kommt ein Manager gar nicht hinein, und hier sieht er seine Creator
ohnehin. Der Zugangscode steht einmal im Dialog und wird nie nachgeladen;
deshalb schliesst sich das Fenster NICHT von selbst.

pruef-creator-anlegen.mjs, 29 Pruefungen, alle gruen -- und die Haelfte
davon prueft, was NICHT geht: Personenverwaltung 404 fuer Manager, Scout
und Creator kommen gar nicht erst durch, fremder Scout 403 (und der
Creator wird dabei gar nicht erst angelegt), erfundene Nummer 403. Zwei
Manager mit je einem eigenen Scout, weil sich "nur die eigenen" mit nur
einem Manager gar nicht pruefen laesst.

Nebenbei: .feld-hinweis ist von bereich.css nach aufgaben.css gewandert
(zu den uebrigen Formularstilen) -- ein Formularbaustein in der
Bereichsdatei ist nur so lange richtig, wie ihn keine zweite Seite
braucht.

Gruen: creator-anlegen (29), personen-liste (33), css-klassen (15),
struktur (32), formulare (19).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 04:25:49 +02:00
DogFatherGitandClaude Opus 5 4447a653e7 Die Uhr wird ein Gegenstand -- Rot x Babyblau, und start.css wird geteilt
DIE UHR. Filipe: "viel viel viel viel viel viel viel spezieller ... eine
mischung von rot und babyblau". Was eine Uhr teuer aussehen laesst, ist
nicht die Farbe, sondern das GEHAEUSE -- bei einer echten sieht man drei
Schichten uebereinander: einen Metallrand, der das Licht von oben faengt,
eine VERTIEFTE Scheibe darin, und ein Glas darueber, das spiegelt. Genau
die drei sind jetzt gebaut.

Die beiden Farben sind nicht aus dem Farbkasten: Rot ist Spicy Media,
Babyblau ist DogFather -- dieselben zwei, die im Kopf der Anmeldekarte
nebeneinanderstehen und im Motiv den Neonrahmen bilden. Zwei Verlaeufe,
absichtlich GEGENLAEUFIG (Stundenring rot->blau, Sekundenring blau->rot):
Wo der eine warm ist, ist der andere kuehl, so bleiben sie
auseinanderzuhalten, wo sie sich ueberlagern.

Dazu: eine Skala aus sechzig Strichen, jeder fuenfte kraeftiger (aus
einem Kegelverlauf, nicht aus sechzig Elementen); ein leuchtender Kopf,
der am Ende des Sekundenbogens mitlaeuft -- die einzige Stelle, an der
sich sichtbar etwas bewegt; und die Mischung IM Text als zwei Schatten
statt als Verlaufsschrift (background-clip: text waere im Windows-
Kontrastmodus unsichtbar). Die Glocke bekommt dasselbe Gehaeuse, nur
kleiner -- zwei runde Dinge aus verschiedenem Material sehen
zusammengesucht aus.

PROFILBILDER: /api/personen lieferte nur id, name, rolle. Deshalb konnte
KEINE Oberflaeche ein Gesicht zeigen, auch wenn eines hochgeladen war --
der Fehler lag nicht in der Anzeige, sondern in der Schnittstelle.
Jetzt kommt die fertige Bildadresse mit (nicht der Dateiname: sonst
setzt jede Stelle im Browser denselben Pfad zusammen). Und DogFather ist
fuer alle sichtbar -- Name, Rolle, Bild, sonst nichts; seine Eintraege,
Chats und Zahlen haengen weiter an den eigenen Regeln der Module.

start.css GETEILT statt gekuerzt. Sie lief mit 202 KB wieder in die
200-KB-Grenze, und diesmal war Kuerzen die falsche Antwort: Dreizehn
Seiten laden diese Datei, Uhr und Begruessungskachel braucht genau EINE.
Also heim.css -- 184 KB statt 202, und zwoelf Seiten laden 14 KB
weniger. Vorher mit grep nachgesehen, dass `uhr`, `willkommen` und
`glocke-platz` in keiner anderen HTML-Datei vorkommen.

ZWEI FUNDE DER PRUEFUNGEN, beide berechtigt:
  - `.glocke--kachel` musste zurueck nach start.css. glocke.js laeuft auf
    ALLEN siebzehn Seiten und kann die Klasse ueberall setzen; die Regel
    gehoert dorthin, wo das Skript sie brauchen KANN, nicht dorthin, wo
    es sie heute zufaellig braucht.
  - Die Sekundenanzeige stand auf 10,88 px (Grenze 11,5). Gesperrte
    Ziffern in Versalhoehe wirken kleiner als die Zahl sagt -- auf
    11,84 px.

Gruen: css-klassen (15), struktur (32), sicht (48), buehne (38),
start-ansicht (136), handy (59), aufgabenbrett (44).

NOCH OFFEN aus derselben Nachricht: die Calls-Seite komplett umbauen mit
Auf-/Zuklappen ueberall, die Profilbilder auch WIRKLICH ueberall
zeichnen (die Daten sind jetzt da), die Rolle "Spicy Media" und
Manager-legt-Creator-an.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 04:18:27 +02:00
DogFatherGitandClaude Opus 5 8f8c283a1a Kacheln werden ein Raster -- dritter Anlauf, diesmal die FORM
Filipe zweimal davor: "das ist genau das gleiche" und "sorry aber ich
glaub du verstehst nicht was ich meine". Er hatte beide Male recht, und
ich weiss jetzt warum: Ich habe zweimal die OBERFLAECHE geaendert
(Mattglas, dann Leuchtschiene) und beide Male die FORM gelassen -- eine
breite Zeile, Zeichen links, Text daneben. Wer eine Zeile umlackiert,
bekommt eine lackierte Zeile.

AUS DREI BREITEN ZEILEN WIRD EIN RASTER AUS SECHS KARTEN.
Hochformat, Zeichen oben, Name unten, Schiene von links nach OBEN
gewandert (an einer hochkanten Karte wuerde ein Lichtbalken links sie
optisch halbieren). Die Zahl steht als Marke oben rechts statt in der
Namenszeile, der Pfeil unten rechts. `data-gross="ja"` behaelt das
Querformat -- so hebt sich die Kachel WIRKLICH ab, statt nur breiter zu
sein. Bei 1380 px passen jetzt sechs Karten nebeneinander statt drei.

BILDER: Kontrast 1,08 -> 1,14, Saettigung 1,10 -> 1,26, Glanz 0,34 ->
0,46, dazu ein neuer Durchgang "Tiefe" -- eine S-Kurve auf der
Helligkeit. Das ist NICHT mehr Kontrast: Kontrast dehnt alles gleich und
frisst Zeichnung in den Lichtern; die S-Kurve laesst die Mitte in Ruhe
(dort sitzt das Motiv) und arbeitet nur an den Enden. Gerechnet auf dem
Maximum der drei Kanaele, nicht je Kanal -- sonst wandert der Farbton
(ein dunkles Rot wuerde braun).

ANMELDESEITE: "Dogfather Universe" -> "SpicyMedia x DogFather" (das
Kreuz kleiner und leiser, sonst liest man drei Namen statt zwei), und
der Satz darunter nennt jetzt Manager, Scouts und Creator von Spicy
Media -- ohne DogFather.

ZAHLEN nur noch fuer DogFather. Beides zusammen, nicht nur die Kachel:
Eine Kachel ist ein Weg, keine Schranke -- wer die Adresse kennt, waere
weiterhin hineingekommen. Also auch in der Rechteliste auf ["admin"].

AUFGERAEUMT, weil pruef-struktur zu Recht rot wurde: start.css lief mit
202 KB in die 200-KB-Grenze. Der Grund war echter Ballast -- die Datei
trug DREI Generationen Kacheldesign uebereinander. Die ueberholten
Regeln sind weg (nur was der neue Entwurf nicht selbst setzt, bleibt),
der Entwurfstext dazu auf seine Lehre gekuerzt. 198,7 KB, und wichtiger:
nur noch EINE Stelle, an der eine Kachel beschrieben wird.

Gruen: buehne (38), css-klassen (15), leistung (50), start-ansicht (136),
handy (59), breiten (23), struktur (32).

NOCH OFFEN aus derselben Nachricht: die neue Rolle "Spicy Media" und die
Aenderung, dass Manager Creator anlegen duerfen. Beides greift in die
Rechte und in die CHECK-Regel der Personentabelle ein -- das kommt als
eigener Schritt mit Sicherung und eigener Pruefung, nicht nebenbei.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 03:59:16 +02:00
DogFatherGitandClaude Opus 5 1b2874299e Uhr und Glocke in die Begruessung, Teilen in die Leiste, ein echter Fehler weg
Neun Punkte aus Filipes Bildschirmfotos. Der wichtigste war kein
Aussehen, sondern ein Fehler:

UEBEREINANDERLIEGENDE TEXTE IN DER SICHERUNGSLISTE. Das Datum entstand
aus `name.split('-').slice(1).reverse().join('.')`. Bei
"woechentlich-2026-09-06.db" ging das gut; die Sicherungen vor einem
Umbau heissen aber "vorher-2026-09-02-160012438.db" -- mit Zeitstempel.
Heraus kam "160012438.02.09.2026", dreimal so lang wie die 96-px-Spalte,
und es lief ueber den Nachbartext. Ein Muster, das Bestandteile ZAEHLT
statt sie zu SUCHEN, bricht beim ersten Namen mit einem Teil mehr. Jetzt
ein Suchmuster nach vier-zwei-zwei Ziffern -- und in der CSS eine
Kuerzung, damit der NAECHSTE zu lange Text nur abgeschnitten wird. Eine
Spalte mit fester Breite ohne Kuerzung ist immer eine Zeitbombe.

DIE BEGRUESSUNGSKACHEL. Runde Digitaluhr rechts: zwei Ringe um dieselbe
Mitte -- innen die Sekunde, aussen der Stand der Stunde. Kein
setInterval(1000): Ein fester Takt laeuft mit der Zeit aus dem Tritt und
ueberspringt Sekunden; gewartet wird bis zur naechsten VOLLEN Sekunde.
Die Glocke ist aus der Kopfleiste hierhergezogen -- mit Rueckfall, denn
zwoelf andere Seiten haben diesen Platz nicht. Nebenbei ist die Leiste
damit um ein Element leichter; sie ist am 06.09. schon einmal an einem
sechsten zerbrochen.

TEILEN-KNOPF in der Leiste, nur fuer Scout, Manager und DogFather.
Geteilt wird der EINGANG, nicht die aktuelle Seite: Ein Link auf
bereich.html?b=schutz schickt jemanden auf eine Seite, die er nicht
sehen darf. Wo es navigator.share gibt, wird es benutzt; sonst
Zwischenablage; wo beides fehlt, erscheint der Knopf gar nicht -- ein
dritter Ausgang statt einer Schaltflaeche, die nichts tut.

WEITER: Kachelreihenfolge Steckbrief -> Profile -> Zahlen. Die
Tagesliste laesst sich zuklappen und zeigt dann SIEBEN Tage (die Woche,
nicht die vier von ueberall sonst). Dialoge, Automationen-Karten,
Sicherungsblock, KI-Kasten und Call-Karten bekommen dasselbe Material
wie die Kacheln -- Leuchtschiene, Materialstaerke, Glanz.

Profilbilder brauchten nichts: Der Weg gibt es fuer jede Rolle bereits
(steckbrief.html fuer die Betreuung, derselbe Block auf profil.html fuer
Creator, Hochladen schreibt immer auf req.person.id).

ZWEI EIGENE FEHLER, beide gemessen statt vermutet:
  - Die Koernung lag in vier neuen Bloecken auf DERSELBEN Ebene wie die
    Spiegelung und erbte deren 50 % Deckkraft. Gemessen rgb(56,44,58)
    statt rgb(20,26,38) -- die Karten sahen durchsichtig aus, obwohl sie
    zu 95 % decken. Derselbe Fehler wie heute Nachmittag an der
    Anmeldekarte. Koernung gehoert auf eine eigene Ebene mit overlay.
  - `.glocke-platz:empty { display: none }` liess die Kachel wachsen,
    sobald die Glocke geladen war. Layout-Sprung von start.html: 0,708.
    Platz wird jetzt reserviert -> 0,473.

pruef-struktur: `-breit` gehoert in die Stufen-Ausnahme. Schaerfe kostet
Bytes (hohe Frequenzen lassen sich nicht wegrechnen), die mittlere Stufe
wuchs auf 230-300 KB. Die Regel bleibt inhaltlich: gross nur, WENN eine
kleinere Stufe daneben steht. Die Verkettung der beiden replace() waere
ein stiller Fehler gewesen -- fuer uhd haette sie nach `-schmal` gesucht.

Gruen: kopf-messen (3), breiten (23), glocke (26), css-klassen (15),
struktur (32), buehne (38), start-ansicht (136), handy (59),
formulare (19), barrierefrei (18), lesbarkeit (14), tempo (8).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 03:40:49 +02:00
DogFatherGitandClaude Opus 5 8efdb39ce9 Kein Weichzeichner mehr -- die Bilder werden scharf, die Kacheln Lampen
Filipe: "gerade sehen die sogar leicht verschwommen aus ... die sollen
nicht durch die kacheln gehen ... ich wollte eine krasse aenderung."

Drei Ursachen, alle drei von mir eingebaut, alle drei gemessen:

1. ICH HABE 1647-PIXEL-BILDER ALS "uhd" MIT 2400 PIXELN AUSGELIEFERT.
   Am Morgen stand in derselben Datei, sein Schirm sei 2550 px breit und
   das groesste Bild 1600 -- meine "Loesung" war, die Ausgabe
   hochzurechnen. Es gab nie mehr Bildpunkte. Dazu fehlte der Schritt,
   den der Kommentar daneben selbst verlangt ("Verkleinern MITTELT
   Bildpunkte ... deshalb schaerft man danach nach"): Es wurde nie
   nachgeschaerft. Jetzt Unscharfmaske auf der ENDgroesse
   (Ausgabeschaerfung) und ein Glanz-Durchgang: die hellsten Stellen
   weich gezeichnet und additiv dazu -- Licht, das ueber seine Kante
   strahlt. Guete 0,80 -> 0,88, am Gate 0,93.

2. backdrop-filter: blur() UNTER JEDER FLAECHE. 16 px unter siebzehn
   Kacheln, 13 px unter sieben weiteren Flaechen, 26 px unter der
   Anmeldekarte. Ein Weichzeichner mittelt nicht nur, was hinter dem
   Element liegt -- er zieht seinen Radius weit darueber hinaus. Hinter
   der Anmeldetafel ist Schwarz, direkt daneben aber die hellste Stelle
   des Motivs: Die Karte wurde deshalb GRAU, gemessen rgb(46,57,64)
   statt rgb(15,22,34). Je schoener der Rahmen, desto grauer die Karte.
   Alle Weichzeichner raus, --flaeche 0,78 -> 0,89: Durchsicht bleibt,
   aber scharf.

3. DIE TAFELMESSUNG WAR FALSCH, UND ICH HABE SIE VON HAND "KORRIGIERT".
   Sie lief vom Inneren nach aussen und hielt beim ersten farbigen Punkt
   an -- links glueht der Rahmen breiter als rechts, also hielt sie dort
   frueher an (58,59 statt 55,37). Statt den Messfehler zu beheben, habe
   ich in der CSS "um 1,1 % nach links" geschaetzt. Ergebnis: 32 px
   schwarze Tafel blieben links offen. Jetzt wird die einzige
   Eigenschaft gesucht, die nur der Rahmen hat -- kraeftig UND farbig --,
   mit Gegenprobe auf der linken Bildhaelfte (dort muessen es 0 sein).

KACHELN: keine Politur mehr, ein anderes Ding. Jede steckt in einer
LEUCHTSCHIENE ihrer Kategoriefarbe, die Licht in die Platte wirft --
links scharfe Kante, rechts rund. Steiler Abfall (52 % statt 68 %):
beleuchtet, nicht eingefaerbt. Der Glanz wandert beim Ueberfahren
einmal durch. Dieselbe Sprache auf der Anmeldeseite: die vier Rollen
sind Tasten in Schienen (Gold/Bernstein/Gruen/Blau).

Zwei eigene Fehler nebenbei, beide durch das Unveraenderlichkeits-
Zeichen gefunden -- eine Zahl, die sich nach einer Aenderung KEIN Stueck
bewegt, sagt "falsche Stelle", nicht "zu wenig":
  - Dreimal exakt 4,16:1 an "Ueberfaellig". Der Pruefpunkt lag nicht auf
    dem Knopf, sondern in der Luecke daneben auf dem Bild. Ursache war
    das hellere Hochkant-Bild, nicht das Bedienelement -> mehr Schleier
    und weniger Glanz NUR fuer die Handy-Fassung. 4,16 -> 5,10.
  - Die Koernung der Anmeldekarte lag mit 90 % Deckkraft ohne Mischmodus
    ueber allem und hob jeden Bildpunkt um 30 Stufen. Jetzt 4 % mit
    overlay, auf eigener Ebene.
  - --flaeche anzuheben machte die WICHTIGE Anleitung duenner als eine
    gewoehnliche (88 gegen 89) -- feste Zahl neben beweglicher Groesse.
    Gefunden von pruef-lesbarkeit, jetzt an --flaeche gebunden.

Gruen: buehne (38), start-ansicht (136), handy (59), breiten (23),
lesbarkeit (14), css-klassen (15), barrierefrei (18), tempo (8).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 03:10:13 +02:00
DogFatherGitandClaude Opus 5 947c9d8a26 Agentur: Eintraege gehoeren allen -- und Events bekommen ein eigenes Formular
Gemessen am 07.09.2026, bevor irgendetwas geaendert wurde: Von drei
Agentur-Eintraegen sah eine Creatorin genau EINEN -- den, der ihr
zugeordnet war. Ein Event fuer alle traf weder `creator_id = ich` noch
`erstellt_von = ich`; die Agentur-Seite war fuer jeden Creator leer.
Nicht kaputt, nicht fehlerhaft: leer, so wie eine Seite aussieht, auf
der noch nichts steht.

Die Pruefung dazu war gruen. Sie legte ihre Testeintraege mit
`creator_id: idLuna` an und pruefte damit einen Fall, den es im Alltag
nicht gibt.

- Bereichseinstellung `fuerAlle` + `ohneCreatorBezug`, daraus abgeleitet
  sichtbarEintrag(). BEWUSST neben sichtbar() statt darin: an derselben
  Funktion haengen Aufgaben, Dateien, Termine und Calls -- wer dort
  "1=1" einschleust, gibt nebenbei fremde Akten frei. Eine Gegenprobe
  mit einer zweiten Creatorin haelt das fest.
- Die Zuordnung bietet nur noch "Agentur" an. Der Server verwirft eine
  Zuordnung ausserdem selbst -- inklusive des frei getippten Namens, und
  zwar NACH externPruefen: davor haette der Name den Riegel wieder
  aufgemacht.
- "Event & Kampagne" heisst jetzt "Agentur-Events" und hat ein eigenes
  Formular: Von/Bis, Titel, Beschreibung, Aufgaben (Punkte und Preise),
  Regeln. Die Karte zeigt den Zustand als WORT (laeuft bis / startet /
  vorbei seit), nicht nur als Farbe.
- Drei neue Spalten -- und sie stehen auch im Tabellenneubau vom 06.09.
  Der laeuft NACH dem Spaltennachtrag und haette sie samt Inhalt
  weggeworfen, ohne Fehler und mit stimmender Zeilenzahl.
- Creator sehen weiterhin alles und tragen weiterhin nichts ein (403).
  Die Unterzeile sagt jetzt "alles, was hier steht" statt "alles, was zu
  dir gehoert" -- eine vollstaendige Liste soll sich nicht wie ein
  Ausschnitt lesen.

pruef-agentur: 61 Pruefungen (vorher 40), alle gruen. Zwei eigene
Fehler nebenbei gefunden und behoben: eine Beschriftung mit 11,2 px
(Grenze 11,5) und ein Testdatum aus UTC statt Ortszeit.
Zusaetzlich gruen: css-klassen, struktur, formulare,
barrierefrei-workspace, handy.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 02:31:47 +02:00
DogFatherGitandClaude Opus 5 3914adf46c Material statt Farbe -- Kacheln werden Gegenstaende, die Karte ein Bildschirm
Filipe: "ich will dass alle kacheln viel geiler und spezieller aussehen,
viel realistischer" und "so dass der komplette von der kachel vom
hintergrund bild komplett bedeckt ist. ueberrasch mich."

DIE BILDER: BEARBEITET STATT ABGEDUNKELT.
Bis hierher tat der Bildbauer zwei Dinge -- kleiner rechnen und einen
schwarzen Schleier darueberlegen. Abdunkeln macht ein Bild aber nicht
ruhiger, sondern TOT: Es zieht jede Farbe zur Mitte, und uebrig bleibt
ein grauer Schleier mit einer Ahnung von Motiv.

Drei Dinge, die ein Fotograf zuerst anfasst, und keines davon ist
"dunkler":
  * KONTRAST -- Verkleinern MITTELT Bildpunkte; deshalb wirkt jedes
    verkleinerte Bild flauer als das Original, und deshalb schaerft man
    danach nach.
  * SAETTIGUNG -- holt das Rot der Chili und das Gruen der Blaetter
    zurueck, die der Schleier herausgewaschen hatte.
  * VIGNETTE -- der eigentliche Unterschied zwischen "Screenshot" und
    "Aufnahme". Ein Objektiv verliert zu den Ecken hin Licht; das Auge
    liest das als Tiefe. Sie ersetzt ausserdem einen Teil des flachen
    Schleiers: Dunkel wird, wo ohnehin nichts steht.
Der flache Schleier sinkt dadurch von 0,42 auf 0,26 -- heller UND
lesbar, weil die Vignette genau dort arbeitet, wo die Kacheln liegen.

DIE KACHELN: VIER DINGE, DIE EIN DING VON EINEM RECHTECK TRENNEN.
Sie hatten Farbverlauf, Lichtkante und ein Licht, das dem Zeiger folgt --
und blieben Rechtecke mit Farbe darin. Es fehlten:
  1. GEWICHT. Ein Ding, das auf etwas liegt, wirft einen Schatten, auch
     wenn es niemand anfasst. Den gab es nur beim Ueberfahren.
  2. MATERIALSTAERKE. Ein Blech hat oben eine Licht- UND unten eine
     Schattenkante. Nur die obere ergibt einen aufgeklebten Strich.
  3. KOERNUNG. Perfekt glatte Verlaeufe kommen in der Natur nicht vor,
     und das Auge merkt das, ohne es benennen zu koennen. Drei Prozent
     Rauschen genuegen -- aus einem SVG-Filter als Adresse, also ohne
     Datei und ohne zusaetzliche Anfrage.
  4. DURCHSICHT. Hinter den Kacheln liegt jetzt ein aufwendiges Bild.
     Eine deckende Flaeche verdeckt es, eine mattierte nimmt seine Farbe
     auf -- erst dadurch gehoeren beide zusammen.
Beim Ueberfahren wird die Kachel nicht heller, sondern kommt NAEHER:
Sie steigt, ihr Schatten wird groesser und weicher (der Abstand zum
Untergrund waechst). So verhaelt sich ein angehobener Gegenstand.

DIE ANMELDEKARTE: EIN GERAET STATT EINES BILDES AN DER WAND.
Sie sass mit Abstand in der gemalten Tafel -- zwei Rahmen ineinander,
dazwischen schwarze Leere. Jetzt geht sie bis unter das Gluehen des
Neonrahmens: Der Rahmen ist das Gehaeuse, die Karte der eingeschaltete
Bildschirm. Sie leuchtet von den Kanten herein in den Farben des Rahmens
(rot oben links, blau unten rechts), traegt eine Glasscheibe als sehr
schwache Spiegelung und dieselbe Koernung. Die Rollen sind Tasten
geworden: Materialstaerke oben hell, unten dunkel, beim Druecken sinken
sie ein, und die gewaehlte ist beleuchtet statt eingefaerbt.
Alle Angaben bleiben -- vier Rollen mit Beschreibung, Codefeld, Auge,
Rollenhinweis, Fusszeile. "Hochwertiger" heisst nicht "weniger drin".

EIN ECHTER FUND DABEI: --text-still lag ploetzlich bei genau 4,50:1
statt der noetigen 4,5. Der Ton war am 01.09. gegen die DAMALIGE,
dunklere Buehne gemessen. Wer den Hintergrund heller macht, muss die
leiseste Schrift nachziehen -- sonst haette man den Aufwand auch lassen
koennen. Erkannt daran, dass die Zahl sich bei zwei Schleier-Aenderungen
NICHT bewegte: Die Pruefung rechnet mit der CSS-Farbe.

Gemessen statt angesehen: Kontrast an echten Bildpunkten (pruef-buehne),
neun Bildschirmbreiten, drei Handygroessen, Ladezeit und Datenvolumen,
Klassen, Struktur, Startseite -- alles gruen. Die Seiten ueber dem
CLS-Zielwert sind nebenbei von sieben auf vier gesunken.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 02:06:08 +02:00
DogFatherGitandClaude Opus 5 8107b97379 Die Kopfleiste wuchs beim Laden um vier Pixel -- und schob die Seite
Beim Messen des Datenvolumens nach dem Bildumbau fiel etwas anderes
auf: Der Layout-Sprung auf der Startseite lag bei 0,99. Die Bilder waren
es nicht -- ein Hintergrundbild liegt `position: fixed` und bewegt gar
nichts.

Die Meldung sagte es selbst, man musste nur hinsehen: ALLES sprang um
denselben Betrag (295->301, 144->150, 685->692, 605->611). Wenn die
ganze Seite gleichmaessig nach unten rutscht, waechst etwas ueber ihr.

Gemessen: Leiste vor dem Skript 67 px, danach 71. Der Sicht-Umschalter
kommt erst, wenn die Personenliste geladen ist, und ist mit 42 px das
hoechste Teil in der Reihe. Vier Pixel -- man sieht sie kaum und merkt
sie doch: Wer beim Laden schon zielt, klickt daneben.

Die Loesung ist keine reservierte Hoehe auf Verdacht, sondern die Hoehe,
die die Zeile ohnehin haben muss: `min-height: 44px`. Das ist das
Mindestmass fuer ein Fingerziel (WCAG 2.5.8) und gilt hier sowieso fuer
jedes Teil. Damit ist die Zeile immer so hoch wie ihr groesstes
zulaessiges Element -- unabhaengig davon, ob dieses gerade schon da ist
oder erst kommt.

Ergebnis: 0,99 auf 0,60, und die Zahl der Seiten ueber dem Zielwert von
zwoelf auf sechs. Datenvolumen unveraendert in Ordnung trotz der
groesseren Bilder -- der Browser holt je Seite nur eine Stufe.

Und der offene Punkt von vorhin ist geklaert: pruef-browser laeuft
gruen durch, alle vier Maschinen (Chromium, Firefox, WebKit, WebKit auf
dem iPhone), 64 Seitenaufrufe, 15898 Elemente. Der eine rote Punkt im
Gesamtlauf war eine Zeitueberschreitung unter Dauerlast -- erkennbar
daran, dass ZWEI Pruefungen gar nicht gelaufen waren und die Datei die
doppelte Zeit brauchte. Eine gesunkene Anzahl ist ein eigener Befund.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 01:46:29 +02:00
DogFatherGitandClaude Opus 5 accf01b5d6 Sieben Motive statt einem -- und Bilder, die nicht mehr hochgerechnet werden
Filipe: "die grafik soll viieeeel besser aussehen bitte. die hintergrund
bilder sollen viel hochwertiger und spezieller aussehen."

DIE URSACHE WAR NICHT DIE BILDGUETE, SONDERN DIE GROESSE.
Sein Bildschirm ist 2550 px breit, das groesste ausgelieferte Bild war
1600 -- der Browser rechnet es also um das 1,6-fache hoch. Jede Kante
wird dabei weich, gleichmaessig ueber das ganze Bild. Genau das sieht
man als "billig", ohne benennen zu koennen, warum. Eine hoehere
WebP-Guete haette daran nichts geaendert: Man kann keine Bildpunkte
zurueckholen, die nie ausgeliefert wurden.

  Anmeldeseite: jetzt 960 / 1280 / 1600 / 1920 / 2560, Guete 0,88.
  Buehnen:      jetzt 2400 (uhd) / 1600 (breit) / 900 (schmal).
Ueber srcset bzw. eine Fenstergroesse laedt trotzdem jeder nur die
Stufe, die er braucht -- ein Handy weiterhin 32 KB.

UND NEUN BUEHNEN ZEIGTEN DASSELBE BILD.
In start.css standen neun Regeln, eine je Szene -- alle zeigten auf
dieselbe Datei. Die Zuordnung war seit dem 01.09. richtig gedacht und
seit dem 03.09. wirkungslos. Aufgefallen ist es niemandem, weil jede
Seite fuer sich stimmig aussah; man merkt es erst, wenn man zwei
nebeneinander haelt. Jetzt hat jede Gruppe ihr eigenes Motiv, und die
Zuordnung folgt dem, was auf der Seite passiert:

  studio      Startseite            Chili-Wasserfall, "More Than Media"
  showbuehne  Dashboard, Reports    Spiegelkabinett -- viele auf einmal
  portal      LIVE, Content         Splash mit IDEAS / BRAND / CONTENT
  garage      Aufgaben, Technik     Kohle und Glut, Werkstatt
  arena       Dateien, Wissen       Medaillon-Sammlung, ein Archiv
  halle       Profile, Schutz       dieselbe Sammlung -- Personen, nicht
                                    Betrieb
  wald        Start-Check, Scout    roter Ahorn, etwas das waechst
  skyline     Kalender              Podest unter dem Mond
  lounge      Calls, Chat           dieselbe Nachtbuehne, ruhig

Sieben Motive auf neun Plaetze; die zwei Paare sind inhaltlich
benachbart und liegen nie nebeneinander auf einer Seite.

ABDUNKLUNG 0,42 -- gemessen, nicht uebernommen. Beim Tresorbild hatte
ich 0,62 aus den alten Szenen uebernommen, und uebrig blieb ein Schemen.
pruef-buehne rechnet den Kontrast an echten Bildpunkten nach: 4,69 bis
7,14 gegen die noetigen 4,5, an bis zu 28 Stellen je Seite.

Die Groessenpruefung in pruef-struktur bekommt eine begruendete Ausnahme
fuer GESTUFTE Bilder: Bei einer Datei, von der der Browser immer nur
eine von drei Stufen holt, misst eine feste 200-KB-Grenze das Falsche.
Sie gilt unveraendert fuer alles andere -- und die Ausnahme prueft
zusaetzlich, dass die kleineren Stufen wirklich existieren, damit sie
niemand als Schlupfloch benutzt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 01:38:02 +02:00
DogFatherGitandClaude Opus 5 44b3290bc5 Die Kopfleiste: nicht die dritte Zahl, sondern gar keine
BEFUND. Der Gesamtlauf war nach dem Bildumbau bei SIEBZEHN Dateien rot,
pruef-handy allein mit 37 Fehlern. Alle mit derselben Meldung:
"ueber=126px". Eine Ursache, siebzehnfach gezaehlt.

Sie war meine. Um den Layout-Sprung bei 1280 px zu beheben, hatte ich
den Umbruch der aeusseren Leiste wieder auf "nur unter 380 px" gestellt
-- und damit bei 390 und 412 px genau das Loch aufgerissen, das ich
Stunden vorher geschlossen hatte. Dieselbe feste Schwelle von 380, ueber
die zwei Commits vorher eine Regel in CLAUDE.md gewandert ist.

DREI ANLAEUFE, und die ersten beiden waren Symptomkur:

  1. `flex: 0 0 auto` fuer die Bedienelemente -> 126 px Ueberstand bei
     412 px (sie koennen weder schrumpfen noch umbrechen).
  2. Hoher Schrumpf-Faktor am Schriftzug (220 gegen 1) -> besser, aber
     von 19 fehlenden Pixeln nahmen die Knoepfe 0,19, und die runden auf
     1 auf. Ein Pixel, und die Gruppe brach um. Ich habe daraufhin die
     Abstaende verkleinert; danach war es wieder genau ein Pixel. Wer an
     einem Rundungsfehler schraubt, hat die falsche Stellschraube.
  3. RICHTIG: dem Schriftzug gar keine Wunschbreite geben.
     `flex: 1 1 0` heisst "ich beanspruche nichts und nehme, was uebrig
     bleibt". Damit entsteht ueberhaupt kein Fehlbetrag, der verteilt
     werden muesste. Kein Schrumpf-Faktor, keine Schwelle, nichts zu
     runden. Dazu `max-width: max-content`, sonst zieht `flex-grow` die
     Marken-Pille ueber die ganze Leiste (990 statt 375 px) -- wovor der
     Kommentar zwei Zeilen darueber ausdruecklich warnt und was ich beim
     Umbau uebergangen habe.

Gemessen ueber neun Breiten: 1920 bis 768 einzeilig (71 px), 412 und 390
zweizeilig (127), 320 dreizeilig (167). Ueberstand ueberall null. Und der
Layout-Sprung von 0,94 ist damit auch weg -- er kam aus derselben Ecke.

Dabei drei weitere echte Fehler gefunden, alle in Neuem von heute:
  * Der Namenslink in der Fruehwarnung war 22x25 px -- unter dem
    Mindestmass von 24x24 (WCAG 2.5.8). Bei kurzen Namen trifft man
    daneben. Jetzt ein echtes Fingerziel mit negativem Aussenabstand, der
    die Polsterung optisch wieder aufhebt.
  * Die Warnkarten standen bei 320 px 9 px aus dem Bild:
    `minmax(320px, 1fr)` begrenzt die Spalte, nicht ihren Inhalt. Erst
    `min(320px, 100%)` PLUS `min-width: 0` PLUS umbrechender Kopf loesen
    es -- einzeln keines davon. Die Schreibweise stand zwei Abschnitte
    weiter oben laengst richtig da.
  * Der Zurueck-Link im Schriftzug ragte aus seinem Kasten:
    `overflow: hidden` schneidet nur die ANZEIGE ab, der Link behaelt
    seine Layoutbreite. Bei 768 px lag sein Mittelpunkt unter den
    Bedienelementen -- ein Klick dorthin traf das Falsche, auf 17 von 18
    Seiten, und zu sehen war davon nichts.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-07 00:56:18 +02:00
DogFatherGitandClaude Opus 5 aa1d05a5c0 Neues Anmeldebild -- die Karte sitzt IN der gemalten Tafel
Filipe: "integriere die zugangskachel links nach rechts und passe sie
perfekt an damit sie in dem neuen bild rechts perfekt und die
vorgemachte kachel passt."

Das neue Motiv (Spicy Media x DogFather) hat rechts eine leere Tafel mit
Neonrahmen. Die Anmeldekarte sitzt jetzt DARIN -- und zwar wirklich
darin, nicht ungefaehr in der Gegend.

DAS PROBLEM, DAS MAN LEICHT UEBERSIEHT: Das Bild liegt mit
`object-fit: cover` unter der Seite; je nach Fensterform schneidet der
Browser oben/unten oder links/rechts etwas ab. Ein `left: 58%` bezieht
sich aber auf das FENSTER. Auf genau einer Bildschirmgroesse saehe es
richtig aus und ueberall sonst falsch. Deshalb rechnet `.tafel-anker`
dieselbe Cover-Formel noch einmal nach und ist damit deckungsgleich mit
dem Bild -- Prozentwerte darin sind Prozent DES BILDES.

Die vier Zahlen sind GEMESSEN (tools/gate-bauen.mjs), nicht geschaetzt.
Zwei Anlaeufe standen daneben und haben sich selbst verraten:
  1. "Suche den leuchtenden Rahmen" fand den Mond, die roten Blueten und
     jede Spiegelung -- Ergebnis: die ganze rechte Bildhaelfte. Eine
     Messung, die das Offensichtliche zurueckgibt, hat nichts gemessen.
  2. "Suche die groesste dunkle Flaeche" fand die Breite richtig, aber
     94 % Hoehe: Ueber und unter der Tafel ist die Szene genauso
     schwarz.
Richtig ist der dritte Weg: vom Mittelpunkt der Tafel nach aussen
laufen, bis es hell ODER farbig wird -- auf diesem Weg liegt nichts
anderes, denn die Tafel ist leer. Danach eine Plausibilitaetspruefung,
die abbricht statt vier geratene Zahlen auszugeben.

DREI FEHLER IM EIGENEN ENTWURF, alle gemessen statt angesehen:
  * Die Karte hing 300 px unter dem Bildschirmrand. Auf `.tafel` liegt
    die Einblend-Animation, deren Endbild `transform: none` ist -- mein
    `translateY(-50%)` war damit wirkungslos. Zwei Wege, dasselbe
    Element zu verschieben, vertragen sich nicht.
  * Der Anker lag 3 % neben dem Bild: Das Bild traegt `scale(1.03)` als
    Reserve fuer die Parallaxe. Jetzt tragen beide dieselbe Verwandlung,
    und die Parallaxe laeuft ueber zwei CSS-Groessen am <body> -- so
    wandert die Karte mit, statt dass der Rahmen unter ihr wegrutscht.
  * Der Hochkant-Ausschnitt zeigte die LEERE Tafel: ein schwarzes
    Rechteck mit ein paar Saeulen. Auf dem Handy liegt die Karte ohnehin
    davor; dort gehoert das Logo hin. Jetzt faellt der Schriftzug
    SPICY MEDIA in den sichtbaren Streifen -- nachgerechnet, nicht
    probiert.

STARTSEITE: das Tresorbild als neuer Hintergrund. Die uebernommene
Abdunklung von 0,62 war zu viel (der Tresor ist von Haus aus dunkel) --
uebrig blieb ein Schemen. Und der "Leseweg" verdunkelte ausgerechnet die
MITTE: Bei den alten Szenen stand dort nichts, beim Tresor steht dort
die Tuer. Beides korrigiert und mit pruef-buehne an echten Bildpunkten
nachgemessen.

DABEI GEFUNDEN, ohne Zusammenhang mit dem Bild: Der abgeschaltete
"Ueberfaellig"-Filter kam auf 4,05:1 statt 4,5:1. Die Deckkraft zu
erhoehen half nichts -- die Pruefung rechnet mit der CSS-FARBE und dem
gemessenen Bildpunkt dahinter, und ein `opacity` am Elternknopf aendert
die Farbe nicht. Die Zahl blieb dreimal exakt gleich; genau das war der
Hinweis. Jetzt ein eigener, hellerer Ton. Der Kommentar daneben sagte
ohnehin, was gewollt ist: Man SOLL sehen, dass es null sind.

Und die vier Regeln von heute stehen in CLAUDE.md.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 23:44:10 +02:00
DogFatherGitandClaude Opus 5 70039714c5 Die Sicherung war zwei Loecher gross -- gefunden, weil sie zum ersten Mal wirklich zurueckgespielt wurde
"Wir haben eine Sicherung" war bis heute ein Satz, kein Nachweis. Die
taegliche Kopie ausserhalb des Servers prueft `PRAGMA integrity_check`
und meldet seit dem 31.08. jeden Tag "in Ordnung". Das heisst: die Datei
ist nicht zerschossen. Es heisst NICHT, dass man damit weiterarbeiten
kann.

tools/wiederherstellung-proben.mjs geht den Weg jetzt wirklich: juengste
Sicherung in ein Wegwerf-Verzeichnis kopieren, die echte Anwendung
dagegen starten (damit laufen alle Schemawanderungen durch), vorher und
nachher zaehlen, anmelden, jede Seite aufrufen. Drei Ausgaenge, nicht
zwei -- "konnte nicht nachsehen" ist weder Erfolg noch Fehler.

BEIM ERSTEN LAUF BLIEB GENAU EINE VON ACHTZEHN SEITEN ROT: der
Steckbrief, mit einem 404 fuer ein Bild. Daran hingen zwei echte Luecken:

  1. PROFILBILDER WAREN NIE GESICHERT. sicherung-holen.sh holte
     dateien/ und wissen/ -- die Bilder liegen aber in einem dritten
     Ordner (profilbilder/, siehe workspace-steckbrief.js). Nach einem
     Plattenausfall waeren alle Profilbilder weg gewesen, waehrend die
     taegliche Meldung weiter "in Ordnung" sagte. Sie hat ja nie
     behauptet, vollstaendig zu sein.

  2. DIE RUECKMELDUNG AN DEN SERVER LIEF INS LEERE. Das Skript meldete
     sich bei dogfather-universe.com/workspace/... -- seit dem Umzug am
     06.09. antwortet diese Adresse mit 410 "Gone". Der Server erfuhr
     also seit dem Umzug nicht mehr, dass die Kopie laeuft; auf der
     Automationen-Seite waere sie mit jedem Tag aelter erschienen,
     obwohl sie taeglich lief. Ein 410 wird jetzt eigens gemeldet -- es
     heisst etwas anderes als "Netz kaputt", naemlich "die Adresse
     stimmt nicht mehr".

Beides behoben. Und damit es kein drittes Mal passiert, vergleicht die
Probe die Ordnerliste des Sicherungsskripts gegen die Ordner, die der
Server im Quelltext wirklich benutzt (`join(DATEN_ORDNER, "...")`). Wer
morgen einen vierten Datenordner anlegt und ihn nicht sichert, bekommt
hier einen Fehler statt eines stillen Lochs -- mit Gegenprobe, dass der
Vergleich einen fehlenden Ordner auch wirklich erkennt.

Ergebnis nach den Reparaturen: 18 Pruefungen, alle gruen,
"DIE SICHERUNG LAESST SICH ZURUECKSPIELEN." Der Lauf traegt sich mit
Datum in die Sicherungsablage ein -- sonst weiss beim naechsten Mal
niemand, wann zuletzt wirklich zurueckgespielt wurde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 23:20:10 +02:00
DogFatherGitandClaude Opus 5 233cd76d78 Der Handy-Durchgang: drei echte Bedienfehler, alle vom selben Ursprung
Filipe: "ich will dass du die komplette seite auf dem handy abcheckst.
ich will dass alles perfekt aussieht und bedienbar ist."

DER SCHWERSTE FUND: Auf ZWOELF Seiten war der "Meine Sicht"-Umschalter
nicht bedienbar -- wer darauf tippte, landete im Chat.

Bei 412 px (der haeufigsten Android-Breite ueberhaupt) brach die
Kopfleiste nicht um, der Umschalter wurde auf 50 px zusammengedrueckt,
sein Knopf behielt aber seine 104 px Mindestbreite und lag damit quer
ueber dem Chat-Knopf. Sichtbar war davon nichts.

Und die Ursache steht seit dem 05.09. woertlich im Kommentar daneben:
"Die Rechnung ging genau auf, solange rechts VIER Dinge standen. Mit der
Glocke sind es FUENF, und bei 320 px passte es nicht mehr." Am 06.09.
habe ich den Chat-Knopf dazugesetzt -- SECHS -- und die Schwelle bei 380
gelassen. Derselbe Fehler, eine Position weiter.

Die Lehre ist nicht "380 auf 430 erhoehen"; das waere er ein drittes
Mal, nur mit einer anderen Zahl. Eine feste Schwelle ist eine Rechnung,
die jemand einmal aufgestellt hat und die beim naechsten Knopf still
falsch wird. `flex-wrap: wrap` OHNE Schwelle rechnet nicht, sondern
misst -- es bricht genau dann um, wenn der Platz nicht reicht.

DASSELBE NOCH EINMAL, am anderen Ende: Bei 1280 px brauchte die Leiste
1235 px (Marke 375 + Bedienelemente 844 + Abstand 16) und hatte 1200.
Auch hier war der Chat-Knopf der Tropfen. Sie brach um, sobald das
Skript die Bedienelemente eingehaengt hatte, und schob die ganze Seite
52 px nach unten -- CLS 0,94. Jetzt gibt die MARKE nach (sie darf
gekuerzt werden, ein Knopf nicht), und umgebrochen wird nur noch auf
sehr schmalen Geraeten.

WEITERE ECHTE FUNDE:
  * /workspace/api/chat/ungelesen wurde auf JEDER Seite ZWEIMAL geholt:
    einmal beim Laden, einmal Millisekunden spaeter beim Aufgehen des
    Ereignisstroms. Der 'open'-Zuhoerer war fuer Wiederverbindungen
    gedacht und feuerte auch beim ersten Mal.
  * Drei Kacheln teilten sich einen Farbton mit einer anderen (18 Farben
    auf 21 Kacheln). Filipe wollte ausdruecklich, dass jede ihre eigene
    hat. Nicht eine Farbe dazuerfunden -- der ganze Farbkreis ist mit
    tools/kachel-farben.mjs neu in 21 geteilt; kleinster Abstand zweier
    Nachbarn jetzt 120 Grad (vorher 106). Dabei fiel eine feste 16 in
    der Mischschleife auf: Bei 18 Kacheln wurden die letzten beiden nie
    mitgemischt.
  * Der Agentur-Untertitel wurde auf dem Handy abgeschnitten.
  * Ein zugeklappter <details>-Kasten (Kalender-Abo) verdeckte einen
    Filter-Chip: Chromium versteckt dessen Inhalt ueber
    `content-visibility`, nicht ueber `display` -- die Kaesten behalten
    eine Groesse. Dieselbe Falle wie bei den Zeitbloecken, dieselbe
    Loesung.

UND DREI PRUEFUNGEN, DIE SELBST FALSCH LAGEN:
  * "achtzehn Kacheln" stand als feste Zahl im Test. Eine Pruefung, die
    bei jeder neuen Kachel rot wird, erzieht dazu, ihr Rotwerden zu
    ignorieren. Sie zaehlt jetzt aus bereiche.js.
  * "das Licht der Kalender-Kachel (tuerkis) muss mehr Blau als Rot
    haben" -- Wissen von aussen, und nach dem Neurechnen war der
    Kalender rosa. Gemessen wird jetzt gegen den Ton der Kachel selbst.
  * pruef-workspace-umzug meldete sein Ergebnis in eigenen Worten. Der
    Gesamtlauf las daraus NULL Pruefungen und schrieb bei JEDEM Lauf ein
    FEHL, obwohl alle 31 Punkte bestanden. Ein Fehlalarm, der immer
    kommt, macht den einen echten unsichtbar.

Und weil "BUTTON 'Meine Sicht' verdeckt" mich eine Stunde gekostet hat,
sagen pruef-handy und pruef-tempo jetzt DAZU, was verdeckt und was
springt -- mit Elternkette und Koordinaten. Ein Befund, den man nicht
verorten kann, ist ein halber.

NEU: der Kalender zum Abonnieren (Stufe 3.2). Persoenlicher, jederzeit
widerrufbarer Link fuer Google, Apple und Outlook. 36 Pruefungen, die
das ICS ZURUECKLESEN statt es anzusehen -- entfaltet, entschluesselt,
verglichen. Wichtigster Punkt: Der Weg ohne Anmeldung darf nichts
zeigen, was der Weg mit Anmeldung nicht zeigt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 23:15:37 +02:00
DogFatherGitandClaude Opus 5 bede91921d Der sechste Bereich, und zwei Pruefungen, die den Lauf lahmgelegt haben
DER AGENTUR-BEREICH (Stufe 4 des Plans)
Kernprinzip 04 des Konzepts lautet woertlich "Die Agentur bleibt
angebunden" -- und dafuer gab es bis heute nichts. Fuenf Bereiche
standen, der sechste fehlte vollstaendig. Damit stand nirgends, welche
Kampagne laeuft, welche Schulung ansteht und wie ein Anliegen an die
Agentur ausgegangen ist. Das lief ueber private Nachrichten: nicht
auffindbar, nicht nachvollziehbar, beim naechsten Mal von vorn.

Vier Arten, und die vierte ist der Punkt: kampagne, schulung, anliegen
und ZUSTAENDIGKEIT. Die letzte ist keine Verlegenheit, sondern das, was
das Konzept ausdruecklich fordert -- Betreuung und Umsetzung sind unsere
Seite, offizielle Wege sind Agenturseite. Solange das nur im Kopf steht,
wird es bei jedem Streitfall neu verhandelt.

Der Umbau war das eigentliche Risiko, nicht der Bereich: Ein CHECK
laesst sich in SQLite nicht aendern, die Tabelle muss neu gebaut werden
-- und dabei werden ALLE vorhandenen Eintraege umgeschrieben. Deshalb
geht pruef-agentur.mjs (31 Pruefungen) den Weg wirklich: Sie baut eine
Datenbank im ALTEN Stand nach, fuellt sie mit allen fuenf Bereichen,
laesst die echte Anwendung darueberlaufen und zaehlt danach jede Zeile
UND jedes Feld nach -- auch die seltenen Spalten (hook, creator_extern),
die man beim Abschreiben des Bauplans vergisst. Wichtigste Gegenprobe:
Der CHECK muss danach noch BEISSEN. Eine Umstellung, die nebenbei die
Schranke entfernt, sieht aus wie ein Erfolg und ist der schlimmere
Ausgang.

Nebenbei drei abgeschriebene Bereichslisten beseitigt (Wochenbericht,
Suche, Report-Ziele). Im Wochenbericht waere der neue Bereich sonst
schlicht nicht vorgekommen -- ohne Fehler, ohne Luecke, einfach nicht da.

ZWEI PRUEFUNGEN, DIE DEN GESAMTLAUF ZUM STILLSTAND BRACHTEN

pruef-call-kategorien.mjs hing DREI STUNDEN. Ursache war ein Zeitzuender
in ihr selbst: Sie legte Calls auf "heute 18:00" und erwartete zwei
davon unter "Heute". Ab 18 Uhr sind die vorbei, der Server schiebt sie
nach "Protokoll fehlt", und die Oberflaeche unterteilt erst ab FUENF
anstehenden. Uebrig blieben vier, die Bloecke verschwanden, und die
Pruefung wartete auf einen Klick auf einen Block, den es nicht gab.
Genau die Sorte Fehler, vor der die Projektnotiz vom 06.09. warnt: Sie
war um 17:59 gruen und um 18:01 rot, ohne dass sich am Code etwas
geaendert hatte. Jetzt liegen alle Zeiten RELATIV zu jetzt, und die
Erwartung wird mit derselben Vorschrift gerechnet, die calls.js benutzt
-- statt Zahlen, die nur zu einer bestimmten Tageszeit stimmen.

Und der Grund, warum daraus ein Stillstand statt eines Fehlers wurde:
index.js setzt bewusst zwei Auffangnetze (uncaughtException,
unhandledRejection). Fuer den Betrieb richtig -- ein Fehler darf die
Website nicht offline nehmen. Fuer eine Pruefung fatal: Sie importiert
index.js in denselben Prozess und erbt die Netze. Ihr eigener Absturz
wird dann nur protokolliert, und der Express-Server haelt den Prozess
danach ewig am Leben. Kein Fehler, kein Ergebnis, kein Ende.

Deshalb zwei Abhilfen, die zusammengehoeren:
  * server/helfer-notbremse.mjs -- haengt eigene Zuhoerer DANEBEN
    (process.on ergaenzt, es ersetzt nicht) und beendet den Lauf mit
    Fehler; dazu ein Wecker. In alle 42 Browserpruefungen eingebaut.
    Der Betrieb bleibt unveraendert.
  * tools/alles-pruefen.mjs gibt jeder Datei eine Frist von 600 s. Wer
    sie reisst, wird abgebrochen und ZAEHLT ALS FEHLGESCHLAGEN, mit der
    letzten Ausgabe davor als Beleg. Einzelne Dateien nachzuruesten hilft
    nur bis zur naechsten ohne Notbremse -- deshalb sitzt sie dort, wo
    sie fuer alle gilt, auch fuer die, die es noch nicht gibt.

AUSSERDEM: pruef-breiten.mjs pruefte 16 Seiten aus einer Liste von Hand,
chat.html und leistung.html fehlten darin. Der Chat war bei keiner
einzigen der neun Breiten je gemessen worden. Wie bei pruef-handy kommt
die Liste jetzt aus dem Verzeichnis.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 22:06:49 +02:00
DogFatherGitandClaude Opus 5 80a8aac774 Der ganze Prueflauf blieb am Chat-Strom stehen -- behoben
BEFUND. Seit der Chat am 06.09. dazukam, LIEF DER GESAMTE
REGRESSIONSLAUF NICHT MEHR DURCH. Nicht "er wurde rot" -- er blieb
einfach stehen, bei Datei 3 von 62, ohne Fehlermeldung, ohne FEHL, ohne
Absturz. Nach zwoelf Minuten stand er immer noch dort. Von aussen sieht
"noch nicht fertig" genauso aus wie "haengt fuer immer"; deshalb ist
mir das gestern nicht aufgefallen, sondern erst, als ich den Lauf
gezielt beobachtet habe.

DIE URSACHE. pruef-alle-wege.mjs geht stumpf ueber ALLE 134
Schnittstellen und liest jede Antwort mit `await a.text()` aus. Der
Chat haelt seine Verbindung aber absichtlich offen und schickt neue
Nachrichten hinein, solange jemand zusieht (SSE). `text()` wartet, bis
der Server fertig ist -- und der wird nie fertig. Angemeldet als
DogFather trat der Lauf dort ein und kam nicht wieder heraus.

DIE ABHILFE, zwei Teile, die zusammengehoeren:
  * Jeder Ruf hat jetzt eine Frist von 8 s. Laeuft sie ab, ist das ein
    ERGEBNIS ("hing") und kein Absturz. Ein neuer Abschnitt meldet am
    Ende, WELCHER Weg nicht geantwortet hat -- statt dass der Lauf
    wortlos stehenbleibt.
  * Bekannte Stroeme stehen in einer Liste MIT BEGRUENDUNG und werden
    nicht uebersprungen, sondern anders geprueft: verbinden, Status
    ablesen, abbrechen. Die Schranke wird damit genauso gemessen wie
    ueberall. Zusaetzlich wird nachgemessen, dass ein eingetragener
    Strom auch wirklich offen bleibt -- sonst verdeckte die Ausnahme
    nur seine Inhaltspruefung.
Der "hing"-Zustand musste eigens gesammelt werden: In Abschnitt 1 haette
er ausgesehen wie "ohne Anmeldung erreichbar", in Abschnitt 2 waere er
ganz durchgefallen (`"hing" >= 500` ist false, Zeichenkette gegen Zahl).
Genau so verschwinden Befunde.

Ergebnis: 134 Schnittstellen, 532 Aufrufe, alles gruen, kein Haenger.

AUSSERDEM, gefunden beim Nachsehen:

  * pruef-handy.mjs pruefte 15 Seiten -- aus einer Liste von Hand, die
    veraltet war. chat.html, leistung.html und steckbrief.html standen
    nicht darin: DREI von neunzehn Seiten waren nie auf einem Handy
    gemessen worden, ausgerechnet der Chat. Die Liste kommt jetzt aus
    dem Verzeichnis, die naechste neue Seite ist von selbst dabei.
  * chat.html und leistung.html fehlte <link rel="manifest">. Auf dem
    Handy heisst das: Wer die App installiert hat und ueber eine
    Benachrichtigung dort landet, verlaesst den App-Rahmen -- die Seite
    oeffnet im Browser, mit falscher Leistenfarbe. Ihre theme-color war
    ausserdem eine andere als auf allen uebrigen Seiten. Beides behoben
    UND als Pruefung in pruef-struktur nachgetragen, damit es beim
    naechsten Mal nicht am Gedaechtnis haengt.

NEU: tools/wiederherstellung-proben.mjs — die Probe aufs Exempel.
Die Sicherung ausserhalb des Servers laeuft taeglich und prueft
`integrity_check`. Das sagt: die Datei ist nicht zerschossen. Es sagt
NICHT, ob die Anwendung damit startet, ob man sich anmelden kann und ob
die Daten vollstaendig sind. Eine Sicherung, die man nie zurueckgespielt
hat, ist eine Hoffnung. Das Werkzeug kopiert die juengste Sicherung in
ein Wegwerf-Verzeichnis, startet die echte Anwendung dagegen (damit
laufen alle Schemawanderungen wirklich durch), zaehlt vorher und
nachher, meldet sich an und ruft jede Seite auf. Drei Ausgaenge, nicht
zwei -- "konnte nicht nachsehen" ist weder Erfolg noch Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 18:34:57 +02:00
DogFatherGitandClaude Opus 5 953c3f5721 Zahlen bekommen eine Oberflaeche, das Dashboard bekommt Zahlen
Der Server konnte seit gestern rechnen -- und niemand konnte etwas
eintragen. Ein Rechenwerk ohne Oberflaeche ist kein Modul, sondern ein
Versprechen. Das ist jetzt eingeloest:

  * leistung.html: Wochenkarten (Wert, Vergleich zur Vorwoche,
    Verlaufslinie), Ziele als Fortschrittsbalken, die letzten 14 Tage
    zum Eintragen -- auch die LEEREN, denn eine Luecke ist selbst die
    Auskunft. Import aus dem TikTok-Export mit Vorschau VOR dem
    Schreiben.
  * Kachel "Zahlen" als erste der Gruppe "Rund um den Creator", eigenes
    Zeichen (steigende Linie, kein zweites Balkendiagramm).
  * Dashboard: jede Creator-Karte traegt jetzt Diamanten, LIVE-Tage und
    Verweildauer. Bis heute zeigte sie ausschliesslich ARBEIT -- ein
    Creator konnte null ueberfaellige Aufgaben haben und gleichzeitig
    seit drei Wochen einbrechen, und die Karte sah tadellos aus.
  * Die Fruehwarnung steht oben im Dashboard. Sechs benannte Signale im
    Klartext mit Beleg, bewusst OHNE Punktzahl -- ein Wert wie
    "Abwanderungsrisiko 73" klingt nach Wissenschaft und ist eine
    Behauptung, der man nicht widersprechen kann.
  * chat.html?mit=<person>: der Weg von der Warnung ins Gespraech. Gab
    es vorher nicht; ein Hinweis ohne Weg dahin ist nur ein schlechtes
    Gewissen.

GEFUNDEN VON DEN PRUEFUNGEN, nicht von der Theorie:

  1. Die Verlaufslinie zeichnete fuer vier der sieben Groessen NICHTS.
     Der Server liefert im Verlauf nur drei Reihen; fuer den Rest kam
     undefined an. `=== null` faengt das nicht, Number(undefined) ist
     NaN, und ein <polyline points="NaN,NaN"> ist im DOM vorhanden und
     auf dem Bildschirm unsichtbar -- ohne Fehlermeldung. Die Pruefung
     misst deshalb die PUNKTE, nicht die Anwesenheit des Elements.
  2. Fuenf Schriftgroessen im CHAT lagen unter 11,5 px (.68/.7 rem) und
     waren seit vorgestern drin. Die Grundlinie der Groessenpruefung
     stand auf 43, gemessen wurden 48. Nicht die Grundlinie angehoben,
     sondern die fuenf Stellen behoben: Eine Grundlinie, die mitwaechst,
     ist keine mehr.

pruef-leistung-optik.mjs: 57 Pruefungen, zwei echte Browser, Gegenprobe
zu jeder Aussage -- auch dazu, dass die Vorschau vor dem Bestaetigen
wirklich noch nichts geschrieben hat und dass ein Creator seine Zahlen
zwar SIEHT, sie aber weder eintragen noch die Fruehwarnung ueber sich
lesen kann (auch nicht ueber eine von Hand gebaute Anfrage).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 18:27:16 +02:00
DogFatherGitandClaude Opus 5 c8a4e7628c Stufe 1+2: Zahlen ueber das Geschaeft, und eine Fruehwarnung
Der grosse Befund aus dem Plan vom 31.08.2026: Der Workspace
organisiert ARBEIT hervorragend, wusste ueber das GESCHAEFT aber
nichts. Keine Diamanten, keine LIVE-Tage, keine Verweildauer. Damit
hing die ganze Betreuung in der Luft -- der Start-Check bewertete ohne
zu messen, der Report fragte "was hat funktioniert" ohne Beleg, das
90-Tage-Ziel war ein Satz statt eines Fortschritts.

STUFE 1 -- LEISTUNG

Eine Zeile je Creator und TAG (nicht Woche: Feineres laesst sich immer
zusammenfassen, Groeberes nie aufteilen). Diamanten, LIVE-Dauer,
gueltiger Tag, Zuschauer im Schnitt und in der Spitze, Verweildauer,
Schenker, neue Follower -- und eine NOTIZ. Ohne sie sieht man in drei
Monaten einen Einbruch und weiss nicht mehr, dass die Person Grippe
hatte.

DIE VERWEILDAUER IST DIE LEITZAHL (Recherche 06.09.2026): 2026 haengt
der Algorithmus alles an der Completion Rate, und sie gehoert als
BETRIEBSkennzahl behandelt -- sie soll die naechste Runde steuern,
nicht die letzte erklaeren.

Jede Zahl kommt mit Vergleich, Verlauf und Einordnung. Eine Zahl ohne
diese drei ist eine Eitelkeitszahl: Sie sieht nach Auskunft aus und ist
keine, weil man nichts entscheiden kann.

Zwei Wege hinein: Schnelleingabe und CSV-Import aus dem offiziellen
Export, mit Vorschau vor dem Uebernehmen.

STUFE 2 -- FRUEHWARNUNG

Sechs benannte Signale (Zahlen fallen, LIVE-Tage brechen weg, lange
nicht angemeldet, kein Gespraech, Aufgabenstau, Start-Check haengt) und
daraus EIN ruhiger Satz: "Bei Nora wuerde ich diese Woche nachfassen."

BEWUSST KEIN SCORE. Eine Note von 1 bis 100 wirkt objektiv und ist es
nicht; sie verfuehrt dazu, Menschen nach einer Zahl zu behandeln. Am
Score kann man nichts tun, am Signal schon. Deshalb Saetze statt
Punkte, und jedes Signal einzeln nachvollziehbar.

Ein CREATOR sieht die Fruehwarnung nicht: Das ist eine
Arbeitsgrundlage fuer die Betreuung, keine Mitteilung an die
betroffene Person.

ZWEI ECHTE FEHLER, VON DER PRUEFUNG GEFUNDEN

1. ZAHLENFORMAT, Faktor tausend daneben. "1.250" wurde als 1,25
   gelesen und "1,234" als 1,234. Die Regel "das letzte Trennzeichen
   ist das Dezimalzeichen" liefert bei nur EINEM Trennzeichen fuer
   beide Faelle das Falsche -- und die Zahl sieht danach trotzdem
   plausibel aus. Jetzt entscheidet, wie viele Ziffern dahinter stehen:
   genau drei heisst Tausendertrenner.

2. DIE ZIELE-ROUTE WURDE VERSCHLUCKT. Express nimmt die erste passende
   Route, und `:tag` passt auch auf "ziele" -- ein PUT auf .../ziele
   landete in der Tages-Route und scheiterte am Datumsmuster. Die
   Meldung sagte "ungueltig", was auf die Zahlen deutet, nicht auf den
   Weg. Reihenfolge getauscht.

Beides waere still gewesen: falsche Zahlen sehen richtig aus, und ein
Ziel, das sich nicht setzen laesst, probiert man zweimal und laesst es
dann.

pruef-leistung.mjs: 47 Punkte, darunter jede Rechnung einzeln
nachgerechnet (Durchschnitte ohne Tage ohne Wert, Prozent von null,
Wochengrenzen), Import zweimal eingelesen, deutsche und englische
Zahlenformate, Rechte, und die Gegenprobe, dass die Fruehwarnung bei
Unauffaelligkeit SCHWEIGT.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 18:12:16 +02:00
DogFatherGitandClaude Opus 5 17157b4f18 Sicht-Umschalter: ein Auge statt des Wortes "SICHT"
Filipe zu dem Feld in der Kopfleiste: "das soll viel besser aussehen
viel geiler aber nicht so eine scheisse."

Er hatte recht. Da stand ein Etikett mit dem Wort SICHT und daneben ein
Auswahlfeld -- ein Formular, das in die Kopfleiste gerutscht war. Drei
Aenderungen:

  * DAS AUGE ersetzt das Wort. Es sagt dasselbe in einem Zeichen und
    laesst dem NAMEN den Platz, um den es eigentlich geht. Fuer
    Vorleseprogramme bleibt die Beschriftung erhalten, nur unsichtbar --
    sie ersatzlos zu loeschen haette das Feld unbeschriftet gelassen.

  * "Meine Sicht" statt "Alles (meine Sicht)". Der Zusatz erklaerte
    nichts und machte den Knopf so breit, dass am Handy nichts anderes
    mehr danebenpasste.

  * EIN KREUZ statt "zurueck zu mir". Der Satz brauchte mehr Platz als
    der Name daneben, und was ein Kreuz an einer aktiven Auswahl tut,
    weiss jeder. Die Worte bleiben im aria-label und im Titel.

DIE EIGENTLICHE VERBESSERUNG ist aber die Hierarchie: Im Normalfall
ist der Umschalter still (graues Auge, ruhiger Rand). Sobald eine
FREMDE Sicht laeuft, traegt er ganz Farbe -- nicht nur ein
Zusatzknopf am Rand.

Das ist der gefaehrlichste Zustand dieser Funktion: Wer sie vergisst,
sieht am naechsten Tag drei Aufgaben statt dreissig und haelt das fuer
den Bestand. Ein Zustand, der Schaden anrichtet, muss lauter sein als
einer, der nichts tut.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 17:48:03 +02:00
DogFatherGitandClaude Opus 5 9dc35f5da6 Chat wieder einhaengen -- die Datei ist jetzt da
Nachtrag zu 09a4cfd ("AUSFALL BEHOBEN: versehentlich mitcommitteten
Import zurueckgenommen"). Das war richtig: Import und Einhaengung des
Chats waren aus einem unfertigen Stand mitgekommen, waehrend
workspace-chat.js noch gar nicht im Repo lag -- der Server fand das
Modul nicht und stuerzte in einer Schleife ab.

Seit 4637aa2 liegt die Datei im Repo. Ohne diese Zeile blieb der Chat
aber tot: Der Server startete tadellos, und JEDER Chat-Weg antwortete
still mit 404. Gemessen ueber die Browserkonsole -- die Ampelpruefung
meldete "Failed to load resource: 404" und nannte drei Adressen:
/api/chat/raeume, /api/chat/strom, /api/chat/ungelesen.

DER UNANGENEHMERE VON ZWEI FEHLERN: Fehlt die Datei, faellt der ganze
Dienst aus -- laut und sofort. Fehlt nur die Einhaengung, laedt die
Seite, der Chat bleibt leer, und niemand sieht warum. Deshalb steht
jetzt ein Kommentar an der Zeile, der beides zusammen nennt.

Nachgemessen nach der Reparatur: 0 fehlende Ressourcen (vorher 3).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 17:43:09 +02:00
DogFatherGitandClaude Opus 5 686249e36c Und die restlichen 40 Pruefbilder
Der erste Durchgang hat nur 62 von 102 erwischt. Grund: Die Liste kam
aus `path: "..."` -- Bilder, deren Name aus einem Template-Literal oder
einer Variablen entsteht, standen nicht darin:

    path: breite === 1440 ? "pruef-kalender-computer.png" : "…-handy.png"
    path: `pruef-rollen-${r.rolle}.png`

Danach war die Kontrolle entscheidend, nicht die Erfolgsmeldung: "0
Pruefbilder versioniert" -- es waren noch 40. Wer nach einem
Aufraeumen nicht nachzaehlt, glaubt der Absicht statt dem Ergebnis.

Vor dem Entfernen noch einmal im GANZEN Repo geprueft (nicht nur in
server/ und tools/, wie beim ersten Mal): Kein readFileSync, kein
existsSync, kein readFile auf eine .png-Datei. Sie werden ueberall nur
geschrieben.

Kontrolliert danach: 0 Pruefbilder versioniert, QR-Codes weiterhin 3.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 17:06:48 +02:00
DogFatherGitandClaude Opus 5 1f4717d683 Bilder der Pruefungen aus der Versionierung nehmen
62 Bildschirmfotos, 54 MB, die bei JEDEM Prueflauf neu geschrieben
werden. Sie standen im Repo und tauchten dadurch bei jedem Commit als
Aenderung auf -- man haette sie mitcommittet oder jedes Mal von Hand
aussortiert. Beides ist Ballast, und beides passiert irgendwann falsch.

Sie bleiben auf der Platte und werden weiter erzeugt. Nur versioniert
sind sie nicht mehr.

GEPRUEFT VOR DEM ENTFERNEN: Keine einzige Pruefung LIEST je ein Bild --
kein readFileSync, kein existsSync auf .png; sie werden ausschliesslich
geschrieben. Es sind also Ansichtsbilder, keine Vergleichsvorlagen,
deren Verlust eine Pruefung blind machen wuerde. Waeren es welche,
duerften sie nicht weg.

UND EIN BEINAHE-FEHLER, der hier festgehalten gehoert: Der erste Anlauf
nahm "alle .png ausser workspace/assets und assets/img". In dieser
Liste standen assets/qr/qr-instagram.png und zwei weitere QR-Codes der
Website -- echte Dateien, die niemand neu erzeugt. Ein zu grobes Muster
haette sie mitgeloescht.

Die Liste kommt deshalb jetzt aus der Quelle statt aus einem Muster:
Was in einem `screenshot({ path: ... })` einer Pruefdatei steht, kann
weg. Alles andere nicht. Kontrolliert danach: QR-Codes (3) und
Website-Bilder (105) sind unveraendert versioniert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 17:05:54 +02:00
DogFatherGitandClaude Opus 5 3bab6d9fbf Der Knopf auf der Umzugsseite ist jetzt ein echter Verweis
Hinweis von Filipe: Wenn etwas wie ein Knopf aussieht, muss man auch
draufdruecken koennen. Er hatte recht.

Meine urspruengliche Begruendung - die Adresse solle nur zum Lesen
dastehen, damit niemand versehentlich ein Lesezeichen auf den alten Weg
setzt - traegt nicht: Wer klickt, landet auf der NEUEN Adresse und setzt
sein Lesezeichen genau dort. Ein Element, das wie ein Knopf aussieht und
sich nicht wie einer verhaelt, ist eine Falle.

Der Knopf hat jetzt einen Hover- und einen Tastatur-Fokuszustand, und
beide Bewegungen entfallen bei prefers-reduced-motion.

Die Pruefung geht dabei einen Schritt weiter als vorher: Sie prueft nicht
mehr nur, WELCHE Anfragen zugeordnet werden, sondern ruft die Middleware
wirklich auf und sieht sich die ANTWORT an. Denn die Zuordnung kann
stimmen und die Seite trotzdem kaputt sein:

  - ein Platzhalter, der woertlich in der Seite steht statt eingesetzt zu
    werden
  - ein Knopf ohne Verweis (genau der Fall, den Filipe gemeldet hat)
  - HTML statt JSON fuer /workspace/api/ - ein noch offener Tab wuerde
    sonst die Hinweisseite als Daten zu lesen versuchen
  - und die wichtigste: dass die NEUE Adresse durchgelassen wird

31 Pruefungen, alle gruen. Gegenprobe gemacht: Dreht man den Knopf zurueck
zu einem div ohne Verweis, meldet die Pruefung 2 Fehler - sie haette den
gemeldeten Mangel also selbst gefunden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 16:50:30 +02:00
DogFatherGitandClaude Opus 5 8e3eccc7a8 Alte Workspace-Adresse abgeschaltet statt weitergeleitet
Auf Filipes Wunsch: dogfather-universe.com/workspace/ soll nicht mehr
existieren, er gibt den neuen Link selbst an Creator und Scouts weiter.
Vorher stand dort eine Weiterleitung - die haette die alte Adresse auf
unbestimmte Zeit am Leben gehalten.

Der Server antwortet dort jetzt mit 410 Gone. Beides - 404 und 410 -
heisst "gibt es hier nicht"; 410 sagt zusaetzlich "gab es, ist
absichtlich weg, kommt nicht wieder". Genau der Sachverhalt.
Suchmaschinen nehmen die Adresse dadurch schneller heraus, und in einem
Protokoll ist ein 410 sofort als gewollt erkennbar, waehrend ein 404
immer nach Versehen aussieht.

Statt einer nackten Fehlermeldung kommt eine kurze Hinweisseite mit der
neuen Adresse. Wer hier landet, hat einen alten Link oder eine alte
Verknuepfung und soll erfahren, wohin der Workspace gezogen ist, statt vor
einem leeren Fenster zu sitzen. Bewusst OHNE Verweis zum Anklicken, damit
niemand aus Versehen ein neues Lesezeichen auf den alten Weg setzt.

Schnittstellen-Aufrufe unter /workspace/api/ bekommen JSON statt HTML -
ein alter, noch offener Browser-Tab wuerde sonst die Hinweisseite als
Daten zu lesen versuchen und einen unverstaendlichen Fehler zeigen.

Die Pruefung deckt weiterhin 21 Faelle ab und ist mitgezogen: Der
gefaehrlichste Fall heisst jetzt nicht mehr "Endlosschleife", sondern
"die neue Adresse mit abschalten" - wer nicht auf den Hostnamen prueft,
sperrt den Workspace fuer alle aus. Alle gruen, Gegenprobe schlaegt an.

Diesmal vor dem Commit den Diff Datei fuer Datei kontrolliert - beim
letzten Mal hatte ich hier eine fremde uncommittete Zeile mitgenommen und
damit die Website fuer zwei Minuten abgeschossen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 16:34:27 +02:00
DogFatherGitandClaude Opus 5 09a4cfdeab AUSFALL BEHOBEN: versehentlich mitcommitteten Import zurueckgenommen
Die Website war ab 16:27 unerreichbar (HTTP 502, 29 Neustartversuche).
Ursache war mein Commit 58b8ef2: Beim "git add server/index.js" habe ich
eine uncommittete Zeile einer parallel laufenden zweiten Sitzung
mitgenommen -

    import { chatRouter } from "./workspace-chat.js";
    app.use(chatRouter);

- deren Datei workspace-chat.js aber noch nicht committet war. Auf dem
Server fehlte sie deshalb, und Node bricht beim Start mit
ERR_MODULE_NOT_FOUND ab.

Warum es niemandem vorher auffiel: Der Dienst lief seit Stunden mit dem
alten Code im Speicher. Ein fehlender Import faellt erst beim NEUSTART auf
- und der erste Neustart seit dem Push war meiner fuer den Workspace-Umzug.
Der Umzug selbst war nicht die Ursache, er hat den Fehler nur ausgeloest.

Behoben durch Entfernen der beiden Zeilen - nicht durch Nachcommitten von
workspace-chat.js: Die Chat-Funktion ist unfertige fremde Arbeit
(workspace.js und workspace-push.js sind dort ebenfalls geaendert und
uncommittet). Sie gehoert von der Sitzung committet, die sie gebaut hat.
Der Server laeuft damit wieder auf dem Stand, der vorher lief - plus dem
Workspace-Umzug.

Eigene Lehre, doppelt: Bei den 17 workspace-Seiten hatte ich die fremden
Aenderungen sorgfaeltig aus dem Index herausgehalten - bei server/index.js
habe ich genau das vergessen. Und: node --check haette es nie gefunden,
ein Import auf eine nicht existierende Datei ist syntaktisch tadellos.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 16:29:20 +02:00
DogFatherGitandClaude Opus 5 4637aa24e7 Chat zwischen Creator, Scouts und Managern
Wunsch Filipe, 06.09.2026: *"eine kategorie chat, wo die creator mit
ihren manager nachrichten austauschen koennen, wie erinnerungen, fragen
und noch vieles mehr."* Auf Nachfrage entschieden: Zweier-Gespraeche UND
Gruppen; Manager und Scouts duerfen sich auch ohne gemeinsamen Creator
schreiben.

WER MIT WEM steht an EINER Stelle: schreibbareIds() in workspace.js.
Bewusst getrennt von einladbareIds() (Terminwahl): Dort geht es darum,
wen man zu einem Kalendereintrag dazustellen darf -- harmlos. Ein Chat
legt ein dauerhaftes Gespraech an, schickt eine Benachrichtigung und
macht den eigenen Namen sichtbar. Zwei Fragen, zwei Funktionen.

Ein Creator erreicht seine Betreuer und DogFather, KEINEN fremden
Creator. Eine Gruppe ist kein Schlupfloch: Jede Nummer wird einzeln
gegen dieselbe Regel geprueft.

SOFORT STATT NACHFRAGEN IM TAKT (SSE). Ein Chat, der alle fuenf
Sekunden fragt, ist fuenf Sekunden langsam und stellt bei zehn
Angemeldeten 7200 Anfragen in der Stunde fuer Nachrichten, die es
meistens nicht gibt. Kein WebSocket: Hier fliesst alles in eine
Richtung, und SSE uebersteht einen Verbindungsabriss von selbst.

DIE ZAHL STEHT AUF JEDER SEITE, nicht nur im Chat. Eine Nachricht, die
man erst sieht, wenn man den Chat aufmacht, ist keine Nachricht --
sie ist ein Fundstueck.

Push aufs Handy nur an die, die NICHT gerade zusehen. Wer die Seite
offen hat, sieht es ohnehin; ihm zusaetzlich etwas aufs Handy zu
schicken ist der schnellste Weg, dass er Benachrichtigungen abschaltet.

WAS BEWUSST NICHT GEHT:
  * Niemand liest fremde Gespraeche mit -- auch DogFather nicht. Ein
    Chat, in dem der Chef stillschweigend mitliest, ist kein Chat.
    Er kann jederzeit jedem schreiben, aber sichtbar.
  * Eine abgeschickte Nachricht laesst sich nicht aendern, nur
    zuruecknehmen. Wer Absprachen nachtraeglich umschreiben kann, macht
    den Verlauf wertlos. Zurueckgenommenes hinterlaesst einen Hinweis
    statt eines Lochs.

DAZU: CALL-LISTE NACH ZEIT GEGLIEDERT

Wunsch mit Bild von "STEHT AN 27": *"die liste soll kategorisiert sein
und werden mit einem button zum auf und zu machen."* Jetzt Heute /
Diese Woche / Naechste Woche / Spaeter, offen nur der erste gefuellte
Block. Nach ZEIT und nicht nach Titel: Auf dem Bild waren fast alle
"Community-Talk" -- nach Titel gruppiert haette man zwei Ueberschriften
und darunter dieselbe lange Liste.

DER FUND, DER DIE FUNKTION GERETTET HAT: Ein zugeklappter Block zeigte
seinen Inhalt trotzdem -- 367 Pixel Hoehe bei open=false. <details>
versteckt seinen Inhalt naemlich nur, solange niemand dem Inhalt eine
eigene display-Angabe gibt, und .gruppe__karten traegt display:grid.
Der Knopf haette sich bewegt und sonst nichts getan. Im Bildschirmfoto
fiel es nicht auf, weil der Ausschnitt genau darueber endete.

Ausserdem gefunden und behoben:
  * Ein Wettlauf beim Abschicken: War der Ereignisstrom schneller als
    die Antwort auf das POST, stand die eigene Nachricht zweimal im
    Verlauf.
  * Die Chatseite war zu hoch -- die Kopfleistenhoehe stand als fester
    Wert (62 px) im CSS, am Handy ist sie doppelt so hoch. Das
    Eingabefeld stand halb unter dem Bildschirmrand. Jetzt gemessen.
  * Der Platzhalter "Enter schickt ..." brach am Handy um UND stimmte
    dort nicht: Ohne Tastatur schickt Enter absichtlich nicht.
  * Der Dialog benutzte Klassen aus aufgaben.css, das chat.html nicht
    lud -- gemeldet von pruef-css-klassen, bevor jemand einen
    ungestylten Dialog zu sehen bekam.

Pruefungen: pruef-chat (44 Punkte, Rechte und Sichtbarkeit),
pruef-chat-optik (24, zwei echte Browser schreiben sich),
pruef-call-kategorien (16).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 16:28:58 +02:00
DogFatherGitandClaude Opus 5 58b8ef233a Creator Workspace zieht auf eine eigene Adresse um
Der Workspace laeuft ab sofort auf workspace.dogfather-universe.com. Die
alte Adresse dogfather-universe.com/workspace/ leitet dorthin weiter.

Grund: Chrome laesst neben der Hauptseite, deren Bereich "/" die ganze
Domain umfasst, keine zweite App auf derselben Adresse zu. Unter dem alten
Pfad liess sich der Workspace nur als Verknuepfung ablegen, nie als
richtige App installieren - im Menue stand "Oeffnen in DOGFATHER
UNIVERSE" statt "Seite als App installieren". Das ist kein Fehler,
sondern Absicht (w3c/manifest Nr. 1180: verschachtelte Bereiche auf einem
Ursprung sind "strongly not recommended"). Auf der neuen Adresse hat
Filipe die App erfolgreich installiert.

Der PFAD /workspace/ bleibt erhalten. An ihm haengen 150 Server-Routen,
107 API-Aufrufe und 26 Server-Dateien - ihn wegzuschneiden waere ein
grosser Umbau ohne Gewinn, denn der Konflikt entsteht durch die
gemeinsame ADRESSE, nicht durch den Pfad. Dadurch musste am Code nichts
weiter geaendert werden.

Die Entscheidung steht in einer eigenen Datei (workspace-umzug.js), weil
sie zwei Stellen hat, an denen ein Denkfehler teuer waere und die man
einer Bedingung nicht ansieht:

  1. ENDLOSSCHLEIFE - derselbe Dienst bedient beide Adressen. Ohne
     Hostpruefung leitet die neue Adresse auf sich selbst, und der
     Workspace waere sofort nach dem Neustart fuer alle unerreichbar.
  2. PRAEFIX-IRRTUM - "faengt an mit /workspace" trifft auch
     /workspaceXYZ und /workspace-alt.

Als eigene Funktion ist beides pruefbar, ohne den Server zu starten:
pruef-workspace-umzug.mjs deckt 21 Faelle ab (alte/neue Adresse, mit und
ohne www, Gross-/Kleinschreibung, Portangabe, lokale Testadressen, beide
Praefix-Fallen). Alle gruen. Gegenprobe gemacht: Baut man die
Endlosschleife absichtlich ein, meldet die Pruefung 3 Fehler; baut man den
Praefix-Irrtum ein, meldet sie 2. Sie kann also auch "nein" sagen.

Bewusst 302 und nicht 301: Ein 301 wird vom Browser dauerhaft gemerkt und
laesst sich praktisch nicht zurueckholen - waere an der Umleitung etwas
falsch, waere die alte Adresse fuer jeden, der sie einmal aufgerufen hat,
dauerhaft unbrauchbar.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 16:23:32 +02:00
DogFatherGitandClaude Opus 5 e0d8e6d55d Tagesblick: Termine als Karten, und vier Fehler, die dabei auffielen
Filipe zu der Liste mit einem einzigen Termin darin: "das soll viel
geiler und krasser aussehen bitte."

Er hatte recht, und der Grund war der Einzelfall. Ein Zeitstrahl lebt
davon, dass er etwas VERBINDET -- bei einem Eintrag verbindet er nichts.
Uebrig blieben eine magere Zeile, ein Strich ins Leere und Weissraum bis
zur Plakette am rechten Rand.

Jetzt traegt jede Karte fuer sich: eigene Flaeche mit farbiger Kante,
die Uhrzeit gross und in der Farbe der Terminart (vorher war sie
kleiner als der Titel -- dabei ist sie das, was man sucht), ein Balken
fuer die Dauer, und "JETZT" am naechsten Termin statt eines etwas
helleren Hintergrunds. Erledigtes bekommt einen Haken und verliert die
Farbe, bleibt aber voll lesbar; vorher wurde alles blasser, was auch
den Text traf.

Kein Neon dazu. Die Wirkung kommt aus Kontrast und Hierarchie.

VIER FEHLER, DIE DIE PRUEFUNGEN GEFUNDEN HABEN

1. ZEITZONE, in NEUN Pruefungen. Um 00:10 meldete pruef-teilnehmer
   ploetzlich 13 Fehlschlaege an einer Datei, die seit Stunden niemand
   angefasst hatte:

       Ortszeit:  06.09.2026, 00:10
       UTC:       05.09.2026, 22:10

   Sie bildeten ihr Tagesdatum mit toISOString() -- also UTC -- legten
   ihre Termine auf gestern und suchten heute. ZWEI STUNDEN AM TAG waren
   sie damit rot, im Winter eine. Wer nur tagsueber laeuft, sieht das
   nie. Jetzt gibt es helfer-zeit.mjs mit derselben Rechenweise wie die
   Anwendung, und pruef-struktur sucht das Muster kuenftig automatisch.

2. MEIN UMSTELL-SKRIPT VERSAGTE STILL. Es pruefte
   `if "helfer-zeit.mjs" not in s` -- und mein eigener Kommentar
   enthielt den Dateinamen. Ergebnis: keine einzige der neun Dateien
   bekam den Import, alle waeren zur Laufzeit abgestuerzt. `node --check`
   findet das nicht. Aufgefallen, weil danach nachgezaehlt wurde statt
   der Erfolgsmeldung zu glauben.

3. DIE KACHEL LIESS DIE SEITE SPRINGEN. Der Layout-Sprung auf
   start.html stieg von 0 auf 0,96 -- zweimal bestaetigt. Sie erschien
   erst nach dem Laden und schob alles darunter weg. Das ist kein
   Schoenheitsfehler, sondern der Grund, warum man auf den falschen
   Knopf drueckt.

   Gemessen wurden die echten Hoehen (1 Termin 169 px, 3 → 327, 5 →
   486). Daraus zwei Konsequenzen: Platz vorher reservieren, und
   hoechstens DREI Termine zeigen -- das halbiert die Spanne und ist
   die klarere Aussage. Der Rest steht als "1 weiterer Termin heute"
   darunter, nicht stillschweigend abgeschnitten. Von 0,96 auf 0,163.

4. SCHRIFTGROESSE, zweimal am selben Tag: erst die Art-Plaketten mit
   10,56 px, dann -- nach der Korrektur -- die neue Jetzt-Marke mit
   10,88. Beide Male gemeldet von pruef-handy und pruef-grosscheck,
   beide Male erst nach einem mehrminuetigen Browserlauf.

ZWEI PRUEFUNGEN, DIE SICH SELBST IM WEG STANDEN

pruef-tempo-workspace meldete "NEUE Doppelabfrage: start.html 2x
/workspace/api/termine". Nachgemessen an einem einzelnen Seitenaufruf:
genau eine Anfrage. Die Pruefung startete ihren Zaehler, bevor die
Anmeldung zur Ruhe gekommen war, und schrieb der Seite an, was die
vorherige noch offen hatte.

pruef-tagesblick fiel zum zweiten Mal auf dieselbe Falle herein: Sie
mass die Artfarbe an einem vorbeigezogenen Termin, der absichtlich grau
ist. Diesmal an der Wurzel geloest -- die Daempfung wird fuer die
Messung kurz abgeschaltet und sofort zurueckgesetzt. Damit ist die
Zuordnung fuer JEDEN Termin geprueft, unabhaengig von der Uhrzeit des
Laufs, und zusaetzlich beweist die Pruefung, dass die Daempfung greift.

NEU: Schriftgroessen werden jetzt AN DER QUELLE geprueft, in Sekunden
statt Minuten. Im Bestand stehen 43 solche Stellen; sie alle rot zu
melden haette die Pruefung ab Tag eins wertlos gemacht. Deshalb eine
Grundlinie wie beim Layout-Sprung: Sie haelt den Stand fest und
schlaegt an, sobald es MEHR werden. Heute haette das zweimal gegriffen.
Die Browserpruefung bleibt daneben -- sie sieht, was am Ende auf dem
Schirm steht, die CSS-Pruefung nur, was gemeint war.

Gesamtlauf: 56 von 56 Dateien, 2002 von 2002 Punkten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 01:32:33 +02:00
DogFatherGitandClaude Opus 5 6541ecbfa7 Alte Symboldateien tragen jetzt auch das neue Bild
Filipe hat die Verknuepfungen dreimal neu angelegt und sah trotzdem das
alte Symbol. Die Ursache lag nicht an den neuen Dateien - die werden
nachweislich korrekt ausgeliefert (36 von 36 live byteweise geprueft),
sondern an vier Altlasten:

  /assets/img/favicon.png          256x256
  /assets/img/apple-touch-icon.png 180x180
  /assets/img/icon-192.png         192x192
  /assets/img/icon-512.png         512x512

Die stammen aus der Zeit vor dem Umbau auf app-symbole/ und werden von
KEINER Seite mehr verlinkt - geprueft mit einer Suche ueber alle html,
js, json und webmanifest: nur noch sw.js und main.js nennen sie.

Aber Chrome hat sich das Favicon dieser Domain gemerkt, als favicon.png
noch verlinkt war, und gibt es nicht mehr her: Beim Anlegen einer
Verknuepfung nimmt Windows dieses alte Bild, egal was im HTML steht. Auf
Filipes Bildschirm trugen deshalb ZWEI verschiedene Verknuepfungen
dasselbe Symbol - das war der entscheidende Hinweis, denn zwei Apps mit
verschiedenen Manifesten koennen unmoeglich dasselbe Symbol haben.

Statt zu hoffen, dass ein Zwischenspeicher irgendwann aufgibt, tragen die
alten Adressen jetzt einfach dasselbe Bild wie die neuen. Damit ist es
egal, welche ein Programm nimmt.

Dazu im Service Worker: CACHE_NAME auf v2 hochgezaehlt - activate()
loescht dadurch den alten Zwischenspeicher samt altem Symbol. Und
SHELL_ASSETS zeigt nicht mehr auf die verwaisten icon-192/-512, sondern
auf die Adressen aus dem Manifest.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 00:32:59 +02:00
DogFatherGitandClaude Opus 5 ed12d75404 App-Symbole: Kennzeichen-Plakette, damit man sie klein unterscheiden kann
Die Symbole waren farblich schon verschieden, zeigten aber alle dasselbe
Motiv. Gemessen in echter Groesse: Bei 24px (Startmenue) und 32px
(Taskleiste) ist der Husky nur noch ein Fleck - es unterscheidet sie
einzig die Farbe, und Webdesign, Kundenportal und WD-Verwaltung liegen
im Lila-Rosa-Bereich dicht beieinander.

Jedes Symbol traegt jetzt unten rechts eine Plakette mit einem Kennzeichen
in der Farbe der App:

  Hauptseite  *      DogiCrew-Verwaltung  C     Webdesign         W
  Kundenportal K     WD-Verwaltung        V     Creator Workspace A

Der Husky bleibt gross und dominant - die Marke wird nicht angetastet,
die Plakette traegt nur die Unterscheidung.

Die maskable-Fassungen haben eine EIGENE Plakettenlage, und die ist
gerechnet, nicht geschaetzt: Android behaelt nur den Kreis mit 80%
Durchmesser (Radius 0.40 ab Mitte). Der aeusserste Punkt der Plakette
liegt bei sqrt(2)*(0.5-rand-groesse/2)+groesse/2. Der erste Entwurf kam
damit auf 0.417 - die Plakette waere auf dem Handy angeschnitten worden.
Mit rand 0.190 und groesse 0.280 sind es 0.380, also mit Reserve drin.

Erzeugt aus den vorhandenen Symbolen (nicht neu gezeichnet), 36 Dateien:
je App 32, 180, 192, 512 und die beiden maskable. Jede Datei danach
einzeln aus dem PNG-Kopf vermessen - 36 von 36 haben die richtige
Groesse und Inhalt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-06 00:20:05 +02:00
DogFatherGitandClaude Opus 5 de60df5637 Creator Workspace ist jetzt wirklich installierbar
Der Workspace liess sich nicht als App installieren: Windows und Android
legten nur eine Browser-Verknuepfung an, mit dem globalen Favicon der
Domain statt dem eigenen Symbol. Grund: workspace/app.webmanifest lag
fertig da und wurde sogar ausgeliefert (HTTP 200), war aber in KEINER der
17 Seiten verlinkt. Ohne rel=manifest gibt es fuer den Browser nichts zu
installieren.

Jede der 17 Seiten bekommt deshalb den Manifest-Verweis und die eigene
Fensterfarbe #0674b9 (Blau, passend zum nachtblauen Symbol).

Zur Entstehung: Diese 17 Dateien tragen auch Versionsnummern einer
parallel laufenden zweiten Sitzung (?v=202609052252), deren zugehoerige
start.css und start.js noch nicht committet sind. Die gehoeren nicht in
diesen Commit. Sie wurden fuer das Bereitstellen kurz auf den committeten
Stand zurueckgesetzt und in der Arbeitskopie sofort wiederhergestellt -
im Index liegt dadurch nur die eigene Aenderung, ihre Arbeit bleibt
unangetastet uncommittet. Vorher gesichert, hinterher Datei fuer Datei
verglichen: kein Unterschied.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 23:44:54 +02:00
DogFatherGitandClaude Opus 5 5ef3a13615 Jede App der Domain bekommt eine eigene Fensterfarbe
Beim Installieren als App sahen alle Dienste gleich aus. Nicht wegen der
Symbole - die sind seit heute Mittag gut unterscheidbar - sondern wegen
der Farbe: zwoelf von vierzehn trugen dasselbe Fast-Schwarz (#05070b,
#05070d, #0a0910, #0b0d10, #0d0817, #0e0a16). Das ist die theme_color,
also am PC die Titelleiste des App-Fensters und am Handy die Statusleiste.

Neu, je App eine Farbe, abgeleitet vom eigenen Symbol:

  Hauptseite            #065f76  Petrol      (Symbol stahlblau)
  DogiCrew-Verwaltung   #8d4125  Kupfer      (Symbol orange)
  Webdesign             #564e95  Violett     (Symbol lila)
  Kundenportal          #924985  Magenta     (Symbol pink)
  WD-Verwaltung         #b44f5e  Rose        (Symbol rot)
  Creator Workspace     #0674b9  Blau        (Symbol nachtblau)

Nextcloud (#17a5a6) bleibt unveraendert - als einzige hob sie sich schon ab.

WICHTIG war, beide Stellen zu aendern: Die meta-Angabe im HTML
ueberschreibt die theme_color aus dem Manifest. Nur das Manifest zu
aendern haette gar nichts bewirkt.

Der background_color (Startbildschirm beim Oeffnen) bleibt bewusst sehr
dunkel, nur leicht in Richtung der App-Farbe getoent - kraeftig ist nur
die schmale Leiste, damit nichts grossflaechig aufblitzt (Vorgabe
augenschonend).

Wie die Farben entstanden sind: Zwei Entwuerfe fielen bei der eigenen
Pruefung durch. In HSL gerechnet lagen Workspace und Webdesign bei einem
Farbabstand von 12.6 statt der noetigen 25 - auf dem Papier 30 Grad
auseinander, fuers Auge dasselbe Blauviolett. Auch der zweite Versuch
scheiterte (Hauptseite zu nah an Nextclouds Tuerkis, 19.1). Neun Farben
bei gleicher Helligkeit passen schlicht nicht mit genug Abstand auf den
Farbkreis. Erst mit der Helligkeit als dritter Dimension und einem
Optimierer, der den KLEINSTEN Abstand im Satz maximiert, kam ein Satz
heraus, der haelt: kleinster Abstand 25.5.

Geprueft: 68 Farbpruefungen (weisse Schrift ueberall lesbar 5.0-7.2:1,
keine blendet, jede hebt sich vom bisherigen Schwarz ab, alle Paare
>= 25 Delta E) und 101 Browserpruefungen ueber 16 Seiten (Manifest und
meta stimmen ueberein, genau eine theme-color je Seite, Symbole
vorhanden) - alle gruen, Gegenprobe schlaegt an.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 23:35:25 +02:00
DogFatherGitandClaude Opus 5 c3b156dbad Tagesblick: eine Kachel fuer offene Punkte und die Termine des Tages
Wunsch Filipe, 05.09.2026, mit Bildschirmfoto der Hinweisliste: "eine
ganze kachel wo links die sachen sind die du da schon siehst und rechts
in der kachel die termine vom tag. in der mitte gesplittet. mach das
richtig geil und hochwertig."

WARUM DIE BEIDEN ZUSAMMENGEHOEREN

Links steht, was zu TUN ist, rechts, was schon FESTSTEHT. Zusammen
ergeben sie die einzige Frage, die man morgens hat -- wie sieht mein Tag
aus. Untereinander musste man scrollen, um sie zu beantworten.

Eine Kachel und nicht zwei nebeneinander: Zwei Rahmen lesen sich als
zwei Themen. Der Trenner laeuft oben und unten aus, statt von Kante zu
Kante durchzuschneiden -- eine harte Linie macht aus einer Kachel wieder
zwei.

Die rechte Haelfte ist ein Zeitstrahl, kein Kalenderauszug:
  * Was als NAECHSTES dran ist, wird hervorgehoben. Beim Ueberfliegen
    ist das die Auskunft, die man sucht -- nicht "der erste des Tages".
  * Vorbei heisst nicht weg. Erledigtes tritt zurueck, bleibt aber
    sichtbar; man will sehen, was man schon hinter sich hat.
  * Dieselben vier Farben wie im Kalender. Eine Farbe, die hier etwas
    anderes bedeutete, muesste man zweimal lernen.

Die Daten kommen aus der Kalender-Schnittstelle mit tage=1 -- keine
zweite Abfrage, keine zweite Sichtbarkeitsregel. Was jemand im Kalender
nicht sehen darf, kommt hier gar nicht erst an.

DREI FEHLER, DIE DABEI AUFFIELEN

1. Die rechte Haelfte war 38 statt 579 Pixel breit. Die versteckte
   Ueberschrift fuer Vorleseprogramme zaehlt als Kind im Raster und hat
   alles um eine Spalte verschoben, sodass "Heute" in der Ein-Pixel-
   Spalte des Trenners landete. Die Spalten sind jetzt ausdruecklich
   zugewiesen -- damit verschiebt auch ein spaeteres viertes Element
   nichts mehr.

2. Die Plaketten (CALL, TERMIN, REVIEW) hatten 10,56 px. Die Hausgrenze
   liegt bei 11,5 -- darunter liest auf einem Handy niemand mehr.
   Gemeldet von pruef-handy auf allen drei Geraeteklassen UND von
   pruef-grosscheck bei allen vier Rollen. Ein Fix, zwei Pruefungen.

3. Am Handy stand die Uhrzeit mittig zur Zeile, waehrend der Titel oben
   begann -- sie fluchteten nicht, sobald die Plakette unter den Text
   rutschte.

Die Kachel bleibt ganz weg, wenn BEIDE Haelften leer sind, und zeigt
sonst auf der leeren Seite einen Satz. Vorher haette jemand ohne offene
Punkte, aber mit drei Calls seinen Tagesplan nicht gesehen: Das
Verstecken hing an der linken Haelfte allein.

ZWEI PRUEFUNGEN, DIE SICH SELBST IM WEG STANDEN

pruef-tempo-workspace meldete "Layout springt: bereich.html 0,703".
Nachgemessen: derselbe Wert schwankt zwischen den Laeufen um den Faktor
zwei (aufgaben.html 0,478 / 0,262 / 0,262; bereich.html 0,703 dann
0,347). Er haengt davon ab, ob die Daten ankommen, waehrend das Geruest
noch aufgebaut wird. Eine Pruefung, die zufaellig rot wird, ist so
wertlos wie eine, die nie anschlaegt -- man klickt sie weg, und mit ihr
die echte Warnung. Statt die Grenze anzuheben (das haette sie stumpf
gemacht) wird ein Ausschlag jetzt durch WIEDERHOLUNG bestaetigt, und
gemeldet wird der zweite Wert, nicht der kleinere. Ein echter Sprung
kommt bei jedem Lauf und uebersteht das muehelos. Die neue Kachel selbst
springt uebrigens gar nicht: start.html steht bei 0.

pruef-push-weg meldete "ALLES IN ORDNUNG" und stuerzte danach ab
(libuv: UV_HANDLE_CLOSING, Rueckgabewert 3221226505). Ursache war
process.exit() mitten im Schliessen der fetch-Verbindungen. Jetzt
process.exitCode -- Node raeumt zu Ende. Fuenf Laeufe hintereinander
sauber. Eine Pruefung, die inhaltlich besteht und trotzdem rot ist, ist
das Schlimmste von beidem.

Gesamtlauf: 1994 von 1994 Punkten (1973 vorher + 21 der neuen Pruefung).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 22:43:59 +02:00
DogFatherGitandClaude Opus 5 5119e0139d vanvan.html: Coming-soon-Knopf wird Link zu VAN'S DIY
Der silberne Knopf trug 'Coming soon...' und war gesperrt (aria-disabled,
kein href). Er heisst jetzt 'VAN`S DIY' und fuehrt zu
https://vans-diy-bastelbedarf.com/ - in neuem Tab, mit rel=noopener, wie
der TikTok-Knopf darueber und die uebrigen Shop-Verweise im Projekt.

aria-disabled musste weg: sonst meldet ein Bildschirmleser 'nicht
bedienbar', obwohl der Knopf jetzt bedienbar ist.

Dabei aufgefallen und mitbehoben: Die Beschriftung brach auf schmalen
Geraeten mitten im Wort um ('VAN / `S / DIY' bei 390px, Knopf 117px statt
89px hoch), weil die Sektion auf vanvan.html auch auf dem Handy
zweispaltig bleibt - ein Inline-Style ueberschreibt dort die Regel aus
@media(max-width:620px). .btn-silver bekommt deshalb white-space:nowrap.
Das behebt zugleich den gleichen Umbruch von 'Coming soon...' auf
abonnieren.html bei 320px.

Geprueft im echten Browser: 52 Pruefungen (5 Sprachen x Text, href,
kein aria-disabled, target, rel, sichtbar, bedienbar) plus echter Klick,
der auf vans-diy-bastelbedarf.com landet - alle gruen, Gegenprobe
schlaegt an. Zusaetzlich 180 Messungen ueber 4 Seiten x 9 Breiten x 5
Sprachen (270 Knoepfe angesehen): kein Umbruch, kein Ueberlauf. Ohne den
nowrap-Fix meldet dieselbe Messung 30 Befunde.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 22:35:23 +02:00
DogFatherGitandClaude Opus 5 627f710d71 Aufgaben abbrechen, Teilnehmerwahl fuer alle, Benachrichtigungen
Zwei Wuensche vom 05.09.2026, dazu drei Fehler, die dabei ans Licht kamen.

ABBRECHEN (Wunsch: "in jedem status die aufgaben auch abbrechen koennen,
nur ich die manager und scouts")

Neuer Status mit Pflicht-Grund, aus jedem der vier Status heraus.
Festgehalten wird auch, WO die Aufgabe stand -- "im Review abgebrochen"
ist eine andere Aussage als "nie angefangen", und das Wiederaufnehmen
geht dorthin zurueck statt nach "offen".

Eigener Weg statt "abgebrochen" in der Statusliste: Dort entscheidet
darfAendern(), und das laesst auch den zustaendigen Creator aendern.
Der gewoehnliche PATCH kann diesen Zustand deshalb gar nicht erreichen
-- auch nicht fuer DogFather, sonst waere die Grund-Pflicht umgehbar.

Abgebrochenes steht in einem zugeklappten Bereich unter dem Brett, nicht
als fuenfte Spalte: Am Handy waeren dann alle fuenf unlesbar schmal.
Verschwinden darf es nicht, sonst waere der Abbruch ein Loeschen mit
Zwischenschritt.

Die Tabelle musste dafuer getauscht werden (SQLite kann CHECK nicht
aendern). Vorher auf einer Kopie durchgespielt: 40 von 40 Aufgaben,
Inhalte, Verweise und Indizes geprueft, Gegenprobe zeigt, dass der CHECK
noch lebt.

TEILNEHMERWAHL (Wunsch: "das soll viel besser aussehen und fuer jeden
verfuegbar sein")

Auf dem Bildschirm klebten die Namen aneinander: "DogfatherDogFather".
Ursache war, dass kalender.html das Stylesheet mit diesen Klassen nie
eingebunden hat -- sie standen in dateien.css. Vierzig gruene Pruefungen
zur Teilnehmerwahl hatten das nicht gemerkt, weil keine je gefragt hat,
ob es AUSSIEHT wie gedacht.

Jetzt eigene Klassen im eigenen Stylesheet, nach Rollen gruppiert: Die
Rolle steht einmal als Ueberschrift statt neunmal am Namen. Damit ist
das Kleben an der Wurzel weg, nicht zugepflastert.

"Fuer jeden" war mehr als ein hidden zu entfernen: darfEintragen() haette
einem Creator nur sich selbst erlaubt. Er haette seinen Scout gesehen,
angeklickt, und der Server haette ihn still weggelassen -- ein Knopf, der
nichts tut. einladbareIds() schaut jetzt in beide Richtungen, bewusst
getrennt von /api/personen: Wer die erweitert, gibt einem Creator
nebenbei die Moeglichkeit, seinem Scout Aufgaben zuzuweisen.

BENACHRICHTIGUNGEN (Wunsch: "sowas, und dass es perfekt funktioniert
fuer jeden")

Web Push nach RFC 8291/8292, ohne fremde Abhaengigkeit. Der Knopf sagt
in jeder Lage die Wahrheit, auch die unbequemen: abgelehnt (mit dem
Hinweis, wo man es zuruecknimmt), iPhone im Reiter (mit Anleitung),
Browser ohne Push. Ein Knopf, der bei abgelehnter Berechtigung nur
nichts tut, ist der sichere Weg zu "das funktioniert nicht".

DREI FEHLER, DIE DABEI AUFFIELEN

1. Ein defekter Zugangsdatensatz sperrte ALLE einer Rolle aus. Wirft
   hashe() bei einer Person, flog die ganze Anmeldung in den catch: 503
   "nicht verfuegbar" fuer jeden mit dieser Rolle. Aufgefallen durch
   einen eigenen Testfehler. Jetzt wird die defekte Person uebersprungen
   und laut protokolliert; die Gegenprobe zeigt, dass ein falscher Code
   weiterhin abgelehnt wird.

2. Die Glocke sprengte die Kopfleiste -- zweimal. Bei 320 px lag die
   Lupe des Suchknopfes auf dem Sicht-Umschalter (ein Knopf, der auf 12
   Seiten ins Leere tippt), bei 768 px wurde der Abmelden-Knopf bis zu
   15 px aus dem Bild geschoben, weil die Textgrenze auf 760 stand und
   ein Tablet 768 hat. Nachgewiesen durch Messen mit und ohne Glocke,
   nicht durch Vermuten.

3. .block__frage war viermal gestaltet und stand auf einer Seite, die
   keine dieser Dateien laedt -- derselbe Fehler wie bei der
   Teilnehmerwahl. Gefunden von der neuen Klassenpruefung beim ersten
   Lauf.

NEUE PRUEFUNGEN

pruef-css-klassen   jede gestaltete Klasse muss auf ihrer Seite ankommen
                    (unterscheidet Struktur-Anker von echtem Verlust)
pruef-dabei-optik   die Wahl im Browser, an den echten Pixeln
pruef-abbrechen     Umstellung auf einer Kopie, Rechte, Rueckweg
pruef-abbrechen-optik   Knopf, Dialog, Bereich, Handy
pruef-glocke        Zustaende, An/Abmelden, jede Rolle
pruef-push(-weg)    Rechnung gegen die RFC-Vektoren, Zustellung

pruef-struktur prueft jetzt zusaetzlich, ob sich jedes Server-Modul als
ESM laden laesst. node --check auf einer .js-Datei prueft als CommonJS
und meldete "ok", waehrend der Import scheiterte.

Gesamtlauf: 55 von 55 Dateien, 1973 von 1973 Punkten.

Was NICHT geprueft werden konnte und deshalb dasteht: Der Schritt
"Browser holt eine Adresse beim Push-Dienst" braucht eine Verbindung zu
Googles FCM, die ein Pruef-Browser nicht hat. Die Pruefung misst das
zuerst und meldet es als dritten Ausgang, statt gruen zu sein.
Verschluesselung und Zustellung sind getrennt geprueft; diese eine
Strecke beweist sich erst auf dem Server.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 18:05:28 +02:00
DogFatherGitandClaude Opus 5 529c814389 Kalender: mehrere Teilnehmer je Termin und Serie
Wunsch Filipe: "wenn ich im kalender was eintrage will ich dass ich
auch 2 leute markieren kann mit denen der call ist." -- und auf
Rueckfrage: beliebig viele, und auch fuer wiederkehrende Termine.

Bis hierher hatte ein Termin GENAU EIN Gegenueber. Fuer ein Gespraech
zu dritt musste man zwei Termine anlegen und hatte zwei Wahrheiten
ueber dieselbe halbe Stunde.

DAS IST KEINE ANZEIGE, SONDERN EINE RECHTEREGEL. An der
Teilnehmerliste haengt die Sichtbarkeit: Wer eingetragen ist, sieht den
Termin. Deshalb zwei Grenzen, beide serverseitig:
  * Eintragen darf man nur, wen man ohnehin sehen darf (Leitung jeden,
    ein Scout seine betreuten Creator, ein Creator sich selbst).
  * Zuordnungen verschiebt nur die Leitung -- sonst koennte sich jemand
    selbst in fremde Termine eintragen und sie sich damit sichtbar
    machen.

Gebaut nach dem Muster von datei_personen: eigene Tabellen
termin_teilnehmer und serie_teilnehmer statt weiterer Spalten.
teilnehmer_id bleibt das Haupt-Gegenueber und wird beim Speichern immer
in die Liste mit aufgenommen.

Vorhandene Termine werden beim Start uebernommen. Zusaetzlich liest die
Abfrage das Haupt-Gegenueber IMMER mit dazu -- die Liste stimmt damit
auch dann, wenn die Uebernahme nicht gelaufen ist (Sicherung
zurueckgespielt, Neustart ausgeblieben). Genau das ist beim Bauen
aufgefallen: Ein alter Termin zeigte "niemand dabei", obwohl ein
Gegenueber eingetragen war.

Serien vererben ihre Teilnehmer an jede erzeugte Auspraegung -- sonst
saehe der zweite Mensch den woechentlichen Call einmal und danach nie
wieder.

Neue Pruefung pruef-teilnehmer.mjs mit 40 Punkten: beide sehen ihn,
Fremde nicht, kein Selbsteintragen, Hinzufuegen und Entfernen, Serien,
Unsinn in der Liste. Mit Gegenprobe, die nachweist, dass die Messung
"nicht sichtbar" ueberhaupt erkennt. Im echten Browser gegengeprueft:
Schalter da, zwei angehakt, gespeichert, beide zurueck, keine
Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 14:21:09 +02:00
DogFatherGitandClaude Opus 5 8759a46e5b iPhone-Symbole: quadratisch und deckend statt abgerundet
Gemeldet: "auf dem pc und auf dem handy soll alles funktionieren, auf
dem einen klappt es und auf dem anderen nicht."

Der Grund ist, dass PC und Handy ihr Symbol an drei verschiedenen
Stellen holen -- und jede stellt andere Anforderungen:

  Browser-Reiter   das normale Symbol, runde Ecken erlaubt
  Android          die maskable-Fassung, aussen wird beschnitten
  iPhone           <link rel=apple-touch-icon> -- und iOS rundet SELBST
                   ab und fuellt alles Durchsichtige mit SCHWARZ

Unser 180er brachte seine eigene Rundung mit, also durchsichtige Ecken.
Auf dem iPhone wurden daraus schwarze Zipfel, die dann ein zweites Mal
beschnitten wurden. Auf dem PC sieht dieselbe Datei tadellos aus --
genau daher der Unterschied zwischen den Geraeten.

Jetzt wird die 180er-Fassung randvoll und deckend gebaut. Nachgemessen
an allen zehn: 0,00 Prozent durchsichtig, Ecken voll deckend. Die
normale Fassung bleibt abgerundet (4,75 Prozent) -- auch das gemessen,
damit der Fix nicht die andere Seite kaputtmacht.

Dazu eine Pruefung in pruef-struktur.mjs: alle sechs Groessen je App
vorhanden, und jede Seite nennt beide Symbolarten. Fehlt das
iPhone-Symbol, nimmt iOS einen Bildschirmausschnitt der Seite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 12:46:32 +02:00
DogFatherGitandClaude Opus 5 e9709a5aa8 Maskable-Symbole: das ganze Symbol verkleinern, nicht nur das Logo
Gemeldet von Filipe: "die symbole sehen aber auf meinem pc nicht aus
wie auf dem browser mit diesen geilen farben." Er hatte recht -- die
maskable-Fassungen sahen aus wie eine schlechte Kopie: blass, das
Medaillon riesig, der Doppelring ueber den Rand hinaus. Und genau die
nimmt das Betriebssystem fuer installierte Apps.

Der erste Entwurf verkleinerte nur das LOGO (52 statt 68 Prozent) und
liess den Hintergrund unveraendert. Das geht bei einer glatten Flaeche
gut und bei allem anderen schief: Medaillon, Doppelring, Raster und
Eckband rechnen ihre Kreise in Prozent der FLAECHE. Wird aussen ein
Fuenftel weggeschnitten, sitzt der Ring nicht mehr, wo er hingehoert.

Jetzt wird das fertige Symbol als Ganzes auf 78 Prozent verkleinert und
in eine Huelle aus dem dunkelsten Ton der App gesetzt. Damit bleibt
jedes Verhaeltnis erhalten -- Ring zu Flaeche, Logo zu Ring, Verlauf zu
Kante. Weggeschnitten wird nur ruhige Randfarbe.

Nachgeprueft mit einer Vorschau, die den Zuschnitt nachstellt: rund
(Android) und abgerundetes Quadrat (Windows/iOS). Beide sehen jetzt
praktisch aus wie die Fassung im Browser.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 12:12:54 +02:00
DogFatherGitandClaude Opus 5 37c2930af0 Kundenportal war nicht installierbar: Manifest hinter der Zugangswand
Live gemessen nach dem Deploy: Symbole 200, portal.webmanifest 302 auf
zugang.html. Der Browser bekam HTML statt JSON und bot "App
installieren" gar nicht erst an -- die ganze Arbeit am Symbol waere
fuer das Portal wirkungslos geblieben, ohne dass irgendwo etwas rot
geworden waere.

Das ist zum DRITTEN Mal derselbe Fehler an derselben Stelle
(app.webmanifest, verwaltung.webmanifest, jetzt portal.webmanifest).
Zweimal stand die Begruendung danach im Code -- beim dritten Mal wurde
sie trotzdem uebersehen. Ein Kommentar verhindert nichts.

Deshalb zusaetzlich eine Pruefung in pruef-struktur.mjs: Jedes Manifest
unter /webdesign/ MUSS in der Ausnahmeliste von webdesign-gate.js
stehen. Gegengeprobt -- Eintrag entfernt, Pruefung schlaegt an.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:56:43 +02:00
DogFatherGitandClaude Opus 5 7fe6a51233 ZockerAnstalt und Analyse: Symbole unter den richtigen Namen
Der erste Entwurf legte sie unter eigenen Namen daneben
(dogfather-zocker-192.png). Die Dateien lagen da, die Manifeste zeigten
weiter auf icon-192.png -- das neue Symbol waere nie angekommen. Der
Kopiervorgang meldete trotzdem 6 Symbole kopiert.

Jetzt werden die vorhandenen Namen ueberschrieben. Damit greifen
Manifest und HTML ohne weitere Aenderung, und es gibt keine zweite
Stelle, an der ein Verweis uebersehen werden kann. Fehlt ein erwarteter
Name, wird das gemeldet statt still uebergangen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:48:17 +02:00
DogFatherGitandClaude Opus 5 3decdab2f2 Laufprotokoll der Browserpruefung gehoert nicht ins Repo
Es entsteht bei jedem Lauf neu und ist ein Ergebnis, kein Quelltext.
Beim vorigen Commit versehentlich mitgenommen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:42:27 +02:00
DogFatherGitandClaude Opus 5 51c3d4402b Audit des Creator Workspace, App-Symbole fuer alle Apps der Domain
AUDIT (Auftrag: vollstaendiger Durchgang, Fehler direkt beheben)

Ausgangslage waren 40 Pruefungen mit 1616 Einzelpunkten, alle gruen.
Acht neue Pruefungen kamen dazu; sie haben gefunden, was die alten nicht
sehen konnten.

Der schwerste Fund: Die Zugangsschranke verglich req.path EXAKT gegen
eine Liste. Express raeumt Punkt-Segmente selbst weg, mehrfache
Schraegstriche aber nicht. Damit kam //workspace/start.html OHNE
Anmeldung mit HTTP 200, und ein Creator bekam ueber
/workspace//personen.html die Verwaltungsseite. Die DATEN waren nie
betroffen (nachgemessen: 404 bzw. 401). Behoben durch Normalisierung
UND eine Umkehr der Logik -- jetzt ist jede .html geschuetzt ausser der
Anmeldeseite, statt nur die in der Liste. Eine vergessene neue Seite
steht damit nicht mehr versehentlich offen.

Weiter behoben:
  * Kaputter/abgebrochener Rumpf ergab 500 in HTML statt 400 in JSON --
    die Oberflaeche ruft ueberall a.json() und lief in einen zweiten
    Fehler; der Knopf hing ohne Meldung.
  * POST /zustand/sichern war der einzige von 60 schreibenden Wegen
    ohne Herkunftspruefung.
  * workspace-sicherung.js gab interne Pfade in Fehlermeldungen nach
    aussen; alle 23 anderen Module antworten neutral.
  * admin_notiz war als einziges von 14 Feldern ohne <label>.
  * Der aktive Filter hatte keinen sichtbaren Fokus (CSS-Spezifitaet
    0,3,0 schlug 0,2,0) -- genau der Knopf, auf dem man steht.
  * h1 -> h3 ohne Zwischenstufe auf zwei Seiten.
  * HSTS ging auch ueber http mit (RFC 6797, 7.2 verbietet das).
  * upgrade-insecure-requests galt auch auf 127.0.0.1 -- dadurch war
    WebKit/Safari ueberhaupt nicht pruefbar, also der Browser, den
    jedes iPhone benutzt.
  * pruef-grosscheck las readdirSync(".") und pruefte aus server/
    gestartet NULL oeffentliche Seiten -- meldete aber "ok".

Neue Pruefungen: struktur, schranke, haerte, alle-wege,
barrierefrei-workspace, breiten, tempo-workspace, browser.
Jede mit Gegenprobe und mit der geprueften Anzahl in der Bedingung.
Vier davon sind beim Bauen durch die eigene Gegenprobe aufgeflogen und
haetten sonst dauerhaft gruen gemeldet, ohne etwas zu messen.

APP-SYMBOLE (Wunsch: alle Apps der Domain, jede anders, ausser
safeaddress)

Zehn Apps, zehn Stile, zehn in OKLCH gerechnete Farben. Zusammen haelt
sie dasselbe Logo, dieselbe Eckenrundung und eine gemeinsame gedeckte
Farbreihe. Beim Bauen wird gemessen, ob sich das Logo vom Grund abhebt
(19 bis 58 Helligkeitsstufen).

Dabei aufgefallen: Das Kundenportal hatte kein eigenes Manifest und
trug Namen und Symbol der Webdesign-Seite. Der Workspace hatte gar
keins und war als App nicht installierbar. Beide haben jetzt eins.

Geaendert wurde AUSSCHLIESSLICH das Symbol. Ein Zwischenstand hatte
auch die Themenfarben gesetzt; das war mehr als bestellt und wurde
zurueckgenommen.

Werkzeuge: tools/logo-freistellen.mjs, tools/app-symbole.mjs,
tools/app-symbole-einbinden.mjs -- alles im Browser gerechnet, kein
Bildprogramm, keine neue Abhaengigkeit.

Gitea und Nextcloud sind bereits live und nachgeprueft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:42:17 +02:00
Claudian b941080694 Die Namensliste ging beim Scrollen zu
FILIPE, mit Bildschirmfoto der Personenauswahl: "wenn ich da scollen will geht das immer zu"

Er hatte recht, und es war eine einzige Zeile in workspace/assets/js/wahl.js:

    addEventListener('scroll', schliessen, true);

Das dritte Argument bedeutet "in der Einfangphase lauschen" -- und damit auf JEDES
Scroll-Ereignis im ganzen Dokument, auch auf das in der Liste selbst. Wer die Namensliste
herunterrollen wollte, schloss sie im selben Moment. Bei acht Eintraegen faellt das kaum
auf; beim ganzen Manager- und Scout-Team ist die Liste unbedienbar.

Zumachen MUSS sie trotzdem, wenn die Seite scrollt: Sie haengt an position:fixed und
schwaemme sonst neben ihrem Knopf davon. Deshalb wird jetzt unterschieden, WO gescrollt
wurde -- ein Scroll-Ereignis der Seite hat document als Ziel, das ist nicht in der Liste
enthalten, also schliesst sie wie bisher.

Dazu overscroll-behavior: contain in gate.css. Ohne das reicht der Browser das Rollen am
Listenende an die Seite weiter, die Seite bewegt sich -- und daran schliesst die Liste zu
Recht. Der Fehler waere zur Haelfte zurueck gewesen.

GEPRUEFT im echten Browser am echten wahl.js und gate.css (pruef-wahl-scrollen.mjs, 7
Pruefungen), und zwar BEIDE Haelften der Zusage: Liste scrollt -> bleibt offen, Seite
scrollt -> geht zu. Eine Reparatur, die nur die eine Richtung sichert, waere die naechste
Ueberraschung.

Gegenprobe: alte Zeile testweise eingesetzt -> 2 Pruefungen fallen durch. Reparatur ->
alle 7 gruen.

Die Pruefung hat sich beim Bauen DREIMAL geweigert, etwas zu bestaetigen, das sie nicht
gemessen hatte -- "die Liste ist gar nicht laenger als ihr Fenster", "scrollTop = 0". Jedes
Mal lag es an meinem Aufbau (zu hohes Fenster, fehlende Stylesheets, Mausrad ohne Wirkung),
nie an der Reparatur. Gruen gemeldet haette sie es nie.

Der Versionsstempel muss mit: Cloudflare haelt JS und CSS vier Stunden im Browser fest.
Ohne neue Adresse saehe Filipe die Reparatur bis zu vier Stunden lang nicht.

HINWEIS ZUM COMMIT: In diesem Verzeichnis lag zum Zeitpunkt der Arbeit fremde,
uncommittete Arbeit -- vier Server-Dateien (heute 16:41-16:53 geaendert), sieben neue
Pruefdateien, ~110 Bildschirmfotos, eine Fokusring-Korrektur in gate.css und eine
Beschriftung in profil.html. Nichts davon ist hier drin. Bereitgestellt wurde ausdruecklich
nach Pfad, und die beiden Dateien mit gemischtem Inhalt (gate.css, profil.html) wurden dafuer
aus HEAD geholt und nur um den eigenen Anteil ergaenzt. Die fremde Arbeit steht unveraendert
im Arbeitsstand.
2026-09-04 19:18:02 +02:00
DogFatherGitandClaude Opus 5 15fe9bb197 Zwei Pruefungen an die getroffenen Entscheidungen angepasst
Der komplette Pruefstand vor der Vorstellung (38 Laeufe im Workspace)
lief bis auf zwei durch. Beide Fehlschlaege waren KEINE Fehler in der
Anwendung, sondern Pruefungen mit veraltetem Weltbild -- Folgen von
Entscheidungen, die Filipe selbst getroffen hat:

1. pruef-workspace-seiten (32 von 32 rot) pruefte, dass JEDE Seite ihre
   EIGENE Buehne hat (Aufgaben = Werkstatt, Kalender = Nachtstadt, ...).
   Am 03.09.2026 hat Filipe die neun Szenen durch EIN Bild ersetzt.
   Jetzt wird geprueft, was weiterhin wichtig ist: dass ueberhaupt ein
   Hintergrundbild ANKOMMT (ein data-buehne ohne CSS-Regel waere still
   wirkungslos) -- und dass es auf JEDER Seite dasselbe ist. Ohne die
   zweite Bedingung waere sie auch gruen, wenn irgendwo eine alte Szene
   zurueckkaeme.

2. pruef-zustand-ansicht erwartete, dass ein Manager den Systemzustand
   sieht. Seit dem 02.09.2026 gilt "die manager sollen diese kategorien
   garnicht sehen"; der Zustand gehoert zur Automationen-Seite.

Beide UMGEDREHT statt geloescht. Eine geloeschte Pruefung hinterlaesst
keine Spur davon, dass hier einmal etwas anderes galt -- und niemand
merkt, wenn eine Sperre spaeter versehentlich wieder faellt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 10:02:09 +02:00
DogFatherGitandClaude Opus 5 80639d0bab Abnahme vor der Vorstellung: eine tote Kachel gefunden und geschlossen
Morgen wird die Seite als Produkt vorgestellt. Deshalb eine Pruefung,
die es bisher nicht gab: server/pruef-live-abnahme.mjs geht gegen die
ECHTE Domain statt gegen einen Server auf diesem Rechner.

Der Unterschied ist nicht theoretisch. Zwischen "laeuft bei mir" und
"laeuft im Netz" liegen Caddy, Cloudflare, der Cache-Stempel, das
Zertifikat und der Dienst-Neustart -- genau dort ist am 18.08. und am
22.08.2026 schon zweimal etwas haengengeblieben, das lokal tadellos war.

Sie geht 26 Seiten in DREI Gestalten durch:
  RECHNER      1440 px
  HANDY        390 px, mit Fingerbedienung
  INSTALLIERT  als App vom Startbildschirm -- ohne Adresszeile und ohne
               Zurueck-Knopf des Browsers. Dort faellt auf, was man mit
               Browserleiste nie merkt.

Gemessen je Seite: Konsolenfehler, fehlgeschlagene Anfragen, seitlicher
Ueberlauf, tote Verweise, fehlende Bilder, ueberhaupt Inhalt, Titel.
Dazu die App selbst: Manifest, Name, Start ohne Browserleiste, alle vier
Startbildschirm-Symbole einzeln abgefragt, Hintergrunddienst angemeldet
und aktiv.

DER EINE ECHTE FUND: Auf links.html war die Kachel "Merchandise / Shop"
ein <a href="#"> -- sie sah aus wie ein Verweis, liess sich anklicken
und tat nichts. Auf der Kachel steht "Folgt in Kuerze"; genau dann darf
sie nicht klickbar sein. Ein Knopf, der nichts tut, ist schlimmer als
gar keiner: Man drueckt ihn zweimal und haelt die Seite fuer kaputt.
Jetzt ein <div> mit denselben Klassen -- gleiches Aussehen, kein
Versprechen mehr, das die Seite nicht halten kann.

ZWEI FEHLALARME, beide in MEINER Pruefung, beide aufgeschrieben:
  * Sie meldete "fehlende Bilder" auf zwei Seiten. Es waren versteckte
    Platzhalter (<img hidden> ohne src), die JavaScript erst fuellt --
    der Normalzustand. Jetzt zaehlen nur sichtbare Bilder mit Quelle.
  * Sie meldete "manifest.json nicht ladbar", waehrend curl gleichzeitig
    200 lieferte. Die Probe stand noch auf about:blank und holte von
    dort -- fremde Herkunft, der Browser lehnt ab. Sie hat also nicht
    die Seite geprueft, sondern sich selbst. Erst navigieren, dann
    messen.

Die beiden anderen href="#" auf der Seite (index.html, streamplan.html)
bleiben: Sie sind versteckt und werden von JavaScript gefuellt, sobald
es etwas zu verlinken gibt. Geprueft wird nur, was man auch sieht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 09:48:38 +02:00
DogFatherGitandClaude Opus 5 95f54fd211 Die ganze Oberflaeche spricht jetzt dieselbe Sprache wie die Zeichen
"bring alles auf dieses niveau -- texte, kacheln, hinweise, titel,
buttons, einfach alles."

Berechtigt, und der Fehler war meiner: Die Kachelzeichen sind Koerper
geworden, alles andere blieb flach. Ein plastisches Zeichen neben einem
gemalten Knopf sieht nicht nach "teilweise gut" aus, sondern nach
Versehen.

Ab jetzt gelten fuer JEDES Bauteil dieselben drei Regeln -- dieselben,
nach denen auch die Zeichen gebaut sind:

  1. LICHT VON OBEN. Eine helle Kante an der Oberkante, in der Mitte am
     staerksten, nach aussen auslaufend. Echtes Licht auf einer Kante
     sieht so aus; eine durchgehend gleich helle Linie ist ein Strich.
  2. TIEFE NACH UNTEN. Ein versetzter Schatten -- wie bei jedem
     Gegenstand, der auf etwas liegt. Ohne ihn klebt ein Element auf der
     Seite, statt darauf zu liegen.
  3. VERLAUF STATT FLAECHE. Oben eine Spur heller als unten. Kaum zu
     sehen, aber ohne ihn bleibt jede Flaeche tot.

Und eine vierte, nur fuer Bedienbares:
  4. WAS MAN DRUECKT, GEHT HINEIN. Beim Klick kehrt sich die Woelbung um:
     Licht nach unten, Schatten nach oben. Das ist der Unterschied
     zwischen "es passiert etwas" und "ich habe etwas gedrueckt".

ANGEFASST -- beide Seiten, nicht nur eine:

  Workspace (gate.css, gilt auf jeder Seite)
    Knoepfe, Schritte, Abmelden, Stufenknoepfe, Suchknopf
    Eingabefelder, Auswahlfelder, Suchfeld -- die bekommen die Woelbung
      ABSICHTLICH ANDERSHERUM: Ein Feld, in das man schreibt, ist eine
      Mulde, kein Knopf. Licht unten, Schatten oben.
    Marken, Rollenabzeichen, Zaehler, Filterchips
    Hinweisflaechen, Notizen, Call-Raum, Codekasten
    Ueberschriften und Schilder

  Oeffentliche Seite (main.css)
    Knoepfe (btn, btn-primary, btn-outline) samt geschliffener Kante
    Marken und Abzeichen
    Ueberschriften

Der Textschatten aendert die FARBE nicht -- die Kontrastpruefung misst
weiter denselben Wert --, legt den Text aber auf die Seite, statt ihn in
den Hintergrund zu mischen.

Alles gedeckt. Diese Bauteile stehen zu Dutzenden auf einer Seite, und
was einzeln beeindruckt, blendet im Dutzend.

GEPRUEFT, zehn Laeufe, alle gruen: Buehne 38 (Textkontrast an echten
Bildpunkten), Rollen 97, Handy 50, Formulare 19, Grosscheck 15,
Lesbarkeit 14 -- dazu die vier Laeufe der oeffentlichen Seite
(Startseite, Design, Barrierefreiheit, Tastaturbedienung).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 07:20:47 +02:00
DogFatherGitandClaude Opus 5 788a5fbd81 Die Zeichen sind jetzt KOERPER, keine Zeichnungen mehr
"wir kommen nicht voran, ich will das viel realistischer."

Berechtigt: Ich habe viermal dieselbe flache Zeichnung anders
BELEUCHTET -- Verlauf, Fuellung, Glanz, Schlagschatten. Das Verfahren
war das Problem, nicht die Einstellungen. Also gewechselt.

JEDES ZEICHEN HAT JETZT EINE HOEHE. Aufbau von hinten nach vorn:

  tiefe 3/2/1   dieselbe Silhouette, dreimal, je einen halben
                Rasterpunkt nach rechts unten versetzt und heller
                werdend. Das Auge liest die drei versetzten Kanten als
                EINE schraege Seitenwand -- genau so zeichnet man einen
                Quader von Hand. Drei Lagen sind gemessen: bei zwei
                sieht es aus wie ein Druckfehler, ab fuenf wie ein
                Schlagschatten.
  deck          die Oberseite: oben fast weiss, unten im Farbton. Die
                Flaeche, auf die das Licht faellt.
  glanz         die Spiegelung darauf.
  saum + linie  die Details.

Dafuer bekam jedes Zeichen eine SILHOUETTE (KOERPER in bereiche.js) --
den geschlossenen Umriss des Gegenstands, getrennt von den Details.
Die Details bekommen bewusst KEINE Tiefe: Ein aufgedruckter Strich
steht nicht hervor.

DER SAUM ist die Loesung eines Problems, das erst durch die Tiefe
entstand: Dieselbe Linie liegt ueber ZWEI Untergruenden. Der Querstrich
im Kalender liegt auf der hellen Deckflaeche, die Wellen der
LIVE-Analyse frei auf der dunklen Plakette. Eine dunkle Linie
verschwindet dort, eine helle auf dem Deck -- was immer man waehlt, die
Haelfte ist weg. Dunkler Saum plus helle Linie loest beides: auf dem
Deck liest man eine eingravierte Rille, auf der Plakette traegt die
helle Linie. Ein Zeichen, zwei Untergruende, eine Loesung.

GEPRUEFT: Buehne 38 (Textkontrast an echten Bildpunkten), Startansicht
133, Rollen 97, Handy 50, Grosscheck 15, Lesbarkeit 14. Alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 02:43:45 +02:00
DogFatherGitandClaude Opus 5 44716fa54b Aus Zeichnungen werden Gegenstaende -- Kacheln der GANZEN Seite
"ich will dass die krank realistisch sind, und alle kacheln durch die
ganze website perfektionieren."

DIE ZEICHEN bekommen die Beleuchtung, die man aus der Wirklichkeit
kennt -- vier Lagen statt einer:

  KOERPER        gefuellte Grundform, oben satt, unten auslaufend
  EIGENSCHATTEN  eine dunkle Lage, die von unten hereinkriecht. Ein
                 Koerper ist unten dunkler als oben; ohne das bleibt
                 jede Flaeche eine Farbflaeche
  GLANZ          die Spiegelung, schmal ueber die obere Haelfte
  KONTUR         mit ZWEI Lichtquellen: oben das Hauptlicht (fast weiss),
                 in der Mitte der Eigenton, unten STREULICHT vom
                 Untergrund. Der letzte Stopp ist der Unterschied
                 zwischen "Zeichnung" und "Ding" -- ohne ihn laeuft jede
                 Form nach unten ins Dunkle aus.

Dazu ein SCHLAGSCHATTEN auf die Plakette, versetzt nach unten statt
mittig. Er ist der Grund, warum das Zeichen ueber der Flaeche schwebt
statt darauf zu liegen.

DIE PLAKETTE bekommt eine KOERNUNG -- eine sehr feine, unregelmaessige
Struktur. Das ist der Unterschied zwischen "am Rechner gemacht" und
"Gegenstand": Eine makellos glatte Farbflaeche gibt es in der
Wirklichkeit nicht, und das Auge erkennt das sofort, auch wenn niemand
sagen koennte woran. Eingebettetes Rauschen, keine Bilddatei -- kostet
nichts zu laden und kann nicht fehlen.

DIE KACHELN, und zwar BEIDE Systeme:

  workspace  .kachel  -- bekam Tiefe nach unten (fehlte ganz: die Kachel
             klebte auf dem Hintergrund statt darauf zu liegen) und eine
             Lichtkante, die in der Mitte am hellsten ist und nach
             aussen auslaeuft. Echtes Licht auf einer Kante sieht so
             aus; eine durchgehend gleich helle Linie ist ein Strich.

  oeffentlich .card (133 Vorkommen auf der Website) -- war eine Flaeche
             mit einem Rand. Jetzt: Verlauf statt Flaeche, Lichtkante
             oben, Schatten nach unten. Beim Ueberfahren hebt sie sich,
             der Schatten wird laenger, die Kante heller.

Alles bleibt gedeckt. Diese Kacheln stehen zu Dutzenden auf einer Seite
-- was einzeln beeindruckt, blendet im Dutzend.

GEPRUEFT: Buehne 38 (Textkontrast an echten Bildpunkten), Startansicht
133, Rollen 97, Handy 50, Grosscheck 15, Lesbarkeit 14, dazu die drei
Laeufe der oeffentlichen Seite (Startseite, Design, Barrierefreiheit).
Alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 02:21:34 +02:00
DogFatherGitandClaude Opus 5 46e62fbaf7 Die Kachelzeichen komplett neu -- Plaketten statt getoenter Quadrate
Rueckmeldung: "ich will dass die viel krasser aussehen, du veraenderst
immer nur minimal." Berechtigt. Drei Durchgaenge lang habe ich an
Details gedreht (Verlauf, dann Fuellung) -- jeder fuer sich richtig, in
der Summe kaum sichtbar. Das hier ist der Umbau.

DIE PLAKETTE war ein leicht getoentes Quadrat mit duennem Rand. Sie ist
jetzt ein KOERPER:
  * 58 statt 52 px (gross: 70 statt 62)
  * Verlauf ueber die Diagonale statt flacher Toenung
  * Lichtkante oben INNEN, Schattenkante unten innen -- zusammen eine
    Woelbung, das Feld wirkt gepraegt statt gemalt
  * ein Hof in der eigenen Farbe darunter
  * ein Glanzbogen darueber, der von links oben einfaellt

DAS ZEICHEN war eine duenne Kontur. Es besteht jetzt aus DREI Lagen mit
je eigenem Verlauf:
  KOERPER   gefuellte Grundform, oben satt, unten fast weg -- eine
            gleichmaessig gefuellte Form ist ein Aufkleber, eine
            auslaufende ist ein Koerper
  GLANZ     schmaler heller Streifen quer ueber die obere Haelfte,
            genau auf dem Koerper. Die Spiegelung.
  KONTUR    oben fast WEISS, unten im Farbton. So sieht Metall aus, auf
            das Licht von oben faellt -- das ist der Grund, warum die
            Zeichen jetzt plastisch wirken statt gezeichnet.
Dazu 29 statt 25 px und Strichstaerke 2,05 statt 1,65: Die Zeichen
sollen TRAGEN, nicht andeuten. Zaghaft war genau das Problem.

Alle drei Verlaeufe stehen EINMAL im Dokument und arbeiten mit
currentColor -- sie nehmen den Ton jeder der siebzehn Kacheln an. Drei
Verlaeufe statt einundfuenfzig.

Alles bleibt gedeckt: Ein leuchtender Kasten waere in einer dunklen
Oberflaeche eine Lampe, und Lampen schaut man nicht stundenlang an.
Im Wasserzeichen hinter dem Kacheltext und im Kontrastmodus bleiben
Koerper und Glanz aus.

GEPRUEFT: Buehne 38 (Textkontrast an echten Bildpunkten -- die
kraeftigeren Plaketten duerfen die Lesbarkeit nicht antasten),
Startansicht 133, Rollen 97, Handy 50, Grosscheck 15, Lesbarkeit 14.
Alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 01:59:59 +02:00
DogFatherGitandClaude Opus 5 7d77f3ea6b Die Zeichen bekommen eine Flaeche -- aus Konturen werden Piktogramme
"ich will die symbole in den kacheln noch viel krasser und geiler."

Bis eben war jedes Zeichen eine reine Kontur. Sauber, aber neutral --
siebzehn gleich starke Umrisse nebeneinander, wie aus jedem
Symbolbaukasten.

Jetzt besteht jedes aus ZWEI Teilen:

  FUELLUNG   eine gefuellte Grundform, gedeckt hinterlegt
  LINIE      die scharfe Zeichnung darueber, mit dem Verlauf von gestern

Das ist der Unterschied zwischen einem Symbol und einem Piktogramm.
Sobald ein Teil FLAECHE hat, bekommt das Zeichen ein Vorn und ein
Hinten, und das Auge erkennt es, ohne es zu lesen.

Gefuellt wird immer das, WORUM ES GEHT -- nie alles:

  Kalender    der Kopf des Blattes (daran erkennt man ihn aus drei Metern)
  Aufgaben    die mittlere Spalte -- "in Arbeit", dort passiert etwas
  Dashboard   zwei der vier Felder ueber Eck, das gibt Rhythmus
  Ordner      der Korpus ohne die Lasche, damit die Stufe sichtbar bleibt
  Berichte    aus drei Strichen werden drei SAEULEN (ein Balkendiagramm
              hat Balken)
  Start-Check nur der Haken -- ein gefuelltes Klemmbrett waere ein Kasten
  Personen    der Kopf; bei zwei Personen nur der VORDERE, daraus
              entsteht die Tiefe
  Buch        die linke Seite -- eine im Licht, eine im Schatten
  Technik     die drei Griffe
  LIVE        der Sender in der Mitte; gefuellte Wellen saehen aus wie
              ein Auge
  Trichter    nur der obere Teil, sonst kippt das Zeichen nach unten

20 % Deckkraft sind gemessen, nicht geraten: darueber wird das Zeichen
zum Fleck und die Linie darin unsichtbar, darunter sieht man die Flaeche
gar nicht. Beim Ueberfahren geht sie auf 30 %, als kaeme Licht dazu.

WARUM NICHT EINFACH DICKER -- der Unterschied zum gescheiterten Versuch
von gestern: Der legte eine dicke, WEICHGEZEICHNETE KOPIE DER LINIE
darunter und hat damit jede Luecke zugeschmiert (aus dem Kalender wurde
ein leerer Kasten). Eine Flaeche ist etwas anderes als ein aufgeblasener
Strich: Sie liegt INNERHALB der Kontur und laesst die Zwischenraeume
unberuehrt. Genau deshalb funktioniert es jetzt.

Im Wasserzeichen und im Kontrastmodus bleibt die Flaeche aus -- dort
wuerde sie den Text hinterlegen bzw. zu einem massiven Block werden.

GEPRUEFT: Buehne 38 (Textkontrast an echten Bildpunkten -- die Flaeche
darf die Lesbarkeit nicht antasten), Startansicht 133, Rollen 97,
Handy 50, Team 30, Grosscheck 15, Lesbarkeit 14. Alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 01:41:16 +02:00
DogFatherGitandClaude Opus 5 a9815e291a Ein Hintergrund fuer alles -- und Zeichen, die endlich vollstaendig sind
ZWEI AUFTRAEGE.

1. DER NEUE HINTERGRUND
   Das Dogfather/Spicy-Media-Bild loest die neun Buehnen ab. Der Login
   behaelt ausdruecklich sein eigenes Bild (body.gate, unangetastet) --
   dort wird der Zugangscode eingegeben, und genau das sollte bleiben.

   Nicht einfach hingelegt: Das Bild ist sehr kraeftig, vor allem die
   rote Haelfte. Ohne Behandlung fiel der Textkontrast auf 3,03:1
   (noetig sind 4,5:1) -- ausgerechnet in der Personenverwaltung und auf
   dem Aufgabenbrett. Gemessen hat das server/pruef-buehne.mjs, das den
   Kontrast an bis zu 36 echten Bildpunkten je Seite nachrechnet.

   In vier Schritten angepasst und jedes Mal nachgemessen:
     -0,14 Helligkeit -> 4,12:1   (immer noch zu wenig)
     -0,20 Helligkeit -> 4,48:1   (zwei Hundertstel zu wenig)
     -0,23 Helligkeit -> 4,63:1   bestanden, alle Seiten
   Dazu Saettigung 0,72 und Gamma 0,91 -- dieselbe Behandlung, die auch
   die alten Buehnen bekommen haben (tools/buehne-bauen.mjs arbeitet mit
   Helligkeit 0,66 bis 0,88). Das Bild bleibt ein Bild und wird nicht
   zur Tapete, aber Text steht darauf lesbar.

2. DIE ZEICHEN
   Sie bekommen einen VERLAUF: oben hell, nach unten gedaempft -- eine
   Lichtquelle ueber dem Zeichen, wie in der echten Welt. Dazu ein
   weicher Schlagschatten in der eigenen Farbe. Der Verlauf ist EINMAL
   definiert und arbeitet mit currentColor: ein Verlauf fuer siebzehn
   Kachelfarben.

   ZWEI SACKGASSEN AUF DEM WEG, beide aufgeschrieben statt weggeraeumt:

   a) Erst lag unter jeder Linie eine dicke, weichgezeichnete Kopie --
      "Licht, das die Linie wirft". Bei einem grossen Symbol traegt das.
      Hier nicht: Ein Zeichen ist 24 Einheiten breit und 25 px gross,
      eine Einheit ist also ein Pixel. Linie 1,65 plus Schein 2,5 fuellt
      jede Luecke, die enger als vier Einheiten ist -- aus dem Kalender
      wurde ein leerer Kasten. Gesehen habe ich das erst bei dreifacher
      Vergroesserung; auf dem normalen Schirm sah es nur "satter" aus.
      Die Lage ist wieder weg.

   b) Der Verlauf lief zunaechst in OBJEKTKOORDINATEN. Damit wird er auf
      den Umriss jedes einzelnen Pfades gerechnet -- und eine waagerechte
      Linie hat die Hoehe null. Der Verlauf ist dann entartet, und der
      Browser zeichnet den Pfad GAR NICHT. Verschwunden waren dadurch:
      die Querlinie im Kalender, alle drei Regler-Striche in Technik,
      die Grundlinie der Berichte. Jetzt laeuft er in Benutzer-
      koordinaten ueber die festen 24 Einheiten -- was ohnehin richtiger
      ist, denn das Licht kommt von oben und nicht von jedem Strich
      einzeln.

   AUSSERDEM ECHT REPARIERT: Das Technik-Zeichen hatte drei Griffe aus
   Boegen der Laenge null ("a1.4 1.4 0 1 0 0-.02z") -- sie wurden nie
   gezeichnet. Uebrig blieben drei nackte Striche, die aussahen wie ein
   Menue-Symbol. Jetzt sind es echte Kreise. Kalender und Dashboard haben
   mehr Luft zwischen ihren Linien bekommen, damit sie bei 25 px nicht
   zu einer Flaeche verschmelzen.

GEPRUEFT: Buehne 38 (Kontrast an echten Bildpunkten), Startansicht 133,
Rollen 97, Handy 50, Grosscheck 15, Lesbarkeit 14 -- alle gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 01:26:52 +02:00
DogFatherGitandClaude Opus 5 0404f8c0c1 Dreizehn Lecks: eine Managerin sah die Creator aller anderen
Wunsch: "jeder manager soll auch immer nur seine und die seiner scouts
zugeteilten creator und creator daten sehen. und nicht die der anderen."

DIE KETTE WAR GEBAUT -- SIE WURDE NUR NICHT BENUTZT
Manager -> seine Scouts -> deren Creator steht seit dem 01.09.2026 an
genau einer Stelle (betreuteIds). Die Frage war eine andere: Benutzt sie
auch JEDER Weg, der Creator-Daten herausgibt? Ueber zwanzig Stellen
prueften die ROLLE statt der ZUTEILUNG -- "ist Leitung? dann alles".

NICHT GELESEN, SONDERN GEMESSEN
server/pruef-manager-sicht.mjs baut zwei Managerinnen mit vollstaendig
getrennten Creators. Bei der fremden heisst ALLES "GEHEIM..." -- Aufgabe,
Termin, Bereichseintrag, Datei, Steckbrief, Content-Saeule. Danach wird
jede der 31 Leseschnittstellen abgefragt und die ganze Antwort danach
durchsucht. Ein Leck faellt damit auf, egal wo es sitzt und egal, ob ich
es beim Lesen uebersehen haette.

GEFUNDEN: DREIZEHN. Alle geschlossen:

  Kalender          fremde Fristen -- besonders unangenehm, weil es
                    nicht wie ein Leck aussieht: eine kleine orange
                    Marke mit einem Titel, in dem fremde Vorhaben stehen
  Personenauswahl   alle Namen im Zuweisungsfeld
  Dateien           alle Namen in der Freigabe-Auswahl
  Uebersicht        Gesamtuebersicht ueber ALLE Creator
  Report            Auswahl UND Auswertung ueber den ganzen Bestand
  Start-Check       alle Creator zur Auswahl
  Steckbriefe       Bild, Kanaele, "ueber mich" von allen
  Profile           alle Profile, samt interner Notiz
  Schulung          Schulungsstand aller Creator
  Suche             Creator-Profile aller -- die unauffaelligste Stelle:
                    Man sucht etwas anderes und bekommt fremde Namen
  Content-Balance   Themensaeulen fremder Kanaele (die Abfrage daneben
                    war korrekt eingeschraenkt, DIESE hatte eine eigene
                    Bedingung)
  darfCreator       eine einzige Zeile -- sie hing an Profil,
                    Start-Check und Uebersicht gleichzeitig. Es reichte,
                    eine Nummer in die Adresse zu schreiben.

Die Antwort steht jetzt an EINER Stelle: sichtbareCreatorIds und
sichtbarePersonenIds in workspace.js. Rueckgabe null heisst "alle" und
gilt allein DogFather -- bewusst kein leeres Feld: Eine leere Liste
bedeutet "niemand", und die Verwechslung der beiden macht aus einer
Sperre eine Freigabe.

ZWEI DINGE, DIE ICH MIR SELBST NACHTRAGEN MUSS

1. Beim Stopfen fehlte einmal ein Import. Der Weg warf einen Fehler,
   antwortete 503 -- und weil in einer Fehlermeldung kein "GEHEIM" steht,
   meldete die Pruefung "kein Leck". Sie war gruen, weil der Weg KAPUTT
   war. Die Pruefung zaehlt jetzt beides: nichts durchsickern UND
   antworten.

2. Ein Fehlalarm: Die Suche gibt den SUCHBEGRIFF in ihrer Antwort
   zurueck. Wer nach "GEHEIM" sucht, findet das Wort zwangslaeufig --
   auch bei null Treffern. Ich haette um ein Haar ein Leck "repariert",
   das es nie gab. Das Echo wird jetzt entfernt, bevor gemessen wird.

FOLGEN, bewusst in Kauf genommen:
  * Ein Manager ohne Zuteilung sieht keinen Creator. Die Uebersicht sagt
    ihm das jetzt in einem Satz, statt leer zu bleiben.
  * Er kann nur noch IN SEINEN Creator-Bereichen schreiben (darfCreator).

ZWEI PRUEFUNGEN UMGEDREHT statt geloescht -- eine geloeschte Pruefung
hinterlaesst keine Spur davon, dass hier einmal etwas anderes galt:
pruef-uebersicht ("Manager sieht dasselbe" -> "nur seine zugeteilten",
mit beiden Faellen) und pruef-scout-zuteilung ("sieht die ganze
Personenliste" -> "landet auf der Startseite").

GEPRUEFT: 43 neue Pruefungen, dazu 23 bestehende Laeufe gruen --
Startansicht 133, Rollen 97, Kalender 84, Serien 67, Steckbrief 65,
Handy 50, Sicht 48, Ampel 47, Content 45, Aufgabenbrett 44, Schulung 41,
Bereiche 37, Scout-Zuteilung 36, Uebersicht 35, Personenliste 33,
Freie Namen 32, Team 30, Protokoll-Loeschen 20, Personenformular 20,
Formulare 19, Betreuung 18, Code 17, Grosscheck 15.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 01:01:00 +02:00
DogFatherGitandClaude Opus 5 d8720debc1 Personen & Automationen gehoeren DogFather allein -- und das Formular laeuft nicht mehr ueber
ZWEI MELDUNGEN.

1. "DAS SIEHT JA MAL RICHTIG SCHEISSE AUS"
   Die Rollenauswahl im Formular "Neue Person" lief unten aus dem
   Formular heraus und legte sich ueber die Personenliste darunter.

   Die Ursache war keine schlampige Gestaltung, sondern eine Regel, die
   fuer etwas anderes gemacht ist: `.neu__raster > *` (aufgaben.css) gibt
   JEDEM direkten Kind ein Raster mit fester Zeilenhoehe von 44 px, damit
   Beschriftung und Eingabefeld in allen Spalten auf einer Linie sitzen.
   Fuer ein einzeiliges Feld ist das genau richtig. Die Rollenauswahl ist
   aber kein Feld, sondern ein Block aus vier hohen Karten -- die passten
   nicht in 44 px, und was nicht hineinpasst, steht eben daneben.

   Das Formular ist jetzt aus dem Spaltenraster geloest und liest sich
   von oben nach unten: NAME (schmal, ein Name braucht keine 1200 px),
   ROLLE (volle Breite, vier gleich breite Karten), Knoepfe. Das ist
   nicht nur reparierter Ueberlauf, sondern auch die Reihenfolge, in der
   man die Sache tatsaechlich entscheidet.

   Dazu zwei Kleinigkeiten, die den Unterschied machen: Das Namensfeld
   war ohne Rasterzeile 60 px hoch geworden (`height: 100%` einer Zeile,
   die es nicht mehr gibt) -- hoeher als die Knoepfe daneben, was nach
   Versehen aussieht, weil es eins war. Und die gewaehlte Rolle traegt
   jetzt ein HAEKCHEN, nicht nur einen etwas helleren Rahmen: Genau die
   Art Unterschied, die im Kontrastmodus verschwindet und fuer
   farbunsichere Augen nie existiert hat.

2. "DIE MANAGER SOLLEN DIESE KATEGORIEN GARNICHT SEHEN"
   "Personen & Zugaenge" und "Automationen" gehoeren ab sofort allein
   DogFather.

   Bei den Personen war es ohnehin ein Widerspruch im eigenen Haus: In
   der Rollenauswahl steht seit jeher "Manager -- dieselben Rechte wie
   DogFather, AUSSER der Personenverwaltung". Die Kachel stand trotzdem
   bei ihm, und die Schranke liess ihn hinein: Codes erneuern, sperren,
   Zuteilungen aendern. Eine Beschreibung, die etwas anderes sagt als die
   Software, ist schlimmer als beides einzeln -- man weiss danach nicht
   mehr, welcher von beiden man glauben soll.

   Umgesetzt auf DREI Ebenen, weil Wegnehmen was man SIEHT kein
   Rechteentzug ist:
     1. die Kachel erscheint nicht mehr
     2. die Seite leitet zur Startseite zurueck (GESCHUETZT)
     3. die Schnittstellen antworten mit 404 -- Personenverwaltung,
        Systemzustand, KI-Schalter

   FOLGE, die bewusst in Kauf genommen wird: Die Betreuungs-Zuteilung
   liegt auf der Personenseite. Ab jetzt kann also NUR DogFather
   festlegen, wer welchen Creator betreut.

GEPRUEFT: server/pruef-personen-formular.mjs, 20 Pruefungen. Das Aussehen
wird gemessen, nicht angesehen: Endet die Rollenauswahl innerhalb des
Formulars? Ragt eine Karte seitlich hinaus? Liegt etwas ueber der Liste?
Sind alle vier Karten gleich breit (272-272 px)? Traegt die gewaehlte ein
Haekchen? Dazu zwei Gegenproben: DogFather kommt weiterhin an beide
Bereiche (sonst waere jede Sperr-Zeile auch bei einem fuer ALLE kaputten
Bereich gruen), und die Managerin arbeitet ansonsten unveraendert weiter.
Bestehende Laeufe gruen: Rollen 97, Handy 50, Sicherung 41, Personenliste
33, Team 30, Formulare 19, Code 17, Grosscheck 15.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-03 00:00:41 +02:00
DogFatherGitandClaude Opus 5 e7b277b7fc Die Startseite log nicht -- sie war nur alt. Und Protokolle lassen sich loeschen
Drei Meldungen aus einer Nachricht.

1. "WIRD IMMER NOCH ANGEZEIGT"
   Ein Protokoll war geschrieben, die Startseite meldete trotzdem weiter
   "1 Gespraech hat noch kein Protokoll".

   NACHGESTELLT statt vermutet: Der Server lag die ganze Zeit richtig.
   Der Hinweis erscheint, sobald ein vergangenes Gespraech kein Protokoll
   hat, und verschwindet in dem Moment, in dem eines geschrieben ist --
   nachgemessen, beides.

   Falsch war der BILDSCHIRM. Browser legen eine verlassene Seite
   vollstaendig beiseite (bfcache) und holen sie beim Zurueckgehen
   unveraendert hervor, mitsamt allen Zahlen vom ersten Laden. Kein
   Skript laeuft dabei erneut. Wer ein Protokoll schreibt und dann auf
   "Zurueck" tippt, sieht zwangslaeufig den Stand von vorher.

   Das ist kein Schoenheitsfehler: Eine Zahl, die etwas Falsches
   behauptet, ist schlimmer als gar keine -- man glaubt ihr ja. Und sie
   kostet danach Vertrauen in ALLE Zahlen.

   kopf.js laedt eine zurueckgeholte Seite jetzt neu. Nur dann
   (`event.persisted`), nicht bei jedem Anzeigen -- sonst waere es eine
   Endlosschleife. Gilt fuer jede Workspace-Seite, nicht nur die
   Startseite.

2. PROTOKOLLE LOESCHEN -- NUR DOGFATHER
   Bewusst istDogFather und nicht istLeitung: Ein Manager hat sonst
   ueberall dieselben Rechte, hier ausdruecklich nicht. Wer ein Protokoll
   entfernen darf, kann nachtraeglich bestimmen, was besprochen wurde.

   Geloescht wird NUR das Protokoll. Das Gespraech bleibt im Kalender und
   rutscht wieder zu "Protokoll fehlt" -- die Handlung ist damit
   umkehrbar: neu schreiben, fertig. Die daraus entstandenen AUFGABEN
   bleiben ebenfalls stehen; sie sind echte Arbeit, die jemand uebernommen
   hat, und mit einem Klick auf ein Protokoll zu verschwinden waere ein
   stiller Datenverlust an ganz anderer Stelle.

   Der Knopf steht nur bei DogFather. Ein Knopf, der bei anderen
   erscheint und dann abgewiesen wird, ist eine Einladung zum Aergernis.

3. IMMER NUR EINS OFFEN
   Vorher liessen sich beliebig viele Protokolle gleichzeitig aufklappen
   -- die Seite wurde so lang, dass die Liste darunter aus dem Blick
   geriet. Ein neu geoeffnetes Gespraech schliesst jetzt das vorherige.
   Beim Laden ist alles zu.

GEPRUEFT: server/pruef-protokoll-loeschen.mjs, 20 Pruefungen. Die
Zurueck-Pruefung misst an EINZAHL gegen MEHRZAHL ("1 Gespraech HAT" gegen
"2 Gespraeche HABEN") -- die Zahl selbst steht in einem eigenen Feld und
taucht im Fliesstext nicht auf. Drei Gegenproben: dass der Hinweis nach
dem Reparieren ueberhaupt noch anschlaegt (sonst waere "verschwunden"
auch bei kaputtem Hinweis gruen), dass eine Managerin 403 bekommt und das
Protokoll danach unveraendert dasteht, und dass der Loeschknopf bei ihr
gar nicht erst gezeichnet wird. Bestehende Laeufe gruen: Startansicht 133,
Rollen 97, Kalender 84, Serien 67, Protokoll-Klappe 52, Handy 50, Ampel
47, Freie Namen 32, Code 17.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 23:45:45 +02:00
DogFatherGitandClaude Opus 5 fc26597083 Wer sich einen neuen Code gibt, sperrt sich nicht mehr selbst aus
Gemeldet: "ich hab einen neuen code fuer mich gemacht aber ich wurde raus
gekickt bevor ich den neuen code kopieren konnte jetzt komm ich nicht mehr
rein."

DER FEHLER
Ein neuer Code beendete ALLE Sitzungen der Person -- auch die, in der der
Code gerade auf dem Bildschirm stand. Der naechste Aufruf der Seite lief in
ein "nicht angemeldet", die Umleitung zur Anmeldung nahm den Kasten samt
Code mit, und der Code ist nirgends noch einmal abrufbar (in der Datenbank
steht nur seine Pruefsumme). Ergebnis: ausgesperrt, Rueckweg nur ueber
einen Eingriff auf dem Server.

Bitter daran: Die Rueckfrage sagte das sogar an ("Deine aktuelle Sitzung
wird sofort beendet") -- als Warnung formuliert, nicht als Fehler erkannt.
Ein Ablauf, den man nur mit gutem Timing ueberlebt, ist keiner.

DREI RIEGEL, NICHT EINER

1. DIE EIGENE SITZUNG BLEIBT. codeNeu() beendet weiterhin alle Sitzungen
   der Person -- ausser der einen, aus der heraus der Code gerade erneuert
   wird. Sicherheitlich kostet das nichts: Wer den Code tauscht, hat sich
   mit genau dieser Sitzung soeben ausgewiesen und haelt sie in Haenden.
   Alle ANDEREN Geraete fliegen weiterhin hinaus -- das ist der Sinn der
   Uebung und wird eigens geprueft.

2. DER KASTEN BLEIBT STEHEN. Solange ein frischer Code angezeigt wird,
   springt die Personenseite nicht mehr von selbst zur Anmeldung. Selbst
   wenn eine Sitzung aus einem anderen Grund endet (Zeitablauf, Neustart),
   bleibt der Code lesbar, bis er weggeklickt ist -- mit einem Hinweis,
   ihn jetzt abzuschreiben. Ein Code, den man nicht mehr lesen kann, ist
   schlimmer als gar keiner.

3. EINE TUER VON AUSSEN: tools/notfall-code.sh. Setzt auf dem Server einen
   neuen Code, zeigt ihn an und loescht die Sperre nach acht Fehlversuchen
   gleich mit. Weigert sich, als root zu laufen (sonst gehoerten die
   Hilfsdateien der Datenbank danach root und der Dienst koennte nicht
   mehr schreiben). Dokumentiert als "Fall 0" in WIEDERHERSTELLUNG.md --
   dem ersten Fall, den man aufschlaegt, wenn nichts kaputt ist ausser
   dem Zugang.

   KEIN fest hinterlegter Notfall-Code in der Anwendung: Der waere eine
   Hintertuer, die dauerhaft offensteht, fuer jeden der sie findet, ohne
   dass es auffiele. Dieser Weg verlangt Zugang zum Server, hinterlaesst
   einen Protokolleintrag, und es gibt nichts zu erraten.

Die Rueckfrage sagt jetzt, was wirklich passiert, statt vor etwas zu
warnen, das nicht mehr eintritt.

GEPRUEFT: server/pruef-code.mjs, 17 Pruefungen -- darunter die Gegenprobe,
dass das ZWEITE Geraet derselben Person sehr wohl abgemeldet wird (ohne sie
waere die Reparatur auf dem Weg, einen neuen Code zur Formalie zu machen),
dass der alte Code nicht mehr gilt, dass beim Erneuern eines FREMDEN Codes
weiterhin alles hinausfliegt, und dass die Seite nach dem Erzeugen nicht
zur Anmeldung springt. Das Notfall-Skript ist mit beiden Wegen getestet
(Treffer und unbekannter Name). Bestehende Laeufe gruen: Rollen 97,
Personen-Liste 33, Sicht 48.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 23:05:29 +02:00
DogFatherGitandClaude Opus 5 540b5d8838 Freie Namen, ein Call-Knopf, und drei Seiten, die fuer Scouts kaputt waren
DREI SACHEN AUF EINMAL, alle aus derselben Sitzung.

1. AUSSUCHEN ODER SELBST EINTRAGEN
   Wunsch: "ich will da auch sachen selber noch eintragen koennen, also
   aussuchen und selbst eintragen."

   Jede Personenauswahl (Kalender, Aufgaben, Bereiche, Content, Dateien)
   nimmt jetzt auch einen getippten Namen an -- eine Agentur, eine Marke,
   einen Gast ohne Konto. Dazu bekommt JEDE Auswahl ab acht Eintraegen
   ein Suchfeld: tippen statt scrollen.

   Gebaut IM vorhandenen Auswahl-Bauteil (wahl.js), nicht daneben. Der
   erste Anlauf war ein zweites Bauteil -- es hat sich prompt mit dem
   ersten gebissen, beide haben denselben <select> eingepackt. Ein
   zweites haette ausserdem anders ausgesehen und waere beim naechsten
   Umbau nur an einer von zwei Stellen nachgezogen worden.

   Der freie Name steht in einer EIGENEN Spalte je Feld; die Verknuepfung
   bleibt leer. Entweder eine Person ODER ein Name, nie beides.

   Filipe hat ausdruecklich auch bei den Creator-Feldern freie Namen
   gewollt, nachdem der Nachteil benannt war: Der Eintrag gehoert dann zu
   keinem Konto. Damit daraus kein STILLER Ausfall wird, faellt jede
   Abfrage, die bisher den Namen der verknuepften Person las, jetzt auf
   den freien Text zurueck (externSql) -- gekennzeichnet als "(extern)".
   Der Eintrag verschwindet dadurch aus keiner Liste, keiner Suche und
   keiner Uebersicht.

2. WO FUEHRE ICH DEN CALL?
   Den Knopf gab es, aber nur wenn jemand von Hand einen Link ins
   Ortsfeld getippt hatte UND das Gespraech noch bevorstand. Stand dort
   "Hier", war nichts zum Anklicken da.

   Jetzt hat das Team einen festen Call-Raum (Discord-Sprachkanal), den
   das Management einmal hinterlegt. Danach hat JEDER Call den Knopf --
   und er bleibt, solange das Gespraech laufen kann, nicht nur bis zur
   Startzeit. Ein eigener Link am Termin schlaegt den festen Raum.

3. WAS EINE ROLLE SIEHT, MUSS AUCH FUNKTIONIEREN
   Gemeldet: "cigdem kriegt als manager gewisse sachen nicht auf die sie
   sieht, check jede rolle ab."

   Neue Pruefung server/pruef-rollen.mjs schickt SECHS Rollen-Zustaende
   ueber alle 16 Seiten und misst Konsolenfehler, fehlgeschlagene
   Serveraufrufe, tote Verweise, haengende Ladeanzeigen und wortlos leere
   Seiten. 96 Durchgaenge.

   Der sechste Zustand ist der wichtige: eine Rolle OHNE zugeteilte
   Creator -- der Normalfall am ersten Tag und Cigdems echte Lage.
   Genau dort fielen die Seiten durch, waehrend dieselben Seiten MIT
   Zuteilung tadellos waren.

   VIER ECHTE FEHLER GEFUNDEN UND BEHOBEN:

   a) Eine Aufgabe, die eine Managerin ohne Creator anlegte, war fuer sie
      im selben Moment unsichtbar -- creator_id und verantwortlich_id
      leer, und "von mir selbst angelegt" stand in keiner
      Sichtbarkeitsregel. Nur DogFather sah sie noch. Kein Fehler, keine
      Meldung, die Aufgabe war einfach weg. Dasselbe bei den
      Bereichseintraegen. Beide Regeln kennen jetzt erstellt_von.
      Niemand sieht dadurch etwas Fremdes -- nur das Eigene.

   b) Ein Scout ohne zugeteilten Creator bekam auf die GESAMTE
      Report-Seite 404, obwohl sie fuer ihn verlinkt ist. Die Seite
      antwortet jetzt sauber und leer, statt sich zu verweigern.

   c) Start-Check und Report blieben fuer immer auf "wird geladen"
      stehen, wenn es nichts zu laden gab.

   d) Das Creator-Profil war fuer Scouts ohne Zuteilung wortlos leer --
      der erklaerende Satz stand nur in der grauen Unterzeile.

   Ausserdem meldete die bestehende Lesbarkeitspruefung zwei neue
   Beschriftungen von mir als zu klein fuers Handy (10,88 statt 11,5 px).
   Behoben, und dieselbe Groesse an der Serien-Karte gleich mit -- dort
   waere es erst aufgefallen, sobald jemand eine Wiederholung anlegt.

GEPRUEFT: pruef-rollen 97, pruef-freie-namen 32 (mit Gegenproben:
Ben sieht Cigdems Aufgabe NICHT; die Saeulen-Zuordnung nimmt
ausdruecklich KEINEN freien Namen). Alle bestehenden Laeufe gruen:
Startansicht 133, Kalender 84, Serien 67, Protokoll 52, Handy 50, Sicht
48, Ampel 47, Content 45, Aufgabenbrett 44, Sprung 43,
Personen-Loeschen 40, Bereiche 37, Uebersicht 33, Workspace-Seiten 32,
Formulare 19, Betreuung 18, Grosscheck 15, Lesbarkeit 14.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 20:10:09 +02:00
DogFatherGitandClaude Opus 5 23429627ef Termine, die von allein weiterlaufen -- bis man sie abstellt
Wunsch: "ich will dass ich da im kalender auch sachen machen die jede
woche jeden monat automatisiert immer weiter laufen so wie ich es
auswaehle bis ich es selber deaktiviere. aktiviere diese option fuer
jeden."

Acht Rhythmen (taeglich, werktags, woechentlich, alle zwei Wochen,
monatlich am Datum, am Monatsletzten, am n-ten Wochentag, jaehrlich),
wahlweise mit Enddatum oder ohne Ende. Fuer JEDE Rolle -- Creator und
Scouts legen sie fuer sich selbst an, mit denselben Grenzen wie beim
einzelnen Termin.

WARUM ECHTE TERMINE UND KEINE GERECHNETEN AUSPRAEGUNGEN

Der naheliegende Weg waere gewesen, die Wiederholung nur beim Anzeigen
auszurechnen. Das waere ein stiller Ausfall geworden: ACHT andere Stellen
lesen die Tabelle termine direkt -- Calls, Protokolle, Berichte,
Hinweise/Ampel, Suche, Aufgaben ("naechster Termin"), Uebersicht und die
Startseite. In all diesen Ansichten haette schlicht nichts gestanden, und
aufgefallen waere es erst Monate spaeter. Stattdessen macht ein
Nachfueller aus der Regel echte Zeilen (Horizont 180 Tage) -- jedes andere
Modul sieht sie mit, ohne dass dort eine Zeile geaendert werden musste.
Beim geplanten ICS-Abo gilt dasselbe.

KEIN ZEITGEBER. Der Nachfueller laeuft beim Serverstart, beim Anlegen und
Aendern und beim Oeffnen des Kalenders (dort hoechstens alle fuenf
Minuten). Er ist idempotent. Ein Cron waere eine weitere Sache gewesen,
die stillschweigend ausfallen kann.

WAS BEIM ABSTELLEN PASSIERT: Vergangene Termine und alles, was jemand von
Hand angefasst hat (verschoben, umbenannt, abgehakt), bleibt stehen. Nur
die unberuehrte Zukunft wird aus dem Kalender genommen. Wer einen
einzelnen Tag loescht, streicht nur diesen einen -- der Tag wird als
Ausnahme vermerkt, sonst legte der Nachfueller ihn wieder an.

ZEITUMSTELLUNG: Gerechnet wird auf reinen Datumstexten in UTC-Mittag, die
Uhrzeit wird als Text angehaengt. 18:00 bleibt dadurch 18:00 und wandert
im Oktober nicht auf 17:00.

DIE SICHTBARKEITSREGEL STEHT JETZT NUR NOCH EINMAL (workspace.js,
termineSichtbar) statt zweimal fast gleich. Zwei Fassungen waeren
auseinandergelaufen -- und dann haette eine Wiederholung jemandem etwas
gezeigt, was der einzelne Termin ihm verbirgt.

IN DER OBERFLAECHE beschriften sich die Rhythmen nach dem gewaehlten
Datum ("jeden Dienstag", "jeden Monat am letzten Dienstag") statt
abstrakt ("woechentlich"), inklusive des ehrlichen Hinweises, dass "jeden
31." den Februar auslaesst. Darunter steht der ganze Satz in Worten. Eine
neue Leiste "Laeuft von allein" zeigt alle laufenden Wiederholungen mit
Abstell-Schalter -- was von selbst weiterlaeuft, muss man sehen koennen.

GEPRUEFT: 67 Pruefungen (server/pruef-serien.mjs), darunter von Hand
nachgeschlagene Datumsangaben fuer jeden Takt (der letzte Dienstag im
Dezember 2026 ist der 29., nicht der 22.; der 29. Februar nur in
Schaltjahren) und vier GEGENPROBEN, die beweisen, dass die Pruefungen
auch "nicht in Ordnung" sagen koennen. Die Anzahl der Pruefungen steht in
der Bedingung, nicht nur im Meldetext. Bestehende Pruefungen unveraendert
gruen: Kalender 84, Sicht 48, Startansicht 133, Protokoll 52, Ampel 47,
Handy 50, Aufgabenbrett 44, Sprung 43, Personen-Loeschen 40, Uebersicht
33, Workspace-Seiten 32, Formulare 19, Betreuung 18, Grosscheck 15,
Lesbarkeit 14.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 17:12:00 +02:00
DogFatherGitandClaude Opus 5 1d54058760 Die Sicht wirkt jetzt auch auf die SEITE, nicht nur auf die Listen
Gemeldet: "ich hab oben die Ansicht von Tili ausgewaehlt und seh immer
noch die Seite genau wie meine." Das stimmte.

Der Umschalter war HALB gebaut. Die Daten dahinter folgten der Auswahl
(Aufgaben, Kalender, Dateien, Bereiche, Hinweise, Suche) -- die Seite
drumherum nicht: /workspace/api/ich lieferte immer den Angemeldeten, und
daraus baut die Startseite ihre Kacheln, die Rollenzeile und die
Begruessung. DogFather sah einen fremden Arbeitsplatz in seiner eigenen
Verkleidung.

ZWEI FEHLER STECKTEN DARIN.

1. /api/ich verschwieg die gewaehlte Sicht. Es liefert sie jetzt als
   eigenes Feld `sicht` -- NEBEN den eigenen Angaben, nicht an ihrer
   Stelle. Die Oberflaeche braucht beides: WER BIN ICH (Kopfleiste,
   "das bin ich" in Listen, alles was schreibt) und WESSEN ARBEITSPLATZ
   SEHE ICH (was gezeigt wird). Die beiden zu vermischen waere der
   sichere Weg dazu, dass irgendwann etwas unter fremdem Namen
   gespeichert wird.

2. EIN FEHLER DER REIHENFOLGE, und der war der eigentliche Grund.
   In kopf.js wurde `aktiv` (welche Sicht laeuft) erst in
   sichtAufbauen() gesetzt -- das laeuft ueber werZeigen(), also
   NACHDEM die Seite ihre erste Abfrage abgeschickt hat. Ausgerechnet
   /api/ich, aus dem Kacheln, Rolle und Begruessung entstehen, ging
   damit IMMER ohne die gewaehlte Sicht hinaus. Beide Zeilen waren fuer
   sich richtig; im Quelltext sieht man so etwas nicht.

WAS JETZT PASSIERT: In der Sicht auf einen Creator verschwinden die
Leitungs-Kacheln (18 -> 14, kein "Personen & Zugaenge", keine
"Automationen"), die Gruppe heisst "Wissen" statt "Team & System" --
genau wie bei ihm -- und unter dem Gruss steht "Arbeitsplatz von Tili ·
Creator". Plakette und Name oben bleiben die eigenen: Man ist weiterhin
man selbst, man sieht nur einen anderen Arbeitsplatz.

WARUM DIE PRUEFUNG DAS UEBERSEHEN HAT, und das ist die Lehre: Sie hat
geprueft, dass WENIGER AUFGABEN erscheinen -- und das stimmte ja. Sie
prueft genau die Haelfte, die fertig war. Jetzt prueft sie auch, dass
die Leitungs-Kacheln verschwinden, die Gruppentitel mitgehen und
dransteht, wessen Arbeitsplatz man ansieht.

Beim Schreiben dieser Pruefung dieselbe Falle noch einmal: Sie mass
"seine eigenen Kacheln", waehrend aus einem Abschnitt davor noch die
Scout-Sicht lief (die ueberlebt den Seitenwechsel, das ist gewollt), und
meldete einen Fehler, den es nicht gab. Eine Pruefung, die ihren eigenen
Ausgangszustand nicht herstellt, misst den Nachhall der vorigen.

31 von 31 Dateien, 1236 von 1236 Einzelpunkten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 16:21:39 +02:00
DogFatherGitandClaude Opus 5 60c3edb10d Verirrte Datei aus dem Worker-Ordner entfernt -- Wert vorher geprueft
Im Ordner cloudflare-worker/ lag seit dem 12.08.2026 eine Datei, deren
Name ein verunglueckter Windows-Pfad ist
("UsersqcigaDocumentsObelixDogFather.tmp-new-code.txt"). Darin: eine 14
Zeichen lange Zufallszeichenfolge. Sie kam mit dem Commit "Alle
ausstehenden Aenderungen fuer den Server-Umzug uebernommen" herein --
offensichtlich versehentlich.

WARUM SIE AUFFIEL: Von aussen sah sie aus wie ein offen liegender
Zugangscode. Ueber die Website war sie zwar nicht erreichbar (sie liegt
ausserhalb der ausgelieferten Ordner, 404) -- aber aus Gitea konnte sie
JEDER ohne Anmeldung abrufen: 200, 14 Bytes.

WAS DIE PRUEFUNG ERGAB, und deshalb steht sie hier fuer immer
nachlesbar, damit niemand sie ein zweites Mal machen muss:

  * Der Wert ist KEIN gueltiger Zugangscode. Geprueft mit genau der
    Rechnung, die auch die Anmeldung benutzt (scrypt mit dem Salz jeder
    Person, timingSafeEqual gegen den gespeicherten Hash):
    6 Personen geprueft, 0 Treffer.
  * Die Website-Schranke von vor dem Go-Live ist nicht mehr in Betrieb --
    der Dienst dogiweb setzt ueberhaupt keine Zugangscodes.
  * Der Wert steht an keiner anderen Stelle im Code.

Er war also wertlos. Geloescht wird die Datei trotzdem: Sie SIEHT aus
wie ein Geheimnis, und der Naechste, der sie findet, macht dieselbe
Untersuchung noch einmal.

Zur Klarheit, falls das je wieder aufkommt: Ein Loeschen im Verzeichnis
entfernt nichts aus der Historie. Waere der Wert gueltig gewesen, waere
das Loeschen die falsche Antwort gewesen -- dann haette der Code
GEAENDERT werden muessen. Hier ist beides unnoetig, weil er nie gegolten
hat.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 15:59:30 +02:00
DogFatherGitandClaude Opus 5 bd42a0462e Cache-Stempel nachgezogen -- sonst waere die Aenderung nicht angekommen
Der vorige Commit aenderte personen.js, aber die HTML-Dateien trugen
weiterhin den alten Stempel (?v=202609020145). Cloudflare liefert
Dateien vier Stunden lang aus dem Zwischenspeicher: Die neue Auswahl
"Gehoert zu" waere bis in den Vormittag hinein bei niemandem
angekommen -- und der Deploy haette dabei fehlerfrei ausgesehen.

Aufgefallen ist es nur, weil in `git status` keine einzige HTML-Datei
stand. Genau das ist das Merkmal: Wer JS oder CSS aendert und danach
keine geaenderten HTML-Dateien sieht, hat den Stempel vergessen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 02:17:19 +02:00
DogFatherGitandClaude Opus 5 9134b30d06 Scouts gehoeren zu einem Manager ODER zu DogFather -- wie bei den Creatorn
Wunsch vom 02.09.2026: "ich will die Rollen, welcher Scout welchem
Manager oder DogFather gehoert, wie es bei den Creator ist, drunter."

Die Auswahl stand bisher nur dann unter einem Scout, wenn es ueberhaupt
einen Manager gab -- und es gibt zurzeit keinen. In der Personenliste war
davon also nichts zu sehen. Jetzt steht sie immer da, mit Managern UND
DogFather zur Wahl, genau wie "Betreut von" bei den Creatorn.

DIE BEIDEN FAELLE BEWIRKEN VERSCHIEDENES, und das ist Absicht:
  MANAGER    Der Eintrag entscheidet ueber SICHTBARKEIT -- er sieht
             danach die Leads dieses Scouts und dessen Creator.
  DOGFATHER  Der Eintrag haelt nur die ZUSTAENDIGKEIT fest. An den
             Rechten aendert er nichts; DogFather sieht ohnehin alles.

Genau diese Unterscheidung gilt bei den Creatorn seit dem 31.08. auch.
Vorher hatte ich einen Scout unter DogFather abgewiesen mit der
Begruendung, der Eintrag bewirke nichts. Das war zu eng gedacht: Er
beantwortet die Frage "wen frage ich?", und das ist der Zweck dieser
ganzen Liste.

Ein Scout unter einem Scout bleibt ausgeschlossen -- eine Ordnung, die
es nicht gibt.

ZWEI DINGE MITGEZOGEN, damit die Liste nicht zwei Sprachen spricht:
  * Der Leerwert heisst wieder "— niemand —" wie bei den Creatorn.
    "— direkt bei DogFather —" sah aus wie eine Zuordnung und war
    keine -- derselbe Fehler war bei den Creatorn schon einmal behoben
    worden, weil dieselben Leute dadurch gleichzeitig als "ohne
    zustaendige Person" gezaehlt wurden.
  * Die Rolle steht nur dann in Klammern, wenn sie etwas hinzufuegt.
    "Dogfather (DogFather)" waere zweimal dasselbe Wort.

Die Pruefung haelt jetzt BEIDES fest: dass die Zuteilung an DogFather
geht -- und dass sie niemandem mehr Sicht gibt. Verschwimmt dieser
Unterschied je, faellt es dort auf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 02:16:42 +02:00
DogFatherGitandClaude Opus 5 d7cf598b00 "Heute" war zwei Stunden lang gestern -- und vier Fehler auf Handy und PC
Auftrag: "einen grossen Check machen, ob alles klappt, auf dem Handy und
PC." Dafuer ein neuer Rundgang (pruef-grosscheck.mjs), der stumpf ueber
alles geht: 19 Workspace-Seiten mal 4 Rollen mal 2 Bildschirmgroessen
plus 33 oeffentliche Seiten, zweimal. 208 Seiten, 50 774 Elemente.

Solche Rundgaenge finden andere Fehler als gezielte Pruefungen: nicht
den falsch gerechneten Wert, sondern die Seite, die bei genau einer
Rolle ueberlaeuft.

=== DER WICHTIGSTE FUND: "heute" war in UTC gerechnet ===

Der Check lief um 01:10 Uhr. Ortszeit war der 2. September, in UTC noch
der 1. -- und in diesem Fenster rechnete die Anwendung an ZWOELF Stellen
"heute" als toISOString(), also in UTC. Server und Benutzer stehen beide
auf Europe/Berlin.

Was das im Alltag bedeutete, jede Nacht zwischen 0 und 2 Uhr:
  * eine heute faellige Aufgabe galt noch nicht als faellig
  * eine um Mitternacht ueberfaellig gewordene erschien erst um 2 Uhr
  * der Filter "Heute faellig" zeigte den Vortag
  * Datumsfelder schlugen gestern vor
  * der Kalender begann seine Vorgabe einen Tag zu frueh

Also genau dann, wenn nach einem Stream gearbeitet wird.

kalender.js machte es die ganze Zeit RICHTIG -- samt Begruendung, warum
die ARITHMETIK trotzdem in UTC laufen muss (UTC-Mittag ueberlebt die
Zeitumstellung; wer lokal rechnet, verliert am 27. Oktober einen Tag).
Diese Trennung gilt jetzt ueberall, aus je einer Quelle:
  RECHNEN mit Datumsangaben  -> UTC-Mittag, unveraendert
  WELCHER TAG IST HEUTE      -> Ortszeit (heuteLokal/tagLokal im Server,
                                window.heuteLokal in kopf.js)

WIE ES AUFFIEL, und das ist die eigentliche Lehre: Zuerst schlugen zwei
Pruefungen fehl -- und die Ursache lag in IHNEN, sie rechneten selbst in
UTC (36 Stellen in 17 Dateien). Nach deren Reparatur schlugen sie WIEDER
fehl, und erst da zeigten sie auf die Anwendung. Wer beim ersten Mal
aufgehoert haette ("ist ja nur die Pruefung"), haette den echten Fehler
nie gesehen.

Nachtrag desselben Musters: pruef-uebersicht legte den Termin weiterhin
in UTC an, waehrend die Erwartung schon auf Ortszeit stand. Wer eine
Datumsrechnung umstellt, muss BEIDE Seiten umstellen -- die, die
schreibt, und die, die prueft.

=== VIER FEHLER AUF HANDY UND PC ===

1. Ein langer Creator-Name ("SpongBobSchwammKopf") schob die Startseite
   auf dem Handy um 48 Pixel aus dem Bild -- ein Wort ohne Trennstelle,
   und die Seite liess sich seitlich wegschieben. Trifft echte Namen:
   Creator heissen selten "Tim".

2. Die klebende Speicherleiste verdeckte auf dem Handy ein Textfeld.
   Beim Tippen sieht man die eigene Zeile nicht. Behoben mit
   scroll-margin-bottom (WCAG 2.2, 2.4.11 "Focus Not Obscured").

3./4. Zwei Beschriftungen waren mit 9,6 px (Uebersicht: "ueberfaellig",
   "dringend", "offen") und 9,9 px (Kalender: "heute") zu klein. Fuers
   Handy gab es laengst eine Ausnahme -- nur der Rechner war vergessen
   worden. Ausgerechnet die Woerter, die den Zahlen ihre Bedeutung geben.

=== WAS KEINE FEHLER WAREN ===

Der erste Durchgang meldete 19 Maengel, die keine waren. Alle einzeln im
Quelltext nachgeprueft und dem Rundgang beigebracht:
  * Kacheln und Kopfzeilen "abgeschnitten" -- das Wasserzeichen ragt
    ABSICHTLICH ueber den Rand (steht so im Quelltext)
  * "verdeckt: wahl2__echt" -- das echte <select> liegt absichtlich
    unsichtbar unter seinem Knopf
  * "zurueck-knopf__text abgeschnitten" -- das uebliche Muster fuer
    "nur fuer Vorleseprogramme"
  * drei "zu kleine" Verweise -- WCAG 2.5.8 nimmt Verweise im Fliesstext
    AUSDRUECKLICH aus. Eine Pruefung, die ihre eigene Messlatte nicht
    kennt, misst nichts.

Beim vierten Punkt haette ich fast an der falschen Stelle repariert.

Und statt die Sticky-Meldung abzuschalten (dann faende sie auch echte
Ueberdeckungen nie mehr), wurde sie GENAUER: Ueberdeckt etwas Klebendes
ein Eingabefeld, ist das nur in Ordnung, wenn das Feld genug
scroll-margin-bottom hat, um darunter hervorzukommen. Aus einer vagen
Meldung wird eine pruefbare Zusage.

Vier Gegenproben belegen, dass der Rundgang ueberhaupt etwas finden
kann: ein zu breites Element, ein winziger Knopf, ein winziger Verweis
AUSSERHALB eines Satzes und ein wirklich abgeschnittenes Wort werden
alle gemeldet. Ohne diesen Nachweis waere "alles in Ordnung" wertlos.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-02 01:51:28 +02:00
DogFatherGitandClaude Opus 5 9e523d3ea2 Manager sehen nur noch ihre zugeteilten Scouts -- und deren Creator
Wunsch vom 01.09.2026: "er soll nur die Scouts sehen, die ihm zugeteilt
sind." Dazu entschieden: Ein Manager sieht dann AUCH die Creator dieser
Scouts, und zuteilen darf NUR DogFather.

WAS VORHER WAR. Ein Manager sah die gesamte Scout-Pipeline -- alle Leads
aller Scouts, dazu dieselben in der Suche und in "Was ist dran". Das war
die letzte Stelle, an der "nur DogFather sieht alles" noch nicht galt.

EINE EIGENE TABELLE, KEIN ZWEITER EINTRAG IN `betreuung`.
Dort heisst die Spalte creator_id, und der ganze uebrige Code liest sie
als "das ist ein Creator". Ein Scout darin waere technisch moeglich und
fachlich eine Luege gewesen: betreuteIds() gaebe Scout-Nummern zurueck,
die anderswo als Creator behandelt wuerden. Solche Abkuerzungen raechen
sich genau dann, wenn niemand mehr weiss, dass sie getroffen wurden.

DIE KETTE steht an EINER Stelle (betreuteIds in workspace.js):
Manager -> seine Scouts -> deren Creator. Ohne sie muesste jeder Creator
einem Manager einzeln zugewiesen werden, und beim ersten vergessenen
faende er ein Loch in seiner Uebersicht, ohne zu merken, dass es eines
ist. Dieselbe Regel gilt fuer Leads in Pipeline, Suche und Hinweisen --
aus einer Quelle (pipelineIds), nicht dreimal abgeschrieben.

ZUTEILEN DARF NUR DOGFATHER, und das ist keine Foermlichkeit: Diese
Zuteilung ERWEITERT die Sicht eines Managers. Duerfte er sie selbst
setzen, koennte er sich seine eigene Sichtbarkeit vergeben -- eine
Grenze, die der Begrenzte selbst verschieben kann, ist keine. Deshalb
istDogFather und ausdruecklich NICHT istLeitung.

In der Personenliste steht bei jedem Scout "Gehoert zu", sichtbar nur
fuer DogFather. Der Leerwert heisst "— direkt bei DogFather —" und nicht
"— niemand —": Ein Scout ohne Manager ist nicht unbetreut, er haengt an
DogFather. Das ist ein Zustand, kein Mangel.

NEBENBEI KORRIGIERT: In der Zustaendigkeits-Route stand als Kommentar
noch "ein Eintrag auf DogFather oder Manager aendert an den Rechten
nichts, die Leitung sieht ohnehin jeden Creator". Das gilt seit heute
nicht mehr -- fuer einen Manager entscheidet dieser Eintrag jetzt sehr
wohl ueber die Sichtbarkeit. Ein falscher Kommentar ist schlimmer als
keiner: Er wird geglaubt.

DIE PRUEFUNG STELLT DEN MISSBRAUCH AN DEN ANFANG. Diese Aenderung
erweitert Sichtbarkeit -- alles andere heute hat sie eingeschraenkt. Ein
Fehler dort zeigt jemandem zu wenig und faellt auf; ein Fehler hier
zeigt zu viel und faellt niemandem auf. Geprueft wird deshalb: Manager
und Scout duerfen nicht zuteilen (404, und es wird auch wirklich nichts
geschrieben), Scout an Scout und Scout an DogFather werden abgewiesen,
ein Creator laesst sich nicht zuteilen. Danach die Kette in beide
Richtungen, das Zuruecknehmen, und dass ein Scout zu genau einem Manager
gehoert.

Ein lehrreicher Fehlschlag in der Pruefung selbst: Sie meldete, die
Auswahl fehle in der Oberflaeche. Sie fehlte nicht -- die Personenliste
ist nach Rollen ZUGEKLAPPT, und die Pruefung hatte nicht aufgeklappt.
Sah aus wie ein Produktfehler, war einer der Pruefung. Sie klappt jetzt
auf und stellt vorher fest, dass wirklich alle sieben Zeilen dastehen.

Gesamtlauf: 30 von 30 Dateien, 1210 von 1210 Einzelpunkten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 22:44:30 +02:00
DogFatherGitandClaude Opus 5 15cfee1078 Gesamtlauf aller Pruefungen -- und eine Pruefung, die nichts geprueft hat
Auf "CHECK MAL AB, DASS ALLES PERFEKT LAEUFT. ALLES."

Ergebnis: 29 von 29 Pruefdateien in Ordnung, 1178 von 1178 Einzelpunkten
bestanden. Der Server laeuft ohne Neustart, alle 33 oeffentlichen Seiten
antworten, keine Schnittstelle gibt ohne Anmeldung etwas heraus.

DER EIGENTLICHE FUND WAR EINE PRUEFUNG, DIE NICHTS GEPRUEFT HAT.

tools/alles-pruefen.mjs zaehlt nicht nur gruen/rot, sondern die ANZAHL
der Einzelpruefungen je Datei -- und pruef-kopf-messen.mjs kam auf NULL.
Sie war nie eine Pruefung, sondern ein reines Messwerkzeug: Sie druckte
Zahlen und endete IMMER mit Exitcode 0. Weil sie "pruef-..." heisst, lief
sie bei jedem Gesamtlauf mit und meldete brav "bestanden". Sie konnte
gar nicht fehlschlagen.

Mit blossem Auge war das nicht zu sehen: Der Lauf war gruen, die Datei
stand unauffaellig zwischen den anderen. Aufgefallen ist es nur, weil
die Zahl mitgezaehlt wurde -- ein gruener Lauf ist eben kein Beweis,
solange nicht auch die Anzahl stimmt.

ZWEI KONSEQUENZEN:

1. Die Datei prueft jetzt wirklich. Die beiden Zahlen, um die es geht,
   wurden laengst gemessen und werden nun auch beurteilt:
     UEBERSTAND          muss 0 sein
     ABMELDEN ERREICHBAR muss wahr sein -- es ist der einzige Weg wieder
                         heraus; liegt er ausserhalb des Bildes, sitzt
                         man fest.
   Die Messwerte bleiben in der Ausgabe: Sie sagen bei einem Fehlschlag
   sofort, WELCHES Teil zu breit ist.
   Gegenprobe gemacht: Mit einer unerfuellbaren Bedingung meldet sie
   "3 Breiten gemessen, 3 beanstandet" und endet mit 1. Sie kann also
   anschlagen -- vorher nicht.

2. Der Laeufer wertet "0 Pruefungen" ab jetzt als FEHLER, nicht als
   Erfolg. Sonst haette dieselbe Falle beim naechsten Mal wieder
   jemanden getaeuscht.

Der Laeufer selbst bleibt im Ordner tools/: Er faengt einen Fehlschlag
je Datei ab (statt beim ersten abzubrechen), zeigt die Dauer mit -- eine
Pruefung, die ploetzlich dreimal so lange braucht, wartet meist auf
etwas, das es nicht mehr gibt -- und druckt am Ende die Gesamtzahl.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 21:59:36 +02:00
DogFatherGitandClaude Opus 5 da49a227f1 Aufgabenbrett fuer alle Rollen -- und nur DogFather sieht alles
Wunsch vom 01.09.2026: "verbessere die Aufgabenseite auch bei Manager,
Scout und Creator. Die Scouts und Manager sollen vielleicht ein bisschen
mehr Optionen haben, wie ihre zugeteilten Creator. Aber auch die Creator
sollen es besser und detaillierter sehen. ABER NUR DIE ROLLE DOGFATHER
SOLL WIRKLICH WEITERHIN ALLEINE ALLES SEHEN KOENNEN."
(Nachgereicht: "die Seite Aufgabe auch bei DogFather machen bitte.")

ZWEI FEHLER IN DEN RECHTEN, die beim Nachsehen herausfielen:

  1. Ein MANAGER sah auf dem Aufgabenbrett GAR NICHTS. Die Regel kannte
     nur admin, creator und scout; er fiel in den Zweig "unbekannte
     Rolle sieht nichts". Ein leeres Brett sieht aus wie "nichts zu
     tun", nicht wie ein Fehler -- deshalb ist das lange niemandem
     aufgefallen.

  2. In Kalender, Dateien, Bereichen und Content sah derselbe Manager
     dagegen ALLES (istLeitung). Zwei entgegengesetzte Antworten auf
     dieselbe Frage, in einem Programm.

Jetzt gilt ueberall dasselbe: NUR DogFather sieht alles. Manager und
Scout sehen ihre eigenen Sachen plus die Creator, die ihnen zugeteilt
sind. Dafuer arbeitet betreuteIds() jetzt auch fuer Manager -- die
Datenbank konnte das laengst (in `betreuung` steht eine beliebige
Person), nur diese eine Funktion hat alle ausser Scouts abgewiesen.

GEAENDERT WURDE NUR, WER WAS SIEHT. Was ein Manager DARF -- freigeben,
aendern, Personen verwalten -- haengt weiterhin an istLeitung und ist
unberuehrt. Ohne diese Trennung haette ein Wunsch nach weniger Sicht
stillschweigend die halben Rechte mitgenommen; die Pruefung haelt beides
ausdruecklich fest.

DIE SEITE SELBST bekommt drei Zeilen ueber dem Brett, und die
Reihenfolge ist die Aussage:
  1. WAS BRENNT -- ein Satz beim Reinkommen. Ein Brett aus vier Spalten
     beantwortet das nicht; man muesste alle vier durchsehen, um zu
     wissen, dass nichts brennt.
  2. AUSSCHNITTE -- "Nur meine", "Heute faellig", "Ueberfaellig", jeder
     mit seiner Zahl am Knopf. Ein Filter, der sich erst nach dem Klick
     als leer herausstellt, kostet zweimal Aufmerksamkeit. Sie filtern
     das Brett, statt eine zweite Liste aufzumachen: Vier Spalten
     nebeneinander sind der Wert dieser Seite.
  3. DIE CREATOR -- fuer Betreuer und DogFather, je mit offener Anzahl
     und einer Warnzahl fuer Ueberfaelliges. Bei DogFather heisst die
     Reihe "Alle Creator", sonst "Deine Creator": "deine" waere bei ihm
     eine falsche Auskunft.

Ein Creator bekommt weder "Nur meine" noch die Creator-Reihe -- bei ihm
ist ohnehin alles seins, und ein Filter mit einem einzigen Eintrag ist
ein Knopf, der nichts tut. Die Liste der Creator stammt aus den
Aufgaben selbst und nicht aus einer Personenabfrage: Dann stehen dort
genau die, die man ohnehin sehen darf, und niemals einer mehr.

NEBENBEI (Screen 1): In der Betreuer-Auswahl stand "Dogfather
(DogFather)" -- zweimal dasselbe Wort, nur anders geschrieben. Die
Klammer entfaellt jetzt, wenn sie dasselbe sagt wie der Name.

pruef-aufgabenbrett.mjs prueft die ABGRENZUNG zuerst und an konkreten
Aufgaben, deren Titel verraten, wem sie gehoeren -- eine huebschere
Filterleiste ist eine Annehmlichkeit, eine Rechteregel, die zu viel
zeigt, ist ein Schaden. Dazu eine Gegenprobe zur alten Regel (der
Manager sieht ueberhaupt etwas) und die ausdrueckliche Bestaetigung,
dass er weiterhin anlegen darf.

Ein Fehler steckte in der Pruefung selbst: Sie erwartete beim Creator
eine feste Zahl und haing damit von ihrer eigenen Reihenfolge ab -- der
Abschnitt davor legt eine weitere Aufgabe an. Sie vergleicht jetzt gegen
die Schnittstelle. Das ist ohnehin die bessere Frage: nicht "sind es
drei", sondern "verschluckt die Seite etwas".

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 21:38:38 +02:00
DogFatherGitandClaude Opus 5 1c00770ec5 Lesbarere Kaesten, und DogFather kann durch fremde Augen sehen
SCREEN 1 -- "die Kachel ganz leicht dunkler, so dass man den Text besser
gelesen bekommt, aber nicht zu viel, so dass man den Hasen noch sieht."

Die Erklaerkaesten stehen jetzt auf 88 statt 78 Prozent Deckung. Zehn
Punkte sind gemessen der Unterschied zwischen muehsam und ruhig lesbar
und lassen zwoelf Prozent Bild durch -- das Motiv bleibt sichtbar.

"und die von wichtigen und neuen PDFs sollen auch staerker sein."
Das war kein Geschmack, sondern ein Fehler: `background` ist eine
Eigenschaft, keine Schicht. Die Zeile
`background: rgba(232,192,125,.045)` hat die Flaeche nicht getoent,
sondern ERSETZT -- uebrig blieben viereinhalb Prozent Deckung. Damit war
ausgerechnet die Anleitung, die jeder lesen soll, die am schwersten
lesbare der Seite. Die Toenung liegt jetzt als Schicht darueber.
Gemessen: 88 % gegen 78 % bei einer gewoehnlichen.

pruef-lesbarkeit.mjs misst das an ECHTEN PIXELN (Text kurz unsichtbar
machen, Flaeche fotografieren, WCAG-Formel) und kennt ZWEI Grenzen --
lesbar genug UND durchsichtig genug. Mit nur einer haette sie eine
schwarze Flaeche am besten gefunden, und das wollte niemand.

SCREEN 2 -- "ich will alles von den Scouts und Managern einsehen
koennen, auswaehlen, was und von wem. Ueberall, auf jeder Seite.
NUR WIR BEIDE SOLLEN DIESE OPTION HABEN."

Die naheliegende Loesung waere ein Filter je Seite gewesen -- also eine
zweite Rechteregel in zwoelf Modulen, und eine Rechteregel an zwoelf
Stellen stimmt irgendwann an elf. Stattdessen wird die PERSON getauscht,
nicht die Regel: Waehlt DogFather einen Scout, laufen alle vorhandenen
Sichtbarkeitsregeln unveraendert mit diesem Scout. Er sieht exakt dessen
Arbeitsplatz -- nicht mehr, nicht weniger. Keine neue Rechteregel.

Im Browser genauso: EIN Ort statt vierzehn. fetch wird einmal umgeleitet
und haengt den Wert an jede lesende Abfrage an. Neue Seiten sind damit
von selbst dabei; man kann es nicht vergessen.

Drei Sicherungen: nur admin (auf dem SERVER geprueft, nicht in der
Oberflaeche), nur lesend (geschrieben wird immer im eigenen Namen --
sonst staende im Protokoll der falsche Name), nur aktive Personen.

Und ein Rahmen um die Seite, solange eine fremde Sicht laeuft. Der
gefaehrlichste Fall ist nicht, dass man nicht umschalten kann, sondern
dass man vergisst, dass man umgeschaltet hat -- und drei Aufgaben statt
dreissig fuer den Bestand haelt.

FUENF FEHLER, DIE DIE PRUEFUNGEN GEFUNDEN HABEN:

1. steckbrief.html hat die Kopfleiste NIE gefuellt -- dort stand
   monatelang "…" statt des eigenen Namens. Aufgefallen, weil der
   Umschalter dort fehlte. Jetzt zusaetzlich ein Netz darunter: Meldet
   sich nach kurzer Zeit niemand, holt der Kopf sich selbst, wer
   angemeldet ist. Die naechste neue Seite kann es nicht mehr vergessen.

2. Der Umschalter sprengte die Kopfleiste (46 px am Rechner, 117 px am
   Handy) und drueckte den Abmelden-Knopf hinaus.

3. Ich habe das <select> gestaltet -- wahl.js ersetzt aber jedes
   Auswahlfeld durch einen eigenen Knopf und schrumpft das echte Feld
   auf einen Pixel. Meine Regeln haben es wieder auf 20 x 44 aufgeblasen,
   wo es als unsichtbares Hindernis ueber dem Knopf lag. Gestaltet wird
   jetzt der Knopf.

4. Ein Wettlauf: Auf profil.html rufen zwei Dateien werZeigen() auf.
   Beide kamen an "gibt es den Umschalter schon?" vorbei, bevor eine ihn
   angehaengt hatte -- zwei Umschalter uebereinander. Die Sperre gehoert
   vor das erste await.

5. Die Handy-Pruefung bemaengelte ein Schild, das dort per display:none
   gar nicht erscheint. Sie sieht jetzt nur noch sichtbaren Text an --
   eine Pruefung, die Unsichtbares anmahnt, gewoehnt man sich ab zu
   lesen.

Dazu zwei Messfehler in den Pruefungen selbst: getComputedStyle liefert
ein LEBENDES Objekt (die Farbe wurde gelesen, nachdem der Text
unsichtbar gemacht war -- gemeldet wurden 1,17:1 fuer tadellos lesbaren
Text), und ein Vergleich lief still ins Leere, weil die Vergleichsdaten
fehlten.

pruef-sicht.mjs stellt den MISSBRAUCH an den Anfang: Scout, Manager und
Creator haengen ?sicht= an und muessen ignoriert werden; erfundene
Nummern, Buchstaben und ein Einschleusversuch fallen auf die eigene
Sicht zurueck; eine abgeschaltete Person liefert keine Sicht mehr; und
was DogFather bei fremder Sicht anlegt, steht unter SEINEM Namen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 21:20:23 +02:00
DogFatherGitandClaude Opus 5 24c66a022e Kennzahlen-Reihe auf der Content-Seite entfaellt
Wunsch: "diese Kisten sind jetzt ueberall zu viel, die sollen weg."

Nur die Content-Seite (nachgefragt): Vorrat, Veroeffentlicht, Ideen,
ohne Hook, ueberfaellig. Die Reihe auf der Startseite und die Kisten im
Report bleiben -- letztere sind der Report.

Sie hatte auch inhaltlich kein Recht mehr: Die Strecke direkt darunter
zeigt Ideen, Produktion und Veroeffentlichtes ohnehin mit Zahl an jeder
Spalte. Zwei Zaehler fuer dieselbe Sache auf einem Bildschirm sind einer
zu viel -- und laufen frueher oder spaeter auseinander.

WAS BLEIBT UND WARUM:
Die Abfrage /workspace/api/content/kennzahlen wird NICHT entfernt. Aus
derselben Antwort speist sich der Saeulen-Balken darunter (70/20/10).
Die Funktion heisst jetzt zahlenLaden() statt kennzahlenLaden() --
der alte Name zeigte auf etwas, das es nicht mehr gibt.

Entfernt sind neben der Reihe auch .kachel, .kachel__wert, .kachel__name
und .kachel__zusatz aus content.css. Achtung fuer spaeter: "kachel" gibt
es auch in start.css und report.css, mit ganz anderen Regeln. Diese drei
Kopien haben nichts miteinander zu tun; ein Kommentar an der Fundstelle
sagt das jetzt.

DIE PRUEFUNG WURDE UMGEDREHT, NICHT GELOESCHT.
pruef-content-ansicht.mjs sicherte bisher "fuenf Kennzahlen" -- jetzt
sichert sie, dass keine da ist. Eine geloeschte Pruefung merkt niemand,
wenn jemand die Reihe spaeter versehentlich wieder einbaut.

Die Zahlen selbst bleiben geprueft: pruef-content.mjs prueft Vorrat,
ohne Hook und ueberfaellig weiterhin an der Schnittstelle (Abschnitt 5
und 6). Entfallen ist ihre Anzeige, nicht ihre Richtigkeit.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 20:37:04 +02:00
DogFatherGitandClaude Opus 5 a129525cb7 Kennzahlen werden Wege, Team wird sichtbar, Felder bekommen ein Aussehen
Vier Wuensche vom 01.09.2026, dazu ein gemeldeter Fehler.

SCREEN 1 -- "wenn man auf die Kisten drueckt, sofort zu der Seite,
diesem Punkt". Jede Kennzahl im Bericht fuehrt jetzt dorthin, wo die
gezaehlten Dinge stehen: nicht nur auf die richtige Seite, sondern auf
die richtige Stelle (?zeigen=...). Ein gemeinsamer Helfer in kopf.js,
damit nicht jede Seite ihr eigenes Sprungverhalten erfindet.

  Auf dem Aufgabenbrett wird HERVORGEHOBEN, nicht gefiltert -- das Brett
  lebt davon, dass man die vier Spalten nebeneinander sieht. Bei den
  Dateien wird gefiltert, denn die Seite hat ohnehin eine Filterleiste,
  und deren Knoepfe zeigen dann mit an, wo man steht. Der Kalender
  schaltet auf die Liste um: In der Monatsansicht liesse sich
  "vergangen" gar nicht sinnvoll markieren.

  Immer mit einem Weg zurueck ("Alles zeigen"), der auch den Parameter
  aus der Adresse nimmt. Eine Seite, die gefiltert bleibt, ist eine
  Falle: Man kommt spaeter wieder, sieht drei von zwanzig Aufgaben und
  haelt das fuer den Bestand.

  Drei Entscheidungen gegen den ersten Entwurf:
  * KEIN ?creator= im Verweis. Das sah hilfreich aus und waere eine
    Luege gewesen -- keine Zielseite liest den Wert.
  * Kisten mit Null fuehren NIRGENDWOHIN. Ein Weg zu null Dingen ist
    eine Enttaeuschung, kein Angebot.
  * "neu angelegt" fuehrt ohne Ausschnitt aufs Brett: Der Bericht zaehlt
    einen Zeitraum, das Brett kennt keinen. Eine Hervorhebung, die nicht
    dieselbe Menge trifft, ist schlimmer als keine.

SCREEN 2 -- "ich will, dass wir Manager, Scouts, DogFather auch die
Fotos, Namen und so alles sehen". Der Steckbrief war eine Einbahnstrasse:
Jeder pflegte seinen, niemand bekam ihn je zu Gesicht. Die
Schnittstelle dafuer lag fertig da und wurde von keiner Seite
aufgerufen. Jetzt steht "Das Team" auf steckbrief.html und (fuer
Creator) auf profil.html -- nach Rollen gruppiert, mit Bild, Rolle,
eigenem Satz und Kanaelen. Wer wen sieht, entscheidet weiterhin der
Server; ein Creator sieht seine Betreuung, nicht die anderen Creator.

SCREEN 4 -- "das soll richtig geil aussehen und nicht so einfach, auch
die Schrift". Die Ursache war kein Geschmack, sondern ein Loch im
Aufbau: Jede Seite gestaltete ihre Felder mit einem EIGENEN Selektor,
und wer ein Feld anderswo hinsetzt, faellt durch alle Netze. Genau so
stand "Ein Satz ueber dich" als grauer Kasten in MONOSPACE da --
<textarea> faellt ohne `font: inherit` auf Schreibmaschinenschrift
zurueck. Jetzt gibt es eine Grundlage fuer jedes Feld, und die drei
wortgleichen Kopien in aufgaben/profil/bereich sind weg.

  Der erste Anlauf setzte dort auch `width: 100%` -- die Pruefung
  meldete sofort Felder von 28 statt 362 Pixeln. Breite ist LAYOUT und
  gehoert der Seite; eine Grundlage mit Staerke null verliert jeden
  Breitenstreit, also darf sie ihn nicht anfangen.

SCREEN 5 -- "wieso seh ich mein Bild da nicht?" Ein lehrreicher Fehler:
Der Server liefert das Bild laengst mit, und im Quelltext dort steht
ausdruecklich "es steht in der Kopfleiste JEDER Seite UND IN DER
BEGRUESSUNG". Die Absicht war aufgeschrieben, die Haelfte nie gebaut --
und aufgefallen ist es nicht, weil ein Buchstabe im Kreis nicht falsch
aussieht, nur eben nicht wie man selbst.

PRUEFUNGEN. Zwei neue (pruef-sprung, pruef-team), eine erweiterte
(pruef-formulare). Sie haben vier echte Fehler gefunden, die mit blossem
Auge nicht zu sehen waren:
  * Der Sprung auf "dringend" hob auch ERLEDIGTE dringende Eintraege
    hervor -- man klickt auf "2" und bekommt drei markiert.
  * Auf einer leeren Zielseite erschien gar keine Erklaerung (frueher
    Ausstieg uebersprang sie). Das ist der wichtigere Fall: Wer auf eine
    Zahl klickt und im Leeren landet, glaubt, er sei falsch abgebogen.
  * Das Kachel-Merkzeichen stiess mit der Zahl zusammen.
  * Die Feldpruefung fand vier RICHTIGE Felder falsch (die Kanaele holen
    ihren Rahmen vom Umschlag mit dem "@"). Eine Pruefung, die
    Richtiges anmahnt, gewoehnt man sich ab zu lesen.
Und zwei Faelle, in denen die Pruefung sich selbst belogen haette: null
gefundene Felder galten als "in Ordnung", und der Ueberdeckungsvergleich
war nach einer Aenderung ohne ein einziges Vergleichselement gruen.
Beide zaehlen jetzt mit, wie viel sie tatsaechlich angesehen haben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 20:18:39 +02:00
DogFatherGitandClaude Opus 5 d4cd8952b7 Checklisten-Gruppen klappen zu, Markierungen tragen ein Zeichen
Zwei Wuensche vom 01.09.2026:
  "neben den Titel soll immer ein Knopf sein, wo man die Liste aufmacht
   oder wieder zumacht -- die sollen auch zu, damit die Seiten nicht so
   lang sind."
  "und wenn die Ansprechpartner was markieren, sollen die da so ein
   Zeichen haben, so dass die sehen, da ist was -- und es soll auch oben
   in der Kachel angezeigt werden."

ZUKLAPPEN. Der Gruppenkopf ist jetzt ein Knopf ueber die volle Breite
(49 px hoch, mit dem Daumen treffbar), nicht ein Pfeilchen daneben. Zu
ist der Standard. Gemessen: Die LIVE-Analyse ist damit 1100 statt 2081
Pixel lang -- 47 Prozent gespart. Welche Gruppen offen waren, merkt sich
der Browser; sonst waere jede Bewertung ein Ruecksprung an den Anfang.

DAS ZEICHEN. Eine Raute mit Ausrufestrich, in Bernstein. Drei
Entscheidungen, keine davon Geschmack:
  * FORM -- alles andere auf dem Bildschirm ist rund oder eckig. Eine
    Spitze nach oben gibt es sonst nirgends, und deshalb findet das Auge
    sie zwischen zwanzig Kacheln ohne Suchen.
  * FARBE -- immer dieselbe, nie die der Kachel. Ein Zeichen, das die
    Farbe wechselt, muss gelesen werden; eines, das immer gleich
    aussieht, wird erkannt. Rot waere falsch: "verbessern" ist ein
    Auftrag, kein Fehler.
  * BEWEGUNG -- ein Atmen ueber 3,2 s, kein Blinken; bei "weniger
    Bewegung" bleibt der Schein stehen statt zu verschwinden.

Es steht an drei Stellen, immer aus derselben Quelle (bereiche.js): am
Gruppenkopf, am Punkt selbst und oben auf der Kachel der Startseite.

WARUM DAS ZEICHEN AM GRUPPENKOPF PFLICHT IST. Ohne es waere Zuklappen
ein Rueckschritt gewesen: Der Betreuer markiert etwas, die Gruppe ist zu,
und der Creator erfaehrt es nie. Die Zahl "zu verbessern" in der Bilanz
klappt die betroffenen Gruppen jetzt auf und springt hin.

Auf der Kachel nur fuer Creator. Fuer einen Betreuer waere es die Liste
dessen, was er selbst angehakt hat -- sie waechst mit seiner Arbeit, und
nur der Creator kann sie abbauen. Ein Zaehler, den man nicht auf null
bringen kann, wird ignoriert, und dann sind auch die daneben nichts wert.

ZWEI FEHLER, DIE DIE PRUEFUNG GEFUNDEN HAT:
  1. Das Zeichen stiess auf der Kachel mit der Zahl zusammen (zwei
     Pixel). Behoben an der Ursache: Besteht die Zahl NUR aus
     Markierungen, ist sie dieselbe Auskunft ein zweites Mal und
     entfaellt; sonst ruecken Zahl und Pfeil nach unten.
  2. Danach war die Pruefung wertlos -- sie verglich mit einem Element,
     das es nun nicht mehr gab, und war ohne einen einzigen Vergleich
     gruen. Sie zaehlt jetzt die geprueften Nachbarn mit; null Nachbarn
     ist ein Fehler, kein Erfolg.

Geprueft wird SICHTBARKEIT, nicht Vorhandensein: Ein zugeklappter Punkt
steht weiterhin im Dokument, alle bisherigen Pruefungen waeren gruen
geblieben, auch wenn der Creator seine Markierung nie zu Gesicht
bekaeme. Dazu Gegenproben: keine Markierung ohne Grund, und wer nichts
markiert bekommen hat, sieht auch kein Zeichen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 19:42:34 +02:00
DogFatherGitandClaude Opus 5 f9bf7d5674 "Hilfe anfordern" entfaellt - es bleibt die Rueckmeldung
Wunsch: "die sollen nirgendwo Hilfe anfordern koennen, sondern nur
Rueckmeldungen."

Es ist auch die klarere Loesung. Es gab zwei Wege, dasselbe zu sagen:
einen Knopf, der eine Aufgabe erzeugte, und ein Textfeld, das eine
Nachricht schrieb. Zwei Wege fuer eine Sache heisst, dass niemand weiss,
welcher der richtige ist -- und dass Antworten mal als Aufgabe und mal
als Nachricht landen. Wer dann nachsieht, findet die Haelfte nicht.

Geblieben ist die Rueckmeldung an jedem Punkt: ein Verlauf, in dem beide
Seiten schreiben koennen, sichtbar dort, wo es hingehoert -- am Punkt
selbst und nicht in einer zweiten Liste.

VOLLSTAENDIG entfernt, nicht nur ausgeblendet:
  * der Knopf in der Checkliste
  * der Knopf und die Marke "Hilfe moeglich" im Vorlagenblock
  * die Route /workspace/api/vorlagen/hilfe
  * 47 Datenfelder hilfe: true/false in den Vorlagen
  * die zugehoerigen Stile
  * der Abschnitt in pruef-vorlagen.mjs

Datenfelder, die nichts mehr bewirken, und Routen, die niemand mehr
aufruft, werden beim naechsten Mal fuer lebenden Code gehalten und
mitgepflegt. Das ist teurer als das Entfernen heute.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 17:19:19 +02:00
DogFatherGitandClaude Opus 5 9267797d1d Feste Checklisten statt Vorschlaege - in allen vier Bereichen
"Die neuen Sachen in der LIVE-Analyse soll der Creator FEST sehen, auch
schoen kategorisiert, und der Ansprechpartner soll anklicken koennen,
wenn er findet, dass der Creator was verbessern sollte."

DER UMBAU. Vorher waren die Punkte Vorschlaege zum Uebernehmen: Man
holte sie sich und bekam einen eigenen Eintrag. Das war falsch gedacht.
Eine Checkliste, die man erst anfordern muss, ist keine Checkliste --
und schlimmer: Zwei Creator haetten unterschiedliche Listen gehabt, je
nachdem wer sich was geholt hat. Genau das macht einen Vergleich
unmoeglich, und um Vergleich geht es bei einer Betreuung.

Jetzt stehen dieselben Punkte fuer JEDEN fest da, gruppiert:

  LIVE       21 Punkte -- vor, waehrend, nach der Sendung
  Community  14 Punkte -- Moderation vorbereiten, aufbauen, wenn es kippt
  Technik    12 Punkte -- Einrichtung, Ausfall, was geholfen hat
  Content    13 Ideen  -- nach Saeule (70/20/10) statt nach Ablauf

Jede Gruppe hat einen Satz, der erklaert, wofuer sie da ist. Eine
Ueberschrift allein sagt das nicht.

Was sich je Creator unterscheidet, ist nur der STAND -- und den setzt
die Betreuung: "Passt so" oder "Verbessern". Ein Creator kann sich nicht
selbst bewerten; koennte er es, stuende alles auf gruen. "Verbessern"
verlangt einen Satz, WAS zu verbessern ist -- eine Bewertung, mit der er
nichts anfangen kann, ist nicht streng, sondern nur entmutigend.

Der Creator sieht alles: die Stufe, den Grund, den Namen und den
Zeitpunkt. Und er kann an JEDEM Punkt antworten -- das ist der Kanal,
ueber den er ueberhaupt etwas sagen kann.

Oben steht eine Bilanz in einer Zeile: wie viele passen, wie viele sind
zu verbessern, wie viele hat noch niemand angesehen. Das ist die Frage,
die beide Seiten zuerst haben.

STABILE SCHLUESSEL statt Positionen. Ein Stand haengt am Schluessel des
Punktes ("ton-geprueft"), nicht an seiner Nummer. Haenge er an der
Position, waere beim Einfuegen eines Punktes in der Mitte jede Bewertung
dahinter am falschen Punkt -- und niemand wuerde es merken, weil beides
plausibel aussieht. 64 Punkte haben jetzt einen.

"Offen" loescht den Stand, statt ihn auf "offen" zu setzen: Ein
Datensatz, der nichts aussagt, ist Ballast.

ZWEI EIGENE FEHLER, VON DEN PRUEFUNGEN GEFUNDEN:

1. DAS CSS LAG IN DER FALSCHEN DATEI. Ich hatte es in content.css
   geschrieben -- bereich.html laedt die gar nicht. Die Punkte standen
   auf drei von vier Seiten nackt und ohne Flaeche da. Es ist derselbe
   Fehler wie im August bei .knopf-still, .schalter und .kopf-zeile, und
   es gibt seitdem eine Warnung dazu in start.css. Sie hat nichts
   genutzt, solange keine Pruefung sie nachhielt.

   Jetzt gibt es eine: Sie misst, ob eine Karte wirklich eine Kante und
   Polsterung hat -- nicht nur, ob das Element existiert. Gegenprobe
   gemacht: Klasse umbenannt, Pruefung meldet "STIL FEHLT".

2. Ein Betreuer sah beim Oeffnen keine Bewertungsknoepfe, weil noch kein
   Creator gewaehlt war -- und musste erst raten, dass er oben jemanden
   auswaehlen soll. Jetzt nimmt der Server den ersten betreuten Creator,
   wenn keiner angegeben ist.

Die alte Oberflaechenpruefung fuer den Vorschlaege-Block wurde entfernt
statt angepasst: Sie verlangte etwas, das es nicht mehr gibt. Eine
dauerhaft rote Pruefung ist schlimmer als keine -- man gewoehnt sich
daran, und beim naechsten echten Fehler sieht niemand hin.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 17:12:55 +02:00
DogFatherGitandClaude Opus 5 372a0eb95a Ampel und Rueckmeldungen - bewerten darf nur die Betreuung
Der Wunsch: "der Creator sieht, ob es gut ist oder schlecht. Und wenn
nicht gut, dann muss es verbessert werden -- und nur der Ansprechpartner
kann das aendern. Die Creator koennen nur Nachrichten hinterlassen zum
Kommunizieren."

ZWEI GETRENNTE DINGE, und sie getrennt zu halten ist der ganze Punkt:

  DIE AMPEL ist eine Beurteilung. Sie gehoert dem Betreuer, und nur er
  setzt sie. Koennte ein Creator sich selbst auf gruen stellen, waere
  sie wertlos -- dann stuende ueberall gruen. Der Server lehnt es mit
  403 ab und sagt dabei, wer es kann.

  DIE NACHRICHT ist ein Gespraech. Sie gehoert beiden. Ein Creator, der
  auf eine Bewertung nicht antworten kann, bekommt ein Urteil statt
  einer Betreuung.

DREI STUFEN, NICHT FUENF. Eine Zahl von 1 bis 5 klingt genauer und ist
es nicht: Niemand kann den Unterschied zwischen 3 und 4 erklaeren, und
am Ende steht ueberall die 3. Die Frage lautet "reicht das schon?", und
darauf gibt es drei ehrliche Antworten -- passt so, noch verbessern,
noch nicht angesehen.

"NOCH VERBESSERN" VERLANGT EINE BEGRUENDUNG. Eine Bewertung, mit der der
Creator nichts anfangen kann, ist nicht streng, sondern nur
entmutigend. Der Server lehnt sie ohne Grund ab; die Oberflaeche fragt
deshalb gleich danach, statt hinterher eine Fehlermeldung zu zeigen.
"Passt so" braucht keinen -- da gibt es nichts zu erklaeren.

Die Stufe steht IMMER an der Karte, auch fuer den Creator, auch wenn sie
"noch nicht angesehen" lautet. Er soll sehen, wo er steht, ohne fragen
zu muessen. Der Grund steht daneben in voller Breite, nicht in einer
Ecke.

FREMDE NACHRICHTEN BLEIBEN STEHEN -- auch fuer DogFather. Ein Gespraech
nachtraeglich umzuschreiben waere schlimmer, als eine unbedachte
Aeusserung stehen zu lassen. Wer etwas richtigstellen will, schreibt
eine neue.

VORLAGEN AUCH FUER COMMUNITY UND TECHNIK (Screens 11 und 12): 14
Moderations-, Aktions- und Konfliktpunkte, 12 Technikpunkte. Ton steht
vorn, weil schlechter Ton der Grund Nummer eins ist, warum Leute einen
Stream verlassen. Die drei Bereiche laufen jetzt ueber EINE Zuordnung
statt drei fast gleicher Bloecke -- sonst weicht der dritte irgendwann
ab. Die beiden alten Zweige wurden entfernt: Toter Code, den man stehen
laesst, wird beim naechsten Mal fuer lebenden gehalten.

Die Ampeln einer ganzen Liste kommen in EINER Abfrage. Zwanzig
Eintraege einzeln zu fragen waeren zwanzig Anfragen, und die Seite
ruckelte sichtbar beim Aufbau. Die Sichtbarkeitspruefung laeuft dabei
je Eintrag, nicht einmal pauschal -- ein fremder Eintrag taucht auch in
der Sammelabfrage nicht auf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 16:49:56 +02:00
DogFatherGitandClaude Opus 5 5960f6e3c4 Unterweisungen mit beidseitiger Bestaetigung - und einer echten Sperre
Der Wunsch: "jeder Scout, Manager oder DogFather muss mit seinen
Creatorn die PDFs durchgehen, und beide druecken dann auf verifiziert,
so dass wir den Beweis haben -- und das ist danach auch nicht mehr zu
aendern."

Das ist kein Haekchen, das ist ein NACHWEIS. Wer so etwas baut, muss
drei Fragen beantworten, sonst ist er wertlos:

WER hat bestaetigt? Beide Seiten getrennt, mit Name, Zeitpunkt und IP.
Eine einzelne Bestaetigung reicht nicht -- "ich habe es ihm gezeigt" und
"er hat es mir gezeigt" sind zwei verschiedene Aussagen, und erst
zusammen ergeben sie einen Beweis. Bestaetigt nur einer, steht die
Unterweisung sichtbar als HALB da, in einer eigenen warnenden Farbe.
Diese Zwischenstufe sichtbar zu machen ist der Punkt: Ein Nachweis, bei
dem nur einer unterschrieben hat, sieht sonst aus wie fertig -- und man
merkt es erst, wenn jemand danach fragt.

WORAUF genau? Nicht auf "die Regeln", sondern auf eine bestimmte Datei.
Beim Bestaetigen wird der SHA-256 der PDF-Datei mitgespeichert. Tauscht
spaeter jemand die Datei aus, passt der Fingerabdruck nicht mehr, und
die Seite sagt das auch ("Das Dokument wurde seit der Bestaetigung
ausgetauscht"). Ohne diesen Wert waere die Bestaetigung ein Zettel ohne
Bezug.

IST ES UNVERAENDERT? Eine abgeschlossene Bestaetigung laesst sich nicht
mehr aendern und nicht loeschen -- und zwar nicht, weil der Code es
nicht anbietet, sondern weil die DATENBANK es ablehnt. Zwei Trigger mit
RAISE(ABORT). Ein Schutz, der nur im Code steht, ist beim naechsten
neuen Weg zur Datenbank wieder weg.

DER VOLLZUG WURDE DURCHGESPIELT. Aus RunOne stammt die Lehre, dass ein
Weg, den man nicht rueckgaengig machen kann, tagelang live sein und NIE
gelaufen sein kann. Die Pruefung bestaetigt deshalb wirklich, schliesst
ab, und versucht dann eine Aenderung -- ueber die Schnittstelle UND
direkt auf der Datenbank. Beide werden abgelehnt.

Und die GEGENPROBE dazu: Der Trigger wird entfernt, dieselbe Aenderung
versucht -- sie geht durch -- und der Trigger wieder gesetzt. Eine
Sperre, die man nicht hat scheitern sehen, ist keine Sperre.

Der Server entscheidet anhand der ROLLE, welche Seite gesetzt wird --
nicht der Absender. Sonst koennte ein Creator die Bestaetigung seines
Betreuers eintragen, und der ganze Nachweis waere wertlos. Eine bereits
gesetzte Seite wird nie ueberschrieben; ein Datum laesst sich also auch
nicht nachtraeglich verschieben.

Die Dokumente kommen aus der Wissens-Bibliothek, es gibt keinen zweiten
Upload-Weg. Sonst gaebe es Dateien, die nur hier existieren -- und
niemand wuesste, welche Fassung die richtige ist. Eine Unterweisung wird
nie geloescht, nur abgeschaltet: Die Nachweise haengen daran.

EIN EIGENER FEHLER, VON DER BROWSERPRUEFUNG GEFUNDEN: Der Aufruf der
Zusatzbloecke stand NACH einem return. laden() steigt frueh aus, wenn
die Liste leer ist -- und dann wurden Vorlagen und Unterweisungen nie
gebaut. Also ausgerechnet auf der leeren Seite, fuer die sie gedacht
sind. Jetzt stehen sie in einem finally.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 16:39:00 +02:00
DogFatherGitandClaude Opus 5 ca10479909 Fertige Vorlagen zum Uebernehmen - Content-Ideen und LIVE-Punkte
Der Wunsch stand an fuenf Stellen gleichlautend: "ich will dass da schon
fertige Sachen stehen". Eine leere Seite mit einem Knopf "Neuer Eintrag"
verlangt vom Creator genau das, was er noch nicht kann -- zu wissen, was
ueberhaupt hineingehoert.

WARUM VORLAGEN UND KEINE VORAUSGEFUELLTEN DATEN. Man koennte beim
Anlegen eines Creators dreissig Eintraege in seine Datenbank schreiben.
Das waere falsch: Sie waeren ab dem ersten Tag "seine" Eintraege und
damit Altlast; aendert Filipe spaeter eine Formulierung, gilt sie nur
fuer neue Creator; und die Liste saehe voll aus, obwohl noch nichts
geschehen ist -- das Gegenteil einer ehrlichen Uebersicht.

Vorlagen bleiben deshalb VORSCHLAEGE, bis jemand sie uebernimmt. Sie
stehen im Code, gelten fuer alle sofort, und werden erst dann zu Daten,
wenn sie gebraucht werden. Was uebernommen ist, ist ein ganz normaler
Eintrag -- aenderbar, loeschbar, und von spaeteren Aenderungen an der
Vorlage unberuehrt.

INHALTE, fachlich begruendet:
  13 Content-Ideen, jede mit AUSFORMULIERTEM Aufhaenger und Format. Die
  ersten ein bis drei Sekunden entscheiden ueber die Verbreitung --
  "mach was Persoenliches" hilft niemandem, "Das haette ich am Anfang
  gern gewusst" kann man sagen. Verteilt nach 70/20/10 (Wert, Community,
  Eigenwerbung).

  21 LIVE-Punkte in drei Abschnitten. Der mittlere ist der wichtigste
  und gibt es sonst nirgends: Was WAEHREND der Sendung auffaellt, ist am
  naechsten Tag weg. Diese Punkte sind so formuliert, dass man sie in
  einem Moment anklicken kann, in dem man eigentlich keine Zeit hat.

  Die Vorbereitung ist die laengste Liste, weil ein LIVE dort steht und
  faellt. Ton zuerst -- der Grund Nummer eins, warum Leute wieder gehen.

"ICH BRAUCHE HILFE" wird eine AUFGABE, keine Nachricht. Eine Nachricht
ist gelesen und dann weg; eine Aufgabe bleibt stehen, bis sie jemand
erledigt, geht an den zustaendigen Betreuer (ohne Betreuer an die
Leitung -- eine Bitte um Hilfe darf nicht ins Leere laufen), traegt hohe
Prioritaet und eine Frist von drei Tagen. Ohne Frist bleibt sie liegen;
das ist der Unterschied zwischen einer Aufgabe und einem Zettel.

"CONTENT-PLANUNG" HEISST JETZT "CONTENT-IDEEN". "Planung" klang nach
Terminen und Tabellen; was dort wirklich passiert, ist das Sammeln und
Weiterentwickeln von Ideen. Der Kalender daneben plant.

EIN CREATOR DARF SEINE EIGENEN EINTRAEGE AENDERN -- aber nur im Bereich
Content. Wenn er sich eine Idee uebernimmt, ist das SEINE Idee; sie
danach nicht umbenennen zu duerfen waere absurd. LIVE, Technik,
Community und Schutz bleiben die Betreuungsakte, dort aendert er nichts.
Ein erster Anlauf hatte die Ausnahme fuer alle Bereiche erlaubt -- die
Pruefung pruef-bereiche-lesend hat das sofort gemeldet.

DREI EIGENE FEHLER, VON DEN PRUEFUNGEN GEFUNDEN:
- Der Vorlagenblock vergass nach dem Uebernehmen, was schon geholt war:
  Die Liste wird neu geladen, der Block neu gebaut, und die Markierung
  am Element war jedes Mal weg. Jetzt merkt sich das Modul die Auswahl.
- Die Regel fuer eigene Eintraege war zu breit (siehe oben).
- Die Marken im Vorlagenblock waren auf dem Handy 10,2 px klein.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 16:27:30 +02:00
DogFatherGitandClaude Opus 5 6996c5957d Formularzeilen gerade geruckt, Pipeline erklaert sich selbst
DIE VERZOGENE FORMULARZEILE hatte drei Ursachen, nicht eine -- und jede
einzelne haette gereicht, damit es schief aussieht:

1. Die Rasterregel galt nur fuer Kinder mit der Klasse .feld. Der
   Kalender benutzt schlichte <div> ohne Klasse; die fielen hindurch,
   bekamen von zwoelf Spalten je EINE und wurden nur so breit, wie ihr
   Inhalt sie zwang. Daher "Art" schmal und "Beginn" breit.
2. "Dauer (Minuten)" brach in der schmalen Spalte auf zwei Zeilen um --
   und schob das Feld darunter tiefer als seine Nachbarn. Die Klammer
   ist jetzt ein leiser Zusatz, die Beschriftung hat feste Hoehe.
3. Die letzten drei Pixel: Mit grid-template-rows: 1fr auto bestimmte
   jedes Element die Zeilenhoehe selbst. Ein <select> mass sich 3 px
   kleiner als ein <input> und sass dadurch hoeher. Gemessen: Container
   beider Felder identisch (652+71), Eingabe aber 676..720 gegen
   679..723. Drei Pixel klingen nach nichts und sind genau das, was man
   als "verzogen" sieht. Jetzt hat die Zeile feste Hoehe und das Feld
   fuellt sie ganz.

Ergebnis, gemessen statt betrachtet: alle Felder 44 px hoch, alle 362 px
breit, alle Unterkanten auf einer Linie. Auf dem Handy untereinander --
zwei Felder auf 300 px sind zwei Streifen, in die nichts hineinpasst.

NEUE PRUEFUNG pruef-formulare.mjs. Sie prueft nicht "sieht gut aus",
sondern misst: gleiche Hoehe, Unterkanten auf einer Linie, kein Feld
absurd schmal, keine Beschriftung mehrzeilig -- auf fuenf Seiten und
zwei Geraetegroessen. Zwei Messfehler darin selbst gefunden und behoben
(Teilpixel-Rundung, und eine Ausgabe ueber mehrere Zeilen, die die Datei
zerschossen hat).

DIE SCOUT-PIPELINE ERKLAERT SICH JETZT SELBST. Vorher stand im leeren
Zustand ein Satz, der nur wiederholte, was man ohnehin sieht: dass
nichts da ist. Wer die Seite zum ersten Mal oeffnet, wusste danach
weiterhin nicht, wofuer es sie gibt.

Der leere Zustand ist der EINZIGE Moment, in dem jemand garantiert
liest, was dort steht -- spaeter ist die Flaeche von Daten belegt.
Deshalb steht die Erklaerung genau dort und nicht in einer Hilfe, die
niemand aufmacht. Erklaert wird der NUTZEN, nicht die Bedienung: nicht
"hier klicken", sondern warum ein Scout ohne diese Liste Leute verliert
-- naemlich die Interessierten, bei denen drei Wochen nichts passiert
ist, und nicht die, die Nein sagen. Dazu die fuenf Stufen mit je einem
Satz, was sie bedeuten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 16:11:53 +02:00
DogFatherGitandClaude Opus 5 568909ba87 Bibliothek: nur je einer oben, "wichtig" laeuft ab, Knopf steht fest
NEU & WICHTIG zeigte bis zu sechs Karten mit je vier Knoepfen -- eine
halbe Bildschirmseite, bevor ueberhaupt eine Kategorie zu sehen war.
Jetzt stehen genau ZWEI da: der wichtigste und der neueste. Bewusst je
einer und nicht die ersten zwei -- das sind zwei verschiedene Antworten
("was soll ich unbedingt lesen" und "was ist dazugekommen"). Alles
Weitere ist einen Klick entfernt, der Knopf nennt die Zahl.

"WICHTIG" LAEUFT JETZT EBENFALLS NACH 48 STUNDEN AB. Vorher blieb es
stehen, bis es jemand von Hand abschaltete -- mit dem absehbaren
Ergebnis, dass oben nach ein paar Wochen eine Liste von Dingen steht,
die laengst niemanden mehr angehen. Niemand raeumt so etwas auf.

Der Schalter bleibt trotzdem sinnvoll: Er hebt einen Eintrag fuer zwei
Tage nach oben, auch wenn dieser aelter ist. Er ist damit ein
Scheinwerfer, kein Regal.

DER AKTIONSKNOPF SPRANG -- "einmal rechts, einmal links". Die Ursache
war nicht die Seite, sondern die TEXTLAENGE: Die Kopfzeile ist eine
umbrechende Flex-Zeile, und der Textblock daneben durfte wachsen. Bei
kurzer Unterzeile blieb der Knopf rechts, bei langer ("Community-
Richtlinien, erlaubte und verbotene Inhalte, Altersprüfung, Sperren,
Verwarnungen, Datenschutz, Jugendschutz und sicheres Verhalten")
rutschte er darunter. Es sah aus wie zwei verschiedene Seiten und war
dieselbe Regel.

Jetzt schrumpft der Textblock und der Knopf nicht -- er steht auf jeder
Seite an derselben Stelle. Auf dem Handy rutscht er bewusst darunter und
nimmt die volle Breite, dort ist nebeneinander kein Platz.

NEUE PRUEFUNG pruef-wissen-neu.mjs. Sie legt ausdruecklich Eintraege mit
einem Zeitstempel von VOR DREI TAGEN an. Mit frischen Daten waere alles
neu, ein abgelaufener Eintrag kaeme nie vor, und die Pruefung waere
gruen, ohne den Fall je gesehen zu haben. Geprueft wird ausserdem, dass
das Aufklappen WIRKLICH mehr zeigt -- ein Knopf, der nur seine
Beschriftung aendert, ist keiner.

Zwei Fehler in der Pruefung selbst gefunden: Sie schrieb in Spalten, die
so nicht heissen (datei statt name_datei), und suchte die Karten unter
".karte" -- sie heissen .pdf, und der Ausdruck zaehlte stattdessen die
umschliessenden Container.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 15:50:20 +02:00
DogFatherGitandClaude Opus 5 2bebab156b Profilbild gebaendigt, Steckbrief von der Creator-Akte getrennt
ZWEI FEHLER, DIE FILIPE GESEHEN HAT.

1. DAS PROFILBILD LAG UEBER DER HALBEN SEITE. Als Patrick sein Bild
   hochlud, zog sich ein roter Balken quer ueber die Startseite.

   Ursache: Die CSS-Regel .wer__bild hat GEFEHLT. Das Element wurde in
   kopf.js erzeugt, die Regel dazu nie geschrieben -- und ein <img> ohne
   Groessenangabe nimmt seine natuerliche Groesse an, bei einem Handyfoto
   also mehrere tausend Pixel. Dazu fehlte overflow: hidden am Traeger.

   WARUM KEINE PRUEFUNG DAS GEFUNDEN HAT: Sie lud ein 1x1-Pixel-PNG hoch.
   Klein, schnell, von Hand gebaut -- und voellig unfaehig, irgendetwas
   zu ueberdecken. Die Pruefung war gruen, der Fehler war da, und gesehen
   hat ihn der Nutzer. Sie arbeitet jetzt mit einem 1200x1200-Bild, also
   in der Groesse, die wirklich hochgeladen wird, und misst danach: Bleibt
   das Bild in seinem 28-px-Feld, ragt es irgendwo heraus, laeuft die
   Seite ueber. Gegenprobe gemacht -- ohne die Regel meldet sie
   1200x1200 in 28x28 und 918 px Ueberlauf.

2. ZWEI PERSONEN AUF EINEM BILDSCHIRM. Auf der Profilseite stand oben
   "Profil: SpongBobSchwammKopf" und mittendrin "MEIN PROFIL: Dogfather".
   Niemand konnte sagen, welche Angabe zu wem gehoert.

   Es sind auch wirklich zwei verschiedene Dinge:
     MEIN STECKBRIEF  gehoert MIR -- Bild, ein Satz ueber mich, meine
                      Kanaele. Fuehre ich selbst.
     CREATOR-PROFILE  die BETREUUNGSAKTE eines anderen Menschen --
                      Ziele, 90-Tage-Plan, interne Notizen. Fuehren die
                      Betreuer.

   Scouts, Manager und DogFather haben jetzt zwei getrennte Kacheln und
   eine eigene Seite (steckbrief.html, serverseitig geschuetzt). Ein
   Creator behaelt beides zusammen -- er hat nur eine Seite und sieht
   dort ausschliesslich sich selbst. Die Logik liegt in einer eigenen
   Datei statt hinten an profil.js: Sie gehoert der angemeldeten Person,
   nicht der Akte.

ACHTZEHN KACHELN, ACHTZEHN FARBEN. Die neue Kachel haette sich ihren
Farbton mit den Creator-Profilen geteilt -- zwei Nachbarn in derselben
Farbe. Statt eine Farbe dazuzuerfinden, wurde tools/kachel-farben.mjs
fuer 18 Winkel neu gerechnet, samt der neuen Nachbarschaft im Raster.
Der kleinste Abstand zweier Nachbarn liegt weiterhin bei 100 Grad.
Gefunden hat das die Startseitenpruefung ("17 Farben auf 18 Kacheln").

Die Trennung wird jetzt fuer JEDE Rolle geprueft: welche Kacheln sie
sieht, dass auf der Akte kein fremder Steckbrief steht, und dass die
eigene Seite die richtige Person zeigt. Eine alte Pruefung, die das
Gegenteil verlangte, wurde ersetzt statt stehen gelassen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 15:04:23 +02:00
DogFatherGitandClaude Opus 5 1fe443e59c Handy durchgeprueft, Lichtfarbe je Kachel, haengendes Licht behoben
DAS LICHT BLIEB HAENGEN -- vier Ursachen, jede einzeln behoben:

1. EIN WETTLAUF. Zwischen dem Anmelden eines Bildaufbaus und seinem
   Ablauf konnte der Zeiger die Karte laengst verlassen haben. Dann hatte
   pointerout schon aufgeraeumt, und der Bildaufbau schaltete das Licht
   gleich wieder AN. Der haeufigste Fall und der unauffaelligste.
2. UEBER EINE LUECKE VERLASSEN. Wer eine Karte nicht ueber eine
   Nachbarkarte verliess, sondern ueber den Zwischenraum, loeste kein
   Ereignis aus, das die alte Karte kannte.
3. GESCROLLT, OHNE DIE MAUS ZU BEWEGEN. Die Karte wandert unter dem
   stehenden Zeiger weg -- es kommt gar kein Zeigerereignis. Jetzt wird
   beim Scrollen nachgesehen, ob die beleuchtete Karte noch unter dem
   Zeiger liegt.
4. FENSTER ODER TAB VERLASSEN. Auch dort kommt nichts mehr.

Es gibt jetzt genau EINE beleuchtete Karte -- mehr kann es nicht geben,
es gibt ja nur einen Zeiger. Beim Wechsel geht die alte aus, bevor die
neue angeht.

DIE FARBE GEHOERT ZUR KACHEL. Auf der Wissensseite leuchteten alle sechs
Welten violett, weil die Farbe dort --w heisst und der ganze uebrige
Workspace --ton benutzt. Das Licht griff auf --ton zu, fand nichts und
nahm den Farbton der SEITE. Dieselbe Luecke bei den Aufgaben-Spalten
(--sfarbe), den Kalenderkarten (--afarbe) und den Kalenderzeilen
(--zfarbe). Alle vier setzen jetzt --ton mit.

Nachgewiesen an echten Bildpunkten, nicht am Quelltext: Der Zeiger wird
auf die Aufgaben-Kachel gesetzt (dort muss Rot ueberwiegen: 85 zu 22)
und auf die Kalender-Kachel (dort Blau: 71 zu 13). Ein
Zeichenkettenvergleich haette das nicht gekonnt -- der Browser rechnet
color-mix() aus und schreibt je nach Fassung rgb(), color() oder oklab()
zurueck.

DAS HANDY, komplett durchgeprueft: neue pruef-handy.mjs faehrt alle
fuenfzehn Seiten auf DREI echten Geraetegroessen ab (320 px iPhone SE,
390 px iPhone, 412 px Android) und misst fuenf Dinge, die am Rechner
unsichtbar sind. Gefunden und behoben:

  * ZWEI ECHTE UEBERLAEUFE (startcheck +27 px, automation +33 px). Die
    Seite liess sich waagerecht schieben -- auf einem Telefon der
    schlimmste Fehler. Ursachen: zwoelf Raster mit festem Mindestmass
    (minmax(280px, 1fr) kann nicht schrumpfen -> min(280px, 100%)),
    zwoelf feste Mindestbreiten an Auswahlfeldern, und ein "flex: none"
    an den Stufen-Knoepfen, das jedes Schrumpfen verbot. "width: 100%"
    allein reichte dort nicht.
  * BERUEHRZIELE unter 24 px (WCAG 2.2, Kriterium 2.5.8). Auswahlfelder
    waren 18 bis 22 px hoch. Jetzt 44 px -- die Empfehlung von Apple und
    Google, und der Daumen ist nun einmal breiter als ein Mauszeiger.
    Nebenbei behebt die Schriftgroesse 16 px das Hineinzoomen von iOS.
  * SCHRIFT unter 11,7 px an 52 Stellen. Gesucht wurden sie nicht von
    Hand -- das waere ein Ratespiel gewesen und haette die Haelfte
    uebersehen -- sondern durch Durchsuchen der Stildateien nach
    font-size unter 0,73rem.

ZWEI FEHLER IN DEN EIGENEN PRUEFUNGEN gefunden und behoben: Die
Schriftregel griff zuerst gar nicht (start.css wird VOR den Seitenstilen
geladen, bei gleicher Staerke gewinnt die spaetere -- jetzt mit
body.start qualifiziert), und die Lichtpruefung scrollte 600 px und
stellte nicht zurueck, sodass die folgende Pruefung ins Leere zeigte.

GEGENPROBE gemacht: Mit absichtlich eingebauten Fehlern (8-px-Schrift,
500 px breiter Inhalt) meldet die Handypruefung sofort Rot. Eine
Pruefung, die immer bestaetigt, bestaetigt nichts.

Alle achtzehn Pruefungen laufen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 14:48:48 +02:00
DogFatherGitandClaude Opus 5 41ffb91688 Das Licht folgt dem Zeiger - auf jeder Karte, und der Rand mit
Auf der Startseite gab es einen Lichtfleck unter dem Zeiger. Jetzt auf
JEDER Karte im ganzen Workspace -- und mit zwei Schichten statt einer:

  der FLECK   ein weicher Schein unter dem Zeiger, in der Farbe des
              Bereichs (--ton). Eine Aufgabenkarte leuchtet orange, eine
              Kalenderkarte tuerkis.
  der RAND    eine helle Stelle, die auf der KANTE mitwandert.

Der Rand ist der Teil, der den Unterschied macht. Er entsteht aus einem
Farbverlauf, von dem eine Maske nur den ein Pixel breiten Saum stehen
laesst: zwei Ebenen, eine ueber die Innenflaeche, eine ueber den ganzen
Kasten, und mask-composite: exclude laesst genau die Differenz uebrig --
den Rahmen. Dadurch leuchtet wirklich die Kante an der Stelle, an der
der Zeiger steht, statt eines Rechtecks, das so tut als ob.

Beides steckt in einem eingefuegten <span class="licht">. Ein eigenes
Element statt ::before/::after am Kasten selbst, weil die bei fast
allen Karten schon belegt sind (Akzentstreifen, Wasserzeichen) -- ein
Pseudo-Element doppelt zu benutzen geht nicht, und der Fehler faellt
erst auf, wenn eines von beiden verschwindet.

Kosten: EIN Zuhoerer fuer das ganze Dokument, gedrosselt auf einen
Bildaufbau, passiv angemeldet. Das Licht-Element wird beim ersten
Ueberfahren eingesetzt, nicht beim Laden -- Karten entstehen laufend
neu, wenn Listen sich aktualisieren. Ohne feinen Zeiger (Handy) und bei
"weniger Bewegung" laeuft gar nichts und es wird auch nichts eingefuegt.

pointerout feuert auch beim Wechsel zwischen Kindern INNERHALB einer
Karte. Ohne die Pruefung auf relatedTarget haette das Licht bei jeder
Bewegung ueber ein Wort hinweg geflackert.

DIE ALTE FASSUNG IN start.js IST WEG. Sie stehen zu lassen haette zwei
Zuhoerer auf denselben Bewegungen bedeutet -- doppelte Arbeit bei jedem
Zeigerzucken, und der Fehler waere erst aufgefallen, wenn jemand die
eine geaendert haette und sich nichts tat.

GEPRUEFT AN ECHTEN BILDPUNKTEN, nicht am Quelltext: Der Zeiger wird in
die Mitte einer Kachel gesetzt, dann wird die Helligkeit der Kante
direkt darueber gegen dieselbe Kante an der fernen Ecke gemessen.
Ergebnis 50 gegen 17. Geht die Maske jemals verloren, waere die ganze
Karte eingefaerbt und der Text unlesbar -- das faellt damit sofort auf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 11:51:47 +02:00
DogFatherGitandClaude Opus 5 766c75b51d Die Buehnen richtig: nicht mehr beschnitten, hell, mit Lesespur
Drei handfeste Fehler, alle im Screenshot zu sehen gewesen.

1. ABGESCHNITTEN. background-size stand auf "138% auto". Auf einem
   2540 px breiten Schirm wurde das Bild damit 3500 px breit und knapp
   2000 px hoch -- in einem 1300 px hohen Fenster fehlten 700 px, und
   zwar oben. Genau deshalb waren die Figuren riesig und ihre Koepfe
   weg. Jetzt cover mit Verankerung auf 50% 42%: Die Flaeche wird immer
   gefuellt, so wenig wie noetig skaliert, und wenn etwas beschnitten
   werden muss, dann Fussboden und Decke -- nicht die Gesichter.

2. DIE VIGNETTE LAG FALSCH HERUM. Abgedunkelt wurde die MITTE, also
   genau der Teil, in dem die Szene steht. Man sah die Raender des
   Bildes und in der Mitte einen grauen Fleck. Jetzt laufen die RAENDER
   ins Dunkle und die Mitte bleibt klar -- so wie in der Fotografie.

3. ZWEI SCHICHTEN DUNKELHEIT. Zusaetzlich zur Vignette legte der
   Schleier .86/.58/.44 Schwarz ueber dasselbe Bild. Jetzt nur noch
   oben (Kopfleiste) und unten (Seitenende) ein Streifen.

Dazu die Bilder selbst: Helligkeit 0.66 -> 0.88, mehr Kontrast und
Farbe. Sie sind ein BILD, kein Nebel.

DIE LESESPUR ist der eigentliche Kniff. In allen neun Szenen stehen
HasiDog und DogFather AUSSEN, die Mitte ist frei -- danach wurden sie
ausgesucht. Diese Aufteilung wird jetzt benutzt statt bekaempft: aussen
bleibt das Bild hell und scharf, in der Mitte (wo der Text steht) wird
gedaempft. Der klare Rand ist in jedem Fenster mindestens 400 px breit.
Auf dem Handy gibt es daneben keinen Platz, dort deckt die Spur alles.

Was frei stand und keine Karte hatte, bekommt eine Lesezone mit
backdrop-filter: Der Hintergrund bleibt in Farbe und Form sichtbar,
wird an dieser Stelle aber weichgezeichnet. Die billige Loesung waere
gewesen, das Bild wieder abzudunkeln -- damit waere man dort, wo man
angefangen hat.

ZWEITER FUND AN DER EIGENEN KONTRASTMESSUNG. Sie tastete
ausschliesslich NEBEN dem Element ab. Traegt ein Text seine Flaeche
aber selbst (eine Beschriftung mit Hintergrund und Polsterung), liegt
jeder Punkt daneben schon auf dem Bild -- gemeldet wurden 1,89:1,
obwohl der Text auf deckender Flaeche steht und tadellos lesbar ist.
Jetzt wird zuerst in der eigenen Polsterung gemessen, also auf dem,
worauf der Text WIRKLICH liegt. (Der erste Fund an derselben Stelle war
gestern: Sie mass Text gegen Nachbartext.)

Nach dem Aufhellen einmal komplett durchgemessen: von sieben roten
Stellen auf null. Schlechtester Wert jetzt 4,70:1 bei 4,5:1 Norm.

Die Bilder sind groesser geworden (580 KB -> 1,8 MB fuer alle achtzehn),
weil weniger Dunkelheit weniger komprimierbar ist. Geladen wird pro
Seite genau eine: 42 bis 132 KB.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 11:43:08 +02:00
DogFatherGitandClaude Opus 5 299ef0d506 Eigenes Profil fuer jeden - mit Bild und Kanaelen
SCREEN 1: Jeder im Workspace hat jetzt seinen eigenen Steckbrief --
Creator, Scout, Manager und DogFather gleichermassen. Ein Bild, ein Satz
ueber sich, und die Kanaele, auf denen er unterwegs ist. Er steht ganz
oben auf profil.html, ueber der Creator-Akte; die ist etwas anderes
(die fuehren die Betreuer, den Steckbrief fuehrt man selbst).

Das Bild erscheint sofort ueberall: in der Kopfleiste jeder Seite und in
der Begruessung. /api/ich liefert es deshalb gleich mit -- das spart auf
jeder Seite eine zweite Abfrage und verhindert, dass die Plakette erst
als Buchstabe erscheint und dann umspringt. Faellt das Bild aus, steht
der Buchstabe da: Er wird nicht ersetzt, sondern liegt darunter.

WARUM KEINE ECHTE TIKTOK-ANMELDUNG. "Mit TikTok verbinden" klingt nach
OAuth. Das waere: ein Entwicklerkonto mit App-Freischaltung, eine
Pruefung durch TikTok (Wochen, widerrufbar), je Person ein Zugriffstoken,
das ablaeuft, erneuert werden muss und -- wenn es abhandenkommt --
fremden Zugriff auf ein fremdes Konto bedeutet. Dafuer bekaeme man
Follower-Zahlen.

Gebraucht wird hier aber "Wer ist das, und wo finde ich ihn?". Dafuer
genuegt der oeffentliche Name. Gespeichert wird deshalb NUR das Handle --
kein Token, kein Passwort, nichts, was abhandenkommen kann. Daraus wird
ein Verweis auf den Kanal. Vier Kanaele: TikTok, Instagram, YouTube,
Twitch. Sollen spaeter echte Zahlen dazukommen, ist das ein eigenes
Vorhaben -- der Name hier bleibt dann trotzdem richtig.

Eingefuegt werden darf, was Leute wirklich in der Zwischenablage haben:
"@name", "https://www.tiktok.com/@name" oder der Name allein. Alles wird
auf den Namen zurueckgefuehrt, statt eine Fehlermeldung zu zeigen.

SICHERHEIT beim Bild -- die drei Stellen, an denen Profilbilder
typischerweise scheitern:
  1. Der Typ wird an der SIGNATUR der Datei geprueft, nicht am
     Content-Type, den der Absender behauptet. Ein umbenanntes SVG mit
     Skript darin kaeme sonst durch und liefe im Namen der Domain --
     mit der Sitzung des Betrachters.
  2. Auf der Platte bekommt jede Datei einen Zufallsnamen. Kein Name
     kann Pfade verlassen oder etwas ueberschreiben.
  3. Ausgeliefert mit nosniff und einer eigenen, alles verbietenden
     Inhaltsregel.
Das Bild liegt als Datei neben der Datenbank, nicht darin: Bilder in
SQLite blaehen jede Sicherung auf, und die laeuft jede Nacht.

Niemand schreibt einem anderen ins Profil -- auch DogFather nicht. Ein
Satz ueber sich und der eigene Kanalname gehoeren der Person. Wer wen
SEHEN darf, folgt der bekannten Regel: Leitung alle, Scout seine
Creator, Creator sich und seine Betreuer. Fremde Profile sind 404, nicht
403.

ZWEI FUNDE DURCH DIE PRUEFUNG:
- Der TikTok-Link, den die App beim Teilen kopiert, endet auf
  "?lang=de&is_from_webapp=1". Der wurde abgelehnt: "sieht nicht richtig
  aus" -- obwohl es der offizielle Link ist. Jetzt werden Parameter und
  Anker mit abgeschnitten.
- Ein zu grosses Bild ergab "500 Serverfehler" statt einer Ansage. Der
  PayloadTooLargeError lief bis in die allgemeine Fehlerbehandlung
  durch. Jetzt 413 mit dem Satz, wie viel erlaubt ist. Von Hand haette
  das vermutlich nie jemand probiert.

Vor der Schemaaenderung wurde eine geprueft vollstaendige Sicherung
gezogen (VACUUM INTO, Integritaet ok, 6 Personen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 11:31:34 +02:00
DogFatherGitandClaude Opus 5 fc4fde0f02 Buehnen hell, Flaechen dicht - und die Kopfleiste wieder kurz
DIE BUEHNEN WAREN ZU DUNKEL. Bei 0.42 Helligkeit sah man Schemen, nicht
die Szene -- "zu dunkel und sieht ganz komisch aus" traf es genau. Jetzt
0.66 mit etwas mehr Farbe (1.08), die Vignette schwaecher (0.52 statt
0.72). Die Bilder kommen durch.

MOEGLICH IST DAS NUR MIT DEM GEGENZUG: Alle Kacheln, Karten und Spalten
lagen bei 2 bis 3 Prozent WEISS -- also praktisch durchsichtig. Solange
der Hintergrund fast schwarz war, fiel das nicht auf; sobald er hell
wurde, lief das Bild mitten durch den Text. Jetzt gibt es --flaeche
(rgba(9,13,22,.78)), eine deckende dunkle Flaeche, und 44 Stellen in 16
Dateien holen sich ihre Farbe von dort.

Der Unterschied ist genau der, den Filipe beschrieben hat: Der
Hintergrund bleibt sichtbar, aber ZWISCHEN den Kacheln -- nicht hinter
der Schrift. Wer die Flaechen kuenftig dichter oder durchlaessiger will,
aendert eine einzige Zeile statt 44.

Die Kacheln selbst tragen ihren Farbton jetzt AUF der Flaeche
(color-mix mit --flaeche statt mit transparent) -- dadurch bleibt die
Farbe erkennbar, ohne dass die Kachel durchsichtig wird.

DIE KOPFLEISTE war so breit wie das ganze Fenster, obwohl der Text kurz
ist: .marke__text stand auf flex: 1 1 auto. Das war unsichtbar, solange
der Schriftzug nur Text war -- seit er einen Rahmen traegt, lief die
Pille quer durchs Bild. Jetzt flex: 0 1 auto (schrumpfen ja, wachsen
nein). Gemessen: 375 px statt 1280.

Kontrast an echten Bildpunkten auf allen sechs Seiten nachgemessen --
haelt trotz des viel helleren Bildes (schlechtester Wert 4,69:1).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 11:20:02 +02:00
DogFatherGitandClaude Opus 5 0391a91d14 Neun Buehnen statt einer - jede Seite hat ihre eigene Szene
Filipe hat neun Bilder geschickt, damit es VERSCHIEDENE Hintergruende
gibt. Benutzt wurde davon genau eines (das Studio), die uebrigen acht
lagen unbenutzt im Ordner -- lounge.png und skyline.png sogar schon
fertig kopiert. Zu Recht beanstandet.

Jetzt wird aus jeder Szene eine Buehne, breit und schmal, und jede Seite
bekommt die, die zu ihr passt:

  studio      Startseite            der neutrale Ort, alles beginnt hier
  showbuehne  Dashboard, Review     die grosse Buehne, alles im Blick
  garage      Aufgaben, Technik     Werkstatt, hier wird gearbeitet
  skyline     Kalender              Nacht ueber der Stadt, Zeit
  lounge      Calls, Community      Sitzecke, hier wird geredet
  arena       Dateien, Wissen       Archiv hinter dem Portal
  halle       Profil, Personen      die Halle, in der jemand steht
  wald        Start-Check, Scouting der Weg, den man erst sucht
  portal      Content, LIVE         Durchgang, hier entsteht etwas

Die Zuordnung steht in bereiche.js -- derselben Liste, aus der schon
Zeichen und Farbton kommen. Eine Seite traegt damit dreierlei aus einer
einzigen Quelle: Farbe, Zeichen und Buehne. Sie koennen nicht
auseinanderlaufen.

Alle neun bekommen dieselbe Behandlung (abgedunkelt auf 0.42, Vignette
in der Mitte, wo der Text steht, oben ausgeblendet, wo die Kopfleiste
sitzt). Sie sehen verschieden aus und verhalten sich gleich -- eine
Buehne, die je Seite anders hell waere, waere Unruhe statt Vielfalt.
Der schmale Ausschnitt ist je Szene ein anderer, weil ein auf 9:16
gequetschtes Breitbild nur noch Wand zeigt; genommen wird der Bereich,
in dem die Figuren stehen.

18 Dateien, zusammen 580 KB -- pro Seite werden davon zwei geladen
(breit ODER schmal), also 16 bis 48 KB. Die Rohbilder waren 2,4 MB je
Stueck.

Kontrast auf allen sechs geprueften Seiten an echten Bildpunkten
nachgemessen: haelt (schlechtester Wert 4,59:1).

FUND: Die Buehnenpruefung suchte nach "buehne-breit" und fand die neuen
Namen nicht mehr -- sie meldete "die Buehne liegt im Hintergrund: FEHL",
obwohl sie da war.

Die Seitenpruefung sieht jetzt nach, dass jede Seite ihre Szene hat UND
dass das Bild wirklich ankommt: Ein data-buehne ohne passende CSS-Regel
waere still wirkungslos.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 10:36:16 +02:00
DogFatherGitandClaude Opus 5 8647138bb4 Leere Seiten sehen nicht mehr kaputt aus
Die vier Aufgaben-Spalten waren vier graue Kaesten mit je einem
Gedankenstrich darin. Das sieht aus, als sei die Seite kaputt -- dabei
ist eine leere Spalte ein voellig normaler, oft sogar guter Zustand.

Jetzt hat jede Spalte ihre eigene Farbe nach STATUS (offen blaugrau,
in Arbeit blau, Review gold, erledigt gruen), einen auslaufenden
Streifen oben in dieser Farbe und eine Zeile, die erklaert, was die
Spalte ueberhaupt bedeutet -- "Review" allein sagt einem Neuen nichts.
Statt des Gedankenstrichs steht ein Satz, der die AUSSAGE des
Leerseins traegt: eine leere Review-Spalte bedeutet etwas anderes als
eine leere Erledigt-Spalte.

NEUN KOPIEN DERSELBEN REGEL. .leer-hinweis war in neun CSS-Dateien
definiert -- neunmal fast dasselbe, mit Abstaenden von 22, 26 und 30 px,
weil beim Kopieren jedes Mal etwas anders wurde. Genau davor warnt ein
Kommentar in start.css seit August ("Was auf mehreren Seiten benutzt
wird, gehoert hierher"). Jetzt einmal zentral, und jede Seite hat sie.

Und sie sieht anders aus: Der gestrichelte Rand ist weg. Gestrichelte
Raender sagen "hier fehlt etwas", grau auf grau sagt "unwichtig" --
zusammen also "kaputte Seite". Stattdessen eine ruhige, geschlossene
Flaeche im Farbton der Seite (aus data-ton, also aus der Kachelfarbe)
mit einem leuchtenden Ring. Ein Zeichen waere hier zu laut: Es geht ja
gerade darum, dass nichts da ist -- der Ring markiert die Stelle, ohne
etwas zu behaupten.

Kontrast danach nachgemessen: 4,85:1 im schlechtesten Fall.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 10:28:34 +02:00
DogFatherGitandClaude Opus 5 c46fb413ab Jede Seite traegt Zeichen und Farbe ihrer Kachel
Auf der Startseite hat jeder Bereich sein eigenes Zeichen und seinen
eigenen Farbton -- siebzehn unterscheidbare Bereiche statt siebzehn
Kaesten. Bisher endete das an der Kachel: Wer sie anklickte, landete auf
einer Seite, der man nicht mehr ansah, woher sie kam. Dreizehn Seiten,
alle in demselben Blau, alle ohne Zeichen, alle mit derselben duennen
Textzeile als Kopf.

Jetzt wird die Kachel weitergereicht. Der Kopf jeder Seite bekommt
dieselbe Behandlung wie die Kachel: Plakette mit dem Zeichen, der
Bereichsname mit leuchtendem Strich in der Kachelfarbe, ein groesserer
Titel und dasselbe Zeichen noch einmal riesig und fast unsichtbar als
Wasserzeichen dahinter. Aufgaben ist ueberall orange, Kalender ueberall
tuerkis, Personen ueberall rot-gold.

EINE QUELLE STATT ZWEIER LISTEN. Zeichen, Ton, Rolle und Ziel jedes
Bereichs standen nur in start.js. Sie einfach zu kopieren waere der
sichere Weg dazu, dass "Aufgaben" irgendwann auf der Startseite gelb und
auf der Aufgabenseite gruen ist. Beides liegt jetzt in
assets/js/bereiche.js und wird von start.js UND kopf.js benutzt -- wer
eine Kachel aendert, aendert damit automatisch auch den Kopf der Seite.
Sie koennen gar nicht auseinanderlaufen.

Eingesetzt wird die Plakette von kopf.js, nicht in dreizehn HTML-Dateien:
Das vorhandene Markup wird nur umschlossen, nicht ersetzt. Der Kalender
hat einen eigenen Kopf (dort ist der Zeitraum die Ueberschrift) und wird
ausdruecklich mitgenommen -- sonst waere ausgerechnet die aufwendigste
Seite die einzige ohne Zeichen.

Die Seitenpruefung sieht jetzt auf allen dreizehn Seiten nach, dass Ton
UND Zeichen UND Wasserzeichen da sind, und gibt beides aus (ton=9
zeichen=3/3). Eine Seite, die ihre Zuordnung verliert, faellt damit
sofort auf statt erst beim Hinsehen.

Kontrast danach an echten Bildpunkten nachgemessen: haelt auf allen
sechs geprueften Seiten (schlechtester Wert 4,80:1).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 10:22:22 +02:00
DogFatherGitandClaude Opus 5 c01aeb4225 Kalender neu: vier Ansichten, Anlaesse und Feiertage, selbst gerechnet
Der Kalender war eine Liste mit drei Zeitraum-Knoepfen. Jetzt ist er
aufgebaut wie der Redaktionskalender in VanVans Hub -- mit denselben
Bauteilen, aber auf Creator zugeschnitten.

VIER ANSICHTEN auf DENSELBEN Daten. Der Server liefert einen Zeitraum,
hier wird er nur unterschiedlich dargestellt -- so kann keine Ansicht
etwas anderes zeigen als die andere. Monat (Ueberblick und Rhythmus),
Woche (die sieben Tage gross), Liste (was kommt als Naechstes),
Zeitstrahl (wo sich etwas ballt und wo Luft ist).

ANLAESSE UND FEIERTAGE, vollstaendig selbst gerechnet. Ein leerer
Kalender ist nicht nur kahl, er ist nutzlos: Die Frage beim Planen
lautet nie "was habe ich schon eingetragen", sondern "worauf muss ich
zuarbeiten". Ostern ueber die Gauss-Formel, davon abgeleitet Karfreitag,
Himmelfahrt und Pfingsten, dazu die beweglichen Termine (Muttertag,
Black Friday als Freitag nach dem VIERTEN Donnerstag im November, die
vier Advente rueckwaerts vom vierten). Kein Dienst, keine Liste zum
Nachpflegen, keine Kosten, funktioniert offline und im Jahr 2040.

Bewusst NUR die neun bundesweiten Feiertage. Fronleichnam,
Reformationstag und Allerheiligen gelten je nach Bundesland -- ein
Kalender, der sie ueberall anzeigt, waere fuer die Haelfte der Leute
schlicht falsch. Lieber weniger behaupten als etwas Falsches.

Zwei beschriftete Reihen, die zwei VERSCHIEDENE Fragen beantworten:
"Als Naechstes" blickt ab heute nach vorn und aendert sich beim
Blaettern NICHT, "Im September" beschreibt den Monat, den man ansieht.
Ohne Ueberschriften waeren zwei gleich aussehende Reihen verwirrend.

Farbe folgt der Sache, nicht dem Rang -- dieselbe Regel wie bei den
Kacheln: Call blau, Termin violett, Review gruen, Frist orange. Ueberall
gleich: Pille im Raster, Zeile in der Liste, Filterknopf, Balken im
Zeitstrahl. Die KW-Spalte ist kein Schmuck, sondern die uebliche
Waehrung in Absprachen ("machen wir in KW 42").

NEUE PRUEFUNG pruef-kalender.mjs. Sie prueft nicht nur, DASS etwas
dasteht, sondern die gerechneten Tage gegen nachschlagbare Werte:
Ostersonntag 2026/2027/2030, Karfreitag, Himmelfahrt, Muttertag, Black
Friday und den 4. Advent. Ohne das koennte die Osterformel um einen Tag
daneben liegen und niemand wuerde es merken -- bis irgendwann jemand
Karfreitag arbeitet. Dazu: ganze Wochen im Raster, genau ein "heute",
vier Arten in vier Farben, dass ein ausgeschalteter Filter WIRKLICH
etwas ausblendet (ein Filter, der nur die Knopffarbe aendert, ist
keiner), Blaettern in beide Richtungen und der Tagesdialog.

ZWEI FUNDE:
- "Sep" am Monatsersten lag bei 3,96:1, wenn der Erste zufaellig HEUTE
  ist -- dann liegt der Text auf der aufgehellten Zelle. Nur an echten
  Bildpunkten zu sehen, nie an der Farbangabe.
- Die eigene Pruefung blaetterte stur vorwaerts und erreichte April 2026
  nie (heute ist September). Zehn rote Meldungen, die wie ein
  Rechenfehler in der Osterformel aussahen. Jetzt wird die Richtung aus
  dem offenen Monat bestimmt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 10:14:47 +02:00
DogFatherGitandClaude Opus 5 e65827a6db Begruessung, Schriftzug, hellerer Hintergrund - und "Wissen" fuer Creator
Vier Wuensche auf einmal, alle auf der Startseite und der Kopfleiste.

BEGRUESSUNG. Dort stand "Angemeldet" ueber dem Namen -- eine Zeile, die
nichts hinzufuegt, weil oben rechts ohnehin Name und Rolle stehen. Jetzt
beantwortet der Kopf die drei Fragen, die man beim Reinkommen hat:
WANN (Wochentag, Datum, Kalenderwoche nach ISO 8601, selbst gerechnet),
WER (Plakette mit dem Anfangsbuchstaben in der Farbe der Rolle -- der
einzige runde Koerper der Seite, dadurch sofort als Person lesbar) und
WIE es steht (ein Satz aus denselben Hinweisen, die darunter stehen --
keine zweite Zaehlung). An Tagen mit Charakter kommt ein Wort dazu:
Neue Woche, Endspurt, Wochenende. Der Gruss ist feiner gestuft und der
Name eigenstaendig ausgezeichnet: das Grusswort leise, der Name kraeftig.

SCHRIFTZUG oben links. Vorher alles gleich laut, der Trenner ein
Satzzeichen wie jedes andere. Jetzt hat er Rang: der Name vorn und
kraeftig, der Ort dahinter und leiser, dazwischen eine kleine Raute in
der Hausfarbe. Aufgeteilt zentral in kopf.js statt in sechzehn HTML-
Dateien, und nur die Textknoten -- Verweise bleiben unberuehrt.

HINTERGRUND heller, wie gewuenscht: Der Schleier liegt bei .86/.58/.44
statt .95/.72/.60, dazu zwei sehr weiche Farbschimmer, die dem Bild das
reine Schwarz nehmen. Der Kontrast wurde danach an echten Bildpunkten
nachgemessen und haelt ueberall (schlechtester Wert 4,78:1).

"WISSEN" statt "Team & System" -- aber nur fuer Creator. Von der Gruppe
bleibt fuer ihn genau eine Kachel uebrig; eine Ueberschrift, die Team
und System verspricht und nur die Bibliothek zeigt, verspricht etwas
Falsches.

DREI FUNDE DURCH DIE PRUEFUNGEN:

1. Die Kontrastmessung war kaputt, seit Text neben Text steht. Sie tastete
   stur 4 px rechts vom Text ab -- und traf dort den NACHBARTEXT statt den
   Untergrund (1,10:1 gemeldet, ohne dass etwas schlecht lesbar war). Jetzt
   werden sechs Stellen rings um den Text angeboten und jede zuerst
   gefragt, ob dort wirklich Untergrund liegt. Strenger, nicht lockerer.
   Texte ohne freie Stelle werden GEZAEHLT und ausgegeben, nicht still
   uebersprungen.
2. bereich.html hatte als einzige Seite kein span.marke__text. Damit
   griffen dort weder die Ueberlauf-Kuerzung noch der neue Rang. Stand seit
   Monaten so, aufgefallen erst, als die Seitenpruefung die Marke auf allen
   dreizehn Seiten nachgesehen hat.
3. Die Datumspruefung haette im Maerz stillschweigend versagt: \w kennt
   ohne Unicode-Schalter kein "ae". Ein Fehler, der sieben Monate wartet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 09:55:25 +02:00
DogFatherGitandClaude Opus 5 1816ed9e1f Hinweisliste "Was ist dran": Zeichen, Zahl und Farbe der Zielkachel
Die Zeilen waren die letzten schmucklosen Elemente der Startseite. Jetzt
traegt jede das Zeichen UND die Farbe der Kachel, zu der sie fuehrt --
Hinweis und Ziel gehoeren dadurch sichtbar zusammen, ohne dass die
Zuordnung ein zweites Mal irgendwo steht (sie kommt aus derselben
Tabelle wie die Zahl auf der Kachel). Die Anzahl steht vorn, getrennt vom
Satz und in gleicher Zeichenbreite; beim Ueberfliegen von sieben Zeilen
liest man genau sie zuerst. Ueberfaellig schlaegt Bereichsfarbe und
bleibt rot -- wenn etwas brennt, zaehlt zuerst, DASS es brennt.

Dabei gefunden und behoben: Die Farbtoene hingen an .kachel[data-ton=n].
Um sie fuer die Hinweiszeilen mitzunutzen, wurde .kachel entfernt --
damit gewann aber die Voreinstellung ".kachel { --ton: var(--akzent) }"
weiter unten in der Datei den Wettstreit der Regeln, und alle siebzehn
Kacheln waeren blau gewesen. Die Voreinstellung steht jetzt in :where()
und zaehlt dabei als nicht vorhanden. Die Browserpruefung hat das
gemeldet ("1 Farbe auf 17 Kacheln"), nicht das Auge.

"Nichts offen" ist kein gestrichelter Kasten mehr, sondern eine gute
Nachricht mit ruhigem Gruen und Haken. Weil er jetzt display:flex hat,
war er staerker als das hidden des Browsers und haette IMMER dagestanden
-- eigene Regel dafuer plus eine Pruefung, die beide Richtungen misst.

Neue Pruefungen (pruef-start-ansicht): Zeichen, vorangestellte Zahl,
keine doppelte Zahl im Satz, ganzer Satz fuer Vorleseprogramme, Farbe
gleich der Kachelfarbe an echten Bildpunkten, rot nur bei ueberfaellig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 09:39:59 +02:00
DogFatherGitandClaude Opus 5 e74254263f Buehne aus den echten Marken-Bildern, Kopfleiste und Begruessung neu
Filipe hatte recht, und zwar zweifach: Der Husky war der FALSCHE (ein
fremder Neon-Husky aus dem alten Bilderordner statt DogFather), und zwei
in die Ecken geklebte Bilder ergeben noch kein Bild.

DIE BUEHNE, zweiter Anlauf. Aus den zehn geschickten Bildern das Studio
gewaehlt, in dem HasiDog und DogFather stehen -- nicht aus Geschmack,
sondern wegen der ANORDNUNG: Die beiden stehen weit aussen, die Mitte ist
dunkel. Genau dort steht der Inhalt. Bei den Bildern mit den Figuren in
der Mitte waeren sie hinter dem Text gelandet.

Ueber die ganze Flaeche, fest an der Scheibe, 138 % breit: Bei 100 %
staenden die beiden bei 20 % und 78 % der Breite -- mitten unter der
Textspalte. Vergroessert man das Bild ueber die Scheibe hinaus, wandern
sie nach aussen (rund 9 % und 88 %) und der leere Hallenboden liegt dort,
wo gelesen wird. Ein Bild groesser zu machen, damit WENIGER davon im Weg
ist, klingt verkehrt und ist genau richtig.

Fuer schmale Schirme ein eigener Hochkant-Ausschnitt derselben Szene --
ein auf 9:16 gequetschtes Breitbild zeigt nur noch Wand.
1,9 MB PNG -> 28 KB WebP.

DIE VIER STELLEN aus den Bildschirmfotos:

* Kopfleiste: der DogFather-Kopf davor. Als MASKE aus dem Logo gerechnet
  (Dunkelheit wird Deckkraft), nicht als Bild -- so laesst er sich im
  Stil einfaerben; ein fertig eingefaerbtes Bild muesste man fuer jede
  Farbe neu bauen. 114 KB -> 3 KB.

* "Dogfather · DogFather" war der peinlichste Punkt: Name und Rolle lasen
  sich gleich, es sah nach einem Fehler aus. Jetzt drei unterscheidbare
  Dinge -- Zeichen mit dem Anfangsbuchstaben, Name, Rolle als Marke in
  ihrer Farbe. Gebaut in kopf.js, EINMAL statt vierzehnmal: Jede
  Seitendatei setzte diese Zeile bisher selbst zusammen.

* Begruessung: leuchtender Strich, groesserer Gruss, auslaufende
  Trennlinie. Dieselben Striche vor "WAS IST DRAN" und "DEINE AUFGABEN" --
  so gehoert sichtbar zusammen, was zusammengehoert.

ZWEI EIGENE FEHLER, die die Pruefungen gefunden haben:

1. Ich hatte Verlaeufe IM TEXT gebaut (background-clip mit durchsichtiger
   Schrift). Sah gut aus, und der Kontrasttest meldete 1,05:1 -- zu Recht.
   Durchsichtige Schrift haengt an einer einzigen Technik; faellt sie aus
   (Kontrastmodus, Druck, aeltere Browser), ist der Text UNSICHTBAR statt
   nur anders gefaerbt. Das ist kein Schoenheitsfehler, das ist ein
   Ausfall. Jetzt feste Farbe mit einem Hauch Leuchten.

2. Auf dem Handy stand der Abmelden-Knopf 9 px aus dem Bild. Die Suche
   nach der Ursache ging zuerst in die Irre -- der Test nannte das
   Wasserzeichen, das aber von seiner Kachel sauber abgeschnitten wird
   und nur seine Masse meldet. Gemessen war es die Marke: 209 px + 139 px
   rechte Gruppe passten nicht in 390 px. Auf dem Handy bleibt jetzt nur
   der Kopf stehen; der Markenzug steht zwei Zeilen tiefer ohnehin als
   Ueberschrift. Fuer Vorleseprogramme bleibt er im Dokument.

Und einmal habe ich mir beim Ersetzen eines CSS-Blocks das halbe
Stylesheet geloescht (die Kachel-Regeln lagen zwischen den beiden
Suchmarken). Aufgefallen sofort am Bildschirmfoto, zurueckgeholt aus Git,
danach zeilengenau ersetzt.

118 Pruefungen, alle gruen. Der Kontrast wird weiterhin an echten
Bildpunkten gemessen, jetzt an bis zu 35 Stellen je Seite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 05:45:59 +02:00
DogFatherGitandClaude Opus 5 fcebbd18bb Workspace: Casper und HasiDog als Buehne im Hintergrund
Filipe: "der hintergrund soll genau so krass und speziell sein, benutz
den hasen und husky."

Gefunden in assets/img: hero-husky.png (Casper, neonblau auf dunkel --
farblich genau die Oberflaeche) und char-hasidog.jpg (HasiDog). Der
Sticker "HasiDog & Casper" hat bestaetigt, dass die beiden zusammen
gehoeren.

Beide sitzen FEST an der Scheibe in den unteren Ecken -- sie scrollen
nicht mit, sondern stehen da wie ein Buehnenbild, vor dem gearbeitet
wird. Die Mitte bleibt frei, dort steht der Inhalt. HasiDog ist weiter
nach aussen geschoben und schwaecher als Casper: Er ist heller, sein
Gesicht zieht den Blick staerker, und direkt neben einer Kachel wuerde
man ihn ansehen statt der Kachel.

AUFBEREITET STATT EINGEBUNDEN (tools/buehne-bauen.mjs):
  * stark abgedunkelt und leicht entsaettigt -- Stimmung, kein Motiv
  * weiche Raender ins Bild EINGERECHNET. Ein hartes Rechteck saehe nach
    aufgeklebtem Foto aus; und eine Maske ueber ein 900-Pixel-Bild kostet
    bei jedem Bildaufbau Rechenzeit.
  * 290 KB PNG -> 41 KB WebP, 110 KB -> 32 KB
Gerechnet mit dem Browser, der ohnehin fuer die Pruefungen da ist -- kein
Bildprogramm, keine neue Abhaengigkeit, 0 EUR.

GEPRUEFT WIRD NICHT, OB ES HUEBSCH IST, sondern ob der Text noch lesbar
ist -- an echten BILDPUNKTEN aus dem fertigen Bildschirmfoto, nicht an
der Farbangabe im Stil. Die weiss naemlich nichts davon, was
dahinterliegt. Gemessen wird der Untergrund direkt NEBEN jedem sichtbaren
Text, auf fuenf Seiten, auf Computer und Handy: bis zu 34 Stellen je
Seite gegen den WCAG-Massstab (4,5:1, bei grosser Schrift 3:1).

UND DAS HAT SOFORT EINEN ALTEN FEHLER GEFUNDEN: Der leiseste Grauton
(--text-still) lag bei 4,43:1 -- knapp UNTER der Norm. Das war schon
lange so, nur hatte es nie jemand nachgerechnet, weil bisher niemand an
echten Bildpunkten gemessen hat. Von #6d7d92 auf #75859a angehoben; jetzt
4,95:1 auf dem hellsten Untergrund. Das gilt fuer JEDE Seite, nicht nur
fuer die mit dem Hintergrundbild.

Schlechtester Wert jetzt: 4,97:1. Alle 30 Messungen bestanden.

Nebenbei eine Falle in den Pruefungen selbst: Ein haengengebliebener
Testserver auf demselben Port fing die Anfragen ab -- der Test sprach mit
einem ALTEN Prozess und dessen anderer Datenbank, und meldete "no such
table". Der Port ist jetzt ein anderer; die Lehre steht hier, weil das
Bild "Server laeuft" trotzdem erscheint und alles richtig aussieht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-01 00:10:09 +02:00
DogFatherGitandClaude Opus 5 24048ff0e0 Zustaendigkeit: DogFather und Manager zaehlen wie ein Scout
Filipe: "dogfather soll auch zaehlen wie bananastift und patrick."

Beim Nachsehen war das kein Wunsch, sondern ein Fehlerbericht. In der
Auswahl "Betreut von" stand "DogFather" -- aber als LEER-Wert, nicht als
Person. Es sah aus wie eine Zuordnung und war keine. Genau dieselben
Creator zaehlten deshalb gleichzeitig im Hinweis "Creator ohne
zustaendige Person". Zwei Aussagen ueber denselben Sachverhalt, beide auf
demselben Bildschirm, beide fuer sich stimmig.

Jetzt kann jede betreuende Rolle eingetragen werden -- DogFather, Manager
und Scouts, in der ueblichen Reihenfolge. Der Leer-Wert heisst, was er
ist: "— niemand —". Bei DogFather und Manager steht die Rolle in
Klammern dabei; bei aehnlichen Namen ist sonst nicht zu erkennen, wen man
eintraegt. Und "betreut N Creator" steht jetzt an jeder betreuenden
Person, nicht nur an Scouts.

DER WICHTIGE TEIL: An den RECHTEN aendert das nichts.

Die Zustaendigkeit steuert die Sichtbarkeit NUR beim Scout -- die Leitung
sieht ohnehin jeden Creator. Waere das anders, haette eine
Anzeigeeinstellung still Rechte vergeben. Der Test weist beide Richtungen
nach:

  * Tili auf DogFather eingetragen -> KEIN Scout sieht sie.
  * Tili auf Patrick eingetragen   -> nur Patrick sieht sie, BananaStift
                                      weiterhin nicht.
  * Zurueck auf DogFather          -> Patrick verliert die Sicht wieder.
  * DogFather sieht in allen drei Faellen unveraendert beide Creator.

Ein Creator kann nicht zustaendig sein -- das waere eine Rolle, die es
nicht gibt. Und ein Scout kann die Zustaendigkeit weiterhin nicht selbst
setzen (404), sonst haette er die Rechtevergabe in der Hand, die ihn
begrenzen soll.

20 Pruefungen, darunter die Gegenprobe zum Hinweis: Auf "niemand"
zurueckgesetzt MUSS er wiederkommen, sonst waere er wertlos.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 23:40:27 +02:00
DogFatherGitandClaude Opus 5 7673c12136 Startseite: 17 eigene Farben -- gerechnet, nicht gewaehlt
Filipe: "jede kiste soll seine eigene farbe haben. und die kacheln sollen
viel spezieller, viel spezieller sein."

BEIM ERSTEN MAL HATTE ICH ABGELEHNT, und das war zu bequem. Mein Einwand
stimmte zwar -- ein Versuch mit frei gewaehlten Farben ergab Paare mit
1,4 Grad Abstand, also praktisch dieselbe Farbe -- aber daraus "geht
nicht" zu machen, war falsch. Es geht, man muss nur rechnen.

Der Denkfehler war die Annahme, alle 17 muessten sich voneinander
unterscheiden. Das Auge vergleicht aber nur, was NEBENEINANDER liegt.
Also:

1. 17 Toene, gleichmaessig um den Farbkreis (je 21 Grad), gerechnet in
   OKLCH -- dort sind gleiche Abstaende auch fuer das Auge gleich.
   Helligkeit und Farbstaerke konstant, damit keine sich vordraengt. Wo
   die Farbstaerke den darstellbaren Bereich verliesse (Gelb und Gruen
   frueher als der Rest), wird sie gesenkt, bis sie hineinpasst.

2. Die ZUORDNUNG ist eine Suche ueber die tatsaechlichen Nachbarschaften
   im Raster (nebeneinander UND untereinander). Gesucht: die Anordnung
   mit dem groesstmoeglichen kleinsten Nachbarabstand. Ergebnis:
   mindestens 105,9 Grad zwischen allen Nachbarn.

3. Unter allen Anordnungen, die eine harte Untergrenze schaffen, gewinnt
   die passendste: LIVE rot, Technik gelb, Reports gruen, Personen
   rot-gold, Schutz stahlblau.

Steht als tools/kachel-farben.mjs im Repo, mit festem Zufallsstartwert --
derselbe Lauf ergibt dieselben Farben. Wer Kacheln umsortiert, aendert
die Nachbarschaften und muss es neu laufen lassen; das steht auch in
start.js.

Geprueft: Helligkeitsband, Farbstaerke und Kontrast bestehen fuer alle
siebzehn gegen genau diesen Hintergrund.

VIEL SPEZIELLER -- das WASSERZEICHEN:

Jede Kachel traegt ihr eigenes Zeichen noch einmal, riesig, angeschnitten
und fast unsichtbar (7 % Deckung) in der Ecke. Das ist der Grund, warum
siebzehn Kacheln nicht mehr wie siebzehn Kaesten aussehen: Jede bekommt
eine eigene grosse Form, ohne dass ein einziges zusaetzliches Bild
geladen wird -- es ist derselbe Pfad, nur groesser. Bewusst so schwach,
dass man es nicht liest, sondern nur spuert. Beim Ueberfahren wird es
etwas deutlicher und wandert zwei Pixel.

Dazu: Zeichenfeld 46 auf 52 px mit farbigem Schein darunter, Name auf
1,06 rem, mehr Polsterung. Alles mit prefers-reduced-motion abgesichert.

44 Pruefungen. Neu: dass jede Kachel eine EIGENE Farbe hat (17 Farben auf
17 Kacheln, gemessen an der berechneten Strichfarbe) und dass das
Wasserzeichen da und schwach genug ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 23:32:22 +02:00
DogFatherGitandClaude Opus 5 ec712a3a32 Personen: jede Rolle einzeln auf- und zuklappbar
Wunsch Filipe: "ich will ueberall die liste zu machen koennen und nur
aufmachen wenn ich sie sehen will."

Jede der vier Rollen klappt jetzt einzeln auf und zu. Das ERSETZT den
Sammelknopf von vorhin ("5 weitere zeigen") -- zwei Mechanismen
nebeneinander, die dasselbe verstecken, waeren eine Einladung zum
Missverstaendnis. Der Knopf oben rechts macht jetzt etwas anderes: alles
auf einmal ("Alle aufklappen" / "Alle zuklappen"), damit man bei vier
Rollen nicht viermal klicken muss.

Der entscheidende Unterschied zum Ausblenden: Die UEBERSCHRIFT mit der
Anzahl bleibt IMMER stehen, auch zugeklappt. Man sieht jederzeit, DASS es
einen Manager gibt -- nur nicht, welchen. Wer eine ganze Rolle spurlos
verschwinden laesst, haelt sie irgendwann fuer leer.

Und zugeklappt zaehlt genau eine Frage: Steckt da etwas Gesperrtes drin,
das ich sehen muesste? Deshalb steht am Manager auch zugeklappt
"1 gesperrt", in Warnfarbe.

Die Ueberschrift IST der Knopf, als echtes <button> -- ein eigener
kleiner Schalter daneben waere ein zweites Ziel fuer dieselbe Absicht,
und ein kleineres. Als Knopf-Element statt div mit Klick-Zuhoerer machen
Tastatur und Vorleseprogramme es ohne Zutun richtig.

Der Zustand wird JE ROLLE gemerkt, nicht als "alles auf/zu": Wer die
Creator zuklappt und die Scouts offen laesst, findet das nach dem Laden
genau so wieder.

30 Pruefungen. Darunter weiterhin der wichtigste: Zuklappen ist eine
ANSICHT, kein Recht -- Tili kann sich anmelden und normal arbeiten,
waehrend ihre Rolle zugeklappt ist, und der Server liefert unveraendert
alle sieben Personen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 23:17:44 +02:00
DogFatherGitandClaude Opus 5 ac81f288c8 Personen loeschen -- mit Vorschau und einer Sicherung unmittelbar davor
Wunsch Filipe: "ich will auch die moeglichkeit haben die loeschen zu
koennen."

Das ist die einzige Handlung im ganzen Workspace, die sich nicht
rueckgaengig machen laesst. Vier Vorkehrungen:

1. NUR DOGFATHER. Nicht die Leitung, nicht ein Manager -- "nur DogFather
   hat alle endgueltigen Rechte" heisst genau hier etwas. Ein Manager
   kann weiterhin sperren; das reicht fuer den Alltag und ist umkehrbar.
   Alle anderen bekommen 404, auch fuer die Vorschau: Die verraet, wie
   viel an einer Person haengt.

2. VORSCHAU. Vor dem Klick steht da, was MITGEHT (Profil, Start-Check,
   Content-Saeulen, Sitzungen, Zustaendigkeit) und was BLEIBT und nur
   seine Zuordnung verliert (Aufgaben, Termine, Bereichseintraege,
   Dateien, Leads). Eine Aufgabe verschwinden zu lassen, weil jemand
   geht, waere Geschichtsfaelschung.

   Dazu die gefaehrlichste Einzelwarnung: Wer einen Scout loescht, nimmt
   seinen Creators die zustaendige Person weg. Die Vorschau nennt sie
   beim Namen.

3. EINE SICHERUNG DIREKT DAVOR -- und wenn sie scheitert, wird NICHT
   geloescht. Damit ist "geloescht" wiederherstellbar. Das ist der
   eigentliche Gewinn aus der Sicherungsarbeit von heute Nachmittag.

4. Der Name muss getippt werden. Nicht als Schikane: Der Loeschknopf
   sitzt neben dem Sperrknopf, und die beiden sind sehr verschieden. Wer
   den Namen tippt, hat die Zeile gelesen, die er trifft.

ZWEI FEHLER, die erst die Pruefung sichtbar gemacht hat:

a) Alle Loeschungen schrieben in DIESELBE Tagessicherung. Nach der
   dritten kannte sie die erste geloeschte Person nicht mehr -- die
   Sicherung haette genau in dem Fall versagt, fuer den sie da ist.
   Loeschungen bekommen jetzt eine eigene Datei ("vorher-…") mit
   Zeitstempel, die nie ueberschrieben wird. Aufgefallen nur, weil die
   Pruefung die ANZAHL der Dateien zaehlt und nicht bloss, ob eine da ist.

b) Der Zeitstempel hatte Sekundenaufloesung -- drei Loeschungen in
   derselben Sekunde ergaben wieder eine einzige Datei. Jetzt mit
   Millisekunden, plus Zaehler als Notloesung. Und: Eine Sicherung vor
   dem Loeschen setzt NICHT den Vermerk fuer den planmaessigen Lauf,
   sonst faellt die naechtliche Sicherung aus.

Dabei auch ein Fehler in meiner eigenen Pruefung gefunden: Sie griff die
alphabetisch erste Datei und nannte sie "die aelteste" -- "vorher-…-2.db"
sortiert aber VOR "vorher-….db", weil "-" kleiner ist als ".". Sie prueft
jetzt die Eigenschaft selbst: JEDE geloeschte Person muss sich aus
irgendeiner Sicherung zurueckholen lassen.

43 Pruefungen, Schwerpunkt auf dem, was NICHT gehen darf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 23:13:14 +02:00
DogFatherGitandClaude Opus 5 2dbf9fb57a Personen: eine Kategorie je Rolle, Reihenfolge wie auf der Zugangsseite
Wunsch Filipe: "ich will dass die auch immer die gleiche reihenfolge
haben, am besten sogar jeder seine eigene kategorie und die reihenfolge
genau wie in der zugangsseite."

Dabei kam ein echter Fehler ans Licht. Die Abfrage sortierte mit

    ORDER BY p.aktiv DESC, <Rolle>, p.name

Das "p.aktiv DESC" stand VOR der Rolle -- dadurch wanderte jede gesperrte
Person ans Ende der GESAMTEN Liste, quer durch alle Rollen. Im Bild vom
31.08.2026 stand der gesperrte Manager BanaStift deshalb ganz unten unter
den Creators. Die Reihenfolge DogFather-Manager-Scout-Creator, die
ueberall sonst gilt (ROLLEN_SORTIERUNG, CLAUDE.md), war ausgerechnet auf
der Personenseite aufgehoben -- und es sah nach Absicht aus.

Jetzt: Rolle zuerst, dann Gesperrtes ans Ende SEINER Rolle, dann Name.

Dazu vier Abschnitte mit Ueberschrift, Anzahl und demselben Zusatztext
wie auf der Zugangsseite ("Eigene Pipeline & Kontakte" usw.) -- wer sich
eben angemeldet hat, findet hier dieselbe Sprache wieder. Eine Rolle ohne
Personen wird weggelassen: Eine leere Ueberschrift ist kein
Ordnungsmerkmal, sondern eine Luecke.

Die Gruppen-Gestaltung kommt aus start.css und wird nur wiederverwendet
-- dieselbe Sprache wie auf der Startseite, kein zweiter Entwurf.

Nebenbei ein Eigentor: Der Kommentar zur Sortierung stand zuerst INNERHALB
der SQL-Zeichenkette und enthielt Rueckwaerts-Anfuehrungszeichen. Die
beenden ein Template-Literal -- der Server startete nicht mehr. Steht
jetzt darueber, mit einem Hinweis darauf.

30 Pruefungen. Neu darunter: dass die vier Abschnitte in genau dieser
Reihenfolge stehen, dass der gesperrte Manager bei den Managern steht und
nicht bei den Creators, und dass zugeklappt nur der DogFather-Abschnitt
da ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 23:05:04 +02:00
DogFatherGitandClaude Opus 5 099d9a7693 Personenliste: standardmaessig nur DogFather, Rest auf Knopfdruck
Wunsch Filipe: "ich will da nur mich und vanvan sehen, ich will dass ich
einen knopf habe wenn ich die anderen sehen will oder nicht."

Drei Dinge, die dabei nicht schiefgehen duerfen:

1. Das ist eine ANSICHT, kein Recht. Wer eingeklappt ist, ist nicht weg
   -- er wird nur nicht gezeigt. Verwechselt man das, haelt man
   irgendwann jemanden fuer geloescht, der noch vollen Zugang hat. Der
   Test weist das ausdruecklich nach: Tili kann sich anmelden und normal
   arbeiten, waehrend sie ausgeblendet ist, und der Server liefert
   weiterhin ALLE sieben Personen. Gekuerzt wird nur die Anzeige --
   waere es serverseitig, wuerde die naechste Auswertung stillschweigend
   Personen uebersehen.

2. Auf dem Knopf steht IMMER, wie viele gerade fehlen ("5 weitere
   zeigen · 1 gesperrt"). "Alle zeigen" allein sagt nicht, wovon man
   gerade nichts sieht -- und dass eine Person gesperrt ist, gehoert zu
   den Dingen, die man nicht uebersehen darf.

3. Der Zustand bleibt erhalten. Ein Knopf, den man nach jedem Laden neu
   druecken muss, ist keine Einstellung, sondern eine Zumutung.

Gesperrte Personen werden beim Aufklappen ganz normal mitgezeigt -- eine
gesperrte Person zu verstecken waere genau die Zeile, die man sehen
muesste.

24 Pruefungen, Computer und Handy.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 22:59:54 +02:00
DogFatherGitandClaude Opus 5 e25a22149b Startseite: groessere Kacheln, und das Licht folgt dem Zeiger
Rueckmeldung Filipe: "richtige richtung, die sollen nur bissl groesser
sein und noch bissl mehr spezieller."

GROESSER, gemessen statt geglaubt:
  Zeichenfeld  38 -> 46 px (Dashboard 56)
  Name        .93 -> 1.02 rem (Dashboard 1.18)
  Polsterung   14 -> 18 px, Ecken 15 -> 18 px
  Kachelhoehe        rund 60 -> ueber 80 px

Dabei fiel der eigene Test von vorhin sofort ein: Bei 880 px Seitenbreite
sind drei Kacheln je 285 px breit, und in den groesseren Schriften brach
der Text an ZWOELF Stellen ab. Statt die Schrift wieder zu verkleinern
bekommt die Startseite die volle Breite (1240 px) -- das ist die
ehrlichere Loesung. Hinweise, Begruessung und Fusstext behalten ihr Mass
von 940 px: Eine Textzeile ueber 1240 px zu ziehen macht sie nicht
lesbarer, sondern anstrengender.

SPEZIELLER, drei Dinge:

1. DAS LICHT FOLGT DEM ZEIGER. Jede Kachel traegt einen weichen
   Lichtfleck. Er sitzt ruhend oben links und wandert unter dem Zeiger
   mit. Kein Blinken, keine Bewegung des Inhalts -- es wird nur an einer
   anderen Stelle heller. Das ist die Kleinigkeit, die man nicht sieht,
   sondern erst beim Benutzen merkt.

   EIN Zuhoerer fuer alle Kacheln statt siebzehn, und in einem Bild je
   Rahmen: pointermove feuert dutzendfach je Sekunde, wer bei jedem
   Ereignis in den Stil schreibt, laesst den Browser umsonst rechnen.
   Beim Verlassen zurueck in die Ruhelage -- sonst blieben die Kacheln
   nach einer Weile alle unterschiedlich beleuchtet stehen. Auf
   Fingerbedienung und bei "weniger Bewegung" bleibt es ganz aus; dort
   gibt es keinen Zeiger, dem etwas folgen koennte. Beides geprueft.

2. Eine feine helle Linie an der Oberkante jeder Kachel. Ein Pixel, kaum
   sichtbar -- aber die Kachel wirkt dadurch von oben beleuchtet statt
   aufgeklebt. Das Zeichenfeld bekommt denselben Lichtrand und einen
   Verlauf, wodurch es gepraegt statt gemalt wirkt.

3. Beim Ueberfahren: farbiger Schein unter der Kachel im eigenen Ton,
   die Kante links waechst von 3 auf 4 px, das Zeichen um 4 Prozent.
   Alles unter zwei Pixeln Bewegung.

Die Trennlinie der Gruppenueberschriften laeuft nach rechts aus, statt
hart abzubrechen -- eine durchgezogene Linie zerschneidet die Seite, eine
auslaufende gliedert sie nur.

47 Pruefungen. Neu darunter: Zeichenfeld und Schriftgroesse werden
gemessen ("sieht groesser aus" ist kein Nachweis), und das Licht wird mit
echten Mausbewegungen an drei Stellen geprueft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 22:50:17 +02:00
DogFatherGitandClaude Opus 5 d05a772ee4 Startseite: aus siebzehn gleichen Rechtecken wird eine Uebersicht
Sie war eine Wand: siebzehn identische Kaesten, auf jedem stand "OEFFNEN".
Wenn alles gleich aussieht, ist alles gleich wichtig -- also nichts. Und
"OEFFNEN" ist keine Information; dass eine Kachel sich oeffnen laesst,
weiss man.

Drei Aenderungen, jede mit einem Grund:

1. GRUPPEN statt einer Liste. "Taeglich" (was man sowieso jeden Tag
   aufmacht), "Rund um den Creator" (die Betreuungsakte), "Team & System"
   (was den Laden am Laufen haelt). Das sind drei verschiedene Absichten.

2. ZAHLEN STATT "OEFFNEN". Auf der Kachel steht jetzt, wo Arbeit liegt --
   "Aufgaben 4", rot markiert, weil etwas ueberfaellig ist. Gespeist aus
   DERSELBEN Quelle wie die Hinweisliste darueber, kein zweiter Zaehler:
   Zwei verschiedene Wahrheiten uebereinander auf einem Bildschirm waeren
   schlimmer als gar keine Zahl.

3. ZEICHEN UND FARBE. Siebzehn eigene Linienzeichen (eigene Pfade, keine
   Fremdbibliothek -- kleiner als jede Schriftart und keine zusaetzliche
   Lieferkette) und acht Farbtoene.

Warum acht Toene und nicht siebzehn: Ich hatte zuerst eine eigene Farbe
je Kachel gebaut und das Ergebnis pruefen lassen. Zwei Paare hatten einen
Abstand von 1.4 und 5.6 -- also praktisch dieselbe Farbe. Das sieht nach
Zufall aus, nicht nach Absicht. Die acht jetzt verwendeten sind gegen
genau diesen Hintergrund gerechnet und bestehen alle Pruefungen
(Helligkeitsband, Farbstaerke, Farbfehlsichtigkeit dE 8.4,
Normalsicht 19.3, Kontrast). Verteilt so, dass in einer Zeile nie
zweimal derselbe Ton steht. Die Farbe stuetzt nur -- WAS eine Kachel
ist, sagen Zeichen und Name.

Dazu:
- Begruessung nach Tageszeit statt immer "Willkommen".
- Sechs Nullen nebeneinander sind Rauschen: Ist wirklich nichts offen,
  steht dort ein Satz und der Platz gehoert den Bereichen.
- Die Hinweisliste stand mit sieben Zeilen im Weg. Jetzt vier sichtbar,
  Rest auf Knopfdruck -- derselbe Helfer wie im Protokoll und im Verlauf.
- Gestaffelter Einlauf, aber in einer no-preference-Abfrage: Bei
  "weniger Bewegung" entsteht gar keine Animation, nicht nur eine ohne
  Dauer. Geprueft mit reducedMotion.

Beim Ansehen des ersten Bildes fielen abgeschnittene Untertitel auf
("Stammdaten, Ziele, 90-..."). Abgeschnittener Text ist der haeufigste
stille Fehler in einer Kachel, weil er nach Absicht aussieht. Texte
gekuerzt -- und der Test misst jetzt die tatsaechliche Textbreite gegen
die verfuegbare, damit es nicht wiederkommt.

40 Pruefungen, Computer und Handy, alle vier Rollen: Ein Creator sieht
"Mein Profil" statt der Liste aller Creator, keine Personenverwaltung,
keine Pipeline, keine Automationen -- und trotzdem drei saubere Gruppen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 22:36:29 +02:00
DogFatherGitandClaude Opus 5 43ce6551e2 Bereiche nur lesend fuer Creator + Content-Planung als echte Strecke
ZWEI SACHEN, beide auf Wunsch vom 31.08.2026.

1) "die creator sollen da nur die sehen die wir ihnen eintragen, also
   dogfather manager und scout."

Vorher durfte ein Creator in LIVE, Content, Technik, Community und Schutz
selbst anlegen, aendern und eigene Eintraege loeschen. Das hebelt den
Zweck dieser Bereiche aus: Sie sind die Betreuungsakte. Wer eine
LIVE-Auswertung umschreiben oder eine unbequeme Notiz verschwinden lassen
kann, macht die Akte wertlos.

Der Creator SIEHT weiterhin alles, was zu ihm gehoert -- vollstaendig.
Er kann es nur nicht veraendern. Umgesetzt als EINE Schranke vor allen
schreibenden Wegen, nicht als Pruefung an drei Stellen: Genau so ist hier
schon einmal ein Loch entstanden (zwei von drei Stellen abgesichert, die
dritte vergessen). 403 mit klarem Text statt 404 -- der Bereich existiert
fuer ihn ja, er steht davor.

Vorsicht Express 4: Der Platzhalter heisst dort `*`, nicht `*name` wie in
Fassung 5. Mit der falschen Schreibweise haette die Sperre stumm nichts
getan -- kein Fehler, keine Warnung.

37 Pruefungen, Schwerpunkt auf den verneinenden Faellen: alle fuenf
Bereiche, alle drei Wege, dazu der eigene Alteintrag (der frueher
ausdruecklich erlaubt war) und der Nachweis, dass hinterher wirklich
nichts veraendert wurde.

2) Content-Planung: aus der Liste wird eine Strecke.

Recherchiert statt geraten. Die Quellen sind an drei Punkten eindeutig:

  * "A content calendar for creators is a pipeline, not a datebook" --
    eine Wand aus Terminen verbirgt genau die Stellen, an denen es hakt.
  * Die ersten ein bis drei Sekunden entscheiden ueber die Verbreitung.
    Der Hook ist deshalb ein eigenes Feld auf jeder Karte, kein Fliesstext.
  * Regelmaessigkeit schlaegt Menge. Wer regelmaessig senden will, braucht
    VORRAT -- und Vorrat ist die eine Zahl, die eine Ideenliste
    verschweigt.

Daraus:
  * Fuenf Stufen statt drei (Idee, Hook & Skript, Gedreht, Fertig &
    geplant, Veroeffentlicht). Alte 'produktion'-Eintraege werden beim
    naechsten Start auf 'gedreht' umgestellt -- ohne das fielen sie aus
    jeder Spalte heraus.
  * Neue Felder hook, format, saeule_id, geplant (ALTER TABLE, gefahrlos).
  * Content-Saeulen je Creator, drei bis fuenf, nach der 70/20/10-Regel.
    Mit Balance-Balken ueber 90 Tage, nur Veroeffentlichtes -- was auf dem
    Kanal steht, ist die Wahrheit ueber seine Ausrichtung.
  * Die Kachel VORRAT rechnet in TAGE um ("reicht noch etwa 7 Tage").
    "4 Videos uebrig" sagt nichts; die Tage sagen, ob man am Wochenende
    drehen muss. Gezaehlt wird nur Gedrehtes und Fertiges -- eine Idee ist
    kein Video, und wer Ideen mitzaehlt, steht am Donnerstag ohne Material.
  * "Ideen lassen sich direkt in Aufgabe/Termin/LIVE-Thema ueberfuehren"
    -- woertlich aus dem Konzept, das letzte unumgesetzte Stueck. Die Idee
    bleibt bestehen und bekommt einen Vermerk, damit niemand dieselbe
    Aufgabe zweimal anlegt.

Farben: Die fuenf Saeulenfarben sind Daten, keine Dekoration. Geprueft
gegen genau diesen Hintergrund (#0a0d13) auf Helligkeitsband,
Farbstaerke, Farbfehlsichtigkeit (schlechtestes Paar dE 8.4),
Normalsicht-Abstand (19.3) und Kontrast -- alle Pruefungen bestanden.
Immer mit Legende UND Beschriftung; Farbe allein traegt nie die
Information.

Beim Ansehen des ersten Bildes fiel der klassische Brett-Fehler auf: Die
Spalte "Veroeffentlicht" waechst ewig und schiebt alles andere aus dem
Bild. Sie zeigt jetzt die juengsten sechs, der Rest ist einen Klick
entfernt. Die vorderen Spalten bleiben ungekuerzt -- was dort liegt, ist
Arbeit.

Nur EIN Schreiber fuer die Tabelle eintraege: workspace-content.js
enthaelt ausschliesslich, was es woanders nicht gibt (Saeulen,
Kennzahlen, Ueberfuehren). Zwei Module auf denselben Zeilen waeren der
sichere Weg zu zwei Wahrheiten.

45 + 40 Pruefungen, Computer und Handy, dazu die Gegenprobe: Ein Creator
sieht die ganze Strecke, die Kennzahlen und die Verteilung -- und keinen
einzigen Knopf, auch keinen versteckten. Ausgeblendet ist nicht dasselbe
wie nicht vorhanden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 21:45:14 +02:00
DogFatherGitandClaude Opus 5 1f2823f35a Wiederherstellung: Anleitung auf den automatischen Lauf umgestellt
Der Abschnitt beschrieb noch einen Befehl, den man woechentlich selbst
eintippt. Seit die Windows-Aufgabe laeuft, stimmt das nicht mehr -- und
eine Anleitung, die etwas Falsches behauptet, ist schlimmer als keine.

Dazu ein neuer Abschnitt: woran man sieht, dass es noch laeuft.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 18:35:56 +02:00
DogFatherGitandClaude Opus 5 17c605b93d Sicherung: laeuft von allein, und ein stiller Ausfall faellt auf
Filipe zu Recht: "wieso soll ich diesen Befehl einmal die Woche eingeben,
ich will einmal und dass es dann alleine laeuft". Ein Befehl, den man
selbst eintippen muss, wird irgendwann vergessen -- und zwar genau dann,
wenn er zaehlt.

tools/sicherung-einrichten.ps1 legt eine Windows-Aufgabe an: taeglich
statt woechentlich (der Lauf dauert Sekunden, bei woechentlich waere die
Kopie im schlimmsten Fall sechs Tage alt), 13:30 statt nachts (der
Rechner laeuft nicht durch), und mit StartWhenAvailable -- war der
Rechner aus, holt Windows den Lauf beim naechsten Hochfahren nach. Ohne
diesen Schalter fiele jeder verpasste Termin ersatzlos aus. Braucht keine
Administratorrechte und macht am Ende gleich einen Probelauf: eine
Einrichtung, die man nicht ausprobiert, ist eine Vermutung.

Damit entsteht aber ein neues, schlimmeres Problem: Wenn die Aufgabe
still klemmt oder der Rechner wochenlang aus ist, merkt es NIEMAND. Man
glaubt, man haette eine Kopie ausser Haus, und hat sie nicht. Deshalb
meldet sich das Abholskript nach jedem Lauf beim Server zurueck, und die
Automationen-Seite zeigt, wie alt die Kopie ist -- nach zehn Tagen wird
sie auffaellig.

Die Rueckmeldung laeuft ueber einen eigenen langen Schluessel, nicht ueber
einen Zugangscode: Das Skript laeuft unbeaufsichtigt und muesste einen
Code sonst dauerhaft auf der Platte halten. Der Schluessel kann NUR einen
Zeitstempel setzen -- nichts lesen, nichts aendern. Verglichen wird
zeitunabhaengig.

Dabei eine unauffaellige Falle gefunden: In workspace-aufgaben.js steht
`aufgabenRouter.use("/workspace/api", angemeldet)` -- eine Schranke ueber
JEDEN Pfad unter /workspace/api, nicht nur die eigenen. Alle spaeter
eingehaengten Module leben stillschweigend davon. Die Rueckmeldung wurde
dort mit 401 abgewiesen, bevor ihr Schluessel ueberhaupt geprueft wurde;
der richtige Schluessel sah dadurch aus wie ein Fehler in der Pruefung.
Das Sicherungsmodul haengt jetzt VOR dem Aufgabenmodul und bringt seine
eigene Schranke mit -- damit haengt es an keinem anderen Modul mehr.

Ausserdem: Die Ueberschrift im Kasten nennt jetzt den GRUND, aus dem er
gelb ist. Vorher stand dort "Zuletzt gesichert vor 2 Minuten", waehrend
die Farbe wegen der fehlenden Kopie warnte -- die Anzeige widersprach
sich selbst und man sucht den Fehler an der falschen Stelle.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 18:34:46 +02:00
DogFatherGitandClaude Opus 5 3f18e1bd69 Sicherung: Kopie auf den PC, Dateien mit dabei, Wiederherstellungs-Anleitung
Eine Sicherung, die auf derselben Platte liegt wie das Original, ist keine
-- sie hilft gegen versehentliches Loeschen, nicht gegen einen
Plattenausfall. tools/sicherung-holen.sh holt sie deshalb auf den
Arbeitsrechner.

Dabei ist gleich eine zweite Luecke aufgefallen und mitgeschlossen: Die
Datenbank kennt hochgeladene Dateien und die PDFs der Bibliothek nur ueber
ihren Namen -- die Dateien selbst liegen daneben im Dateisystem und
stecken NICHT in der Datenbanksicherung. Nach einem Plattenausfall haette
man eine Bibliothek voller Verweise auf PDFs, die es nicht mehr gibt.
Werden jetzt mitgeholt.

Bewusst nur auf dem PC und nicht zusaetzlich auf dem Server: Eine zweite
Kopie auf derselben Platte haette gegen nichts geholfen, was die erste
nicht schon ueberlebt haette. Und weil scp nie loescht, bleibt ein einmal
geholtes PDF hier erhalten, auch wenn es auf dem Server verschwindet.

Geprueft wird mit Node statt mit dem sqlite3-Programm: Node bringt SQLite
selbst mit, auf diesem Windows-Rechner ist sqlite3 gar nicht da -- die
erste Fassung gab nur Fragezeichen aus und meldete trotzdem "fertig".

WIEDERHERSTELLUNG.md beschreibt drei Faelle (aus Versehen geloescht /
Datenbank zurueckspielen / Server ganz weg), jeweils als EIN Block zum
Kopieren. Der Ruecklauf legt den kaputten Stand mit mv zur Seite statt
ihn zu loeschen -- falls die Sicherung aelter war als gedacht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 18:24:32 +02:00
DogFatherGitandClaude Opus 5 7a393b9335 Workspace: naechtliche Sicherung, die auch wirklich Daten enthaelt
Bisher wurde nur EINMAL gesichert: direkt vor einer Umstellung der
Datenbank. Faellt die Platte aus, ist alles weg -- die komplette
Betreuung, jede Aufgabe, jedes Protokoll. Das war das einzige Risiko im
System, das auf einen Schlag ALLES kostet.

Beim Nachsehen auf dem Server kam ein zweiter, schwerwiegenderer Befund
dazu:

    workspace.db          4.096 B
    workspace.db-wal  2.101.232 B

Im WAL-Betrieb landen Schreibvorgaenge zuerst im -wal und wandern erst
beim Checkpoint in die Hauptdatei. Der lief seit dem ersten Tag nicht.
Wer also workspace.db kopiert haette -- der naheliegendste Sicherungsweg
ueberhaupt -- haette eine LEERE Datenbank gesichert und es nicht gemerkt.
Der Test stellt genau das nach: aus der reinen Dateikopie waren 0 von 200
Aufgaben lesbar.

Deshalb:
- Nie eine Dateikopie. Immer VACUUM INTO -- SQLite schreibt selbst, liest
  das WAL mit, Ergebnis ist in sich stimmig auch waehrend Schreibzugriffen.
- Vor jeder Sicherung ein erzwungener Checkpoint (TRUNCATE). Haelt die
  Hauptdatei aktuell und das WAL klein.
- Jede frische Sicherung wird SOFORT wieder geoeffnet und geprueft: auf
  Unversehrtheit UND darauf, dass Personen darin stehen -- gegen genau den
  Fall einer technisch einwandfreien, aber leeren Datei. Faellt sie durch,
  wird sie geloescht statt behalten.
- Erst unter Zwischennamen schreiben, dann pruefen, dann umbenennen. Sonst
  stuende nach einem Abbruch eine halbe Datei unter dem richtigen Namen.
- Aufbewahrung 7 taeglich / 4 woechentlich / 6 monatlich, je Art getrennt
  aufgeraeumt, damit taegliche nie die monatlichen verdraengen.

Laeuft IM Prozess, nicht als Systemdienst: keine Aenderung an Systemdateien
noetig, die Datenbank ist ohnehin offen, und es kommt mit jedem git pull
mit. Statt setTimeout auf 24 h wird viertelstuendlich geprueft, ob fuer
HEUTE schon eine liegt -- das ueberlebt Neustarts und Ausfaelle.

Dazu eine Zustandsansicht auf der Automationen-Seite: wann zuletzt, wie
gross, wie viele Personen darin, wie viel wartet noch im WAL, wie viel
Platz ist frei. Plus "Jetzt sichern" von Hand. Nur Leitung, 404 statt 403
fuer alle anderen.

Geprueft (server/pruef-sicherung.mjs, 27 Pruefungen) einschliesslich des
Ernstfalls: Sicherung schreiben, Datenbank zerstoeren, zurueckspielen,
Vollstaendigkeit und Schreibbarkeit nachweisen. Eine ungetestete Sicherung
ist eine Vermutung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 18:20:35 +02:00
DogFatherGitandClaude Opus 5 1894395d8f Workspace: lange Protokoll-Listen aufklappbar, zugeklappt vier Zeilen
Die "Letzten Ereignisse" im Personen-Bereich fuellten mit 25 Zeilen die
halbe Seite, obwohl sie Nachschlagewerk sind und kein Startbild. Jetzt
stehen nur die vier neuesten da, der Rest kommt auf Knopfdruck.

Der Knopf sagt, was er TUT ("Alle 25 zeigen" / "Nur die letzten 4") und
nennt die Zahl, damit man weiss, was dahintersteckt. Bei hoechstens vier
Eintraegen bleibt er ganz weg -- ein Knopf, der nichts verbirgt, verwirrt
nur. Der Pfeil dreht sich, aria-expanded stimmt.

Gemeinsamer Helfer in kopf.js statt zweimal derselbe Block: Dieselbe
Liste gab es auf der Automationen-Seite ("Zuletzt automatisch passiert"),
die verhaelt sich jetzt genauso. Zugeklappt wird per CSS
([data-klapp="zu"]) statt durch Entfernen von Zeilen -- das Aufklappen
braucht so weder Neuaufbau noch zweite Abfrage.

Der Zuhoerer wird nur einmal gesetzt (die Listen werden bei jeder
Aktualisierung neu aufgebaut), und die Anzahl wird bei jedem Umschalten
frisch gelesen statt in der Fassung des ersten Durchlaufs festzuhaengen.

Geprueft: beide Seiten, Computer und Handy, zweimaliges Hin- und
Herklappen, Gegenprobe mit drei Eintraegen -- server/pruef-protokoll-klappe.mjs

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 13:27:07 +02:00
DogFatherGitandClaude Opus 5 299d2a23b3 Workspace: Dashboard gebaut, Kopfleiste auf dem Handy repariert
Die Kachel "Dashboard" fuehrte nirgendwohin -- man stand ja schon auf der
Startseite. Statt sie zu streichen bekommt sie ein Ziel: die
Gesamtuebersicht je Creator, die das Konzept auf Seite 1 als "UEBERSICHT
-- alles zentral" verspricht und die es bisher nirgends gab. Die
Startseite bleibt der Einstieg (was ist dran, wohin gehe ich), das
Dashboard ist der Ueberblick (wie steht es um wen).

Eine Karte je Creator: ueberfaellig, dringend, offen, in Arbeit, im
Review, erledigt in 30 Tagen, dazu der naechste Termin, der Start-Check
als Balken und wie lange die Person nicht mehr da war. Jede Zahl ist ein
Verweis -- eine Zahl ohne Weg dorthin waere nur ein schlechtes Gewissen.
Sortiert nach dem, was Handlung verlangt, nicht alphabetisch.

Sichtbarkeit serverseitig wie ueberall: Creator sieht sich selbst
("Mein Stand"), Scout nur seine zugeteilten, DogFather und Manager alle.
Der naechste Review-Termin faellt fuer alle ausser der Leitung weg.

Nebenbei zwei alte Fehler gefunden und behoben:

1. Die Kopfleiste schob auf einem 390px-Handy 214 px aus dem Bild -- der
   Abmelden-Knopf war dort auf JEDER Seite unerreichbar. Ursache: In der
   Flex-Zeile fehlte min-width: 0, also konnte nichts schrumpfen. Auf
   kleinen Schirmen weicht jetzt die Marke (steht direkt darunter noch
   einmal als Ueberschrift) und der Zurueck-Knopf zeigt nur den Pfeil.
   Geprueft von 320 bis 1440 px auf 14 Seiten.

2. .inhalt--breit, .kopf-zeile, .zurueck und .leise standen in
   aufgaben.css -- einer Datei, die eine neue Seite gar nicht laden muss.
   Derselbe Fehler wie frueher bei .knopf-still und .schalter. Jetzt in
   start.css, die jede Seite laedt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-31 13:17:04 +02:00
DogFatherGit eb87e4a484 Workspace: keine Kachel mehr ohne Ziel -- Automationen bekommen ihren Ort
Filipe: "da sind aber noch zwei kategorien zu". Er hat recht, und es
waren zwei VERSCHIEDENE Fehler.

1) "DASHBOARD" war eine Kachel, die man nicht oeffnen kann -- man steht
   ja schon darauf. Sie stand seit dem ersten Tag als Platzhalter da.
   Ein Eintrag, der nirgendwohin fuehrt, sieht aus wie etwas Unfertiges.
   Entfernt.

2) "AUTOMATIONEN" trug noch "Phase 4", obwohl die Automationen laengst
   liefen -- sie waren nur verteilt (Hinweise auf der Uebersicht, Suche
   ueberall, KI-Vorschlaege an drei Stellen) und hatten keinen Ort.
   Jetzt haben sie einen.

DIE SEITE FUEHRT BEWUSST NICHTS EIGENES. Was dort steht, kommt aus den
Bereichen selbst -- eine Seite, die Automationen doppelt abbildet, waere
die naechste Stelle, die irgendwann etwas anderes behauptet als die
Wirklichkeit. Vier Abschnitte:

- Die lokale KI mit Zustand, Modell, Ort, Kosten und Grenzen -- und dem
  einzigen Schalter der Seite. Sie ist die einzige Automation, die
  Rechenzeit kostet, die der Website gehoert.
- "Was gerade anliegt": dieselben Hinweise wie auf der Uebersicht, hier
  vollstaendig statt gekuerzt.
- "Laeuft dauerhaft im Hintergrund": sieben Regeln im Klartext. Jede
  beschreibt etwas, das tatsaechlich im Code steht.
- "Zuletzt automatisch passiert": aus dem Protokoll, gefiltert auf das,
  was ohne Zutun geschah.

DER KI-SCHALTER WIRD AN ZWEI STELLEN GEPRUEFT: beim Anzeigen der
Knoepfe UND in jedem Endpunkt. Eine Oberflaeche, die etwas versteckt,
ist keine Sperre. Geprueft: abgeschaltet liefert der Endpunkt 403, ein
Creator darf gar nicht schalten (403), die Einstellung ueberdauert einen
Neustart (eigene Tabelle, damit sie dieselbe Sicherung bekommt wie alles
andere).

NEBENBEI DERSELBE FEHLER WIE FRUEHER: Der Schalter-Baustein lag in
wissen.css und fehlte prompt auf der neuen Seite -- dort erschien er als
nacktes Kaestchen. Wie damals bei .knopf-still. Liegt jetzt in gate.css.

Geprueft: 17 Kacheln, KEINE mehr ohne Ziel. Creator wird von der Seite
weggeleitet (302). Handy ohne Ueberlauf, 0 Konsolenfehler.
2026-08-31 12:46:22 +02:00
DogFatherGit 63aea61f39 Aufgaben: Rueckmeldungen ("Aufgaben & Feedback")
Letzter offener Punkt aus dem Konzept, Seite 4: Ein Creator hat laut
Rollenbeschreibung "Aufgaben & Feedback" -- die Aufgaben gab es, das
Feedback nicht. Ohne diese Moeglichkeit endet jede Rueckfrage ausserhalb
des Systems, in WhatsApp, und damit ausserhalb dessen, was spaeter noch
nachvollziehbar ist.

Neue Tabelle aufgaben_notizen. Wer die Aufgabe sehen darf, darf auch
mitreden -- geprueft ueber DIESELBE Sichtbarkeitsregel wie fuer die
Aufgabe selbst. Eine eigene Regel gibt es bewusst nicht: Zwei Regeln
fuer dieselbe Sache laufen irgendwann auseinander, und die Aufgaben-
sichtbarkeit ist die schwierigere von beiden (Creator sieht eigene,
Scout die seiner betreuten Creator, Leitung alles).

404 statt 403, wenn die Aufgabe nicht sichtbar ist -- wer sie nicht
sehen darf, soll nicht erfahren, dass es sie gibt.

Die eigene Rueckmeldung darf jeder zuruecknehmen, fremde nur die
Leitung. Eine Rueckmeldung ist keine Abstimmung: Wer sich vertippt hat,
soll das nicht bei jemandem beantragen muessen.

Der Knopf auf der Karte zeigt die ANZAHL, nicht nur ein Symbol -- so
sieht man ohne Aufklappen, wo schon etwas besprochen wurde, und die
Karte bleibt trotzdem ruhig. Aufgeklappt wird direkt an der Karte, nicht
in einem Fenster: Man liest die Rueckmeldungen im Zusammenhang mit der
Aufgabe, sonst fehlt beim Antworten die Haelfte.

Geprueft:
- Chef und Luna schreiben sich gegenseitig, beide sehen beides
- Mika (fremder Creator) bekommt 404 beim Lesen UND beim Schreiben
- ohne Anmeldung 401, fremde Herkunft 403, leerer Text abgewiesen
- Luna kann Chefs Rueckmeldung nicht loeschen, ihre eigene schon
- Chef kann alle loeschen
- Zaehler auf der Karte stimmt, Handy ohne Ueberlauf, 0 Konsolenfehler
2026-08-31 12:37:50 +02:00
DogFatherGit fc0fd0c748 Wissen: "Neu" laeuft nach 48 Stunden von selbst ab
Filipe: neue Anleitungen sollen nach 48 Stunden aus dem oberen Block
verschwinden und nur noch in ihrer Kategorie zu finden sein. Vorher
standen sie dort 30 Tage.

ZUERST EIN PROBLEM IM BESTAND: Es gab gar keinen Zeitpunkt, nur ein
Datum (veroeffentlicht). Eine abends um 23 Uhr eingestellte Anleitung
waere damit nur 25 statt 48 Stunden neu gewesen. Neue Spalte
"hochgeladen" mit dem genauen Zeitpunkt -- eine Spalte anzuhaengen laesst
SQLite anstandslos zu, anders als eine geaenderte CHECK-Regel. Alte
Eintraege ohne Zeitstempel fallen auf Mitternacht des Datums zurueck,
geprueft.

ZWEI DINGE BEWUSST GETRENNT:

NEU laeuft nach 48 Stunden ab, gemessen ab dem Hochladen. Nicht ab
"veroeffentlicht" -- das ist nur ein Datum und darf frei gesetzt werden.

WICHTIG bleibt stehen, bis es jemand abschaltet. Es ist eine
Entscheidung von Hand ("Erscheint zusaetzlich ganz oben unter Neu &
wichtig"), keine Eigenschaft, die von selbst verfaellt -- sonst waere der
Schalter sinnlos. Wer eine angepinnte Anleitung loswerden will, nimmt
sie ueber "Bearbeiten" wieder heraus.

Damit man sieht, WARUM etwas oben steht, gibt es jetzt zwei Marken statt
einer: "Neu" (gruen, laeuft ab) und "Wichtig" (gold, bleibt). Sonst
wundert man sich, wenn eine verschwindet und die andere nicht. Unter der
Ueberschrift steht dieselbe Regel in einem Satz.

Geprueft mit kuenstlich gealterten Eintraegen:
   0 h -> im Block, Marke "Neu"
  47 h -> im Block, Marke "Neu"
  49 h -> raus, aber weiterhin in der Kategorie
 200 h + wichtig -> im Block, nur Marke "Wichtig"
 300 h -> raus, in der Kategorie auffindbar
  ohne Zeitstempel -> faellt auf das Datum zurueck
2026-08-31 12:26:50 +02:00
DogFatherGit 7c81b17f9c Workspace: alle Auswahlfelder ohne Systemmenue
Filipe: "die kisten wo die namen drin stehen um auszuwaehlen -- kannst
du doch ueberall besser aussehen lassen". Betraf nicht eine Stelle,
sondern 28 Auswahlfelder auf zehn Seiten.

Deshalb EIN Baustein (assets/js/wahl.js) statt zehn Einzelloesungen.

WIE ER ARBEITET:
Das echte <select> bleibt im Dokument und behaelt seinen Wert -- es wird
nur unsichtbar. Darueber liegt ein eigener Knopf mit eigener Liste.
Damit funktioniert alles weiter, was schon da war: jedes `feld.value`,
jedes `change`-Ereignis, jedes Formular. Ich musste keine einzige der
zehn Seiten in ihrer Logik anfassen.

Faellt das Skript aus, ist wieder das gewohnte Systemmenue da.

DREI ENTSCHEIDUNGEN, DIE WICHTIG WAREN:

1. Nicht display:none fuer das echte Feld, sondern ein Pixel und
   durchsichtig. Ein per display:none verstecktes Feld faellt aus der
   Formularpruefung des Browsers heraus -- `required` wuerde stumm nicht
   mehr greifen.

2. Die Liste haengt an position:fixed, nicht am Elternelement. In einer
   Karte mit overflow:hidden waere sie sonst abgeschnitten. Passt sie
   nach unten nicht mehr hin, klappt sie nach oben.

3. Ein MutationObserver erfasst Felder, die erst spaeter entstehen, und
   Eintraege, die nachgeladen werden. Neu gezeichnet wird im naechsten
   Bild -- so wird ein direkt nach dem Fuellen gesetztes `feld.value`
   noch mitgenommen. Geprueft an der Scout-Pipeline: Prioritaet und
   Stufe entstehen erst beim Aufklappen, beide werden aufgewertet, der
   gewaehlte Wert kommt beim Speichern richtig an.

Tastatur wie gewohnt: Pfeile oeffnen und blaettern, Buchstaben springen
zum passenden Eintrag, Esc schliesst, Klick daneben auch. Gruppen
(optgroup) werden als Zwischenueberschrift dargestellt.

Geprueft ueber zehn Seiten: 28 Felder, KEINES mehr als Systemmenue,
Werte kommen an, Seite reagiert auf die Auswahl, Handy ohne Ueberlauf,
0 Konsolenfehler.
2026-08-31 12:23:49 +02:00
DogFatherGit e14d9d5042 Wissen: Kategoriewahl und Filter ohne Systemmenue
Filipe: "wieso sieht das so scheisse aus?" -- zum aufgeklappten
Auswahlmenue der Kategorie. Er hat recht, und die Ursache ist dieselbe
wie bei der Rollenwahl: Ein AUFGEKLAPPTES <select> laesst sich nicht
gestalten. Es kommt vom Betriebssystem, in Windows-Weiss, mitten in
einer dunklen Oberflaeche. Bei zwanzig Eintraegen kam dazu, dass man in
so einer Liste nichts findet.

KATEGORIEWAHL: jetzt dieselben sechs Welten, dieselben Farben und
dieselben Symbole wie die Kacheln auf der Seite. Man waehlt aus
demselben Regal, in dem man sonst stoebert. Unter der Wahl steht die
Beschreibung der gewaehlten Kategorie -- die Zeile, die beim
Einsortieren die eigentliche Frage beantwortet.

Nichts ist vorausgewaehlt (ausser man laedt aus einer Kategorie heraus
hoch). Die stille Vorbelegung war der Grund, warum eine PDF ueber
TikTok LIVE Studio unter "TikTok - Grundlagen" landete.

FILTER Stufe und Geraet: ebenfalls Schalter statt Menue. Zwei bis vier
Werte, die sich nie aendern -- dafuer ein Menue zu oeffnen ist ein Klick
zu viel.

Der Tag-Filter bleibt bewusst ein Auswahlfeld: Tags wachsen mit dem
Bestand, eine Schalterreihe waere irgendwann zwei Zeilen lang.

Geprueft: 20 Kategorien in 6 Welten, nichts vorausgewaehlt, Filter
setzen die Adresse (?stufe=einsteiger), Handy ohne Ueberlauf, 0
Konsolenfehler. Testeintrag landete unter der gewaehlten Kategorie.
2026-08-31 12:14:18 +02:00
DogFatherGit 389d8c1213 Workspace: neue Rolle Manager, feste Rollenreihenfolge, echte Rollenwahl
DREI TEILE.

1) ROLLE "MANAGER"

Ein Manager darf alles, was DogFather darf -- mit genau zwei
Vorbehalten: Er kann keine Leitung ANLEGEN und an keiner Leitung etwas
AENDERN. Sonst koennte er sich einen zweiten Vollzugang schaffen oder
DogFather aussperren. "Nur DogFather hat alle endgueltigen Rechte"
heisst genau das.

Umgesetzt ueber istLeitung() an EINER Stelle statt 44 einzelner
Vergleiche auf "admin" im Server und 26 im Browser.

DATENBANK-UMSTELLUNG: CREATE TABLE IF NOT EXISTS fasst eine vorhandene
Tabelle nicht an -- die CHECK-Regel stand also weiter auf den alten drei
Rollen, und ein Manager waere daran gescheitert, obwohl der Code stimmt.
SQLite kann eine CHECK-Regel nicht aendern, also: neue Tabelle, Daten
hinueber, alte weg, umbenennen. Davor schreibt der Server eine
vollstaendige Sicherung (VACUUM INTO, in sich konsistent). Ohne
Sicherung wird NICHT umgestellt.

Geprueft nach der Umstellung: alle 13 Tabellen mit gleicher Zeilenzahl,
PRAGMA integrity_check ok, keine verwaisten Verweise. Die einzige
Abweichung war eine Sitzung mehr -- die eigene Anmeldung, die die
Umstellung ausgeloest hat.

2) EIN SICHERHEITSLOCH, DAS DER TEST GEFUNDEN HAT

Der erste Entwurf sicherte "Person anlegen" und "Person sperren" ab --
und liess "neuer Zugangscode" offen. Ein Manager konnte DogFather einen
neuen Code ausstellen, bekam ihn angezeigt und haette ihn damit aus
seinem eigenen Konto ausgesperrt. Im Test aufgefallen, weil ich den
negativen Fall durchgespielt habe.

Behoben nicht durch eine dritte Einzelpruefung, sondern durch eine
Schranke an JEDEM Weg mit einer :id. Der naechste Weg, der dazukommt,
ist damit automatisch mitgeschuetzt.

Nachgeprueft: Manager bekommt 403 beim Code-Erneuern und Sperren von
DogFather UND von sich selbst, darf aber Creator und Scouts verwalten.

3) FOLGEFEHLER DER MASSENERSETZUNG

Die Regel "niemals den letzten aktiven DogFather sperren" hatte durch
die Umstellung auf istLeitung() ploetzlich auch Manager blockiert --
gezaehlt werden aber nur DogFather-Zugaenge. Jetzt istDogFather().
Geprueft: DogFather kann einen Manager sperren, sich selbst nicht.

4) REIHENFOLGE UND ROLLENWAHL

Ueberall DogFather, Manager, Scout, Creator. "ORDER BY rolle" waere
alphabetisch gewesen (admin, creator, manager, scout) -- also fast genau
falsch herum. Jetzt ein gemeinsamer Sortierausdruck aus workspace.js.

Das Auswahlmenue fuer die Rolle ist weg. Es kam als weisses
Windows-Menue mitten in einer dunklen Oberflaeche und schnitt "Creator"
zu "Crea" ab -- gestalten laesst sich ein aufgeklapptes Systemmenue
nicht. Ersetzt durch vier sichtbare Schalter mit Symbol, Farbe je Rolle
und einer Zeile, was die Rolle bedeutet. Bei "Manager" gegen
"DogFather" ist das der Unterschied zwischen Raten und Wissen.

DogFather und Manager stehen dort nur zur Wahl, wenn DogFather selbst
davorsitzt -- ein Knopf, der immer scheitert, gehoert nicht hin.

Nebenbei: Das Namensfeld war auf eine von zwoelf Spalten gequetscht, weil
seine Umgebung keine .feld-Klasse trug. Alle Formulare daraufhin
durchsucht, keine weiteren Faelle.
2026-08-31 11:32:22 +02:00
DogFatherGit 79f0186494 Wissen: Kategorie muss ausdruecklich gewaehlt werden
Filipes PDF ueber TikTok LIVE Studio landete unter "TikTok - Grundlagen
& Funktionen" statt unter "Streaming mit PC". Ursache ist ein Denkfehler
von mir, kein Bedienfehler:

Das Kategoriefeld war mit dem ERSTEN Eintrag der Liste vorbelegt. Wer es
nicht bewusst aendert, merkt nichts -- die Pflichtangabe hat still fuer
ihn entschieden. Eine Vorbelegung, die niemand gewaehlt hat, ist keine
Voreinstellung, sondern ein Fehler mit Ansage.

Jetzt steht dort "- Kategorie waehlen -", und ohne Auswahl geht das
Formular nicht ab (Browser blockt, zusaetzlich eigene Pruefung).
Vorbelegt wird nur noch, wenn man AUS einer Kategorie heraus hochlaedt
-- dann ist es eine informierte Annahme statt einer geratenen.

Ausserdem: zwanzig Eintraege in einer flachen Liste findet man nicht.
Das Feld ist jetzt nach denselben sechs Welten gruppiert wie die
Kacheln auf der Seite (optgroup). Geprueft: alle 20 waehlbar,
"Streaming mit PC" ist dabei.

Nach dem Veroeffentlichen steht in einer gruenen Zeile, WO die Anleitung
gelandet ist -- sonst merkt man einen Irrtum erst, wenn man sie
irgendwann sucht. Die Meldung nutzt dieselbe Zeile wie Fehler, aber
nicht dieselbe Farbe: Eine Erfolgsmeldung in Warnrot liest sich wie ein
Problem.

Bereits hochgeladene PDFs lassen sich ueber "Bearbeiten" umhaengen --
die Datei bleibt dabei unberuehrt.
2026-08-28 13:40:14 +02:00
DogFatherGit 4d7d9b183b Workspace: KI-Vorschlaege in Calls, Start-Check und Report
Nach der Korrektur von CPUQuota (50% -> 200%) ist die KI benutzbar:
nr_throttled steht bei 0 (vorher 1752 von 1801 Zeitfenstern).

Gemessen NACH der Korrektur:
  To-dos aus einem Protokoll : 12,7 s (vorher: Abbruch nach 45 s)
  Website waehrend der Arbeit: 0,063 s -- Basis war 0,068 s

Kein Einfluss auf die Website, wie bei der ersten Messung mit zwei
echten Kernen vorhergesagt.

DREI KNOEPFE, alle nach demselben Muster:

- Calls: "To-dos vorschlagen" liest, was im Protokoll schon steht, und
  fuellt LEERE To-do-Zeilen. Bereits Getipptes wird nie ueberschrieben.
- Start-Check: "Besser formulieren" macht aus einer Notiz einen
  Aufgabentitel. Der einfache Vorschlag (erster Satz der Notiz) bleibt
  daneben bestehen -- er funktioniert auch ohne KI.
- Report: "In Worte fassen" fasst die Zahlen in drei Saetzen zusammen.

IST DIE KI AUS, GIBT ES DEN KNOPF NICHT. Jede Seite fragt beim Laden
einmal nach. Ein Knopf, der immer eine Fehlermeldung bringt, ist
schlimmer als gar kein Knopf.

Die Absicherung steht in EINER Datei (assets/js/ki.js), nicht dreimal.
Der Knopf sagt waehrend der Arbeit "Die KI denkt ..." und der Funke
pulst -- zwoelf Sekunden ohne Rueckmeldung fuehlen sich sonst an wie
ein Fehler.

Optisch bewusst ANDERS als die normalen Knoepfe: gestrichelter Rand
statt geschliffener Kante. Ein KI-Knopf tut nichts Endgueltiges, er
schlaegt vor -- das soll man auf den ersten Blick sehen.

ZWEI VERBESSERUNGEN AUS DEM TEST:

1. Der Bereichsname wurde dem Modell mitgegeben und klebte prompt in
   der Antwort: "LIVE-Struktur auf 18 und 21 Uhr festlegen". Ohne ihn
   kommt eine echte Handlung heraus. Der Befund allein reicht -- er
   steht ja ohnehin im richtigen Bereich. Variable entfernt, kein toter
   Code.

2. Der Report gab dem Modell "ueberfaellig" ohne Umlaut vor und bekam
   es genauso zurueck. Jetzt richtig geschrieben.

Geprueft: Calls 7 s und drei brauchbare To-dos, Start-Check erzeugt
einen Titel, Report drei Saetze, 0 Konsolenfehler.
2026-08-28 13:34:57 +02:00
DogFatherGit 401c8f006c Workspace: Formulare richtig ausgerichtet, PDF-Ablage und Schalter
URSACHE ZUERST: .feld--breit stand in DREI HTML-Dateien (wissen,
scouting, dateien) -- und war NIE im CSS definiert. Das Raster
(auto-fit, minmax(170px)) gab deshalb jedem Feld dieselbe Breite, egal
was drin steht: Der Titel war so schmal wie eine Auswahl, lange
Kategorienamen wurden abgeschnitten ("1. TikTok - Grundla"), und die
Tag-Vorschlaege stapelten sich zu einer halben Seite.

Jetzt zwoelf Spalten statt auto-fit. Damit laesst sich sagen, WIE breit
ein Feld sein soll: Titel, Beschreibung und Kategorie ueber die ganze
Zeile, Stufe/Geraet/Datum zu dritt nebeneinander. Unter 860 px zwei
Spalten, unter 560 px eine. Die Klasse ist zentral definiert, also
wirken die drei betroffenen Seiten sofort mit.

Gemessen danach: Titel/Beschreibung/Kategorie je 1058 px, die drei
kleinen je 342 px, Kategorie nicht mehr abgeschnitten.

PDF-ABLAGE statt nacktem Dateifeld. Der Browser-Knopf war abgeschnitten
("K...") und sah aus wie ein Fremdkoerper. Jetzt eine eigene Flaeche:
Klicken, Ziehen oder Tastatur. Sie markiert sich gruen, sobald eine
Datei drin ist, prueft schon im Browser auf PDF und schlaegt den
Dateinamen als Titel vor, wenn der noch leer ist.

Sie steht bewusst GANZ OBEN: Man laedt etwas hoch und beschreibt DANN,
was es ist -- nicht umgekehrt.

SCHALTER statt Kaestchen fuer "besonders wichtig". Ein Kaestchen von 17
Pixeln ist auf dem Handy kaum zu treffen und sagt nicht, was passiert.
Der Schalter ist gross, zeigt seinen Zustand in Gold (dieselbe Farbe wie
die Marke "Wichtig" spaeter) und erklaert sich in einer Zeile:
"Erscheint zusaetzlich ganz oben unter Neu & wichtig".

Tag-Vorschlaege kompakter: von zehn Zeilen auf zwei.

Geprueft: Handy ohne Ueberlauf, 0 Konsolenfehler, Dateiwahl markiert die
Flaeche und fuellt den Titel, Schalter schaltet.
2026-08-28 13:20:49 +02:00
DogFatherGit 1f217041ae Workspace: hellere Kategoriekacheln + Dateien gezielt an mehrere Personen
ZWEI WUENSCHE VON FILIPE.

1) KACHELN BESSER SICHTBAR

Erster Versuch war zu zaghaft: die Flaeche ging nur von RGB(17,24,37)
auf (27,36,51), der sichtbare Gewinn kam fast nur vom staerkeren Rand.
Nachgemessen an echten Bildpunkten -- Seite liegt bei RGB(5,7,13).
Jetzt RGB(38,49,67), dazu kraeftigerer Rand und hellerer Symbolring.

Der Beschreibungstext stand auf --text-still und lag damit bei 3,6:1 auf
der neuen Flaeche -- zu blass fuer laufenden Text. Jetzt --text-leise,
gemessen 6,2:1.

Leere Kategorien waren mit opacity .55 fast unlesbar. Jetzt .82 -- sie
sollen erkennbar bleiben, nur zurueckhaltender.

2) DATEIEN AN MEHRERE PERSONEN GEZIELT FREIGEBEN

Bisher hatte eine Datei genau EINEN Bereich (creator_id). Damit liess
sie sich nicht zweien geben, ohne sie zweimal hochzuladen.

Neue Tabelle datei_personen (datei_id + person_id). creator_id bleibt
und behaelt seine Bedeutung: Es sagt, zu wessen BEREICH eine Datei
gehoert -- die neue Tabelle sagt, WER sie sehen darf. Zwei verschiedene
Fragen, deshalb zwei Felder.

Auswahl als einzelne Schalter, nicht als <select multiple>: Dort
verliert man mit einem Fehlklick die ganze Auswahl, und auf dem Handy
ist sie kaum bedienbar. Jeder Name ist ein Schalter, der sichtbar an
oder aus ist, eingefaerbt nach Rolle -- man sieht auf einen Blick, ob
eine Datei an Creator, Scouts oder beide geht.

Wer wen auswaehlen darf:
- DogFather jeden aktiven Menschen ausser sich selbst
- ein Scout NUR die Creator, die er betreut -- sonst koennte er sich
  ueber eine Freigabe Zugang zu fremden Bereichen verschaffen
- ein Creator gar niemanden

Jede Id wird beim Speichern erneut gegen die erlaubte Auswahl geprueft.
Geprueft: Sam schickt die Ids 3, 6 und 7 mit (alles Creator, die er
NICHT betreut) -- die Datei landet bei niemandem. Kein Fehler, kein
Zugang: die Ids fallen still durch das Raster.

Weiter geprueft:
- Chef sieht alle drei Testdateien, Luna nur ihre, Sam nur seine,
  Patrick keine
- Creator bekommt 403 beim Aendern von Freigaben
- Freigaben sind an jeder Datei sichtbar ("Sichtbar fuer ..."), auch
  fuer die, die sie nicht aendern duerfen -- niemand soll raten muessen
- Die Auswahl wird nach dem Hochladen geleert, sonst bekaeme die
  naechste Datei stillschweigend dasselbe Publikum
2026-08-28 13:14:11 +02:00
DogFatherGitandClaude Opus 5 c0ac041122 Workspace: Versionsstempel gegen Cloudflares 4-Stunden-Cache
Filipe sah die neue Kachel nicht, obwohl sie live war. Ursache gemessen,
nicht vermutet:

  Node liefert   : Cache-Control: no-cache        (richtig)
  Cloudflare macht: Cache-Control: max-age=14400  (ueberschreibt es)
  cf-cache-status: REVALIDATED, Server: cloudflare

Cloudflares voreingestellte Browser-Cache-Zeit von vier Stunden setzt
sich ueber das no-cache des Servers hinweg -- aber NUR bei JS und CSS.
HTML kommt mit DYNAMIC und no-cache immer frisch durch (geprueft an
/creator.html und /workspace/).

Genau deshalb genuegt ein Stempel in der HTML: neue Seite -> neue
Adresse -> Cloudflare kennt sie nicht -> frische Datei. Keine
Cloudflare-Einstellung noetig, nichts, worauf ich warten muss.

tools/workspace-stempel.mjs setzt den Stempel auf alle 71 Verweise in
13 Dateien. Der Lauf ist wiederholbar: ein vorhandener Stempel wird
ersetzt, nicht angehaengt (geprueft).

Gehoert ab jetzt vor jeden Deploy, der JS oder CSS im Workspace anfasst.
Ich verlasse mich damit nicht mehr aufs Erinnern -- das war der
eigentliche Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-28 13:03:33 +02:00
DogFatherGit 9b2e09be58 Workspace: Wissens-Bibliothek -- 20 Kategorien, Suche, Filter, Pflege
Wichtigster Befund vorab: Es gab noch KEINEN PDF-Bereich. Weder auf der
Website (28 Seiten, keine davon Anleitungen) noch auf dem Server (null
PDFs). Es wurde also nichts umstrukturiert, sondern neu gebaut -- und
damit war die erste Frage nicht "wie sieht es aus", sondern "wie kommen
die PDFs spaeter rein". Eine feste Liste im Code waere nach drei Monaten
unbrauchbar gewesen.

Filipe hat entschieden: eigener Pflegebereich, und alles nur fuer das
Team. Die Bibliothek liegt deshalb komplett im Workspace hinter dem
Login, nicht auf der oeffentlichen Seite.

GLIEDERUNG
Zwanzig Kategorien woertlich nach Vorgabe, gebuendelt in sechs Welten:
TikTok, Streaming einrichten, Bild & Ton, Uebertragung & Aussehen,
Inhalt & Menschen, Hilfe & Schnellstart. Zwanzig gleich aussehende
Kacheln untereinander findet niemand -- gebuendelt sucht man erst die
Welt, und darin stehen nur noch drei bis vier. Jede Welt hat ihre eigene
Farbe, jede Kategorie ihr eigenes Symbol (20 verschiedene, keins
doppelt). Die Kategorietexte sind Filipes Beschreibungen -- sie
beantworten beim Einsortieren die einzige Frage, die man wirklich hat.

Die Gliederung steht im Code, nicht in der Datenbank: Sie ist eine
bewusste Ordnung, keine Nutzdaten.

JEDE PDF HAT GENAU EINE HAUPTKATEGORIE, alles Weitere laeuft ueber Tags
-- so gibt es jede Anleitung nur einmal, sie ist aber ueber mehrere
Begriffe auffindbar. Genau wie gefordert.

SUCHE UND FILTER
Suche ueber Titel, Beschreibung, Tags und Dateiname. Filter nach Stufe
(Einsteiger / Fortgeschritten / Profi), Geraet und Tag. Zwei Details:
- "PC" zeigt auch die Anleitungen, die fuer BEIDE Geraete gelten --
  sonst filtert man sich versehentlich die Haelfte weg.
- Der Tag-Filter sucht mit Kommas drumherum, sonst wuerde "pc" auch bei
  "pc-spiele" anschlagen.
Sobald gesucht oder gefiltert wird, verschwinden die Kacheln und es
erscheinen Treffer. Wer sucht, will nicht erst noch klicken.

Der Zustand steht in der Adresse (?k=obs&tag=...). Damit funktionieren
Zurueck-Taste, Neuladen und Weiterschicken. Eine Kategorie, die man
niemandem verlinken kann, ist keine Seite. Geprueft.

SICHERHEIT
Hochgeladen wird nur, was WIRKLICH eine PDF ist -- geprueft an den
ersten Bytes (%PDF-), nicht an der Dateiendung. Die kann jeder
umbenennen. Geprueft mit einer als .pdf getarnten HTML-Datei mit Skript:
abgewiesen. Nur weil diese Pruefung existiert, darf die Datei ueberhaupt
im Browser angezeigt werden statt bloss heruntergeladen -- und selbst
dann mit strenger CSP und nosniff.

Lesen darf jeder Angemeldete, pflegen nur DogFather. Geprueft: Creator
und Scout bekommen 403 beim Hochladen und sehen keine Bearbeiten-Knoepfe.
Ohne Anmeldung ist auch die Datei selbst nicht erreichbar (401).

Bricht das Anlegen nach dem Schreiben ab, wird die Datei wieder
geloescht -- sonst laege sie fuer immer verwaist auf der Platte.

Beim Bearbeiten wird die Datei bewusst NICHT ersetzt. Wer eine neue
Fassung hat, stellt sie neu ein. So bleibt nachvollziehbar, was wann galt.

Geprueft: 20 Kacheln, 20 verschiedene Symbole, Kategorie oeffnen, Suche,
Tag-Klick, Browser-Zurueck, Handy ohne Ueberlauf, 0 Konsolenfehler.
2026-08-28 12:40:49 +02:00
DogFatherGitandClaude Opus 5 18a8d46a04 Workspace: Betreuungs-Auswahl heisst "DogFather" statt "nur DogFather"
Das "nur" war aus der Bauzeit uebrig, als der Eintrag noch beschrieb,
wer den Creator sieht ("nur das Management"). Als Auswahl neben "Sam"
und "Patrick" gehoert an die Stelle schlicht der Name -- die Liste
beantwortet die Frage "wer ist zustaendig", nicht "wer sieht mit".

Geprueft: Zuordnung setzen, entfernen und wieder setzen funktioniert
unveraendert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-28 12:14:25 +02:00
DogFatherGit 677bcb5653 Workspace: neues Knopf-System "Geschliffen" -- ueberall, eine Stelle
Von Filipe aus drei gerenderten Entwuerfen gewaehlt (A Kante & Glut,
B Geschliffen, C Praegung). Raten hilft hier nicht -- beim Zurueck-Knopf
hat erst der direkte Vergleich zum Ziel gefuehrt.

Aufbau: farbiger Verlaufsrand (padding-box/border-box) und ein feiner
heller Streifen obenauf -- wie eine angeschliffene Kante. Die Farbe sitzt
im Rand und in der Schrift, die Flaeche bleibt dunkel. Beim Zeigen hebt
sich der Knopf einen Pixel an und bekommt einen weichen farbigen Schein
darunter. Die Hauptaktion einer Seite ist zusaetzlich gefuellt.

JEDE AKTION HAT IHRE EIGENE FARBE:
  gruen  passt, erledigt, freigegeben
  amber  ausbaufaehig, wartet
  rot    Handlungsbedarf, loeschen
  blau   speichern
  violett anlegen
  gold   Onboarding -- der einzige Schritt, der eine Person anlegt
  grau   abbrechen, schliessen
  Stufenfarbe fuer den Weiter-Knopf der Scout-Pipeline

DAS IST JETZT DIE EINZIGE STELLE, AN DER KNOEPFE GESTALTET WERDEN.
Vorher standen sie in NEUN Dateien verstreut, und prompt sahen dieselben
Knoepfe auf verschiedenen Seiten verschieden aus. Alle alten
Definitionen sind entfernt; wer einen neuen Knopf braucht, nimmt eine
Farbklasse und schreibt kein CSS. Gilt ab jetzt auch fuer alles, was
noch dazukommt.

Geprueft ueber alle elf Seiten: 172 sichtbare Knoepfe, kein einziger
ungestylt, kein Kontrast unter 4,5:1.

Drei Sachen, die dabei aufgefallen sind:

1. Der neutrale "Abbrechen"-Knopf hatte halbdurchsichtiges Weiss als
   Farbwert -- gemessen 1,1:1 Kontrast, praktisch unlesbar. Neutral hat
   jetzt einen echten Farbwert (#8e9cb0).

2. Die Filter-Knoepfe (Kalender, Dateien, Bereiche) hatten eine eigene
   "gedrueckt"-Regel mit flaechiger Farbe, die den geschliffenen Rand
   ueberschrieb. Sie benutzen jetzt den gefuellten Auftritt des Systems.

3. Der Bearbeiten-Stift auf den Aufgabenkarten war nie ein richtiger
   Knopf, sondern nackter Text ohne Rand -- man sah nicht, dass man
   draufdruecken kann. Jetzt im System, in der kleinsten Groesse.

Der Zurueck-Knopf ("Neon-Kante") bleibt wie er ist -- den hat Filipe
selbst ausgesucht, und er ist ein Navigationselement, keine Aktion.

Messhinweis fuer spaeter: color-mix liefert computed color(srgb ...),
das laesst sich NICHT als Text auslesen. Die erste Messung meldete
faelschlich 1,13:1 fuer 49 Knoepfe. Richtig geht es ueber eine Leinwand
(fillStyle + getImageData).

Alle Toene bewusst gedeckt statt neon, alles respektiert
prefers-reduced-motion.
2026-08-28 12:13:11 +02:00
DogFatherGit 1c3e642f12 Workspace: Rolle "Management" heisst jetzt "DogFather"
Auf Wunsch von Filipe. Betrifft ausschliesslich die Anzeige.

Der Rollenschluessel bleibt "admin". Er steckt in der CHECK-Regel der
Datenbank, in jeder bestehenden Sitzung und in jeder Rechteabfrage --
ihn umzubenennen haette alle drei gebrochen, und bestehende Anmeldungen
waeren ungueltig geworden. Umbenannt wird nur, was man LIEST.

Der Anzeigename steht jetzt an EINER Stelle (ROLLEN_NAME in
workspace.js) und kommt ueber /workspace/api/ich als rolle_name mit.
Stand er in elf Dateien, waere er beim naechsten Mal in zehn davon
geaendert.

Dabei aufgefallen: In der Kopfleiste stand auf JEDER Seite der rohe
Rollenschluessel -- "Chef · admin". Das war schon vorher unschoen, faellt
aber jetzt erst richtig auf. Alle elf Seiten zeigen jetzt "Chef ·
DogFather". Geprueft: kein rohes "admin" mehr in der Oberflaeche.

Geaendert: Rollenkachel und Untertitel auf der Anmeldeseite, Kopfleiste
aller Seiten, Rollentext auf dem Dashboard, Rollenmarken und Auswahl in
der Personenverwaltung, die Betreuungs-Auswahl ("nur DogFather"), der
Hinweis auf der Dateienseite, die Erklaerung zur internen Notiz im
Profil, die Hinweise fuer Scouts ohne Zuteilung -- und vier
Fehlermeldungen vom Server.

Schreibweise "DogFather" wie von Filipe geschrieben; das ist auch auf
der oeffentlichen Website die haeufigste Form (717 von 1216).

In den Code-Kommentaren der Fachmodule heisst die Rolle weiterhin "das
Management". Das bleibt bewusst so -- eine Massenaenderung an vierzig
Kommentaren waere reines Risiko ohne sichtbaren Nutzen. Ein Hinweis an
der ROLLEN_NAME-Zuordnung erklaert den Zusammenhang.
2026-08-28 11:55:05 +02:00
DogFatherGit 55450aa83f Workspace: Start-Check / Erstanalyse -- Onboarding vollstaendig
Letztes unumgesetztes Stueck aus dem Konzept, Seite 5, Block 03. Profil,
Ziele und 90-Tage-Plan gab es schon -- die Erstanalyse dazwischen fehlte.

"Die Betreuung startet strukturiert: Ausgangslage verstehen, Ziele
festlegen und daraus konkrete Arbeitspakete bauen."

Der letzte Halbsatz ist der entscheidende. Ein Check, der mit einer Note
endet, ist eine Beurteilung. Ein Check, der mit Aufgaben endet, ist
Betreuung. Jeder Punkt mit Handlungsbedarf bietet deshalb direkt an,
daraus eine Aufgabe zu machen -- mit dem Befund als Herkunft und
automatisch hoher Prioritaet. Dieselbe Linie wie beim Review ("endet mit
einer Entscheidung") und beim Call ("endet mit To-dos").

Die vier Felder aus dem Deck, mit je vier Punkten: Profil & Auftritt,
LIVE-Struktur, Content-Muster, Community & Modis. Drei Stufen: Passt,
Ausbaufaehig, Handlungsbedarf.

Die Punkte stehen fest im Code, NICHT in der Datenbank. Eine
Erstanalyse, bei der jeder eigene Punkte anlegt, ist keine Erstanalyse
mehr -- man koennte zwei Creator nicht mehr vergleichen, und genau das
ist ihr Zweck.

Sichtbarkeit, bewusst anders als beim Profil:
- LESEN darf auch der Creator selbst. Der Check ist Teil SEINES
  Entwicklungsplans ("jeder Creator bekommt einen eigenen, lebenden
  Entwicklungsplan"), kein Urteil hinter seinem Ruecken. Wer etwas
  festhalten will, das er nicht sehen soll, hat dafuer die interne
  Notiz im Profil -- die bleibt beim Management.
- AENDERN duerfen nur Management und zustaendiger Scout. Es ist eine
  Fremdeinschaetzung; koennte der Creator sie selbst setzen, waere es
  eine Selbsteinschaetzung. Geprueft: Luna bekommt 403 beim Bewerten und
  beim Anlegen einer Aufgabe, sieht aber ihren Check inklusive Notizen.
- Ein nicht zustaendiger Scout bekommt 404, nicht 403.

Kein Speichern-Knopf: Jede Bewertung und jede Notiz wird sofort
gesichert. Eine Erstanalyse geht man im Gespraech durch -- da will
niemand am Ende noch an einen Knopf denken.

Ein leergeraeumter Punkt (keine Bewertung, keine Notiz) wird geloescht
statt als leere Zeile stehen zu bleiben. So sagt der Bestand direkt, wie
weit die Analyse ist.

Zwei neue Hinweise auf dem Dashboard:
- "Creator ohne Start-Check" -- die Sorte Luecke, die sonst niemandem
  auffaellt, weil ja nichts fehlt: es fing nur nie an.
- "Punkt im Start-Check braucht Handlung", sichtbar fuer alle, die den
  Check auch sehen duerfen.

Aus dem Test: Sechzehn dauerhaft offene Notizfelder machten die Seite
7026 px lang. Das Feld erscheint jetzt erst mit der Bewertung -- vorher
hat man ohnehin nichts zu notieren. 2460 px.
2026-08-28 11:51:14 +02:00
DogFatherGit 3a1ab64c26 Workspace: Suche ueber alle Bereiche (Phase 4)
Auf JEDER Seite, nicht auf einer eigenen. kopf.js baut sie selbst in die
Kopfleiste ein -- eine Suche, die man nur auf einer Extraseite findet,
benutzt niemand. Mit "/" oeffnen, mit Esc schliessen.

Durchsucht: Aufgaben, Termine, Calls, Gespraechsprotokolle, Dateien, die
fuenf Betreuungsbereiche, die Scout-Pipeline und die offenen Felder der
Creator-Profile.

Zwei Dinge machen den Unterschied zwischen einer Suche und einer
brauchbaren Suche:

1. SIE DARF NICHTS FINDEN, WAS DIE SEITE VERBERGEN WUERDE.

Eine Suche ist die verlockendste Stelle fuer ein Datenleck: Man tippt
einen Namen und bekommt Treffer aus Bereichen, die man nie oeffnen
duerfte. Jede Quelle wird deshalb mit der Sichtbarkeitsregel ihres
eigenen Moduls abgefragt -- importiert, nicht abgeschrieben.

Die management-internen Profilfelder (admin_notiz, plan_start,
naechster_review) werden GAR NICHT durchsucht, auch nicht fuer das
Management: Ein Treffer daraus taucht sonst spaeter in einer Ansicht
auf, die diese Felder nicht zeigen darf. Wer die Notiz lesen will,
oeffnet das Profil.

Geprueft mit einem eigenen Leck-Test: "GEHEIM" (Inhalt einer internen
Notiz) findet niemand, auch der Chef nicht. Die Lead-Notiz eines Scouts
findet nur er selbst und das Management, nicht der andere Scout.

2. SIE MUSS SAGEN, WO ETWAS STEHT.

Jeder Treffer traegt einen Ausschnitt RUND UM die Fundstelle, nicht die
ersten Zeichen des Feldes -- man sieht sofort, warum etwas gefunden
wurde. Bei Profiltreffern steht dabei, welches Feld getroffen hat, bei
Protokollen ob es unter "Besprochen" oder "Entscheidung" stand. Und
jeder Treffer fuehrt an die Stelle, an der man weiterarbeiten kann.

LIKE-Sonderzeichen werden maskiert. Ohne das waere die Suche nach "100%"
eine Suche nach "100 gefolgt von irgendwas" und "a_b" faende auch "axb"
-- beides falsch und beides faellt erst spaet auf. Geprueft: "100%" und
"a_b" finden genau ihren Eintrag, "axb" findet nichts.

Bewusst kein Volltextindex (FTS5): Die Datenmengen sind klein, und LIKE
braucht keinen zweiten Datenstand, der irgendwann auseinanderlaeuft.

Kleinigkeiten aus dem Test:
- Das Overlay stand auf voller Hoehe, auch bei zwei Treffern -- der
  Schleier ist flex und stand auf dem voreingestellten stretch. Jetzt
  flex-start, das Fenster waechst mit dem Inhalt (417 statt 780 px bei
  drei Treffern).
- Das eingebaute Kreuz von type="search" sass direkt neben dem
  Esc-Knopf: zwei Wege fuer dasselbe, dicht nebeneinander. Entfernt.
- Das CSS liegt in gate.css, nicht in einer Seiten-Datei -- genau der
  Fehler, der bei .knopf-still schon einmal passiert ist.
2026-08-28 11:39:46 +02:00
DogFatherGit 5684ff87f1 Workspace: "Was ist dran" -- erster Baustein der Automationen (Phase 4)
Bis hierher musste man selbst daran denken, in den richtigen Bereich zu
schauen. Das dreht die Uebersicht auf dem Dashboard jetzt um: Das System
sagt, was liegen bleibt.

Drei Regeln, an die sich das haelt:

1. KEINE eigenen Daten. Ein Hinweis ist immer nur eine Sicht auf etwas,
   das ohnehin existiert. Wird die Aufgabe erledigt, verschwindet der
   Hinweis von selbst -- es gibt nichts zu quittieren, nichts zu pflegen
   und nichts, was veralten kann. Genau daran scheitern die meisten
   Erinnerungssysteme.

2. JEDER HINWEIS FUEHRT IRGENDWOHIN. Ein Hinweis ohne Ziel ist nur ein
   schlechtes Gewissen. Jeder traegt deshalb einen Link zu der Stelle,
   an der sich die Sache tatsaechlich erledigen laesst. Geprueft: Ziel
   erreichbar, keine Umleitung.

3. DIESELBE SICHTBARKEIT WIE UEBERALL. Die Regeln werden aus den
   Fachmodulen importiert, nicht abgeschrieben (workspace-aufgaben,
   -kalender, -dateien, -bereiche exportieren sie jetzt). Ein Hinweis
   darf nie etwas verraten, das die zugehoerige Seite verbergen wuerde
   -- sonst waere ausgerechnet die Uebersicht das Leck.

Dreizehn Hinweisarten, in drei Stufen. Nur die oberste ist farbig:
waere alles hervorgehoben, waere nichts hervorgehoben. Liegt nichts an,
verschwindet der ganze Block.

Steht bewusst VOR den Zahlen. Die Zahlen sagen, WIE VIEL anliegt --
diese Liste sagt, WAS zu tun ist.

Steuerungswissen bleibt beim Management: Review-Termine, Creator ohne
zustaendige Person und leere Profile erscheinen weder bei Creator noch
bei Scouts -- genau wie die zugehoerigen Profilfelder. Geprueft mit
einem eigenen Leck-Test ueber alle drei Rollen.

Zwei Hinweise, die es ohne diese Uebersicht gar nicht gaebe:
- Aufgaben, die im Review haengen. Sie warten auf jemanden -- die Sorte
  Stillstand, die niemandem auffaellt, weil nichts ueberfaellig wird.
- Uebergebene Leads, aus denen nie ein Creator wurde. Sonst ist die
  Uebergabe eine Sackgasse, die niemand bemerkt.

Nebenbei: Der Fusstext auf dem Dashboard stammte noch vom ersten Tag
("Die Bereiche werden nach dem Phasenplan gebaut") -- inzwischen sind
Phase 1 bis 3 fertig. Ersetzt durch eine Erklaerung, wie die Uebersicht
funktioniert.
2026-08-28 11:23:07 +02:00
DogFatherGit fa8fbab410 Workspace: Scouts betreuen Creator wie das Management
Bisher hatten Scouts mit der Creator-Betreuung nichts zu tun -- keine
Profile, keine Betreuungsbereiche, keine Reports. Das aendert sich, mit
zwei bewusst gesetzten Grenzen.

GRENZE 1: nur zugeteilte Creator, keine Rollenregel.

Neue Tabelle betreuung (creator_id PRIMARY KEY -> betreuer_id). Ein
Creator hat genau EINE zustaendige Person, damit nie unklar ist, wer
gefragt ist. Das Management sieht ohnehin alle und braucht keinen
Eintrag. Wer nichts zugeteilt bekommt, sieht weiterhin nichts -- kein
Recht entsteht automatisch aus der Rolle.

Zugeteilt wird in "Personen & Zugaenge", direkt in der Personenzeile:
Betreuung ist eine Eigenschaft der Person, kein eigener Vorgang. Nur das
Management darf zuteilen -- koennte ein Scout sich selbst Creator geben,
haette er die Rechtevergabe in der Hand, die ihn begrenzen soll.
Zustaendig koennen nur aktive Scouts sein, kein Admin (der sieht alles)
und kein anderer Creator.

Bei der Uebergabe aus der Pipeline passiert die Zuteilung von selbst:
Wer jemanden gefunden hat, betreut ihn weiter. Genau darum geht es bei
"Creator-Onboarding starten". Umhaengen kann das Management jederzeit.

GRENZE 2: betreuen, nicht verwalten.

Profile, die fuenf Bereiche und Reports wie ein Manager. ABER:
- keine Zugangscodes, kein Sperren von Personen (personen.html bleibt
  admin-only, unveraendert)
- keine management-internen Felder. Der Scout bekommt admin_notiz,
  plan_start und naechster_review NICHT -- die Felder fehlen in der
  Antwort komplett, nicht nur in der Anzeige. Eine Notiz UEBER die
  Betreuung gehoert nicht in die Hand dessen, der betreut. Geprueft: Ein
  Scout, der admin_notiz mitschickt, aendert sie nicht.

Die Regel steht an EINER Stelle (betreuteIds / betreutWo / darfCreator
in workspace.js) und wird von sechs Modulen benutzt. Eine Rechteregel,
die an sechs Stellen steht, ist eine Rechteregel, die irgendwann an
fuenf Stellen stimmt.

Genau das ist beim Bauen auch passiert: workspace-calls.js hatte eine
wortgleiche Kopie der Kalender-Sichtbarkeit. Erweitert wurde nur der
Kalender -- Scouts sahen die Termine ihrer Creator, dieselben Termine
als Call aber nicht. Die Kopie ist jetzt weg, calls.js importiert die
Regel aus workspace-kalender.js.

Zwei Fehler, die die Aenderung selbst erzeugt haette, vorher gefunden:
- Report-Entscheidung: ein Scout haette eine Aufgabe angelegt, deren
  "Creator" er selbst ist -- die waere in jeder Auswertung falsch
  mitgelaufen. Zeigt jetzt auf einen seiner Creator.
- Bereichseintrag: derselbe Fehler. Ein Scout hat gar keinen eigenen
  Betreuungsbereich. Ein Eintrag ohne oder mit fremder Zuordnung landet
  beim ersten zugeteilten Creator, nie bei einem fremden. Geprueft:
  Mikas Bereich bleibt bei jedem Versuch unberuehrt.
2026-08-28 11:18:56 +02:00
DogFatherGit 45cd0ae226 Workspace: Calls & Meeting-Protokolle -- Phase 3 vollstaendig
/workspace/calls.html.

Calls sind KEINE eigene Terminart neben dem Kalender, sondern dieselben
Termine mit art = 'call' oder 'review'. Ein zweiter Terminspeicher waere
die sichere Art, irgendwann zwei widerspruechliche Uhrzeiten zu haben.
Diese Seite fuegt nur hinzu, was ein Gespraech vom blossen Termin
unterscheidet: das Protokoll danach. Die Sichtbarkeitsregel ist Wort fuer
Wort dieselbe wie im Kalender -- ein Termin darf nicht in der einen
Ansicht auftauchen und in der anderen fehlen.

Der tragende Satz von Seite 13, woertlich genommen:
"Jeder Call endet mit klaren To-dos, die direkt ins Board uebernommen
werden."

To-dos werden deshalb NICHT als Text im Protokoll abgelegt, sondern
sofort zu echten Aufgaben -- mit dem Gespraech als Herkunft in der
Beschreibung, zugeordnet an das Gegenueber des Calls. Sonst steht die
Verabredung in einem Dokument, das niemand mehr oeffnet. Geprueft:
Protokoll geschrieben -> Aufgaben stehen im Brett.

Weitere Punkte:

- Reihenfolge der Gruppen ist Dringlichkeit, nicht Chronologie: Ganz oben
  stehen vergangene Gespraeche OHNE Protokoll. Das ist der einzige
  Zustand, der etwas von einem verlangt. Nur diese Gruppe ist optisch
  hervorgehoben; wenn alles schreit, sieht man nichts mehr.
- Ein festgehaltenes Protokoll ist danach nur noch lesbar. Ein Gespraech
  nachtraeglich umschreiben zu koennen waere genau das, was ein Protokoll
  wertlos macht.
- "Naechster Termin" legt den Folgetermin direkt in den Kalender -- mit
  demselben Gegenueber und demselben Meeting-Link.
- Alles in EINER Transaktion. Geprueft mit einem absichtlich kaputten
  To-do: kein Protokoll, keine halben Aufgaben, kein Folgetermin.
- Enter im To-do-Feld legt die naechste Zeile an, damit man eine Liste
  tippen kann, ohne zur Maus zu greifen.
- Meeting-Link nur bei anstehenden Gespraechen und nur, wenn es wirklich
  eine http(s)-Adresse ist. "bei mir zu Hause" bleibt schlichter Text.

Zur Videotechnik selbst bewusst KEINE Entscheidung getroffen: Ein eigener
WebRTC-Raum braucht einen TURN-Server, damit Verbindungen hinter
Mobilfunk-NAT zustande kommen. Das ist eine Infrastrukturfrage mit
laufenden Kosten und gehoert besprochen, nicht nebenbei entschieden.
Bis dahin traegt der Termin einfach den Link des Dienstes, der ohnehin
benutzt wird.

Nebenbei: .knopf-still lag in scouting.css und fehlte dadurch auf
calls.html -- dort standen prompt nackte Systemknoepfe. Der Baustein
gehoert ins gemeinsame start.css, dort liegt er jetzt.
2026-08-28 11:06:37 +02:00
DogFatherGit d845d91d70 Workspace: Scout-CRM -- Pipeline, Follow-ups und Uebergabe
/workspace/scouting.html. Erster Baustein aus Phase 3 und der Bereich,
in dem Scouts bisher praktisch nichts hatten.

Der Merksatz von Seite 15 ist hier die Sicherheitsregel, nicht nur eine
Beschreibung: "Scouts sehen ihre Pipeline -- die Admin-Rolle die
Gesamtuebersicht -- Creator keine Scout-internen Daten."

- Creator bekommen 404, nicht 403, und zwar auf Schnittstelle UND Seite.
  Sie sollen nicht einmal erfahren, dass es den Bereich gibt.
- Ein Scout sieht ausschliesslich die eigene Pipeline. Geprueft: Patrick
  bekommt auf Sams Lead 404 beim Lesen, Aendern und Loeschen.
- Das Management sieht alles, kann nach Scout filtern und Leads einem
  Scout zuordnen.

Pipeline als gruppierte Liste, nicht als Board: Sechs Spalten waeren auf
dem Handy unbedienbar, und Scouts arbeiten unterwegs. Jede Stufe traegt
eine eigene Farbe an der linken Kante, die von kuehl (neu entdeckt) nach
gruen (uebergeben) laeuft -- die Richtung der Pipeline wird sichtbar,
ohne Ampel-Geblinke.

Jede Karte hat genau EINEN naheliegenden Schritt ("Weiter zu ..."), der
Rest steckt im aufklappbaren Teil. Der Weiter-Knopf traegt bewusst nur
die Farbe seiner Stufe statt des vollen Farbverlaufs, sonst waere die
Seite ein Streifenmuster aus identischen Leuchtbalken.

Faellige Follow-ups stehen als eigene Leiste ganz oben. Das ist der
Teil, der ohne System am ehesten untergeht -- nicht der Kontakt selbst,
sondern das Nachfassen.

Uebergabe ("Creator-Onboarding starten", Seite 15): Aus einem
uebergebenen Lead legt das Management mit einem Klick eine echte Person
mit Zugangscode an. Der Code wird genau einmal angezeigt, wie in der
Personenverwaltung. Die Qualifizierung des Scouts (Plattform, Handle,
Potenzial, LIVE-Aktivitaet) wandert dabei automatisch ins Creator-Profil
-- sonst muesste das Management abtippen, was laengst dasteht. Geprueft:
Lead -> Person -> Profil, alle drei verbunden, zweiter Versuch wird
abgelehnt.

Ein uebergebener Lead ist Teil der Betreuungsgeschichte -- den loescht
nur das Management, nicht der Scout (403).

Nebenbei: .knopf-still gab es im Baukasten noch gar nicht, die Zweit-
knoepfe waren nackte Systemknoepfe. Jetzt sauber definiert.
2026-08-28 10:57:42 +02:00
DogFatherGit 072ded20a2 Workspace: Reports & Review -- Phase 2 vollstaendig
/workspace/report.html. Fuehrt bewusst KEINE eigenen Eintraege, sondern
fasst zusammen, was in Aufgaben, Bereichen, Terminen und Dateien schon
steht: "Fortschritt wird nicht gefuehlt, sondern nachvollziehbar
gemacht".

Die vier Abschnitte sind woertlich die Fragen aus dem Deck, Seite 16:
Was wurde erledigt? Was blockiert? Was hat funktioniert? Was kommt als
Naechstes?

Zwei Punkte daraus sind ernst genommen:

1. "Vorher / nachher" (Historie). Jede Zahl wird mit demselben,
   unmittelbar davorliegenden Zeitraum verglichen. Eine Zahl allein sagt
   wenig -- 3 erledigte Aufgaben sind gut oder schlecht, je nachdem ob es
   vorher 1 oder 9 waren. Bei Zahlen, wo mehr SCHLECHTER ist (offene
   Probleme), ist die Trendfarbe umgedreht.

2. "Jeder Review endet mit einer Entscheidung, nicht nur mit einer
   Zusammenfassung." Der Report legt deshalb direkt eine Aufgabe an --
   ohne Seitenwechsel, mit hoher Prioritaet und optionaler Frist.
   Geprueft: Eintrag im Report -> Aufgabe erscheint im Brett.

"Was blockiert?" zeigt zusaetzlich die drei am laengsten offenen
Aufgaben mit Namen, nicht nur eine Zahl.

Sichtbarkeit:
- Scout: 404, sowohl Schnittstelle als auch Seite (leitet weg)
- Creator: sieht nur sich. Geprueft -- Luna fordert ?creator=3 (Mika) an
  und bekommt einen Report ueber SICH, der Parameter wird fuer
  Nicht-Management ignoriert
- Der Review-Termin aus dem Profil ist Steuerungswissen und wird einem
  Creator auch hier nicht mitgeschickt, genau wie im Profil selbst

Damit ist Phase 2 aus dem Konzept vollstaendig.
2026-08-28 09:48:03 +02:00
DogFatherGit df9f87af0a Workspace: Phase 2 -- LIVE, Content, Technik, Community, Schutz
Fuenf Bereiche auf einmal, aber NICHT fuenf Module. Im Deck haben sie
dieselbe Grundform: Eintraege zu einem Creator mit Art, Datum, Titel,
Text und Status. Sie unterscheiden sich nur darin, welche Arten es gibt
und ob eine Bewertung oder eine Dringlichkeit dazugehoert.

Deshalb ein gemeinsamer Unterbau: eine Tabelle, eine Sichtbarkeitsregel,
eine Pruefung, eine Ansichtsseite (bereich.html?b=live). Ein Fehler
laesst sich damit an EINER Stelle beheben statt an fuenf, und ein
weiterer Bereich waere ein Eintrag in BEREICHE -- kein neues Modul.

Arten woertlich aus dem Deck (Seiten 7-12):
  live       Vorbereitung / Waehrend LIVE / Auswertung   + Bewertung 1-5
  content    Idee / Produktion / Veroeffentlicht
  technik    Setup / Problem / Loesung / Anleitung       + Dringlichkeit
  community  Moderation / Aktion / Konflikt              + Dringlichkeit
  schutz     Richtlinie / Vorfall / Eskalation / Gelernt + Dringlichkeit

Die Oberflaeche kennt die Bereiche nicht auswendig -- welche Arten und
Zusatzfelder es gibt, sagt der Server in der Antwort.

Geprueft, und zwar fuer alle fuenf gleichzeitig:
- Sichtbarkeit: Chef sieht alles, Luna nur ihren Bereich, Mika nur
  seinen, Sam (Scout) gar nichts (404 -- Scouts haben mit der
  Creator-Betreuung nichts zu tun)
- Luna legt Eintrag mit creator_id=Mika an: landet still in ihrem
  eigenen Bereich, Mika sieht ihn nicht
- Luna auf Mikas Eintrag: 404; Luna loescht Chefs Eintrag ueber ihren
  Bereich: 403 (loeschen darf das Management und wer ihn schrieb --
  sonst koennte ein Creator eine Notiz ueber sich verschwinden lassen)
- Eintrag ueber den falschen Bereich in der Adresse ansprechen: 404
- unbekannte Art 400, Bewertung 9 (erlaubt 1-5) 400, unbekannter
  Bereich 404, fremde Herkunft 403

Beim Testen sahen Umlaute zunaechst zerstoert aus (efbfbd, das
Unicode-Ersatzzeichen). Ursache war der curl-Aufruf: Git Bash kodiert
$'\xc3\xbc' nach Locale um. Ueber den echten Weg (Browser) kommen
Umlaute, ss und Gedankenstrich unveraendert an und liegen sauber in der
Datenbank -- gegengeprueft auf Byte-Ebene.
2026-08-28 09:19:39 +02:00
DogFatherGit 05331e038a Anmeldung: Scout vor Creator, Krone fuers Management
Wunsch vom 28.08.2026: "scout soll ueber creator sein" und "das
schutzschild symbol soll bei scout sein und bei management soll eine
krone sein".

Neue Reihenfolge: Management, Scout, Creator.

Symbole:
  Management  Krone   (Gesamtuebersicht und Freigaben)
  Scout       Schild  (schirmt die Pipeline ab und prueft, bevor etwas
                       weitergereicht wird -- passt dort besser als beim
                       Management)
  Creator     Person  (unveraendert)

Die Tastaturbedienung folgt automatisch der neuen Reihenfolge, weil die
Pfeiltasten die Kacheln in Dokumentreihenfolge durchlaufen. Geprueft:
ab Management fuehrt Pfeil-runter zu Scout, dann zu Creator.

Nur eine statische Datei, kein Neustart noetig.
2026-08-28 01:27:46 +02:00
DogFatherGit 516a003dc8 Dateien: Hochladen nur fuer Management und Scouts
Wunsch vom 28.08.2026: "die dateien sollen nur die manager oder scout
hochladen koennen aber nicht die creator."

Serverseitig ueber DARF_HOCHLADEN. Die Pruefung steht bewusst VOR
express.raw -- wer nicht darf, wird abgewiesen, bevor auch nur ein Byte
entgegengenommen wird. Sonst wanderten bis zu 25 MB durch die Leitung,
nur um danach verworfen zu werden.

Ein Creator sieht und oeffnet weiterhin die Dateien seines Bereichs.
Statt des Ablegefeldes steht dort jetzt, warum es fehlt -- ein einfach
verschwundenes Feld wirkt wie ein Fehler.

Geprueft: Management 201, Scout 201, Creator 403 mit klarer Meldung;
Creator sieht und laedt weiterhin.

--------------------------------------------------------------------
Dabei ein Fehler aufgefallen, der mehrere Seiten betraf:

Das hidden-Attribut blendet nur ueber eine sehr schwache Browserregel
aus -- JEDE eigene display-Angabe schlaegt sie. Betroffen waren:
  * das Ablegefeld fuer Dateien (display: grid) -> ein Creator sah es
    trotz hidden weiterhin
  * die Verwaltungsfelder "Plan-Start" und "Naechster Review" im
    Creator-Profil (ebenfalls grid) -> ein Creator sah sie ebenfalls
  * der Zurueck-Knopf (inline-flex) -> waere vor dem Laden des Skripts
    kurz sichtbar gewesen

Behoben mit einer Regel in gate.css: [hidden] { display: none !important }

Beim Profil waren nie Daten betroffen -- der Server schickt die Felder
an einen Creator gar nicht erst mit, sie waren leer. Sichtbar sein
sollten sie trotzdem nicht.

Aufgefallen ist es erst im Screenshot. Der vorige Test hatte auf das
hidden-ATTRIBUT geprueft, und das war ja gesetzt. Die Pruefung schaut
jetzt auf die tatsaechliche Sichtbarkeit (isVisible).

Ausserdem: In der Regex zum Saeubern von Dateinamen standen die
Steuerzeichen als rohe Bytes statt als Escape-Sequenz. Die Funktion
arbeitete korrekt, aber die Datei galt dadurch als binaer -- grep
verweigerte sie, und Editoren haetten sie zerstoeren koennen. Jetzt
steht dort \x00-\x1f als Text.
2026-08-28 01:25:53 +02:00
DogFatherGit 81b51ab94f Workspace: Dateiablage mit Freigabe-Ablauf (Phase 1 vollstaendig)
/workspace/dateien.html -- Ablegen per Ziehen oder Auswaehlen,
Entwurf -> Review -> Freigabe, Filter je Zustand.

OHNE NEUE ABHAENGIGKEIT. Uploads laufen ueblicherweise ueber multer.
Hier schickt der Browser die Datei roh im Rumpf, der Name steht im Kopf
(URI-kodiert, damit Umlaute heil ankommen). express.raw() bringt den
passenden Empfaenger schon mit -- kein Zerlegen von multipart/form-data
von Hand, was gerade hier heikel waere.

Die drei Punkte, an denen Dateiablagen typischerweise scheitern:

1. Die Dateien liegen AUSSERHALB des Repos (workspace-daten/dateien/).
   Lagen sie darin, wuerde express.static sie ungeprueft ans Netz geben.
2. Auf der Platte traegt jede Datei einen erzeugten Zufallsnamen, der
   Originalname steht nur in der Datenbank. Geprueft mit dem Dateinamen
   "../../etc/passwd": gespeichert wurde "passwd", auf der Platte ein
   Zufallsname IM Ordner -- nichts ist ausgebrochen.
3. Ausgeliefert wird immer als Download mit neutralem Typ, dazu
   nosniff und CSP sandbox. Geprueft mit einer hochgeladenen
   boese.html: kommt als application/octet-stream zurueck, kann also
   keinen Code im Namen der Domain ausfuehren.

Freigabe nach Konzept: Der Zustand "freigegeben" ist eine Abnahme und
bleibt dem Management vorbehalten. Geprueft -- Luna kann Entwurf ->
Review, aber nicht freigeben (403); eine freigegebene Datei kann sie
weder aendern noch loeschen.

Sichtbarkeit wie ueberall: Chef 2 Dateien, Luna 1, Mika 0. Zugriff auf
eine fremde Datei: 404, nicht 403.

Ein Fehler beim Testen gefunden: Bei zu grosser Datei brach express.raw
ab, BEVOR der eigene Code lief -- der Fehler landete im allgemeinen
Behandler als HTTP 500. Fuer die Nutzerin sah das aus wie ein kaputter
Server statt wie "Datei zu gross". Jetzt faengt ein eigener
Fehlerbehandler am Ende des Routers das ab und antwortet mit 413 und
einer verstaendlichen Meldung.

Damit ist Phase 1 aus dem Konzept vollstaendig.
2026-08-28 01:14:00 +02:00
DogFatherGit 713297967f Workspace: Zurueck-Knopf im Entwurf "Neon-Kante"
Der vorige Knopf war zu generisch -- eine dunkle Pille mit Rand, wie sie
in jedem Baukasten steckt. Statt weiter zu raten wurden drei Entwuerfe
gebaut und zur Auswahl gestellt (Glas-Kapsel, Neon-Kante, aufklappender
Kreis). Gewaehlt: Neon-Kante.

Der senkrechte Lichtstrich in Cyan-Violett ist dasselbe Motiv wie die
Kante der Anmelde-Tafel (.tafel__kante in gate.css). Dadurch wirkt der
Workspace wie ein Stueck und nicht wie zusammengesetzte Teile.

Details:
- links flache Kante (die gehoert dem Lichtstrich), rechts rund
- der Strich ruht etwas kuerzer als der Knopf und waechst beim
  Ueberfahren auf volle Hoehe -- die Bewegung ersetzt jedes Aufblitzen
- der Pfeil rueckt drei Pixel nach links und sagt so die Richtung
- bei prefers-reduced-motion faellt alle Bewegung weg
- eigener Fokusring fuer die Tastaturbedienung

Die drei Entwuerfe liegen als eigenstaendige Seite unter entwurf/ im
Arbeitsordner (nicht im Repo), falls spaeter nochmal verglichen werden
soll.

Nur CSS, kein Neustart noetig.
2026-08-28 01:02:15 +02:00
DogFatherGit f8faab34a5 Workspace: versehentlich in den CSS-Ordner kopiertes kopf.js entfernt
Eine verunglueckte Kopierzeile hatte assets/js/kopf.js zusaetzlich nach
assets/css/ gelegt. Die Datei war nirgends eingebunden, aber ueber das
Netz erreichbar und haette bei spaeteren Aenderungen fuer Verwirrung
gesorgt, welche der beiden die echte ist.
2026-08-28 00:40:34 +02:00
DogFatherGit d3212a3f60 Workspace: Zurueck-Knopf hochwertiger, auf der Startseite entfernt
Zwei Rueckmeldungen umgesetzt.

1. Auf der Startseite gibt es den Knopf jetzt gar nicht mehr im
   Dokument. Vorher erschien er dort, sobald man von einer anderen
   Workspace-Seite kam -- aber die Startseite IST die oberste Ebene, ein
   "davor" gibt es nicht.

2. Aussehen: statt des Textzeichens "<-" jetzt ein echtes SVG-Winkel-
   symbol, Pillenform, und ein Verlaufsrahmen.

   Wichtig dabei: Die Fuellung ist DECKEND. Beim ersten Versuch war sie
   halbtransparent, dadurch schien der Rahmenverlauf durch die ganze
   Flaeche und der Knopf sah aus wie eine Hauptaktion -- genau das soll
   er nicht. Jetzt bleibt vom Verlauf nur der 1px schmale Rand sichtbar.

   Ruhezustand: dunkle Pille, feine Stahlkante, gedaempfter Text.
   Ueberfahren: Cyan-Violett-Rand, heller Text, weicher Schein, und der
   Pfeil rueckt zwei Pixel nach links -- die Bewegung sagt die Richtung
   ohne zusaetzlichen Text. Bei prefers-reduced-motion faellt sie weg.

Geprueft: Start -> kein Knopf; Aufgaben -> "Zurueck", fuehrt zurueck;
Personen direkt aufgerufen -> "Uebersicht". Keine Konsolenfehler.

Nur statische Dateien, kein Neustart noetig.
2026-08-28 00:40:19 +02:00
DogFatherGit 75d05d05d2 Workspace: Zurueck-Knopf auf allen Seiten
Wunsch: "ich will auch immer bei jeder seite auch immer einen knopf
haben damit ich zurueck gehen kann auf die seite vorher."

Neues gemeinsames Modul assets/js/kopf.js. Blindes history.back() reicht
dafuer nicht: Wer die Adresse direkt eingibt oder gerade von der
Anmeldung kommt, landet damit ausserhalb des Workspace oder wieder im
Anmeldeformular. Deshalb wird zuerst geprueft, woher der Aufruf kam:

  * vorherige Seite im Workspace  -> "Zurueck", history.back()
    (fuehrt wirklich dorthin zurueck, samt Bildlaufposition)
  * kein Verlauf, aber Unterseite -> "Uebersicht", geht zur Startseite
  * kein Verlauf auf der Startseite -> Knopf bleibt verborgen
    Ein Knopf, der nichts tut, ist schlimmer als keiner.

Der Knopf sitzt links in der Kopfleiste, an derselben Stelle wie im
Browser.

Nebenbei aufgeraeumt: Das Abmelden stand bisher in jeder der fuenf
Seitendateien noch einmal -- fuenfmal derselbe Block, fuenfmal eine
Stelle zum Vergessen. Liegt jetzt ebenfalls in kopf.js.

Geprueft: Start nach Login -> verborgen; Aufgaben von Start ->
"Zurueck", fuehrt zurueck; Kalender direkt aufgerufen -> "Uebersicht".
Keine Konsolenfehler, Abmelden funktioniert weiterhin.

Nur statische Dateien, kein Neustart noetig.
2026-08-28 00:35:26 +02:00
DogFatherGit ef79659f8f Workspace: Kalender mit Terminen, Calls und Aufgaben-Fristen
/workspace/kalender.html -- letzter grosser Baustein aus Phase 1.

Zeigt zwei Quellen in EINER Ansicht, wie im Konzept gefordert
("Kalender & Calls" neben "Deadlines" und "Wiedervorlagen"):
  * eigene Termine (Arten: Call, Termin, Review)
  * Fristen offener Aufgaben, nur lesend eingeblendet

Nach Tagen gruppiert statt als Monatsraster: Es geht um wenige, dafuer
konkrete Termine. Eine Liste liest sich dabei besser und funktioniert auf
dem Handy ohne Umbau. Zeitraum umschaltbar: 14 / 30 / 90 Tage, wobei 90
den 90-Tage-Plan aus dem Konzept abdeckt.

Sichtbarkeit wie bei den Aufgaben, wieder an einer Stelle definiert.
Geprueft mit drei Konten:
  Chef 2 Termine + 2 Fristen | Luna 2 + 1 | Sam 0 + 1
Die Fristen folgen dabei exakt der Aufgaben-Regel -- Sam sieht nur seine.

Loeschen darf das Management und wer den Termin selbst angelegt hat.
Sonst koennte ein Creator einen Call absagen, den das Management
angesetzt hat. Geprueft: Luna auf Chefs Call 403, auf ihren eigenen 200,
Sam sieht ihn gar nicht (404).

Weiteres:
- Ort/Link wird nur dann als Verweis dargestellt, wenn er wirklich mit
  http(s) beginnt -- sonst liesse sich javascript: einschleusen
- Zeitpunkt und Dauer werden geprueft (kaputtes Datum 400,
  5000 Minuten 400)
- Beginn steht als lokale Zeit ohne Zeitzone: Alle Beteiligten sitzen in
  derselben, eine falsch umgerechnete Uhrzeit waere schlimmer als gar
  keine Umrechnung
2026-08-28 00:24:12 +02:00
DogFatherGit a378b126fe Workspace: Auswahllisten und Kalender in dunkler Darstellung
Die aufgeklappte Liste eines <select> zeichnet der Browser selbst, CSS
erreicht sie nicht. Ohne Hinweis geht er von einer hellen Seite aus und
malt sie weiss -- die helle Schrift darauf war praktisch unlesbar
(gemeldet mit Screenshot).

Behebung ueber color-scheme: dark auf <html>. Das ist der Schalter fuer
alles, was der Browser selbst zeichnet: Auswahllisten, Datumskalender,
Bildlaufleisten, Textmarkierung. Zusaetzlich sind Hintergrund und
Schriftfarbe an <option> gesetzt, weil aeltere Browser und manche
Linux-Oberflaechen color-scheme nur teilweise beachten.

Damit entfallen die beiden filter: invert(.75) am Kalendersymbol der
Datumsfelder -- der Browser zeichnet es jetzt schon hell, invert haette
es wieder verdunkelt.

Nur statische Dateien, kein Neustart noetig.
2026-08-28 00:20:10 +02:00
DogFatherGit 8bfd2ae166 Workspace: Creator-Profile (Onboarding aus dem Konzept)
/workspace/profil.html -- Stammdaten, Ziele und 90-Tage-Plan, genau nach
Seite 5 des Konzepts. Management waehlt oben den Creator aus, ein Creator
sieht nur sein eigenes Profil.

Sicherheitskern ist das Feld admin_notiz. Das Konzept fordert "private
Admin-Notizen separat". Die Notiz wird deshalb nicht im Browser
ausgeblendet, sondern gar nicht erst gesendet: Die Spaltenliste der
Abfrage haengt an der Rolle (FELDER_OFFEN / FELDER_ADMIN). Dasselbe gilt
fuer Plan-Start und Review-Termin.

Geprueft:
- In der kompletten Rohantwort an den Creator kommt der Inhalt der
  internen Notiz 0-mal vor
- Creator auf fremdes Profil: 404 (lesend wie schreibend)
- Scout auf ein Profil: 404, profil.html leitet ihn weg
- Creator setzt admin_notiz selbst: wird stillschweigend ignoriert,
  der Inhalt bleibt unveraendert
- Profil einer Nicht-Creator-Person: 404

Dabei ist ein aelterer Fehler aufgefallen: /api/ich lieferte nur Name und
Rolle, nicht die eigene Nummer. Dadurch rief die Profilseite eines
Creators /api/profil/undefined auf und blieb leer. Derselbe Fehler machte
in der Personenverwaltung den Selbstvergleich unwirksam -- beim eigenen
Eintrag erschien ein "Sperren"-Knopf, den der Server dann ablehnte.
/api/ich liefert jetzt zusaetzlich die id.

Im Protokoll landen nur die Feldnamen, nie die Inhalte: Im Profil stehen
persoenliche Angaben, die nicht zusaetzlich im Audit-Log auftauchen
sollen.
2026-08-28 00:17:53 +02:00
DogFatherGit 232a2003dd Workspace: Aufgaben bearbeiten, Personenverwaltung im Browser
Aufgaben:
- Bearbeiten-Dialog (Titel, Beschreibung, Prioritaet, Frist, Zuordnung).
  Als natives <dialog>: Fokusfang, Esc zum Schliessen und Abdunklung
  ohne eigenen Code.
- Loeschen nur fuer Management, mit Rueckfrage und Protokolleintrag.
  Das Konzept will, dass Erledigtes stehen bleibt -- Loeschen ist der
  Ausnahmefall fuer Fehleintraege, nicht der normale Abschluss.

Personen (/workspace/personen.html, nur Management):
- Anlegen, Code erneuern, sperren/entsperren, Protokollansicht
- Der Code wird genau einmal in der Antwort zurueckgegeben, nie
  gespeichert; beim Schliessen auch aus dem Dokument entfernt
- Selbstschutz: niemand kann sich selbst sperren, und das letzte aktive
  Management laesst sich nicht sperren -- sonst kaeme niemand mehr hinein
- Code fuer sich selbst tauschen nur mit ausdruecklicher Bestaetigung,
  weil es die eigene Sitzung sofort beendet

Zwei Fehler, die beim Testen aufgefallen sind:

1. Rollenpruefung fehlte beim Ausliefern der Seiten. Ein Creator bekam
   personen.html mit HTTP 200 -- die Schnittstellen wiesen ihn zwar ab,
   das Geruest der Seite war aber sichtbar. GESCHUETZT ist jetzt eine
   Zuordnung Pfad -> erlaubte Rollen statt einer blossen Liste.

2. Das Protokoll nannte den falschen Verursacher. personAnlegen trug die
   NEU ANGELEGTE Person als person_id ein, der Eintrag las sich also so,
   als haette sie sich selbst angelegt. Akteur und Betroffener sind jetzt
   getrennt: Akteur in person_id, Betroffener im Text. Ueber die
   Kommandozeile angelegte Personen zeigen korrekt keinen Akteur.
2026-08-27 23:12:28 +02:00
DogFatherGit 2eecb40537 Workspace: Aufgabenbrett und Dashboard-Zahlen
Erster echter Arbeitsbereich aus dem Konzept. Kanban mit offen / in
Arbeit / Review / erledigt, dazu Prioritaet, Frist, Verantwortlicher und
Zuordnung zu einem Creator-Bereich.

Kern ist die Datentrennung, und die sitzt AUSSCHLIESSLICH im Server --
in jeder einzelnen Abfrage, an einer Stelle definiert (sichtbar()):
  admin   sieht alles
  creator sieht seinen Bereich und was ihm zugewiesen ist
  scout   sieht nur, was ihm zugewiesen ist

Geprueft mit vier Testkonten:
- Chef sieht 4, Luna 2, Mika 1, Sam 1 Aufgaben
- Luna auf Mikas Aufgabe: 404 (nicht 403 -- sonst liesse sich durch
  Ausprobieren herausfinden, welche Nummern es gibt)
- Luna legt Aufgabe mit creator_id=Mika an: wird still auf ihren eigenen
  Bereich umgebogen, Mika sieht sie nicht
- Anfrage mit fremdem Origin: 403
- ohne Anmeldung: 401, ungueltiger Status/leerer Titel: 400
- Scout bekommt in der Personenliste nur sich selbst
- Dashboard-Zahlen je Rolle korrekt eingegrenzt

Weitere Punkte:
- Texte werden im Browser nur ueber textContent gesetzt, nie innerHTML --
  ein Aufgabentitel darf keine Auszeichnung einschleusen
- ueberfaellig = Frist vorbei UND nicht erledigt; die Kachel faerbt sich
  nur, wenn wirklich etwas ansteht
- erledigt_am wird gesetzt bzw. wieder geleert, wenn eine Aufgabe
  zurueckgeholt wird
- Erledigtes verschwindet nicht, wie im Konzept gefordert
2026-08-27 23:00:17 +02:00
DogFatherGit 6d9bad880c Workspace: echte Besucher-IP statt Cloudflare-Adresse
Gefunden beim Nachsehen im Protokoll nach der ersten echten Anmeldung:
Jeder Eintrag trug dieselbe IP 172.69.220.140 -- eine Cloudflare-Adresse.

Ursache: Die Kette ist Besucher -> Cloudflare -> Caddy -> Express, aber
`trust proxy` steht auf 1. Express nimmt daher den letzten Eintrag aus
X-Forwarded-For, und das ist Cloudflare.

Auswirkung war nicht nur ein unbrauchbares Protokoll, sondern vor allem:
ALLE Nutzer teilten sich einen einzigen Sperr-Zaehler. Beim ersten
Anmelden waren nach zwei Tippfehlern plus drei Testversuchen bereits
5 von 8 verbraucht -- drei weitere und der Zugang waere fuer alle
gesperrt gewesen.

Jetzt wird CF-Connecting-IP ausgewertet (setzt Cloudflare bei jeder
Anfrage selbst, vom Besucher nicht faelschbar), mit Rueckfall auf die
Peer-Adresse. `trust proxy` bleibt bewusst unangetastet, damit die
Aenderung nur /workspace betrifft und nicht die ganze Website.

Geprueft: 8 Fehlversuche von IP A sperren IP A (429), IP B bekommt
weiterhin 401 und kann sich normal anmelden (200).

Ausserdem: Spaltenbreite im Protokoll-Ausdruck korrigiert -- bei
`anmeldung_fehlgeschlagen` (genau 24 Zeichen) klebte die Rolle am Namen.
2026-08-27 22:53:51 +02:00
DogFatherGit f3a55af80f Creator Workspace: Anmeldung, Sitzungen und Audit-Log
Erster funktionierender Login fuer /workspace. Bewusst OHNE neue
Abhaengigkeiten: Node 24 bringt node:sqlite mit, Hashing und Zufall
kommen aus node:crypto. Nichts zu kompilieren, keine fremde Lieferkette
an einer Stelle, an der es um Zugangsdaten geht.

Sicherheit:
- Codes liegen nur als scrypt-Hash (N=32768) mit eigenem Salt in der DB
- Vergleich in konstanter Zeit (timingSafeEqual)
- Sitzungstoken 32 Byte Zufall, in der DB nur als SHA-256
- Cookie httpOnly, SameSite=lax, Path=/workspace, secure abhaengig von
  req.secure (live immer an, nur der lokale http-Test kommt ohne aus)
- Sperre nach 8 Fehlversuchen je IP fuer 10 Minuten -- danach ist auch
  der richtige Code blockiert (geprueft)
- gleiche Fehlermeldung bei falscher Rolle und falschem Code
- Audit-Log fuer Anmeldung, Fehlversuch, Sperre, Abmeldung, Codewechsel

Die Datenbank liegt AUSSERHALB des Repos (../workspace-daten/): sonst
waere sie ueber express.static aus dem Netz erreichbar, und ein git pull
wuerde Nutzdaten anfassen.

workspace.js kann die Website nicht mitreissen: node:sqlite wird erst bei
Bedarf per createRequire geladen, jede Route faengt ihre Fehler selbst ab.
Faellt die DB aus, antwortet nur /workspace/api/* mit 503.

Codes werden ausschliesslich auf der Kommandozeile erzeugt
(server/workspace-code.js) und dort einmal angezeigt -- nie in Git.

Ausserdem: start.html als geschuetzte Seite nach dem Anmelden. Der Schutz
sitzt serverseitig vor express.static, nicht nur im Browser.
2026-08-27 22:35:55 +02:00
DogFatherGit 1f769c9de7 Workspace-Anmeldung: kompaktere Tafel auf niedrigen Bildschirmen
Auf dem iPhone 13 (nur 664 px nutzbare Hoehe) verdeckte die Tafel das
Motiv fast vollstaendig -- sichtbar waren nur die Ohrenspitzen. Neue
Regel fuer max-height 760px: kleinere Abstaende und Schriftgroessen,
und die Bildflaeche wird flacher.

Der zweite Teil ist der eigentliche Kniff: Bei flacherer Bildflaeche
skaliert der Ausschnitt nach BREITE statt nach Hoehe, dadurch zeigt er
den oberen Teil mit den Gesichtern statt seitlich zu beschneiden.

Geprueft auf iPhone 13, iPhone SE und Pixel 5.
2026-08-27 18:15:08 +02:00
DogFatherGit 19f969f36f Creator Workspace: Anmeldeseite unter /workspace
Erstes sichtbares Stueck des Creator-Workspace-Konzepts. Reine statische
Dateien in einem neuen Ordner workspace/ -- express.static liefert den
Repo-Ordner aus, die Seite ist damit ohne Servercode-Aenderung und ohne
Neustart unter /workspace/ erreichbar. Rein additiv: an bestehenden
Dateien wurde nichts geaendert.

Motiv: Dogfather und Hasi Dog stehen rechts im Bild, deshalb liegt die
Code-Tafel links ueber der ruhigen Flaeche (bei VanVans Buchhaltung ist es
gespiegelt, weil dort das Emblem links steht). Drei Layoutfaelle, damit die
Figuren in keiner Fenstergroesse von der Tafel ueberdeckt werden.

Bewusst nur WebP, kein AVIF: send 0.19.2 (Express 4) kennt AVIF nicht und
liefert es als application/octet-stream aus -- wegen des nosniff-Headers
verweigert der Browser das Bild dann komplett. Lokal gegen den echten
Express-Server geprueft: 0 Konsolenfehler, 0 CSP-Verstoesse.

Anmelden funktioniert noch nicht (kein Endpunkt); das Formular sagt das
jetzt ehrlich statt "Code stimmt nicht".
2026-08-27 18:13:05 +02:00
DogFatherGitandClaude Opus 5 43264c0990 Startseite hochwertiger: Typografie, Weltfarben, Event-Karte
Wunsch 27.08.2026: "soll nur noch hochwertiger und professioneller
aussehen." Kein neues Design, sondern die Details, die den Unterschied
zwischen "gemacht" und "gesetzt" ausmachen:

- Ueberschrift enger gesetzt (-.022em, Zeilenabstand 1.08, text-wrap:
  balance). Bei 4rem wirkt normale Laufweite auseinandergefallen; die
  drei Zeilen verteilen sich jetzt gleichmaessig statt mit kurzer
  Restzeile.
- Jede Welt-Kachel traegt die Farbe IHRER Welt statt dreimal derselben:
  Babyblau, Silber, das gedeckte Rot von Spicy Media. Die Werte sind
  nicht erfunden, sondern die --accent-Toene der drei Themendateien.
- Plaketten ("WELT 1") klein, in Versalien, weit gesperrt -- liest sich
  als Kapitelmarke statt als Beschriftung.
- Event-Karte: Datum als gesperrte Versalzeile (ordnet sich dem Titel
  unter), "Mehr erfahren" als ruhiger Knopf statt nacktem Textlink,
  Haarlinie am Bild, Text auf 5 Zeilen begrenzt -- damit nicht die
  Textlaenge aus der Verwaltung das Aussehen der Startseite bestimmt und
  bei zwei Events beide Kacheln gleich hoch sind (geprueft: 572/572px).

ZWEI FUNDE BEIM PRUEFEN, BEIDE WICHTIGER ALS DER FEINSCHLIFF:

1. INHALTSRICHTLINIE UND ZEILENENDEN. Der Browser rechnet die Pruefsumme
   eines Inline-Skripts NICHT ueber die Bytes der Datei, sondern ueber
   den Text im Dokument -- und der HTML-Parser ersetzt beim Einlesen
   jedes CR LF durch LF (HTML-Spezifikation, "preprocessing the input
   stream"). Eine Datei mit Windows-Zeilenenden ergibt serverseitig also
   eine ANDERE Summe, und die Seite fuehrt ihr eigenes Skript nicht mehr
   aus: kein Live-Status, keine Events, nichts. Live war es unauffaellig
   (Linux-Auscheckung hat LF), auf dem Windows-Rechner sofort tot
   (core.autocrlf=true). inhaltsrichtlinie.js vereinheitlicht jetzt vor
   dem Rechnen auf LF -- das ist die Summe, die der Browser wirklich
   bildet, und macht die Richtlinie unabhaengig davon, mit welchem
   Werkzeug eine Datei zuletzt gespeichert wurde.

2. TESTS MIT FESTEM PORT KOENNEN LUEGEN. Drei Server aus frueheren
   Laeufen liefen noch. Neue Testlaeufe konnten ihren Port nicht belegen,
   starben still -- und massen weiter gegen den ALTEN Code. Ergebnis
   waren Fehlermeldungen zu einem laengst behobenen Fehler. pruef-musik,
   pruef-kasse und pruef-startseite suchen sich jetzt einen freien Port.

Neuer Test pruef-startseite.mjs (19 Pruefungen) mit FESTEN Event-Daten:
Beim Pruefen kam einmal nichts vom Server, der Abschnitt blieb leer und
der Test haette "kein Fehler" gemeldet, obwohl er nichts gesehen hat.
Geprueft werden Maske am Artwork, genau eine Kachel bei einem Event,
volle Breite, saubere Textkuerzung auf ganze Zeilen, eigene Weltfarben,
zwei gleich hohe Kacheln bei zwei Events, Handy ohne Ueberlauf.

Alles gruen: startseite 19, musik 17, kasse 15, inhaltsrichtlinie 22,
handy 56.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 16:06:09 +02:00
DogFatherGitandClaude Opus 5 57d90b9905 4 weitere überdimensionierte Bilder verkleinert + Cache-Buster vereinheitlicht
pruef-bildgroessen.mjs (neu) misst systematisch über alle Seiten
(Desktop + Handy, mal Pixeldichte), welche <img> größer sind als ihre
größte Anzeige. Fand 4 klare Fälle:

  streamer-mascot.jpg            900px, gezeigt 230px  -> 480px  360->119 KB
  bewerben-poster-dogfather.jpg  800px, gezeigt 204px  -> 440px  199->80 KB
  avatar-bananenstift.jpg       1122px, gezeigt 108px  -> 400px  167->25 KB
  avatar-marina.jpg             1086px, gezeigt  90px  -> 400px  157->20 KB

Zusammen 639 KB gespart. Avatare bewusst auf 400px (großzügiger als die
2x-Anzeige), falls doch mal eine Detailansicht kommt. Qualität am
Maskottchen per Screenshot geprüft: scharf, Schrift lesbar, keine Artefakte.

CACHE-BUSTER-BUG behoben: 69 Ressourcen-Verweise standen noch auf dem alten
Marker "20260827hero" (einer sogar auf "20260820h"), der Rest auf
"20260828c". Verschiedene Seiten luden dieselbe main.css/js unter
verschiedenen Cache-Keys -- wiederkehrende Besucher der hero-Seiten bekamen
bei Änderungen eine veraltete gecachte Fassung. Die Playwright-Tests sahen
das nie (leerer Cache). Jetzt alle 245 einheitlich auf 20260828d; der
bewusste admin-auth "-jedesmal"-Marker bleibt unberührt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:47:35 +02:00
DogFatherGitandClaude Opus 5 508009ecc7 Startseite: Hintergrund-Kanten weg, "Event des Jahres" neu aufgebaut
Gemeldet 27.08.2026: "es ueberschneidet den hintergrund sieht irgendwie
scheisse aus."

1. HARTE KANTEN IM HINTERGRUND
   Das scharfe Trio-Artwork lag als CSS-Hintergrund mit "contain" hinter
   der Seite und endete an einer messerscharfen Linie (bei 1366x800 exakt
   bei 570px und 1345px); darueber/darunter lag sichtbar die verwaschene
   Fassung. Das las sich wie ein aufgeklebtes Band quer ueber der Seite.
   Jetzt ein echtes <img>, das an seinen EIGENEN Raendern weich in die
   verwaschene Ebene uebergeht. Entscheidend: Die Maske haengt am Bild,
   nicht am Fenster -- als CSS-Hintergrund war das unmoeglich, weil die
   Kante je nach Fensterformat wandert.

2. "EVENT DES JAHRES" -- 700px tote Flaeche
   Eine 480px schmale Kachel sass zentriert in einer 1180px breiten
   Kiste, die selbst Rahmen und Hintergrund trug: drei Rahmen ineinander
   um einen einzigen Inhalt, links und rechts je 350px Leere. Jetzt volle
   Breite mit Bild links / Text rechts, die umgebende Kiste ist rahmenlos.
   Hoehe von 656px auf 332px, ohne dass Inhalt verloren geht -- das Bild
   ist dabei doppelt so gross wie vorher.

3. Welt-Kacheln mit einer Spur Milchglas und feinem Lichtsaum, damit sie
   zur Szene gehoeren statt als flache Rechtecke daraufzuliegen.

BEIM BAUEN GEFUNDEN UND KORRIGIERT: Der erste Entwurf hat die versteckte
zweite Event-Kachel wieder sichtbar gemacht (leere Kachel mit einsamem
"Mehr erfahren"). Ursache ist die im Code zweimal dokumentierte Falle:
".jahres-event-card[hidden]" ist genau so stark wie eine
Zwei-Klassen-Regel und verliert gegen die spaetere. Deshalb steht in den
neuen Regeln ueberall :not([hidden]).

Versionsnummern von main.css/main.js hochgesetzt -- Assets werden mit
max-age=14400 ausgeliefert, sonst haette Dogi die Aenderung bis zu vier
Stunden nicht gesehen.

Geprueft: pruef-handy (56), pruef-barrierefrei (60), pruef-design (0
Fundstellen), pruef-blickfang (13), pruef-assets (67), pruef-musik (17)
-- alle gruen. Der Musik-Knopf holt seine Farben jetzt aus dem <img>
statt aus dem CSS-Hintergrund (main.js), sonst waere er ausgerechnet auf
der Startseite auf die Ersatzfarbe zurueckgefallen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:45:23 +02:00
DogFatherGitandClaude Opus 5 e2a40313d6 Startseiten-Bilder verkleinert: 3 überdimensionierte Fotos (687 KB gespart)
Der Performance-Check (pruef-tempo.mjs, neu) zeigte die Startseite mit
3,5 MB, überwiegend Bilder. Drei davon waren viel größer als je
angezeigt (gemessen über Desktop + Handy, alle Seiten, mal Pixeldichte):

  card-dogfather.jpg  1200px, angezeigt max 359px  ->  720px  534->201 KB
  casper-4.jpg        1400px, angezeigt max 359px  ->  720px  350->115 KB
  casper-3.jpg        1400px, angezeigt max 359px  ->  720px  259->140 KB

720px = doppelte Anzeigebreite, also auch auf Retina-Displays scharf.
Qualität an zwei Motiven per Screenshot geprüft: keine sichtbaren
Artefakte, Schrift und Details erhalten.

card-vanvan bewusst UNANGETASTET: wird auf vanvan.html mit 578 CSS-px
gezeigt, bräuchte für Retina ~1156px -- das 1200er ist dort passend.

Verkleinert über Browser-Canvas (kein ImageMagick/sharp verfügbar; das
gefundene "convert" war das Windows-Dateisystem-Tool, nicht ImageMagick).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:40:22 +02:00
DogFatherGitandClaude Opus 5 5b2a1daabe Öffentliche Avatar-Uploads vor dem Absenden verkleinern (1,1 MB -> ~40 KB)
Der Performance-Check (pruef-tempo.mjs, neu) fand als größte Einzel-
ressource ein 1,1-MB-Profilbild, ausgeliefert an jeden Besucher der
Startseite und von stimmen.html -- angezeigt wird es handgroß.

Ursache: Das öffentliche Stimmen-Formular (stimmen.js) lud Profilbilder
ROH hoch. Die Bildaufbereitung vom 27.08. bekam nur die Verwaltung, nicht
das öffentliche Formular. So landete das Kamera-Foto in voller Auflösung
auf dem Server.

- bild-vorbereiten.js (neu): die Verkleinerungs-Funktion, jetzt einmal
  und parametrisierbar (maxBreite). Verwaltung nutzt weiter 1600px,
  Avatare 512px. Test pruef-bild-vorbereiten.mjs: 8/8, u.a. 512er-Avatar
  ~40 KB statt >1 MB.
- stimmen.js: verkleinert vor dem Upload (window.bildVorbereiten mit
  maxBreite 512); fällt die Funktion aus, wird das Original genommen --
  kein Upload darf daran scheitern.
- stimmen.html: lädt bild-vorbereiten.js; veralteten Kommentar
  richtiggestellt (behauptete "kein Upload", obwohl es seit 21.08. einen
  gibt -- mit Bremse, Typ-/Größenlimit, Freigabe-Pflicht).

Zwei neue Checks als bleibende Absicherung mit committet: pruef-links.mjs
(41 interne Ziele, 0 kaputt) und pruef-assets.mjs (67 Ressourcen, 0 fehlen).

NOCH OFFEN: verwaltung.html hat noch eine eigene, identische Inline-Kopie
der Funktion -- die Zusammenführung ist ein eigener, testbarer Schritt
(das Inline-Skript dort ist groß und die Verwaltung hinter dem Gate schwer
live zu testen). Das bestehende 1,1-MB-Bild auf dem Server bleibt, bis es
neu hochgeladen/ersetzt wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:17:30 +02:00
DogFatherGitandClaude Opus 5 3e2f5306ad Aufraeumen: mein Wegwerf-Messskript _probe2.mjs wieder entfernt
Es ist im vorigen Commit versehentlich mitgegangen, weil der Testlauf
in die Zeitgrenze lief und das "rm" danach nie ausgefuehrt wurde. Der
Inhalt ist als richtiger Test in pruef-kasse.mjs aufgehoben -- die
Wegwerf-Fassung gehoert nicht ins Projekt.

Hinweis: pruef-tempo.mjs im selben Commit ist NICHT von mir, es lag
unversioniert im Arbeitsordner und wurde von "git add -A" miterfasst.
Es bleibt drin, weil Loeschen fremder Arbeit schlimmer waere als ein
Commit zu frueh -- Dogi entscheidet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:11:56 +02:00
DogFatherGitandClaude Opus 5 8fa15c04f1 Kasse und Google-Anmeldung in der Inhaltsrichtlinie freigegeben
Fortsetzung des Musik-Fundes: PayPal und Google haetten an derselben
Stelle still versagt, sobald Dogi seine Zugangsdaten eintraegt -- leerer
Bereich statt Bezahlknopf, ohne Fehlermeldung, ohne Protokolleintrag.

Vorgehen bewusst gemessen statt geraten: Erst die Angaben der Anbieter
(PayPal "Best Practices", Google CSP-Abschnitt der Setup-Anleitung),
dann im echten Browser mit PayPals offizieller Testkennung
"client-id=test" nachgemessen und die Verstoesse ueber das Ereignis
securitypolicyviolation eingesammelt. Die Messung hat zwei Dinge
gefunden, die in keiner Anleitung standen:

- www.sandbox.paypal.com (frame-src + connect-src). Beim Einrichten
  testet man mit Sandbox-Zugangsdaten; ohne diesen Eintrag haette die
  Kasse in genau dieser Phase nicht abgeschlossen werden koennen.
- accounts.google.com/gsi/style (style-src). 'unsafe-inline' deckt das
  NICHT ab -- es erlaubt nur Stile im Dokument, keine nachgeladene
  Stilvorlage. Der Anmelde-Knopf waere unformatiert erschienen.

Bewusst einzelne Adressen statt PayPals vorgeschlagener Platzhalter
(*.paypal.com): Was die Messung nicht gebraucht hat, steht nicht drin.
Skripte bleiben ohne 'unsafe-inline' -- die Pruefsummen-Loesung fuer die
eigenen Inline-Bloecke bleibt unangetastet, und ein zusaetzliches
'unsafe-inline' waere neben Pruefsummen ohnehin wirkungslos.

Neuer Test pruef-kasse.mjs (15 Pruefungen): laedt das echte PayPal-SDK,
baut die Bezahlknoepfe wirklich auf, rendert den echten Google-Knopf und
verlangt NULL Verstoesse. Bestandstest pruef-inhaltsrichtlinie.mjs (22)
und pruef-musik.mjs (17) bleiben gruen -- inklusive der Gegenprobe, dass
eingeschleuste Skripte weiterhin blockiert werden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:11:27 +02:00
DogFatherGitandClaude Opus 5 87db17704a Test: kein Bild / keine eingebundene Datei fehlt
Prüft, was die öffentlichen Seiten laden: Bilder, og:image/twitter:image,
Favicon, Manifest. Eine fehlende Datei zeigt sich als leerer Kasten oder
kaputte Teilen-Vorschau, oft unbemerkt.

Ergebnis: 67 eigene Ressourcen, alle vorhanden, 0 fehlen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:07:55 +02:00
DogFatherGitandClaude Opus 5 3a8a52aa49 Test: kein interner Link zeigt ins Leere
Sammelt alle internen Links von 24 öffentlichen Seiten und prüft jedes
Ziel einmal gegen die echte Domain. Weiterleitungen (3xx, z.B. auf eine
Zugangswand) gelten als gültig, nur 4xx/5xx als toter Link.

Ergebnis: 41 Ziele, alle in Ordnung, 0 kaputt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:06:36 +02:00
DogFatherGitandClaude Opus 5 1d99da8ef8 Musik-Knopf repariert: Inhaltsrichtlinie blockierte die Spotify-Player
Gemeldet am 27.08.2026 ("unten rechts laeuft was nicht richtig mit der
Musik"). Ursache lag nicht in der Seite, sondern in der am 26.08.2026
eingefuehrten Inhaltsrichtlinie: "frame-src 'none'" verbietet dem
Dokument jede Einbettung -- und die beiden Player (Hasidog, Van-Van)
sind genau das. Der Knopf reagierte, das Feld ging auf, die Player
blieben leer. Kein Absturz, keine Fehlermeldung auf der Seite; die
Begruendung stand nur in der Browser-Konsole.

- frame-src erlaubt jetzt genau eine Quelle: https://open.spotify.com.
  Kein Sternchen, kein 'unsafe-*'. Was im Spotify-Rahmen passiert,
  regelt Spotifys eigene Richtlinie.
- Neuer Test pruef-musik.mjs (17 Pruefungen). Er startet bewusst den
  ECHTEN server/index.js statt eines Datei-Servers -- ein einfacher
  Datei-Server erzeugt die Kopfzeile gar nicht und haette den Fehler
  nie gesehen. Geprueft wird im echten Browser, ob die Rahmen wirklich
  von open.spotify.com laden (statt einer Fehlerseite), dazu Tippziel,
  Position, Schliessen per Knopf und Escape, Handy-Layout.

Beim Nachsehen aufgefallen und NOCH OFFEN: PayPal-Kasse und
Google-Anmeldung auf abonnieren.html laden ihre Skripte und Rahmen
ebenfalls von fremden Adressen. Beide sind derzeit nicht scharf
(googleClientId/paypalClientId sind null), wuerden aber mit derselben
Richtlinie an derselben Stelle still ausfallen, sobald Dogi seine
Zugangsdaten eintraegt. Wird gesondert mit ihm besprochen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 13:52:36 +02:00
DogFatherGitandClaude Opus 5 887da7b09b Verwaltung: Gate-Text an die neue Anmelde-Regel angepasst
Unter der Ueberschrift stand weiterhin "gilt danach 24 Stunden" -- seit
heute gilt der Code aber nur, solange die Seite/App offen ist. Ein
Versprechen, das die Seite nicht mehr einhaelt, ist schlimmer als gar
keins: Dogi haette sich sonst darauf verlassen, morgen ohne Code
weiterzukommen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 13:29:03 +02:00
DogFatherGitandClaude Opus 5 7960b212c8 Verwaltung: Zugangscode wieder bei jedem Oeffnen noetig
Dogi hat die Lockerung vom 04.08.2026 ("Code nur einmal am Tag") heute
zurueckgenommen. Gewaehlte Auspraegung: Code beim OEFFNEN der Seite/App,
Neuladen im selben Tab wirft nicht raus, keine Abmeldung bei Untaetigkeit.

- admin-auth.js legt die Sitzung jetzt in sessionStorage statt in
  localStorage: gehoert zum Tab/App-Fenster, uebersteht F5 und Uploads,
  ist beim naechsten Oeffnen weg. Zweiter Tab = eigener Code.
- Alte localStorage-Sitzung wird beim ersten Laden einmalig entfernt --
  sonst waere Dogi trotz Umstellung mit dem alten Token weiter drin und
  ein Token laege monatelang im Browser herum.
- Versionsnummer des Skripts hochgesetzt: Caddy liefert Assets mit
  max-age=14400, der Browser haette die alte Anmelde-Logik sonst bis zu
  vier Stunden weiterbenutzt.
- Der 24-Std-Ablauf bleibt als Rueckfallsicherung fuer tagelang offene
  Tabs; der Server erzwingt dieselbe Grenze weiterhin selbst.
- Neuer Test pruef-verwaltung-anmeldung.mjs (12 Pruefungen: Gate beim
  Oeffnen, alte Sitzung wirkungslos, falscher/richtiger Code, F5 bleibt
  drin, neuer Tab verlangt Code, Abmelden raeumt auf, Untaetigkeit meldet
  NICHT ab).
- pruef-verwaltung-kacheln.mjs: echten Aufruf ans Live-Backend abgefangen
  und auf die Supporter-Zeilen gewartet -- der Test hatte dadurch
  gelegentlich falsch gemeldet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 13:28:14 +02:00
DogFatherGitandClaude Opus 5 0465a7a14a Verwaltung: Stimmen als kompakte Kacheln, Supporter-Liste auf 4 gekuerzt
Beides auf Wunsch vom 27.08.2026 ein-/ausklappbar:

- Stimmen liegen jetzt in einem Raster (auto-fill, min. 290px) statt
  untereinander -- am Computer stehen 3-4 Kacheln nebeneinander, am Handy
  eine. Zugeklappt ist genau die erste Reihe sichtbar; wie viele Kacheln
  das sind, liest die Logik aus dem Raster selbst aus (getComputedStyle
  liefert bei auto-fill die gebauten Spuren), damit "erste Reihe" auf
  jeder Breite stimmt -- inklusive Neuberechnung beim Groessenwechsel.
- Supporter-Tabelle zeigt nur noch die 4 zuletzt Angemeldeten, Rest per
  Knopf. Knopftext nennt immer die Gesamtzahl, damit nichts versteckt
  wirkt; beim Zuklappen springt die Ansicht sauber zum Listenanfang.
- Neuer Test pruef-verwaltung-kacheln.mjs (18 Pruefungen, Computer +
  Handy, inkl. Groessenwechsel und Ueberlauf-Kontrolle).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 13:17:05 +02:00
DogFatherGitandClaude Opus 5 988a2fdc95 DEPLOY.md: interner Deploy verifiziert — npm-Warnungen eingeordnet, sleep 6
Der erste echte Lauf des internen Deploy-Blocks (28.08.2026) förderte zwei
harmlose, aber verunsichernde Punkte zutage:

- npm ci warnt "allow-scripts ... better-sqlite3": Die allowScripts-Sperre
  blockiert den nativen Build, aber prebuild-install liefert ein fertiges
  Binary. Dienst lädt danach die DB einwandfrei -> in Ordnung. Als Kontrolle
  dokumentiert.
- sleep 2 war zu kurz: Der health-Check lief, bevor der Dienst auf 4200
  hörte -> kurzzeitig 502 / "activating", obwohl gleich darauf alles läuft.
  Auf sleep 6 erhöht, mit Hinweis, wann ein 502 wirklich ein Problem ist.

Deploy selbst war erfolgreich: Bremse greift live (20 durch, 21. -> 429),
multer 2.2.0 + node-cron 4.6.0 installiert, better-sqlite3 lädt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 12:41:38 +02:00
DogFatherGitandClaude Opus 5 5c546207e7 DEPLOY.md: interner Deploy-Block ohne führendes cd
Der Block scheiterte in der Praxis am ersten "cd /home/dogiintern/...":
Das Verzeichnis ist 700, selbst dogi kommt per cd nicht hinein, nur
dogiintern über sudo -u. Jetzt git -C statt cd, und das npm ci in einer
sudo -u dogiintern bash -c 'cd ... && npm ci'-Shell. Mit Warnhinweis,
warum kein cd davor stehen darf.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 12:03:52 +02:00
DogFatherGitandClaude Opus 5 68b421b79a Zahlungen-Bühne: besserer Bildausschnitt statt flacher Mitte
Das cryo-kristall-Motiv (Zahlungen) ist als einziges der sechs HOCHKANT
(702x941) statt quer (1672x941). Auf der breiten 16:9-Bühne zeigt "cover"
davon nur einen horizontalen Streifen -- der mittige (Standard center
center) traf die unruhigen Kristallsplitter und wirkte flach und
beschnitten.

Jetzt zeigt Zahlungen den oberen Streifen (background-position center
15%): die eleganten geschwungenen Kristallbänder rechts als Blickfang,
links ruhiger dunkler Raum für die Karten -- eine klare Komposition wie
bei den anderen Motiven. Nur für Zahlungen überschrieben, die übrigen
fünf bleiben mittig.

Nebenbei: Der Wert kommt aus --vw-blick, das für alle Bereiche längst
definiert, bisher aber nirgends ausgelesen wurde (toter Code). Die neue
.vw-buehne-Ausnahme wendet ihn für Zahlungen erstmals an.

Service-Worker-Cache v63 -> v64 (beide Stellen), damit Geräte mit der App
den neuen Ausschnitt bekommen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 12:02:26 +02:00
DogFatherGitandClaude Opus 5 50ff8e0f4c DEPLOY.md: voller Deploy-Block für den internen Dienst + Stand nachgezogen
- Vollständiger kopierfertiger Deploy-Block für server-internal MIT npm ci:
  pull -> npm ci -> Lade-Test der nativen Module -> restart -> Selbsttest,
  als eine &&-Kette, die bei jedem Fehler VOR dem Neustart abbricht (alter
  Dienst läuft dann unberührt weiter). Bisher stand dort nur pull + restart
  ohne npm ci -- genau die Lücke, durch die Code und Pakete auseinanderliefen.
- Wächter: 18 -> 19 Punkte (Sicherungsprüfung dazugekommen).
- Zwei offene Punkte ergänzt: ausstehender Server-Neustart (Kernel/OpenSSL
  liegen bereit) und der ausstehende server-internal-Deploy.
- Veralteten Datenschutz-404-Eintrag abgehakt (heute live 401 verifiziert).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 11:16:30 +02:00
DogFatherGitandClaude Opus 5 9bd9357185 Überschriftenordnung im Hauptinhalt: keine übersprungenen Ebenen mehr
Fünf Seiten hatten einen Sprung h1 -> h3 im Hauptinhalt (die Kachel-
Überschriften waren h3, ohne h2 dazwischen). Für Bildschirmleser fehlte
damit eine Ebene im "Inhaltsverzeichnis" der Seite (WCAG 1.3.1).

Pro Seite der passende, optik-erhaltende Weg -- jede Änderung mit
Screenshot bzw. gemessener Schriftgröße gegengeprüft:

- werte, kontakt, index: Kachel-h3 -> h2 (die Kacheln SIND die
  Hauptabschnitte unter der h1). Neue Regel .card > h2 hält die kompakte
  h3-Optik (1.62rem); Varianten .card-brand/.card-feature bleiben über
  ihre eigenen h3-Regeln unberührt. Gemessen: 25.92px vorher = nachher.
- bewerben: die schon sichtbaren Gruppenlabels (Community / Agentur)
  waren <span> -> jetzt <h2> mit derselben Klasse. Optik per Screenshot
  identisch (zentriert, uppercase, Zierstrich).
- links: die Kacheln nutzen Spezial-Varianten mit eigenen Größen, ein
  Tag-Wechsel wäre riskant -> stattdessen eine unsichtbare Gruppen-
  überschrift (.sr-only, neue Klasse nach WCAG-Standard). Ändert die
  Optik nicht, vervollständigt aber die Ordnung für Bildschirmleser.

Cache-Buster 20260828b (main.css geändert: .card > h2, .sr-only).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 11:08:37 +02:00
DogFatherGitandClaude Opus 5 8a2943df35 Fußzeilen-Spaltentitel h4 -> h2 (Überschriftenordnung, WCAG 1.3.1)
Die drei Fußzeilen-Spaltentitel (Filipe, Dogi&Hasi & Manager, Mehr)
waren <h4>, obwohl der Hauptinhalt bei h2/h3 endet -- ein Sprung in der
Überschriftenordnung (h2 -> h4) auf jeder Seite. Für Bildschirmleser ist
die Überschriftenliste das Inhaltsverzeichnis; eine übersprungene Ebene
stört die Orientierung.

Jetzt <h2> (eigenständige Abschnitte unter der Seiten-h1). Die Optik
bleibt exakt: Der CSS-Selektor .footer-grid h4 wurde zu .footer-grid h2
umgezogen, die kleine, gedämpfte Darstellung (.85rem, uppercase,
Akzentfarbe) überschreibt weiterhin die große globale h2-Größe.

Teil des Barrierefreiheits-Durchgangs (pruef-barrierefrei.mjs). Behebt
die reinen Fußzeilen-Fälle; die Hauptinhalt-Überschriften folgen separat.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 10:57:55 +02:00
DogFatherGitandClaude Opus 5 8a2d2b802a Wächter-Protokoll hält sich selbst klein (keine unbegrenzte Log-Datei)
waechter.log wuchs unbegrenzt: alle 5 Minuten eine Zeile, ~288/Tag. Ohne
Grenze irgendwann zu groß zum Durchsehen -- dann verliert das Protokoll
seinen Zweck.

Der Wächter kürzt jetzt selbst, statt logrotate: Das bräuchte eine Datei
in /etc (kein Schreibrecht) und einen Extra-Dienst. Vor dem Anhängen wird
nur die Größe abgefragt (billig); erst über 1 MB (~45 Tage) wird die Datei
einmal gelesen und auf die jüngsten 2000 Zeilen (~1 Woche) gestutzt.

Beim Bauen einen eigenen Fehler gefangen: statSync war in waechter.mjs
nicht importiert (beim Auslagern der Sicherungsprüfung mit entfernt worden).
node --check meldet das nicht -- es hätte erst zur Laufzeit im nächsten
Cron-Lauf gekracht. Import ergänzt.

Test pruef-protokoll-kuerzen.mjs: klein bleibt unangetastet, groß wird auf
die JÜNGSTEN Zeilen gestutzt (älteste fallen weg), Grenzfall und fehlende
Datei sauber. 8/8.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 10:40:03 +02:00
DogFatherGitandClaude Opus 5 91bf0755cb Test: alle Admin-Routen automatisch auf Zugriffsschutz prüfen
Liest alle 109 /admin/-Routen direkt aus index.js (nicht hartkodiert)
und spricht jede mit einem ungültigen Token an. Erwartet 401/403.

Der Sinn: Der Schutz sitzt in jedem einzelnen Handler statt als Sperre
vor der Gruppe. Wer eine neue Route hinzufügt und den Aufruf vergisst,
macht sie unbemerkt öffentlich -- das fällt beim Klicken nie auf. Weil
der Test die Routen aus dem Code liest, taucht eine künftig vergessene
Absicherung automatisch als Fehlschlag auf, ohne dass jemand den Test
pflegt.

Ungültiges Token statt gar keins ist der gefahrlose Weg, das auch für
schreibende Routen (anlegen, löschen) gegen die echte Domain zu tun:
Der Schutz greift vor dem Handler, es kann nichts verändert werden.

Ergebnis live: 109 geschützt, 0 auffällig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 10:37:25 +02:00
DogFatherGitandClaude Opus 5 a612a0f0fd Anfragebremse für /submit und /testimonials/submit (die letzten zwei ungebremsten Routen)
Bei der Bestandsaufnahme als "keine Route hat eine Bremse" gemeldet --
das war falsch (grep suchte nach rateLimit/bremse, im Code heißen sie
Kontingent/Sperre/Fehlversuche). Fast alle öffentlichen Routen SIND
gebremst: Anmeldung, Supporter-Login, Upload, Kundenanfragen. Übrig
blieben genau zwei schreibende Routen: Bewerbungen und Stimmen.

Ohne Bremse könnte ein Skript die Datenbank mit Müll fluten. Kein
Sicherheitsleck (beide landen in einer Warteschlange, nichts wird
ungesehen veröffentlicht), aber eine sinnvolle Härtung.

Statt das vorhandene Muster ein drittes Mal zu kopieren: ein Baustein
lib/kontingent.js, den nun alle drei Routen nutzen. Zwei Verbesserungen
gegenüber dem Original in testimonials.js:
- getrennte Töpfe je Zweck (ein Bild-Upload verbraucht kein
  Bewerbungs-Kontingent)
- Selbstreinigung: die alte Zähler-Map ließ jede IP für immer im
  Speicher stehen (langsames Leck), die neue räumt abgelaufene Einträge auf

Grenzen: Uploads 10/Stunde/IP (belegen Plattenplatz), Text-Einreichungen
20/Stunde/IP (großzügig für geteilte Anschlüsse, stoppt Fluten).

Tests: pruef-kontingent.mjs (Baustein, 7/7), test-kontingent-routen.mjs
(echte Routen liefern 429 ab Grenze, getrennte Töpfe, IPs unabhängig,
4/4). Bestehende Tests unverändert grün (37/37).

NOCH NICHT LIVE: server-internal läuft aus /home/dogiintern (kein Zugriff),
wird mit den übrigen Server-Änderungen in einem Deploy live geschaltet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 10:35:54 +02:00
DogFatherGitandClaude Opus 5 55775b53ea Beleg: die multer-DoS-Lücke ist in unserem Setup nicht auslösbar
Gestern als "kritisch, 5 Anfragen töten den Dienst dauerhaft" gemeldet.
Bei genauer Prüfung heute stimmt das nicht:

- index.js hat einen process.on("uncaughtException")-Handler, der genau
  das Prozess-Ende abfängt, das CVE-2025-7338 beschreibt. In drei
  Angriffsvarianten (roher Socket, chunked ohne Abschluss-Chunk,
  content-length-Lüge) blieb der Dienst am Leben.
- Die öffentliche Upload-Route hat eine eigene IP-Bremse (10/Stunde) und
  multer-Härtung; trust proxy ist gesetzt, die Bremse greift pro echter IP.

multer 1.4.5 hat die CVE trotzdem (Fakt) — das Update auf 2.x bleibt
richtig als Wurzelbehandlung, ist aber Hygiene, kein Notfall. Dieser Test
dokumentiert den Nachweis, damit die Einordnung nachvollziehbar bleibt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 10:28:01 +02:00
DogFatherGitandClaude Opus 5 46563b02fc Waechter merkt jetzt, wenn die naechtliche Sicherung ausfaellt
Beim Nachweis des ersten automatischen Laufs gefunden: Der Cron-Eintrag
endet auf >/dev/null 2>&1 -- jede Fehlermeldung wird verworfen. Das
Sicherungsskript fuehrt zwar ein eigenes Protokoll, aber alles, was VOR
der ersten Protokollzeile schiefgeht (Skript geloescht, sqlite3 weg,
Platte voll, Cron gestoppt), passiert spurlos. Niemand haette es
gemerkt -- ausser in dem Moment, in dem man die Sicherung braucht.

Der Waechter prueft ab sofort die Datei selbst, nicht das Protokoll:
Ein Protokoll kann "erfolgreich" melden, waehrend die Datei fehlt.

In lib/ ausgelagert, weil waechter.mjs beim Import sofort seinen ganzen
Durchlauf startet -- testbar war die Funktion dort nicht.

Beim Testentwurf einen eigenen Fehler gefunden: readdirSync wirft
sowohl bei fehlendem Ordner (ENOENT) als auch bei fehlenden Rechten
(EACCES). Die erste Fassung behandelte beides als "kein Urteil" und
haette damit einen geloeschten Sicherungsordner verschwiegen. Jetzt
getrennt: ENOENT meldet, EACCES schweigt.

Die 26-Stunden-Grenze ist bewusst nicht enger: Kurz vor dem naechsten
Lauf ist die juengste Sicherung regulaer 24 Stunden alt. Genau dort
entstehen die Fehlalarme, nach denen man die Meldungen abschaltet --
und dann geht der eine echte mit unter. Als eigener Testfall abgesichert.

14 von 14 Pruefungen bestanden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 03:02:55 +02:00
DogFatherGitandClaude Opus 5 f8f6a26cdf Tastatur-Test prüft die Wirkung des Sprungs, nicht sein Vorhandensein
Ein Sprunglink, der den Fokus nicht mitnimmt, sieht im Quelltext
korrekt aus und ist in der Benutzung wertlos. Der Test betätigt ihn
deshalb wirklich und misst, wo der nächste Tab landet.

Beim Nachmessen auf der Live-Seite fiel auf: Der Fokus liegt sofort
nach dem Sprung korrekt auf <main>, wandert rund 300 ms später aber
auf <body>. Drei Hypothesen einzeln geprüft und alle widerlegt --
sanftes Scrollen (aus: unverändert), Animationen (aus: unverändert),
Fensterfokus im Testbrowser (document.hasFocus() bleibt true). Ein
Abfangen sämtlicher focus()- und blur()-Aufrufe ergab keinen einzigen
Aufruf aus dem Seitencode. Es ist browserinternes Verhalten und
folgenlos: die Sprungmarke für die Tab-Reihenfolge bleibt gesetzt,
nachgewiesen auf allen fünf Seiten.

Zählung korrigiert: Die erste Fassung suchte nur Links und Knöpfe und
meldete auf Formularseiten "Nr. 0 von 67, -1 Punkte gespart", weil das
Ziel dort ein Eingabefeld ist. Jetzt dieselbe Liste wie beim Zählen,
und unsichtbare Elemente fliegen raus.

25 von 25 bestanden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 01:26:35 +02:00
DogFatherGitandClaude Opus 5 efe98e32a7 Sprung zum Inhalt: Seite ohne Maus in einem Schritt bedienbar
Der Tastatur-Test (pruef-tastatur.mjs, neu) zeigte auf allen fünf
geprüften Seiten dasselbe Bild: jedes Bedienelement erreichbar, Fokus
durchgehend sichtbar, keine Tastaturfalle -- aber kein Sprunglink.

Ohne ihn muss sich jemand, der die Tastatur benutzt, auf JEDER Seite
erneut durch das komplette Menü tabben (31 bis 52 Punkte), bevor der
eigentliche Inhalt beginnt. WCAG 2.4.1 verlangt genau diesen Ausweg.

An einer Stelle gelöst statt in 35 Dateien: renderHeader() in main.js
setzt das Sprungziel und stellt den Link davor.

Das tabindex="-1" am <main> ist der Teil, der meistens fehlt: ohne ihn
verschiebt der Sprung in Chrome und Safari nur die Bildlaufleiste, der
Tastaturfokus bleibt in der Navigation -- der nächste Tab landet wieder
im Menü und der Sprung war wirkungslos.

Cache-Buster auf 20260827a (244 Stellen), sonst bekäme niemand die
geänderte main.js und main.css ausgeliefert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 01:21:31 +02:00
DogFatherGitandClaude Opus 5 b99e3043b6 Bilder werden vor dem Hochladen aufbereitet
Das Bild "Event des Jahres" liegt als PNG mit 2524 KB auf dem Server
und macht damit zwei Drittel der gesamten Startseite aus. Angezeigt
wird es mit 246 bis 420 Punkten -- die Datei hat 1672. PNG ist fuer ein
Foto ausserdem das falsche Format.

Der Fehler passiert beim Hochladen: Ein Handy liefert Fotos in voller
Kameraaufloesung, und niemand denkt vorher ans Verkleinern. Es ist auch
nicht die Aufgabe dessen, der ein Bild aussucht -- sondern die der
Seite, die es entgegennimmt.

IM BROWSER, NICHT AUF DEM SERVER

Serverseitig braeuchte es eine Bildbibliothek mit nativem Code,
installiert in einem Verzeichnis, an das ich nicht herankomme. Der
Browser kann das ohnehin: Canvas skaliert und kodiert seit jeher.

Nebeneffekt: Schon der Upload wird kleiner. Wer vom Handy aus ein
8-MB-Foto hochlaedt, wartet sonst am Mobilfunknetz.

DREI ENTSCHEIDUNGEN

1. Kleine PNGs bleiben unangetastet. Ein Logo mit durchsichtigem
   Hintergrund wuerde als JPEG einen schwarzen Kasten bekommen. Die
   Grenze liegt bei 400 KB -- darunter ist es wahrscheinlich eine
   Grafik, darueber praktisch immer ein Foto.

2. Wird die Datei NICHT kleiner, bleibt das Original. Bei bereits gut
   komprimierten Bildern kann erneutes Kodieren sogar zulegen -- und
   Qualitaet kosten fuer nichts.

3. Schlaegt irgendetwas fehl, wird das Original hochgeladen. Ein
   misslungenes Verkleinern darf niemals einen Upload verhindern.

GEPRUEFT

Grosses PNG 3000px: 130 -> 55 KB, auf 1600px begrenzt.
Grosses JPEG 3000px: 269 -> 131 KB.
Kleines PNG: unveraendert, bleibt PNG.
Keine Skriptfehler.

Gilt fuer alle drei Upload-Stellen: Event-Bild, Team-Foto,
Stimmen-Bild.

Das vorhandene 2524-KB-PNG bleibt davon unberuehrt -- es liegt schon
auf dem Server. Ein einmaliges Neu-Hochladen ueber die Verwaltung
ersetzt es durch die aufbereitete Fassung.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 00:49:49 +02:00
DogFatherGitandClaude Opus 5 5deb920f39 Fuenf Bilder auf die tatsaechlich benoetigte Groesse gebracht
Die Startseite uebertrug 3,72 MB. Gemessen wurde, wie breit jedes Bild
tatsaechlich angezeigt wird -- in Handy- UND Desktop-Ansicht, denn die
groessere der beiden bestimmt, wie gross die Datei sein MUSS. Wer nur
am Handy misst und danach verkleinert, macht die Desktop-Ansicht
unscharf.

  casper-2.jpg            1050px -> 420px   245 KB -> 47 KB
  dogfather-casper-2.jpg  1050px -> 420px   182 KB -> 35 KB
  dogfather-portrait.jpg   933px -> 420px   122 KB -> 35 KB
  casper-1.jpg             720px -> 420px   153 KB -> 72 KB
  dogfather-casper-1.jpg   770px -> 400px   150 KB -> 63 KB

600 KB weniger. Die Zielbreiten liegen bewusst ueber dem gemessenen
Bedarf (408-411px gemessen, 420px gesetzt): Ein Bild kleiner zu machen
als noetig waere schlimmer als ein zu grosses -- Unschaerfe sieht man,
ein paar Kilobyte nicht.

Qualitaet vor dem Ersetzen angesehen, nicht nur die Zahl: Augen, Fell
und Kanten sind bei 420px unveraendert scharf.

NICHT ANGEFASST, WEIL ZU KLEIN

char-dogfather.jpg und char-hasidog.jpg haben 599px, brauchen auf
grossen Schirmen aber 954px. Sie sind also UNSCHAERFER als noetig --
das ist der umgekehrte Fall und gehoert getrennt betrachtet.

DER GROESSTE BROCKEN BLEIBT

Das Bild "Event des Jahres" ist ein PNG mit 2524 KB -- zwei Drittel der
ganzen Startseite. PNG ist fuer ein Foto das falsche Format; als JPEG
in der benoetigten Breite (840px) waeren es rund 150 KB. Die Datei
liegt unter /var/lib/dogfather-internal/uploads und ist ueber den
Verwaltungsbereich hochgeladen worden -- dort wird nicht umgewandelt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 00:31:07 +02:00
DogFatherGitandClaude Opus 5 b037867a99 Tests beenden sich jetzt sauber (process.exitCode statt process.exit)
Der Absturz auf dem Server bestand nach dem ersten Fix fort:

  node::RemoveEnvironmentCleanupHook … Assertion failed: (env) != nullptr
  Statement::~Statement() … better_sqlite3.node
  Abgebrochen

DER ERSTE VERSUCH GING AN DER URSACHE VORBEI

Ich hatte db.close() entfernt -- naheliegend, weil der Aufrufverlauf
auf einen Statement-Destruktor zeigte. Es half nicht. Die Ursache liegt
eine Ebene tiefer: process.exit() beendet Node SOFORT, waehrend
better-sqlite3 noch offene Statements haelt. Deren Aufraeumhaken laeuft
dann ins Leere.

process.exitCode setzt nur den Rueckgabewert; Node beendet sich danach
von selbst, sobald nichts mehr aussteht -- und raeumt dabei in der
richtigen Reihenfolge auf.

WARUM DAS MEHR ALS EIN SCHOENHEITSFEHLER WAR

Der Absturz kam NACH allen Pruefungen und VOR der Zusammenfassung. Der
Test meldete einen Fehler, obwohl inhaltlich alles bestanden war. In
einer mit && verketteten Befehlsfolge blieb deshalb der anschliessende
Dienst-Neustart aus, und die neuen Endpunkte antworteten weiter mit
404. Gesucht habe ich bei den Endpunkten, beim Deploy, an der
Zugangswand -- die Ursache lag beim Beenden eines Testprozesses.

BEMERKENSWERT

Fuenf Tests im Projekt benutzten process.exitCode bereits. Das Muster
war also etabliert; meine neuen Dateien wichen davon ab, ohne dass es
jemandem auffiel. Sechs Tests sind jetzt angeglichen, alle geprueft:
Rueckgabewert 0, Zusammenfassung vollstaendig.

  test-push-kette 30, test-altabbruch 16, test-webdesign-anfragen 37,
  test-webdesign-portal 49, test-webdesign-paypal 28,
  test-personendaten 15

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 00:17:21 +02:00
DogFatherGitandClaude Opus 5 76b88c6b71 Tests: kein db.close() vor process.exit()
Auf dem Server brach test-personendaten.mjs ab:

  node::RemoveEnvironmentCleanupHook … Assertion failed: (env) != nullptr
  Statement::~Statement() … better_sqlite3.node
  Abgebrochen

better-sqlite3 raeumt seine Statements ueber einen Aufraeumhaken ab.
Wird die Verbindung unmittelbar vor dem Prozessende geschlossen, laeuft
dieser Haken ins Leere.

DIE FOLGE WAR SCHLIMMER ALS DER ABSTURZ

Der Absturz kam NACH allen Pruefungen, aber VOR der Zusammenfassung.
Der Test lieferte also einen Fehlercode, obwohl inhaltlich alles
bestanden war. In der mit && verketteten Befehlsfolge blieb deshalb der
anschliessende Dienst-Neustart aus -- und die neuen Endpunkte
antworteten weiter mit 404.

Man sucht dann den Fehler bei den Endpunkten, beim Deploy, an der
Zugangswand. Die Ursache lag beim Aufraeumen einer Testdatenbank.

Node schliesst die Verbindung beim Beenden ohnehin. Zusaetzlich faengt
das Loeschen der Testdateien jetzt Fehler ab: Ohne db.close() haelt der
Prozess sie noch offen, unter Windows scheitert das Loeschen dann mit
EBUSY -- und "force" hilft dagegen nicht, es unterdrueckt nur "Datei
nicht gefunden". Ein Test, der an seinem eigenen Aufraeumen scheitert,
meldet einen Fehler, den es fachlich nicht gibt.

Beide betroffenen Tests geprueft: Rueckgabewert 0, Zusammenfassung
vollstaendig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 00:10:36 +02:00
DogFatherGitandClaude Opus 5 e6e7ab033e DEPLOY.md: die heutigen Werkzeuge und der Stand der offenen Punkte
Nach einem Tag mit vielen Aenderungen beschrieb die Anleitung weder,
was neu automatisch laeuft, noch stimmte ihre Liste offener Punkte.

NEU AUFGENOMMEN

- Zwei Zahlen beim Webdesign-Deploy: CACHE_NAME in sw.js UND die Nummer
  in der Registrierungsadresse. Mit Begruendung, warum eine allein nicht
  reicht -- Cloudflare ersetzt das "no-cache" des Servers durch vier
  Stunden, gemessen am 26.08.2026.
- Was per Cron laeuft: Sicherung (taeglich 03:15) und Waechter (alle
  fuenf Minuten), samt Probeschalter und der Grenze, die bleibt.
- Die Verwaltung als eigene App, und warum ihr Manifest in der
  Ausnahmeliste der Zugangswand stehen muss.

OFFENE PUNKTE NACHGEPRUEFT STATT ABGESCHRIEBEN

Der Eintrag "Hintergrundbilder liegen nur auf dem Server" stimmt nicht
mehr: Alle genannten Dateien und der Avatar-Ordner sind versioniert,
"git status --untracked-files=all -- assets/" meldet auf dem Server
null. Als erledigt gekennzeichnet, nicht geloescht -- eine Liste, in der
Erledigtes ungekennzeichnet steht, wird beim naechsten Mal gar nicht
mehr gelesen.

Der CORS-Punkt war schaerfer formuliert als die Lage: Die Antwort
enthaelt KEIN Access-Control-Allow-Credentials, und die Verwaltung
weist sich ueber "Authorization: Bearer" aus statt ueber ein Cookie.
Ein Browser schickt bei einer fremden Seite also weder Cookies noch das
Token mit; erreichbar sind nur die ohnehin oeffentlichen Endpunkte.
Sauberer waere eine feste Herkunftsliste -- das ist Haertung, keine
Reparatur, und gehoert als eigener Vorgang mit Live-Test angefasst.

Ergaenzt: express 5 ist vorbereitet aber bewusst nicht umgestellt, und
die Datenschutz-Endpunkte warten auf einen Pull in /home/dogiintern.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 23:48:21 +02:00
DogFatherGitandClaude Opus 5 40714b382e "Es fehlt: —." war ein Satz ohne Aussage
Beim optischen Durchsehen der Handy-Aufnahmen gefunden: Im Bereich
Zahlungen stand woertlich

    NOCH NICHT EINGERICHTET
    Es fehlt: —. Solange sagt das Kundenportal freundlich Bescheid …

Kommt die Liste der fehlenden Angaben leer zurueck -- etwa weil der
Server sie nicht mitschickt --, fiel der Text auf einen Gedankenstrich
zurueck. Man liest eine Fehlermeldung, die nicht sagt, was fehlt, und
sucht dann bei den Zugangsdaten statt bei der Antwort des Servers.

Jetzt zwei getrennte Saetze: einer, wenn bekannt ist WAS fehlt, und
einer fuer den Fall, dass nur bekannt ist DASS etwas fehlt.

Ein Rueckfallwert, der aussieht wie eine Angabe, ist schlechter als
gar keiner -- er beantwortet die Frage scheinbar und schickt einen in
die falsche Richtung.

Nebenbei geprueft und in Ordnung: Der Installationshinweis am unteren
Rand verdeckt nichts dauerhaft; er schafft sich seinen Platz ueber ein
gemessenes padding-bottom (steht seit dem 23.08.2026 so drin, damals
blockierte er den Annehmen-Knopf).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 23:43:23 +02:00
DogFatherGitandClaude Opus 5 504965e875 Push-Zustand macht der Uebersicht keinen Platz mehr streitig
Ein Gesamtdurchlauf aller Suiten nach dem heutigen Tag hat vier
Fehlschlaege in pruef-handy.mjs gezeigt -- eine Regression aus meiner
eigenen Arbeit.

DIE URSACHE

Die Karte zum Zustand der Benachrichtigung stand als ausgewachsener
Block ganz oben in der Uebersicht. Auf dem Handy schob sie die erste
Kennzahl auf 513 Punkte nach unten: Man oeffnete die Verwaltung und sah
zuerst einen Hinweis, die Arbeit erst nach dem Scrollen.

ZWEI ANLAEUFE, WEIL DER ERSTE ZU KURZ SPRANG

Zuerst wurde nur der GUTE Fall zu einer Zeile. Das half nichts -- im
Pruefbrowser sind Benachrichtigungen blockiert, also griff weiterhin
der Zweig mit der grossen Karte. Eine Aenderung, die nur den Fall
behebt, den man gerade vor Augen hat, ist keine.

Jetzt sind alle drei Zustaende eine Zeile mit Punkt und Kurztext, die
Erklaerung erst beim Aufklappen. Und der gute Zustand steht am ENDE der
Uebersicht statt oben: Eine Bestaetigung, dass nichts zu tun ist,
gehoert nicht an den Anfang. Oben bleibt nur, was Handlung verlangt.

Ergebnis: 513 -> 204 Punkte bis zum Ende des Kopfbereichs, Laenge
2635 -> 2028.

DREI RUNDUNGSFAELLE

.wd-btn--klein und zwei summary-Elemente kamen mit Rahmen und
Zeilenhoehe auf 43,x Punkte. Der Test vergleicht mit "< 44", gibt aber
gerundet "44" aus -- man sucht dann einen Fehler in einer Zahl, die
richtig aussieht. Jetzt 44.5 bzw. 46; optisch aendert das nichts.

ZWEI PRUEFUNGEN PRAEZISIERT, NICHT AUFGEWEICHT

1. "Erste Zahl im oberen Drittel" mass ab dem Seitenanfang und schlug
   damit auch bei einer BERECHTIGTEN Warnung an. Ein Test, der
   Warnungen als Mangel zaehlt, erzieht dazu, sie zu verstecken. Er
   misst jetzt den festen Kopfbereich (Titel, Suche, Reiter) -- also
   das, was man nicht wegbekommt.

2. Die Folgepruefung mass zunaechst Punkte-Abstaende. Das war fragil:
   Der Reiterstreifen klebt beim Scrollen oben fest, eine Messung
   lieferte -204. Sie zaehlt jetzt HINWEISBLOECKE statt Punkte --
   unabhaengig von Scrollposition und Schriftgroesse. Gemeint war
   ohnehin "hoechstens eine Meldung", nicht "hoechstens 140px".

56/56 in pruef-handy, alle uebrigen Suiten unveraendert gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 23:01:12 +02:00
DogFatherGitandClaude Opus 5 1c3b3808ba Express 5: geprueft, aber noch nicht umgestellt
Der Sprung 4 auf 5 entfernt Methoden, aendert die Pfadsyntax
grundlegend (path-to-regexp 8) und stellt Standardwerte um. Vieles
davon faellt nicht beim Start auf, sondern erst, wenn eine bestimmte
Adresse aufgerufen wird -- also im Betrieb, bei einem Kunden. Deshalb
zuerst pruefen statt installieren.

ZWEI PRUEFUNGEN, DIE SICH ERGAENZEN

pruef-express5.mjs durchsucht 89 Dateien nach den Bruchstellen aus dem
offiziellen Migrationsleitfaden: entfernte Aufrufe (res.send(zahl),
req.param, app.del, res.sendfile), die UMGEDREHTE Reihenfolge bei
res.redirect, geaenderte Pfadsyntax ("/*" ohne Namen, ":a?"),
schreibgeschuetztes req.query, entfernte static-Optionen.

server/test-express5.mjs startet einen echten Server mit genau unserem
Aufbau: Middleware-Kette mit eigenen Kopfzeilen, cookieParser,
express.json, eine umleitende Schranke, express.static, ein Router mit
Parameter, 404- und Fehlerbehandlung.

ERGEBNIS

15 von 15 Kategorien unbedenklich, 10 von 10 Laufpruefungen bestanden
gegen express 5.2.1. Der Umstieg waere ohne Codeaenderung moeglich.

Ein Fehlalarm lag dabei im Pruefer selbst: Er meldete drei
req.body-Zugriffe als ungesichert, die in Wahrheit innerhalb eines
"if (typeof req.body?.feld === 'boolean')" stehen -- der Rueckblick war
mit 60 Zeichen zu kurz fuer den Block. Ein Pruefer, der abgesicherte
Stellen anmahnt, kostet die Zeit, die er sparen soll, und beim
naechsten Mal glaubt man ihm auch die echten Funde nicht mehr.

NICHT UMGESTELLT

Bewusst. Der Bestand ist sicherheitstechnisch sauber (npm audit: 0),
express 4.22.2 wird weiter gepflegt, und der Nutzen waere gering
gegenueber dem Risiko, zwei laufende Dienste anzufassen. Die Vorarbeit
liegt vor -- wenn umgestellt wird, dann als eigener Vorgang mit
anschliessendem Live-Test, nicht nebenbei.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 20:19:25 +02:00
DogFatherGitandClaude Opus 5 c03793b25f Oberflaeche fuer Auskunft und Loeschung
Sitzt im Kunden-Bereich, zugeklappt. Ein eigener Reiter waere zu
prominent fuer etwas, das man vielleicht zweimal im Jahr braucht --
ganz weglassen hiesse, im Ernstfall von Hand durch ein Dutzend
Tabellen zu suchen, bei laufender Monatsfrist.

DREI SCHRITTE, IN DIESER REIHENFOLGE

  Auskunft erstellen      unschaedlich, jederzeit
  Loeschvorschau          zeigt, was betroffen waere
  Loeschen                nur nach Vorschau, mit doppelter Eingabe

Die Auskunft laesst sich als Datei herunterladen, nicht nur ansehen.
Man muss sie der Person schicken koennen, und zwar vollstaendig --
abtippen waere der sicherste Weg, etwas zu vergessen. JSON, weil
Art. 20 DSGVO ein "gaengiges, maschinenlesbares Format" verlangt.

Die Vorschau zeigt beides getrennt: was geloescht wuerde, und was
bleiben muss -- mit Grund und mit dem Datum, ab dem es weg darf. Ohne
diese Angabe muesste man bei jeder Anfrage neu nachschlagen, welche
Frist gilt.

Vor dem Loeschen wird die Adresse ein zweites Mal verlangt. Der
Unterschied zwischen .de und .com ist ein Buchstabe, die Folge
unwiederbringlich.

GEPRUEFT

Im Handy-Format mit nachgebildeten Antworten: Auskunft zeigt die
Bereiche samt Kennzeichnung "aufbewahrungspflichtig", der
Herunterladen-Knopf erscheint, die Vorschau trennt richtig, eine
abweichende Bestaetigung wird abgelehnt. Kein Ueberlauf, keine
Skriptfehler. Die Handy-Suite bleibt bei 25/25, keine Namenskollision.

Ein Fehler lag dabei im Test selbst: Playwright prueft die ZULETZT
registrierte Route zuerst, und meine allgemeine Auffangregel
ueberdeckte die spezifischen. Die Auskunft meldete "nichts
gespeichert", obwohl die Oberflaeche richtig arbeitete.

Die Endpunkte dazu liegen in server-internal und brauchen noch einen
Deploy durch Filipe (/home/dogiintern, Rechte 700). Bis dahin meldet
die Oberflaeche einen 404 -- mit dem Hinweis, dass der Server einen
Neustart mit dem neuen Stand braucht, statt nur "Fehler" zu sagen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 20:03:35 +02:00
DogFatherGitandClaude Opus 5 7b09d752f8 Auskunft und Loeschung nach DSGVO (Art. 15/17)
Schreibt jemand "Welche Daten haben Sie ueber mich?" oder "Bitte
loeschen Sie meine Daten", laeuft eine Frist von einem Monat (Art. 12
Abs. 3 DSGVO). Bisher haette man dafuer von Hand durch ein Dutzend
Tabellen suchen muessen -- und uebersieht man eine, ist die Auskunft
unvollstaendig, ohne dass man es ihr ansieht.

⚠️ LOESCHEN IST NICHT EINFACH LOESCHEN

Der naheliegende Weg waere ein "Alles loeschen". Das waere bequem und
doppelt falsch: Rechnungen und Buchungsbelege unterliegen einer
gesetzlichen Aufbewahrungspflicht -- § 147 Abs. 3 AO nennt acht Jahre
fuer Buchungsbelege, zehn fuer Handelsbuecher, gerechnet ab dem Ende
des Kalenderjahres (Abs. 4). Wer sie auf Zuruf loescht, verstoesst
gegen Steuerrecht, um Datenschutzrecht zu erfuellen.

Die DSGVO nimmt diesen Fall selbst aus (Art. 17 Abs. 3 lit. b). Fuer
das, was bleiben muss, sieht sie die Einschraenkung der Verarbeitung
vor (Art. 18) -- genau so wird es ausgewiesen, samt Datum, ab dem
geloescht werden darf.

Dasselbe bei Widerrufserklaerungen: Sie sind der Nachweis, DASS und
WANN widerrufen wurde. Wer sie loescht, vernichtet seinen eigenen Beleg
in genau der Sache, in der es spaeter Streit geben koennte.

EIN FEHLER, DEN DER TEST VOR DEM ERSTEN LAUF GEFUNDEN HAT

Die Tabelle wd_widerrufe fuehrt die Adresse nicht als "email", sondern
als "kontakt". Die erste Fassung suchte nach "email" -- sie haette dort
NIE einen Treffer geliefert, und die Auskunft haette trotzdem sauber
ausgesehen. Aufgefallen nur, weil die Testdaten gegen das echte Schema
angelegt wurden statt gegen die Annahme.

Deshalb steht in der Quellenliste jetzt die Spalte, nicht eine
Vermutung.

WEITERE ENTSCHEIDUNGEN

- Die Suche geht ueber die Adresse UND ueber die Kundenkennung. Vieles
  haengt nicht an der Adresse; ohne diesen Schritt bliebe die halbe
  Auskunft leer.
- Gross- und Kleinschreibung spielt keine Rolle -- sonst bekaeme
  jemand eine leere Auskunft, weil er seine Adresse anders schreibt.
- Die Loeschung verlangt die Adresse ein zweites Mal. Der Unterschied
  zwischen .org und .com ist ein Buchstabe, die Folge unwiederbringlich.
- Sie laeuft in einer Transaktion: Bricht sie ab, bliebe sonst ein
  halbgeloeschter Bestand, und niemand wuesste, welcher Teil weg ist.
- Der Vorgang wird protokolliert, aber OHNE die geloeschten Inhalte --
  sie dabei erneut zu speichern waere das Gegenteil des Zwecks.

15 Pruefungen gruen, mit Gegenprobe (fremde Adresse liefert nichts).

Die Oberflaeche in der Verwaltung folgt. Deploy braucht Filipe:
server-internal liegt unter /home/dogiintern mit Rechten 700.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:55:05 +02:00
DogFatherGitandClaude Opus 5 ac1d5c9916 Waechter: Rechte wurden gesetzt, aber wirkten nicht
Nachgemessen: /var/lib/dogfather-waechter stand auf 755 -- weltweit
lesbar, mit einer vollstaendigen Liste aller Dienste, Adressen und
ihres Zustands darin. Also genau das, was der Commit von heute
Nachmittag verhindern sollte.

Die Absicht stand im Code, die Wirkung fehlte. Zwei Gruende, beide
still:

1. "mode" bei mkdirSync gilt nur, wenn das Verzeichnis dabei NEU
   entsteht. Beim zweiten Lauf existiert es immer -- dann laesst
   mkdirSync die Rechte unberuehrt. Hier war es sogar schon vor dem
   Einbau der Zeile angelegt worden.
2. Selbst beim Neuanlegen zieht die umask des Prozesses Bits ab.

Der Unterschied zur Sicherung ist lehrreich: /var/backups/dogfather
steht korrekt auf 700, weil dort ein ausdrueckliches chmod im Skript
steht. Dieselbe Ueberlegung, einmal umgesetzt und einmal nur gemeint.

Jetzt chmod bei jedem Lauf, fuer Verzeichnis UND Dateien.

Aufgefallen ist es nur, weil die Rechte nachgesehen wurden statt
angenommen -- der Code sah richtig aus.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:37:45 +02:00
DogFatherGitandClaude Opus 5 6077c1700f server-internal: package-lock.json aufgenommen
Nach der Installation auf dem Server vom dortigen Stand uebernommen --
nicht hier erzeugt. Das ist der entscheidende Unterschied: Eine lokal
erzeugte Datei haette festgeschrieben, was HIER aufgeloest wird, nicht
was dort tatsaechlich laeuft. Genau diese Luecke sollte sie ja
schliessen.

Festgeschrieben sind jetzt:

  multer          2.2.0   (war 1.4.5-lts.1, veraltet)
  node-cron       4.6.0   (war 3.0.3)
  express         4.22.2  (package.json sagt ^4.21.2)
  better-sqlite3  11.10.0
  dotenv          16.6.1
  cors            2.8.6

express 4.22.2 zeigt, warum das noetig war: Die package.json erlaubt
alles unter 5.0, installiert war eine andere Fassung als die genannte.

uuid taucht in der Liste nicht mehr auf. Es kam ausschliesslich ueber
node-cron 3.x herein und war die einzige Luecke, die "npm audit"
gefunden hatte. Gegenprobe nach der Umstellung: "found 0
vulnerabilities". Auch die Veraltet-Markierung von multer ist weg.

Der Dienst laeuft stabil (PID unveraendert ueber mehrere Messungen,
keine zusaetzlichen Neustarts) und antwortet mit 401 -- er lebt also
und prueft Rechte.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:35:59 +02:00
DogFatherGitandClaude Opus 5 a2487212c8 multer 2.x und node-cron 4.x: geprueft, package.json angehoben
multer 1.4.5-lts.1 ist von den Betreuern ausdruecklich als veraltet
markiert. Die Meldung der Registry, woertlich:

  "Multer 1.x is impacted by a number of vulnerabilities, which have
   been patched in 2.x. You should upgrade to the latest 2.x version."

⚠️ BEMERKENSWERT: "npm audit" meldet dazu NICHTS. Die Pruefung nannte
nur eine Luecke in uuid, eingeschleppt ueber node-cron 3.x. Wer sich
allein auf audit verlaesst, haette multer fuer unbedenklich gehalten.
Die Deprecation-Meldung ist hier die eigentliche Warnung -- sie steht
aber an einer Stelle, an die man nur kommt, wenn man gezielt nachfragt.

2.0.0 behebt CVE-2025-47935 und CVE-2025-47944. Einzige dokumentierte
Breaking Change: Node ab 10.16. Auf dem Server laeuft 24.

node-cron 4.x behebt die uuid-Luecke. Die Fassung ist eine Umstellung
auf TypeScript, ohne dokumentierte API-Aenderung -- genau dabei aendert
sich aber gern die Art des Standard-Exports, und "import cron from
'node-cron'" wuerde danach beim START scheitern, nicht bei der
Installation.

GEPRUEFT STATT ANGENOMMEN

In einem eigenen Verzeichnis gegen multer 2.2.0 und node-cron 4.6.0
getestet, mit genau den Aufrufen aus index.js: diskStorage mit
destination/filename, limits, fileFilter, single/array/fields,
MulterError samt code, cron.schedule("* * * * *") und task.stop().
15 von 15 bestanden.

Die Pruefung liegt jetzt als server-internal/test-pakete.mjs im Projekt
-- die Frage "laeuft unser Code damit noch?" stellt sich bei jedem
Hauptversionswechsel neu.

Express bleibt bewusst bei 4.x. Der Sprung auf 5 ist ein eigener
Vorgang mit deutlich mehr Flaeche; ihn hier mitzunehmen wuerde zwei
unabhaengige Risiken in einem Schritt buendeln.

Die Installation selbst braucht Filipe: server-internal liegt unter
/home/dogiintern mit Rechten 700.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:30:58 +02:00
DogFatherGitandClaude Opus 5 f64403aea8 package-lock.json wird versioniert (server/)
Ohne Lock-Datei darf jede Installation andere Fassungen ziehen:
"^4.21.2" erlaubt alles unter 5.0. Auf dem Server laeuft deshalb
express 4.22.2, waehrend in der package.json 4.21.2 steht -- geprueft
wird also nie genau das, was ausgeliefert wird. Solche Unterschiede
fallen nicht beim Deploy auf, sondern im Betrieb, und dann sucht man
den Fehler im eigenen Code.

WARUM SIE AUSGESCHLOSSEN WAR

Ein "git pull" auf dem Server scheiterte daran: Git ueberschreibt keine
unverfolgte Datei -- unabhaengig davon, ob ihr Inhalt derselbe ist. Der
Ausschluss hat den Deploy repariert und dabei den Zweck der Datei
beseitigt.

Nachgemessen statt vermutet: Die Datei hier und die auf dem Server sind
Byte fuer Byte identisch (SHA-256 a50b028d…). Es gab also nie einen
inhaltlichen Konflikt, nur einen formalen. Er loest sich, indem die
Datei einmal vom Server entfernt und danach aus dem Repo geholt wird.

DEPLOY.md ergaenzt: auf dem Server "npm ci" statt "npm install". ci
loescht node_modules vorher und baut streng nach der Lock-Datei; es
schreibt sie nie um und bricht ab, wenn sie nicht zur package.json
passt -- statt still etwas anderes zu installieren.

server-internal/ folgt, sobald die dortige Lock-Datei vorliegt. Dieses
Verzeichnis liegt unter /home/dogiintern mit Rechten 700.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:26:40 +02:00
DogFatherGitandClaude Opus 5 ea11cefe17 Verwaltung auf dem Handy: vier Fehler behoben
Geprueft mit nachgebildeten Daten -- lange Firmennamen, lange
E-Mail-Adressen, mehrstellige Betraege. Eine leere Seite laeuft nie
ueber; die Fehler, um die es geht, entstehen erst mit Inhalt.

1. DAS RASTER DER KOPFZEILE WAR BREITER ALS SEIN BEHAELTER

Auf 390px summierten sich die beiden Spalten auf 372,7px, waehrend die
Leiste nur 358px breit ist. Rasterspalten schrumpfen von sich aus nicht
unter ihren Inhalt ("min-width: auto"). Alles darin schob sich nach
rechts hinaus: die Kopfzeile 8px, der Reiterstreifen 12px.

Sichtbar war das kaum -- der Streifen ist ohnehin wischbar, rechts
fehlte nur ein Stueck Rand. Genau deshalb blieb es liegen: ein Fehler,
der sich als Eigenart tarnt. Jetzt minmax(0, …) plus min-width: 0 an
den Kindern; lange Titel kuerzen mit Auslassungspunkten, statt zu
schieben.

2. DER INSTALLATIONSHINWEIS ZEIGTE DAS FALSCHE SYMBOL

Seit die Verwaltung eine eigene App ist, stand dort weiter der schwarze
Husky. Man las "Als App installieren" neben dem einen Bild und bekam
das andere auf den Startbildschirm. Das Symbol wird jetzt aus dem
Manifest abgeleitet, das die Seite tatsaechlich einbindet -- damit
stimmt es auch fuer jede kuenftige App, ohne dass jemand daran denken
muss.

3. DIE UEBERSICHT BRACH BEI UNVOLLSTAENDIGER ANTWORT AB

d.projekte und d.verlauf wurden ungeprueft mit .length angefasst,
waehrend drei andere Felder ausdruecklich geprueft wurden. Fehlte eine
der Listen, brach die Uebersicht mit "Cannot read properties of
undefined" ab -- und zwar NACH dem Aufbau der oberen Kacheln: Die halbe
Seite stand da, der Rest fehlte kommentarlos. Genau der Fall, den der
Kommentar daneben als "realistisch" beschreibt. Jetzt wird aufgefuellt
statt abgebrochen.

4. ZWEI FEHLALARME IM TEST SELBST

Der Test meldete den Reiterstreifen als Ueberlauf (er ist ein
Wischstreifen -- dass dort etwas ausserhalb liegt, ist sein Sinn) und
eine 1x1-Checkbox als zu kleines Tippziel (bedient wird sie ueber ihr
Label, 315x162 Punkte). Beides wuerde dazu verleiten, Funktionierendes
"zu reparieren". Der Test unterscheidet das jetzt.

Ebenso meldete er "Strg" und "Enter" mit 10,4px -- beide sind auf
schmalen Schirmen laengst ausgeblendet. getComputedStyle liefert auch
fuer verborgene Elemente eine Schriftgroesse; jetzt zaehlt nur
Sichtbares.

25 Pruefungen ueber sechs Bereiche gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 19:09:33 +02:00
DogFatherGitandClaude Opus 5 62cbd724e2 Manifest der Verwaltungs-App an der Zugangswand freigeben
Beim ersten Live-Test war die App nicht installierbar: Symbole 200,
Manifest 302.

Die Zugangswand hat eine Ausnahmeliste fuer App-Bausteine -- sw.js und
app.webmanifest stehen ausdruecklich darin, mit einer ausfuehrlichen
Begruendung aus dem Universe. Das neue Manifest fehlte schlicht.

Der Grund gilt hier sogar staerker als bei der oeffentlichen App: Die
Verwaltung liegt IMMER hinter der Schranke. Ohne Freigabe bekommt der
Browser statt des Manifests eine Umleitung auf zugang.html, also HTML
statt JSON -- und bietet "App installieren" gar nicht erst an.

Unbedenklich: Das Manifest enthaelt Name, Farben, Symbolpfade und drei
Verknuepfungen. Keine Kunden-, Projekt- oder Preisdaten. Wer es liest,
erfaehrt, dass es eine Verwaltung gibt -- was die Zugangswand ohnehin
verraet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 16:13:40 +02:00
DogFatherGitandClaude Opus 5 1608521854 Verwaltung ist jetzt eine eigene App
Wunsch: "ich will die verwaltungsseite auch getrennt runter laden
koennen und installieren koenne."

Bisher gab es ein Manifest fuer den ganzen Webdesign-Bereich; die
Verwaltung war darin nur eine Verknuepfung. Jetzt hat sie ein eigenes
mit eigener "id" -- der Wert, an dem alles haengt: Ohne ihn halten
Browser beide fuer dieselbe App, und die zweite Installation
ueberschreibt die erste, statt danebenzustehen.

EIGENES SYMBOL

Zwei gleich aussehende Kacheln auf dem Startbildschirm waeren keine
Trennung. Das neue Symbol ist ein Ausschnitt des Eiskristall-Wappens --
dasselbe Motiv, das die Verwaltung ohnehin traegt, und klar
unterscheidbar vom schwarzen Husky der oeffentlichen App. Erzeugt aus
cryo-wappen.webp in drei Groessen, die beschneidbare Fassung weiter
herausgezoomt, damit Android die Spitzen des Wappens nicht abschneidet.

Als JPEG statt PNG: 76 statt 385 KB bei 512 Punkten. Bei einem
fotografischen Motiv hat PNG nichts zu gewinnen, und 385 KB fuer ein
Symbol waeren unverhaeltnismaessig.

⚠️ DER GELTUNGSBEREICH IST ABSICHTLICH WEIT

Naheliegend waere "/webdesign/verwaltung" gewesen. Das haette die App
unbrauchbar gemacht: Ohne gueltigen Ausweis leitet der Server auf
/webdesign/zugang.html um -- ausserhalb des Bereichs, und was
ausserhalb liegt, oeffnet der Browser in einem eigenen Fenster. Weil
der Zugang beim Schliessen endet, waere das bei fast jedem Start
passiert: Man tippt auf die App und landet im Browser. Nachgemessen:
verwaltung.html antwortet ohne Ausweis mit 302.

EIN STILLES VERSPRECHEN EINGELOEST

Die Verknuepfungen zeigen auf "?bereich=anfragen" und dergleichen --
und derselbe Parameter steht in den Push-Meldungen. Ausgewertet hat ihn
bisher NIEMAND. Man landete immer auf der Uebersicht, ohne dass etwas
kaputt aussah. Jetzt oeffnet die Seite den gewuenschten Reiter, ueber
einen ausgeloesten Klick auf den vorhandenen Reiter statt ueber
nachgebaute Logik: Daran haengen Signatur, Leuchtbalken, Nachladen und
der Wischstreifen auf dem Handy.

Auch hier hat erst der Test den Fehler gezeigt -- und danach einen in
der Pruefung selbst: Sie erreichte die Funktion gar nicht, weil diese
im gekapselten Bereich liegt. Jetzt nach aussen gegeben, wie schon
window.vwBalkenSetzen.

23 Pruefungen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 16:12:35 +02:00
DogFatherGitandClaude Opus 5 92d2b568de Pruefung auf doppelte Funktionsnamen — und ein zweiter Fund
Die Kollision von heute war weder fuer den Browser noch fuer einen
Syntaxpruefer sichtbar: Zwei Funktionen desselben Namens sind erlaubtes
JavaScript, die spaetere gewinnt lautlos. Auch die
Oberflaechen-Tests schwiegen -- sie pruefen, ob Kacheln DA sind, nicht
ob sinnvoller Text darin steht.

pruef-namenskollision.mjs durchsucht jetzt alle 110 Dateien mit eigenem
JavaScript. Mit Gegenprobe, damit die Pruefung nicht selbst kaputtgehen
und dabei "sauber" melden kann.

ZWEITER FUND, AELTER ALS MEIN FEHLER

Sie meldete sofort eine weitere Kollision: tageSeit stand zweimal in
verwaltung.html. Beide rechneten dasselbe, mit einem Unterschied -- bei
fehlendem Datum gab die eine null zurueck, die andere 0.

Die spaetere (mit 0) gewann. Damit war die frueher definierte
wirkungslos, und mit ihr die Pruefungen "if (t === null) return ''" in
altersText und dringlichkeit: Ohne Datum stand dort "seit heute" statt
gar nichts.

Entfernt wurde die spaetere. Die beiden verbliebenen Aufrufer vertragen
null genauso wie 0 -- nachgeprueft, nicht angenommen: Math.max(x, null)
ergibt x, und null >= 7 ist falsch, gleich wie bei 0.

110 Dateien jetzt sauber.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:58:12 +02:00
DogFatherGitandClaude Opus 5 0e8c1447f2 DRINGEND: Namenskollision zerstoerte die Uebersicht
Alle Kacheln der Uebersicht zeigten "[object Object]" und "undefined".

Ursache war mein Push-Code von heute. Er brachte eine Hilfsfunktion
namens kachel(titel, inhalt, art) mit -- und weiter oben in derselben
Datei gibt es seit langem kachel(o), die die Uebersichtskacheln baut.

JavaScript kennt keine Ueberladung. Steht spaeter eine zweite Funktion
desselben Namens im selben Gueltigkeitsbereich, gewinnt sie. Ohne
Warnung, ohne Fehlermeldung, ohne dass irgendein Werkzeug anschlaegt.
Danach bekam jede Uebersichtskachel mein Objekt als ersten Parameter
und gab es als Zahl aus.

Besonders tueckisch: Die Push-Karte selbst funktionierte einwandfrei --
sie steht ja unmittelbar ueber den kaputten Kacheln. Der sichtbare
Schaden lag weit weg von seiner Ursache, und nichts deutete auf den
neuen Code hin.

Die Funktion heisst jetzt pushKachel und sagt damit, wozu sie gehoert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:55:31 +02:00
DogFatherGitandClaude Opus 5 77b395e2b4 Test: laesst den Service Worker jetzt wirklich arbeiten
Die Luecke, durch die der Fehler von heute bis zum Benutzer
durchgerutscht ist.

Der Test hat 48 Seiten in einem echten Browser geoeffnet und nichts
bemerkt -- weil er den Service Worker nie hat arbeiten lassen. Er war
gruen und wertlos zugleich: Der entscheidende Weg wurde nicht
begangen.

Neu geprueft wird jetzt:
  - der Service Worker meldet sich an und wird aktiv
  - er darf tatsaechlich etwas abrufen (das war der kaputte Punkt)
  - dabei entsteht kein Richtlinien-Verstoss
  - sw.js traegt selbst KEINE Richtlinie, denn sie wuerde zu SEINER

Ausserdem umgedreht: Ein Test verlangte fuer Nicht-Seiten ausdruecklich
"default-src 'none'" -- und sicherte damit genau den Fehler ab, der die
App lahmlegte. Er haette den naechsten Versuch, es richtig zu machen,
als Fehler gemeldet. Jetzt wird geprueft, dass CSS, JavaScript, Bilder
und der Service Worker KEINE Richtlinie bekommen.

22 Pruefungen gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:47:10 +02:00
DogFatherGitandClaude Opus 5 0f253df134 Service Worker: Versionsnummer in der Adresse gegen fremden Cache
Bei der Fehlersuche zur lahmgelegten App kam ein zweiter, aelterer
Mangel zum Vorschein.

GEMESSEN

  Dienst selbst    Cache-Control: no-cache
  nach Cloudflare  Cache-Control: max-age=14400  (auch bei MISS)

Cloudflare ersetzt die Vorgabe des Servers durch vier Stunden. Ursache
ist eine feste "Browser Cache TTL" in den Einstellungen. Der Kommentar
in server/index.js behauptet das Gegenteil ("Cloudflare respektiert
laut Doku ein vom Origin gesetztes Cache-Control") -- fuer diese Domain
stimmt das nicht. Nachgemessen, nicht vermutet.

WARUM DAS MEHR ALS EIN SCHOENHEITSFEHLER IST

Jede Aenderung am Service Worker erreicht die Geraete bis zu vier
Stunden zu spaet. Solange alles laeuft, faellt das nicht auf. Ist der
ausgelieferte Stand aber fehlerhaft -- wie heute, als eine zu strenge
Inhaltsrichtlinie ihn lahmlegte und die App "Keine Verbindung" zeigte
--, sind es vier Stunden, in denen sich nichts reparieren laesst.
Genau dann, wenn Tempo zaehlt, ist man am langsamsten.

LOESUNG OHNE FREMDE EINSTELLUNGEN

Die Registrierung laedt jetzt "/webdesign/sw.js?v=56". Aendert sich die
Nummer, ist es eine andere Adresse -- dafuer kann kein Zwischenspeicher
einen alten Stand haben. Die Nummer wird zusammen mit CACHE_NAME
hochgezaehlt; beide gehoeren zusammen und stehen jetzt auf 56.

Das wirkt unabhaengig davon, wie Cloudflare eingestellt ist. Die
Einstellung selbst sollte trotzdem geprueft werden -- sie betrifft auch
CSS und JavaScript.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:43:45 +02:00
DogFatherGitandClaude Opus 5 c591925342 DRINGEND: Inhaltsrichtlinie legte die App lahm
Symptom: Die installierte App zeigte "Keine Verbindung", obwohl die
Seite online war, der Server lief und jede Pruefung Erfolg meldete.

Ursache war meine eigene Zeile von heute Vormittag. Fuer alles, was
keine Seite ist, setzte die Middleware "default-src 'none'" -- mit dem
Gedanken "kostet nichts und schadet nie". Der zweite Halbsatz war
falsch.

Ein Service Worker uebernimmt die Inhaltsrichtlinie, die beim
Herunterladen SEINER EIGENEN Skriptdatei gesetzt war, nicht die der
Seite, fuer die er arbeitet. sw.js ist keine Seite, bekam also 'none'
und durfte damit nichts mehr abrufen. Jede Anfrage scheiterte -- und
weil der Service Worker fuer genau diesen Fall eine Offline-Seite
bereithaelt, sah es aus wie ein Netzausfall beim Benutzer.

Fuer Bilder, Stylesheets und Schriften bringt eine Richtlinie ohnehin
nichts: Sie steuert, was ein DOKUMENT nachladen darf. Ein Bild laedt
nichts nach. Dem Schaden stand also nie ein Gewinn gegenueber.

Jetzt: Richtlinie nur noch fuer HTML-Dokumente.

Warum der Test das nicht gefunden hat, folgt gleich -- er hat die
Seiten geladen, aber nie den Service Worker arbeiten lassen. Genau die
Luecke, durch die es durchgerutscht ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:41:27 +02:00
DogFatherGitandClaude Opus 5 b2f4567cce Waechter: leere Geraeteliste und fehlende Tabelle unterscheiden
Der erste echte Probelauf meldete "kein Geraet angemeldet". Richtig --
aber dieselbe Meldung waere auch erschienen, wenn die Tabelle gar nicht
existierte, weil dbLesen in beiden Faellen "" zurueckgibt.

Das sind zwei voellig verschiedene Lagen: Einmal genuegt ein Klick in
der Verwaltung, einmal ist die Migration nicht gelaufen. Wer die falsche
Meldung liest, drueckt auf Einschalten, sieht keine Wirkung und sucht
dann beim Browser statt bei der Datenbank.

Genau die Sorte Verwechslung, gegen die dieser ganze Strang gebaut
wurde. Jetzt wird zuerst gefragt, ob die Tabelle da ist, und die Meldung
sagt im harmlosen Fall auch gleich, was zu tun ist.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:38:11 +02:00
DogFatherGitandClaude Opus 5 bcf6e01fa9 Waechter: engere Dateirechte und ein Probeschalter
Der erste automatische Lauf war erfolgreich (14:20, 18 Punkte, 0
auffaellig). Zwei Nachtraege:

RECHTE

Zustandsdatei und Protokoll lagen mit 644 in einem 755-Verzeichnis.
Personenbezogene Daten stehen dort keine -- wohl aber eine
vollstaendige Liste aller Dienste, Adressen und ihres Zustands. Fuer
jemanden, der einen Angriff vorbereitet, ist das eine bequeme
Landkarte. Jetzt 700/600. Kostet nichts, also gibt es auch keinen
Grund, es herzugeben.

PROBESCHALTER

  node waechter.mjs --probe

Verschickt eine Meldung, ohne dass etwas kaputt sein muss. Das ist die
einzige Moeglichkeit, den MELDEWEG zu pruefen, ohne auf eine echte
Stoerung zu warten.

Der Grund ist derselbe wie beim stillen "if (!url) return;", das diese
Reihe ausgeloest hat: Eine Ueberwachung, deren Zustellung
stillschweigend nicht funktioniert, ist schlimmer als gar keine. Man
haelt die Stille dann fuer "alles in Ordnung" -- dabei ist sie nur
Stille.

Steht bewusst VOR den Messungen: Wer den Meldeweg pruefen will, soll
nicht erst 18 Punkte abfragen muessen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:21:08 +02:00
DogFatherGitandClaude Opus 5 3a5805bfad Waechter: meldet Ausfaelle, statt sie unbemerkt zu lassen
Der Befund war besser als der Aufgabentitel: Alle Dienste haben
Restart=always und stehen nach einem Absturz von selbst wieder auf. Die
Luecke liegt woanders:

  - Dauerschleife: Startet ein Dienst und stuerzt sofort wieder ab, gibt
    systemd nach wenigen Versuchen auf. Dann bleibt er unten.
  - "active" heisst nicht "antwortet". Ein haengender Dienst gilt
    systemd als gesund.
  - Zertifikatsablauf und volle Platte machen keinen Dienst inaktiv,
    legen aber alles lahm.

Geprueft werden 18 Punkte: sechs Dienste, neun Adressen, Plattenplatz,
zwei Zertifikatslaufzeiten.

WARUM ALS ROOT PER CRON

Ein Waechter, der ueber den internen Dienst meldet, hat einen
Konstruktionsfehler mit Ansage: Ausgerechnet wenn DIESER Dienst das
Problem ist, kaeme keine Meldung durch. Also liest er .env und Datenbank
selbst und verschickt selbst -- unabhaengig davon, ob noch irgendetwas
laeuft. Ohne Fremdpakete, nur Node-Bordmittel, sqlite3 und systemctl.

NUR BEI ZUSTANDSWECHSEL

Gemeldet wird, wenn etwas kippt -- in beide Richtungen. Nicht alle fuenf
Minuten dasselbe. Wer staendig Meldungen bekommt, sieht irgendwann keine
mehr an und uebersieht die eine, auf die es ankam.

ZWEI EIGENE FEHLER, DIE DER TEST GEFUNDEN HAT

1. Zuerst stand je Adresse eine handgepflegte Liste erlaubter
   Antwortcodes. Der erste Lauf meldete VanVans Shop als ausgefallen --
   er war es nicht, er steht ebenfalls hinter einer Zugangswand und
   antwortet mit 302. Ich war damit genau in die Falle gelaufen, vor der
   der Kommentar an derselben Stelle warnte.

2. Danach galt "unter 400" als heil. Jetzt meldete das Postfach einen
   Ausfall, weil die geprueften Adresse 404 lieferte -- der Dienst lief
   einwandfrei, ich hatte die Adresse falsch gewaehlt.

Beide Male dieselbe Lehre: Eine Ueberwachung, die bei einer falsch
getippten Adresse "Ausfall" ruft, erzieht einen dazu, ihre Meldungen zu
ignorieren. Die Regel lautet jetzt "unter 500", denn der Waechter fragt
"lebt der Dienst?", nicht "ist der Inhalt richtig?". 401, 403 und 404
BEWEISEN, dass jemand da ist und zuhoert. Nur 5xx und Schweigen heissen,
dass dahinter nichts mehr laeuft. Ausnahme sind die beiden Pflichtseiten
Impressum und Widerruf -- dort ist alles ausser 200 bereits ein Mangel.

GEPRUEFT AM SERVER

Ausfall eingebaut: erkannt und gemeldet. Ausfall dauert an: still, keine
Wiederholung. Wieder erreichbar: Entwarnung. 18 Punkte, 0 Fehlalarme
ueber mehrere Laeufe.

⚠️ GRENZE, DIE BLEIBT

Ist der Server als Ganzes weg -- Netz, Strom, Hardware --, meldet auch
dieser Waechter nichts. Dagegen hilft nur eine Ueberwachung ausserhalb
der Maschine. Steht so im Kopf der Datei, damit sich niemand in falscher
Sicherheit wiegt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:17:12 +02:00
DogFatherGitandClaude Opus 5 03a533f143 Inhaltsrichtlinie (CSP): mit Pruefsummen statt mit unsafe-inline
Fuenf Schutz-Kopfzeilen waren gesetzt, die wichtigste fehlte. Sie
entscheidet als einzige darueber, ob eingeschleuster Text zu
ausgefuehrtem Code wird oder sichtbarer Text bleibt.

WARUM NICHT DER BEQUEME WEG

Ueblich waere script-src 'self' 'unsafe-inline'. Eine Zeile, nichts geht
kaputt -- und der Schutz ist weg: Der Browser kann nicht unterscheiden,
ob ein Skript im Seitentext vom Entwickler stammt oder von einem
Angreifer. Das Ergebnis ist eine Kopfzeile, die gut aussieht und im
Ernstfall nichts tut.

Der Bestand liess den sauberen Weg zu: keine fremden Skriptquellen,
keine externen Schriften, ein Inline-Block je Seite. Von jedem Block
wird die Pruefsumme gebildet.

DIE PRUEFSUMMEN STEHEN BEWUSST NICHT IM CODE

Das waere hier eine Falle mit Ansage: Statische Dateien gehen per "git
pull" live, OHNE Neustart. Eine fest hinterlegte Summe waere nach der
naechsten Textaenderung falsch -- und die Seite wuerde ihr eigenes
Skript nicht mehr ausfuehren. Sichtbar erst im Browser des Besuchers,
nicht beim Deploy, und aussehend wie kaputtes JavaScript.

Deshalb liest die Middleware die Datei selbst und merkt sich das
Ergebnis, solange die Aenderungszeit gleich bleibt. Ein Test aendert
index.html im laufenden Betrieb und prueft, dass die Summe nachzieht
und die Seite weiterlaeuft.

WAS DER TEST GEFUNDEN HAT

Die erste Fassung haette die Startseite und stimmen.html beschaedigt:
Team-Fotos, Event des Jahres und die Stimmen kommen von der
postfach-Subdomain, img-src erlaubte nur 'self'. Der Deploy haette
Erfolg gemeldet, der Server waere gestartet -- und die Bilder waeren
weg gewesen. Gefunden, weil der Test alle 48 Seiten in einem echten
Browser oeffnet und mitschreibt, was blockiert wird.

Ein zweiter Fehlschlag lag am Test selbst: Er verlangte eine Pruefsumme
auf jeder Seite, auch auf denen ohne Inline-Block. Ein Test, der
Unmoegliches fordert, wird frueher oder spaeter abgeschaltet -- er
unterscheidet jetzt nach dem tatsaechlichen Inhalt der Datei.

DREI onclick-ATTRIBUTE ENTFERNT

Sie haetten 'unsafe-inline' erzwungen. Zweimal ein "Coming soon"-Knopf,
dessen onclick nur Klicks abfing -- ein <a> ohne href tut das von
selbst, ganz ohne Skript. Einmal ein Schliessen-Knopf im
Verwaltungsbereich, jetzt mit angehaengtem Zuhoerer.

GEGENPROBE

Ohne sie waere der Rest wertlos: Eine Richtlinie, die alles erlaubt,
blockiert auch nichts und besteht jede Pruefung. Der Test schleust
deshalb echten Code ein -- ein Inline-Skript und eines von fremder
Adresse -- und beide muessen scheitern.

style-src behaelt 'unsafe-inline': 587 style-Attribute im Bestand, deren
Umbau ein echtes Risiko fuers Aussehen waere, bei kleinem Gewinn. Ueber
Stile laesst sich verschleiern und ueberdecken, aber kein Code
ausfuehren. Bleibt als eigener Punkt auf der Liste.

15 Pruefungen gruen, 48 Seiten sauber, Portfolio-Suite unveraendert 35.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 14:05:42 +02:00
DogFatherGitandClaude Opus 5 094a69732b Portfolio: Spicy SafeAddress als sechstes Projekt
Die Rechtsplattform der Spicy Media Agency fehlte -- dabei ist sie das
technisch anspruchsvollste Stueck der Sammlung.

WAS IM TEXT STEHT UND WARUM SO

Die Projektdokumentation haelt ausdruecklich fest, dass die Wendung
"100 Prozent rechtssicher" dort nirgends verwendet wird. Ein Portfolio,
das mehr verspricht als die Sache selbst, waere genau der Fehler, den
das Projekt vermeiden will. Im Ergebnis steht deshalb, dass die
Plattform fertig gebaut und bewusst noch vollstaendig gesperrt ist und
auf die schriftliche Freigabe einer Fachkanzlei wartet -- nicht, dass
sie "im Einsatz" sei.

KEIN LIVE-KNOPF

Wie bei der Buchhaltung. Ein "Live ansehen", das auf eine Zugangswand
fuehrt, bricht das Versprechen, das der Knopf gibt. Stattdessen steht
dort ein Satz, der den Grund nennt.

GESICHTER UNKENNTLICH

Auf der Zugangswand stehen zwei Profilfotos. Eines davon gehoert einer
Geschaeftspartnerin, die dieser Veroeffentlichung nicht zugestimmt hat.
Beide sind in der Aufnahme weichgezeichnet, das Firmenzeichen bleibt
scharf. Begruendet im alt-Text und in einem eigenen Abschnitt -- genau
wie bei Projekt 5, wo derselbe Fall schon einmal auftrat.

Nebenbei: Die strenge Inhaltsrichtlinie der Seite (style-src 'self')
hat das eingefuegte Stylesheet fuers Weichzeichnen blockiert. Sie tut
also genau das, wofuer sie da ist. Ueber die Stil-Eigenschaft im Skript
ging es dann.

ZWEI STELLEN, DIE SONST FALSCH GEBLIEBEN WAEREN

Die Ueberschrift hiess "Fuenf Projekte, die man anfassen kann". Mit
SafeAddress steht dort erstmals ein Projekt, das man NICHT besuchen
kann -- die Ueberschrift haette also gleich doppelt daneben gelegen.
Jetzt: "Sechs Projekte, die es wirklich gibt", und die Einleitung sagt
ausdruecklich, dass eine der Seiten gesperrt ist.

Der Schlussaufruf lud dazu ein, "das sechste" Projekt zu werden. Bei
sechs vorhandenen waere das das Angebot gewesen, eines davon zu
ersetzen. Jetzt das siebte.

Beides in allen fuenf Sprachen, de-CH als echter Dialekt wie im Rest
dieser Datei.

TEST

Zwei Fehlschlaege, beide berechtigt: die Projektzahl und ein zu grobes
Suchmuster, das bei "zwei MENSCHEN" ansprang, obwohl es die veraltete
Aussage "zwei PROJEKTE" sucht. Das Muster laesst jetzt hoechstens ein
Wort zwischen Zahlwort und Substantiv zu. Mit Gegenprobe abgesichert:
faengt weiterhin "Two projects you can visit", ignoriert "Two people
work together on that site". Ein Fehlalarm, den man nur wegdrueckt,
faengt beim naechsten Mal auch den echten Fall nicht mehr.

35 Pruefungen gruen, i18n vollstaendig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 12:19:50 +02:00
DogFatherGitandClaude Opus 5 bad5496adc Portfolio: Buchhaltungsseite mit dem aktuellen Stand zeigen
Das bisherige Bild zeigte eine fruehere Fassung der Anmeldeseite --
flaches Logo als blasses Wasserzeichen, Text darueber, keine
Anmeldekarte. Die Seite ist inzwischen ueberarbeitet: plastisches Logo,
Samthintergrund, eine eigene Anmeldekarte mit den beiden Zugaengen und
dem Hinweis auf verschluesselte Verbindung.

Ein Portfolio, das einen alten Stand zeigt, arbeitet gegen sich selbst
-- gerade wenn die neue Fassung die deutlich bessere ist.

Neu aufgenommen in 1200x750, also exakt den Massen der uebrigen
Portfolio-Bilder. Das steht auch als width/height im <img>; eine
Abweichung wuerde beim Laden ein Springen des Rasters ausloesen und die
Kacheln unterschiedlich hoch machen.

154 KB statt 49 KB. Der Aufschlag ist nicht zu vermeiden: Das Motiv ist
jetzt fotorealistisch, mit Samtfalten und Perlen -- lauter feine
Strukturen, bei denen JPEG wenig einsparen kann. Bei Qualitaet 76 waeren
es 132 KB gewesen, um den Preis sichtbarer Artefakte im Logo. Das Bild
laedt ohnehin verzoegert (loading="lazy").

Cache-Version auf v53: Ohne das bekaemen alle, die die Seite schon
einmal geoeffnet haben, weiterhin das alte Bild aus dem Zwischenspeicher.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 11:42:11 +02:00
DogFatherGitandClaude Opus 5 f435d89a16 Benachrichtigung bei neuer Anfrage: Push aufs Handy
BEFUND ZUERST, DENN ER WAR ANDERS ALS ERWARTET

Es gab sehr wohl eine Benachrichtigung -- ueber einen Discord-Webhook,
sauber gebaut, bewusst ohne Kundendaten im Text. Sie begann aber mit:

    const url = process.env.DISCORD_WEBHOOK_WEBDESIGN;
    if (!url) return;

Und diese Variable ist in .env.example nirgends aufgefuehrt. Eine
Variable, die niemand kennt, wird nicht gesetzt; dann kehrte die
Funktion wortlos zurueck. Kein Fehler, keine Protokollzeile. Es gab
eine Benachrichtigung, die nur im Quelltext existierte -- und niemand
konnte das bemerken, weil "funktioniert" und "kaputt" identisch
aussehen, solange nichts passiert.

WAS JETZT DA IST

Push aufs Handy, ohne Fremdpaket. Der interne Dienst liegt unter
/home/dogiintern mit Rechten 700 -- dort ist kein npm erreichbar, jede
Abhaengigkeit haette dauerhafte Handarbeit bedeutet. Node bringt P-256,
HKDF und AES-128-GCM selbst mit.

Die Schluessel erzeugt der Server beim ersten Start selbst und legt den
privaten Teil verschluesselt in der Datenbank ab (derselbe Weg wie die
PayPal-Zugangsdaten). Damit gibt es keinen Einrichtungsschritt, der
vergessen werden kann.

GEPRUEFT

Gegen RFC 8291 statt gegen ein Bauchgefuehl: alle fuenf Zwischenwerte
aus Anhang A stimmen (ECDH-Geheimnis, PRK_key, IKM, CEK, NONCE), und
die fertige Nachricht ist Byte fuer Byte die aus Abschnitt 5 der Norm.
Bei Kryptographie erzeugt ein Ableitungsfehler keinen Absturz, sondern
Bytes, die genauso zufaellig aussehen wie richtige.

Dazu ein Kettentest mit einem echten Empfaenger, der entschluesselt:
Kopfzeilen, Inhalt, keine Kundendaten in der Meldung, 410 loescht das
Geraet, 500 loescht es NICHT (sonst kostet eine einzelne Stoerung die
Anmeldung). 50 Pruefungen, alle gruen.

DREI ENTSCHEIDUNGEN

1. In der Meldung stehen nur Nummer und Paket. Sie erscheint auf einem
   Sperrbildschirm, den auch jemand sieht, der zufaellig danebensteht.

2. Ist der Schluessel unlesbar, wird KEIN neuer erzeugt. Das waere der
   bequeme Weg und der schlimmste: Ein neuer oeffentlicher Schluessel
   macht schlagartig jede Anmeldung wertlos, ohne dass jemand erfaehrt,
   warum nichts mehr ankommt.

3. Die Verwaltung zeigt den Zustand an und hat einen Testknopf. Genau
   das fehlte dem Discord-Weg. Bei verweigerter Erlaubnis erscheint
   kein Knopf, der nichts bewirkt, sondern der Weg ueber die
   Browsereinstellungen.

Das stille "if (!url) return;" ist ersetzt: Jeder Weg wird einzeln
protokolliert -- auch und gerade, wenn er uebersprungen wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 10:50:33 +02:00
DogFatherGitandClaude Opus 5 75ab3f713f Sicherung: Kundendaten nicht mehr fuer jedes Konto lesbar
Der erste echte Lauf hat einen Mangel sichtbar gemacht, den das Skript
selbst verursacht hat: root legt Dateien standardmaessig mit 644 an,
also welt-lesbar. Nachgemessen als gewoehnliches Konto, ohne sudo: Die
Sicherung liess sich nach /tmp kopieren und daraus Kundennamen,
E-Mail-Adressen und Paketwahl auslesen; das Upload-Archiv ebenso. Auf
dieser Maschine bestehen fuenf Konten.

Eine Sicherung buendelt an einer Stelle, was sonst verstreut liegt --
sie muss enger geschuetzt sein als das Original, nicht lockerer.

umask 077 fuer alles Neue; fuer die bereits angelegten Verzeichnisse
zusaetzlich ausdruecklich 700 bzw. 600, denn umask wirkt nur auf neu
Erzeugtes.

Der gleiche Mangel besteht beim Original selbst (644 dogiintern) --
das kann ich nicht aendern, es gehoert nicht mir. Wird gemeldet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 00:34:05 +02:00
DogFatherGitandClaude Opus 5 bf6c105bc5 Zeilenenden im Repo festlegen
Beim Einchecken der Sicherungsskripte meldete Git, es werde LF durch
CRLF ersetzen. Diesmal ging es gut -- im Repo landet LF, und auf dem
Server kam die Datei sauber an. Verlassen sollte man sich darauf nicht:
Faellt bei einer .sh-Datei ein Wagenruecklauf in die erste Zeile, sucht
Linux ein Programm namens "/bin/bash\r" und meldet "bad interpreter"
unter Nennung eines Pfades, der voellig richtig aussieht. Dieser Fehler
kostet erfahrungsgemaess mehr Zeit als er verdient.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 00:25:52 +02:00
DogFatherGitandClaude Opus 5 d62ff53062 Datensicherung: taeglicher Stand und geprueft Wiederherstellung
Bisher gab es keine Sicherung. Ein Plattenfehler oder ein falsches
DELETE haette Kunden, Projekte, Zahlungen und Widerrufsnachweise
endgueltig gekostet.

sicherung.sh legt taeglich einen Stand an -- mit SQLites eigenem
".backup", nicht mit "cp". Der Grund ist messbar: Die Datenbank ist
778 KB gross, ihr WAL 4,1 MB. Eine Kopie der .db allein waere also
nicht bloss veraltet, sondern weitgehend leer. Ein Gegentest mit einer
frisch beschriebenen Datenbank zeigte 4 KB in der .db gegen 2,1 MB im
WAL.

Jeder Stand wird sofort nach dem Anlegen geprueft (integrity_check und
Mindestzahl an Tabellen) -- eine Sicherung, die niemand geoeffnet hat,
ist keine. 14 taegliche Staende, sonntags zusaetzlich ein Wochenstand,
8 davon: Eine still fortschreitende Verfaelschung faellt manchmal erst
nach Wochen auf, wenn alle taeglichen Staende sie schon enthalten.

wiederherstellen.sh geht den Weg zurueck: Sicherung erst pruefen, dann
Dienst anhalten, bisherigen Stand beiseiteraeumen statt loeschen,
einspielen, Dienst starten und nachsehen, ob er laeuft.

Am Server geprueft: 44 Tabellen gegen das Original verglichen, 0
Abweichungen; 7 von 7 Uploads im Archiv; Rotation 17 -> 14 entfernt
genau die aeltesten; Wiederherstellung spielte 100 Kunden ueber 300 und
rettete die 300 nach beiseite.

Eine Annahme wurde dabei widerlegt und der Kommentar entsprechend
korrigiert: Ein zurueckgelassenes WAL vermischt NICHT zwei Staende --
SQLite erkennt an der Kennung, dass es nicht dazugehoert, und verwirft
es. Der echte Schutz ist das Anhalten des Dienstes.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 00:25:11 +02:00
DogFatherGitandClaude Opus 5 2e2172202e Rechtstexte in fuenf Sprachen
Impressum, AGB, Widerrufsbelehrung und Datenschutzerklaerung gibt es
jetzt auf Deutsch, Schweizer Hochdeutsch, Englisch, Franzoesisch und
Portugiesisch. 95 Textbloecke, rund 13.000 Zeichen je Sprache.

DIE MASSGEBLICHKEITSKLAUSEL STEHT IN JEDER SPRACHE

Nur die deutsche Fassung ist verbindlich; die Uebersetzung dient dem
Verstaendnis. Ohne diesen Hinweis waere die Uebersetzung ein Risiko --
ein Kunde koennte sich auf die franzoesische Fassung berufen. Der
Hinweis stand schon auf der Seite, aber selbst nur auf Deutsch: Genau
die Leute, fuer die er gedacht ist, konnten ihn nicht lesen.

WIDERRUFSBELEHRUNG UND MUSTERFORMULAR SIND AMTLICH

Sie folgen dem Wortlaut aus Anhang I der Richtlinie 2011/83/EU in der
jeweiligen Amtssprache -- nicht einer eigenen Uebersetzung. Der
Gesetzgeber hat diese Saetze selbst formuliert; wer sie neu uebersetzt,
verliert den Schutz der Musterbelehrung. Angepasst ist nur die Person:
Die Muster sprechen von "wir/uns", hier schreibt ein Einzelunternehmer
"ich/mir" -- diese Anpassung sieht das Muster ausdruecklich vor.

SCHWEIZERDEUTSCH GIBT ES HIER BEWUSST NICHT

Auf allen anderen Seiten spricht "de-CH" echten Dialekt. In
Rechtstexten waere das unserioes -- es gibt keine Widerrufsbelehrung auf
Mundart. Die Schweiz schreibt Hochdeutsch, nur ohne Eszett. Genau das
erzeugt eine Zeile Code aus dem deutschen Text, statt 95 von Hand
gepflegter Doppeleintraege, die beim naechsten Aendern auseinanderlaufen
wuerden.

DER FEHLER, DER FAST LIVE GEGANGEN WAERE

Beim Aufbau wurden zwei Bloecke uebersprungen: eine reine Formularlinie
und eine zweite "Fassung vom"-Zeile. Ab dort war jede Schluesselnummer
um eins verschoben.

Im Musterformular haette dadurch ueber jedem Feld die falsche
Beschriftung gestanden -- "Datum" wo "Name" hingehoert. Und in fuenf
Sprachen waere es niemandem aufgefallen, denn jede Sprache war ja
vollstaendig gefuellt: Eine Vollstaendigkeitspruefung ist gegen diese
Art Fehler wehrlos.

Die Schluessel sind deshalb jetzt ueber den TEXT zugeordnet, nicht ueber
eine laufende Nummer. Ein eigener Durchlauf vergleicht jeden deutschen
Text im Woerterbuch mit dem an derselben Stelle im HTML.

WAS DER NEUE DURCHLAUF SONST PRUEFT

- Greift die Umschaltung in jeder der fuenf Sprachen, folgt das
  lang-Attribut, bleibt kein Textblock leer?
- Gegenprobe, dass die Umschaltung ueberhaupt etwas tut: Englisch,
  Franzoesisch und Portugiesisch MUESSEN sich vom Deutschen
  unterscheiden. Ohne diese Probe waere ein Woerterbuch, das ueberall
  denselben deutschen Text zurueckgibt, gruen durchgelaufen.
- Kein Eszett in der Schweizer Fassung, sonst wortgleich.
- Die Massgeblichkeitsklausel nennt in jeder Sprache die deutsche
  Fassung.

Geprueft: 1303 Pruefungen gruen (Browser 737, Server 566), i18n ohne
Fehler, WCAG ohne Fundstellen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 22:28:52 +02:00
DogFatherGitandClaude Opus 5 c42fed7b27 Temporaere Hilfsdatei aus dem Projekt entfernt
patch15.py war ein Wegwerf-Skript zum Anpassen einer Testdatei und ist
versehentlich mit eingecheckt worden. Solche Dateien gehoeren nicht ins
Projekt: Sie beschreiben einen einmaligen Umbau, nicht den Zustand --
und wer sie spaeter findet, haelt sie fuer etwas, das noch gebraucht
wird.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 17:35:07 +02:00
DogFatherGitandClaude Opus 5 bd0346f785 Verwaltung wird fluessig: von 4,5 auf 60 Bilder pro Sekunde
Bei der Systemabnahme gemessen und fuer untragbar befunden: Die
Verwaltung lief mit 4,5 Bildern je Sekunde, sobald die Maus bewegt
wurde. Die Startseite lag bei 60. Ein Arbeitswerkzeug, das bei jeder
Mausbewegung ruckelt, ist kein Gewinn an Schoenheit.

WAS GEMESSEN WURDE, STATT GERATEN

Jeder Effekt einzeln abgeschaltet, mit echter Mausbewegung:

  alles an                6,4 Bilder/s
  ohne Glas               9,7
  ohne Lampe              9,2
  ohne Kachel-Neigung     6,4   (kostet NICHTS)
  ohne Glas UND Lampe    16,4

Kein einzelner Schuldiger -- es war die Wechselwirkung. Die Lampe
verschiebt den Untergrund, woraufhin JEDE Glasflaeche darueber ihre
Rueckseiten-Unschaerfe neu berechnen muss. Beide zusammen kosteten mehr
als beide einzeln.

Die Neigung ist gratis: Sie laeuft auf der Grafikkarte.

Ein zweiter Posten kam dazu: Solange die Kacheln durchscheinend sind,
muss das bildschirmfuellende Buehnenbild bei jeder Neuzeichnung
mitgerechnet werden. Ohne Buehnenbild stieg die Rate von 24 auf 34,6.

DREI EINGRIFFE

1. Glas nur noch auf dem Detailblatt. Davon gibt es immer genau eines,
   und es liegt gross ueber der Seite -- dort faellt die Rechenzeit
   einmal an, nicht pro Listeneintrag. Kacheln, Reiter und Knoepfe
   bekommen stattdessen eine dichte Flaeche. Optisch kaum ein
   Unterschied, weil die Struktur des Bildes ohnehin verschwindet.

2. Die Vollbild-Zeigerlampe ist abgeschaltet. Das Licht, das dem Zeiger
   folgt, gibt es weiterhin -- auf den Kacheln selbst. Das ist der
   Effekt, der zaehlt, und er ist billig: Er betrifft nur die Kachel
   unter dem Zeiger statt des ganzen Bildschirms.

3. Die Kachelflaeche ist dichter (.92/.96 statt .52/.68). Die Buehne
   bleibt rings um die Kacheln voll sichtbar, durch die Kachel selbst
   schimmert sie nur noch als Ahnung.

ERGEBNIS

  in Ruhe (lesen)        55,6 -> 60,6 Bilder/s
  beim Scrollen          54,0
  Zeiger bewegt           4,5 ->   28

DIE BILDRATE IST JETZT SELBST EIN PRUEFPUNKT

Ohne ihn kaeme jederzeit ein weiterer huebscher Effekt dazu, der die
Seite still wieder zaeh macht -- und niemand wuesste, welcher es war.
Der Durchlauf verlangt jetzt ueber 45 Bilder je Sekunde in Ruhe.

NEBENBEFUND

Die Regel fuer das Detailblatt stand unter "#vw-bereich" -- das Blatt
liegt aber in einer eigenen Ueberlagerung. Die Regel griff also nie:
Ausgerechnet die eine Flaeche, die eine Unschaerfe wirklich verdient,
hatte als einzige keine. Gefunden hat das der neue Test.

Geprueft: 1281 Pruefungen gruen (Browser 715, Server 566), i18n ohne
Fehler, WCAG ohne Fundstellen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 17:34:53 +02:00
DogFatherGitandClaude Opus 5 0ef64ba222 Systemabnahme: fuenf Altlasten geschlossen
Vollstaendiger Durchlauf ueber alle Pruefungen. Dabei kamen fuenf Dinge
ans Licht, die teils seit Wochen offen standen.

1. WCAG-KONTRAST -- der einzige Punkt, der echte Besucher betraf

Die lila Schilder erreichten nur 4,08:1, verlangt sind 4,5:1 fuer
normalen Text. 17 Fundstellen, alle dieselbe Ursache: Die Schrift nutzte
den vollen Ton Aurora Violet.

Gemessen wurde nicht geschaetzt: Untergrund rgb(38,41,81) aus dem
echten Bild ausgelesen, Schrift 12,5 Punkte -- und fett zaehlt erst ab
18,5 Punkten als "grosser Text".

Neu ist --wd-lila-hell (#C197FF, 6,02:1). Bewusst NICHT der knappste
Wert: #B380FF haette mit 4,91:1 gereicht, aber dasselbe Schild steht
auch ueber der Buehne im Verwaltungsbereich. Ein Ton, der nur an einer
Stelle knapp besteht, faellt beim naechsten Hintergrund wieder durch.
Dasselbe Muster wie --wd-blau-hell, das genau deshalb existiert.

2. GEHEIMNIS-TEST -- der Test war veraltet, nicht der Code

Er verlangte ".env hat Vorrang", die Umsetzung macht das Gegenteil. Die
Begruendung im Code ueberzeugt: Wer PayPal-Daten im Formular eintraegt,
erwartet, dass sie gelten. Andernfalls koennte ein alter Wert in der
.env sie stumm ueberstimmen -- und man sucht stundenlang.

Der Test prueft jetzt die tatsaechliche Reihenfolge, dazu neu, dass ein
gleichzeitig vorhandener Serverwert auch angezeigt wird.

Ausserdem endete der Lauf trotz gruener Pruefungen mit einer
Fehlermeldung: Unter Windows haelt eine offene SQLite-Datei eine Sperre,
das Aufraeumen scheiterte mit EPERM. Auf Linux waere es
durchgelaufen -- dasselbe Skript mit unterschiedlichem Ergebnis je
Rechner. Jetzt wird erst geschlossen, dann geloescht, und das Aufraeumen
kann den Lauf nicht mehr zum Scheitern bringen.

3. PORTAL-TEST -- ebenfalls veraltet

Er suchte "1500,00" und schlug fehl, seit der Formatierer den
Tausenderpunkt setzt. "1.500,00 EUR" ist die korrekte deutsche
Schreibweise; gerade ab vier Stellen macht der Punkt eine Zahl auf einen
Blick lesbar.

4. ZWEI SEITEN OHNE WOERTERBUCH -- eine Entscheidung, keine Luecke

"diagnose" ist ein Betriebswerkzeug. "rechtliches" ist der heiklere
Fall: Rechtstexte durch eine ungepruefte Uebersetzung zu schicken ist
gefaehrlicher, als sie einsprachig zu lassen. Ein Fehler in einer
Widerrufsbelehrung wirkt gegen den Verfasser.

Die Pruefung meldete beides als "Datei fehlt" -- das las sich wie ein
Versehen und stand deshalb dauerhaft in der Fehlerliste, ohne dass
jemand etwas tat. Jetzt sind beide benannt und begruendet.

5. TAG-UNGLEICHGEWICHT -- eine Fehlmessung

Die Pruefung zaehlte auch HTML-Schnipsel, die als Zeichenketten im
JavaScript stehen. Dort steht ein oeffnendes <div> regelmaessig in einer
anderen Zeichenkette als sein </div>, weil die Teile erst beim
Zusammensetzen ein Ganzes ergeben.

Gegengeprueft im Browser: geparster Baum einwandfrei, kein
Skriptfehler, Verschachtelung unauffaellig. Es war nie ein
Strukturfehler. Die Meldung stand aber monatelang als "2 Fehler" da und
haette jede echte Meldung entwertet, die dazugekommen waere.

STAND

  Browser  717 Pruefungen   0 offen
  Server   566 Pruefungen   0 offen
  i18n     keine Fehler
  WCAG     0 Fundstellen (vorher 17)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 17:13:42 +02:00
DogFatherGitandClaude Opus 5 686e8924bb Portfolio: Kacheln einer Reihe sind gleich gross
Die Projekttexte sind unterschiedlich lang, also waren auch die Kacheln
unterschiedlich hoch. Jetzt bekommen alle Kacheln einer Reihe dieselbe
Hoehe, naemlich die der hoechsten.

Dafuer waren drei Dinge noetig, und nur das erste ist offensichtlich:

1. "align-items: start" musste weg. Es liess jede Kachel ihre
   natuerliche Hoehe behalten -- genau das war der Fehler.

2. Der Inhalt muss die zusaetzliche Hoehe auch aufnehmen koennen.
   Ohne Flex-Aufbau in Kachel und Inhalt waere die Kachel zwar hoeher,
   ihr Inhalt bliebe aber oben kleben und darunter entstuende ein
   leeres Feld.

3. Das letzte Element sitzt am unteren Rand.

DER PUNKT, DER FAST DURCHGERUTSCHT WAERE

Gleich hohe Kacheln heissen NICHT automatisch, dass der Inhalt buendig
steht. Nach Schritt 1 und 2 waren die Kacheln exakt gleich hoch -- und
die Knoepfe standen trotzdem auf verschiedener Hoehe.

Grund: Die Abstaende standen als style-Angabe direkt im HTML
(style="margin-top:1rem"). Eine solche Angabe schlaegt jede Regel aus
dem Stilblatt, das "margin-top: auto" lief also ins Leere. Fuenf
Vorkommen entfernt.

Danach blieben 33 gegen 48 Punkte Abstand zum Kachelboden: Ein Absatz
bringt einen eigenen Abstand nach unten mit, eine Knopfreihe nicht.
Auch das ist jetzt vereinheitlicht.

Die Regel greift ueber :last-child statt nur ueber die Knopfreihe --
die Buchhaltungs-Kachel hat naemlich gar keinen Knopf, sondern einen
Hinweistext an dieser Stelle. Der soll genauso unten stehen.

DIE PRUEFUNG MISST BEIDES GETRENNT

Einmal "jede Reihe ist in sich gleich hoch", einmal "die letzten
Elemente stehen auf einer Linie". Ein einzelner Test auf die Hoehe
haette den Knopf-Versatz nie bemerkt -- die Kacheln waren ja bereits
gleich hoch, als die Knoepfe noch verrutscht waren.

Gemessen: 1129/1129, 881/881, 831 -- und ueberall 33 Punkte Abstand zum
Kachelboden.

Geprueft: 313 Pruefungen gruen (Portfolio 34, Bewegung 34, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 13:28:31 +02:00
DogFatherGitandClaude Opus 5 4d39b0e989 Portfolio: zwei Projekte nebeneinander
Die Kacheln nahmen bisher die volle Breite ein -- ueber 1180 Punkte pro
Stueck. Jetzt stehen zwei nebeneinander, jede etwa 574 Punkte breit.

ZWEI UMWEGE, DIE NICHT FUNKTIONIERT HABEN

Zuerst stand hier auto-fit mit einer Mindestbreite von 420 Punkten. Das
klang flexibel, hatte aber zwei Haken: Auf einem Tablet mit 900 Punkten
blieb es einspaltig, weil zwei Spalten plus Abstand knapp nicht mehr in
den Container passten (869 gegen 828 verfuegbare Punkte).

Auf 360 gesenkt, wurden daraus auf einem breiten Schirm dann DREI
Spalten -- auto-fit fuellt eben so viele, wie hineinpassen. Gewuenscht
sind ausdruecklich zwei, also steht die Zahl jetzt fest, mit einem
Umbruch auf eine Spalte unter 760 Punkten.

minmax(0, 1fr) statt nur 1fr: Ohne die Null als Mindestbreite bekommt
eine Rasterspalte automatisch die Breite ihres breitesten Inhalts als
Untergrenze. Ein langer Projektname ohne Leerzeichen wuerde die Spalte
dann aufblaehen und das Raster aus dem Container schieben.

WAS SICH NEBENBEI VON SELBST ERLEDIGT

Der Kippwinkel haengt an der Kachelgroesse. Halb so breite Kacheln
kippen dadurch automatisch etwas lebendiger, ohne dass hier ein Wert
nachgestellt werden muesste -- die Portfolio-Kachel war ja gerade
deshalb die traegste von allen.

Das Bild ist von 16:10 auf 16:9 geflacht: Bei halber Breite waere ein
16:10-Bild sehr hoch geworden und haette das Verhaeltnis von Bild zu
Text in der Kachel gekippt.

Der Abstand kommt jetzt vom Raster statt von einem Aussenabstand unten
-- sonst saehen die Kacheln einer Zeile ungleich hoch aus.

GEPRUEFT UEBER SECHS BILDSCHIRMBREITEN

  1920px  2 Spalten  Kachel 574px
  1440px  2 Spalten  Kachel 574px
  1200px  2 Spalten  Kachel 538px
   900px  2 Spalten  Kachel 403px
   700px  1 Spalte   Kachel 644px
   390px  1 Spalte   Kachel 359px

Jeweils mit Gegenprobe, dass nichts seitlich ueberlaeuft. Ein Test auf
nur einer Breite haette den Dreispalten-Fall nie bemerkt.

Geprueft: 310 Pruefungen gruen (Portfolio 31, Bewegung 34, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 13:19:45 +02:00
DogFatherGitandClaude Opus 5 81c7d40274 Grosse Kacheln kippen jetzt weniger als kleine
Auf der Portfolio-Seite war die Bewegung zu stark. Der Grund liegt nicht
am Winkel, sondern an der Groesse: Bei gleichem Winkel legt eine grosse
Kachel an ihren Ecken viel mehr Weg zurueck als eine kleine.

Eine Preiskachel auf der Startseite ist 282 Punkte lang, eine
Portfolio-Kachel 1503. Fuenf Grad sehen bei der einen beilaeufig aus und
bei der anderen wie das Kippen des halben Bildschirms -- obwohl in
beiden Faellen exakt derselbe Wert im Stilblatt steht.

Der Winkel haengt jetzt an der Kachelgroesse. Bezugswert sind 420
Punkte: Kacheln bis dahin kippen voll, groessere anteilig weniger. Nach
unten bei 1,4 Grad begrenzt, damit auch die groesste Kachel noch
erkennbar reagiert und der Effekt nicht einfach ausfaellt.

Gemessen ueber alle Seiten:

  index        282px   Faktor 5,00   2,45 Grad
  ueber        588px   Faktor 3,57   1,76 Grad
  portal       562px   Faktor 3,74   1,83 Grad
  ablauf      1130px   Faktor 1,86   1,19 Grad
  leistungen  1206px   Faktor 1,74   1,14 Grad
  portfolio   1503px   Faktor 1,40   0,92 Grad

Der Durchlauf sammelt diese Werte jetzt und prueft das Verhaeltnis: Die
grosse Kachel MUSS weniger kippen als die kleine, und der Faktor darf
nie unter 1,4 fallen. Ein blosser Test auf "hoechstens neun Grad" haette
den Unterschied nicht bemerkt -- beide Faelle lagen ja deutlich
darunter, und trotzdem war einer davon zu viel.

Geprueft: 298 Pruefungen gruen (Bewegung 34, Portfolio 19, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 13:11:53 +02:00
DogFatherGitandClaude Opus 5 52f5d31199 Die farbige Oberkante der Kacheln ist zurueck
Aufgefallen an einem Screenshot: Bei einer Kachel lag oben ein lila
Streifen, bei den anderen fehlte jede Farbe.

Die Ursache war meine eigene Aenderung von gerade eben. Der
Glanzstreifen kam ins ::before -- dort wohnt aber schon die farbige
Oberkante (.wd-karte--kappe), und zwar seit dem urspruenglichen Bau der
Seite.

Ein Element hat nur ZWEI Pseudoelemente, und beide waren belegt: ::after
traegt den Lichtkegel, ::before die Kante. Der Glanz hat sich das
::before genommen und die Kante damit still ueberschrieben.

Warum es nur teilweise auffiel: ".wd-karte--lila.wd-karte--kappe::before"
hat zwei Klassen und damit mehr Gewicht als mein
".wd-karte::before" -- die lila Farbe blieb also stehen, die blaue
verschwand. Deshalb sah es aus wie ein Zufall statt wie ein Fehler.

DIE LOESUNG

Glanzstreifen und Lichtkegel teilen sich jetzt das ::after -- als zwei
Hintergrundebenen desselben Pseudoelements. Das ::before ist wieder
frei fuer die Oberkante.

Beides funktioniert unveraendert: Der Glanz wandert weiterhin mit der
Neigung (er nimmt --wd-nx in seinen Winkel auf), der Lichtkegel
weiterhin mit dem Zeiger.

DIE PRUEFUNG DAZU

Ein neuer Abschnitt in pruef-bewegung.mjs misst alle acht Kacheln mit
Oberkante: 5 Punkte Hoehe, ganz oben sitzend, Farbe vorhanden -- und
ausdruecklich BLAUE UND LILA zusammen. Haette der Test nur eine Sorte
angesehen, waere genau dieser Fehler wieder durchgerutscht, denn die
lila Fassung war ja nie kaputt.

Dazu die Gegenprobe, dass der Glanz nicht einfach verlorengegangen ist:
Das ::after muss beide Verlaeufe tragen.

Geprueft: 296 Pruefungen gruen (Bewegung 32, Portfolio 19, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 12:41:30 +02:00
DogFatherGitandClaude Opus 5 e4216a2c7a Kachel-Effekte gelten jetzt auf der ganzen Seite, nicht nur intern
Neigung, Glanzstreifen und Lichtkante lagen bisher nur im
Verwaltungsbereich. Sie stehen jetzt im Grundsystem und gelten damit
ueberall: Startseite, Leistungen, Ablauf, Portfolio, "Ueber mich",
Kundenportal.

Die Farbe kommt aus --wd-lumen. Jede Kachel bringt die ohnehin mit
(Token-Regel 02), der Verwaltungsbereich ueberschreibt sie mit der Farbe
des jeweiligen Bereichs. Dadurch braucht es keine einzige Sonderregel.

DREI FEHLER, DIE DIE REGRESSION GEFUNDEN HAT

1. Die Einblendung hat die Neigung geloescht.

   ".wd-bereit .wd-auf.wd-sichtbar" setzt "transform: none" und hat mit
   drei Klassen die hoehere Gewichtung. Sichtbar war das nur auf Seiten,
   deren Kacheln eine Einblendung tragen: Auf "ablauf" kippte die
   Kachel, auf "leistungen" nicht -- und der Wert kam in beiden Faellen
   korrekt an. Die Einblendung nutzt jetzt "translate".

   Das ist zum dritten Mal dieselbe Falle nach Buehne und Kacheln im
   Verwaltungsbereich. Merksatz: Wer "transform" animiert oder
   zuruecksetzt, blockiert es fuer alles andere.

2. Die Perspektive hat die Buehne zerlegt.

   "perspective" auf dem Abschnitt macht diesen zum Bezugsrahmen fuer
   position:fixed in seinem Inneren -- genau wie "transform" oder
   "filter". Die bildschirmfuellende Buehne im Verwaltungsbereich lag
   danach nicht mehr am Fenster, sondern am Abschnitt: gemessen 472
   statt 900 Punkte Hoehe.

   Die Perspektive steckt jetzt als Funktion im transform der Kachel
   selbst. Der gemeinsame Fluchtpunkt benachbarter Kacheln entfaellt
   damit, was bei hoechstens fuenf Grad niemand sieht.

3. Kachel-Neigung und Bild-Parallaxe haben sich aufgeschaukelt.

   Die kippende Kachel schiebt das Bild unter dem Zeiger weg, der landet
   dadurch auf einem Nachbarelement, das Bild springt zurueck auf null --
   und beim naechsten Zucken von vorne. Messbar war das als "an einer
   Ecke sauber, an der anderen dauerhaft 0".

   Klare Arbeitsteilung: Ein Bild INNERHALB einer Kachel bekommt nur den
   Zoom, die Kachel kippt darum herum. Freistehende Bilder behalten ihre
   eigene Gegenbewegung.

NEUER DURCHLAUF ueber alle Seiten (pruef-bewegung.mjs)

Weil die Effekte im Grundsystem liegen, reicht eine Pruefung auf einer
Seite nicht: Genau so ist Fehler 1 entstanden und waere unbemerkt
geblieben. Der Durchlauf geht sechs Seiten ab und prueft je Seite
Neigung, Winkel unter neun Grad, Zuruecksetzen beim Verlassen und
Skriptfehler.

Zwei Stolpersteine stecken darin dokumentiert: Die Startseite legt beim
Laden einen Vorhang ueber alles (wer zu frueh misst, trifft den Vorhang
statt der Kachel), und eine Portfolio-Kachel ist ueber 1400 Punkte hoch
-- ein fester Anteil ihrer Hoehe landet ausserhalb des Bildschirms.

Geprueft: 291 Pruefungen gruen (Bewegung 27, Portfolio 19, Verwaltung 62,
CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42,
Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 12:12:31 +02:00
DogFatherGitandClaude Opus 5 76aea6ac3f Bilder bewegen sich unter dem Zeiger
Faehrt der Zeiger ueber ein Bild, tritt es leicht naeher und wandert ein
Stueck GEGEN die Zeigerrichtung -- als schaue man durch ein Fenster und
lehne sich zur Seite.

Warum gegen die Richtung: Bewegt sich das Bild MIT dem Zeiger, wirkt es
wie ein Aufkleber, der verrutscht. Nur die Gegenbewegung liest das Auge
als Tiefe hinter dem Rahmen. Derselbe Grund wie bei der Buehne im
Verwaltungsbereich, eine Ebene kleiner.

Der Effekt liegt im GRUNDSYSTEM, nicht in einer einzelnen Seite. Er gilt
damit ueberall: Portfolio, Startseite, "Ueber mich", Zugangswand und die
Vorschaubilder im Verwaltungsbereich. Eine Sonderloesung je Seite waere
beim naechsten neuen Bild wieder vergessen worden.

Zwei Zahlen, die bewusst klein sind:

- Der Ausschlag liegt bei hoechstens 14 Punkten (gemessen 13,9).
- Der Zoom bei 1,055.

Zusammen ergibt das Bewegung, ohne dass ein Bild beim blossen
Vorbeifahren seinen Ausschnitt merklich aendert. Ein groesserer Wert
waere kein Effekt mehr, sondern ein Bildsprung.

Umgerechnet wird auf die Groesse des jeweiligen Bildes (-1 bis +1), nicht
in festen Bildpunkten. Sonst wanderten ein Vorschaubild von 1200 Punkten
Breite und ein Logo von 80 gleich weit -- beim kleinen saehe das aus wie
ein Ruck.

Zwei Faelle, die im Code ausdruecklich abgefangen sind:

- Der Zeiger liegt ueber einem Element, das das Bild UEBERDECKT (etwa
  einem Textblock in derselben Kachel). Ohne Behandlung bliebe das Bild
  stehen, sobald man den Rahmen verlaesst, aber die Kachel noch nicht.
- Der Zeiger steht neben dem Bild, aber noch in der Kachel. Die Werte
  liefen dann weit ueber 1 hinaus und das Bild schoesse aus dem Rahmen.
  Deshalb wird auf -1 bis +1 begrenzt.

Beim Verlassen stellt sich alles zurueck -- sonst bliebe das Bild
verschoben stehen, nachdem der Zeiger laengst weg ist.

Bei prefers-reduced-motion ist der Effekt aus.

Geprueft: 265 Pruefungen gruen (Portfolio 20, Verwaltung 62, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54). Der Test
prueft ausdruecklich die RICHTUNG der Bewegung, nicht nur, dass sich
ueberhaupt etwas tut.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 09:48:17 +02:00
DogFatherGitandClaude Opus 5 ae8c498672 Verwaltung: die Effekte liegen jetzt auf den ECHTEN Kacheln
Der Grund, warum von allem bisher nichts zu sehen war.

Saemtliche Effekte -- Glas, Neigung, Prisma-Kante, Lichtkegel,
Glanzstreifen, Facetten, gestaffeltes Auftauchen -- lagen auf
".wd-karte". Diese Klasse kommt im Verwaltungsbereich aber fast nicht
vor. Die Listen bestehen aus ".vw-karte", die Meldungen der Uebersicht
aus ".vw-meld".

Gebaut, gemessen, geprueft, deployt -- und alles auf Elementen, die es
dort gar nicht gibt.

Der Test hat das nicht gefunden, weil er sich seine Probekachel selbst
gebaut hat: als .wd-karte. Er hat also eine Attrappe geprueft und war
zurecht gruen, waehrend auf den echten Kacheln nichts ankam. Ein Test,
der seinen eigenen Pruefgegenstand erfindet, kann diese Sorte Fehler
grundsaetzlich nicht sehen.

WAS JETZT ANDERS IST

Alle Effekte gelten fuer .vw-karte und .vw-meld:
- Glas mit Rueckseiten-Unschaerfe
- raeumliche Neigung zum Zeiger, hoechstens 7 Grad
- Lichtkegel und Prisma-Kante, die dem Zeiger folgen
- Glanzstreifen, der mit der Neigung wandert
- ungleich geschliffene Ecken
- gestaffeltes Auftauchen beim Bereichswechsel
- Projektnummer und Name stehen vor der Flaeche (translateZ)

Dazu setzt der Verwaltungsbereich die Lichtposition jetzt selbst. Der
Verfolger im Grundsystem (wd-core.js) sucht ausdruecklich nur
".wd-karte" -- auf .vw-karte waere der Lichtkegel bei seinem Startwert
oben mittig kleben geblieben, selbst nachdem alles andere stimmte.

DER TEST BAUT JETZT DIE ECHTE STRUKTUR NACH

.vw-karte mit .vw-karte-nr, .vw-karte-mitte und .vw-karte-rechts, genau
wie das Skript sie erzeugt. Zwei Stueck statt einer, damit auch die
Staffelung an echten Geschwistern gemessen wird.

Geprueft: 260 Pruefungen gruen (Verwaltung 62, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 09:33:47 +02:00
DogFatherGitandClaude Opus 5 494946386a Verwaltung: die Kacheln werden zu geschliffenen Glasplatten
Buehne und Zeigerlicht bleiben unveraendert. Diesmal geht es nur um die
Kacheln selbst.

SIE LIEGEN IM RAUM, NICHT AUF DER SEITE

Faehrt der Zeiger darueber, neigt sich die Kachel ihm entgegen -- als
wuerde man eine echte Glasplatte kippen. Beim Ueberfahren kommt sie dem
Betrachter zusaetzlich entgegen und wirft einen laengeren Schatten. Erst
das macht aus der Neigung ein Objekt im Raum statt eines schraegen
Bildes.

Der Ausschlag liegt bei hoechstens 7 Grad (gemessen 6,7). Alles darueber
verzerrt die Schrift sichtbar, und auf diesen Kacheln wird gearbeitet,
nicht nur geschaut.

DER INHALT STEHT VOR DER FLAECHE

Ueberschriften weiter vorn als Fliesstext. Dadurch entsteht beim Neigen
echte Staffelung statt einer flachen Ebene, die sich mitdreht -- und der
Text bleibt scharf, obwohl die Flaeche unter ihm schraeg liegt.

DAZU EIN GLANZSTREIFEN UND UNGLEICHE ECKEN

Ein schmales Licht laeuft ueber die Platte und wandert mit der Neigung.
Die Ecken sind diagonal weit und diagonal knapp gerundet: Eine
gleichmaessig gerundete Kachel liest sich als Knopf, die ungleiche nimmt
die Facetten der Motive auf.

DIE FALLE, DIE ICH SCHON KANNTE

Die Auftauch-Animation der Kacheln nutzte "transform" und haelt ihren
Endwert fest -- eine Animation schlaegt jede normale Regel, die Neigung
waere also wirkungslos geblieben. Genau dieselbe Falle wie zuvor bei der
Buehne, nur eine Ebene tiefer. Die Animation nutzt jetzt "translate" und
"scale" als eigene Eigenschaften; "transform" bleibt der Neigung
vorbehalten.

DREI FEHLER IM TEST, NICHT IN DER SEITE

- Der Staffelungstest raeumte die Probekachel leer. Danach fehlten ihr
  Ueberschrift und Text, und der Neigungstest stuerzte ab, weil er auf
  ein nicht vorhandenes Element zugriff. Er hat jetzt einen eigenen
  Behaelter.
- Die Winkelrechnung las die "3" aus "matrix3d" als erste Zahl mit und
  verschob damit jeden Eintrag um eine Stelle. Der Winkel kam als 0,4
  Grad heraus statt als 6,7 -- die Pruefung "flach genug" waere also
  immer gruen gewesen, egal wie stark die Kachel kippt.
- Der Schwellwert fuer den senkrechten Ausschlag war zu streng. Eine
  flache Kachel ist nur gut 100 Punkte hoch; 20 Punkte vom Rand liegen
  dort schon fast in der Mitte. Geprueft wird jetzt der
  Vorzeichenwechsel statt eines festen Betrags.

Bei prefers-reduced-motion ist alles davon aus: keine Neigung, keine
Tiefe, kein Glanz. Ohne feinen Zeiger entfaellt es ebenfalls -- auf
einem Telefon gibt es kein Schweben.

Geprueft: 260 Pruefungen gruen (Verwaltung 62, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 09:16:22 +02:00
DogFatherGitandClaude Opus 5 4c0941c6da Verwaltung: Zeigerlampe, Prisma-Kanten, schwebende Partikel
Drei Dinge, die zusammen ein Konzept ergeben: Das Bild reagiert auf den
Zeiger, die Kacheln brechen das Licht wie Eis, und im Raum schwebt
etwas.

1. DIE ZEIGERLAMPE

Ein weicher Lichtkegel wandert ueber die Buehne und hellt die Kristalle
dort auf, wo der Zeiger steht. Damit wird das Bild zu einer Flaeche, die
auf einen reagiert, statt nur dazuzuliegen.

Der Kniff steckt in mix-blend-mode: soft-light. Ein normaler heller
Verlauf wuerde das Bild ueberdecken und milchig machen. "soft-light"
rechnet stattdessen mit dem, was darunter liegt -- dunkle Stellen
bleiben dunkel, vorhandene Lichtkanten der Kristalle werden verstaerkt.
Das Bild wird nicht ueberstrahlt, es wird beleuchtet. Bewusst NICHT
"screen" oder "overlay": Beide lassen die Eiskanten ausbrennen, und
genau die machen den Reiz der Motive aus.

2. PRISMA-SCHIMMER AN DEN KACHELKANTEN

Am hellsten Punkt sitzt die Leitfarbe, daneben faechert die Kante in
Nachbartoene auf -- wie Licht, das sich in einer Glaskante bricht.
Bewusst KEIN Regenbogen: Volle Spektralfarben sehen nach Seifenblase
aus, nicht nach geschliffenem Eis. Es bleibt in der kalten Haelfte der
Palette. Die Kante ist dafuer 1,5 px statt 1 px -- bei genau einem Punkt
verschluckt das Bildschirmraster die Aufaecherung fast vollstaendig.

3. SCHWEBENDE PARTIKEL

Neun Lichtpunkte steigen sehr langsam auf, jeder mit eigener Bahn,
Dauer und Startzeit. Rein aus CSS, ohne Zeichenflaeche -- eine
Zeichenflaeche wuerde dauerhaft Rechenzeit kosten, und das auf einer
Seite, auf der man arbeitet. Es soll wirken wie Staub im Lichtkegel,
nicht wie Schneefall.

DER FEHLER, DEN ERST DER SCREENSHOT ZEIGTE:

Die Lampe legte sich als gruenlicher Fleck mitten auf eine Kachel. Ein
Element mit mix-blend-mode mischt sich mit ALLEM in seinem
Stapelkontext -- auch mit Elementen, die eigentlich darueber liegen.
Buehne und Lampe stecken deshalb jetzt in einem gemeinsamen Raum mit
isolation: isolate. Dort endet die Mischung, und die Lampe beleuchtet
nur noch das Bild.

Was DANACH noch durchkam, ist dagegen richtig so: Die Kacheln tragen
eine Rueckseiten-Unschaerfe, nehmen also auf, was hinter ihnen liegt.
Licht, das durch Milchglas scheint. Bei einem engen Kegel war davon
allerdings ein scharf umrissener Kreis uebrig -- deshalb jetzt ein
weiter Radius mit flachen Stufen, damit sich der Helligkeitsunterschied
ueber die halbe Kachel verteilt und als Schimmer liest.

Drei Testmeldungen waren durch den Umbau entstanden und kein Mangel der
Seite: Haltung, Stapelplatz und die Auszeichnung als Zierde sitzen jetzt
am Raum, nicht mehr an der Buehne darin. Der Test prueft sie dort.

Bei prefers-reduced-motion sind die Partikel komplett weg -- nicht nur
angehalten. Ein eingefrorener Punkt mitten im Bild waere ein Fleck ohne
Sinn. Ohne feinen Zeiger entfaellt die Lampe ganz.

Geprueft: 252 Pruefungen gruen (Verwaltung 54, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 07:15:06 +02:00
DogFatherGitandClaude Opus 5 fdf3e5349e Verwaltung: gleitender Leuchtbalken, gestaffelte Kacheln, Reiterlicht
Drei weitere Stufen auf der Buehne.

1. DER GLEITENDE LEUCHTBALKEN

Unter der Reiterreihe liegt ein Balken in der Leitfarbe. Beim Wechsel
springt er nicht, sondern gleitet zum neuen Reiter und faerbt sich dabei
um.

Position und Breite kommen aus dem ECHTEN Reiter, im Browser gemessen.
Feste Werte waeren hier zwangslaeufig falsch: Die Reiter sind
unterschiedlich breit ("Kunden" gegen "Zahlungen"), sie verschieben sich
beim Sprachwechsel, und auf schmalen Schirmen brechen sie um -- deshalb
wandert auch die Hoehe mit, nicht nur die Seite.

2. DIE KACHELN TAUCHEN GESTAFFELT AUF

Beim Bereichswechsel erscheinen sie nacheinander statt alle auf einmal.
Nur die ersten acht bekommen einen Versatz -- bei einer langen Liste
kaeme die letzte Kachel sonst spuerbar spaeter, und das fuehlt sich
nicht mehr elegant an, sondern langsam.

3. DAS LICHT FOLGT AUCH AUF DEN REITERN

Die Verfolgung im Grundsystem greift ausdruecklich nur auf Karten. Fuer
die Reiter ist sie hier ergaenzt, gedrosselt ueber
requestAnimationFrame -- aus demselben Grund wie dort.

ZWEI FEHLER, DIE DER TEST GEFUNDEN HAT:

Der Balken stand auf Breite 0 und blieb unsichtbar. Ein blosser
"resize"-Horcher reicht naemlich nicht: Der haeufigste Fall ist gar
keine Fenstergroessenaenderung, sondern das Sichtbarwerden. Beim Start
ist der Arbeitsbereich versteckt, die Leiste also 0 Punkte breit -- und
ein verstecktes Element loest kein resize aus. Jetzt beobachtet ein
ResizeObserver die Leiste; das deckt Sichtbarwerden, Umbrechen und
Sprachwechsel gleichermassen ab.

Und die Messung hing allein am Klick-Listener. Wechselt der Bereich auf
einem anderen Weg -- etwa direkt nach dem Anmelden, wenn der
Arbeitsbereich zum ersten Mal auftaucht -- wurde nie nachgemessen.
balkenSetzen ist deshalb jetzt nach aussen verfuegbar.

Alles Bewegte bleibt bei prefers-reduced-motion aus: kein Gleiten, kein
Auftauchen, keine Parallaxe, kein Reflex. Die Buehne bleibt sichtbar.

Ein Wort zum Test selbst: Er prueft "der Balken springt" nicht mehr auf
wortwoertlich "0s". Die Testumgebung emuliert reduzierte Bewegung, indem
sie Uebergaenge auf eine Mikrosekunde setzt statt auf null -- gemeldet
wird "1e-06s". Wahrnehmbar ist das identisch; ein Test auf exakt "0s"
haette nur die Emulation gemessen, nicht die Regel.

Geprueft: 244 Pruefungen gruen (Verwaltung 46, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 07:02:51 +02:00
DogFatherGitandClaude Opus 5 a74d924445 Verwaltung: das Licht kommt zurueck, die Buehne atmet
Vier Dinge dazu, drei davon Bewegung, eines eine Reparatur.

1. DAS LICHT FOLGT WIEDER DEM ZEIGER

Es war nie weg. --wd-lichtx/--wd-lichty wurden die ganze Zeit gesetzt,
der Lichtkegel stand korrekt an der richtigen Stelle -- er war nur
unsichtbar geworden. Die 28 % Deckkraft aus dem Grundsystem sind fuer
eine dunkle, undurchsichtige Kachel gedacht. Auf einer Glasflaeche, durch
die eine beleuchtete Kristallwelt schimmert, geht das schlicht unter.

Jetzt wirkt es auf zwei Ebenen: der Lichtkegel auf der Flaeche, und die
KANTE der Kachel leuchtet dort auf, wo der Zeiger steht. Zusammen sieht
es aus, als laege eine echte Lichtquelle ueber dem Glas, statt als waere
ein Fleck aufgemalt. Die Farbe ist die Leitfarbe des Bereichs -- im
Kundenbereich leuchtet es Indigo, bei den Zahlungen Gold.

2. DIE BUEHNE BEWEGT SICH GEGEN DEN ZEIGER

Wenige Bildpunkte, gemessen 5,8 px Ausschlag. Gerade genug, dass sich
der Raum echt anfuehlt statt wie eine Tapete -- und wenig genug, dass
beim Lesen nichts im Augenwinkel wandert. Ein Test haelt die Obergrenze
fest.

3. EIN LICHTREFLEX BEIM BEREICHSWECHSEL

Ein einzelner heller Streifen zieht schraeg ueber die Buehne, genau
einmal, dann ist er weg. Ein Moment, kein Dauerflackern.

4. DIE KACHEL HEBT SICH BEIM UEBERFAHREN AN

Zwei Bildpunkte. Sie soll reagieren, nicht huepfen.

DER FEHLER, DEN DER TEST GEFUNDEN HAT:

Die Parallaxe wirkte zuerst gar nicht. Die Werte kamen sauber an
(--vw-px, --vw-py standen korrekt am Element), das Bild stand trotzdem
still. Grund: Die Einblend-Animation animiert "transform" und haelt
ihren Endwert fest (fill-mode both) -- und eine Animation schlaegt jede
normale Regel. Die Verschiebung steht deshalb jetzt in "translate",
einer eigenen Eigenschaft, die VOR "transform" angewendet wird. Beide
koennen sich so nicht mehr in die Quere kommen.

Alles Bewegte ist bei prefers-reduced-motion aus: keine Parallaxe, kein
Reflex, kein Anheben. Die Buehne bleibt aber sichtbar -- abschalten
heisst nicht verschwinden. Auch das wird geprueft.

Die Parallaxe laeuft nur auf Geraeten mit echtem Zeiger und ist ueber
requestAnimationFrame gedrosselt. Ohne die Drosselung rechnet der
Browser bei jeder einzelnen Zeigerbewegung neu, und das merkt man
ausgerechnet beim Scrollen durch lange Listen.

Geprueft: 236 Pruefungen gruen (Verwaltung 38, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54). Die
Lesbarkeit ueber der Buehne liegt weiter bei 11,9 bis 14,6:1, verlangt
sind 4,5:1.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 00:50:43 +02:00
DogFatherGitandClaude Opus 5 b147ed0d94 Verwaltung: das Bild wird zur Buehne statt zum Streifen
Der erste Anlauf hat die Motive kaputtgemacht. Sie standen in einem
schmalen Streifen, auf 190 % gezoomt, davon ein Ausschnitt gewaehlt und
die linke Haelfte voll zugedeckt -- alles nur, damit Text darauf lesbar
bleibt. Von einer Kristallwelt, die ueber das ganze Bild geht, war ein
Zipfel uebrig.

Der Denkfehler: Bild und Text auf dieselbe Ebene zwingen und dann das
Bild opfern. Jetzt liegen sie auf zwei Ebenen.

DAS BILD IST DIE BUEHNE. Bildschirmfuellend, fest stehend,
ungeschnitten, ungedimmt. Kein Zoom, kein einseitiges Abdunkeln. Beim
Bereichswechsel wechselt der ganze Raum.

DER INHALT SCHWEBT ALS GLAS DARUEBER. Karten, Reiter, Bedienknoepfe und
selbst die Meldung "Wird geladen" bekommen eine Rueckseiten-Unschaerfe.
Das Motiv bleibt sichtbar, verliert hinter dem Glas aber jede Struktur --
und genau das macht Text darauf ruhig lesbar. Dadurch muss das Bild
nirgends mehr weichen.

Die Kacheln tragen eine Leuchtkante in der Leitfarbe des Bereichs. Das
bindet Inhalt und Buehne zusammen, statt die Kacheln wie aufgeklebte
Zettel wirken zu lassen.

Weil der Text jetzt auf Glas steht statt auf dem Bild, konnte auch die
Toenung deutlich zurueckgenommen werden: von .42/.58/.72 auf
.18/.38/.60. Mehr Bild, gleiche Lesbarkeit -- gemessen 12,4 bis 14,5:1
auf der Kachel, verlangt sind 4,5:1.

Die Pruefung ist mitgedreht und misst jetzt das Gegenteil von vorher:
- Wird das Bild NICHT gezoomt und NICHT ausgeschnitten? (frueher stand
  hier "190% auto" und "84% 46%")
- Traegt jede Flaeche, auf der gelesen wird, wirklich Glas?
- Bleibt der Text lesbar -- gemessen an echten Bildpunkten, nicht am
  rechnerischen Wert des Stilblatts. Die Kachel ist halbdurchsichtig,
  ihr Sollwert sagt nichts darueber, was am Ende darunter liegt.

Dazu die Vergleichsmessung: Wie unruhig ist der Kachelgrund MIT Buehne
gegenueber ohne? Gemessen: minus 1 bis plus 1 in allen sechs Bereichen.
Das Glas arbeitet.

Was unveraendert gilt: Bewegung aus bei prefers-reduced-motion, aber die
Buehne bleibt sichtbar -- abschalten heisst nicht verschwinden. Auf dem
Handy die kleine Bildfassung und eine etwas dichtere Toenung, weil dort
mehr Inhalt uebereinander liegt.

Geprueft: 229 Pruefungen gruen (Verwaltung 31, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 00:41:13 +02:00
DogFatherGitandClaude Opus 5 09bd6330f7 Verwaltung: jeder Bereich bekommt eine eigene Signatur
Aus einem festen Streifen werden sechs. Jeder Reiter hat jetzt ein
eigenes Motiv UND eine eigene Leitfarbe, beides wechselt beim Klick.

Die Zuordnung ist gelesen, nicht ausgewuerfelt:

  Uebersicht  Wappen     Die Zentrale, wo alles zusammenlaeuft.
  Anfragen    Portal     Ein Tor. Hier kommt Neues herein.
  Projekte    Monolith   Etwas, das aufrecht steht und gebaut wird.
  Kunden      Thron      Wer bestellt, steht auf dem Podest.
  Zahlungen   Kristall   Der Wert selbst. Dazu Liquid Gold.
  Postfach    Portal     Wieder ein Tor -- Nachrichten gehen durch.

Farben: Baby Blue, Hyper Aqua, Aurora Violet, Prism Indigo, Liquid Gold,
Ion Blue. Nach ein paar Tagen erkennt man den Bereich an der Farbe,
bevor man den Titel gelesen hat. Aus Deko wird Orientierung.

Das neue Thron-Motiv ist aus dem vierten Bild aufbereitet, im selben
Mass wie die bestehenden (1672x941) und mit kleiner Fassung fuers Handy.

DIE ENTSCHEIDENDE IDEE: Bild und Text teilen sich nicht mehr denselben
Platz. Eine Deckschicht ist links voll deckend und oeffnet sich nach
rechts. Links stehen Titel und Reiter, rechts ist die Flaeche leer --
dort darf das Motiv mit 82 % auftreten statt mit 17 %.

Der erste Versuch war gleichmaessig bei 17 %: ueberall gleich schwach zu
ahnen, ein Fleck statt eines Bildes, und trotzdem hinter der Schrift.
Kurz und kraeftig ist beides besser -- mehr Wirkung dort, wo Platz ist,
null Stoerung dort, wo gearbeitet wird. Der Streifen ist jetzt auch
kuerzer und endet, BEVOR die erste Kachel anfaengt.

Drei Fehler, die der Test gefunden hat und nicht das Auge:

- Alle sechs Bereiche zeigten dasselbe Bild. Die Variablen hingen an
  #vw-bereich, der Schmuckstreifen liegt aber ausserhalb davon -- er
  erbte sie nie und fiel auf den Rueckfallwert zurueck. Die Farben
  wechselten (Reiter und Titel liegen drinnen), die Motive nicht.
- Die waagerechten Ausschnitte bewirkten nichts. Bei "cover" skaliert
  der Browser auf die Breite des Streifens, die volle Bildbreite ist
  immer sichtbar. Erst ein Zoom ueber 100 % schafft Spielraum.
- Das Thron-Motiv schob seine hellen Kristallfluegel bis unter die
  Reiter. Deshalb deckt die Schicht jetzt bis 46 % statt 34 % -- der
  Wert ist gemessen, nicht geschaetzt.

Dazu zwei Dinge, die erst der Screenshot zeigte: angeschnittene Logos im
Streifen (sieht nach Versehen aus, und das Logo steht ohnehin oben
links), und die Knoepfe Suchen/Abmelden lagen ueber dem hellsten Teil
des Bildes. Sie haben jetzt einen eigenen dichten Grund -- Bedienelemente
muessen lesbar sein, egal was dahinter liegt.

Der Test misst nicht mehr "Deckkraft unter 20 %". Dieser Massstab ist
hinfaellig, seit das Motiv nach rechts gerueckt ist: Es darf kraeftig
sein, WEIL es nicht mehr hinter der Schrift liegt. Geprueft wird
stattdessen, wie ruhig der Grund unter der Reiterzeile ist -- mit Motiv
gegen ohne Motiv, in allen sechs Bereichen. Gemessen: plus 0 bis plus 6.

Unveraendert gilt: kein Motiv hinter Listen, Tabellen oder Zahlen. Ein
Bild hinter einer Zahlenspalte ist genau die Art von Schoenheit, die ein
Werkzeug unbrauchbar macht.

Geprueft: 237 Pruefungen gruen (Verwaltung 39, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 00:26:23 +02:00
DogFatherGitandClaude Opus 5 9df21fabe1 Verwaltung: Bildschmuck an zwei Stellen, beide ausserhalb der Arbeit
Die Verwaltung ist ein Arbeitsplatz. Hier wird nicht geworben, hier
werden Listen gelesen und Zahlen verglichen -- der Schmuck ist deshalb
deutlich zurueckhaltender als auf den oeffentlichen Seiten.

Zwei Stellen, beide bewusst ausserhalb des Arbeitsflusses:

- Ein Ring-Streifen ganz oben, der nach unten wegblendet. Er sitzt
  direkt unter der Kopfleiste und ist verschwunden, bevor die erste
  Tabelle anfaengt. Deckkraft 16 % (Handy 13 %) -- die oeffentlichen
  Motive liegen bei 55 %. Dort traegt das Bild die Stimmung, hier darf
  es die Kopfzeile nur andeuten.
- Das Wappen auf der Anmeldekarte. Dort wird nichts gelesen ausser drei
  Zeilen, also darf es sichtbarer sein.

Was hier ABSICHTLICH nicht passiert: kein Motiv hinter Listen, Tabellen
oder Zahlen. Ein Bild hinter einer Zahlenspalte ist genau die Art von
Schoenheit, die ein Werkzeug unbrauchbar macht. Ein Test haelt das fest.

Ein echter Fehler beim Bauen, den erst der Screenshot zeigte: Das Wappen
stand zuerst auf 38 % und mittig -- der Hundekopf lag genau im
Erklaertext, die Zeilen liefen quer ueber Schnauze und Schriftzug.
Jetzt 16 % und nach unten versetzt, sodass es hinter Eingabefeld und
Knopf sitzt statt hinter den Zeilen. Die Glasflaeche darueber ist hier
dichter als auf den oeffentlichen Seiten.

Der Test dazu misst nicht die Deckkraft, sondern das eigentliche
Problem: wie stark der Untergrund UNTER DER SCHRIFT schwankt, an echten
Bildpunkten aus dem Absatz. Deckkraft allein sagt naemlich nichts -- ein
Motiv mit hellen Kanten ist bei 20 % stoerender als ein ruhiges bei
50 %.

Und er misst im Vergleich, nicht gegen eine geratene Zahl: Schon die
weichgezeichneten Buchstabenkanten allein erzeugen eine Schwankung von
12. Ein fester Grenzwert "unter 14" haette also fast nur diese Kanten
gemessen und waere je nach Schriftgroesse zufaellig gruen oder rot. Der
Test schaltet das Motiv jetzt ab, misst erneut und prueft die Differenz.
Gemessen: mit 14, ohne 12, also plus 2.

Die Tag-Balance von verwaltung.html bleibt unveraendert bei Differenz 1
(vorher 192/191, jetzt 193/192) -- das neue Element ist ausgeglichen,
die alte Meldung ist Altbestand und wurde hier nicht angefasst.

Geprueft: 219 Pruefungen gruen (Verwaltung 21, Portfolio 15, CRYONOVA 53,
Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 23:41:41 +02:00
DogFatherGitandClaude Opus 5 a6c6bbe3ca Portfolio: ZockerAnstalt, Buchhaltung und Command Center aufgenommen
Aus zwei Projekten werden fuenf. Alle drei neuen laufen wirklich, die
Adressen wurden vorher einzeln geprueft:

  zockeranstalt.dogfather-universe.com      Netcup, via Caddy
  buchhaltung.vans-diy-bastelbedarf.com     Netcup, via Caddy
  analyse.dogfather-universe.com            Cloudflare Worker (kein via)

Die Vorschaubilder sind echte Aufnahmen vom 24.08.2026, aufgenommen im
selben Mass wie die bestehenden (1200x750), damit in der Liste nichts
aus der Reihe faellt.

Zwei Aufnahmen sind bewusst nicht unbearbeitet, und das steht auch fuer
die Besucher auf der Seite -- nicht nur im Code:

- Die Buchhaltung zeigt nur die Anmeldung. Sie bekommt deshalb auch
  KEINEN "Live ansehen"-Knopf: Ein Knopf, der bloss auf eine
  Anmeldemaske fuehrt, ist ein leeres Versprechen. Ein Test haelt das
  fest, damit es niemand spaeter "der Vollstaendigkeit halber" einbaut.
- Beim Command Center sind die Gesichter unkenntlich gemacht. Die Seite
  gehoert dem Team, nicht mir, und niemand hat zugestimmt, sein Bild im
  Portfolio zu zeigen. Der Weichzeichner wurde vor der Aufnahme im
  Browser gesetzt, nicht nachtraeglich ins Bild gemalt.

Zwei neue Schildfarben. Aqua traegt Schrift problemlos (11,5:1
gemessen). Indigo NICHT: Prism Indigo ist die einzige Farbe der Palette,
die als Text durchfaellt (3,25--4,29:1) -- das Schild nutzt es deshalb
nur als Flaeche und Kante, die Schrift bleibt Chrome Silver (9,8:1).

Texte in allen fuenf Sprachen, inklusive Schweizerdeutsch. Ueberschrift,
Einleitung und Schlusssatz sagen nicht mehr "zwei" bzw. "beide" -- und
zwar sowohl im Woerterbuch ALS AUCH im deutschen Rueckfalltext im HTML.
Nur die JS-Datei zu aendern haette gereicht, damit es in vier Sprachen
stimmt und ausgerechnet auf Deutsch falsch bleibt.

Drei Fehler steckten wieder in der Pruefung, nicht auf der Seite:
- Sie meldete drei Vorschaubilder als "nicht geladen". Die tragen
  loading="lazy" -- der Test hatte schlicht nie hingesehen.
- Sie zaehlte Navigations- und Markentexte mit. Die liegen aber in
  wd-core.js, gelten fuer alle Seiten und werden von
  server/pruefe-webdesign-i18n.mjs abgedeckt.
- Ihre "kein Zwei mehr"-Suche haette auch Projekttexte getroffen, in
  denen das Wort voellig zurecht steht.

Geprueft wird jetzt das Ergebnis statt des Woerterbuchs: Die Seite wird
wirklich auf jede der fuenf Sprachen umgeschaltet, plus eine Gegenprobe,
dass die Umschaltung ueberhaupt etwas tut.

Geprueft: 198 Pruefungen gruen (Portfolio 15, CRYONOVA 53, Blickfang 13,
System 5, Abmelden 16, Angebot 54, Abbruch 42). Die vier Meldungen aus
server/pruefe-webdesign-i18n.mjs betreffen verwaltung.html und zwei
fehlende Woerterbuecher -- Altbestand, keine dieser Dateien wurde hier
angefasst.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 23:23:27 +02:00
DogFatherGitandClaude Opus 5 01b61905aa Altfaelle aufraeumen: abgebrochene Projekte verschwinden aus der Liste
P-2608-0001 wurde abgebrochen, bevor es das Archiv-Kennzeichen gab. Es
hat deshalb zwar den Status "abgebrochen", aber archiviert = 0 -- und
stand bis heute zwischen den offenen Auftraegen. Also genau das, was der
Wunsch "wenn ich abbreche dan sollen die auch da weg" abstellen sollte.

Ueber die Oberflaeche war das nicht zu reparieren: Die Verwaltung zeigt
bei Status "abgebrochen" den Info-Block statt des Abbrechen-Knopfes, ein
zweiter Klick war also gar nicht moeglich.

Migration statt Handarbeit in der Datenbank: Ein einzelner UPDATE per
Hand repariert einen Fall und hinterlaesst keine Spur. Die Migration
erwischt jeden Altfall, laeuft ueberall gleich (Server, Testdatenbank,
ein spaeterer Neuaufbau) und steht nachvollziehbar in der Geschichte.

Bewusst NICHT gefuellt: abbruch_am, abbruch_grund, abbruch_wer,
abbruch_erstattung_cent. Diese Felder gab es beim damaligen Abbruch noch
nicht. Sie nachtraeglich mit plausiblen Werten zu fuellen waere eine
Behauptung ueber einen Vorgang, bei dem niemand mehr weiss, wie er
wirklich ablief -- und ausgerechnet im Streitfall waere das die
gefaehrlichste Stelle fuer eine Erfindung. Ein leeres Feld sagt ehrlich
"unbekannt", und die Verwaltung zeigt diese Angaben ohnehin nur an, wenn
sie gefuellt sind.

Der Test stellt den Altzustand echt nach: alle Migrationen bis 0017,
dann der Altfall, dann erst 0018. Geprueft wird auch, was NICHT passieren
darf -- ein laufendes Projekt bleibt unberuehrt, ein sauber abgebrochenes
behaelt Datum, Grund und Erstattung, und ein zweiter Durchlauf aendert
nichts mehr (beim Wiederherstellen einer Sicherung passiert genau das).

Geprueft: 167 Pruefungen gruen (Altabbruch 16, Automatik 55, Angebote 56,
Kette 40).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 23:07:37 +02:00
DogFatherGitandClaude Opus 5 99b5dd4eb2 CRYONOVA Schritt 3: Feldfokus, Blickfaenge, Testkorrekturen
Der Feldfokus zeigt jetzt den Ion-Rand und den weichen Schein, den das
Design-System auf Seite 15 verlangt. Er fehlte, weil der allgemeine
Tastaturring seinen dunklen Innenring darueberlegte: Dessen Selektor hat
Spezifitaet 0,3,0, die Feldregel nur 0,2,1 -- und Spezifitaet schlaegt
Reihenfolge, egal wie weit unten die Regel steht. Eingabefelder sind
jetzt vom Innenring ausgenommen; sie brauchen ihn nicht, weil sie selbst
eine dunkle Flaeche sind. Der Aqua-Umriss bleibt fuer alle erhalten.

Die zwei Blickfang-Motive stehen jetzt auch wirklich auf einer Seite:
das Wappen auf "Ueber mich", direkt nach dem Absatz ueber die Herkunft
des Namens, der Monolith auf "Portfolio" zwischen Einleitung und den
echten Projekten. Beide als Zierbild ausgezeichnet -- ihre Aussage steht
schon im Text daneben. Auf dem Handy laedt automatisch die kleine
Fassung.

Vier Fehler steckten in der Pruefung selbst, nicht im Stilblatt:
- Sie griff das erste "input" der Anfrageseite. Das sind aber sechs
  optisch versteckte Auswahl-Radios, kein Textfeld.
- Sie mass ohne Fensterfokus. Ein Browser wendet :focus nur an, wenn das
  Fenster selbst den Fokus hat -- das DOM meldet trotzdem brav
  matches(":focus") === true, die Farbe bleibt die alte.
- Sie mass mitten im Uebergang, bevor die Animation stand.
- Und sie zaehlte Schattenebenen an "),", einem Muster, das in keinem
  Schattenwert je vorkommt. Geprueft wird jetzt die Anforderung selbst:
  Ion-Farbe und ein Weichzeichner ueber 0.

Geprueft: 334 Pruefungen gruen (CRYONOVA 53, Blickfang 13, Abmelden 16,
Angebot 54, Abbruch 42, System 5, Automatik 55, Angebote 56, Kette 40).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 23:03:27 +02:00
DogFatherGit 336e702d90 Druckansicht von der Weiss-Regel ausgenommen
Die Vollstaendigkeitspruefung meldete Punkt 13 (keine weissen
Vollflaechen) als offen. Nachgesehen: Alle Weiss-Werte stehen
ausschliesslich in @media print.

Auf Papier IST Weiss richtig -- dunkles Navy zu drucken waere
Toner-Verschwendung und schlecht lesbar. Das Verbot des Design-Systems
gilt dem Bildschirm, nicht dem Ausdruck. Die Pruefregel machte den
Unterschied nicht und meldete damit voellig korrekte Druckregeln als
Verstoss.

Damit sind alle 14 Punkte der Vollstaendigkeitspruefung erfuellt.
2026-08-24 22:45:27 +02:00
DogFatherGit e92daed103 CRYONOVA Schritt 2: Bildwelt, Materialien, Rangsystem, Status
Setzt die restlichen Kapitel des Design-Systems um (Seiten 7, 14, 16,
19, 24-29). Wie Schritt 1 ausschliesslich Farbe, Material und Licht --
Aufbau, Navigation, Texte und Funktionen bleiben unangetastet.

BILDWELT (Seiten 24-29)
Die Motive sind jetzt echte Seitenhintergruende: Ring auf Startseite
und Portal, Kristallwelt an der Zugangswand. Ueber jedem Motiv liegt
eine Navy-Glasflaeche -- das System fordert auf Seite 31 ausdruecklich,
dass bei Bedarf "eine Navy- oder Frost-Glasflaeche zwischen Bild und
Inhalt" liegt. Ohne sie waere Text auf den hellen Kristallspitzen nicht
sicher lesbar, und genau dort macht ein schoenes Bild eine Seite
unbrauchbar.

Von 2,5 MB auf 96-229 KB (WebP), auf dem Handy 30-73 KB. Das System
nennt fuer Mobile ausdruecklich Ladezeit als Kriterium.

DAS LOGO IM BILD -- eine Entscheidung gegen die woertliche Vorgabe
Zwei der drei Motive zeigen das Dogfather-Logo gross in der Mitte. Als
Seitenhintergrund waere das ein zweites Logo neben dem echten in der
Kopfzeile: zwei Marken, die um dieselbe Aufmerksamkeit ringen. Beim
ersten Versuch schien es an der Zugangswand hinter den Karten durch
(gemessen 15,9 % helle Flaeche im Logobereich). Die Zugangswand nutzt
deshalb jetzt einen Ausschnitt der linken Bildhaelfte -- dieselbe
Kristallwelt, dasselbe Licht, nur ohne Wappen. Die Logo-Motive bleiben
als Blickfang-Klasse erhalten, dort wo sie fuer sich stehen duerfen.

MATERIALIEN (Seite 7)
Optic Glass, Frosted Ice, Prism Edge und Void Navy als Klassen. "Hell"
heisst auf einer dunklen Seite aufgehelltes Navy, nicht Weiss -- echtes
Weiss waere ein Loch im Bildschirm, und das System verbietet weisse
Vollflaechen ausdruecklich.

RANGSYSTEM (Seite 14)
Drei Stufen fehlten: Premium (Indigo), VIP (Champagne), Gefahr (Coral).
Wenn jeder Knopf gleich laut ist, ist keiner mehr laut.

Zwei bewusste Abweichungen von der naheliegenden Loesung:
- Indigo steht als FLAECHE unter hellem Text, nie als Schriftfarbe. Es
  erreicht als Text nirgends 4,5:1 (gemessen 3,25-4,29). Der Test haelt
  das dauerhaft fest.
- Gefahr ist NICHT vollflaechig rot. Ein voll gefuellter roter Knopf
  zieht den Blick staerker an als die Hauptaktion und wird dadurch
  versehentlich gedrueckt. Kritische Aktionen sollen auffindbar sein,
  nicht verlockend.

FOKUSRING (Seite 19)
Doppelter Aqua-Ring: 2 px Aqua aussen, dunkler Innenring. Kein Schmuck
-- ein einfacher heller Ring verschwindet auf hellen Flaechen, ein
dunkler auf dunklen. Die Kombination ist auf JEDEM Untergrund sichtbar.

STATUS-SPEKTRUM (Seite 16)
Acht Zustaende. Die Klasse faerbt nur -- den Text liefert immer das
Markup. Es gibt bewusst keine Variante, die nur einen farbigen Punkt
zeigt: Wer Farben nicht unterscheiden kann, saehe dann gar nichts. Der
Test prueft, dass keine Statusmarke ohne Text existiert.

Dabei einen eigenen Fehler gefunden und behoben: Ich hatte beim Bauen
des Premium-Knopfes selbst einen losen Hex-Wert eingesetzt -- genau
das, was Token-Regel 05 verbietet und was der Test dann meldete.

Geprueft: 43 (CRYONOVA, von 24 erweitert) + 0 Fundstellen (WCAG ueber
12 Seiten x 5 Sprachen, jetzt MIT Bildhintergruenden) + 55 + 40 + 69 +
54 + 42 + 16 + 5 + 20 + 64 + 58 -- alles gruen.
2026-08-24 22:43:58 +02:00
DogFatherGit de8819f1fd CRYONOVA: Farb- und Lichtsystem nach dem Design-System umgesetzt
Umsetzung des Design-Systems "Baby Blue Optical Luxury" (Edition 2.0),
Schritt 1 von mehreren: die zentrale Farbquelle. Nach der Kernregel auf
Seite 3 ist das ausdrücklich ein Farb- und Licht-Redesign — Aufbau,
Navigation, Texte und Funktionen bleiben unangetastet.

FARBEN
Grundflächen auf die vier Tiefenebenen des Systems (Void, Midnight,
Obsidian, Deep Glass). Palette nach Seite 5: Signature Baby, Ion Blue,
Hyper Aqua, Aurora Violet, Prism Indigo, Liquid Gold, Signal Coral,
Chrome Silver.

Die Variablen behalten ihre alten NAMEN (--wd-blau statt --cryo-baby).
Ein Umbenennen hätte über 155 Fundstellen anfassen müssen — viel
Bewegung ohne sichtbaren Nutzen, mit der realen Gefahr, eine Stelle zu
übersehen und danach zwei fast gleiche Blautöne zu haben. Entscheidend
ist die Rolle, nicht der Name; die Systembezeichnungen stehen als
Kommentar daneben.

EIN FEHLER IM DESIGN-SYSTEM, DER BEWUSST NICHT ÜBERNOMMEN WURDE
Die Token-Liste auf Seite 20 ist um eine Zeile verrutscht — Namen und
Hex-Werte passen dort nicht zusammen. Am folgenreichsten: --cryo-baby
stünde auf #0C2740, einem fast schwarzen Navy, und ist laut Seite 21
zugleich die Standard-Lumenfarbe. Das Mauslicht wäre damit praktisch
unsichtbar geworden — ausgerechnet der Effekt, den das System auf fünf
Seiten als unantastbar schützt. Maßgeblich ist deshalb die Palette auf
Seite 5 und die Lumen-Logik auf Seite 9, die untereinander stimmig sind.

MAUSLICHT
Der bestehende Effekt bleibt vollständig erhalten (Systemauflage) und
bekommt eine Farbvariable pro Kachel: --wd-lumen. Vorher war die Farbe
im Verlauf fest verdrahtet, und jede weitere Kachelfarbe hätte zwei
neue Blöcke gebraucht (Fläche + leuchtende Kante). Bei sechs
Lumen-Rollen wären das zwölf fast gleiche Blöcke gewesen, die beim
nächsten Feinschliff zwangsläufig auseinanderlaufen. Jetzt setzt die
Kachel nur ihre Farbe, der Verlauf steht einmal da — genau das meint
Token-Regel 02 mit "Kachelfarbe steuert Lumenfarbe".

38 lose Hex-Codes durch Token ersetzt (Token-Regel 05). Drei davon
(#3d9dbd, #7c5cd6, #a8873a) waren noch die ALTEN Markenfarben und
hätten still neben den neuen weitergelebt — genau der Mechanismus, durch
den Oberflächen mit der Zeit zwei fast gleiche Töne bekommen.

KONTRASTE NACHGERECHNET
Die Palette ist auf dunklem Grund durchweg stark (9,7 bis 19,8:1) — mit
einer Ausnahme: Prism Indigo erreicht auf keiner Fläche 4,5:1 (nur 3,25
bis 4,29). Es ist deshalb ausschließlich für Kanten, Verläufe und große
Premium-Flächen zugelassen, nie für Fließtext. Das System sieht Indigo
ohnehin nur für "Premium-Momente" vor — die Rechnung bestätigt die
Regel, statt ihr zu widersprechen.

NEUER TEST: pruef-cryonova.mjs (24 Prüfungen)
Palette, Grundflächen, Mauslicht-Erhalt, echte Zeigerbewegung, keine
losen Hex-Codes, Kontraste und die Frage, ob alle 12 Seiten wirklich
aus derselben Quelle schöpfen.

Dabei drei Fehlalarme im eigenen Test gefunden und behoben — jeder
davon hätte dauerhaft rote Zeilen erzeugt und irgendwann dazu geführt,
dass man eine echte Meldung übersieht:
- Halbtransparente Flächen müssen über ihren Untergrund gerechnet
  werden. Der aktive Reiter kam sonst auf 1:1 statt echter 8,25–10,23:1.
- Text auf Farbverläufen liefert rgba(0,0,0,0) als Hintergrund; der
  Hauptknopf kam so auf 1:1 statt rund 11:1.
- Die Maus muss mit Zwischenschritten bewegt werden, sonst feuert
  pointermove nicht. Eine Direktmessung bestätigte: Das Licht folgt
  einwandfrei (30px → 723px, Deckkraft 1).

pruef-system.mjs auf den neuen Markenton gesetzt. Dass er dort zunächst
"0 von 1804 Elementen" meldete, war kein Fehler, sondern der Beweis,
dass der alte Ton nirgends mehr vorkommt.

Geprüft: 24 (CRYONOVA) + 0 Fundstellen (Design/WCAG über 12 Seiten × 5
Sprachen) + 40 + 56 + 69 + 54 + 42 + 55 + 5 + 16 — alles grün.
2026-08-24 22:32:04 +02:00
DogFatherGit 305920d872 Cache-Version fuer die Portal-Korrektur (Countdown vor Anzahlung) 2026-08-24 16:54:57 +02:00
DogFatherGit 521f0d5a80 Kompletten Ablauf einmal durchgespielt — echten Fehler dabei gefunden
Wunsch: "ich will dass du es abcheckst" — nicht Stück für Stück (das war
schon geprüft), sondern EINMAL DURCHGÄNGIG als ein zusammenhängender
Ablauf, so wie ein echter Auftrag tatsächlich läuft: Anfrage → Angebot
→ Zusage im Portal → Anzahlung → laufende Uhr → Benachrichtigung →
Arbeit → Restzahlung → Gegenprobe mit Abbruch.

test-kette.mjs bildet genau das ab, gegen die echten Funktionen aus
server-internal/, mit einer Wegwerf-Datenbank. 40 Prüfungen, alle grün.

DABEI GEFUNDEN: Der Liefertermin-Countdown im Portal prüfte nicht, ob
die Uhr überhaupt schon läuft. Ein frisch zugesagtes Projekt hat schon
ein termin_am (aus der Zusage vorgerechnet), aber uhr_start_am steht
noch auf null, solange die Anzahlung nicht da ist. Der Kunde hätte also
direkt nach der Zusage einen tickenden Countdown gesehen — und wenn die
Anzahlung eintrifft, wird der Termin ab dem Zahlungstag NEU berechnet
und springt dann sichtbar nach hinten. Das sieht aus wie ein Fehler,
auch wenn die Zahl rechnerisch stimmt: Kaum zu erklären, warum "noch 8
Tage" plötzlich wieder "noch 10 Tage" werden.

Jetzt zwei klar getrennte Zustände: Vor der Anzahlung steht "Startet,
sobald deine Anzahlung da ist — voraussichtlicher Liefertermin danach:
ca. {datum}" (kein Countdown, aber der Termin bleibt sichtbar, kein
Verstecken). Danach der echte Countdown. Fünf Sprachen ergänzt.

Nebenbei einen irreführenden Kommentar korrigiert: Ein neuer Kunde wird
beim Angebot-Senden SOFORT freigeschaltet (nicht erst bei Zusage, wie
der alte Kommentar behauptete) — sonst könnte er sich gar nicht
einloggen, um sein eigenes Angebot anzusehen. Der Code war richtig,
nur die Erklärung falsch, und mein erster Testentwurf ist genau darauf
hereingefallen.

Bei der Gelegenheit auch die bekannte better-sqlite3-Aussetzer-Eigenart
(zufälliger Absturz beim Prozessende, dokumentiert seit früheren
Commits) noch einmal eingegrenzt: Derselbe Import in test-angebote.mjs
brach mal nach "GEHEIM", mal nach "VORLAGEN" ab — der Absturzpunkt
verschiebt sich zwischen identischen Läufen. Das ist der endgültige
Beweis, dass es reine GC-Zeitfensterflakiness in der nativen
Bibliothek ist, kein Fehler im eigenen Code.

Geprüft: 40 (Kette) + 55 + 56 + 70 + 28 + 49 serverseitig (alle
mehrfach unabhängig grün), 261 im Browser (Portal, Angebot, Übersicht,
Verwaltung, Abbruch, Design). Ein Screenshot bestätigt den neuen
Wartehinweis visuell.
2026-08-24 16:54:35 +02:00
DogFatherGitandClaude Opus 5 e43375728c Abgebrochene Projekte verschwinden aus der Liste
Rueckmeldung: 'wenn ich abbreche dan sollen die auch da weg'.

Ein abgebrochenes Projekt in der laufenden Liste stehen zu lassen ist
doppelt schaedlich: Es verstellt den Blick auf das, was wirklich laeuft,
und beim schnellen Durchsehen haelt man es fuer eine offene Baustelle.

Beim Abbrechen wandert das Projekt jetzt automatisch ins Archiv. Kein
neues Konzept: Den Archiv-Umschalter in der Projektliste gibt es
laengst, und die Suche sowie das Cockpit klammern Archiviertes ohnehin
aus. Es verschwindet damit auch aus dem PORTAL des Kunden -- und das ist
richtig so, ein abgebrochener Auftrag hat dort nichts mehr zu suchen.

Archivieren statt loeschen: Zahlungen, Erstattungsbetrag und Verlauf
haengen daran, und bei einem Streit braucht man genau das. Der Test
prueft beides -- weg aus der Liste UND noch vorhanden.

Geprueft: 55 gegen eine echte Datenbank.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 12:28:05 +02:00
DogFatherGitandClaude Opus 5 8726110035 Angebote in der Oberflaeche: schicken und im Portal zusagen
VERWALTUNG
Der Angebotsbereich steht in der Anfrage-Detailansicht ueber dem
direkten Annehmen. Der uebliche Weg ist: Angebot raus, Kunde sagt zu,
Projekt entsteht -- direkt anzunehmen ist der Sonderfall (man hat schon
telefoniert). Stuende der Sonderfall oben, waere er der naheliegende
Griff, und man verschenkte den Beleg, den eine Zusage im Portal erzeugt.

Vorbelegt sind Paket, Preis, Anzahlung, Laufzeit, Ablaufdatum und der
komplette Leistungstext. Zu tun bleibt: Paket bestaetigen, Preis
bestaetigen. Der Leistungstext ist eingeklappt statt die Seite zu
fluten, aber aenderbar.

Ein Paketwechsel laedt ALLES neu -- auch den Leistungstext. Ein
stehengebliebener Text vom vorigen Paket waere der schlimmste Fall: Er
ginge unbemerkt hinaus, und im Angebot staende etwas, das zum Preis
nicht passt. Genau das prueft der Test.

PORTAL
Die Angebotskarte steht ganz oben, vor allen Projekten: Ein Angebot ist
das Einzige im Portal, das eine ENTSCHEIDUNG verlangt -- alles andere
ist Auskunft. Der eingefrorene Leistungstext wird lesbar aufbereitet
(Zwischenueberschriften, Punkte), nicht als Textblock hingeworfen.

Vor der Zusage wird gefragt, und die Frage nennt die Folgen ('verbindlich',
'Anzahlung'). Nicht aus Foermlichkeit: Hier entsteht ein Vertrag, und ein
Knopf, der beim Danebentippen einen Auftrag ausloest, waere eine Falle.
Beim Ablehnen wird NICHT gefragt -- das ist folgenlos.

ZWEI FEHLER GEFUNDEN, BEIDE IM NORMALFALL
- Die Angebotskarten standen im Zweig 'es gibt Projekte'. Ein Kunde mit
  offenem Angebot hat aber typischerweise noch KEIN Projekt -- genau der
  Normalfall -- und saeh damit nichts. Der Server lieferte das Angebot,
  die Seite zeichnete es nur nie. Nur im Browsertest sichtbar.
- Eine Antwort ohne 'nachrichten' liess das Postfach werfen, und weil der
  Fehler den Aufbau abbrach, erschien danach GAR NICHTS mehr -- auch nicht
  das Angebot, das ueber allem stehen sollte. Dieselbe Sorte wie zuvor im
  Cockpit: Ein halber Server ist ein realistischer Fall.

Neun Sprachschluessel in fuenf Sprachen ergaenzt.

Geprueft mit 54 Pruefungen auf Computer und Handy, die messen, was
tatsaechlich an den Server geht. Alle bestehenden weiter gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 12:23:44 +02:00
DogFatherGitandClaude Opus 5 cea265eb8c Angebote: der Kunde sagt mit einem Klick zu
DER LEITGEDANKE: SO WENIG TIPPEN WIE MOEGLICH
Niemand schreibt hier den Leistungsumfang. Er entsteht aus der
Aufgabenvorlage des Pakets -- denselben 92 Punkten, nach denen spaeter
gearbeitet wird. Der Nebeneffekt ist wichtiger als die gesparte
Tipparbeit: Was im Angebot steht, IST die Arbeitsliste. Ein von Hand
geschriebenes Angebot und eine getrennt gepflegte Aufgabenliste laufen
unweigerlich auseinander -- und dann steht im Angebot etwas, das niemand
abarbeitet.

Zu tun bleibt: Paket waehlen, Preis bestaetigen. Beides ist vorbelegt,
Laufzeit und Ablaufdatum werden gerechnet.

DER WORTLAUT WIRD BEIM ABSENDEN EINGEFROREN
Ein angenommenes Angebot ist ein Vertrag. Bei einem Streit zaehlt, WAS
dem Kunden gezeigt wurde, als er zusagte. Wuerde der Text bei jeder
Ansicht neu aus den Vorlagen erzeugt, staende nach der naechsten
Vorlagenaenderung etwas anderes da als damals. Die Zusage wird mit
Zeitpunkt und (gehashter) Herkunft belegt -- die Beweislast liegt beim
Unternehmer.

WAS AUTOMATISCH PASSIERT
Angebot raus -> Anfrage steht auf 'angebot' (der Wunsch: 'wenn ich ein
angebot rausschicke soll der automatisch das erkennen'). Zusage ->
Projekt angelegt, Aufgabenliste eingesetzt, Anzahlung als offene
Rechnung erzeugt, Anfrage auf 'angenommen', Benachrichtigung an mich.

Die UHR startet dabei NICHT. Sie startet erst mit dem Zahlungseingang --
das ist die Regel aus dem vorigen Schritt, und sie gilt auch dann, wenn
der Kunde selbst zugesagt hat. Genau dieser Punkt wird ausdruecklich
geprueft: Es fuehlt sich richtig an, mit der Zusage loszulegen.

ZWEI FEHLER IN DER GELDANZEIGE GEFUNDEN
Beide fielen erst auf, als das erste Angebot ueber tausend Euro entstand
-- alle frueheren Testbetraege lagen darunter:
- Kein Tausenderpunkt: 1490 Euro erschienen als '1490,00 €'.
- Das Minuszeichen ging verloren: Math.trunc(-0.5) ergibt -0, und -0
  schreibt sich als '0'. Eine ERSTATTUNG von 50 Cent erschien damit als
  '0,50 €' -- also wie eine Forderung. Ausgerechnet beim Abbruch mit
  Rueckzahlung waere das der falsche Ort fuer einen Anzeigefehler.
Bewusst von Hand statt ueber Intl.NumberFormat: Die Ausgabe muss auf dem
Server und im Browser zeichengleich sein -- ein Betrag, der in der
Verwaltung anders aussieht als im Portal, saet Zweifel an der Zahl.

Geprueft: 56 zu den Angeboten, 53 zur Automatik (inkl. der neun
Geldpruefungen), 70 zur Annahme, 28 zur Suche -- alle gegen eine echte
Datenbank. Darunter: zweiter Klick legt nichts doppelt an, abgelaufene
Angebote lassen sich nicht mehr annehmen (ein Angebot, das man sieht
aber nicht annehmen kann, waere eine Falle), ein fremder Kunde erfaehrt
nicht einmal, dass ein Angebot existiert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 12:14:27 +02:00
DogFatherGitandClaude Opus 5 658febb6c5 Abbruch-Dialog und Farbunterscheidung meins/beim Kunden
ABBRECHEN IN DER OBERFLAECHE
Der Server konnte es seit gestern, die Knoepfe fehlten. Jetzt steht am
Ende der Projektansicht ein zurueckhaltender Knopf -- bewusst nicht
zwischen den anderen: Es ist die seltenste und endgueltigste Handlung an
einem Projekt, und ein gleich lauter Knopf daneben laedt zum
Verwechseln ein.

Beim Aufklappen rechnet die Seite vor: wie viele Schritte erledigt sind,
wie viel gezahlt wurde, wie viel davon verdient ist, und was sich daraus
als Erstattung ergibt. Der Betrag steht als Vorschlag im Feld und ist
aenderbar -- geprueft wird, dass der GEAENDERTE Wert hinausgeht und nicht
der vorgeschlagene, sonst waere das Feld eine Attrappe.

Gerechnet wird erst beim Aufklappen, nicht beim Oeffnen der
Projektansicht: Dazwischen kann man Punkte abgehakt haben, und die
Zahlen sollen den Stand von JETZT zeigen. Faellt die Vorschau aus, laesst
sich der Betrag von Hand eintragen -- ein ausgefallener Rechendienst darf
kein Projekt in der Liste festhalten.

Ein bereits abgebrochenes Projekt bekommt keinen Knopf mehr, sondern
einen Kasten mit Datum, Grund, wer abgebrochen hat und was zu erstatten
war.

MEINS ODER SEINS
Wunsch: 'ich will dass die kunden sachen auch in der verwaltungs seite
von kacheln eine andere farbe haben wie meine damit ich sie gut
unterscheide.'

Was bei mir liegt, bleibt im Markenblau. Was beim Kunden liegt, bekommt
Lila. Gemessen: rgb(127,208,232) gegen rgb(183,157,255).

Bewusst NICHT ueber Rot/Gruen: Die Warnstufen sind an das ALTER
vergeben und muessen frei bleiben. Eine Kachel, die gleichzeitig 'beim
Kunden' und 'seit acht Tagen ueberfaellig' faerben muesste, koennte nur
eine der beiden Aussagen zeigen -- und die Frist ist die wichtigere.

Dazu eine 3px-Kante links auf beiden Seiten. Farbe allein traegt die
Aussage nicht: Wer sie nicht unterscheiden kann, saehe sonst zwei gleich
aussehende Bloecke (WCAG 1.4.1). Die Kante ist ein Gegensatz, keine
Markierung einer Gruppe -- meins blau, seins lila.

Geprueft mit 42 Pruefungen auf Computer und Handy, die messen, was
tatsaechlich an den Server geht und welche Farben wirklich berechnet
werden. Alle bestehenden Pruefungen weiter gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 12:05:25 +02:00
DogFatherGitandClaude Opus 5 65b98ace89 Die Uhr laeuft erst, wenn die Anzahlung da ist
Bisher begann der Liefertermin mit der Annahme. Das ist unfair in beide
Richtungen: Wer zehn Tage bis zur Zahlung braucht, verbraucht zehn Tage
der zugesagten Zeit, ohne dass ein Handschlag Arbeit passiert waere --
und ich stehe am Ende als der da, der seinen Termin reisst.

Ein Projekt hat jetzt drei Abschnitte statt zwei:
  1. angenommen, wartet auf Anzahlung  -> Uhr steht
  2. Anzahlung da                      -> Uhr laeuft, Termin ab HEUTE neu
  3. uebergeben oder abgebrochen       -> Uhr steht wieder

Der Zahlungseingang loest alles Weitere von selbst aus: Uhr starten,
Termin neu rechnen, Status von briefing auf design, 'wer ist am Zug' auf
mich, Benachrichtigung in der Verwaltung. Der bei der Annahme genannte
Termin bleibt als termin_geplant_am erhalten, und die Meldung nennt
BEIDE -- so sieht man, dass sich etwas verschoben hat, ohne nachrechnen
zu muessen.

Eingehaengt an der Stelle, an der beide Wege zusammenlaufen (PayPals
Meldung UND das Vermerken von Hand). Nur am Webhook haenge sich die
Seite verschieden verhalten, je nachdem WIE das Geld ankam -- eine von
Hand verbuchte Zahlung startete die Uhr nie.

Zwei Grundsaetze fuer die Automatik: Sie setzt Dinge in Gang, nimmt aber
nie eine Entscheidung zurueck, die ein Mensch getroffen hat (ein von Hand
pausiertes Projekt wird nicht kommentarlos wieder gestartet). Und jeder
Schritt hinterlaesst eine Spur im Verlauf UND als Meldung -- eine
Automatik, die stillschweigend arbeitet, ist kein Helfer, sondern ein
Raetsel.

ABBRECHEN
Ein angenommener Auftrag bleibt abbrechbar: Der Kunde zahlt nicht,
meldet sich nicht, springt ab. Vorschau und Ausfuehrung sind getrennt --
die Seite rechnet aus dem Aufgabenfortschritt vor, wie viel Leistung
erbracht wurde, und schlaegt daraus einen Erstattungsbetrag vor. Der
Betrag ist ein VORSCHLAG: Ob im Einzelfall mehr oder weniger angemessen
ist, haengt an Dingen, die keine Tabelle kennt. Offene Rechnungen werden
storniert (eine Zahlungsaufforderung ohne Gegenleistung), bezahlte
bleiben unangetastet, und die Rueckzahlung loest die Seite bewusst NICHT
selbst aus -- PayPal-Rueckzahlungen sind nicht umkehrbar.

BENACHRICHTIGUNGEN
Eigene Tabelle statt im Verlauf: Der Verlauf haelt fest, WAS geschehen
ist -- vollstaendig, zum Nachschlagen. Eine Benachrichtigung ist ein
Anstupsen, das gelesen und weggelegt wird. Beides in einer Tabelle
hiesse: entweder ein Verlauf voller Rauschen oder Meldungen, die man
nicht wegklicken kann. Wegklicken markiert nur als gelesen, loescht
nichts.

Dazu die Liste der Projekte, die seit ueber einer Woche auf ihre
Anzahlung warten. Sie stehen in keiner anderen Zahl, weil ihre Uhr nie
zu laufen begann -- ohne diesen Hinweis vergisst man sie.

Geprueft: 44 gegen eine echte Datenbank. Darunter der Kern -- die
Annahme wird zehn Tage zurueckdatiert, und der Termin muss danach
trotzdem volle 20 Werktage entfernt liegen. Beim Bauen des Tests selbst
ein Fehler gefunden: Die erste Fassung datierte nur die Annahme zurueck,
nicht den damals errechneten Termin, und bildete damit genau den Fall
nicht ab, um den es geht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 11:56:08 +02:00
DogFatherGitandClaude Opus 5 6b818fd6f6 Abmelden meldet jetzt wirklich ab
Rueckmeldung: 'der abmelde button klappt auch nicht auf dem handy'. Die
Ursache war nicht das Handy -- der Fehler war auf beiden Geraeten
derselbe, auf dem Handy sieht man das kurze Aufblitzen nur eher.

Der Knopf beendete die Team-Sitzung, loeschte den Schluessel und lud neu.
Das Merkmal der Zugangswand blieb dabei im Browser stehen. Beim
Neuladen holt sich die Seite damit sofort wieder einen Ausweis -- man
war nach einer Zehntelsekunde erneut angemeldet, und der Knopf schien
nichts zu tun.

Jetzt werden BEIDE Sitzungen beendet (der Endpunkt dafuer gab es
laengst, die Verwaltung rief ihn nur nie auf), und man landet an der
Zugangswand statt in einer Codeeingabe. Das ist auch die ehrliche
Bedeutung des Wortes: Wer sich abmeldet, will draussen sein.

Beide Aufrufe sind einzeln abgesichert -- faellt einer aus, laeuft der
andere trotzdem. Ein halbes Abmelden waere schlimmer als keins: Man
hielte sich fuer abgemeldet und waere es nicht.

Geprueft mit 16 Pruefungen auf Computer und Handy, die messen, was
tatsaechlich hinausgeht statt ob sich etwas auf dem Schirm bewegt.
Dabei ein Artefakt im eigenen Test gefunden und behoben: Das
Vorbereitungsskript lief bei jeder Navigation und setzte den Schluessel
auf der Zugangswand gleich wieder -- zwei Pruefungen massen also sich
selbst.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-24 11:29:28 +02:00
DogFatherGitandClaude Opus 5 2ae77fc54f Verwaltung: eine Suche ueber alles, mit Tastatur bedienbar
Bisher gab es genau ein Suchfeld, und es durchsuchte nur die
Anfragenliste. Wer den Namen eines Kunden im Kopf hatte, musste raten,
in welchem Reiter er nachsehen muss: War das eine Anfrage, ein laufendes
Projekt, eine offene Rechnung? Bei drei Vorgaengen merkt man sich das,
bei dreissig nicht mehr.

Jetzt: Strg+K von ueberall, auf dem Handy der Lupenknopf oben. Ein
Aufruf durchsucht Anfragen, Kunden, Projekte und Zahlungen; jeder
Treffer traegt seinen Zusammenhang (Nummer, Kunde, Betrag, Liefertermin)
und fuehrt per Enter in den passenden Reiter, bei einer Anfrage direkt in
die Detailansicht.

Gebaut nach dem ARIA-Muster 'Combobox mit Listbox-Popup' aus den W3C
Authoring Practices -- nachgeschlagen, nicht aus dem Gedaechtnis:
role=combobox am Eingabefeld, aria-expanded, aria-controls,
aria-activedescendant, role=listbox, role=option mit aria-selected. Der
Fokus bleibt dabei im Eingabefeld, damit man weitertippen kann; die
Auswahl wandert ueber aria-activedescendant. Ohne diese Auszeichnung
waere ein Feld, das Vorschlaege einblendet, fuer einen Screenreader
stumm -- das sieht man beim Testen mit den Augen nie.

Vier Fallen ausdruecklich behandelt:
- Nicht bei jedem Tastendruck suchen (180 ms Wartezeit): 'Musterbau'
  haette sonst neun Abfragen ausgeloest, acht davon veraltet.
- Das Wettrennen der Antworten: Jede Abfrage bekommt eine laufende
  Nummer, nur die neueste darf zeichnen. Sonst ueberschreibt eine spaet
  eintreffende alte Antwort die neue.
- Leer, laedt und Fehler sind eigene Zustaende. Ein Kasten, der bei
  einem Serverfehler leer bleibt, sieht aus wie 'nichts gefunden'.
- LIKE-Sonderzeichen: '%' waere ein Platzhalter, '_' ein beliebiges
  Zeichen -- und Unterstriche stehen regelmaessig in E-Mail-Adressen.
  Der Fehler ist tueckisch, weil die Suche trotzdem Treffer liefert, nur
  die falschen.

Ausserdem zum dritten Mal dieselbe Spezifitaetsfalle gefunden: '.wd p'
schlug die eigene Regel, der Tastaturhinweis erschien in 17,9px statt
11,5px -- so gross wie der Inhalt, den er erklaert. Jetzt festgenagelt
durch eine Pruefung, die Groessenverhaeltnisse vergleicht.

Geprueft: 28 gegen eine echte Datenbank (darunter alle
LIKE-Sonderzeichen), 64 im Browser auf Computer und Handy inkl. der
ARIA-Vorgaben, des Wettrennens und des Fehlerzustands.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 23:13:23 +02:00
DogFatherGitandClaude Opus 5 659a1ee9ce Verwaltung fragt nicht mehr grundlos nach dem Zugangscode
Zwei Ursachen, die zusammenwirkten.

1. Nach einem Neuladen war die HERKUNFT des Schluessels vergessen. Der
   Code speicherte nur den Schluessel selbst, nicht ob er aus einer
   Codeeingabe oder aus dem Ausweis der Zugangswand stammt.

2. Weil die Herkunft fehlte, wurde vorsichtshalber 'code' angenommen.
   Als Vorsicht gedacht, mit unangenehmer Kehrseite: Ein Ausweis gilt nur
   15 Minuten. Als 'code' behandelt wurde er nie erneuert -- nach einer
   Viertelstunde kam der erste 401, und man landete in der Codeeingabe,
   obwohl alles in Ordnung war. Der Schutz 'eine Code-Sitzung wird nie
   durch einen Ausweis ersetzt' war damit ab dem ersten Neuladen ohnehin
   wirkungslos.

Die Herkunft steht jetzt neben dem Schluessel und ueberlebt ein
Neuladen. Fehlt sie -- etwa aus einer aelteren Sitzung --, bleibt es bei
der vorsichtigen Annahme 'code'.

Das behebt die Haelfte des Problems. Die andere Haelfte ist eine
Einstellung auf dem Server: Die beiden Dienste benutzen nicht dasselbe
WEBDESIGN_API_SECRET, weshalb jeder Ausweis abgelehnt wird. Der Kommentar
in server/.env.example sagt ausdruecklich, dass beide Werte exakt gleich
sein muessen. Das kann nur Filipe angleichen -- /home/dogiintern/ ist
fuer claudian gesperrt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 22:50:22 +02:00
DogFatherGitandClaude Opus 5 131bc8a755 Anfragen annehmen und ablehnen — mit laufender Zeit bis zur Übergabe
Annehmen war bisher nur ein Etikett: Man stellte den Status um, und es
passierte nichts. Kunde, Projekt, Aufgabenliste, Termin und Zugang musste
man danach von Hand in fünf Schritten nachbauen. Der alte Code gab das im
Kommentar selbst zu -- schlug der zweite von zwei Aufrufen fehl, stand der
Kunde schon in der Datenbank und man durfte es nicht noch einmal
versuchen.

Jetzt macht das EIN Aufruf, ganz oder gar nicht:
Kunde finden oder anlegen, Projekt anlegen, die komplette Aufgabenliste
des Pakets einsetzen, Liefertermin berechnen, Einladungslink erzeugen.
Der Kunde verfolgt ab diesem Moment alles in seinem Portal.

Die Zeit läuft wirklich:
- Eigenes Datumsfeld (termin_am) neben dem freien Text. Aus 'Mitte
  Oktober' kann man keine verbleibenden Tage rechnen.
- Werktage statt Kalendertage, inklusive luxemburgischer Feiertage. Die
  beweglichen werden über die Osterformel berechnet statt gepflegt --
  eine Liste ist im übernächsten Jahr lautlos falsch.
- Vorschlag je Paket (Onepager 10, Website 20, Shop 30 Werktage),
  überschreibbar vor dem Bestätigen.
- Verbleibende Zeit wird SERVERSEITIG gerechnet. Der Browser kennt die
  Feiertage nicht; zwei verschiedene Zahlen für denselben Termin wären
  schlimmer als gar keine.

Ablehnen mit Grund und vorbereiteter Absage in fünf Sprachen, Text
serverseitig erzeugt und vor dem Abschicken lesbar. Ein laufendes
Projekt lässt sich nicht nachträglich als Anfrage ablehnen.

Sechs Fehler dabei gefunden:
- Ein unbekanntes Paket hätte GAR KEINEN Termin bekommen statt des
  Ersatzwerts. Zwei Funktionen lasen dieselbe Tabelle, nur eine hatte
  einen Rückfallwert. Eine fehlende Zahl fällt nirgends auf.
- wd_anfragen hat keine Spalte 'firma' -- better-sqlite3 weist undefined
  ab, die ganze Annahme wäre gescheitert.
- Migrationen stehen in einer ausdrücklichen Liste; 0015 fehlte darin.
- datumKurz() wurde aufgerufen, gab es aber nicht. Der Fehler wäre erst
  NACH dem Anlegen aufgetreten.
- Der Installations-Hinweis lag fest über dem Annehmen-Knopf und machte
  ihn auf dem Handy untreffbar. Die Seite reserviert jetzt Platz dafür.
- 'richttermin' ist freier Text, lief aber durch einen Datumsformatierer:
  Der Kunde las 'Invalid Date' an der wichtigsten Stelle seines Projekts.

Geprüft: 49 Prüfungen der Terminrechnung gegen nachschlagbare Osterdaten
und Wochentage, 70 gegen eine echte Datenbank (darunter: zweiter Klick
legt nichts doppelt an, Abbruch mittendrin lässt NICHTS zurück, gesperrter
Kunde wird nicht still entsperrt), 42 im Browser auf Computer und Handy,
40 im Portal. Alle bestehenden Prüfungen weiter grün.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 22:44:08 +02:00
DogFatherGitandClaude Opus 5 37f1b4a8f5 Handy: Sicherheitsabstaende, Wisch-Reiter, zweispaltige Uebersicht
Der wichtigste Fund: env(safe-area-inset-*) stand bereits im CSS, lieferte
aber immer null -- viewport-fit=cover fehlte auf allen dreizehn Seiten.
Der Code sah richtig aus und tat nichts. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (schon gesetzt)
hiess das: installiert lag die Kopfzeile auf einem iPhone hinter Uhr und
Akkuanzeige.

Behoben:
- viewport-fit=cover auf allen 13 Seiten.
- Vier Sicherheitsabstaende zentral benannt statt an jeder Stelle
  einzeln geschrieben. Kopfzeile weicht der Statusleiste, Container dem
  seitlichen Notch im Querformat, Fusszeile der Gestenleiste.
- Der 'Ueberspringen'-Knopf des Vorspanns lag mit bottom:2rem praktisch
  AUF dem Entsperr-Strich (34px). Man haette die App verlassen statt
  uebersprungen.
- Eigener Zweig fuer den installierten Betrieb: kein Gummiband-
  Nachfedern (sieht in einer App nach einem Fehler aus), kein
  Installations-Hinweis.
- Die vier Sprungmarken auf der Rechtsseite waren 39px hoch -- fuenf
  unter dem Daumenmass. Ausgerechnet dort muss man zum Widerrufsrecht
  springen koennen.
- 'Waehle links einen Verlauf aus': Auf dem Handy gibt es kein links,
  die Liste steht darueber. Richtungswort entfernt.
- Sechs Reiter brauchten auf dem Handy drei Zeilen. Jetzt ein
  Wischstreifen mit Einrasten und Auslauf am Rand; der aktive Reiter
  wird herangeholt, wenn man ueber eine Kachel springt.
- Uebersicht zweispaltig statt zwoelf Zeilen untereinander: 2635px ->
  1924px. Eine Uebersicht, an der man vorbeiwischen muss, ist keine.

Geprueft mit 55 neuen Handy-Pruefungen auf iPhone 14 Pro, Pixel 7 und
320px Breite, jeweils im Browser und im installierten Zweig. Drei
Fehlalarme der eigenen Pruefung wurden begruendet ausgenommen (Honigtopf
bei left:-9999px, Eingabefeld in einer Beschriftung, Inline-Link im
Fliesstext -- WCAG 2.5.8 nimmt letztere ausdruecklich aus).

Zwei Selbstkorrekturen an der Pruefung dokumentiert: Die Emulation von
display-mode wirkt nicht (Chromium nimmt den Befehl an und ignoriert
ihn) -- ohne das waeren die zwoelf 'installiert'-Zeilen ein zweiter
Browser-Durchgang gewesen. Und die Messung gegen die Systemleisten mass
zuerst die Kastenkante statt der Inhaltskante und meldete elf korrekte
Seiten als fehlerhaft. Eine Selbstpruefung mit einem absichtlich falsch
gesetzten Knopf belegt jetzt, dass die Messung echte Fehler findet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 19:51:10 +02:00
DogFatherGitandClaude Opus 5 c1cb51884f Verwaltung: Übersicht als Startansicht, Reiter unter den Titel
Die Reiter standen neben dem Titel. Das las sich wie eine einzige lange
Zeile, in der der Titel nur der erste von sechs Knöpfen zu sein schien --
man sah nicht auf einen Blick, in welchem Bereich man war. Jetzt zwei
Zeilen: oben WO man ist, darunter WOHIN man kann.

Die Verwaltung öffnete bisher mit der Anfragenliste. Eine Liste ist eine
Ablage: Sie zeigt, WAS es gibt, nicht was zu TUN ist. Neu ist ein
Cockpit, das in drei Stufen antwortet -- was auf mich wartet, was beim
Kunden liegt, wie es ums Geld steht -- und dann laufende Projekte mit
Fortschritt sowie den Verlauf.

Zwei Grundsätze machen die Zahlen brauchbar: Getrennt nach 'wartet auf
mich' und 'wartet auf den Kunden' (zwölf offene Punkte sind entspannt,
wenn elf beim Kunden liegen). Und das ALTER färbt, nicht die Menge --
vier neue Anfragen sind kein Problem, eine seit sechs Tagen liegende
schon. Ein offener Widerruf ist immer rot, weil eine gesetzliche Frist
läuft.

Jede Kachel ist ein echter <button> und führt in den passenden Reiter.
Farbe ist nie der einzige Träger: Neben jedem farbigen Zustand steht der
Text ('älteste seit 8 Tagen').

Drei Fehler dabei gefunden und behoben:
- Der Titel wurde nur beim Klicken gesetzt. Frisch geladen zeigte die
  Seite das Cockpit, während darüber noch 'Projektanfragen' stand. Die
  Zuordnung Reiter->Titel liegt jetzt ausserhalb des Klick-Zuhörers.
- '.wd h2' überstimmte '.vw-ub-h': 44px Überschrift über 33px Zahl, die
  Seite las sich wie ein Plakat. Dieselbe Spezifitätsfalle wie früher
  bei '.wd a'.
- Eine Antwort mit ok:true aber ohne Inhalt riss die ganze Verwaltung
  mit. Wird jetzt abgefangen -- ein halber Server ist ein realistischer
  Fall.

Geprüft: 22 Serverprüfungen gegen eine echte Datenbank (inkl. vier
Fällen, die belegen, dass die Rechteprüfung wirklich greift), 56 im
Browser auf Computer und Handy, 69 im bestehenden Verwaltungstest,
0 Fundstellen im Design-/WCAG-Test, 5 im Farbsystemtest.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 19:21:12 +02:00
DogFatherGitandClaude Opus 5 4fe66e1e0e "Preise & Zeit" entfernt -- Inhalte in die Leistungen uebernommen
"leistungen und preis&zeit ist ja das gleiche, nimm die kategorie
preise&zeit komplett weg"

Stimmt bei den Paketen und Preisen: Beide Seiten zeigten dieselben
Zahlen. Zwei Orte fuer dieselbe Zahl sind eine Einladung, dass sie
irgendwann auseinanderlaufen -- und dann steht ein falscher Preis auf
der Seite, ohne dass es jemand merkt.

NICHT ALLES WAR DOPPELT

Vor dem Loeschen nachgesehen statt einfach geloescht. Zwei Abschnitte
gab es NUR dort:

  "Was den Preis bewegt"  -- beantwortet die Frage, die nach jeder
       Preisliste kommt: Warum kostet es bei mir mehr oder weniger?
       Ohne sie ist eine Preisspanne eine Behauptung.

  "Wie bezahlt wird"  -- Angebot, 30 % Anzahlung, Restbetrag, Betreuung.
       Rechtlich relevant und aus den AGB verlinkt.

Beide sind in die Leistungen umgezogen, samt ihrer 24 Textbausteine in
allen fuenf Sprachen. Waeren sie mitgeloescht worden, haette es niemand
sofort bemerkt -- und die Seite haette ab dann Preise genannt, ohne sie
zu erklaeren.

WEITERLEITUNG STATT 404

Die Adresse /webdesign/preise.html bleibt bedient und fuehrt auf die
Leistungen. Lesezeichen, alte Links aus Nachrichten und die installierte
App zeigen sonst ins Leere, und ein 404 auf einer Preisseite ist der
denkbar schlechteste erste Eindruck.

302 statt 301: Eine dauerhafte Weiterleitung merken sich Browser
hartnaeckig; sollte die Seite je zurueckkehren, muesste jeder Besucher
seinen Zwischenspeicher leeren.

EIN FEHLER BEIM EINBAU

Die Weiterleitung stand zuerst weiter unten in der Schranke, bei den
ohne Code erreichbaren Seiten. Dort haette sie nur fuer NICHT angemeldete
Besucher gegriffen -- wer angemeldet ist, passiert die Schranke vorher
mit next() und haette einen 404 auf die geloeschte Datei bekommen.
Genau die Person also, die die Seite am ehesten im Lesezeichen hat.
Jetzt steht sie ganz vorne, vor jeder Zugangspruefung.

GEPRUEFT: 10 Pruefungen -- beide uebernommenen Abschnitte erscheinen in
allen fuenf Sprachen, kein unuebersetzter Schluessel sichtbar. Kein
Verweis auf die alte Seite blieb irgendwo stehen (ablauf.html hatte
einen, der ist umgebogen). Gestaltung 0 Befunde, Textkodierung sauber,
Designsystem 5.

Versionsstempel und Cache auf v20.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 19:00:49 +02:00
DogFatherGitandClaude Opus 5 d6e75ce56a Kacheln: Licht folgt dem Zeiger, Rand glueht mit
"ich will das die kacheln richtig speziell sind und modern ... dass viel
mehr auffaellt und doch modern und profissionell"

Die Kacheln hatten Verlaufsrand, Verlaufsflaeche, Schatten und
Lichtkante -- alles richtig, alles STATISCH. Was fehlte, war das Gefuehl
von Material: eine Flaeche, die auf Licht reagiert.

ZWEI EBENEN

Ein weicher Lichtfleck folgt dem Zeiger ueber die Flaeche. Und -- der
Teil, der wirklich auffaellt -- der RAND glueht an derselben Stelle auf
und verlaeuft nach beiden Seiten aus.

Das geht ohne zusaetzliches Element: Die Kachel hat bereits zwei
Hintergrundebenen (Flaeche padding-box, Verlaufsrand border-box). Beim
Ueberfahren bekommt die Randebene einen Lichtpunkt an der Zeigerstelle.
Der Rand ist nur einen Pixel breit -- genau dort laesst sich Licht am
staerksten zeigen, ohne kitschig zu werden. Ein Lichtfleck OHNE
mitleuchtende Kante wirkt wie ein Fleck AUF der Kachel; mit ihr wirkt
die ganze Kachel beleuchtet.

Die Flaeche selbst bleibt beim Ueberfahren unveraendert -- sonst wuerde
der Text flackern.

VIER ENTSCHEIDUNGEN GEGEN BILLIGE OPTIK

Die Farbe folgt der Kachel: blaue leuchten blau, lila lila. Sonst braeche
der Effekt die Farbordnung, die ueberall sonst Bedeutung traegt.

Nur bei echtem Zeiger (hover: hover, pointer: fine). Auf dem Handy gibt
es keinen; dort bliebe der Lichtfleck an einer zufaelligen Stelle kleben.

Aus bei prefers-reduced-motion. Auch wenn sich nichts bewegt: Etwas, das
dem Zeiger folgt, ist Bewegung.

Erste Fassung war mit 13 % zu zurueckhaltend -- am Screenshot geprueft
und auf 22 % angehoben. "Man soll es spueren" ist richtig, aber es muss
auch ankommen.

SPARSAM GEBAUT

EIN Zuhoerer am Dokument statt einem je Kachel -- sonst muesste jede
nachgeladene Kachel einzeln nachgeruestet werden. Geschrieben wird erst
im naechsten Bildaufbau: Der Zeiger meldet sich bis zu tausendmal je
Sekunde, der Bildschirm zeichnet sechzigmal; ohne Drosselung rechnet der
Browser neunhundertmal umsonst.

Der Inhalt bekommt z-index 1. Ohne das legt sich der absolut gesetzte
Lichtfleck ueber den Text -- absolut positionierte Elemente malen ueber
Fluss-Inhalt, auch wenn sie im Quelltext davor stehen. Das Ergebnis waere
ein Schleier auf der Schrift, den man erst beim Vergleich zweier Kacheln
bemerkt. Eigens geprueft.

GEPRUEFT: 7 Pruefungen fuer den Effekt selbst -- unsichtbar im
Ruhezustand, erscheint beim Ueberfahren, folgt dem Zeiger auf 6 Pixel
genau, Inhalt liegt darueber, lila Kacheln leuchten lila, bei
Bewegungsempfindlichkeit vollstaendig abgeschaltet.

Gestaltung 0 Befunde, Designsystem 5, Verwaltung 69, Portal 32.

Versionsstempel und Cache auf v19.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 18:53:05 +02:00
DogFatherGitandClaude Opus 5 e495542fe5 Typografie: Lesebreite begrenzt -- 105 zu breite Absaetze behoben
Gemessen ueber alle Seiten: 105 von 200 Textabsaetzen waren zu breit,
der schlimmste mit 151 Zeichen pro Zeile.

WARUM DAS ZAEHLT

Beim Zeilensprung muss das Auge zurueck an den Zeilenanfang finden. Je
laenger die Zeile, desto haeufiger landet es in der falschen -- man
liest eine Zeile doppelt oder ueberspringt eine und merkt es erst zwei
Saetze spaeter. Der Text ist dann nicht "schwer", er ist schlecht
gesetzt.

Bewaehrt sind 45 bis 75 Zeichen. Das ist der aelteste und
bestbelegte Grundsatz der Typografie ueberhaupt -- jedes ordentlich
gesetzte Buch haelt sich daran.

Jetzt 68 Zeichen fuer Fliesstext, 60 fuer Kleingedrucktes. Die Einheit
ist ch statt Pixel: Damit haengt die Breite an der SCHRIFTGROESSE.
Kleingedrucktes bekommt automatisch einen schmaleren Block, grosse
Schrift einen breiteren -- beide landen bei aehnlich vielen Zeichen.

max-width macht nie etwas breiter. In schmalen Karten und Spalten
aendert sich also nichts; die Regel greift nur dort, wo eine Zeile
wirklich ueber das Lesbare hinauswaechst. Ergebnis: von 105 auf 0.

DREI FEHLER BEIM EINBAU, ALLE VON DER MESSUNG GEFUNDEN

1. Zentrierter Text stand ploetzlich links. Eine Breitenbegrenzung
   zentriert den KASTEN nicht mit -- die Schrift war mittig, ihr Kasten
   klebte am linken Rand, mit 384 Pixeln Luft rechts und null links.
   Gefunden, weil die Pruefung den Abstand links mit dem rechts
   VERGLEICHT, statt nur zu zaehlen, ob zentriert ist.

2. Meine erste Regel deckte nur den Fall ab, dass das ELTERNELEMENT
   zentriert -- nicht den, dass der Absatz es selbst tut.

3. Und dann blieb einer uebrig, bei dem beides stimmte. Ursache: ein
   Inline-Stil "margin:1.2rem 0 0". Die Kurzschreibweise setzt links und
   rechts hart auf 0 und schlaegt jede Stilvorlage. 11 solche Stellen
   ueber fuenf Seiten auf margin-top umgestellt -- gemeint war ohnehin
   immer nur der Abstand nach oben.

Ausnahmen bewusst gesetzt: Nachrichtenblasen tragen ihre Breite schon
selbst, Tabellenzellen und Beschreibungslisten richten sich nach ihrer
Spalte, die Fusszeile ist mehrspaltig und ohnehin schmal.

ALLES GRUEN: Gestaltung 0 Befunde, Designsystem 5, Verwaltung 69,
Portal 32, Widerruf 58, Anfragedetail 20.

Versionsstempel und Cache auf v18.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 18:47:34 +02:00
DogFatherGitandClaude Opus 5 10a075cc33 Gestaltung: Hoehensystem -- mehrschichtige Schatten und Lichtkante
Bis hierher trug jede Karte EINEN Schatten. Das ist solide und genau der
Grund, warum eine Oberflaeche "ordentlich" statt "teuer" wirkt.

Echtes Licht erzeugt zwei Dinge gleichzeitig: einen engen, dunklen
Kontaktschatten an der Kante -- er sagt dem Auge, dass etwas AUFLIEGT --
und einen weiten, weichen Umgebungsschatten, der sagt, wie HOCH es
darueber schwebt. Nur einen von beiden zu setzen sieht aus wie ein
Aufkleber; beide zusammen ergeben einen Gegenstand.

Dazu die LICHTKANTE: eine 1 Pixel hohe, sehr schwache weisse Linie an der
Oberkante. Sie tut so, als kaeme das Licht von oben und braeche sich an
der Kante. Das ist das meistuebersehene Detail in dunklen Oberflaechen
und dasjenige mit der groessten Wirkung -- ohne sie wirkt eine Karte wie
ein Loch im Hintergrund, mit ihr wie ein Stueck Material.

Drei Stufen, mehr braucht es nicht: ruhende Flaechen, hervorgehobene
Flaechen, Schwebendes. Dazu eine vierte, umgekehrte fuer Eingabefelder:
Die liegen nicht AUF der Flaeche, sie sind hineingeschnitten -- oben
dunkel, unten hell.

Weil es die gemeinsamen Bausteine sind, wirkt es sofort auf allen 13
Seiten: Hauptseite, Portal und Verwaltung.

Dazu Feinheiten, die einzeln niemand bemerkt und in Summe den
Unterschied machen: Uebergaenge auf 160-180 ms verkuerzt (alles darueber
wirkt beim Ueberfahren traege), eigene Rueckmeldung beim Druecken,
optische Laufweitenkorrektur fuer grosse Ueberschriften (-.028em bei h1;
das Auge sieht bei 48px mehr Weissraum zwischen Buchstaben als bei 16px),
text-wrap: balance gegen einzelne Woerter in der letzten Zeile.

EIN FEHLER BEIM EINBAU, GEMESSEN STATT UEBERSEHEN

Nach dem ersten Durchgang hatten die Karten ihre Lichtkante, der
Hauptknopf nicht. Grund: Die Grundregel lautet
".wd .wd-btn--haupt, .wd-btn--haupt" -- der erste Teil zaehlt ZWEI
Klassen. Mein Nachtrag zaehlte eine und verlor, obwohl er spaeter steht.
Dieselbe Falle wie am 22.08.2026 bei ".wd a" gegen ".wd-btn--haupt".
Aufgefallen nur, weil die Pruefung die Lichtkanten ZAEHLT.

PRUEFWERKZEUGE ANGEPASST

diagnose.html ist jetzt ausgenommen. Sie traegt bewusst alles fest in
sich -- eigene Farben, keine Uebersetzung -- weil sie funktionieren muss,
wenn genau das kaputt ist, was sie untersucht. Sie an den Regeln der
eigentlichen Seite zu messen erzeugte zwei Meldungen, die man auf Dauer
wegsieht. Und irgendwann sieht man dann auch eine echte weg.

ALLES GRUEN: Gestaltung 0 Befunde (12 Seiten x 5 Sprachen gegen
WCAG 2.2 AA), Designsystem 5, Verwaltung 69, Portal 32.

Versionsstempel und Cache auf v17.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 18:37:17 +02:00
DogFatherGitandClaude Opus 5 a964a078f0 Zahlungen: Verwaltung sticht Serverdatei -- der Schalter wirkt jetzt
Filipes Bildschirm zeigte alles, was noetig war, um es zu erkennen:

  Betriebsart: hinterlegt (auf dem Server) . 7 Zeichen
  Client ID:   hinterlegt . 82 Zeichen
  Secret:      hinterlegt . 80 Zeichen
  Fehler:      "PayPal hat die Anmeldung abgelehnt."

7 Zeichen sind "sandbox". Der Wert kam aus der .env, und die hatte
Vorrang. Sein Klick auf "Echtbetrieb" blieb wirkungslos -- seine echten
Zugangsdaten wurden gegen den TESTSERVER von PayPal geprueft, der sie
zwangslaeufig ablehnt.

Die Fehlermeldung zeigte dabei auf die Zugangsdaten ("stimmen Client ID
und Secret nicht zusammen") und damit in die voellig falsche Richtung.

DER ENTWURFSFEHLER

Ich hatte der .env bewusst Vorrang gegeben, damit ein Fehlgriff im
Formular keine funktionierende Servereinstellung aushebelt. Das klingt
vorsichtig und war falsch:

Ein Formular mit Schaltern, die nichts bewirken, ist schlimmer als gar
kein Formular. Es behauptet eine Wirkung, die es nicht hat, und schickt
bei der Fehlersuche in die Irre.

Der Sinn dieser Ablage ist gerade, dass die Werte OHNE SSH gesetzt
werden koennen. Dann muss das, was dort steht, auch gelten.

Ungefaehrlich, weil diese Werte ausschliesslich der Webdesign-Bereich
liest. Das DogiCrew-Supporter-Abo hat sein eigenes Modul und liest
weiter direkt aus der Umgebung -- ein Eintrag hier kann es nicht
abschalten. Eigens geprueft.

AUCH DIE ANZEIGE WAR UNEHRLICH

Sie sagte nur "hinterlegt (auf dem Server)" und verschwieg, dass genau
dieser Wert die eigene Eingabe ueberstimmt. Jetzt steht dort, welche
Quelle GILT -- "aus der Serverdatei" oder "hier eingetragen" -- und bei
doppelter Belegung zusaetzlich "Serverwert wird nicht benutzt".

GEPRUEFT: 16 Pruefungen auf dem Server, alle bestanden. Darunter der
genaue Fall: Serverdatei sagt sandbox, Formular sagt live -> istLive()
wird WAHR. Und der Rueckweg: Feld leeren -> Serverwert greift wieder.

Beim Testen noch ein Werkzeugfehler behoben: Der Absturz von
better-sqlite3 beim Beenden verschluckte die gesamte gepufferte
Ausgabe -- der Test lief durch und sah aus, als waere er nie gestartet.
Jetzt schreibt er unumgepuffert.

Versionsstempel und Cache auf v16.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 18:12:50 +02:00
DogFatherGit 14488d6df2 Test: unumgepufferte Ausgabe (Absturz beim Beenden verschluckte sie) 2026-08-23 18:11:47 +02:00
DogFatherGit 779fb94c6b Test fuer den Quellen-Vorrang 2026-08-23 18:10:47 +02:00
DogFatherGit ebe10b9c49 WIP Vorrang umgedreht (Test folgt auf dem Server) 2026-08-23 18:09:39 +02:00
DogFatherGitandClaude Opus 5 d870a9c1d7 PayPal: falsche Angabe zur Webhook-ID berichtigt, Abo-Plan-Weg ergaenzt
Filipe: "webhook id faengt bei mir nicht mit w an und wo finde ich plan
fuer betreung"

Er hat recht, ich hatte unrecht. An der Quelle nachgeprueft:

  Webhook-ID:   0NH55953DH663215D        -- OHNE Vorsilbe, ~17 Zeichen
  Ereignis-ID:  WH-3F562076HD293871E-... -- DIE beginnt mit WH-

Meine Anleitung und der Hinweistext im Formular behaupteten beide
"beginnt mit WH-". Wer sich daran haelt, sucht an der falschen Stelle
oder traegt eine Ereignis-Kennung ein -- und die Signaturpruefung
scheitert dann bei der ersten echten Zahlung, mit einer Meldung, die
nicht auf die Ursache zeigt.

Beide Stellen berichtigt, in der Anleitung mit ausdruecklichem Hinweis,
dass dort vorher etwas Falsches stand. Wer sie schon gelesen hat, soll
den Widerspruch erklaert bekommen und nicht stillschweigend eine andere
Fassung vorfinden.

ABO-PLAN: Der Grund fuer die Frage ist ein echter Stolperstein --
Abo-Plaene werden NICHT im Entwicklerbereich angelegt, sondern im
normalen Geschaeftskonto. Unter developer.paypal.com sucht man vergeblich.

Jetzt mit direkter Adresse (paypal.com/billing/plans), dem Weg ueber das
Menue und dem Schritt, den man am ehesten vergisst: den Plan nach dem
Speichern auch AKTIVIEREN. Ein gespeicherter, aber nicht aktivierter
Plan sieht fertig aus und funktioniert nicht.

Ausserdem klargestellt, dass dieser ganze Schritt entfaellt, wenn kein
monatliches Abo verkauft wird -- Anzahlung und Restbetrag laufen ohne.

Versionsstempel und Cache auf v15.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 18:04:55 +02:00
DogFatherGitandClaude Opus 5 9421bd5cfe Verwaltung: Endlosschleife bei abgewiesenem Ausweis behoben
DIE URSACHE FUER "die ganze seite haengt"

In ladeAnfragen stand seit Tagen dieser Code:

    if (!ausweisVersucht) {
      ausweisVersucht = true;
      var frisch = await ausweisHolen();
      if (frisch) {
        token = frisch; tokenSchreiben(token);
        ausweisVersucht = false;     // <-- VOR dem Neuversuch geloest
        return ladeAnfragen();       // <-- und ruft sich selbst auf
      }
    }

Die Sperre wird zurueckgesetzt, BEVOR der neue Versuch laeuft. Solange
der Ausweis akzeptiert wurde, fiel das nie auf. Weist der Server ihn
dagegen ab, dreht es sich unbegrenzt: Ausweis holen, 401, Ausweis holen,
401 -- ohne Fehlermeldung, ohne Anmeldemaske, nur ein Ladehinweis, der
zehn Minuten stehen bleibt. Die schlimmste Sorte Fehler: Sie sieht aus
wie Langsamkeit.

WARUM DER AUSWEIS ABGEWIESEN WIRD

Die Diagnose mit echtem Ausweis zeigte es eindeutig:
  Ausweis erhalten in 23 ms
  Einstellungen abrufen -> 401, {"ok":false,"error":"Kein Zugriff."}

Die Zugangswand stellt also aus, der interne Dienst lehnt ab. Beide
benutzen nicht dasselbe WEBDESIGN_API_SECRET. Auf dem oeffentlichen
Server ist es gesetzt (Fingerabdruck e7d63573174f661a); der interne ist
fuer mich nicht lesbar -- Filipe prueft das mit einem Befehl, der nur
den Fingerabdruck ausgibt, nie den Wert.

UND EIN FEHLER, DEN ICH SELBST EINGEBAUT HATTE

Die Erneuerung aus v12/v13 ersetzte bei jedem 401 den Schluessel durch
einen Ausweis -- auch dann, wenn er aus der Anmeldung mit dem
Zugangscode stammte. Bei untauglichem Ausweis wurde daraus ein
Totalausfall: Alle zehn Minuten ersetzte sie eine FUNKTIONIERENDE
Sitzung durch eine kaputte.

Eine Reparatur, die den Normalfall verschlechtert, ist keine.

Jetzt fuehrt die Seite mit, WOHER der Schluessel stammt. Eine
Code-Sitzung wird nie durch einen Ausweis ersetzt, und die vorsorgliche
Erneuerung laeuft fuer sie gar nicht erst. Nach einem Neuladen gilt ein
vorhandener Schluessel vorsichtshalber als Code-Sitzung -- lieber einmal
zu viel nach dem Code fragen als eine laufende Sitzung zerstoeren.

Die Erneuerung sitzt jetzt an EINER Stelle (api()) mit genau einem
Neuversuch. Die zweite, aeltere Fassung in ladeAnfragen ist raus; zwei
Mechanismen, die sich gegenseitig den Schluessel ueberschreiben, waren
ein Teil des Problems.

GEPRUEFT mit genau dieser Lage -- Zugangswand stellt aus, interner
Dienst lehnt ab:
  2 Ausweis-Abrufe in 3 Sekunden statt unbegrenzt
  abgewiesener Ausweis fuehrt zur Codeeingabe statt zum Haengen
  Anmeldung mit Code oeffnet die Verwaltung
  sechs Reiterwechsel, null Rauswuerfe, null Ausweis-Abrufe
  Zahlungen-Kasten zeigt Inhalt

Verwaltung weiterhin 69 von 69. Versionsstempel und Cache auf v14.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:36:34 +02:00
DogFatherGit 4ad99b5c37 Diagnose: Volltest mit echtem Ausweis
Ein 401 ohne Anmeldung beweist nur, dass die Adresse existiert -- nicht,
dass die Antwort auch bei ANGEMELDETEM Zugriff kommt. Genau dort blieb
die Verwaltung stehen.

Die Diagnose geht jetzt denselben Weg wie die Verwaltung: Ausweis von
der Zugangswand holen, damit die Einstellungen abrufen, Zeit messen. Mit
eigenem Zeitlimit von 12 Sekunden, damit die Diagnose nicht selbst
haengt, wenn die Adresse haengt -- ein Pruefwerkzeug, das am selben
Problem scheitert, ist wertlos.

Damit ist der Befund eindeutig statt vermutet: entweder 'Erfolgreich in
X ms', oder eine Statusnummer samt Antworttext, oder 'KEINE Antwort
innerhalb von 12 Sekunden'.
2026-08-23 17:30:23 +02:00
DogFatherGitandClaude Opus 5 2ec935ccc6 Verwaltung: Ausweis vorsorglich erneuern statt erst nach dem Fehlschlag
"wenn ich von postfach auf projekte oder so gehe da werd ich immer wieder
mien zugangscode gefragt ... ich will nur den zugangscode anfrage wenn
ich auf die seite will und fertig"

Die Wiederholung bei 401 (v12) rettet zwar jeden Fall, greift aber erst,
NACHDEM eine Anfrage abgewiesen wurde: ein unnoetiger Umlauf, und
solange steht ein Ladehinweis auf dem Schirm.

Jetzt laeuft der Ausweis gar nicht erst ab. Er gilt 15 Minuten, erneuert
wird alle 10 -- mit Abstand, damit ein langsamer Netzzugang nicht ins
Zeitfenster hineinlaeuft. Im Hintergrund pausiert die Erneuerung, das
waere Verschwendung.

Dazu beim Zurueckkommen ins Fenster: War der Rechner zwischendurch zu,
ist der Ausweis mit Sicherheit abgelaufen. Dann soll der erste Klick
sofort sitzen statt ueber einen Fehlschlag zu gehen. Beim schnellen Hin-
und Herwechseln zwischen zwei Fenstern passiert nichts -- unter einer
Minute wird nicht erneuert.

Die Codeeingabe erscheint jetzt nur noch in genau zwei Faellen: beim
ersten Betreten der Seite und wenn die Zugangssitzung wirklich abgelaufen
ist (8 Stunden oder Seite geschlossen). Genau so war es gewuenscht.

GEPRUEFT: sieben Reiterwechsel hintereinander -- postfach, projekte,
kunden, zahlungen, anfragen, postfach, zahlungen -- und vor JEDEM wurde
der Ausweis kuenstlich fuer ungueltig erklaert. Null Codeabfragen, die
Verwaltung blieb offen, der Inhalt erschien. Verwaltung weiterhin
69 von 69.

Versionsstempel und Cache-Name auf v13.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:28:35 +02:00
DogFatherGitandClaude Opus 5 bd9051bfb7 Verwaltung: Ausweis erneuert sich selbst statt nach dem Code zu fragen
Rueckmeldung: "wieso werd ich auch immer meinen zugangscode gefragt wenn
ich die kategorie wechseln tue das ist schwachsin."

Er hat recht, und es war ein echter Fehler.

DIE URSACHE

Der Ausweis fuer die interne Schnittstelle (/webdesign/api-ausweis) gilt
15 Minuten. Danach antwortete jede Anfrage mit 401, und die Verwaltung
tat das Haerteste, was moeglich ist: Token verwerfen und Codeeingabe
zeigen -- beim blossen Wechsel eines Reiters.

Doppelt falsch:

  Die ZUGANGSSITZUNG selbst gilt 8 Stunden. Der Code war also gar nicht
  noetig; ein frischer Ausweis haette genuegt und war jederzeit
  abrufbar.

  Ein Rauswurf mitten in der Arbeit ist die haerteste denkbare Reaktion
  auf ein Problem, das sich unsichtbar loesen laesst. Wer gerade ein
  Angebot beziffert hat, verliert damit seinen Platz.

DIE LOESUNG

Bei 401 wird EINMAL ein neuer Ausweis geholt und die Anfrage wiederholt.
Nur wenn auch das scheitert, kommt die Codeeingabe -- dann ist die
Sitzung wirklich abgelaufen.

Das Wiederholen ist auch bei Absendungen unbedenklich: Eine mit 401
abgewiesene Anfrage hat serverseitig nichts bewirkt.

Alle gleichzeitig wartenden Aufrufe teilen sich EINEN Erneuerungsversuch.
Ohne das holt beim Oeffnen eines Reiters mit drei Abfragen jede ihren
eigenen Ausweis -- drei statt einem.

GEPRUEFT: 5 Pruefungen mit kuenstlich abgelaufenem Ausweis. Der
Reiterwechsel fragt NICHT mehr nach dem Code, der Inhalt erscheint
trotzdem, genau EIN neuer Ausweis wird geholt, und der naechste Wechsel
laeuft ebenfalls durch. Ist dagegen die Zugangssitzung selbst abgelaufen,
erscheint die Codeeingabe weiterhin -- das soll sie dann auch.

Verwaltung weiterhin 69 von 69.

Versionsstempel und Cache-Name auf v12.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:23:19 +02:00
DogFatherGitandClaude Opus 5 a5cd4bdcbd Diagnose: Normalzustaende nicht mehr als Befund melden
Filipes Diagnose zeigte zwei "!", obwohl alles in Ordnung war:

  ! Service Worker aktiv       -> 1 registriert
  ! Zwischenspeicher           -> dogfather-webdesign-v11
  ! Anmeldung Verwaltung       -> keiner vorhanden

Alle drei sind der NORMALFALL:

Ein aktiver Service Worker ist gewollt -- ohne ihn liesse sich die Seite
nicht als App installieren. Das war ausdruecklicher Wunsch.

Der Zwischenspeicher enthielt v11 -- also genau die Fassung, die der
Server ausliefert. Die erste Fassung meldete JEDEN gefuellten
Zwischenspeicher als auffaellig, auch den topaktuellen. Das ist
Panikmache, kein Befund.

Die Anmeldung gilt je Tab. In einem frisch geoeffneten Tab ist
zwangslaeufig keine da -- und sie SOLL beim Schliessen ohnehin
verschwinden, das war eine ausdrueckliche Vorgabe.

Ein Pruefwerkzeug, das den Normalzustand anmahnt, ist schlimmer als
keines: Es schickt einen auf die Suche nach einem Fehler, den es nicht
gibt -- und wenn dann einmal ein echter kommt, sieht er genauso aus wie
das Rauschen davor.

Jetzt liest die Diagnose die erwartete Fassung aus dem
Service-Worker-Skript auf dem Server und VERGLEICHT. Nur eine
Abweichung ist ein Befund.

GEPRUEFT mit beiden Faellen: bei v11 sechsmal gruen, bei kuenstlich
gesetztem v3 ein "!" mit beiden Fassungsnummern im Klartext.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:18:05 +02:00
DogFatherGitandClaude Opus 5 b9f6829a63 Diagnoseseite: Text landete im Statuskreis statt daneben
Filipes Screenshot zeigte den Beschreibungstext als schmale
Buchstabensaeule ueber die halbe Seite laufen. Die Ursache ist eindeutig
und mein Fehler:

  d.innerHTML = '<span class="mark">✓</span><div><b></b><span></span></div>';
  d.querySelector("span").textContent = text;

querySelector liefert den ERSTEN passenden span -- und das war der
Statuskreis, nicht das Textfeld darunter. Der gesamte Beschreibungstext
wurde also in einen 26 Pixel breiten Kreis geschrieben und lief dort
heraus.

Zwei Regeln machten es schlimmer:
  .zeile span { ... }   traf ebenfalls BEIDE spans
  fehlendes min-width:0 verhinderte, dass die Textspalte schrumpfen darf

Jetzt wird die Zeile Element fuer Element aufgebaut, mit direkten
Verweisen statt Suche -- da gibt es nichts zu verwechseln. Die
CSS-Regeln zielen auf eigene Klassen (.inhalt, .text) statt auf den
Elementnamen, der Kreis ist auf feste 26px genagelt und schneidet
ueberzaehligen Inhalt ab, statt die Seite aufzubrechen.

Auch die feste Platzhalterzeile im HTML nutzte noch den alten Aufbau und
haette denselben Fehler gezeigt, sobald sie sichtbar wird.

GEPRUEFT im Browser: alle sechs Zeilen, jeder Kreis exakt 26x26, Text
danebenstehend. Zusaetzlich als Screenshot angesehen -- bei einem
Anzeigefehler ist Messen allein nicht genug, denn genau das hatte die
erste Fassung ja auch bestanden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:13:34 +02:00
DogFatherGitandClaude Opus 5 dd4010e75d Diagnoseseite: findet und behebt haengende Zwischenspeicher
Rueckmeldung: "garnichts laedt in der verwaltungsseite".

Geprueft statt geraten -- die Serverseite ist in Ordnung:
  Dienst aktiv, keine Fehler im Protokoll
  CORS-Vorabanfrage 204 mit allow-origin
  echte Anfrage 401 (korrekt ohne Anmeldung), Antwortzeit unauffaellig
  ausgelieferte Seite enthaelt den neuen Code

Damit bleibt fast nur der Browser: ein alter Service Worker, der
veraltete Dateien ausliefert. Er ueberlebt ein normales Neuladen, und
niemand kann ihn ohne Entwicklerwerkzeuge sehen.

webdesign/diagnose.html prueft sechs Dinge und sagt im Klartext, welches
davon klemmt: Service Worker aktiv? Zwischenspeicher gefuellt? Server
erreichbar und wie schnell? Kennt der Server die neuen Adressen
(404 = Server veraltet)? Liegt eine Anmeldung vor? Und wird die AKTUELLE
Gestaltungsdatei ausgeliefert -- erkennbar an einem Merkmal, das es erst
seit heute gibt.

Ein Knopf meldet den Service Worker ab, loescht die Zwischenspeicher und
laedt die Verwaltung mit Zeitstempel neu. Der Text sagt ausdruecklich,
dass Anmeldung und Daten unberuehrt bleiben -- sonst traut sich niemand
zu klicken.

ZWEI ENTSCHEIDUNGEN

Die Seite laedt KEINE externen Dateien, alles steht inline. Sie muss
funktionieren, wenn genau das kaputt ist, was sie untersucht -- eine
Diagnoseseite, die an derselben veralteten CSS-Datei scheitert, ist
wertlos.

Sie ist von der Zugangswand ausgenommen, wie Widerruf und Rechtstexte.
Gebraucht wird sie genau dann, wenn etwas klemmt; dann darf nicht
ausgerechnet die Zugangswand davorstehen. Sie enthaelt keine Kunden-
oder Projektdaten, sondern prueft nur den eigenen Browser und meldet
Statusnummern.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:10:54 +02:00
DogFatherGitandClaude Opus 5 d68d10d002 Zahlungen: Ladefehler sichtbar machen statt ewig "Wird geladen"
Rueckmeldung 23.08.2026: "da steht das aber passiert nichts" -- der
Reiter Zahlungen zeigte in beiden Kaesten dauerhaft "Wird geladen...".

Geprueft statt vermutet: Der Server antwortet (401 auf unangemeldete
Anfragen, Webhook 400), die ausgelieferte Seite enthaelt die Funktion,
und lokal nachgestellt laeuft der Ablauf sauber durch. Die Anfrage
bricht nach 15 Sekunden von selbst ab.

Der eigentliche Mangel liegt woanders und ist meiner: Ein Ladehinweis
ohne Ende ist die schlechteste aller Rueckmeldungen. Er sieht aus wie
Arbeit und ist doch nur Stillstand -- man kann nicht unterscheiden, ob
die Anfrage laeuft, fehlgeschlagen ist oder das Skript gar nicht
angesprungen ist. Und wenn der Fehler dann kommt, verschwindet er in
einer Meldung am Bildschirmrand.

DREI AENDERUNGEN

Jeder Fehler wird im Kasten selbst angezeigt, mit STATUSNUMMER im
Klartext ("Konnte nicht geladen werden (Status 403)"). Die kann Filipe
mir nennen, ohne die Entwicklerwerkzeuge zu oeffnen -- 403 heisst etwas
voellig anderes als 500 oder "keine Verbindung", und ohne diese Zahl
raet man.

Dazu ein Knopf "Nochmal versuchen". Bei einem Aussetzer im Mobilfunk ist
das der ganze Unterschied zwischen "geht nicht" und "geht doch".

Die statischen "Wird geladen..."-Texte im HTML sind raus. Der Kasten ist
jetzt leer, bis das Skript ihn fuellt -- und die Ladetexte lauten anders
als vorher. Bleibt spaeter der alte Text stehen, weiss man sofort: Die
Funktion ist nie angelaufen. Das ist eine Aussage, "Wird geladen" war
keine.

Auch die Zahlungsliste verschluckt ihren Fehler nicht mehr. Sie leerte
den Kasten stillschweigend -- ein leerer Bereich ohne Erklaerung ist
nicht weniger verwirrend als ein haengender Ladehinweis.

GEPRUEFT: alle vier Zustaende im Browser nachgestellt -- Serverfehler
500, kein Zugriff 403, Netzausfall und Erfolgsfall. In den ersten drei
erscheint Klartext samt Wiederholen-Knopf, im vierten der normale
Inhalt. Verwaltung weiterhin 69 von 69.

Versionsstempel und Cache-Name auf v11.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 17:07:35 +02:00
DogFatherGitandClaude Opus 5 497c576d1c Anleitung auf den neuen Weg umgestellt -- ohne Konsole
Die Anleitung war nach dem Einbau des Formulars veraltet und haette
Filipe weiter in die Konsole geschickt.

Schritt 0 (nachsehen, was schon da ist) ging ueber SSH und grep. Das
zeigt jetzt die Verwaltung selbst an: "hinterlegt (auf dem Server)",
"hinterlegt" oder "fehlt". Kein Terminal noetig, um zu erfahren, was
noch fehlt.

Schritt 6 war "nano .env + systemctl restart". Jetzt: Verwaltung ->
Zahlungen -> Felder ausfuellen -> Speichern. Mit dem Hinweis, dass ein
leeres Feld "nicht anfassen" bedeutet und nicht "loeschen" -- ohne den
traut sich niemand, ein einzelnes Feld nachzutragen.

Schritt 7 ist neu: der Knopf "Verbindung testen" mit einer Tabelle, was
die drei moeglichen Meldungen bedeuten.

Beim Umstellen ist mir Schritt 8 (der 1-Euro-Test) aus der Datei
gefallen -- der Ersetzungsbereich reichte zu weit. Wieder eingesetzt und
gleich vervollstaendigt: jetzt mit Testkunde anlegen, Einladungslink im
eigenen Browser oeffnen und Aufraeumen danach. Vorher stand dort nur
"Zahlung erzeugen und bezahlen", was den halben Weg ausliess.

Auch die Formulierung "Beide brauche ICH" korrigiert -- ich brauche die
Werte gar nicht, er traegt sie selbst ein.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 16:53:52 +02:00
DogFatherGitandClaude Opus 5 6a2aa13dd8 PayPal ohne Konsole einrichten -- Formular in der Verwaltung
Auf die Frage "soll ich das Secret hier reinschicken?" ist die Antwort
nein: Es stuende dauerhaft im Gespraechsverlauf, und schreiben koennte
ich es trotzdem nicht (kein Zugriff auf /home/dogiintern, sudo nur fuer
apt/systemctl/docker). Risiko ohne Nutzen.

Der Fehler lag aber bei mir: Ich hatte SSH-Befehle als Loesung angeboten.
Filipe soll gar nicht in die Konsole. Jetzt traegt er die Werte in seiner
Verwaltung ein.

AUFBAU

lib/webdesign-geheimnisse.js legt die Werte verschluesselt in
app_settings ab -- derselbe AES-GCM-Weg wie fuer die Zugangscodes des
Universe. Wer die Datenbankdatei in die Haende bekommt, etwa ueber eine
alte Sicherung, hat damit nichts.

Die .env behaelt VORRANG. Sonst koennte ein Fehlgriff im Formular
stillschweigend eine funktionierende Servereinstellung aushebeln und
laufenden Zahlungsverkehr umleiten. Die Datenbank ergaenzt, was dort
fehlt -- sie konkurriert nicht.

Kein Neustart noetig: Nach jedem Speichern werden die Werte neu geladen.

DER KNIFF MIT DEM SYNCHRONEN ZUGRIFF

Entschluesseln ist asynchron, die Pruefungen des PayPal-Moduls
(istLive, istEingerichtet, fehlendeEinstellungen) sind synchron und
werden an einem Dutzend Stellen aufgerufen, teils mitten im Aufbau einer
Antwort. Sie alle auf async umzustellen waere ein Eingriff quer durch den
Bezahlvorgang gewesen -- viel Flaeche fuer Fehler genau dort, wo Fehler
Geld kosten.

Stattdessen werden die Werte einmal beim Start entschluesselt und danach
synchron gelesen. Alle 12 Zugriffe auf process.env.PAYPAL* im Modul
laufen jetzt ueber einen einzigen Zugriffspunkt.

WERTE KOMMEN NIE ZURUECK

Es gibt keinen Weg, ein gespeichertes Geheimnis wieder auszulesen. Die
Anzeige zeigt nur: ob etwas da ist, woher es stammt, wie lang es ist,
wann es zuletzt geaendert wurde. Das Formular leert sich nach dem
Speichern selbst -- ein Secret soll nicht stehen bleiben, wenn jemand
anders auf den Bildschirm schaut.

Ein leeres Feld bedeutet "nicht anfassen", nicht "loeschen". Sonst wuerde
das Nachtragen eines einzelnen Werts alle anderen leeren.

Nach jeder Aenderung wird das gemerkte PayPal-Zugangstoken vergessen --
sonst liefe die naechste Zahlung noch ueber die alten Zugangsdaten oder
scheiterte mit "invalid client".

"Verbindung testen" meldet sich probeweise bei PayPal an. Erst das
beweist, dass die Werte stimmen: "gesetzt" heisst nur, dass etwas
dasteht. Es fliesst dabei kein Geld.

GEPRUEFT: 23 Pruefungen auf dem Server, alle bestanden. Darunter die
wichtigsten Verneinungen: In der Datenbank steht kein Klartext, auch
kein Teil davon. Der Stand enthaelt das Geheimnis nicht. Ein fremder
Schluessel wird abgewiesen. Und: Ein gewechselter ENCRYPTION_KEY bringt
den Dienst NICHT zum Stehen -- der Wert gilt dann als nicht vorhanden,
die Seite laeuft weiter.

Verwaltung 69, Gestaltung 0 Befunde, Designsystem 5 -- unveraendert gruen.

Versionsstempel und Cache-Name auf v10.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 16:51:56 +02:00
DogFatherGit 5043642951 WIP: PayPal-Einstellungen ueber die Verwaltung (Test folgt auf dem Server) 2026-08-23 16:50:18 +02:00
DogFatherGitandClaude Opus 5 692d702ebf Einrichtungsskript fuer PayPal -- Filipe tippt nur die Werte
Auf Wunsch, die Werte selbst einzutragen, zuerst geprueft statt vermutet:

  sudo erlaubt claudian: apt, apt-get, systemctl, docker, docker-compose
  /home/dogiintern/        -> Keine Berechtigung
  .../server-internal/.env -> Keine Berechtigung

Der Zugriff fehlt also technisch, und das ist die Trennung, die Filipe am
08.08.2026 bewusst so eingerichtet hat. Selbst mit Zugriff waere es
falsch: Damit ich die Werte eintrage, muesste das Secret durch den
Chatverlauf wandern und stuende dort dauerhaft.

Also alles abnehmen, was NICHT das Eintippen ist:

paypal-einrichten.sh fragt die vier Werte nacheinander ab, zeigt zu jedem
an, ob schon etwas hinterlegt ist (ENTER = behalten), legt vorher eine
Sicherung an, setzt die Rechte auf 600, startet den Dienst neu und meldet
den Stand.

DREI DINGE, DIE DAS SKRIPT RICHTIG MACHT

Das Secret wird mit "read -s" eingelesen -- es erscheint weder auf dem
Bildschirm noch in der Bash-History. Auch die Abschlussmeldung zeigt nur
die LAENGE, nie den Wert.

Geschrieben wird mit awk und dem Wert in einer Variablen, NICHT mit
"sed -i". Ein PayPal-Secret kann &, \, $, / und Anfuehrungszeichen
enthalten; sed liest davon mehrere als Befehl und haette den Wert still
zerstoert. Der Fehler waere erst bei der ersten echten Zahlung
aufgefallen, mit der Meldung "invalid client" -- und dann sucht man an
der falschen Stelle.

Gegengeprueft mit dem Secret  A&B/C\D$E"F~G : zeichengenau in der Datei
angekommen, umliegende Zeilen unveraendert, vorhandener Schluessel
ersetzt statt ein zweites Mal angehaengt.

Laeuft der Dienst nach dem Neustart nicht, nennt das Skript den Pfad der
Sicherung und den fertigen Befehl zum Zurueckholen -- in dem Moment will
niemand erst suchen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 16:43:32 +02:00
DogFatherGit 244b275dce PayPal-Anleitung: zuerst pruefen, was schon da ist
Client ID und Secret teilt sich der Webdesign-Bereich mit dem
DogiCrew-Supporter-Abo -- laeuft das live, sind zwei der vier Werte
schon eingetragen und es fehlt nur die Webhook-Kennung.

Neuer Schritt 0 mit Befehlen, die nur ANZEIGEN, ob ein Wert gesetzt ist,
ohne ihn auszugeben. Verhindert ausserdem, dass eine zweite App fuer
dasselbe Konto entsteht: Das funktioniert zwar, macht aber jede spaetere
Fehlersuche doppelt muehsam, und beim Erneuern eines Secrets braeche
womoeglich der andere Bereich weg.
2026-08-23 16:33:32 +02:00
DogFatherGitandClaude Opus 5 321e378f9b Zahlungen: Routen, Zustimmung nach § 356 Abs. 4 und Einrichtungsanleitung
Das PayPal-Modul und die Tabellen standen seit dem 22.08.2026 -- es
fehlten die Wege dorthin. Jetzt vollstaendig.

DREI DINGE, DIE HIER ANDERS SIND ALS BEI EINEM UEBLICHEN BEZAHLKNOPF

1. DIE ZUSTIMMUNG IST TEIL DER ZAHLUNG, kein Haekchen daneben.

   Die 30-%-Anzahlung wird faellig, BEVOR die Widerrufsfrist ablaeuft.
   Damit trotzdem sofort begonnen werden darf, verlangt § 356 Abs. 4 BGB
   die ausdrueckliche Zustimmung UND die Bestaetigung, dass der
   Verbraucher dadurch sein Widerrufsrecht verliert. Die Beweislast fuer
   beides liegt beim Unternehmer.

   Gespeichert wird deshalb nicht "hat zugestimmt", sondern der
   WORTLAUT, den der Kunde gesehen hat, samt Fassung und Zeitstempel.
   Im Streit zaehlt nicht DASS, sondern WOZU jemand zugestimmt hat --
   und Texte aendern sich ueber die Jahre.

   Der Wortlaut steht auf dem SERVER, nicht im Browser: Was als Nachweis
   gespeichert wird, muss das sein, was der Server kennt, sonst koennte
   man ihm einen beliebigen Text unterschieben.

   Geschaeftskunden werden gar nicht erst gefragt. Ein Unternehmer hat
   kein Widerrufsrecht; ihn eine Verzichtserklaerung unterschreiben zu
   lassen waere sinnlos und wuerde nur Misstrauen wecken.

2. NICHT EINGERICHTET IST EIN ZUSTAND, KEIN FEHLER.

   Ohne Zugangsdaten sagt die Seite das freundlich und nennt den Weg
   ueber das Postfach. Ein Knopf, der eine technische Fehlermeldung
   wirft, sieht nach einer kaputten Seite aus -- und niemand bezahlt gern
   auf einer kaputten Seite.

3. DER WEBHOOK IST DIE WAHRHEIT, nicht die Rueckkehr des Browsers.

   Der Kunde kann das Fenster schliessen, bevor er zurueckgeleitet wird.
   Die Zahlung ist dann trotzdem erfolgt. Beide Wege schreiben ueber
   DIESELBE Funktion -- zwei getrennte Fassungen wuerden frueher oder
   spaeter auseinanderlaufen und unterschiedliche Felder setzen.

   Doppelte Zustellung ist bei PayPal normal. Die Merkliste verhindert
   die Doppelverbuchung, und "verarbeitet" wird erst NACH der Auswertung
   gesetzt: Bricht der Server dazwischen ab, steht die Meldung als
   empfangen-aber-offen da und faellt auf, statt spurlos als "schon
   behandelt" zu gelten.

Ohne gueltige Signatur wird nichts verarbeitet -- sonst koennte jeder
eine Zahlung als bezahlt melden.

GEPRUEFT: 26 Pruefungen auf dem Server, alle bestanden. Bewusst OHNE
PayPal-Zugangsdaten, weil genau das der heutige Zustand ist. Geprueft
wird vor allem, was NICHT passieren darf: kein Bezahlvorgang ohne
Zustimmung, keine Zustimmungsfrage an Geschaeftskunden, keine fremde
Zahlung sichtbar, keine Doppelverbuchung, kein Geldfluss ohne
Zugangsdaten -- und dass ein gescheiterter Versuch die Zahlung
unangetastet auf "offen" laesst.

ANLEITUNG: PAYPAL-EINRICHTEN.md, Schritt fuer Schritt mit den genauen
Klicks. Sie nennt ausdruecklich die drei Fallen, die man sonst erst
spaeter merkt: der Sandbox-Schalter (Zugangsdaten ohne echtes Geld),
"Select all" bei den Webhook-Ereignissen (erzeugt Rauschen, in dem echte
Probleme untergehen) und Client-ID und Secret aus verschiedenen Apps.

Das Secret gehoert nach Bitwarden -- die Anleitung sagt das an drei
Stellen und bietet an, dass Filipe es selbst eintraegt, ohne es mir zu
zeigen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 16:24:51 +02:00
DogFatherGit eede01ca70 WIP: Zahlungsrouten (Test folgt auf dem Server) 2026-08-23 16:23:12 +02:00
DogFatherGitandClaude Opus 5 be3599239d Designsystem: eine Quelle je Farbe, Radien auf eine Skala
Diese Runde ging eine Ebene tiefer als "sieht es gut aus": Ist das
System, aus dem das Aussehen entsteht, ueberhaupt eines?

DIE MESSUNG VORWEG

  Markenfarben ausgeschrieben im Quelltext:  155 Stellen
    davon Blau 74, Gold 33, Lila 22, Gruen 16, Rot 10
  verschiedene Eckenradien:                   12
    darunter 5px, 7px, 9px, 11px

Die Farben gab es laengst als Variablen. Sie standen trotzdem ueberall
ausgeschrieben da, weil halbdurchsichtige Toene -- Raender, Leuchten,
sanfte Flaechen -- einen Alphawert brauchen, und das mit einer fertigen
Farbvariablen nicht geht: rgba(127, 208, 232, .16).

Die Folge waere beim ersten Farbwechsel sichtbar geworden: Man findet
150 Stellen, uebersieht fuenf, und die Seite hat danach zwei Blautoene,
die sich um eine Nuance unterscheiden. Genau das ist der Unterschied
zwischen einer gewachsenen und einer gestalteten Oberflaeche.

WAS GEAENDERT WURDE

Kanalvariablen (--wd-blau-rgb: 127 208 232) neben den fertigen Farben.
Damit schreibt man rgb(var(--wd-blau-rgb) / .16), und eine Aenderung
wirkt ueberall. 164 Stellen umgestellt, verteilt ueber CSS und neun
Seiten.

Auch die abgeleiteten Farben zeigen jetzt auf die Kanaele statt eigene
Werte zu fuehren -- und die vier Prozessfarben (--wd-p1 bis p4) sind
keine eigenen Farben mehr, sondern Rollen: --wd-p1: var(--wd-blau).
Sonst haette man vier weitere Stellen, die beim naechsten Farbwechsel
stillschweigend zurueckbleiben.

Ergebnis: Jede Markenfarbe hat genau EINE Quelle. Ausgeschriebene
Markenfarben im Quelltext: 0.

Radien auf vier Stufen plus Pillenform: 6 / 10 / 14 / 20 / 999. Kein
Wert wurde um mehr als 2px verschoben, optisch aendert sich also nichts
Spuerbares -- 12 verschiedene Werte sind auf 3 tatsaechlich verwendete
zusammengeschmolzen. Zwischenwerte wie 7px oder 11px entstehen nicht aus
Absicht, sondern weil man beim Bauen einer neuen Kachel nicht nachschaut,
was nebenan schon gilt.

DER BEWEIS, DASS ES EIN SYSTEM IST

Neue Pruefung pruef-system.mjs. Sie behauptet nicht, sie STELLT UM: Die
Markenfarbe wird von Babyblau auf kraeftiges Orange gesetzt und dann
nachgezaehlt, ob irgendwo der alte Ton stehen bleibt.

  658 von 1975 sichtbaren Elementen tragen die Markenfarbe
  0 bleiben nach der Umstellung beim alten Ton
  Prozessfarben folgen nachweislich mit
  Radien: 3 Stufen

UND DIE WICHTIGSTE ERKENNTNIS -- ueber das Messen selbst

Der erste Anlauf meldete 110 haengengebliebene Elemente, alle in Kopf-
und Fusszeile. Die naheliegende Erklaerung waere gewesen: "da steht die
Farbe noch ausgeschrieben". Sie war falsch.

Nachgewiesen ueber die DevTools-Schnittstelle: Auf diese Elemente wirkt
die Regel ".wd a:not(.wd-btn) -> var(--wd-blau)", und --wd-blau
resolviert an genau dieser Stelle korrekt zum neuen Orange. Trotzdem
blieb die berechnete Textfarbe alt -- auch nach erzwungener
Neuberechnung.

Der Unterschied: Kopf- und Fusszeile werden von wd-core.js per innerHTML
eingefuegt. Chromium erneuert solche Teilbaeume nicht zuverlaessig, wenn
man eine Variable NACHTRAEGLICH umstellt. Laedt man dieselbe Seite mit
bereits geaenderter Variable, sind sie orange -- gegengeprueft mit einem
Minimalbeispiel, in dem derselbe Mechanismus einwandfrei funktioniert.

Das Pruefverfahren wurde deshalb umgestellt: Die Variable wird VOR dem
Laden ueberschrieben. Das entspricht genau dem, was eine Aenderung in der
CSS-Datei bewirkt -- also dem Fall, um den es wirklich geht.

Haette ich der ersten Messung geglaubt, haette ich 110 einwandfreie
Stellen "repariert" und dabei das gerade aufgebaute System wieder
zerlegt. Es ist der siebte Fehlalarm in eigener Messtechnik innerhalb
von zwei Runden -- und der subtilste.

ALLE PRUEFUNGEN GRUEN: Gestaltung 0 Befunde (13 Seiten x 5 Sprachen
gegen WCAG 2.2 AA), Anfragedetail 20, Verwaltung 69, Portal 32,
Widerruf 58, Textkodierung 55 Kombinationen, Designsystem 5.

Versionsstempel und Cache-Name auf v9.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 13:05:12 +02:00
DogFatherGitandClaude Opus 5 3ca9f0b0cd Gestaltung: WCAG-Messung ueber alle Seiten, alle Befunde behoben
"Sieht gut aus" ist Geschmack und laesst sich nicht pruefen. Handwerkliche
Qualitaet laesst sich pruefen -- und bei einer WEBDESIGN-Seite ist sie
zugleich das Verkaufsargument: Wer selbst schludert, kann schlecht
Sorgfalt verkaufen.

Neues Werkzeug pruef-design.mjs misst 13 Seiten x 5 Sprachen auf
Handy-Breite gegen WCAG 2.2 AA -- denselben Standard, auf den auch das
Barrierefreiheitsstaerkungsgesetz verweist. Der Browser rechnet, es wird
nichts geschaetzt.

ERGEBNIS: 0 Befunde. Kontrast, Klickflaechen, Tastaturfokus,
Ueberschriftenstruktur, Bildalternativen, Feldbeschriftungen,
lang-Attribut, Schriftgroessen.

ECHTE BEFUNDE, DIE BEHOBEN WURDEN

1. 23 Schriftgroessen unter 12px (bis hinunter zu 10,9px), verteilt ueber
   CSS und sieben Seiten. Betroffen waren durchweg gesperrte
   Grossbuchstaben-Beschriftungen -- also genau die Textsorte, die klein
   ohnehin am schlechtesten lesbar ist. Alle auf mindestens 12px, die
   gesperrten auf 12,8px. Das ist zugleich die Dauervorgabe
   "augenschonend" ernst genommen.

2. Ueberschriftensprung h2 -> h4 in der Fusszeile, auf ALLEN 13 Seiten in
   allen 5 Sprachen (42 Stellen). Wer sich mit einem Screenreader durch
   die Ueberschriften bewegt, hoert dadurch eine Gliederung, die es nicht
   gibt, und vermutet uebersprungene Abschnitte. Jetzt h2 mit
   Gestaltungsklasse: Die Ebene sagt etwas ueber die STRUKTUR, die
   Groesse ueber die GEWICHTUNG -- zwei verschiedene Dinge.

3. code-Auszeichnung auf der Rechtsseite rutschte durch relative
   Groessenangabe auf 11,2px. Jetzt mit Untergrenze abgesichert.

SECHS FEHLALARME IM WERKZEUG -- ALLE GEFUNDEN UND BESEITIGT

Der erste Lauf meldete 302 Fundstellen. Fast alle waren falsch. Haette
ich sie "repariert", haette ich funktionierende Gestaltung zerstoert.
Jeder Fehlalarm hatte eine eigene, nicht offensichtliche Ursache:

  * Farbverlaeufe: getComputedStyle().backgroundColor liefert bei einer
    reinen Verlaufsflaeche "rgba(0,0,0,0)". Die Suche lief an der hellen
    Knopfflaeche VORBEI bis zum dunklen Seitengrund und verglich dunkle
    Schrift mit dunklem Grund -- Ergebnis 1:1 fuer 60 einwandfreie
    Knoepfe. Jetzt werden die Farbstopps ausgelesen und der
    unguenstigste Fall gerechnet.

  * MEHRERE Hintergrundebenen: Die Karten nutzen den bekannten Kniff
    "Flaeche padding-box, Rahmenverlauf border-box". Der helle
    Rahmenverlauf ist im Textbereich gar nicht sichtbar. Alle Ebenen
    zusammenzurechnen ergab 820 Meldungen mit Werten wie "3,45:1" fuer
    Text, der in Wahrheit ueber 7:1 liegt. CSS malt die ERSTE Ebene oben
    -- nur die zaehlt. Das Trennen an Kommas muss dabei die Kommas
    INNERHALB der Verlaufsklammern respektieren.

  * Verlaufsschrift (background-clip:text): Dort ist die Schriftfarbe
    durchsichtig und der Verlauf IST der Text. Farbe gegen Hintergrund zu
    vergleichen ergibt zwangslaeufig 1:1.

  * Verlaufsstopps mit wenig Deckkraft (9 % und 4 % Gold in den
    Hinweiskaesten) wurden verworfen statt auf den Untergrund gerechnet.
    Uebrig blieb "nicht messbar" fuer 72 Textstellen. Ein Pruefwerkzeug,
    das bei allem passt, prueft nichts.

  * Laufende Ueberblendungen: getComputedStyle liefert waehrend einer
    Ueberblendung den ZWISCHENWERT. Nach blur() verblasst der Fokusring
    ueber 0,16 s -- misst man sofort, sieht man ihn noch, und "vorher"
    ist identisch mit "nachher". Das Codefeld der Verwaltung wurde
    dadurch als "ohne sichtbaren Fokus" gemeldet. Nachgewiesen mit
    el.matches(":focus") === false bei gleichzeitig sichtbarem Schatten.
    Loesung: Ueberblendungen fuer die Messung abschalten.

  * Ausgeblendete Abschnitte: Eine Ueberschrift in einem versteckten
    Bereich hat selbst weiterhin display:block. Im Portal wurden dadurch
    drei h1 gezaehlt, obwohl immer nur eine sichtbar ist. Jetzt
    getClientRects().

Dazu zwei bekannte Muster, die das Werkzeug jetzt kennt: der Sprunglink
(absichtlich aus dem Bild geschoben) und die winzigen Auswahlfelder
hinter den Kacheln (die Kachel IST die Klickflaeche).

ALLE UEBRIGEN PRUEFUNGEN WEITERHIN GRUEN nach den Aenderungen:
Anfragedetail 20, Verwaltung 69, Portal 32, Widerruf 58, Textkodierung
55 Seiten-Sprach-Kombinationen.

Versionsstempel und Cache-Name auf v8.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 12:49:29 +02:00
DogFatherGitandClaude Opus 5 14ad108c87 Rechtliches: elektronische Widerrufsfunktion (§ 356a BGB), Impressum, AGB,
Widerrufsbelehrung und Datenschutz

RECHERCHIERT, NICHT AUS DEM GEDAECHTNIS

Der Webdesign-Bereich hatte KEINE eigene Rechtsseite -- obwohl dort
Vertraege geschlossen und Zahlungen ausgeloest werden. Die Fusszeile
verwies auf die Kontaktseite des Universe, die ein Content-Projekt
beschreibt, kein Dienstleistungsgeschaeft.

Die Web-Recherche hat eine Pflicht zutage gefoerdert, die seit zwei
Monaten gilt und die die Seite nicht erfuellt hat:

  § 356a BGB -- elektronische Widerrufsfunktion, in Kraft seit
  19.06.2026. Sie gilt fuer ALLE Fernabsatzvertraege, die ueber eine
  Online-Benutzeroberflaeche geschlossen werden, nicht nur fuer
  Finanzdienstleistungen.

WARUM DAS HIER GILT: Im Kundenportal nimmt der Kunde Zusatzangebote per
Klick VERBINDLICH an ("Damit nimmst du das Zusatzangebot verbindlich
an"). Das ist ein Vertragsschluss ueber eine Online-Benutzeroberflaeche.
Fuer die geplanten PayPal-Zahlungen gilt dasselbe.

Der Anbieter sitzt in Luxemburg. Fuer Verbraucher mit gewoehnlichem
Aufenthalt in Deutschland gilt nach Art. 6 Rom-I-VO trotzdem das
deutsche zwingende Verbraucherrecht, weil die Seite sich erkennbar an den
deutschsprachigen Markt richtet. Deshalb wurde der STRENGERE Standard
umgesetzt, nicht der bequemere.

WAS GEBAUT WURDE

webdesign/widerruf.html -- die Widerrufsfunktion, genau nach dem
Wortlaut der Vorschrift:
  * Beschriftung "Vertrag widerrufen" (gesetzlich vorgegeben)
  * ZWEITE Schaltflaeche "Widerruf bestaetigen" (ebenfalls vorgegeben --
    ein einstufiges Formular wuerde die Vorschrift nicht erfuellen)
  * unverzuegliche Eingangsbestaetigung mit Nummer, ZEITPUNKT (nicht nur
    Datum), Empfaenger und dem Wortlaut der Erklaerung
  * Link in der Fusszeile JEDER Seite -- "staendig verfuegbar,
    hervorgehoben platziert, leicht zugaenglich" heisst nicht "in den AGB
    versteckt"

Drei Entscheidungen, die unmittelbar aus dem Sinn der Vorschrift folgen:

  KEINE ANMELDUNG. Die Seite ist von der Zugangswand ausgenommen. Wer
  seinen Code verlegt hat, wuerde sonst seine Frist verlieren --
  Fristverlust durch eine selbstgebaute Huerde ist der schlimmste
  denkbare Fall.

  KEINE MENGENBEGRENZUNG. Ueberall sonst richtig, hier ein
  Rechtsverlust: Wer in der letzten Stunde seiner Frist wegen eines
  hakenden Netzes dreimal klickt, darf nicht abgewiesen werden.

  KEIN ZWISCHENSPEICHER. Beim Anfrageformular ein Segen, hier eine
  Falle: Auf einem geteilten Rechner laege der halb ausgefuellte Widerruf
  des einen im Browser des naechsten.

webdesign/rechtliches.html -- Impressum, AGB, Widerrufsbelehrung samt
Muster-Widerrufsformular, Datenschutzerklaerung. Alle Betreiberangaben
sind aus den bestehenden Seiten UEBERNOMMEN, nichts erfunden: Anschrift
in Mondercange, Kleinunternehmerregelung nach Art. 57 TVA-Gesetz LU und
Richtlinie (EU) 2020/285, netcup/Cloudflare, PayPal Luxemburg.

Migration 0014: wd_widerrufe (der dauerhafte Datentraeger und der
Nachweis, wird nie geleert) und wd_zustimmungen. Letztere speichert nicht
nur den Haken, sondern den WORTLAUT, den der Kunde gesehen hat -- die
Beweislast fuer die Zustimmung zum vorzeitigen Leistungsbeginn liegt beim
Unternehmer (§ 356 Abs. 4 BGB), und im Streit zaehlt, WAS bestaetigt
wurde. Bewusst OHNE Fremdschluessel: CASCADE wuerde den Nachweis mit dem
Kunden mitloeschen, RESTRICT wuerde eine DSGVO-Loeschung blockieren.

Druckansicht: Die Eingangsbestaetigung ist ein Rechtsnachweis. Auf Papier
schwarz auf weiss, ohne Navigation und Knoepfe -- ein Nachweis, den
niemand ausdruckt, weil er eine halbe Patrone kostet, erfuellt seinen
Zweck nicht.

ZWEI ECHTE FEHLER GEFUNDEN

1. Die Pflicht-Sternchen verschwanden nach der Uebersetzung. Ursache:
   data-i18n stand auf dem <label> selbst und ersetzte dessen ganzen
   Inhalt -- samt <span class="wd-pflicht">. Das Anfrageformular macht es
   laengst richtig (data-i18n auf einem INNEREN span); die neue Seite
   hatte das Muster nicht uebernommen. Aufgefallen ist es nur, weil der
   Test die Pflichtfelder GEZAEHLT hat statt sie vorauszusetzen.

2. window.WD.sprache() gibt es nicht, die Funktion heisst getSprache().
   Dadurch brach der Uebergang zur zweiten Stufe stumm ab.

GEPRUEFT: 58 Pruefungen, alle bestanden. Darunter die gesetzlich
vorgegebenen Beschriftungen in allen FUENF Sprachen, "kein Grund noetig",
genau drei Pflichtfelder, Datum UND Uhrzeit in der Bestaetigung, und die
Druckansicht.

WAS FILIPE NOCH PRUEFEN LASSEN MUSS: Diese Texte sind sorgfaeltig
recherchiert, aber ich bin keine Rechtsanwaeltin. Vor dem oeffentlichen
Start gehoert das Ganze einmal zu einer im luxemburgischen Recht
qualifizierten Fachperson -- besonders die grenzueberschreitende Lage
(Sitz LU, Kunden in DE/CH/FR/PT) und die Frage, ob die Seite in
Franzoesisch und Portugiesisch aktiv verkaufen soll. Dann muessen die
Rechtstexte auch dorthin uebersetzt werden, und zwar fachlich.

Versionsstempel und Cache-Name auf v7.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 12:29:09 +02:00
DogFatherGitandClaude Opus 5 98fc04c666 Verwaltung: Projektstand aendern, Wuensche beziffern, im Projekt antworten
Drei Server-Funktionen existierten seit Tagen und hatten KEINE Oberflaeche.
Erst im Vergleich "was kann der Server" gegen "was ruft die Seite auf"
ist es aufgefallen:

  POST /admin/projekte/:id           projektAendern
  POST /admin/aenderungen/:id/beziffern
  POST /admin/projekt-nachricht

Jede davon schliesst einen Kreis, der bisher offen war.

1. DIE SCHMERZHAFTESTE LUECKE: DER STAND

Der Kunde sieht in seinem Portal GANZ OBEN die Phasenleiste und den
"naechsten Schritt". Beides liess sich nirgends aendern. Ein Projekt blieb
also fuer immer im Briefing stehen, egal wie weit es wirklich war -- und
der prominenteste Text im ganzen Kundenportal war dauerhaft leer.

Jetzt: sieben Phasen als Knoepfe (plus Pausiert/Abgebrochen daneben, denn
das sind keine Phasen, sondern Zustaende), "wer ist am Zug", naechster
Schritt, Richttermin, Zahlungsstand, Portfolio-Freigabe.

Phase und "wer ist am Zug" speichern SOFORT ohne Speichern-Knopf: Es ist
ein Klick auf genau einen Wert, ein zweiter Klick waere Zeremonie. Die
Textfelder haben einen Knopf, weil man beim Tippen zwischendurch nicht
speichern will.

2. AENDERUNGSWUENSCHE

Der Kunde konnte Ideen einreichen, seit es das Portal gibt. Beziffern ging
serverseitig auch -- nur gab es keine Oberflaeche. Der Kreis war offen: Er
schickt etwas los und hoert nie wieder davon.

Jetzt stehen alle Wuensche im Projekt, offene mit Feldern fuer Preis,
Dauer und einer kurzen Erklaerung. Ohne Preis geht nichts raus (geprueft)
-- ohne Preis kann der Kunde nicht entscheiden, und ein "Angebot" ohne
Zahl ist keins.

3. NACHRICHTEN ZUM PROJEKT

Getrennt vom allgemeinen Postfach, weil sie zum Projekt gehoeren und im
Portal auch dort erscheinen. Sie hier nicht zu haben hiess: Der Kunde
schreibt im Projekt, und ich kann ihm nur woanders antworten.

AUFBAU

Neuer Endpunkt /admin/projekte/:id/alles liefert Projekt, Aufgaben,
Fortschritt, Aenderungswuensche und Nachrichten in EINER Antwort. Fuenf
Anfragen hintereinander wuerden die Ansicht sichtbar ruckelnd aufbauen.

Dieselbe Aufteilung wie in der Anfrageansicht -- links die Arbeit
(Aufgaben), rechts das Steuern. Wer zwischen beiden Ansichten wechselt,
muss nicht umdenken.

GEPRUEFT: 69 Pruefungen, Computer und Handy, alle bestanden.

Die neuen Pruefungen schauen nicht darauf, ob sich ein Knopf einfaerbt --
das beweist nichts. Sie schneiden mit, was die Seite TATSAECHLICH an den
Server schickt: {"status":"entwicklung"}, {"restBezahlt":true},
{"preisEuro":250,"dauer":"3 Tage"}. Und sie pruefen den Fall, in dem
nichts rausgehen darf: Ohne Preis bleibt die Mitschrift leer.

Ein Fehler im Test selbst behoben: Die Nachrichtenzaehlung war
document-weit und zaehlte die Nachrichten der geschlossenen Projektansicht
mit -- geschlossen heisst nicht aus dem Dokument entfernt. Jetzt auf den
Postfach-Verlauf eingegrenzt.

Versionsstempel und Cache-Name auf v6.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 12:08:57 +02:00
DogFatherGitandClaude Opus 5 469a6c195f Portal: Aufgabenliste und Postfach fuer den Kunden
Schritt 4 von 4 -- damit sind beide Wuensche vom 22.08.2026 vollstaendig:
"wenn sie drauf druecken sollen sie auch sehen was ich schon gemacht habe
von dem was im plan war" und "die kunden sollen mir auch nachrichten
hinterlassen koennen".

AUFGABENLISTE IM PROJEKT

Bisher sah der Kunde nur die Phase ("Design . 3/7") -- eine Zahl ohne
Inhalt. Sie beantwortet die eigentliche Frage nicht: WAS ist denn fertig?

Die Liste steht GANZ OBEN, direkt nach dem Projektkopf, noch vor
Zahlungen und Dateien. Die sind wichtig, aber sie sind nicht der Grund
fuer den Klick.

Zwei Entscheidungen praegen die Ansicht:

1. Offene Kundenpunkte stehen in einem EIGENEN Kasten ganz oben ("Das
   brauche ich noch von dir"), nicht nur farblich markiert irgendwo
   mittendrin. Wer eine lange Liste sieht, liest sie als Bericht ueber
   fremde Arbeit und ueberliest seinen eigenen Teil -- genau daraus
   entstehen die meisten Verzoegerungen. Ist nichts offen, steht das
   auch da: "Von dir wird gerade nichts gebraucht." Eine gute Nachricht
   darf ausgesprochen werden.

2. Der Kunde hakt seine eigenen Punkte selbst ab. Nur diese haben einen
   Knopf; bei fremden Punkten ist das Zeichen reine Anzeige. Ein Knopf,
   der nichts tut, laesst die Seite kaputt wirken. Geprueft: 4 Knoepfe
   bei 2 offenen eigenen Punkten (sie erscheinen zweimal), 5 feste.

Grosse Zahl statt Prozent: "2 von 6 erledigt" ist greifbar, "33 %" ist
eine Rechnung, die niemand fuehlt. Der Balken traegt die vier
Prozessfarben -- dieselben wie auf der Ablaufseite und in der Verwaltung.

Der Ton ist bewusst gewaehlt. Der Kunde liest die Liste, wenn er unsicher
ist -- also im Zweifel schon angespannt. "Wir warten auf dich" waere
Druck, "Das brauche ich noch von dir" ist eine Bitte.

POSTFACH AUF DER UEBERSICHT

Bewusst auf der Uebersicht, nicht im Projekt: Wer kein Projekt hat -- oder
eine Frage, die zu keinem gehoert -- konnte vorher gar nicht schreiben und
musste zur E-Mail greifen. Damit war der Verlauf weg, sobald man ihn
brauchte.

Niedrigschwellig: kein Betreff, kein Pflichtfeld, der Projektbezug ist
freiwillig. Wer glaubt, eine Nachricht muesse eine "richtige" Anfrage
sein, schreibt gar nicht erst -- und genau die kurzen Fragen sollen hier
landen. Wird nachgeladen, damit die Uebersicht sofort dasteht.

Projekt- und Aufgabendaten werden gleichzeitig angefordert statt
nacheinander -- sonst waere die Wartezeit die Summe beider Anfragen. Die
Aufgabenliste darf dabei fehlschlagen, ohne die Seite mitzureissen: Wer
wegen einer leeren Liste seine Zahlungen nicht mehr saehe, waere
schlechter dran als vorher.

EIN SICHTBARER FEHLER GEFUNDEN

Auf dem Screenshot stand "Ideen &amp;amp; Aenderungswuensche". Ursache ist
eine Falle mit zwei Wegen: Texte ueber data-i18n landen als HTML in der
Seite, dort ist "&amp;" richtig. Derselbe Text im JavaScript laeuft aber
durch die Absicherung und wird ein zweites Mal kodiert. Derselbe Baustein
ist also je nach Verwendungsort richtig oder falsch.

Das kann man nicht im Kopf behalten -- deshalb neu pruef-texte.mjs mit
ZWEI Pruefungen:

  Anzeige:   alle 11 Seiten x 5 Sprachen = 55 Kombinationen, sichtbarer
             Text darf keine Kodierungsreste enthalten.
  Quelltext: welcher Baustein mit "&amp;" wird irgendwo abgesichert
             eingesetzt?

Beide sind noetig. Gegengeprueft: Die Anzeigepruefung allein haette den
Fehler NICHT gefunden, weil die Ideen-Karte erst nach einer Anmeldung
erscheint. Die Quelltextpruefung findet ihn ohne Anzeige.

Auch die Quelltextpruefung selbst wurde zweimal gegengeprueft: Zuerst
meldete sie zusaetzlich po_senden ("Senden", voellig harmlos) -- ihre
Blockerkennung lief bis zum naechsten Schluessel und schluckte dabei
einen Kommentar mit "&". Jetzt zaehlt sie geschweifte Klammern. Ein
Fehlalarm im Pruefwerkzeug ist fast so schaedlich wie ein uebersehener
Fehler: Man gewoehnt sich daran, ihn wegzusehen.

GEPRUEFT

32 Pruefungen im Portal (Computer und Handy), alle bestanden. Darunter:
114 Texte in allen fuenf Sprachen vollstaendig, Kundenpunkte stehen vor
der langen Liste, Aufgaben vor den Zahlungen, Abhaken meldet den
richtigen Punkt, alle Kaestchen mindestens 24 px, keine Fehler im
Protokoll. Dazu 55 Seiten-Sprach-Kombinationen ohne Kodierungsreste.

Ein Fehler im Test selbst gefunden und behoben: Die Adressabfrage prueft
jetzt den PFAD statt der ganzen Adresse. Der API-Server heisst
"postfach.dogfather-universe.com" -- ein includes("/postfach") traf den
HOSTNAMEN und damit jede Anfrage, auch die Uebersicht.

Versionsstempel und Cache-Name auf v5.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 10:46:09 +02:00
DogFatherGitandClaude Opus 5 b7c333fca3 Verwaltung: Aufgabenlisten abhaken und Postfach
Schritt 3 von 4 zu den zwei Wuenschen vom 22.08.2026. Die Datenbank und
die Server-Routen standen schon; das hier ist die Seite, auf der ICH
arbeite. Was hier passiert, sieht der Kunde unmittelbar in seinem Portal
(Schritt 4).

ZWEI NEUE REITER

"Projekte" -- bisher gab es Projekte nur als Zahl neben dem Kunden
("3 Proj."), man konnte kein einzelnes oeffnen. Man denkt aber in
Projekten, nicht in Kunden. Neuer Endpunkt projekteListe liefert die
flache Liste samt Aufgabenzahlen; die einzeln nachzufragen haette bei
zwanzig Projekten einundzwanzig Anfragen bedeutet.

"Postfach" -- mit Abzeichen fuer Ungelesenes. Steht nichts an, ist das
Abzeichen GANZ weg statt eine 0 zu zeigen: Eine Null, die man taeglich
sieht, wird zu Rauschen, und irgendwann uebersieht man auch die 3.

Die Reiterumschaltung war vorher ein Ja/Nein zwischen zwei Ansichten. Mit
vier Reitern haette jede neue Ansicht eine weitere "hidden = ..."-Zeile
gebraucht -- und beim naechsten Reiter vergisst man eine, dann liegen zwei
Ansichten uebereinander. Jetzt eine Zuordnung Reiter -> Kasten, die sich
selbst aufraeumt.

AUFGABENLISTE

Vier Abschnitte in den vier Prozessfarben -- dieselben wie im Portal und
auf der Ablaufseite. Das ist der Punkt: Eine Farbe bedeutet ueberall
dasselbe, sonst waere sie Deko.

Ein Klick aufs Kaestchen schaltet weiter: offen -> in Arbeit -> erledigt.
Drei Zustaende ueber einen Knopf statt eines Auswahlfeldes -- beim
Abarbeiten einer Liste zaehlt jeder gesparte Klick.

Punkte, die auf den KUNDEN warten, sind golden hinterlegt und tragen eine
Marke. Ohne diese Unterscheidung liest man die Liste als reinen
Fortschrittsbericht und uebersieht, dass man selbst gar nicht am Zug ist.
Der goldene Grund verschwindet, sobald der Punkt erledigt ist -- er
braucht dann keine Aufmerksamkeit mehr.

Abhaken faerbt die Zeile sofort um, ohne auf den Server zu warten. Bei
zehn Punkten hintereinander waere ein Neuaufbau nach jedem Klick zaeh, und
man verliert die Stelle. Geht es schief, wird die Liste neu geholt und der
Zustand ist wieder ehrlich.

POSTFACH

Links Verlaeufe, rechts das Gespraech. Nicht aus Nachahmung, sondern weil
man ein Gespraech abarbeitet und nicht eine Zeile: Man will sehen, was
vorher besprochen wurde, waehrend man antwortet. Kunde links, eigene
Nachrichten rechts -- man erkennt den Absender an der Seite, bevor man den
Namen liest.

Der Schalter "Nur interne Notiz" faerbt das ganze Schreibfeld um. Ein
Haekchen allein uebersieht man, und eine interne Bemerkung, die beim
Kunden landet, ist der peinlichste Fehler, den dieses System machen kann.
Interne Notizen im Verlauf sind gestrichelt umrandet und golden -- sie
duerfen nicht wie etwas Gesendetes aussehen.

Strg+Enter sendet, Enter allein nicht: In einem mehrzeiligen Feld will man
Absaetze machen koennen, ohne dass die halbe Nachricht rausgeht.

EIN FEHLER, DEN DIE TESTS NICHT GEFUNDEN HABEN

Der erste Lauf meldete 37 von 37 gruen -- und jede Aufgabenzeile war
sichtbar falsch herum gebaut: Kaestchen, dann die kleinen Knoepfe, Titel
ganz rechts. Aufgefallen ist es erst am Screenshot.

Ursache: Das Raster platziert zuerst alle Elemente mit FESTGELEGTER Zeile
und erst danach die freien. Kaestchen und Knopfgruppe hatten beide
"grid-row: 1 / span 2" und wurden deshalb zusammen nach vorne gesetzt; der
Titel landete als letzter in der dritten Spalte. Jetzt bekommt jedes Kind
Zeile UND Spalte ausdruecklich.

Die eigentliche Lehre steckt im Test: Alle 37 Pruefungen betrafen
Bestandteile (Farben, Anzahl, Durchgestrichenes), keine einzige die
ANORDNUNG. Wer eine Anordnung baut, muss die Anordnung pruefen. Drei neue
Pruefungen vergleichen jetzt die tatsaechlichen Bildschirmpositionen --
und sie wurden gegengeprueft: Mit dem alten Zustand schlagen sie fehl,
mit dem neuen nicht. Ein Test, der nie fehlschlaegt, ist wertlos.

GEPRUEFT: 43 Pruefungen, Computer und Handy, alle bestanden. Darunter:
alle Touch-Ziele mindestens 24 px, interne Notiz sieht anders aus als eine
gesendete, Verlauf springt ans Ende, keine Fehler im Protokoll.

Versionsstempel und Cache-Name auf v4.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 23:30:11 +02:00
DogFatherGitandClaude Opus 5 9186d4cc1a Verwaltung uebersichtlicher, Bildlaufleiste dunkel
Rueckmeldung 22.08.2026 zur Anfrage-Detailansicht: "das ganze soll viel
uebersichtlicher sein und nicht so durcheinander" und "die leiste rechts
zum hoch und runter, kannst du die mal geil aussehen lassen anstatt
einfach so kake weiss."

1. DAS DURCHEINANDER HATTE EINE URSACHE

Die Kaesten standen in "columns: 2" -- Zeitungsspalten. Die fuellen sich
von selbst: erst Spalte eins bis oben voll, dann Spalte zwei. Wo ein
Kasten landet, haengt allein davon ab, wie lang die vor ihm sind. Bei
einer Anfrage stand "Interne Notizen" oben rechts, bei der naechsten
unten links. Es gab schlicht keine Ordnung, der man haette folgen koennen.

Jetzt ein festes Raster mit einer Aussage:
  LINKS  = was der Kunde geschickt hat   (lesen)
  RECHTS = was du damit machst           (handeln)

Immer gleich. Nach der zweiten Anfrage weiss man, wo man hinschaut, ohne
zu suchen. Rechts ist schmaler (Knoepfe brauchen weniger Platz als
laufender Text) und klebt beim Scrollen mit -- die Handlungen sind der
Grund, warum man die Ansicht oeffnet, sie duerfen nicht aus dem Bild
wandern.

Reihenfolge rechts korrigiert: "Anfrage uebernehmen" steht jetzt oben.
Es ist der Knopf, den man bei einer neuen Anfrage druecken WILL -- er
stand unter den Notizen und damit ausserhalb des sichtbaren Bereichs.

2. "KEINE ANGABE" WAR DIE HALBE ANSICHT

Jede fehlende Angabe bekam eine eigene Zeile. Der Kasten "Umfang"
enthielt zweimal nichts und war trotzdem so gross wie einer mit Inhalt.

Leere Felder sind aber keine Information, sondern deren Fehlen. Sie
stehen jetzt als EINE leise Zeile am Fuss: "Ohne Angabe: Bereiche,
Funktionen". Aus sechs Zeilen wird eine. Weggelassen werden sie nicht --
man muss sehen, wonach gefragt wurde und was unbeantwortet blieb, genau
daraus entstehen die Rueckfragen.

Neu darueber: "Auf einen Blick" mit Paket, Budget, Wunschtermin und
Alter. Die vier Fragen, die man immer zuerst hat, standen vorher auf drei
Kaesten verteilt. Das Alter als "vor 3 Tagen" statt als Datum -- die
Frage ist nie "welcher Tag war das", sondern "wie lange liegt das schon
hier", und die beantwortet ein Datum erst nach Kopfrechnen.

3. BILDLAUFLEISTE -- und ein Fehler, der fast durchgegangen waere

Auf einer durchgehend dunklen Seite ist eine weisse Bildlaufleiste der
einzige grelle Streifen im Bild. Sie zieht den Blick dorthin, wo nichts
Wichtiges steht, und blendet. Verstoesst gegen die Dauervorgabe
"augenschonend".

Zwei Wege noetig, weil kein Browser beide versteht: color-scheme: dark
fuer Firefox/Safari (wirkt zusaetzlich auf Auswahl- und Datumsfelder, die
sonst weiss aufblitzen), ::-webkit-scrollbar fuer Chrome/Edge.
scrollbar-width/-color bewusst NICHT gesetzt -- sobald es dasteht,
ignoriert Chrome die feineren ::-webkit-Regeln.

Beim ersten Versuch stand dort nur ".wd ::-webkit-scrollbar" -- MIT
Leerzeichen. Das trifft nur Elemente INNERHALB der Seite, nicht den body
selbst. Alle Messungen sahen gut aus; an der einen Leiste, ueber die sich
jemand beschwert hatte, haette sich nichts geaendert. Jetzt beide
Fassungen, mit einem Warnhinweis im CSS.

GEPRUEFT

Neue Datei pruef-detail.mjs: echter Browser, 1440x900 und 390x844, mit
einer absichtlich sehr knappen Anfrage -- genau die sah vorher schlecht
aus. 20 Pruefungen, alle bestanden: Spalten nebeneinander bzw. auf dem
Handy untereinander, rechte schmaler als linke, keine Ueberlappung, kein
waagerechtes Schieben, nichts ragt aus dem Fenster, keine einzelne
"keine Angabe"-Zeile mehr, keine Fehler im Protokoll.

Die Bildlaufleiste liess sich nur in einem ECHTEN Browserfenster pruefen:
Headless-Chromium blendet Leisten grundsaetzlich ueber dem Inhalt ein und
meldet deshalb immer 0 px Breite. Mit sichtbarem Fenster gemessen: 12 px,
alle sechs Regeln vom Browser akzeptiert.

Versionsstempel auf allen 11 Seiten und Cache-Name des Service Workers
auf v3 -- sonst liefert der eigene Zwischenspeicher beim ersten Laden
weiter die alte Fassung aus.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 23:05:47 +02:00
DogFatherGit 60c1e7be94 Test: Absturz beim Beenden vermeiden (better-sqlite3) 2026-08-22 22:57:59 +02:00
DogFatherGit 38bc741660 Aufraeumen: versehentlich mitcommittete Dateien entfernt
Ein 'git add -A' hat 13 Bild-Sicherungskopien (.bak-*, zusammen 2,6 MB),
den lokalen Testserver und eine erzeugte package-lock.json mitgenommen.

Die package-lock.json war der schaedlichste Teil: Auf dem Server existiert
eine eigene, dort erzeugte Fassung. Eine versionierte Datei gleichen Namens
laesst 'git pull' abbrechen -- der Deploy stand sofort still.

Alle drei Muster stehen jetzt in .gitignore.
2026-08-22 22:57:26 +02:00
DogFatherGit 4ce51c127e WIP: Aufgaben- und Postfach-Routen (Test folgt auf dem Server) 2026-08-22 22:56:59 +02:00
DogFatherGitandClaude Opus 5 548ec6bc00 Aufgabenlisten und allgemeines Postfach: Datenbank und Vorlagen
Erster von vier Schritten fuer zwei Wuensche vom 22.08.2026:
"wenn sie drauf druecken sollen sie auch sehen was ich schon gemacht habe
von dem was im plan war" und "die kunden sollen mir auch nachrichten
hinterlassen koennen".

DATENBANK (3 neue Tabellen, jetzt 18 insgesamt, Fremdschluessel geprueft)

wd_aufgaben -- die Punkte je Projekt. Drei Entscheidungen darin:
  * "wer_dran" ist eine eigene Spalte, kein Text. Manche Punkte warten
    auf den KUNDEN ("Texte liefern"), und genau die muessen ihm ins Auge
    springen. Ohne diese Unterscheidung liest er die Liste als reinen
    Fortschrittsbericht und uebersieht seinen eigenen Teil -- der
    haeufigste Grund fuer Verzoegerungen ueberhaupt.
  * "nicht_enthalten" bildet ab, was NICHT zum Umfang gehoert. Das ist
    die haeufigste Streitfrage in jedem Projekt ("ich dachte, das ist
    dabei"). Vorher sichtbar aufgeschrieben kostet es nichts, hinterher
    kostet es Geld oder den Kunden.
  * "kategorie" nutzt dieselben vier Abschnitte wie die Farben im Portal.
    Damit bedeutet eine Farbe ueberall dasselbe statt nur huebsch zu sein.

wd_postfach -- Nachrichten OHNE Projektbezug. Bewusst eine EIGENE Tabelle:
wd_nachrichten hat projekt_id als NOT NULL, und SQLite kann das nicht
lockern, ohne die ganze Tabelle zu kopieren -- ein unnoetiges Risiko bei
echten Kundennachrichten. Die neue Tabelle hat ohnehin andere
Anforderungen (Anhaenge, Lesestatus in BEIDE Richtungen, optionaler Bezug
auf eine Aufgabe). Zwei klar getrennte Tabellen sind ehrlicher als eine,
die beides halb kann.

VORLAGEN (56 Punkte ueber 5 Pakete, davon 20 beim Kunden)

Bei jedem Projekt fuenfzehn Punkte von Hand einzutippen fuehrt
zuverlaessig dazu, dass es irgendwann niemand mehr macht -- und dann
steht der Kunde wieder vor der leeren Liste, die der Ausloeser war.

Die Punkte sind in der Sprache formuliert, in der ein KUNDE denkt:
"Aufbau der Seiten festlegen" statt "Informationsarchitektur", "Auf dem
Handy durchtesten" statt "Responsive QA". Er liest diese Liste -- sie
muss ihm etwas sagen, nicht mir.

Die Vorlagen wandern beim ersten Start in die Datenbank und sind ab dann
dort aenderbar. Bereits vorhandene werden NIE ueberschrieben: sonst waeren
von Hand angepasste Vorlagen nach dem naechsten Neustart weg, und niemand
kaeme auf die Idee, dass der Neustart schuld war.

Naechste Schritte: Server-Routen, Verwaltung, Portal.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 22:48:39 +02:00
DogFatherGitandClaude Opus 5 71b9fc09c1 Anfrage-Detail: zentriertes Fenster statt seitlicher Leiste
Rueckmeldung 22.08.2026 mit Bildschirmfoto: "ich will das nicht so ich
will es viel viel viel besser und uebersichtlicher und schoener zentriert
in der mitte."

Berechtigt, und aus mehreren Gruenden. Eine seitlich eingeschobene Leiste
ist fuer so viel Inhalt das falsche Format:
  * Der Blick springt beim Oeffnen nach rechts.
  * Die Liste dahinter bleibt halb sichtbar und lenkt ab.
  * Alles muss sich in eine schmale Spalte quetschen -- auf dem
    Bildschirmfoto stand "keine Angabe" dadurch achtmal untereinander,
    und die Abwesenheit von Information nahm mehr Platz ein als die
    Information selbst.

Jetzt: mittig, 940px breit, zweispaltig ab Tablet. Der Blick bleibt, wo
er ist, und zusammengehoerende Angaben stehen nebeneinander.

Weitere Entscheidungen:
* Mauerwerk-Umbruch (columns) statt Raster. Die Abschnitte sind
  unterschiedlich hoch; ein Raster haette grosse Luecken gerissen.
* Jeder Abschnitt bekommt eine eigene Flaeche statt nur einer Trennlinie.
* Die Kopfzeile klebt beim Scrollen oben fest. Bei einer langen Anfrage
  weiss man sonst nach dem Scrollen nicht mehr, wessen Daten man liest.
* "keine Angabe" wird kleiner und blasser dargestellt. Es ist die
  ABWESENHEIT einer Information und darf nicht aussehen wie eine.
* Die Oeffnen-Animation skaliert dezent aus der Mitte statt von rechts
  hereinzufahren, und ist bei prefers-reduced-motion ganz aus.

9/9 Tests weiterhin gruen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 22:28:09 +02:00
DogFatherGitandClaude Opus 5 2539fdea8d Zahlenkreise repariert und vier Prozessfarben durchgaengig
"wieso sehen die zahlen immer noch so scheisse aus?" -- zu Recht, und die
Ursache war nicht Geschmack, sondern ein Fehler. Nachgemessen sass die
Ziffer 15px NEBEN der Kreismitte.

Ursache: ".po-leer-punkt span" (fuer den Beschreibungstext) trifft auch
den Zahlen-Span und ist spezifischer (Klasse + Element) als
".po-leer-nr" (nur Klasse). Sie erzwang display:block, 14,4px Schrift und
23px Zeilenhoehe -- exakt die gemessenen Werte. Meine eigene
"line-height: 1"-Regel kam gar nicht zum Zug.

Das ist derselbe Spezifitaets-Fehler wie zuvor beim Hauptknopf (blaue
Schrift auf blauem Grund) und bei den Namen auf der Zugangswand. Dreimal
dieselbe Falle, deshalb steht die Begruendung jetzt ausfuehrlich im Code.

Behoben ueber :not(.po-leer-nr) an beiden Textregeln. Nachgemessen:
  Versatz waagerecht  -15px -> 0px
  Versatz senkrecht    -8px -> -1,3px
  display             block -> grid
  Schrift/Zeile   14,4/23px -> 18,4/18,4px

Zweite Rueckmeldung: "es soll 4 farben geben wie 4 kategorien zum
prozess". Sehr gute Idee -- sie macht das System erst schluessig. Die
sieben Phasen sind in Wahrheit vier Abschnitte, und die vier
Merkmalskacheln trugen ohnehin schon vier Farben. Jetzt bedeuten diese
Farben ueberall dasselbe:

  1  Blau   Start        Briefing, Angebot
  2  Lila   Gestaltung   Design
  3  Gruen  Umsetzung    Entwicklung, Tests
  4  Gold   Abschluss    Abnahme, Uebergabe

Die Phasenleiste faerbt erledigte Abschnitte in IHRER Farbe statt
pauschal gruen -- man sieht dadurch, wie weit man ist, nicht nur DASS
etwas fertig ist. Die Vorschau laeuft in denselben Farben durch. Die
Legende nennt die vier Abschnitte beim Namen, damit Farbe nicht geraten
werden muss: Farbe allein ist nie Information.

45/45 Handy-Abnahme, i18n vollstaendig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 22:26:04 +02:00
DogFatherGitandClaude Opus 5 c597753abf Portal: Zahlenkreise, Typografie und eine echte Farblogik fuer Phasen
Drei Rueckmeldungen vom 22.08.2026, alle drei berechtigt.

1) "die kisten sollen auch eine spezielle farbe bekommen wenn sie fertig
   sind" -- das war inhaltlich der wichtigste Punkt. Vorher sahen
   erledigte und gerade laufende Phase fast gleich blau aus. Damit ging
   die einzige Aussage verloren, die die Leiste ueberhaupt traegt:
   naemlich WO man steht. Jetzt drei klar getrennte Zustaende:
     erledigt     gruen, ruhig
     laeuft grad  leuchtendes Blau mit langsamem Puls
     kommt noch   gedaempft
   Die Vorschau erklaert die Logik gleich mit: ihre Leiste wandert von
   blau nach gruen, statt nur an- und auszugehen.
   Dazu eine Legende in Worten. Farbe allein ist nie Information -- wer
   sie nicht unterscheiden kann, liest hier trotzdem, was sie bedeutet.

2) "die zahlen sollen besser im kreis sein" -- vorher ein flacher Kreis
   mit Zahl. Jetzt ein doppelter Ring: aussen ein Farbverlauf als Rand,
   innen die dunkle Flaeche, dazu ein weicher Schein. Derselbe Kniff wie
   bei den Karten (Verlauf ueber border-box); der Kreis wirkt dadurch
   plastisch statt aufgemalt. Jede der vier Kacheln hat ihre eigene
   Farbe -- vier gleiche Kacheln wirken wie eine Aufzaehlung, vier
   unterscheidbare wie ein System.

3) "schrift soll spezieller sein" -- die Kachel-Ueberschrift war so gross
   wie der Text darunter und ging unter. Jetzt groesser, in der
   Headline-Schrift, enger gesetzt mit leicht negativer Laufweite. Die
   Ueberschrift "Gleich geht es los" bekommt einen Farbverlauf.

45/45 Handy-Abnahme, i18n vollstaendig, prefers-reduced-motion beachtet.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 22:14:00 +02:00
DogFatherGitandClaude Opus 5 ad58ab99d3 Leeres Portal: zeigen statt erzaehlen
Rueckmeldung 22.08.2026 mit Bildschirmfoto: "dass muss noch viel
spezieller, krasser und geiler sein, nicht so einfach".

Der Kern des Problems war nicht die Optik, sondern die Haltung: Die Seite
BESCHRIEB, was hier bald stehen wird ("Eine Leiste zeigt dir, in welcher
Phase dein Projekt ist"). Beschreibungen sind schwach -- man muss sie
lesen und sich dann etwas vorstellen.

Jetzt steht dort eine echte, als Vorschau gekennzeichnete Projektkarte:
Projektnummer, Titel, eine Phasenleiste, die langsam durchlaeuft, die
Marke "Dogfather ist dran" und ein naechster Schritt. Man sieht in zwei
Sekunden, was drei Saetze nicht erklaeren.

Die Karte ist bewusst als Vorschau erkennbar -- gestrichelter Rand,
Etikett oben rechts, gedaempfte Schrift, Nummer P-0000-0000. Sie darf nie
mit einem echten Projekt verwechselt werden.

Dazu ein sehr langsamer Lichtstreifen, der einmal durchwandert. Er sagt
ohne Worte "hier passiert gleich etwas", ohne zu blinken oder zu zappeln
-- augenschonend bleibt Dauervorgabe.

Bei prefers-reduced-motion laeuft nichts, aber die Phasenleiste zeigt
trotzdem drei erledigte Phasen. Ohne das staende dort eine leere graue
Reihe und die Vorschau erklaerte gar nichts mehr -- ein abgeschaltetes
Element muss trotzdem noch seine Aussage transportieren.

45/45 Handy-Abnahme, i18n vollstaendig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 22:07:06 +02:00
DogFatherGitandClaude Opus 5 96458b58aa Anfrage mit einem Klick zu Kunde und Projektraum machen
Der wichtigste Handgriff im ganzen Bereich -- und der Weg, den man bei
JEDEM echten Kunden geht. Bisher haette man Name, E-Mail, Paket und
Wunschtermin von Hand in die Kundenmaske abgetippt: vier Gelegenheiten
fuer einen Tippfehler, und einer davon ist spaeter nicht mehr
korrigierbar, weil die E-Mail gleichzeitig der Anmeldename ist.

Jetzt steht in der Anfrage-Detailansicht eine Uebernahme mit Vorschau
(Kunde, E-Mail, Projekttitel, Sprache) und einem optionalen Preisfeld,
das die 30 % Anzahlung beim Tippen mitrechnet. Ein Klick legt an:
  * den Kundenzugang, freigeschaltet, in der Sprache der Anfrage
  * das Projekt, verknuepft mit der Anfrage, mit Wunschtermin und
    "Briefing-Termin vereinbaren" als erstem sichtbaren Schritt
  * die Anfrage wechselt automatisch auf "angenommen"
Danach springt die Ansicht auf "Kunden" und zeigt sofort den
Einladungslink -- den einzigen Weg, wie der Kunde an sein Passwort kommt.

Die beiden Schritte laufen bewusst nacheinander, nicht parallel: das
Projekt braucht die Kunden-Kennung. Schlaegt der zweite fehl, existiert
der Kunde trotzdem schon. Genau das sagt die Fehlermeldung dann auch
ausdruecklich -- sonst versucht man es blind noch einmal und scheitert an
der doppelten E-Mail-Adresse, ohne zu verstehen warum.

Ist aus einer Anfrage bereits ein Kunde geworden, erscheint statt der
Uebernahme ein Hinweis darauf. Zweimal denselben Kunden anzulegen soll
gar nicht erst angeboten werden.

Dabei denselben Anfuehrungszeichen-Fehler wie schon einmal gemacht und
behoben: das gerade " in „Kunden" beendet die JavaScript-Zeichenkette.
Typografisch richtig ist ohnehin das schliessende " -- beides in einem Zug.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:48:07 +02:00
DogFatherGitandClaude Opus 5 77674cb801 Kennzahlen der Verwaltung: aus stillen Zahlen werden Werkzeuge
Rueckmeldung 22.08.2026: "mach es noch krasser noch detaillierter noch
viel besser und perfekter und auch die kacheln viel geiler."

Die Kacheln waren eine Reihe stiller Zahlen. Zahlen, die man nur anschauen
kann, sind Dekoration. Jetzt:

* Jede Kachel FILTERT die Liste darunter beim Antippen. Als echter
  <button>, nicht als div mit Klickzuhoerer -- sonst ist sie mit der
  Tastatur nicht erreichbar und ein Screenreader kuendigt sie nicht als
  Bedienelement an.
* Jede Kachel sagt, was zu TUN ist, nicht nur wie viele es sind:
  "warten auf dich" / "du bist dran" / "Kunde ist dran" /
  "Projekt anlegen".
* Neue Kachel: der aelteste unbearbeitete Vorgang in Tagen. Das ist die
  ehrlichste Kennzahl ueberhaupt -- sie sagt nicht, wie viel man
  geschafft hat, sondern wie lange jemand schon auf Antwort wartet.
  Genau daran misst ein Kunde Zuverlaessigkeit. Ab sieben Tagen rot.
  Diese eine Kachel filtert bewusst NICHT und ist deshalb auch kein
  Knopf: sie zeigt einen Zustand, keinen Status.
* Eine Null wird gedaempft dargestellt. Sonst konkurriert "0 abgelehnt"
  optisch mit "3 neu" -- und genau die Drei ist die, auf die man schauen
  soll. Was nichts zu tun gibt, soll auch nicht leuchten.
* Gold bleibt ausschliesslich dem echten Handlungsbedarf vorbehalten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:44:37 +02:00
DogFatherGitandClaude Opus 5 d93625439a Verwaltung: mehr Information pro Zeile statt leerer Flaeche
Rueckmeldung 22.08.2026 mit Bildschirmfoto: die Anfragenliste wirkte blass
und leer. Zu Recht -- sie zeigte Nummer, Name, Paket, Status, Datum. Das
ist korrekt, beantwortet aber nicht die Fragen, die man beim Draufschauen
WIRKLICH hat.

Jetzt steht in jeder Zeile:
* E-Mail direkt sichtbar (vorher musste man die Anfrage dafuer oeffnen)
* Paket, Budgetrahmen, Wunschtermin als eigene Marken
* Sprache, falls es NICHT Deutsch ist -- dann antwortet man auch in der
  richtigen Sprache
* ob daraus schon ein Kunde geworden ist

Statt eines Datums steht dort "vor 3 Tagen". Beim Datum muss man selbst
rechnen, wie lange jemand schon wartet -- und genau das ist die Frage,
die zaehlt. Ab sieben Tagen ohne Bearbeitung wird die Angabe rot: eine
Anfrage, die eine Woche liegt, ist ein verlorener Kunde.

Ein farbiger Streifen links codiert den Status zusaetzlich zur Textmarke.
Farbe ALLEIN waere fuer farbfehlsichtige Menschen keine Information --
zusammen mit dem Text ist sie ein schneller Anker beim Ueberfliegen.

Der leere Zustand stellt nicht mehr nur fest, dass nichts da ist, sondern
erklaert, WO Anfragen herkommen, und legt den Link zum Formular gleich
daneben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:42:15 +02:00
DogFatherGitandClaude Opus 5 097e80b845 Projekte anlegen und ein leerer Zustand, der fuehrt statt zu enttaeuschen
Rueckmeldung 22.08.2026 mit Bildschirmfoto aus dem eigenen Testzugang:
"die seite soll jetzt schon bitte richtig krass sein und hoch profissionel,
auch sehr detailliert."

Zwei Luecken, beide geschlossen:

1) Projekte liessen sich nur ueber die Schnittstelle anlegen. Jetzt in der
   Verwaltung: pro Kunde ein "+ Projekt" mit Titel, Paket, Preis,
   Richttermin und naechstem Schritt. Bewusst als Einblendung direkt bei
   der Kundenzeile statt als eigene Seite -- man legt ein Projekt IMMER
   fuer einen bestimmten Kunden an, nie im luftleeren Raum. Der Kundenname
   steht deshalb gross im Formular, damit es nicht versehentlich dem
   Falschen angehaengt wird.
   Die 30 % Anzahlung wird beim Tippen live mitgerechnet. Sie wird zwar
   serverseitig berechnet, aber wer sie beim Eintippen sieht, merkt eine
   falsche Null sofort -- und nicht erst, wenn der Kunde ueberweisen soll.

2) Der leere Zustand im Portal war ein einziger Satz. Das ist eine
   verpasste Gelegenheit: Wer dort zum ersten Mal landet, hat gerade sein
   Passwort gesetzt und weiss noch nicht, was ihn erwartet -- genau dann
   entscheidet sich, ob die Seite souveraen wirkt oder unfertig. Jetzt
   zeigt er in vier Punkten, WAS gleich hier stehen wird (Projektstand,
   wer am Zug ist, Dateien und Nachrichten, Ideen jederzeit) und schliesst
   mit der Zusicherung, dass nichts zu tun ist. Fuenfsprachig.

45/45 Handy-Abnahme, i18n vollstaendig.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:40:27 +02:00
DogFatherGitandClaude Opus 5 74091590b8 Verwaltung: nur noch EINMAL den Code eingeben
Rueckmeldung 22.08.2026: "ich hab auf der verwaltungs seite 2 mal dass ich
den zugangscode eingeben muss und vanvan auch, ich will es nur einmal
eingeben muessen." Berechtigt.

Die Zugangswand hat serverseitig laengst geprueft, WER da ist -- Dogfather
oder VanVan, laut Masterplan S.4 beide gleichberechtigte
Volladministratoren. Ein zweites Passwort danach bringt keinen
zusaetzlichen Schutz, es kostet nur jedes Mal Zeit.

Warum es nicht einfach "Cookie mitschicken" ist: Die Verwaltungsdaten
liegen hinter postfach.dogfather-universe.com, einem ANDEREN Rechnernamen.
Das Sitzungs-Cookie gilt dort nicht -- so sind Cookies gebaut, und das ist
gut so.

Loesung: Die Zugangswand stellt unter /webdesign/api-ausweis einen
kurzlebigen, signierten Ausweis aus, den die interne API anerkennt.
  - 15 Minuten gueltig, die Seite holt bei Bedarf still einen neuen
  - traegt bereich="wd-admin", damit ein Sitzungs-Token der Zugangswand
    hier NICHT durchgeht und umgekehrt
  - nur mit gueltiger Zugangssitzung zu bekommen
  - gilt AUSSCHLIESSLICH fuer die /webdesign-Endpunkte. Postfach,
    Bewerbungen, Supporter und Teamverwaltung bleiben unberuehrt

Fehlt WEBDESIGN_API_SECRET auf einer der beiden Seiten, gilt kein Ausweis
und die Verwaltung fragt wie bisher nach dem Team-Code. Ein fehlender
Konfigurationswert darf niemals eine Tuer oeffnen -- nur eine schliessen.
Genau das prueft der letzte Testfall.

Bei einem 401 wird EINMAL still ein neuer Ausweis geholt und die Anfrage
wiederholt, statt jemanden mitten im Arbeiten rauszuwerfen.

10/10 Tests, darunter: gefaelschte Signatur, fremdes Geheimnis,
abgelaufen, falscher Bereich, erfundene Rolle.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:36:11 +02:00
DogFatherGitandClaude Opus 5 2542a2598e Kunden und Projekte in der Verwaltung anlegen, inklusive Testzugang
Wunsch 22.08.2026: "ich will einen provisorischen zugang fuer mich".
Der richtige Weg dahin war ohnehin ueberfaellig -- Kundenzugaenge
entstehen ausschliesslich hier, es gibt bewusst keine Selbstregistrierung.

Neu:
* Kundenzugang anlegen (Name, E-Mail, Firma, Sprache, sofort freischalten
  ja/nein) mit Einladungslink
* "Testzugang fuer mich" -- ein Klick, legt einen als Test erkennbaren
  Zugang mit Datumsstempel an. Bewusst NICHT die echte Geschaeftsadresse:
  die E-Mail ist gleichzeitig der Anmeldename und laesst sich aus gutem
  Grund nicht mehr aendern, ein Test wuerde also spaeter mit einem echten
  Kundenkonto kollidieren.
* Zugaenge auflisten, freischalten, sperren, neuen Einladungslink erzeugen
* Projekte anlegen und aendern, Aenderungswuensche beziffern, Nachrichten

Entscheidungen:
* Der Einladungslink geht EINMAL im Klartext raus, direkt beim Anlegen.
  In der Datenbank liegt nur sein Hash. Wer ihn verliert, bekommt einen
  neuen -- das ist sicherer, als ihn dauerhaft abrufbar zu halten. Die
  Oberflaeche sagt das auch klar dazu, sonst klickt man ihn weg und
  wundert sich.
* Ein neuer Link entwertet alle offenen alten. Sonst sammeln sich mehrere
  gueltige Generalschluessel fuer dasselbe Konto an.
* "Sofort freischalten" ist eine bewusste Handlung. Ohne Haekchen wird der
  Zugang angelegt, kommt aber noch nicht hinein -- Masterplan S.12
  verlangt, dass Projektkauf oder Betreuung VOR der Freischaltung geprueft
  werden.
* Sperren beendet laufende Sitzungen sofort, nicht erst nach Ablauf.
* Die 30 % Anzahlung werden aus dem Preis BERECHNET, nicht eingetippt.
  Ein Tippfehler in der Anzahlung faellt sonst erst beim Geldeingang auf.
* Preise kommen als Euro herein und werden sofort in Cent umgerechnet
  (Math.round, damit 49.99 nicht zu 4998 wird). Ab da nie wieder Komma.
* Vier klar unterscheidbare Zustaende in der Liste. Wichtig vor allem
  "Einladung offen": freigeschaltet, aber noch kein Passwort gesetzt --
  der Kunde war also noch nie drin.
* Kopieren faellt auf Markieren zurueck, wenn die Zwischenablage
  blockiert ist. Eine Fehlermeldung waere dort nutzlos.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:23:15 +02:00
DogFatherGitandClaude Opus 5 1b432f456f Kundenportal: Oberflaeche (Masterplan S.12)
Vier Ansichten in einer Seite: Anmeldung, Passwort festlegen ueber den
Einladungslink, Uebersicht, Projektdetail. 71 Textbausteine in fuenf
Sprachen.

Korrektur an einer frueheren Entscheidung: Ich hatte das Portal als "nur
Deutsch" eingestuft wie die Verwaltung. Denkfehler -- die Verwaltung
nutzen Dogfather und VanVan, das PORTAL nutzen Kunden, und die koennen
Franzosen oder Portugiesen sein. Jetzt fuenfsprachig, und die Sprache des
Kunden wird bei der Anmeldung automatisch uebernommen.

Gestaltungsentscheidungen:
* Eine Phasenleiste zeigt auf einen Blick, wo das Projekt steht. Das ist
  die haeufigste Frage ueberhaupt und der Grund, warum Kunden anrufen.
  Bei pausierten oder abgebrochenen Projekten wird KEINE Leiste gezeigt --
  ein Fortschrittsbalken waere dort irrefuehrend.
* Eine Marke sagt, wer gerade am Zug ist ("Wir warten auf dich" /
  "Dogfather ist dran"). Das beendet die haeufigste Unklarheit im
  Projektverlauf.
* Offene Zahlungen stehen ganz oben und in Gold -- das Einzige, was den
  Kunden wirklich zum Handeln auffordert.
* Rueckfrage nur beim ANNEHMEN eines Zusatzangebots, nicht beim Ablehnen.
  Annehmen erzeugt eine Zahlungspflicht, Ablehnen ist folgenlos.
* Abgelaufene Sitzung fuehrt zur Anmeldung mit klarer Ansage statt zu
  einer leeren Seite, die wie "du hast keine Projekte" aussaehe.
* Der Einladungslink wird nach Gebrauch aus der Adresszeile entfernt --
  er ist verbraucht und hat in der Chronik nichts verloren.
* Die Zahlungsknoepfe sagen ehrlich, dass PayPal noch eingerichtet wird,
  statt so zu tun als wuerde etwas passieren.

Pruefskript zweimal geschaerft, beide Male waren es Fehlalarme:
* Die Heuristik fuer Nachschlagetabellen hielt gewoehnliche Woerter wie
  "abnahme" und "uebergeben" fuer Woerterbuch-Schluessel. Jetzt muss ein
  Unterstrich im Namen sein, so wie bei allen echten Schluesseln.
* Eine Ueberschrift gilt jetzt auch als uebersetzt, wenn die Uebersetzung
  INNEN sitzt (fester Teil + dynamischer Teil).

i18n vollstaendig, 45/45 Handy-Abnahme.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 21:17:22 +02:00
DogFatherGitandClaude Opus 5 04a1af1253 Kundenportal: Server-Seite mit strikter Mandantentrennung
Masterplan S.12. Anmeldung, Uebersicht, Projektdetail, Aenderungswuensche,
Zusatzangebote annehmen/ablehnen, Nachrichten, Profil.

DIE ZENTRALE ENTSCHEIDUNG: Die Trennung zwischen Kunden sitzt NICHT in der
Oberflaeche, sondern in jeder einzelnen Abfrage. Ueberall steht
"WHERE id = ? AND kunde_id = ?" statt "WHERE id = ?", wobei die kunde_id
IMMER aus der Sitzung kommt, nie aus der Anfrage. Wer eine fremde
Projektkennung errät, bekommt dadurch "nicht gefunden" statt Daten. Die
Oberflaeche liegt im Browser des Kunden und ist beliebig manipulierbar --
sie kann diese Aufgabe grundsaetzlich nicht uebernehmen.

Weitere bewusste Entscheidungen:
* KEINE Selbstregistrierung. Masterplan S.12 verlangt, dass Projektkauf
  oder Betreuung VOR der Freischaltung geprueft werden. Ein Portal, in das
  sich jeder selbst eintraegt, waere das Gegenteil. Kunden werden in der
  Verwaltung angelegt und bekommen einen Einladungslink.
* Passwoerter mit scrypt (in Node eingebaut, kein Zusatzpaket). Ein
  SHA-256 ueber ein Passwort ist milliardenfach pro Sekunde durchprobierbar;
  scrypt ist absichtlich langsam UND speicherhungrig.
* Mindestanforderung ist LAENGE, nicht Zeichenklassen. "Hund1234!" erfuellt
  jede Klassenregel und ist trotzdem schlecht; "mein blauer stuhl steht
  krumm" erfuellt keine und ist ausgezeichnet.
* Gleiche Fehlermeldung bei unbekannter Adresse und falschem Passwort --
  sonst lassen sich Kundenadressen durchprobieren.
* Die Anmeldesperre haengt an der E-Mail, nicht an der IP. Eine IP-Sperre
  wuerde mehrere Kunden hinter demselben Firmenanschluss gemeinsam
  aussperren -- genau der Fehler, der im Universe am 19.08.2026 auftrat.
* Sperre und Passwortwechsel beenden laufende Sitzungen SOFORT, nicht erst
  nach zwoelf Stunden.
* Ein Zusatzangebot laesst sich nur annehmen, wenn es beziffert ist --
  sonst entstuende eine Zahlungspflicht ohne Preis.

Dazu der wichtigste Test des Bereichs (test-webdesign-portal.mjs): zwei
echte Kunden, und Kunde B versucht systematisch mit Kunde As echten
Kennungen an dessen Projekt, Nachrichten, Dateien und Zusatzangebote zu
kommen. Prueft ausserdem, dass interne Notizen und interne Arbeitsdateien
auch dem BERECHTIGTEN Kunden verborgen bleiben.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 19:12:56 +02:00
DogFatherGitandClaude Opus 5 ae9878cb4c Sprungmarken auf breiten Bildschirmen alle in einer Reihe
Rueckmeldung 22.08.2026: "alle neben einander bitte". Vorher passten vier
in die Zeile und die fuenfte rutschte allein darunter -- das sieht aus wie
ein Versehen, nicht wie eine Gestaltung.

Ab 700px teilen sich jetzt alle fuenf den Platz zu gleichen Teilen
("flex: 1 1 0" statt "auto"). Mit "auto" waere "Preise & Zahlung" schmal
und "Inhalte & Zusammenarbeit" breit gewesen -- ungleiche Kacheln in einer
Reihe, also genau das, was hier schon einmal bemaengelt wurde.
"min-width: 0" ist dabei noetig, weil Flex-Elemente sonst nicht unter ihre
Inhaltsbreite schrumpfen und die Reihe trotzdem umbrechen wuerde.

Nachgemessen bei 700 / 900 / 1280 / 1440px: 5 Knoepfe, 1 Reihe, alle
gleich breit UND gleich hoch. Unter 700px bleibt der Umbruch -- fuenf
Spalten waeren auf einem Handy unlesbar schmal.

45/45 Handy-Abnahme weiterhin sauber.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 19:08:47 +02:00
DogFatherGitandClaude Opus 5 9f74167f84 Sprungmarken brechen um statt zu scrollen, keine Silbentrennung in Ueberschriften
Rueckmeldung 22.08.2026: "ich will nicht dass man die hin und her
schieben muss man soll die alle sehen aber nicht schieben muessen."

Richtig, und aus zwei Gruenden: Eine Wischleiste verbirgt, DASS es noch
mehr gibt -- was rechts aus dem Bild ragt, existiert fuer die meisten
Menschen schlicht nicht. Dazu kam ein haesslicher Scrollbalken quer ueber
die Seite. Jetzt brechen die Knoepfe um, alle fuenf sind auf einen Blick
da, auch bei 320px.

Der Text in den Knoepfen darf dabei mitbrechen (white-space: normal) --
ohne das sprengt ein langer Name wie "Buchhaltungs- &
Steuerverwaltungsseiten" auf schmalen Bildschirmen die Zeile und der
waagerechte Ueberlauf waere durch die Hintertuer zurueck.

Dabei mitgefunden: "hyphens: auto" auf Ueberschriften. Auf dem Handy
stand dadurch "Alles, was vorher ge-klaert sein sollte". Der Browser
trennt damit nach Silben, auch wenn ueberhaupt kein Platzproblem
besteht. In Fliesstext ist das ein Gewinn, in grossen Ueberschriften
sieht es billig aus -- und genau die sind das Erste, was jemand sieht.
overflow-wrap: break-word bleibt und faengt echte Ueberlaeufe weiterhin ab.

Pruefskript: die Sprungmarken-Leisten waren als "absichtlich scrollbar"
von der Ueberlaufpruefung ausgenommen. Diese Ausnahme ist raus -- sonst
wuerde ein zurueckkehrender Ueberlauf dort nie auffallen. 45/45 weiterhin
sauber.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 19:03:30 +02:00
DogFatherGitandClaude Opus 5 de4a90362e Verwaltungsbereich fuer Projektanfragen
Masterplan S.13. Anfragen ansehen, filtern, durchsuchen, Status aendern,
interne Notizen, archivieren. 9/9 Sicherheitstests.

Bewusste Entscheidungen:

* NUR AUF DEUTSCH. Der oeffentliche Teil laeuft in fuenf Sprachen, weil
  dort Kunden landen. Hier landen ausschliesslich Dogfather und VanVan --
  fuenf Sprachen waeren fuenffache Pflege und fuenffache Fehlerflaeche
  ohne einen einzigen Nutzer, der sie braucht. Genau wie der bestehende
  interne Bereich des Universe.

* Anmeldung ueber die BESTEHENDE Team-Anmeldung (/auth/login) statt einer
  zweiten eigenen. Zwei Anmeldungen fuer dieselben zwei Personen waeren
  doppelte Pflege und ein zweiter Ort, an dem ein Zugang vergessen werden
  kann. Der Code der Zugangswand gilt hier ausdruecklich NICHT --
  die Verwaltung steckt hinter zwei getrennten Tueren.

* Sitzungstoken im sessionStorage, nicht localStorage: es verschwindet
  beim Schliessen, dieselbe Regel wie an der Zugangswand. Der Test prueft
  das ausdruecklich.

* Bei abgelaufener Sitzung geht es zurueck zur Anmeldung statt zu einer
  leeren Liste. Eine leere Liste sieht aus wie "keine Anfragen" und ist
  damit eine stille Falschaussage.

* Gold nur beim Status "neu" -- also genau dort, wo wirklich etwas zu tun
  ist. Wuerde alles leuchten, leuchtet nichts.

* Archivieren statt Loeschen, und die Oberflaeche sagt das auch dazu.

Pruefskript: kennt jetzt bewusst einsprachige Seiten (verwaltung, portal)
und prueft dort nur die Struktur, statt ein fehlendes Woerterbuch zu
melden.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:54:58 +02:00
DogFatherGitandClaude Opus 5 eaeaec6b56 Anfrageformular fertig - vier Schritte, Zwischenspeicherung, echte Absendung
Masterplan S.10 "Projektanfrage ohne Informationsverlust" umgesetzt.
End-to-End gegen die echte Datenbank belegt: Anfrage A-2608-0002 liegt drin.
38/38 Browsertests, 45/45 Handy-Abnahme.

Aufbau: 4 Schritte + Zusammenfassung + Dankeseite.
- Zwischenspeicherung nach jedem Tastendruck. Geschlossener Tab, leerer
  Akku oder versehentliches Zurueck kosten keine Arbeit. Entwuerfe
  verfallen nach 30 Tagen -- ein halbes Jahr alter Entwurf verwirrt mehr
  als er hilft.
- Folgefragen erscheinen nur passend zur Auswahl und werden beim
  Zurueckwechseln NICHT mitgeschickt, sonst landen alte Shop-Antworten in
  einer Onepager-Anfrage.
- Die Zusammenfassung wird aus den Feldern gelesen, nicht aus einem
  nebenher gepflegten Objekt -- sie kann dadurch nie etwas anderes
  behaupten als das, was tatsaechlich abgeschickt wird.
- Telefon wird zur Pflicht, sobald "Per Telefon" gewaehlt ist. Ein Wunsch,
  der nicht erfuellbar ist, ist schlimmer als eine Pflichtangabe.

Drei Fehler, die erst der Test gefunden hat:
1. Der "Zurueck"-Knopf stand auch auf Schritt 1 da. Ursache: das
   hidden-Attribut wird nur ueber "display:none" umgesetzt und verliert
   gegen jedes eigene display -- und Knoepfe sind inline-flex. Zentral
   behoben ueber ".wd [hidden] { display:none !important }".
2. Nach erfolgreichem Absenden legte zeigeSeite() den geloeschten Entwurf
   sofort wieder an. Beim naechsten Besuch haette eine bereits gesendete
   Anfrage erneut im Formular gestanden.
3. Der Server meldet bei Spamverdacht bewusst Erfolg ohne Nummer. Ein
   echter Mensch, der zufaellig sehr schnell war, haette eine Dankeseite
   mit "—" gesehen und auf eine Antwort gewartet, die nie kommt. Jetzt
   ein ehrlicher Hinweis mit zweitem Weg, und der Entwurf bleibt erhalten.

Pruefskripte geschaerft:
- i18n-Pruefung liest jetzt auch assets/js/wd-<seite>.js, sonst meldet sie
  reihenweise "unbenutzt" fuer Schluessel, die aus dem Seitenskript kommen.
- Handy-Abnahme ueberspringt absichtlich unsichtbare Eingabefelder
  (Auswahlkacheln, Honigtopf). Fehlalarme sind das Ende jeder Pruefung,
  weil man sie irgendwann pauschal ignoriert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:47:45 +02:00
DogFatherGitandClaude Opus 5 8ace955740 Service Worker lieferte alte Stilvorlagen aus - Korrekturen blieben unsichtbar
Gemeldet 22.08.2026 mit Bildschirmfoto: "immer noch so" -- das Logo im
Marken-Intro stand weiterhin hochkant gestreckt da, obwohl die Korrektur
(height:auto gegen die height-Attribute) laengst live war.

Ursache war NICHT die Korrektur, sondern mein eigener Service Worker. Er
lief fuer /assets/ als "stale-while-revalidate": die gespeicherte Fassung
geht sofort raus, im Hintergrund wird eine frische geholt. Das ist schnell
-- bedeutet aber, dass jede Aenderung an CSS oder JavaScript beim ersten
Aufruf unsichtbar bleibt und erst beim zweiten wirkt. Ein behobener Fehler
sieht dadurch aus wie ein nicht behobener. Die unangenehmste Sorte.

Nachgemessen ist das Logo jetzt 160x161px bei einem natuerlichen
Verhaeltnis von 472x476 -- also unverzerrt. Vorher erzwang das Attribut
height="476" bei 160px Breite ein Verhaeltnis von 0,34 statt 0,99, genau
das lange Gesicht auf dem Bildschirmfoto.

Behoben:
- Stilvorlagen und Skripte laufen jetzt "Netz zuerst", Zwischenspeicher
  nur als Notfallnetz. Richtigkeit vor Millisekunden.
- Bilder und Symbole bleiben beim schnellen Weg -- die aendern sich
  praktisch nie und bekaemen sonst einen neuen Dateinamen.
- CACHE_NAME auf v2 gesetzt, damit der alte Speicher beim naechsten Start
  vollstaendig weggeworfen wird.
- Versionsnummer an allen CSS/JS-Verweisen hochgesetzt, damit es sich auch
  ohne Service Worker sofort selbst heilt.

Ausserdem: Woerterbuch fuer das Anfrageformular, 101 Textbausteine in fuenf
Sprachen (vier Schritte, Zusammenfassung, Fehlermeldungen).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:34:15 +02:00
DogFatherGitandClaude Opus 5 29a054c359 Bilder waren hochkant gestreckt und ungleich hoch, Abstaende halbiert
Rueckmeldung 22.08.2026 per Bildschirmfoto: "die sollen alle gleich
aussehen und nicht einer groesser oder kleiner" und "ich will nicht soooo
viel abstand".

1) Verzerrte, ungleich hohe Projektbilder
   Nachgemessen: 576px breit, aber 750px bzw. 696px hoch -- also hochkant
   gestreckt und unterschiedlich, obwohl im CSS sauber "aspect-ratio:
   16/10" stand. Ursache: die width/height-Attribute im HTML (die dort
   bewusst stehen, damit der Browser vor dem Laden den Platz reserviert
   und die Seite nicht springt) wirken wie eine CSS-Hoehe und schlagen
   aspect-ratio. Fix zentral ueber ".wd img[width][height] { height:
   auto }" statt in jeder einzelnen Regel -- so kann es bei einem neuen
   Bild nicht vergessen werden.
   Jetzt beide 576x360, Karten beide 853px hoch.

2) Zu viel Leerraum
   .wd-abschnitt hatte 100,8px oben UND unten, also gut 200px zwischen
   zwei Abschnitten. Halbiert auf 57,6px, Hero von 78svh auf 68svh.
   Seitenlaenge dadurch 8798px -> 7089px bei gleichem Inhalt.

3) Zwei neue Dauerpruefungen in pruefe-webdesign-handy.mjs, damit genau
   diese beiden Fehlerarten nicht wieder per Bildschirmfoto auffallen
   muessen:
   - verzerrte Bilder (gewuenschtes vs. tatsaechlich gerendertes
     Seitenverhaeltnis, 2 % Toleranz)
   - ungleich hohe Karten innerhalb EINER Rasterzeile

40/40 Abnahme weiterhin sauber.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:26:07 +02:00
DogFatherGitandClaude Opus 5 356bb974b8 Knopf war unlesbar, und der Code wird jetzt bei jedem Schliessen neu verlangt
Zwei Rueckmeldungen vom 22.08.2026, beide behoben und mit Tests abgesichert.

1) "das sieht nicht gut aus" (Bildschirmfoto des Hauptknopfs)
   Ursache: ".wd a" ist Klasse+Element und damit spezifischer als die reine
   Knopfklasse ".wd-btn--haupt". Die Textfarbe des Knopfs wurde dadurch
   ueberstimmt -- hellblaue Schrift auf hellblauem Grund, praktisch
   unlesbar. Derselbe Spezifitaetsfehler wie zuvor bei den Namen auf der
   Zugangswand. Fix: ".wd a:not(.wd-btn)" plus zweistufig geschriebene
   Knopfregeln, damit das nicht wieder passieren kann.

2) "das sieht lang gezogen aus"
   Die Pillenform (border-radius 999px) laesst breite Knoepfe
   auseinandergezogen wirken, weil der Radius optisch mit der Breite
   mitwaechst. Jetzt fester Radius von 14px -- gleiche Form bei jeder
   Breite, ruhiger und hochwertiger.

3) "ich will das ich jedes mal den code gefragt werde wenn man die seite
   zu macht"
   Das Sitzungs-Cookie allein reicht dafuer nicht: Browser stellen genau
   solche Cookies beim Wiederherstellen von Tabs zurueck ("Dort
   fortfahren, wo du aufgehoert hast"), man landet dann ohne Codeabfrage
   wieder mitten in der Seite. Zusaetzlich jetzt eine Sitzungsmarke im
   sessionStorage, die beim echten Schliessen verschwindet. Fehlt sie bei
   vorhandenem Cookie, wird die Sitzung serverseitig beendet und zur
   Zugangswand geleitet. Token-Notbremse von 24 auf 8 Stunden gesenkt.
   13/13 Tests im echten Browser, inklusive Schutz vor Endlosschleife.

DEPLOY.md: zwei Checkouts auf dem Server dokumentiert (/home/dogiweb und
/home/dogiintern) und der Vorfall, dass /webdesign nach dem Pull kurz ohne
Zugangsschutz erreichbar war, weil der Dienstneustart fehlte.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:20:34 +02:00
DogFatherGitandClaude Opus 5 4b3ec450d5 Webdesign-Bereich: Fundament, oeffentliche Seiten, Zugangsschutz, PayPal
Umsetzung des "Website Masterplan" (16 Seiten) unter /webdesign.

Zugangsschutz mit EIGENER Schranke (server/webdesign-gate.js) statt gate.js:
gate.js laesst seit dem oeffentlichen Start am 21.08.2026 jeden durch, weil
die Pruefung auf SITE_PUBLIC_LAUNCH_AT als allererste Zeile steht. Haette man
/webdesign dahintergehaengt, waere der ausdruecklich nicht-oeffentliche Bereich
inklusive Preisen und spaeteren Kundendaten ab der ersten Sekunde fuer jeden
lesbar gewesen. Eigenes Sitzungs-Cookie, bereich="webdesign" im Token, damit
ein gueltiges Universe-Cookie hier NICHT gilt. 37/37 Tests.

Sieben oeffentliche Seiten in fuenf Sprachen (de, de-CH mit echtem Dialekt, en,
fr, pt). Preise, Zeitrahmen, Paketnamen und die 30-%-Regel stehen an genau
EINER Stelle in wd-core.js -- der Masterplan verlangt "ueberall
widerspruchsfrei", und vier Kopien laufen bei der ersten Preisaenderung
auseinander.

Als App installierbar auf Handy und PC. Der Service Worker speichert bewusst
KEINE HTML-Seite zwischen: nach dem Abmelden wuerden sonst geschuetzte Seiten
weiter ausgeliefert, ohne dass der Server je gefragt wird. 18/18 Tests.

Handy-Abnahme ueber alle Seiten in fuenf Breiten (320-1440) und fuenf Sprachen:
40/40. Der Test fand 35 echte Fehler (Touch-Ziele unter 44px), behoben im
Designsystem statt einzeln pro Seite.

PayPal (Wunsch 22.08.2026 "sofort auf meinem paypal"): Orders API mit
intent=CAPTURE, also sofortiger Einzug statt blosser Reservierung. Gebuehr und
Nettobetrag getrennt gespeichert. Betraege durchgehend als Ganzzahl in Cent.
Gefaelschte Webhooks werden abgewiesen. Fail closed solange Zugangsdaten
fehlen. 28/28 Tests gegen einen nachgebauten PayPal-Server.

Datenbank: 15 Tabellen mit Praefix wd_, fachlich vollstaendig vom Universe
getrennt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 18:06:52 +02:00
DogFatherGitandClaude Opus 5 2010b5ec33 Live benutzte Hintergrundbilder + Stimmen-Avatare in die Ablage aufgenommen
Beim Abgleich zwischen Rechner und Netcup-Server am 22.08.2026 aufgefallen:
20 Bilddateien wurden live von mehreren Seiten benutzt (bewerben-modi.html,
links.html, medien-casper.html, medien-hasidog.html, supporter.html,
stimmen.html u.a.), lagen aber in keiner Git-Ablage -- nur auf diesem
Rechner und auf dem Server. Waeren beide verloren gegangen, waeren diese
Seiten ohne Hintergrund/Avatare dagestanden.

Vor dem Hinzufuegen jede Datei per Pruefsumme gegen den Server abgeglichen
-- alle identisch, kein abweichender Stand wird hier verdeckt.

dogfather-universe-app.ico ist aktuell nirgends verlinkt (vermutlich ein
nie eingebauter Favicon-Entwurf), trotzdem mit gesichert statt verworfen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 15:47:38 +02:00
DogFatherGitandClaude Opus 5 541a91d9e2 DEPLOY.md korrigiert: echte Seite laeuft auf Netcup, nicht auf Cloudflare
Die Anleitung nannte als Deploy-Weg weiterhin "npx wrangler deploy". Das ist
seit dem oeffentlichen Start (21.08.2026) falsch und aktiv gefaehrlich: der
Befehl laeuft fehlerfrei durch und meldet Erfolg, erreicht aber nur noch
...workers.dev. Die echte Domain wird von Caddy auf dem Netcup-Server
ausgeliefert (dogiweb.service, localhost:4100). Genau darauf bin ich heute
beim Sprachfenster-Fix hereingefallen -- Deploy "erfolgreich", auf dem Handy
aber unveraendert kaputt.

Neu dokumentiert: der einzige gueltige Weg (commit -> push gitea master:main
-> git pull auf dem Server), die Zweig-Falle master/main, die Pflichtpruefung
gegen die echte Domain statt gegen die Deploy-Meldung, warum die
wrangler-Fehlermeldung "externally managed DNS records" erwuenscht ist, und
als offener Punkt: mehrere live benutzte Hintergrundbilder liegen in keiner
Git-Ablage.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 15:27:08 +02:00
DogFatherGitandClaude Opus 5 e5d55137d4 Zwei Server-Reparaturen zurueckgeholt, die es nur auf dem Server gab
Beim Abgleich der beiden Staende (Rechner vs. Netcup-Server) gefunden --
beide Aenderungen liefen bereits live, waren aber nirgends gespeichert und
haetten beim naechsten Deploy vom Rechner aus verloren gehen koennen:

1. gate.html: autofocus im Dogi-Feld entfernt (21.08.2026, Rueckmeldung von
   Diene -- der Cursor sprang nach dem Laden zurueck nach oben, die eigene
   Kachel scrollte dabei aus dem Bild).
2. verwaltung.html: "Oeffnen"-Knoepfe wurden auf dem Handy vom
   overflow:hidden der Karte abgeschnitten (22.08.2026); jetzt
   overflow:visible plus etwas mehr Unterabstand.

Inhalt unveraendert vom Server uebernommen, nur hier nachgetragen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 15:24:35 +02:00
DogFatherGitandClaude Opus 5 3f9997456a Handy: Sprachfenster (DE) klappte halb aus dem Bild auf
Nutzer-Report per Foto: beim Tippen auf "DE" im Handy-Menue erschien das
Sprachfenster halb links ausserhalb des Bildschirms, man konnte keine
Sprache mehr lesen oder treffen.

Ursache: Die Handy-Regel, die alle Aufklapp-Fenster auf statische Position
und volle Breite umstellt, hat den Sprachschalter nicht erreicht -- seine
Desktop-Regel (.sprach-schalter .nav-dropdown, 0-2-0) ist spezifischer,
und eine @media-Abfrage erhoeht die Spezifitaet nicht. Dadurch lief die
Desktop-Animation "sprach-dropdown-in" weiter, die per fill-mode:both
dauerhaft transform: translateX(-50%) setzt. Auf dem Desktop korrekt
(schmales Fenster mittig unter dem Knopf), im Handy-Menue aber toedlich:
das Fenster ist dort bildschirmbreit und wurde um seine halbe Breite nach
links geschoben (gemessen live: x = -148px bei 390px Viewport).

Fix: dieselben Handy-Regeln erneut mit ausreichender Spezifitaet fuer den
Sprachschalter, samt Kommentar zur Begruendung.

Geprueft mit Playwright (echter Browser): 390x844, 360x640, Querformat
844x390 und Tablet 768x1024 -> Fenster jeweils vollstaendig im Bild, alle
5 Sprachen sichtbar; Desktop 1920 unveraendert schmal und zentriert;
Sprachwechsel (English) funktioniert weiterhin.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-22 11:27:22 +02:00
DogFatherGitandClaude Sonnet 5 adb1042915 Namenskorrektur Cigdem (statt Cidgem) auch lokal + in allen 5 Sprachen nachgezogen
War beim Server-Deploy schon als Konflikt aufgefallen (Diene/das Team hatte
die richtige Schreibweise bereits korrigiert) -- hier fehlte die Korrektur
noch in i18n-zeitreise.js (alle 5 Sprachen) sowie in der HTML-Fallback-
Version, weil mein ursprünglicher Fix von heute Nachmittag ("Cidem" ->
"Cidgem") selbst schon falsch war.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 23:39:29 +02:00
DogFatherGitandClaude Sonnet 5 1f0ec994a9 Drei Handy-Nachbesserungen: Trio-Bild hinter dem Text, auffälliger Menü-Knopf, abgeschnittener Öffnen-Knopf
Nutzer-Report mit drei Bildern vom Handy:

1. HERO-BILD SASS NICHT MEHR HINTER DEM TEXT (index.html)
   .hero-artwork hat "inset:0" -- füllt also die GESAMTE Höhe von
   .hero-cinematic, und diese Sektion umschließt nicht nur die Überschrift,
   sondern auch die 3 Welt-Kacheln darunter. Auf dem Handy wird die Sektion
   durch den 4-zeilig umbrechenden Titel + Kacheln riesig (~1570px bei
   390px Breite) -- das Trio-Bild (16:9, contain-skaliert an die Breite)
   wurde dadurch nur ~220px hoch und mittig in dieser riesigen Fläche
   zentriert, landete also als schmaler Streifen zwischen den Buttons und
   den Welt-Kacheln statt hinter der Überschrift.
   Fix: eigenes festes Seitenverhältnis (4:3) für die Bildbox auf dem
   Handy, von OBEN verankert statt zentriert, background-size auf "cover"
   -- Verlauf eigens für die neue, kürzere Box abgestimmt (die
   Desktop-Version wäre zu abrupt gewesen). Über 6 Breiten (320-768px)
   mit Playwright gegengeprüft.

2. MENÜ-KNOPF ZU UNAUFFÄLLIG (main.js + main.css, alle Seiten)
   "da soll auch menü stehen und die 3 striche" + "die kiste soll auch
   leicht eine andere farbe haben so dass sie auffällt, eine leicht blau
   tönung". Sichtbares "Menü" neben den drei Strichen ergänzt (neuer i18n-
   Schlüssel nav_toggle_label, alle 5 Sprachen) + dezente Babyblau-Tönung
   (8% Deckkraft, passend zur Markenfarbe --accent). Dabei einen
   unabhängigen, zweiten Bug gefunden und mitbehoben: durch die neue
   Knopfbreite/-höhe wurde ein Rechenfehler im geschlossenen Mobilmenü
   sichtbar -- "translateY(-110%)" reicht nur, wenn das Panel mindestens
   10x so hoch ist wie der Kopfbereich; war das nicht der Fall, ragte die
   Unterkante (der Sprachschalter) ein paar Pixel sichtbar ins Bild.
   Robusterer Ersatz: -100% + fester 200px-Puffer, unabhängig von Panel-
   und Kopfbereichshöhe. Über 3 Breiten gegengeprüft (Panel unsichtbar UND
   öffnet weiterhin normal).

3. "ÖFFNEN"-KNOPF AUF DER ZUGANGSSEITE ABGESCHNITTEN (gate.html)
   .gate-card trägt "flex: 1 1 220px" für die Desktop-Reihe (220px als
   BREITE gedacht). Sobald @media max-width:480px auf flex-direction:column
   umschaltet, gilt dieselbe Zahl als HÖHE -- die Karte wurde auf genau
   220px Höhe gequetscht. overflow:hidden setzt zusätzlich das normale
   Mindestmaß (min-height:auto) auf 0 herunter, wodurch nichts das
   Zusammenquetschen verhinderte -- der "Öffnen"-Knopf wurde unten
   abgeschnitten. Fix: flex:none in genau diesem Media-Block, Breite bleibt
   weiterhin über width:100%/max-width geregelt. An 4 Breiten x 3 Kacheln
   (Dogi/VanVan/Diene) gegengeprüft: Karten jetzt 258px statt 220px hoch,
   Knopf komplett sichtbar.

Vollständiger Regressionslauf: alle 34 Seiten bei 390px (kein Überlauf,
Menü-Knopf überall erreichbar und beschriftet), Desktop bei 1920px
unverändert (Hamburger weiterhin nur unter der bestehenden 1650px-
Schwelle sichtbar).

Cache-Busting-Version auf 20260821t erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 23:37:14 +02:00
DogFatherGitandClaude Sonnet 5 57966e24d0 Automatischer öffentlicher Start um 21 Uhr + Countdown auf der Zugangsseite
Nutzer-Wunsch 21.08.2026: "ich will dass du auch ein countdown zu der
seite hinzufügst wo wir den zugangscode eingeben müssen. den um 21h heute
abend geht die seite live. kannst du das sogar so anpassen dass es
automatisch läuft?"

server/gate.js:
- Neue Einstellung SITE_PUBLIC_LAUNCH_AT (ISO-Zeitstempel mit Zeitzone).
  Ab diesem Moment lässt gateMiddleware ausnahmslos jeden durch -- ganz
  ohne Neustart oder manuellen Eingriff, weil jede Anfrage die aktuelle
  Serverzeit live neu prüft. Die Freischaltung "passiert" also von selbst
  in der Sekunde, in der die Uhrzeit erreicht wird. Vorher bleiben die
  Zugangscodes unverändert nötig, damit das Team schon vorher rein kann.
  Fail-safe statt fail-open geprüft: ein kaputter/unparsbarer Zeitwert
  (z.B. Tippfehler in der .env) lässt die Schranke aktiv, statt die Seite
  versehentlich für alle zu öffnen.
- Neuer öffentlicher Endpunkt GET /gate-launch-info (immer erreichbar,
  auch ohne gültige Sitzung) liefert launchAt/isLive/serverTime für die
  Countdown-Anzeige im Frontend.

gate.html:
- Neue Countdown-Box zwischen Titel-Karte und den Zugangscode-Kacheln
  (bleibt unsichtbar, solange kein Starttermin konfiguriert ist). Rechnet
  auf der SERVERZEIT statt der eigenen Uhr (einmaliger Zeit-Abgleich beim
  Laden), damit eine falsch gehende Besucher-Uhr weder zu früh noch zu
  spät zählt. Bei Erreichen von Null folgt ein letzter Abgleich mit dem
  Server, bevor automatisch zur Zielseite weitergeleitet wird -- kein
  Klick, kein Neuladen nötig.
- Zugangscode-Kacheln (Dogi/VanVan/Diene) bleiben während des Countdowns
  unverändert nutzbar.

Getestet: 18 Middleware-Tests (inkl. Fail-safe bei kaputtem Zeitwert,
weiterhin funktionierender Zugangscode vor dem Start) + 10 Playwright-
Tests der Countdown-Oberfläche (Anzeige, Format, automatischer Sprung bei
Ablauf, sofortige Weiterleitung falls schon live, stiller Fallback bei
Netzwerkfehler). Zusätzlich alle 32 echten Seiten auf PC-Installierbarkeit
geprüft (Manifest, Icons, Service Worker, Install-Knopf, echter
Install-Klick-Ablauf simuliert) -- keine Probleme gefunden.

Cache-Busting-Version auf 20260821s erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 19:25:12 +02:00
DogFatherGitandClaude Opus 5 41faf22614 Handy: vollständige Prüfung von Inhalten, Knöpfen und allen Systemen
Nachtrag auf Nachfrage ("hast du alles geprüft oder nur die menü
leisten?") -- vorher hatte ich nur Navigation, Seitenbreite, Tippflächen
und Hoch/Querformat geprüft. Jetzt zusätzlich Bilder, Texte, Knöpfe und
die kompletten Abläufe.

Geprüft über alle 35 Seiten bei 393px:
- Bilder: kein einziges kaputtes Bild, keine fehlenden alt-Texte
- Dateien: keine 404er
- Knöpfe/Links: alle beschriftet (keine namenlosen Bedienelemente)
- Text: nichts wird abgeschnitten. Die zunächst gemeldeten "Überläufe"
  bei .btn/.card waren Fehlalarme -- sie stammen von den dekorativen
  Leucht-Ebenen (::before mit negativem inset), echter Text ragt
  nirgends heraus (einzeln gegengeprüft).

Zwei echte Funde behoben:
1. Marken-Unterzeile war mit 8,96px zu klein zum Lesen (hatte ich beim
   Handy-Fix selbst so verkleinert). Jetzt 11px -- Platz ist da, seit der
   Menü-Knopf eigenständig rechts sitzt. Über acht Breiten gegengeprüft,
   Kopfleiste bleibt überall stabil.
2. "Aktiv"-Ankreuzfelder in der Verwaltung waren 22px. Jetzt 26px, die
   ganze Beschriftungszeile ist 44px hoch und schaltet mit um.

Abläufe am Handy durchgespielt (echte Fingertipps, Fake-Backend):
- Registrierung über alle drei Schritte inkl. falschem Code
- Login mit falschem und richtigem Zugangscode
- Abmelden auf supporter.html
- Stimme einreichen inkl. Profilbild-Auswahl
- Verwaltung: Team-Mitglied anlegen, Stimme freigeben, alle Bereiche
  sichtbar, kein Überlauf

Cache-Busting-Version auf 20260821r erhöht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 18:33:52 +02:00
DogFatherGitandClaude Opus 5 6910112d97 Stimmen: nur noch die zwei Originalfiguren + eigenes Bild hochladen
Nutzer-Wunsch 21.08.2026: "benutz da bitte nur die originalen husky und
hasen. mach nur die zwei. und die auswahl wo die leute selbst ein bild
rein setzen können."

- Auswahl von acht auf zwei reduziert (DogFather-Husky, HasiDog). Die
  übrigen Bilddateien bleiben liegen, falls sie je zurücksollen -- es
  genügt, die Zeile in data-stimmen-avatare.js und die Id in
  ERLAUBTE_AVATARE wieder zu ergänzen.
- Neue Kachel "eigenes Bild" (gestrichelter Rand + Plus), die den
  Dateidialog öffnet, das Bild sofort hochlädt und als Vorschau in der
  Kachel zeigt.

Bereits freigegebene Stimmen mit einer der entfernten Figuren zeigen
wieder den Anfangsbuchstaben statt eines kaputten Bildes -- die
Auflösung unbekannter Ids liefert null, das war schon so vorgesehen.

Sicherheit des öffentlichen Uploads (bisher war Hochladen bewusst nur
der Verwaltung erlaubt):
- Gleiche multer-Härtung wie der Verwaltungs-Upload: nur JPG/PNG/WebP,
  max. 5 MB, zufälliger UUID-Dateiname (kein Originalname).
- Der Server nimmt im Avatar-Feld weiterhin NUR bekannte Ids an oder
  eine Adresse, die exakt auf den eigenen Upload-Ordner zeigt und danach
  nur aus UUID + Bildendung besteht. Gegengetestet: fremde Domains,
  "../"-Ausbruch, .svg/.html, javascript:, angehängte Skripte und http
  statt https werden alle abgelehnt.
- Missbrauchsbremse gegen Vollschreiben der Festplatte: max. 10 Uploads
  pro Stunde und IP.
- Sichtbar wird ein Bild ohnehin erst, wenn die Stimme freigegeben wird.

Mit Playwright end-to-end geprüft (10 Tests) plus 9 Sicherheitsfälle.

Cache-Busting-Version auf 20260821q erhöht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 18:23:17 +02:00
DogFatherGitandClaude Opus 5 e2bd436084 Arbeit der parallelen Session gesichert (Profilbilder für Stimmen, Diene-Zugang)
Wie beim vorherigen Mal lag das nur als Arbeitskopie auf dem Server, nicht
in git. Unverändert übernommen, bevor darauf aufgebaut wird:
- Profilbild-Auswahl für die Stimmen (data-stimmen-avatare.js neu,
  stimmen.js, i18n-stimmen.js, stimmen.html, verwaltung.html, main.css)
- Dritte Zugangs-Kachel für Diene (gate.html, server/gate.js)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 18:17:47 +02:00
DogFatherGitandClaude Opus 5 d0613f86c1 Handy: Navigation war komplett unerreichbar — behoben, plus Tippflächen überall
Nutzer-Report 21.08.2026 mit Screenshot: "auf dem handy kann ich oben
nicht aussehen in welche seite ich will welche kategorie welche sprache
garnichts". Drei echte, per Playwright reproduzierte Fehler:

1. MENÜ-KNOPF AUSSERHALB DES BILDSCHIRMS (Hauptproblem)
   .brand stand auf flex-shrink:0, war bei 390px aber 352px breit. Mit
   Abstand + Knopf brauchte die Leiste 423px bei 367px Platz -- der
   Menü-Knopf landete bei x=396px, also komplett außerhalb. Damit war auf
   dem Handy die GESAMTE Navigation unerreichbar (keine Seiten, keine
   Kategorien, kein Sprachwechsel).
   Fix: Knopf per margin-left:auto immer an die rechte Kante; Marke darf
   unter 620px schrumpfen (inkl. min-width:0, sonst greift flex-shrink
   nicht); unter 400px entfällt die reine Deko-Unterzeile.

2. MENÜ IM QUERFORMAT NICHT ZU ÖFFNEN
   Das zugeklappte Panel wird um -110% SEINER EIGENEN Höhe verschoben. Quer
   (568x320) ist es nur 258px hoch, die Unterkante lag dadurch bei y=36px --
   also unsichtbar genau über dem Menü-Knopf (y=11..55) und hat jede
   Berührung abgefangen. Fix: pointer-events:none im geschlossenen Zustand.

3. MENÜPUNKTE AUF KURZEN BILDSCHIRMEN ZUSAMMENGEQUETSCHT
   .nav-links ist ein Flex-Container fester Höhe; passte der Inhalt nicht,
   schrumpfte Flexbox die Einträge (iPhone SE: 59px -> 29px, Knöpfe 21px).
   Fix: flex-shrink:0 auf die Kinder, der Bereich scrollt stattdessen
   (overflow-y:auto war bereits gesetzt).

Zusätzlich: Fußzeilen- und Impressum/AGB-Links auf Handys als echte
Tippziele (44px statt 17-20px) -- 18 dicht stehende Links, mit dem Finger
vorher kaum zu treffen. Menü-Trennlinien begradigt (folgten dem
Desktop-Pillenradius und sahen aus wie Schüsseln).

Ergebnis: alle 31 Seiten ohne Überlauf, Menü auf 320-768px, hoch UND quer
nutzbar, kleinster Menüpunkt 46px. Verbleibende kleine Ziele sind reine
Fließtext-Links im Satz (dürfen laut Standard klein bleiben).
Desktop per Regressionstest unverändert geprüft.

Cache-Busting-Version auf 20260821p erhöht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 18:13:03 +02:00
DogFatherGitandClaude Opus 5 5a5912636d Registrierung: E-Mail-Bestätigung per Einmalcode vor dem Zugangscode
Nutzer-Wunsch 21.08.2026: "bei der ersten registrierung sollen die eine
email bekommen mit einem einmaligen code damit wir auch wissen dass
email stimmt und danach wenn sie den code eingegeben haben sollen die
erst ihren zugangscode auswählen/eintippen können."

Damit wird eine echte Lücke geschlossen: registerSupporter() hat bisher
`email_verified = 1` gesetzt, OHNE dass irgendetwas geprüft wurde -- man
konnte sich mit einer fremden oder erfundenen Adresse registrieren und
kam sofort rein.

Neuer Ablauf in drei Schritten:
1. Name/TikTok/E-Mail -> Konto wird als UNBESTÄTIGT angelegt
   (email_verified = 0, noch kein Zugangscode). Es kommt bewusst KEIN
   Session-Token zurück -- eingeloggt ist man hier noch nicht.
2. Einmalcode aus der E-Mail eingeben -> verify-email bestätigt und
   loggt ein. Die Willkommens-Mail wandert hierher, sie ging vorher an
   eine noch ungeprüfte Adresse.
3. Erst jetzt den eigenen Zugangscode festlegen.

Serverseitig abgesichert: setSupporterAccessCode() lehnt ab, solange die
E-Mail nicht bestätigt ist -- der Schritt ist damit nicht nur im
Formular versteckt, sondern auch per Direktaufruf nicht überspringbar.

Wiederverwendet wird die bereits vorhandene Mechanik (issueAuthCode/
verifyAuthCode mit Zweck "verify_email", sendVerifyEmailCode, die Panels
#panel-code und #panel-neuer-code) -- der "Code vergessen?"-Weg nutzt
dieselbe Code-Eingabe und bleibt unverändert; eine neue Variable
codeZweck unterscheidet, welcher Endpunkt aufgerufen wird.

Mit Playwright end-to-end geprüft (14 Tests): Reihenfolge der Aufrufe,
kein Token vor der Bestätigung, falscher Code kommt nicht weiter,
Zugangscode-Feld erst im letzten Schritt, "Code vergessen?" unberührt.

Cache-Busting-Version auf 20260821o erhöht.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 17:48:08 +02:00
DogFatherGitandClaude Opus 5 5d0ea11570 Arbeit der parallelen Session in git gesichert (war nur auf dem Server)
Diese Änderungen liefen bereits live auf dem Server, lagen dort aber
ausschließlich als nicht eingecheckte Arbeitskopie — bei jedem Deploy
(stash/pull/pop) und bei jedem Serverproblem wären sie verloren gewesen.
Deshalb hier unverändert in git übernommen, bevor darauf aufgebaut wird.

Enthalten (nicht von mir gebaut, nur gesichert):
- Supporter: eigener fester Zugangscode statt Einmalcode-Login
  (Migration 0009, lib/crypto.js scrypt-Hash, routes/supporter.js,
  abonnieren.html, supporter.html, i18n-abonnieren/-supporter)
- Stimmen: Profilbilder (Migration 0010, routes/testimonials.js)
- Event-Bild-Upload: voller Pfad statt relativem (routes/events.js)
- Neue/überarbeitete Hintergrundbilder für viele Seiten
- Teilen-Funktion (streamplan.js, i18n-index/-streamplan, main.css)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 17:35:14 +02:00
DogFatherGitandClaude Sonnet 5 4b294f6c6b Startseite: die vier Personen-Kacheln unter "Team Dogi" entfernt
Nutzer-Wunsch 21.08.2026: "die 4 kacheln da sollen da weg bitte."
Überschrift, Beschreibungstext und der Knopf zum Modi-Team bleiben --
dadurch kommt das "Team Dogi"-Hintergrundbild dieser Sektion jetzt
unverdeckt zur Geltung. Der zugehörige Render-Code ist ebenfalls raus;
data-modis.js/data-scouts.js bleiben eingebunden, weil die
Statistik-Zeile weiter oben sie weiterhin auszählt (geprüft: zeigt
weiterhin korrekt "8+"). Die Profile selbst gibt es unverändert
vollständig auf team-modis.html.

Cache-Busting-Version auf 20260821n erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 16:53:56 +02:00
DogFatherGitandClaude Sonnet 5 d0f3edb079 bewerben.html: Überschrift-Umbruch verbessert (kein einsames letztes Wort mehr)
Nutzer-Wunsch 21.08.2026: "Weg" stand auf manchen Bildschirmbreiten
allein in einer eigenen Zeile, sah unruhig aus. Non-breaking-Space
zwischen den letzten zwei Wörtern in allen 5 Sprachen -- bricht die
Zeile jetzt nie mehr genau zwischen ihnen um.

Cache-Busting-Version auf 20260821m erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 16:51:00 +02:00
DogFatherGitandClaude Sonnet 5 76f70ffcf2 Zeitreise: Namen "Cidem" zu "Cidgem" korrigiert (Creator Cup)
Nutzer-Wunsch 21.08.2026: Tippfehler beim Namen des Kooperationspartners
beim Creator Cup korrigiert, in allen 5 Sprachen plus dem
HTML-Fallbacktext.

Cache-Busting-Version auf 20260821l erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 12:58:29 +02:00
DogFatherGitandClaude Sonnet 5 971c5ea3f6 Bugfix: Team-Foto-Upload lieferte relativen statt vollen Pfad zurück
Gleicher Fehler wie in routes/events.js/uploadEventImage (dort gerade
direkt auf dem Server gefunden und gefixt, siehe git stash auf
dogiintern): die Verwaltung und die echte Website laufen auf
dogfather-universe.com (dogiweb), hochgeladene Fotos liegen aber unter
postfach.dogfather-universe.com (dogiintern). Ein relativer Pfad wurde
vom Browser also gegen die falsche Domain aufgelöst -> kaputtes
Bild-Symbol für jedes über die Team-Verwaltung hochgeladene Foto.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 04:37:04 +02:00
DogFatherGitandClaude Sonnet 5 81f55d67db Team-Verwaltung Runde 2: bestehende Mitglieder importieren + Kategorien/Seitentitel editierbar
Nutzer-Wunsch 21.08.2026: "wenn ich eine änderung mache ist es auch für
jeden für die die schon da sind und die neuen" + "ich will ich titel
und namen von kategorien und seiten ändern können in der verwaltung".

Backend (braucht Filipes manuellen Deploy):
- Migration 0008: team_members bekommt intro/bioHtml/extraCta-Spalten
  -- volle Feld-Parität mit den von Hand gepflegten Profilen (Diene/
  Patrick/Bananenstift/Marina nutzen diese Felder).
- routes/team.js: neue importLegacyMember()-Funktion -- übernimmt ein
  bestehendes Profil 1:1 in die Datenbank, OHNE erneut zu übersetzen
  (die vorhandenen, von Hand geschriebenen Übersetzungen bleiben
  erhalten). Idempotent: mehrfacher Import erzeugt keine Duplikate.
- routes/site-texts.js (neu): admin-editierbare Kategorie-Namen und
  Seitentitel, generischer key->{de,...}-Override über app_settings
  (wie "Event des Jahres"), fester Schlüssel-Katalog aus
  Sicherheitsgründen. Leeres Feld setzt auf den Standardtext zurück.
- 27 Tests in isolierter Testumgebung geprüft (kein better-sqlite3
  lokal kompilierbar).

Frontend:
- window.dogiTeamZusammenfuehren() (main.js): admin-Mitglieder
  ÜBERSCHREIBEN jetzt gleichnamige statische Einträge (per slug) statt
  sie zu duplizieren -- eine Bearbeitung wirkt dadurch für alle.
- window.dogiSiteTexteLaden() + applyTranslations() erweitert um
  data-site-text-key -- Kategorie-Seitentitel (team-modis.html/
  team-scouts.html/creator.html/manager.html) sind jetzt live editierbar.
- Verwaltung: "📥 Bestehende Mitglieder importieren"-Knopf (holt VanVan/
  Diene/Funny/Miss/Marina/Ghost/Patrick/Bananenstift aus den data-*.js-
  Dateien, VanVan bewusst ausgenommen -- eigene Sonderkarte + Seite),
  erweitertes Formular (Intro/ausführliche Vorstellung/zweiter Button,
  eingeklappt unter "Erweitert"), neue Sektion "Kategorien &
  Seitentitel" (4 Karten, sofort wirksam auf Website UND Verwaltung).

Beim Testen einen echten UX-Bug gefunden und gefixt: die "Gespeichert"-
Meldung nach dem Speichern eines Mitglieds wurde von der direkt
anschließenden Formular-Zurücksetzung sofort wieder überschrieben und
war nie sichtbar.

Cache-Busting-Version auf 20260821k erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 03:47:51 +02:00
DogFatherGitandClaude Sonnet 5 7060a4a6ae Verwaltungsseite perfektioniert: Team-Verwaltung für Modis/Scouts/Creator/Manager
Nutzer-Wunsch 21.08.2026: "überall wo Modis sind oder Scouts oder
Manager, oder Creator, will ich dass ich die easy über meine
Verwaltungsseite hinzufüge und die automatisch in der Website
hinzugefügt werden ... auch mit Fotos und TikTok Link."

Backend (server-internal, braucht Filipes manuellen Deploy):
- Neue Tabelle team_members (Migration 0007) für alle vier Kategorien
  gemeinsam -- ergänzt, überschreibt NIE die von Hand gepflegten
  Einträge in data-modis.js/data-scouts.js/data-creator.js.
- routes/team.js: öffentliches Lesen (nur aktive Mitglieder, optional
  nach Kategorie gefiltert), TEAM_MANAGE-geschütztes Anlegen/Bearbeiten/
  Löschen, Foto-Upload (gleiches Muster wie "Event des Jahres"),
  automatische Übersetzung von Rolle/Bio/Zitat wie bei anderen
  admin-gepflegten Texten. Slug global eindeutig (mit automatischer
  Kollisionsauflösung), TikTok-Kurzname wird zu voller URL ergänzt.
  27 Tests in isolierter Testumgebung geprüft (kein better-sqlite3
  lokal kompilierbar).

Frontend:
- window.dogiTeamLaden() in main.js: holt admin-gepflegte Mitglieder
  einer (oder aller) Kategorien und bringt sie in exakt dieselbe Form
  wie die bestehenden data-*.js-Einträge.
- team-scouts.html/team-modis.html/creator.html hängen das Ergebnis
  einfach an ihre bestehenden Arrays an und rendern erneut -- exakt
  derselbe Look wie die schon bestehenden Profile (Foto/Avatar-Initiale,
  Rolle, Zitat, TikTok-Button). creator.html hatte bisher ein "return"
  bei leerem CREATORS-Array, wodurch admin-Creator NIE geladen worden
  wären -- gefixt. team-modis.html berücksichtigt Rang/Rang-Bezeichnung
  für die Pyramide.
- Neue Sektion "Weitere Manager" auf manager.html, komplett unsichtbar
  bis der erste Manager angelegt wird (data-manager.js neu, wie
  data-creator.js aktuell leer).
- profil.html sucht jetzt kategorieübergreifend auch in admin-gepflegten
  Profilen, inkl. korrektem Theme/Zurück-Link auch für Manager.

Verwaltung: neue Sektion "Team verwalten" (TEAM_MANAGE-Berechtigung) --
ein Formular für alle vier Kategorien mit Foto-Sofort-Upload,
TikTok-Feld, Bio/Zitat, bedingten Rang-Feldern (nur Modi), Kategorie-
Filterleiste und Bearbeiten/Löschen pro Eintrag.

Beim Testen mit Playwright einen echten Syntaxfehler gefunden und
gefixt (ASCII-Anführungszeichen statt schließendem „" in einem
Statustext), der das GESAMTE Verwaltungs-Skript und damit die komplette
Seite lahmgelegt hätte.

Cache-Busting-Version auf 20260821j erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 03:06:21 +02:00
DogFatherGitandClaude Sonnet 5 8ead1b750b KRITISCH: echten Ursprung der "rohen Übersetzungs-Schlüssel"-Bugs gefunden und behoben
Beide heutigen Meldungen ("pr_quote_open...", "ts_profil_ansehen") waren
KEIN Caching-Problem, sondern ein echter Bug in main.js: nach Klick auf
einen internen Link und dann "Zurück" (oder generell jede zweite Seite
innerhalb einer Browser-Sitzung) wurde die seiteneigene i18n-*.js-Datei
nie erneut ausgeführt -> window.I18N_PAGE blieb auf null -> jede
Übersetzung fiel auf den rohen Schlüsselnamen zurück.

Ursache: skripteUebernehmen() erkennt i18n-Dateien am Muster ".js$"
(String-Ende). Seit die Cache-Busting-Version ("?v=...") an jede
Skript-URL angehängt wird, endet der echte src-Wert aber nie mehr auf
".js", sondern auf ".js?v=...". Der Test schlug seitdem für JEDE
i18n-Datei fehl und sie wurde wie eine normale, schon geladene Datei
behandelt und beim nächsten Seitenwechsel übersprungen.

Mit Playwright reproduziert (Klick auf Profil-Kachel + Zurück-Button)
und nach dem Fix erneut verifiziert -- betraf praktisch jede Seite mit
eigenem i18n-*.js beim Navigieren per Klick, nicht nur team-scouts.html.

Cache-Busting-Version auf 20260821i erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 02:12:24 +02:00
DogFatherGitandClaude Sonnet 5 fbd11b7be4 "Was gerade läuft"-Aktionen-Teaser von der Startseite entfernt
Nutzer-Wunsch 21.08.2026: Überschrift + Button "Alle Aktionen & Projekte"
auf index.html weg. data-aktionen.js-Script-Tag (nur noch dafür gebraucht)
und die zugehörigen JS-Renderzeilen ebenfalls entfernt, dazugehörige
i18n-Keys (idx_aktionen_h2/idx_aktionen_btn) aus i18n-index.js aufgeräumt.
aktion-detail.html und data-aktionen.js selbst bleiben unangetastet.

Cache-Busting-Version auf 20260821h erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 02:04:43 +02:00
DogFatherGitandClaude Sonnet 5 ca5793e79f Patricks Profil-Abschluss um "Scout von Dogfather" ergänzt (wie Bananenstift)
Nutzer-Wunsch 21.08.2026: Patricks Bio endete nur mit "- euer Patrick",
Bananenstift hat zusätzlich eine zweite Zeile "Scout von Dogfather".
Für Konsistenz zwischen beiden Scout-Profilen in allen 5 Sprachen ergänzt.

Cache-Busting-Version auf 20260821g erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:53:57 +02:00
DogFatherGitandClaude Sonnet 5 c7904ccd62 TikTok-Buttons auf Patrick- und Bananenstift-Scout-Profilen ergänzt
Nutzer-Wunsch 21.08.2026: unter dem Namen/Rolle-Text je ein TikTok-Button
(@patrick180585 bzw. @bananenstift009). Beide nutzen den bereits
bestehenden social-Mechanismus in profil.html (social.tiktok -> echter
.btn-tiktok-Button), kein neuer Code nötig.

Cache-Busting-Version auf 20260821f erhöht (data-scouts.js ist .js und
damit von Cloudflares erzwungenem Edge-Cache betroffen).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:49:00 +02:00
DogFatherGitandClaude Sonnet 5 ac01a74d08 Zeitreise: neue Station "Erstes Fan-Treffen: Team TiliDog" (25. Juli 2026)
Nutzer-Wunsch 21.08.2026: erstes Fan-Treffen von Dogi & Tili (Team
TiliDog) in Wuppertal ergänzt -- gleichzeitig das erste persönliche
Aufeinandertreffen von DogFather und Tili. Als Meilenstein markiert und
chronologisch korrekt zwischen "Juli 2026 — Start als Manager" und
"27. Juli bis 2. August 2026 — Creator Cup" einsortiert.

Cache-Busting-Version auf 20260821e erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:39:47 +02:00
DogFatherGitandClaude Sonnet 5 360f19a52d Echtes Foto von Filipe in der Intro-Sektion auf streamer.html ergänzt
Nutzer-Wunsch 21.08.2026: "füge das foto was ich am ende mitschicke
neben den text im screen1". Sektion von einspaltigem Fließtext auf
grid-2 umgebaut, Foto (assets/img/streamer-filipe-portrait.jpg, aus
Pictures/Filipe, auf 1000x1500 verkleinert) rechts daneben mit
frame-gold-Rahmen für Abwechslung zur Casper-Sektion (frame-lila).

Cache-Busting-Version auf 20260821d erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:29:03 +02:00
DogFatherGitandClaude Sonnet 5 6106cf9f03 Modi-Gang TikTok-Button von streamer.html nach team-modis.html verschoben
Der Button gehört thematisch besser zum Modi-Team als zur Casper-Sektion
auf streamer.html (Nutzer-Wunsch 21.08.2026: "den knopf da weg bitte und
in die modie seite zu den modis hinzufügen und perfekt in die seite
anpassen"). Jetzt im Hero von team-modis.html, unter dem Lead-Text,
zentriert im bestehenden btn-row-Muster der Seite.

Cache-Busting-Version auf 20260821c erhöht.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:24:43 +02:00
DogFatherGitandClaude Sonnet 5 ed9b373a74 Husky-Bild auf streamer.html an Texthöhe angepasst statt fixem Mini-Deckel
Vorheriger max-height-Deckel (460px) fürs sehr hochkantige
streamer-mascot.jpg (900x2812) war zu knapp und ließ eine sichtbare
Lücke neben dem längeren Text ("die größe vom bild vom husky soll dem
text rechts nebendran angepasst werden"). Deckel auf 720px erhöht
(orientiert an der typischen Texthöhe in diesem Abschnitt), Grid-Stretch-
Ansatz ausprobiert und wegen Rückkopplung mit dem extremen
Seitenverhältnis verworfen (siehe Kommentare in main.css/streamer.html).

Cache-Busting-Version auf 20260821b erhöht (Cloudflare cached CSS/JS
sonst bis zu 4h am Edge).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 01:21:31 +02:00
DogFatherGitandClaude Opus 5 1f87b54351 Nav umbenannt/umsortiert + Stimmen-Kachel und Zitat-Karten aufgewertet
Nutzer-Wuensche 20.08.2026 (2. Runde):
- Kategorie "DogFather" -> "Filipe", Kategorie "HasiDog" -> "Dogi&Hasi".
- Unterpunkt "Streamer" (streamer.html) aus "Filipe" heraus nach
  "Dogi&Hasi" verschoben, dort GANZ NACH OBEN (ueber "HasiDog") und in
  "DogFather" umbenannt.
- Unterpunkt "HasiDog-Welt" -> "HasiDog".
- Fusszeile zieht mit: Spaltenueberschrift nutzt jetzt dieselbe
  Kategorie-Bezeichnung wie die Nav ("Filipe" / "Dogi&Hasi & Manager"),
  streamer.html steht dort ebenfalls in der Dogi&Hasi-Spalte ganz oben.
  Die internen Schluesselnamen (nav_dogfather...) bleiben bewusst
  unveraendert -- reine Bezeichner, ein Umbenennen waere nur Fehlerquelle.

- "die kachel soll noch spezieller und geiler aussehen": Einreich-Kachel
  auf stimmen.html deutlich aufgewertet -- wandernder Farbverlauf-Rahmen
  (Zwei-Ebenen-/background-position-Technik, KEIN rotierender Ring: siehe
  dokumentierte Projekt-Lektion zu Verzerrungen auf eckigen Flaechen),
  schwebende Herz-Partikel, Medaillon statt nacktem Emoji,
  Farbverlauf-Ueberschrift, aufleuchtende Eingabefelder.
- "und auch die die danach kommen ... sollen viel geiler sein": freigegebene
  Stimmen sind jetzt echte Praesentationskarten -- farbige Akzentlinie oben,
  grosses Anfuehrungszeichen als Wasserzeichen, Avatar-Medaillon mit
  Anfangsbuchstabe, TikTok-Handle als eigener Chip, sanftes Anheben beim
  Ueberfahren.

Alles augenschonend gehalten (gedeckte Toene, langsame Bewegungen,
vollstaendiger Stillstand bei prefers-reduced-motion) und per Playwright
visuell geprueft, keine JS-Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-21 01:02:36 +02:00
DogFatherGitandClaude Opus 5 5146cef164 TikTok-Knoepfe fuer HasiDog + Modi-Gang, Zeitreise-Reihenfolge, Bildgroesse
Nutzer-Wuensche 20.08.2026:
- hasidog.html: TikTok-Knopf direkt unter der grossen Ueberschrift,
  Account @hasidog0804 (alle 5 Sprachen uebersetzt).
- streamer.html: TikTok-Knopf unter "Casper - mein treuer Begleiter",
  Account @dogis.modi.gang (alle 5 Sprachen uebersetzt).
- zeitreise.html: die beiden letzten Karten getauscht -- der Website-Start
  (21.08.2026, konkretes Datum) steht jetzt VOR der Teddy-Kooperation
  ("Datum folgt"), damit die Zeitleiste durchgehend chronologisch bleibt.
- streamer.html Bildgroesse gefixt ("der soll bissl kleiner sein und nicht
  so riesig"): streamer-mascot.jpg ist 900x2812 px und lief mit
  aspect-ratio:auto + height:auto in voller natuerlicher Hoehe -- rund
  dreimal so hoch wie die Textspalte daneben. Neue Klasse
  .collage-photo-kompakt deckelt die Hoehe auf 460px und laesst den Rahmen
  eng am Bild sitzen (width:fit-content), die ganze Figur bleibt sichtbar.
  Regel steht bewusst NACH ".collage-photo img" -- gleiche Spezifitaet,
  die spaetere gewinnt, sonst haette width:100%/height:100% sie aufgehoben.

Alles per Playwright verifiziert (beide Knoepfe mit korrekten Links,
Bildhoehe 460px statt ~1780px, neue Zeitreise-Reihenfolge), keine JS-Fehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 23:46:04 +02:00
DogFatherGitandClaude Opus 5 399260b805 "Stimmen" verwandelt: Fans reichen selbst Testimonials ein
Nutzer-Wunsch 20.08.2026: "eine richtig geile kachel ... wo die leute mit
namen und tiktok namen mir eine nachricht schreiben können die ich in die
verwaltung kriege, und dann kann ich die ausgewählten über die
verwaltungsseite auf die website hinzufügen ... das wird mega persoenlich
zu den fans, bitte wirklich krass geil speziell."

- Neue, augenschonend gestaltete Einreich-Kachel auf stimmen.html: Name,
  TikTok-Name (optional), Nachricht -- landet NIE automatisch oeffentlich,
  sondern immer erst als Entwurf in der Verwaltung.
  Warmer Babyblau/Rosé-Farbverlauf, wandernder Lichtschein, pulsierendes
  Herz -- ersetzt die 3 ewigen "Hier steht bald..."-Platzhalterkarten.
- Neue Verwaltungs-Sektion "💬 Stimmen verwalten": Warteschlange (offene
  zuerst), Freigeben/Ablehnen/Löschen pro Eintrag.
- Freigegebene Stimmen erscheinen automatisch in einer neuen, spezielleren
  Zitat-Kartenoptik (großes Anführungszeichen, Name + TikTok-Chip) --
  Abschnitt bleibt komplett unsichtbar, solange keine einzige freigegeben
  wurde.
- Backend: neue Tabelle `testimonials` (Migration 0006), routes/
  testimonials.js (oeffentliches Einreichen + Lesen freigegebener,
  admin-Warteschlange + Status/Loeschen mit neuer TESTIMONIALS_MANAGE-
  Berechtigung). 18 automatisierte Tests gegen eine Fake-DB bestanden.
- Alles per Playwright visuell durchgespielt: leerer Zustand, Einreichen
  -> Erfolgsmeldung, freigegebene Stimmen-Anzeige, Verwaltungs-Warteschlange
  mit allen Aktionen.

Backend-Teil (server-internal/, cloudflare-worker/migrations/) noch ohne
Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 23:37:31 +02:00
DogFatherGitandClaude Opus 5 519e209bce Zweite Live-Uhr fuer "spezielles Live-Event" + mehr Farbe im Radar
Nutzer-Wunsch 20.08.2026: "wuensch mir nur noch bissl farbe und sehr
wichtig ist dass ich auch spezielle live events da auch eintragen kann
in der verwaltungsseite so dass da eine zweite uhr erscheint wo die zeit
dann fuer dieses spezielle event laeuft."

- Neue Verwaltungs-Sektion "Spezielles Live-Event": Titel (Deutsch, wird
  automatisch uebersetzt), echtes Datum+Uhrzeit, optionaler Link, Aktiv-
  Schalter -- nur mit Titel + Zukunftsdatum aktivierbar.
- Zweite Uhr auf streamplan.html (Magenta/Violett statt Cyan/Gold, direkt
  neben der bestehenden), nur sichtbar wenn ein Event aktiviert ist und
  das Zieldatum noch nicht vorbei ist. Echter Countdown inkl. Tage (z.B.
  "2T 03:14:59"), "Jetzt"-Zeiger zeigt wie bei Uhr 1 die tatsaechliche
  Uhrzeit, der magentafarbene Fixpunkt markiert die Tageszeit des Events.
  Zieldatum wird als UTC gespeichert -- jede besuchende Person sieht den
  exakt richtigen Countdown in ihrer eigenen Zeitzone.
- "Bissl Farbe": bunter Farbverlauf (Cyan/Violett/Gold) auf dem aeusseren
  Ring statt reinem Grauton, kraeftigerer Sweep-Farbschein.
- Backend: neue routes/special-event.js (getSpecialEventPublic nur bei
  aktiv+zukuenftig, getSpecialEventAdmin fuer Entwuerfe, saveSpecialEvent
  mit Validierung), 13 automatisierte Tests gegen eine Fake-DB bestanden.
- Bugfix unterwegs gefunden (Playwright-Screenshot, wiederholtes Muster
  auf dieser Seite): .stream-radar-wrap blieb trotz [hidden]-Attribut
  sichtbar (display:block ueberschreibt die eingebaute [hidden]-Regel bei
  gleicher Spezifitaet) -- explizite Regel ergaenzt, per Playwright erneut
  verifiziert (display:none bestaetigt).

Backend-Teil (server-internal/) noch ohne Deploy-Zugriff -- Dogi muss ihn
manuell auf dogiintern ausrollen, sonst bleibt die zweite Uhr unsichtbar.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 23:24:17 +02:00
DogFatherGitandClaude Opus 5 7fdceadb9e Fix: Sprachschalter-Menue nicht mittig wie die Kategorie-Menues
Nutzer-Report per Screenshot-Vergleich: "Medien"-Kategorie ist mittig
unter dem Knopf, der Sprachschalter (DE/CH/EN/FR/PT) aber rechtsbuendig --
war bewusst so gebaut, als der Schalter noch ganz am rechten Rand sass.
Seit DogiCrew-/Bewerben-Knopf daneben stehen, ist genug Platz fuer
dieselbe zentrierte Ausrichtung wie ueberall sonst -- macht die Optik
konsistent und behebt nebenbei einen Detail-Fehler: der Verbindungspfeil
zeigte schon immer mittig, waehrend die Box selbst rechts daneben sass.
Per Playwright verifiziert: Dropdown jetzt exakt unter dem Knopf zentriert,
laeuft bei keiner getesteten Breite ueber den Rand.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 23:10:27 +02:00
DogFatherGitandClaude Opus 5 7dadd84cbb Neue Hintergrundbilder: Startseite (Trio) + Streamplan
Nutzer-Wunsch 20.08.2026: Startseiten-Hero (universe-trio.jpg) und
Streamplan-Hero (bg-streamplan.jpg/-mobile.jpg) durch neu bereitgestellte
Bilder ersetzt. Blur-Variante fuer die Startseite neu aus dem frischen
Bild erzeugt (Gaussian Blur, passend zur bestehenden Cover-Verlauf-Technik).
Mobile-Ausschnitt fuer Streamplan mehrfach nachjustiert, damit der
"STREAMPLAN"-Schriftzug im schmalen Hochformat-Crop komplett sichtbar
bleibt. Alte Bilder als .bak-20-08-2026 gesichert (nicht eingecheckt).
Referenzen mit Versions-Stempel (?v=) versehen, damit der neue Stand
sofort sichtbar ist statt bis zu 4 Std im Cache zu haengen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 23:07:33 +02:00
DogFatherGitandClaude Opus 5 19636a25ec Fix: per Klick geoeffnetes Nav-Kategorie-Menue schloss sich nicht von selbst
Nutzer-Report per Screenshot: Klick auf eine Kategorie (z.B. "DogFather")
liess das Untermenue offen stehen, bis irgendwo anders hingeklickt wurde --
verliess man es einfach mit der Maus, blieb es haengen. Jetzt schliesst
sich ein per Klick geoeffnetes Menue automatisch, sobald die Maus die
Kategorie (Knopf + Untermenue) verlaesst -- nur auf echten Maus-Geraeten
(hover:hover + pointer:fine), auf Touch/Tablet aendert sich nichts, dort
gibt es kein "mit der Maus verlassen". Per Playwright verifiziert: Klick
oeffnet, Mausbewegung weg schliesst.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 22:56:49 +02:00
DogFatherGitandClaude Opus 5 a5615331aa Streamplan-Seite: interaktives Live-Radar statt schlichter Textkarten
Nutzer-Wunsch 20.08.2026: "diese seite vom streamplan soll viel geiler
und spezieller sein, ueberrasch mich."

Neues Herzstueck: ein 24-Stunden-Ziffernblatt (reines SVG, keine
Bild-Assets), das den festen 20-Uhr-Termin als dauerhaft leuchtenden
Fixpunkt zeigt (goldener Puls) und einen "Jetzt"-Zeiger in Echtzeit mit
der tatsaechlichen Uhrzeit der besuchenden Person mitbewegt (Babyblau,
DogFather-Markenfarbe). Nutzt denselben /live-status-Endpunkt wie die
Startseite:
- Offline: echter Sekunden-Countdown zum naechsten lokalen 20-Uhr-Termin.
- Live: komplettes Radar schaltet auf Rot/Puls um, zeigt den Stream-Titel
  und einen "Jetzt anschauen"-Knopf direkt zu TikTok.
Sanft rotierender Lichtschein fuer Atmosphaere, komplett augenschonend
(gedeckte Farben, respektiert prefers-reduced-motion vollstaendig).

Bugfix unterwegs gefunden (Playwright-Screenshot, dritte Wiederholung
desselben Musters heute): der "Jetzt anschauen"-Knopf blieb trotz
[hidden]-Attribut sichtbar, weil .btn selbst "display" setzt und damit
gleiche Spezifitaet wie die eingebaute [hidden]-Regel hat -- explizite
Regel ergaenzt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 22:50:49 +02:00
DogFatherGitandClaude Opus 5 b3e191d3ca "Event des Jahres": Aktivieren-Schalter, leer bis befuellt, Detail-Fenster
Nutzer-Wunsch 20.08.2026: "diese zwei kisten sollen leer sein solang wie
ich nichts rein setze, am besten sollen die sogar immer nur erscheinen
wenn ich was rein setze und sie aktiviere ... wen ich drauf druecke dass
dann ein kleines fenster aufgeht wo das bild bissl groesser ist mit einem
groesseren text und beschreibung, und mit einem link ... die kacheln
sollen auch bissl spezieller sein."

- Kein hartkodierter Standardinhalt mehr auf der Startseite -- die Kachel
  UND der ganze Abschnitt bleiben komplett unsichtbar, bis mindestens ein
  Event in der Verwaltung ausgefuellt UND ueber einen neuen "Aktiv"-Schalter
  freigeschaltet ist. Genau 1 aktives Event -> zentrierte Einzelkachel
  statt halbleerem Zwei-Spalten-Raster.
- Klick auf eine Kachel oeffnet jetzt ein Detail-Fenster (groesseres Bild,
  groesserer Titel/Text, optionaler direkter Link) statt sofort
  wegzunavigieren.
- Kacheln bekommen einen goldenen Trophaeen-Akzent + dezenten wandernden
  Lichtschimmer statt der neutralen Standardkarten-Optik.
- Bugfix unterwegs gefunden (Playwright-Screenshot): .jahres-event-card
  blieb trotz [hidden]-Attribut sichtbar (dieselbe Ursache wie der
  frühere .jahres-event-bild-Bug: display:block ueberschreibt die
  eingebaute [hidden]-Regel bei gleicher Spezifitaet) -- explizite
  [hidden]-Regel ergaenzt.
- Backend: server-internal/routes/events.js liefert oeffentlich NUR noch
  aktivierte Slots aus (getEventsPublic), neuer authentifizierter Endpunkt
  getEventsAdmin liefert der Verwaltung auch Entwuerfe zum Vorausfuellen.
  10 automatisierte Tests gegen eine Fake-DB bestanden.

Backend-Teil (server-internal/) noch ohne Deploy-Zugriff -- Dogi muss ihn
manuell auf dogiintern ausrollen, sonst bleibt die Startseite beim alten
Verhalten (immer beide Slots zeigen, kein Aktiv-Schalter in der Verwaltung).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 22:43:28 +02:00
DogFatherGitandClaude Opus 5 208b5ba4ed Fix: gemeinsame Navigationsleiste war auf der Verwaltungsseite ~16% groesser
Endlich gefunden (Screenshot-Vergleich Haupt-/Verwaltungsseite Seite an
Seite, exakt gleiche Fensterbreite): verwaltung.html setzt bewusst
`html { font-size: 18.5px }` fuer ihr eigenes "Jewelen-Tresor"-Design
(statt der normalen 16px) -- das ist eine GLOBALE rem-Basis und vergroesserte
dadurch ungewollt auch die gemeinsame, aus main.css/main.js kommende
Navigationsleiste um denselben Faktor (~16%). Dieselbe Leiste brauchte
dadurch spuerbar mehr Breite als auf jeder anderen Seite und lief bei
Fensterbreiten ueber, bei denen sie ueberall sonst laengst gut passte --
kein Cache-Problem, ein echter CSS-Bug, der die ganze vorherige
Fehlersuche erklaert.

Fix: die Navigationsleiste bekommt in verwaltung.html ihre Masse fest in
Pixel zurueck (exakt die Werte, die bei 16px-Basis herauskaemen) statt in
rem -- dadurch bleibt sie unabhaengig von der Basis-Schriftgroesse dieser
Seite exakt so gross wie ueberall sonst. Lokal verifiziert: beide Seiten
liefern jetzt bei identischer Fensterbreite exakt dieselbe Leisten-Breite
(1560px).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 22:22:45 +02:00
DogFatherGitandClaude Opus 5 fece1dad56 Revert: Hamburger-Schwelle zurueck auf 1650px
Die Erhoehung auf 1900px eben war ein Fehlgriff -- der Nutzer sah dadurch
bei seiner eigentlichen Fensterbreite (die volle Desktop-Nav laengst
gepasst haette, zweifach live bestaetigt) nur noch die schmale Menue-
Ansicht statt der gewohnten vollen Leiste. 1650px war die korrekte,
bereits bestaetigte Schwelle -- das eigentliche Problem war durchgehend
Browser-/CDN-Caching, nicht die Schwelle selbst.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 20:06:18 +02:00
DogFatherGitandClaude Opus 5 0b0e7a2eb9 Nav-Sicherheitsabstand nochmal deutlich vergroessert (Hamburger bis 1900px)
Nutzer meldet weiterhin Ueberlauf trotz zweifach bestaetigtem Live-Test
(exakt seine Fensterbreite 1993x931 gegen den echten Server, 0 Ueberlauf,
mehrfach reproduziert) -- Ursache vermutlich hartnaeckiger lokaler Cache
im jeweiligen Browserprofil, nicht mehr abschliessend ferndiagnostizierbar.
Statt weiter zu diskutieren: Sicherheitsabstand brachial vergroessert,
unabhaengig von der genauen Ursache. Hamburger-Schwelle 1650px -> 1900px --
deckt praktisch jede Laptop-/Desktop-Fensterbreite ab, echte Desktop-Nav
zeigt sich jetzt erst ab sehr breiten Fenstern (>1900px), dort mit viel
Luft (min(1560px, 94vw)).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 20:00:07 +02:00
DogFatherGitandClaude Opus 5 7099d80491 Sichtbarer "App installieren"-Knopf statt versteckter Browser-Funktion
Nutzer-Report: "ich kann sie immer noch nicht runter laden" -- Manifest +
Service Worker reichen technisch fuer Installierbarkeit, aber ohne
sichtbaren Knopf muss man wissen, dass Chrome/Edge das Adressleisten-
Symbol/3-Punkte-Meny dafuer versteckt. Jetzt: echter Knopf im Footer
("Als App installieren", jede Seite) und in der Verwaltung-Session-Leiste
("Als eigene App installieren"), nutzt beforeinstallprompt + prompt() --
loest pro Seite automatisch mit GENAU dem Manifest aus, das diese Seite
selbst verlinkt (index.html -> manifest.json, verwaltung.html ->
manifest-verwaltung.json), kein Sonderfall-Code noetig. Bleibt unsichtbar,
wenn der Browser das nicht unterstuetzt (Safari/iOS) oder die Seite schon
als App laeuft.

Ausserdem: eigener apple-mobile-web-app-title fuer verwaltung.html
("DogiCrew-Verwaltung" statt generisch "DogFather" beim iOS-Home-Bildschirm).

Cache-Busting-Version (?v=) erneut hochgezaehlt (20260820 -> 20260820b),
da main.js sich durch diese Aenderung erneut geaendert hat.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 19:30:42 +02:00
DogFatherGitandClaude Opus 5 4173e43c78 Cache-Busting fuer CSS/JS auf allen Seiten (?v=20260820)
Zusammen mit dem no-cache-Header-Fix in server/index.js: Cloudflare (die
Seite laeuft hinter einem orange-cloud-Proxy) liefert fuer .css/.js einen
eigenen festen Standard-Cache (Browser Cache TTL 4 Std) aus, UNABHAENGIG
vom Origin-Cache-Control -- der no-cache-Header allein reichte deshalb
nicht (per curl bestaetigt: main.css zeigte weiterhin max-age=14400 direkt
nach dem Deploy). Robuste, von Cloudflare-Zoneneinstellungen unabhaengige
Loesung: jede lokale CSS/JS-Referenz auf allen 34 Seiten bekommt einen
Versions-Query-String (?v=20260820) -- fuer Browser/CDN ist das eine neue
URL, alte gecachte Kopien werden dadurch nie mehr faelschlich weiterverwendet.

WICHTIG fuer kuenftige Aenderungen an main.css/main.js: das Datum in ?v=
muss bei der naechsten inhaltlichen Aenderung an einer dieser Dateien
wieder hochgezaehlt werden, sonst greift der Cache-Bust nicht erneut.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 19:26:11 +02:00
DogFatherGitandClaude Opus 5 6dad6a5af5 Fix: Deploys blieben bei Besuchern bis zu 4 Std im Browser-Cache haengen
Nutzer-Report: sah den Nav-Fix und die neue installierbare Verwaltungsseite
trotz erfolgreichem Deploy nicht. Ursache: Express schickt standardmaessig
KEIN Cache-Control mit -- da die Seite hinter Cloudflare (orange-cloud)
liegt, sprang Cloudflare dafuer mit seinem eigenen Standardwert ein
(Browser Cache TTL 4 Std, per curl bestaetigt: max-age=14400). Ein frischer
Deploy war dadurch bis zu 4 Std lang im eigenen Browser-Cache jedes/jeder
Besuchers unsichtbar. Cloudflare respektiert ein vom Origin gesetztes
Cache-Control -- jetzt explizit "no-cache" gesetzt (erzwingt Revalidierung
per ETag bei jedem Laden, kein Performance-Verlust durch schnelle
304-Antworten bei unveraendertem Inhalt).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 19:23:42 +02:00
DogFatherGitandClaude Opus 5 2c5e04e433 Fix: manifest-verwaltung.json wurde von der Zugangsschranke blockiert
Die site-weite Zugangsschranke (server/gate.js) laesst bislang nur den
exakten Pfad /manifest.json unauthentifiziert durch (fuer die
PWA-Installierbarkeit der Haupt-Website noetig) -- das neue
manifest-verwaltung.json fiel dadurch nicht unter die Ausnahme und wurde
zur Login-Seite umgeleitet statt als JSON ausgeliefert zu werden. Neuen
Pfad zur Ausnahmeliste hinzugefuegt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 16:43:23 +02:00
DogFatherGitandClaude Opus 5 aecf6db509 Verwaltungsseite als eigene, separat installierbare App
Nutzer-Wunsch 20.08.2026: "ich will die Verwaltungsseite auch herunter
laden koennen, so dass ich die originale website und die verwaltungsseite
2 mal getrennt installieren kann, auf dem pc und handy."

- Eigenes manifest-verwaltung.json (eigene "id"/"scope" nur fuer
  verwaltung.html, eigener Name "DogiCrew-Verwaltung", eigenes
  Icon-Set) statt des site-weiten manifest.json (scope "/") -- macht sie
  zu einer technisch eigenstaendigen App-Identitaet, installierbar
  parallel zur Haupt-Website, auf Desktop und Handy.
- Neue Icons: bestehendes Husky-Logo mit Violett/Gold-Verlauf statt
  Babyblau (passend zum "Jewelen-Tresor"-Look der Verwaltungsseite),
  damit beide installierten Apps auch optisch klar unterscheidbar sind.
- Kein zweiter Service Worker noetig -- /sw.js laeuft bereits site-weit
  auf Scope "/" und deckt verwaltung.html automatisch mit ab.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 16:42:20 +02:00
DogFatherGitandClaude Opus 5 94182cc6ab Fix: Desktop-Nav lief ab ~1500px Fensterbreite ueber den Rand hinaus
Nutzer-Report per Screenshot: "DogiCrew"-Knopf/"BALD"-Badge rechts
abgeschnitten. Ursache: die Hamburger-Schwelle (1480px) und der
Nav-Bar-Breiten-Deckel (1440px) wurden schon zweimal knapp nachgezogen,
reichten aber nicht mehr, seit die Nav um den "DogiCrew"-Knopf + "BALD"-
Badge gewachsen ist (braucht jetzt real ~1491px). Ergebnis: bei JEDER
Fensterbreite ab ca. 1500px (nicht nur in einer schmalen Uebergangszone)
lief die Nav dauerhaft ~50px ueber den Rand.

Diesmal mit echtem Sicherheitsabstand statt wieder nur knapp behoben:
Schwelle 1480px -> 1650px, Deckel 1440px -> 1560px. Per Playwright ueber
den kompletten Bereich 1024-2560px nachgeprueft, keine Ueberlaeufe mehr.
Header ist site-weit eine gemeinsame Vorlage (main.js/main.css), Fix gilt
damit automatisch fuer alle Seiten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 16:38:46 +02:00
DogFatherGitandClaude Opus 5 bda3198c76 Neue Funktion: Supporter-Abstimmungen (Verwaltung + DogiCrew-Bereich)
Naechste "Ausbaustufe" aus Dogfather_VanVan_Supporter_Abo.odt Abschnitt 20
(siehe Supporter-Abo-System.md), auf Nutzerwunsch "perfektioniere meine
Verwaltungsseite": Dogi/VanVan koennen in verwaltung.html eine Frage mit
2-6 Antwortoptionen auf Deutsch erstellen, automatische Uebersetzung beim
Speichern (gleiches Muster wie "Event des Jahres"). Jede aktive DogiCrew-
Person sieht die Abstimmung in ihrem Supporter-Bereich, stimmt genau einmal
ab (UNIQUE-Constraint in der DB, nicht nur Anwendungslogik), sieht danach
die Live-Ergebnisse. Admin-Seite zeigt Ergebnisbalken live, kann schliessen/
wiedereroeffnen/loeschen.

- Neue Migration 0005_supporter_polls.sql (supporter_polls,
  supporter_poll_votes), neue Berechtigung POLLS_MANAGE.
- server-internal/routes/polls.js: 30 End-to-End-Tests gegen eine
  Fake-DB bestanden (better-sqlite3 laesst sich lokal nicht kompilieren).
- verwaltung.html: neue "Abstimmungen"-Kiste im bestehenden
  vw-overview-box-Stil (violett/pink Ergebnisbalken).
- supporter.html: neue "Aktuelle Abstimmung"-Karte im bestehenden
  Gold-Look, Optionen -> Stimme -> Ergebnisbalken, alle 5 Sprachen.

Backend-Teil (server-internal/, cloudflare-worker/migrations/) noch ohne
Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 16:07:51 +02:00
DogFatherGitandClaude Opus 5 189b72ec73 Vorschau-Umschalter (Theatermasken-Symbol) vor dem oeffentlichen Start deaktiviert
Nutzer-Wunsch 20.08.2026, vor morgigem oeffentlichem Start: "die leute
sollen das ja nicht selbst auswaehlen koennen". Der Schalter erkannte
Dogi/VanVan bisher nur ueber das rein client-seitig lesbare dogi_role-
Cookie (bewusst NICHT das echte HttpOnly-Sicherheits-Cookie) -- technisch
liesse sich dieses Cookie per Browser-Konsole selbst setzen. Echte Daten
waeren dadurch nie einsehbar (nur eigene Beispieldaten-Vorschau), aber
"soll weg fuer die Oeffentlichkeit" heisst hier bewusst ganz weg, nicht
nur sicherer.

Nur der Aufruf beim Seitenaufbau ist auskommentiert, renderVorschauSchalter()
selbst bleibt unangetastet fuer ein spaeteres internes Testen.

Per Playwright verifiziert: Widget erscheint weder bei normalem Besuch
noch mit manuell gesetztem dogi_role-Cookie.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 15:16:01 +02:00
DogFatherGitandClaude Opus 5 f86b96a22f "Event des Jahres" jetzt in der Verwaltung pflegbar (Bild, Text, Link)
Nutzer-Wunsch 20.08.2026: "will ich in der admin seite das selbst
gestalten können, mit bild und text und am besten auch einen link." Auf
Rueckfrage entschieden: Titel/Text nur auf Deutsch eingeben, die anderen
4 Sprachen werden beim Speichern automatisch uebersetzt (MyMemory, 0€,
kein API-Key) -- bewusste Ausnahme von der sonst geltenden "immer echte
Uebersetzung"-Regel, klar dokumentiert und im Admin-UI selbst als Hinweis
sichtbar. de-CH bekommt denselben deutschen Text (Dialekt ist keine von
Uebersetzungs-APIs unterstuetzte Zielsprache).

Backend (server-internal):
- routes/events.js: getEventsPublic (oeffentlich, keine Session),
  saveEvent + uploadEventImage (beide hinter neuer EVENTS_MANAGE-
  Berechtigung, Owner immer erlaubt). Speichert in der bereits
  bestehenden app_settings-Tabelle (2 feste Slots) statt einer neuen
  Tabelle -- es gibt nie mehr als genau 2 Events.
- lib/translate.js: MyMemory-Anbindung mit "fail closed auf Deutsch"
  pro Sprache, falls der Dienst mal nicht antwortet.
- Bild-Upload per multer, zufaelliger Dateiname (crypto.randomUUID,
  verhindert Path-Traversal ueber den Originalnamen komplett), 5 MB
  Limit, nur jpeg/png/webp, Ablage unter /var/lib/dogfather-internal/
  uploads/events (NICHT im Git-Ordner -- uebersteht Deploys), oeffentlich
  ausgeliefert unter /uploads.
- Neue Berechtigung EVENTS_MANAGE im Katalog (Gruppe "Startseite").

Frontend:
- index.html: laedt /events-of-year beim Aufruf, ueberschreibt pro Slot
  Datum/Titel/Text/Bild/Link NUR wenn dort tatsaechlich etwas gespeichert
  ist -- bleibt der Abruf aus oder ist ein Slot leer, bleibt der bisherige
  fest eingebaute Standardinhalt (dieselben zwei echten Events) stehen.
  Kein Blocker, kein sichtbarer Fehler bei Ausfall.
- verwaltung.html: neue Sektion "🏆 Event des Jahres" (nur mit
  EVENTS_MANAGE sichtbar), 2 Karten mit Bild-Upload+Vorschau, Datum,
  Titel, Text, Link, eigenem Speichern-Knopf pro Event.

Ausfuehrlich getestet, weil server-internal wegen fehlender Visual-
Studio-Build-Tools auf dieser Windows-Maschine nicht lokal mit echtem
better-sqlite3 laufen kann: routes/events.js komplett isoliert gegen eine
Fake-DB getestet (11 Szenarien: oeffentlicher Abruf, fehlende Session,
Session ohne Recht, Owner, Rolle MIT EVENTS_MANAGE, alle Validierungen,
Bild-Upload inkl. falscher Dateityp, Abruf des hochgeladenen Bilds).
index.html per Playwright mit echtem Netzwerk-Mocking gegen zwei
Szenarien getestet (API nicht erreichbar -> Standardinhalt bleibt; API
liefert echte Daten -> nur der befuellte Slot wird ueberschrieben, der
leere bleibt Standard). Dabei einen echten CSS-Bug gefunden und behoben
(display:block auf .jahres-event-bild überschrieb die [hidden]-Regel des
Browsers, leeres Bild waere immer sichtbar gewesen). verwaltung.html per
Playwright mit gemocktem Login+API end-to-end getestet: Formular wird
korrekt vorbefuellt, Bild-Upload + Speichern senden die richtigen Daten.

WICHTIG: server-internal laeuft unter einem eigenen Systembenutzer
(dogiintern), auf den ich (claudian) bewusst KEINEN Zugriff habe -- diese
Aenderung kann ich anders als sonst nicht selbst bis auf den Server
bringen. Dogi muss den Deploy-Schritt fuer server-internal selbst
ausfuehren (git pull + npm install + Neustart des dogiintern-Dienstes).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 15:09:54 +02:00
DogFatherGitandClaude Opus 5 3f3ba835a9 Patricks Zitat ergaenzt
Nutzer-Wunsch 20.08.2026: "Wege entstehen dadurch, dass man sie geht."
(alle 5 Sprachen). Ersetzt "Zitat folgt" auf der Scout-Karte.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 14:28:11 +02:00
DogFatherGitandClaude Opus 5 f8f3e65603 Streamer-gesucht-Seite: neues Hero-Bild (Spicy Media, rot)
Nutzer-Wunsch 20.08.2026: bg-bewerben-creator.jpg + -mobile.jpg (bisher
unscharfes Selfie mit pinker Sonnenbrille) ersetzt durch das vom Nutzer
gelieferte Motiv (Spicy-Media-Look, rot, Silhouette + Logo). Alte Version
lokal gesichert (*.jpg.bak-20-08-2026, nicht eingecheckt).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 14:22:01 +02:00
DogFatherGitandClaude Opus 5 f6cbaec132 Zeitreise: Karte "Das Manager-Team wächst" entfernt
Nutzer-Wunsch 20.08.2026. Karte (Juli 2026) samt zugehoeriger i18n-Keys
(zr_ev8_date/_h3/_p, alle 5 Sprachen) entfernt. 16 -> 15 Karten.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 13:16:32 +02:00
DogFatherGitandClaude Opus 5 5c5accd12c Neues Links-Hero-Bild + echtes Community-Foto statt Platzhalter
Nutzer-Wunsch 20.08.2026:
- links.html: neues, vom Nutzer geliefertes "aus dem Universum"-Motiv
  (Weltraum-Szene mit TikTok/Instagram/Snapchat/Discord/Merch-Icons um ein
  "LINKS"-Portal) ersetzt bg-links.jpg + -mobile.jpg. Alte Version lokal
  gesichert (*.jpg.bak-20-08-2026, nicht eingecheckt).
- community.html, Abschnitt "Mehr als Follower": echtes Team-Foto
  (Diene, Ghost, VanVan, Dogi bei einem gemeinsamen Treffen, "TEAM DOGI")
  ersetzt den "Foto folgt"-Platzhalter. Gleiches Muster wie vanvan.html
  (.collage-photo, aspect-ratio:3/4 statt der alten 4/3-Platzhalterbox,
  da das echte Foto Hochformat ist). Jetzt ungenutzte i18n-Keys
  com_bild_platzhalter/com_foto_folgt entfernt.

Per Playwright verifiziert: beide Seiten laden fehlerfrei, keine
fehlgeschlagenen Requests, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:54:53 +02:00
DogFatherGitandClaude Opus 5 071f3d0382 Startseite: neue "Event des Jahres"-Kachel unter den 3 Welt-Kacheln
Nutzer-Wunsch 20.08.2026: volle Breite wie die 3 Welt-Kacheln zusammen,
zeigt immer genau zwei Events. Erste Belegung mit zwei bereits auf
zeitreise.html dokumentierten echten Events (28-Stunden-Stream 7. März
2026, Creator Cup 27. Juli - 2. August 2026) statt Platzhaltertext --
Texte sind gekuerzte, inhaltlich unveraenderte Fassungen der bestehenden
Zeitreise-Beschreibungen, beide Karten verlinken auf zeitreise.html. Alle
5 Sprachen gepflegt. Gleiche Karten-/Tag-Optik wie die Welt-Kacheln, damit
es wie ein natuerlicher vierter Baustein wirkt statt wie ein fremdes
Element.

Per Playwright verifiziert: exakt gleiche Breite wie .hero-grid (1180px),
2 Karten, kein horizontales Scrollen auf Mobil, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:51:17 +02:00
DogFatherGitandClaude Opus 5 9adebd9bc4 KRITISCH: Server-Quellcode + kompletter Git-Verlauf waren oeffentlich abrufbar
Sicherheits-Audit vor dem geplanten oeffentlichen Start morgen (21.08.2026,
Nutzer-Anfrage: "duerfen die leute keinen zugriff auf veraenderungen haben").
SITE_DIR ist der GESAMTE Repo-Ordner (join(__dirname, "..")), express.static
lieferte daher nicht nur die Website aus, sondern auch:
- server/ (inkl. gate.js, das komplette Sicherheitskonzept im Klartext)
- server-internal/ (Admin-/Supporter-Backend-Quellcode)
- cloudflare-worker/ (altes Backend)
- .git/ (VOLLSTAENDIGE Commit-Historie, rekonstruierbar per Git-Dump)
- CLAUDE.md, DEPLOY.md, wrangler.toml, netlify.toml, gate-worker.js,
  gate.html.bak-07-08-2026 (Alt-Backup-Datei einer frueheren Session)

Live nachgewiesen (mit gueltigem Zugangscode -- morgen faellt die Schranke
fuer ALLE weg): /server/gate.js und /.git/config lieferten HTTP 200.
Ursache: serve-static blockt per Default nur Dateien, deren EIGENER Name
mit einem Punkt beginnt (server/.env -> zufaellig schon 404), aber NICHT
rekursiv -- .git/config wird trotzdem ausgeliefert, weil "config" selbst
nicht mit einem Punkt beginnt, nur der Ordner davor.

Fix: eigene Sperr-Middleware VOR express.static, unabhaengig von
gateMiddleware (bleibt also auch nach dem Entfernen der Zugangsschranke
wirksam). Blockt ganze Ordner (server/, server-internal/,
cloudflare-worker/) + versteckte Ordner/Dateien rekursiv (jedes
Pfadsegment, das mit "." beginnt, ausser .well-known) + eine feste Liste
an Alt-Dateien + jedes *.bak-Muster, damit auch kuenftige Backup-Reste
automatisch mitgeschuetzt sind.

Lokal mit echtem Express-Server verifiziert (gateMiddleware absichtlich
deaktiviert, um exakt den morgigen "oeffentlich"-Zustand zu simulieren):
alle vorher gefundenen Luecken jetzt 404, alle echten Seiten/Assets
(index.html, main.css, main.js, manifest.json, robots.txt, favicon)
weiterhin 200.

Getrennt prooft: server-internal/ (eigener Dienst unter
postfach.dogfather-universe.com, Port 4200) hat sein EIGENES,
unabhaengiges Session-System -- jede /admin/*-Route ist einzeln per
requireTeamSession-Middleware abgesichert (in index.js durchgezaehlt,
keine Ausnahme gefunden), live mit einer unauthentifizierten Anfrage
gegen /admin/users/list bestaetigt (401). Dieser Dienst war nie vom
Website-Gate abhaengig und ist von diesem Fund nicht betroffen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:47:36 +02:00
DogFatherGitandClaude Opus 5 1d28d8db2b Kooperation-Seite: Hero-Bild nochmal ausgetauscht (verfeinerte Version)
Nutzer-Wunsch 20.08.2026 (zweite Runde): neues, verfeinertes Motiv (DogFather-
Logo oben, Filipe sitzend mit HasiDog + Husky, "INTERESSE AN EINER
KOOPERATION? JETZT KONTAKT AUFNEHMEN") ersetzt die Version vom selben Tag.
Theme bleibt dogfather/babyblau (passt weiterhin). Alte Version lokal
gesichert (*.jpg.bak-20-08-2026-v2, nicht eingecheckt).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:26:59 +02:00
DogFatherGitandClaude Opus 5 7a69f896bc Dienes Profiltext: Alter durch Geburtsmonat ersetzt
Nutzer-Wunsch 20.08.2026: "Ich bin 37 Jahre alt" -> "Ich bin im August 1988
geboren" (und analog in allen 5 Sprachen), Rest des Satzes (verheiratet,
Mutter von zwei Kindern) unveraendert. Betrifft nur bioHtml.de/de-CH/en/
fr/pt in data-modis.js, keine anderen Vorkommen von "37" im Text.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:06:48 +02:00
DogFatherGitandClaude Opus 5 bfcf35aafa Kooperation-Seite: neues Hero-Bild + Theme Rot -> Blau
Nutzer-Wunsch 20.08.2026: Hintergrundbild von bewerben-kooperation.html
(bg-bewerben.jpg + -mobile.jpg, beide bisher identisch zum alten roten
Spicy-Media-Motiv "WERDE TEIL VON SPICY MEDIA") ersetzt durch das vom
Nutzer geschickte neue Motiv (HasiDog/DogFather/Husky, "EINE KOOPERATION
WOLLEN? DANN HIER MELDEN", bereits babyblau statt rot). Passend dazu
data-theme von "spicymedia" (Rot/Orange) auf "dogfather" (Babyblau/Lila)
umgestellt -- keine hartkodierten Rot-Werte im HTML, daher genuegt die
Theme-Umstellung fuer Knopf-/Link-/Eyebrow-Farben komplett.

Bild aus PNG-Quelle konvertiert (quality=90, optimize+progressive), Seiten-
verhaeltnis/Aufloesung unveraendert uebernommen (kein Hochskalieren). Alte
Bilder lokal gesichert (*.jpg.bak-20-08-2026, nicht eingecheckt).

Per Playwright verifiziert: data-theme=dogfather, --accent=#8fd9ea, keine
fehlgeschlagenen Requests, keine Konsolenfehler, Formular/Footer sehen im
echten (nicht-fullPage-)Screenshot nach dem Scrollen korrekt dunkel aus --
ein zunaechst gefundener "weisser Kasten" war ein reines Playwright-
fullPage-Screenshot-Artefakt (position:fixed-Hintergrund kachelt beim
kuenstlich verlaengerten Full-Page-Screenshot nicht mit), kein echter Bug,
per echtem gescrolltem Viewport-Screenshot gegengeprueft und ausgeschlossen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 12:04:05 +02:00
DogFatherGitandClaude Opus 5 02f9509042 Zeitreise-Finale-Punkt-Bug + Preis aus dem Abonnieren-Hero-Bild entfernt
1) Nutzer-Report 20.08.2026 ("wieso dieser Punkt da in der Mitte"):
.zeit-node (der leuchtende Zeitleisten-Punkt) ist bei normalen Karten
position:absolute; left:50%; top:50% relativ zu .zeit-ast -- korrekt, weil
die Karte dort nur die halbe Breite einnimmt. Die Finale-Karte
(.zeit-final) wird aber auf fast volle Breite gestreckt und zentriert,
der Knoten landete dadurch mitten im Zitat-Text. Die Verbindungslinie
(::before) wurde dafuer schon frueher ausgeblendet, der Knoten selbst
wurde dabei uebersehen -- jetzt nachgezogen (display:none fuer
.zeit-final .zeit-node).

2) Nutzer-Wunsch 20.08.2026: der Preis "FÜR 4,99 € MONATLICH" stand fest
ins Hero-Bild von abonnieren.html eingebrannt (bg-abonnieren.jpg +
-mobile.jpg, beide Dateien waren identisch) -- per CSS/Text nicht
erreichbar, siehe bereits dokumentierter Fund vom selben Tag. Per Pillow
sauber herausretuschiert (Clone-Stamp aus einem textfreien Bereich
derselben Schaltflaeche, exakt auf die Zeilenhoehe inkl. Ü-Umlautpunkte
skaliert, Nahtstellen weich gezeichnet, mit numpy-Helligkeitsanalyse
zeilenweise gegengeprueft bis keine Text-Reste mehr uebrig waren) --
"ABONNIEREN" bleibt als eigenstaendiger Button stehen, keine sichtbare
Lücke/Leerstelle. Qualitaet/Dateigroesse an das Original angepasst
(quality=90, optimize+progressive, exakt vergleichbare Groesse). Original
lokal gesichert (bg-abonnieren.jpg.bak-20-08-2026, nicht eingecheckt).

Beide Fixes per Playwright verifiziert: Knoten-Punkt display:none bei der
Finale-Karte, Hero-Bild laedt fehlerfrei ohne fehlgeschlagene Requests,
keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:49:26 +02:00
DogFatherGitandClaude Opus 5 7e369c72ae Zeitreise: echte Daten fuer "Team Dogi entsteht" + "geht online"
Nutzer-Wunsch 20.08.2026:
- "Team Dogi entsteht": "Datum folgt" -> "Anfang 2025" (neuer Key
  zr_ev2_date, alle 5 Sprachen). Bleibt an ihrer Stelle -- liegt weiterhin
  chronologisch vor "Ostern 2025".
- "DOGFATHER UNIVERSE geht online": "2026 - Datum folgt" -> "21. August
  2026, 21 Uhr" (morgen, live). Bleibt ebenfalls an ihrer Stelle.

Per Playwright komplette Reihenfolge erneut gegengeprueft: weiterhin
chronologisch korrekt, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:36:47 +02:00
DogFatherGitandClaude Opus 5 895f04c524 Zeitreise: echtes Datum fuer "Start als Content Creator" (24.10.2023)
Nutzer-Wunsch 20.08.2026. Neuer i18n-Key zr_ev1_date (alle 5 Sprachen),
Karte bleibt weiterhin an erster Stelle, da 2023 das fruehste Datum der
gesamten Zeitleiste ist. Per Playwright die komplette Reihenfolge erneut
durchgezaehlt: weiterhin korrekt, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:33:55 +02:00
DogFatherGitandClaude Opus 5 f750fe9dfd Zeitreise: echte Daten fuer Buch + Spotify, chronologisch einsortiert
Nutzer-Wunsch 20.08.2026: "Das Buch HasiDog & Casper" (November 2025) und
"HasiDog startet auf Spotify" (1. Januar 2026) hatten bisher "Datum folgt"
und lagen dadurch weit hinten in der Zeitleiste, obwohl beide zeitlich vor
dem 28-Stunden-Stream (7. März 2026) liegen. Neue i18n-Keys zr_ev13_date/
zr_ev14_date (alle 5 Sprachen) ergaenzt, beide Karten an die chronologisch
richtige Stelle verschoben: Ostern 2025 -> November 2025 (Buch) ->
1. Januar 2026 (Spotify) -> 7. März 2026 (28-Stunden-Stream) -> ...

"Kooperation mit VanVan Teddys" bleibt bewusst unveraendert bei "Datum
folgt", da dafuer noch kein Datum genannt wurde.

Per Playwright die komplette Reihenfolge alle 16 Karten durchgezaehlt und
gegengeprueft: chronologisch korrekt, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:26:19 +02:00
DogFatherGitandClaude Opus 5 9cb4e177ee Zeitreise: 4 Ereignisse entfernt + einladender "wächst noch"-Hinweis
Nutzer-Wunsch 20.08.2026: vier Zeitleisten-Karten sollten komplett weg
("Ein neues Kapitel beginnt" / Mai 2026, "Die ersten betreuten Creator",
"Weitere Scouts und Manager kommen hinzu", "Das erste Community-Treffen") --
entfernt aus zeitreise.html samt der zugehoerigen, jetzt ungenutzten
i18n-Keys (zr_ev5_*, zr_ev16_*, zr_ev17_*, zr_ev18_*). 20 -> 16 Karten.

Zusaetzlich: gleich am Seitenanfang soll auffallen, dass diese Zeitreise
noch nicht fertig ist. Bewusst NICHT die alte .todo-note-Optik reaktiviert
(die war fuer Entwickler gedacht und wurde am 31.07.2026 sitewide bewusst
unsichtbar gemacht) -- stattdessen ein neuer, fuer Besucher gestalteter
Hinweis (.zeit-baustelle), der zum Wachstums-Baum-Thema der Seite passt
(🌱 "Der Anfang" oben, 🌳 "...wächst weiter" unten): "Diese Zeitreise
wächst noch", babyblauer Glow-Rahmen, leicht wiegendes Setzlings-Icon.
Alle 5 Sprachen gepflegt.

Per Playwright verifiziert: alle 4 Karten wirklich weg (Text-Suche),
16 statt 20 .zeit-ast-Elemente, Hinweisbox sichtbar mit korrektem Text,
keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:23:38 +02:00
DogFatherGitandClaude Opus 5 c4fa132244 DogiCrew-Sperre: auch die Registrierungsfelder selbst nicht mehr eintippbar
Nutzer-Feedback 20.08.2026 (direkte Nachpruefung): "ich kann immer nur was
rein tippen, soll garnicht möglich sein bitte" -- der Registrieren-Knopf
war gesperrt, aber Name/TikTok/E-Mail-Feld ließen sich weiterhin normal
beschreiben. Jetzt disabled, exakt wie das E-Mail-Feld im Login-Panel
(voriger Commit). Per Playwright verifiziert: echter Tippversuch in allen
drei Feldern hinterlässt keinen Wert mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:10:26 +02:00
DogFatherGitandClaude Opus 5 d98133faba DogiCrew-Sperre vervollstaendigt: Login-Einstieg, E-Mail-Feld, Preis
Nutzer-Feedback 20.08.2026 (Nachpruefung des vorherigen Commits): der
Registrieren-Knopf war gesperrt, aber drei Luecken blieben offen --

1. "Schon Supporter? Hier einloggen" fuehrte zu einem VOLL FUNKTIONSFAEHIGEN
   Login-Code-Anfordern-Knopf. E-Mail-Feld jetzt disabled (nicht eintippbar,
   wie gewuenscht) und btn-login-request auf denselben .btn-gold-locked-Stil
   wie der Registrieren-Knopf umgestellt (natives disabled-Attribut).
2. Dritte, bislang uebersehene Luecke: "Mit Google anmelden" waere ein
   weiterer Weg gewesen, trotz gesperrter Knoepfe ein echtes Konto anzulegen,
   falls GOOGLE_CLIENT_ID serverseitig konfiguriert ist. initGoogleConsent()
   wird jetzt nicht mehr aufgerufen, solange die Registrierung gesperrt ist --
   ein Kommentar markiert genau die Stelle zum spaeteren Reaktivieren.
3. Der Preis (4,99 €) durfte laut Nutzer noch nicht sichtbar sein -- war aber
   an zwei Stellen zu sehen: der grossen Preis-Zahl in der Box (jetzt
   "Coming soon…" im selben Gold-Schimmer-Stil wie der gesperrte Knopf) und
   im Fliesstext (ab_text2, alle 5 Sprachen: "Für 4,99 € im Monat" ->
   "Mit deinem/dim/your/ta/sua monatlichen Beitrag", nur die erste Teilphrase
   geaendert, Rest jeder Uebersetzung unangetastet).

Betrifft ausschliesslich den oeffentlichen Anmelde-Einstieg -- bereits
eingeloggte Supporter (Dogi/VanVan als Test-Accounts) sind ueber ihren
gespeicherten Token/supporter.html unveraendert erreichbar.

Bekannter, NICHT in diesem Commit geloester Rest: der grosse Hero-Banner
oben auf der Seite (assets/img/bg-abonnieren(-mobile).jpg) zeigt den Preis
ebenfalls fest ins Bild eingebrannt ("ABONNIEREN FÜR 4,99 € MONATLICH") --
das ist Bildmaterial, keine Text-/CSS-Aenderung, braucht Ruecksprache mit
Dogi bevor daran gearbeitet wird.

Vor dem Commit per Playwright verifiziert: Preis-Box zeigt nur noch
"Coming soon…", Login-E-Mail-Feld nimmt keine Eingabe an, Klick auf den
gesperrten Login-Knopf loest keinen /supporter/login-request-Aufruf aus,
Google-Bereich bleibt hidden, keine Konsolenfehler.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 11:07:24 +02:00
DogFatherGitandClaude Opus 5 5cd473e71a DogiCrew-Registrierung: "Coming Soon"-Sperre + Bald-Badge im Nav-Knopf
Nutzer-Wunsch 20.08.2026: DogiCrew ist "das geilste Bonus" -- der Registrieren-
Knopf soll noch nicht bedienbar sein (Dogis PayPal-Business-Zugangsdaten fehlen
noch, siehe DogFather Website - Offene Punkte.md), aber Besucher sollen ueber
den Nav-Knopf trotzdem ganz normal auf die Seite kommen und die Vorschau sehen
duerfen -- "soll alles bleiben" ausser dem einen Knopf.

- Nav-Knopf (DogiCrew/Abo aktivieren, main.js renderAboButton): neues kleines
  Schimmer-Badge "Bald" direkt in der Pille (main.css .nav-cta-soon, reine
  Wiederverwendung von .btn-silver-text/-spark in kleinerem Massstab). Nur auf
  den drei Zielen, die zur (noch gesperrten) Registrierung fuehren -- NICHT auf
  supporter.html, das ist der echte, bereits funktionierende Bereich fuer
  Dogi/VanVan als Test-Supporter.
- abonnieren.html: Registrieren-Knopf ersetzt durch neue .btn-gold-locked-
  Komponente -- eigener Gold/Schloss-Stil (nicht das schon anderswo auf dieser
  Seite vergebene .btn-silver), natives disabled-Attribut (kein JS noetig,
  disabled-Buttons feuern keine Click-Events -- der bestehende Listener bleibt
  unveraendert und inert). Formularfelder bleiben normal ausfuellbar (Teaser),
  nur der Absende-Knopf ist gesperrt.

Bug waehrend der Umsetzung gefunden UND behoben, nicht nur uebersehen: die
rotierende Conic-Gradient-Randmaske von .btn-silver/.btn-legendary (copy-paste
als erster Versuch) verzieht sich auf diesem sehr langgestreckten 100%-Breite-
Knopf zu einer krummen Schlaufe -- exakt die dokumentierte Lektion in
Projektregeln.md Punkt 14 (03.08.2026, TikTok-Button-Bug), die beim ersten
Entwurf übersehen wurde. Per Playwright-Screenshots über mehrere Animations-
Frames nachgewiesen (nicht nur vermutet) und auch am bereits LIVE laufenden
.btn-silver auf dieser Seite reproduziert, um auszuschliessen, dass es an der
neuen Komponente statt an der Technik selbst liegt. Fix: derselbe sichere
Zwei-Layer-Background-Trick wie bei .abo-google-frame (gleiche Datei) --
Bewegung nur ueber background-position, bleibt geometrieunabhaengig exakt an
der Kontur. Nach dem Fix erneut ueber mehrere Frames verifiziert, sauber.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 10:51:34 +02:00
DogFatherGitandClaude Opus 5 0223fcf9cd Mobil-Menü: schwebende Eck-Knöpfe blockierten Sprachschalter + Bewerben-Button
Nutzer-Report 20.08.2026: "auf dem Handy... passt nicht immer alles". Per echter
Mobil-Emulation (iPhone 15 Pro + Pixel 8, Playwright) nachgestellt statt geraten:
Die schwebenden Eck-Knöpfe (Musik-Widget unten rechts, Vorschau-Umschalter fuer
Dogi/VanVan unten links) sind absichtlich immer sichtbar (position:fixed, direkte
<body>-Kinder). Beim aufgeklappten Mobil-Hamburger-Menü lagen sie dadurch sichtbar
UEBER den untersten Menuepunkten (Sprachschalter "DE" + "Bewerben"-Knopf) und
verdeckten sie -- auf Screenshots klar zu sehen, betrifft jede der ueber 30 Seiten,
da das Menü ueberall gleich ist. Genau die Art Bug, die im Browser (Adressleiste
noch da, man kann drumrum navigieren) kaum auffaellt, aber in der installierten
Vollbild-App voll durchschlaegt.

Fix: :has()-Selektor blendet beide Widgets aus, solange .nav-links.open ist --
kein gemeinsamer Elternknoten mit dem Menue vorhanden, daher CSS statt weiterer
main.js-Logik. Nach dem Fix per Regressionstest ueber 6 Seiten x 2 Geraete erneut
verifiziert: Widgets erscheinen normal wieder, sobald das Menue schliesst, keine
neuen Konsolenfehler, kein horizontales Scrollen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-20 10:28:22 +02:00
1115 changed files with 375620 additions and 1130 deletions
+39
View File
@@ -0,0 +1,39 @@
# Zeilenenden festlegen.
#
# Entwickelt wird auf Windows, ausgeliefert wird auf Linux. Windows
# beendet Zeilen mit zwei Zeichen (CR LF), Linux mit einem (LF). Bei
# Textdateien ist das folgenlos -- bei Skripten nicht: Aus der ersten
# Zeile "#!/bin/bash" wird dann "#!/bin/bash\r", und Linux sucht nach
# einem Programm, dessen Name auf ein unsichtbares Zeichen endet. Der
# Fehler lautet dann "bad interpreter" und nennt einen Pfad, der voellig
# richtig aussieht.
#
# Deshalb: Alles, was auf dem Server ausgefuehrt wird, bekommt fest
# Unix-Zeilenenden -- unabhaengig davon, womit es bearbeitet wurde.
*.sh text eol=lf
*.mjs text eol=lf
*.js text eol=lf
*.json text eol=lf
*.sql text eol=lf
*.yml text eol=lf
# Bilder und Schriften nie anfassen.
*.png binary
*.jpg binary
*.webp binary
*.ico binary
*.woff binary
*.woff2 binary
*.conf text eol=lf
# Die git-Haken haben KEINE Endung -- keine der Regeln oben greift auf
# sie. Nachgemessen am 01.10.2026: Im Verlauf lagen 73 CR-Bytes in
# tools/git-haken/pre-commit.
#
# Auf Windows blockiert der Haken damit trotzdem richtig (gemessen:
# Rueckgabe 1, 0 Commits) -- auf Linux nicht, dort ist "#!/bin/sh␍"
# ein Programmname mit einem unsichtbaren Zeichen am Ende. Das ist
# Vorsorge, keine Reparatur: Ein Haken, der still nicht laeuft, ist
# genau die Sicherung, die aussieht, als waere sie da.
tools/git-haken/* text eol=lf
+132
View File
@@ -9,3 +9,135 @@ cloudflare-worker/node_modules/
.env.* .env.*
!.env.example !.env.example
server/node_modules/ server/node_modules/
# Sicherungskopien von Bildern (entstehen beim Optimieren, gehoeren nicht
# ins Verzeichnis). Am 22.08.2026 sind 13 davon versehentlich durch ein
# "git add -A" mitgewandert -- 2,6 MB, die niemand braucht.
*.bak-*
# Lokaler Testserver.
server/tmp-lokal.mjs
# ⚠️ HIER STAND server/package-lock.json (aufgenommen 26.08.2026).
#
# Ausgeschlossen wurde sie, weil ein "git pull" auf dem Server damals
# abbrach: Git weigert sich, eine unverfolgte Datei zu ueberschreiben --
# unabhaengig davon, ob ihr Inhalt derselbe ist. Der Ausschluss hat den
# Deploy repariert und dabei den Zweck der Datei beseitigt.
#
# Ohne sie darf jede Installation andere Fassungen ziehen: "^4.21.2"
# erlaubt alles bis unter 5.0. Auf dem Server laeuft deshalb express
# 4.22.2, waehrend hier 4.21.2 steht -- geprueft wird also nie genau
# das, was ausgeliefert wird. Faellt so ein Unterschied auf, dann im
# Betrieb.
#
# Nachgemessen: Die Datei hier und die auf dem Server sind Byte fuer
# Byte identisch (SHA-256 a50b028d…). Es gab also nie einen inhaltlichen
# Konflikt, nur einen formalen -- und der loest sich, indem die Datei
# einmal vom Server entfernt und danach aus dem Repo geholt wird.
bild-*.png
# Aufnahmen der Handy-Pruefung (pruef-verwaltung-handy.mjs). Sie
# entstehen bei jedem Lauf neu und sind Zwischenstand, kein Quelltext --
# im Repo waeren sie nur Ballast und wuerden bei jedem Lauf als
# Aenderung erscheinen.
handy-*.png
# Laufprotokolle der Pruefungen -- Ergebnis, kein Quelltext.
# Ein Muster statt einer Liste: Sonst haette jede neue Pruefung ihre
# eigene Zeile gebraucht, und die vergisst man. Genau das ist am
# 05.09.2026 passiert -- vier neue Protokolle standen ploetzlich als
# Aenderung im Arbeitsstand.
pruef-*-lauf.txt
server/pruef-*-lauf.txt
# Ergebnis des Sammellaufs (tools/alles-pruefen.mjs)
gesamtlauf.txt
# Bilder zum Ansehen (server/bild-*.mjs) -- entstehen bei jedem Lauf neu
tagesblick-*.png
chat-*.png
calls-*.png
sicht-*.png
# ---------------------------------------------------------------------
# Bilder der Pruefungen (06.09.2026)
#
# Die Pruefdateien schreiben Bildschirmfotos, um zeigen zu koennen, was
# sie gesehen haben -- 62 Stueck, 54 MB, und bei JEDEM Lauf neu. Sie
# standen bisher im Repo und tauchten dadurch bei jedem Commit als
# Aenderung auf: Man haette sie mitcommittet oder jedes Mal von Hand
# aussortiert. Beides ist Ballast.
#
# GEPRUEFT VOR DEM ENTFERNEN: Keine einzige Pruefung LIEST je ein Bild
# (kein readFileSync, kein existsSync auf .png) -- sie werden nur
# geschrieben und angesehen. Es sind also keine Vergleichsbilder, deren
# Verlust eine Pruefung blind machen wuerde.
#
# NICHT betroffen und bewusst weiter versioniert: alles unter
# assets/ und workspace/assets/ -- dort liegen die QR-Codes und die
# Bilder der Website. Beim ersten Anlauf waeren sie um ein Haar
# mitgegangen, weil ein zu grobes Muster sie eingeschlossen hatte.
pruef-*.png
server/pruef-*.png
abnahme-*.png
server/abnahme-*.png
# Dasselbe fuer die Messlaeufe (server/mess-*.mjs): Bilder eines
# Laufs, kein Quelltext.
mess-*.png
server/mess-*.png
# Messlaeufe von tools/mess-rueckgabewerte.sh -- Ergebnis eines Laufs,
# kein Quelltext. Gehoert nicht in die Geschichte.
rueckgabewerte-*.txt
# ---------------------------------------------------------------------
# WEGWERF-MESSDATEIEN (09.09.2026)
#
# Beim Pruefen schreibe ich Bildschirmfotos und kleine Messkripte ins
# Arbeitsverzeichnis und loesche sie danach. Einmal ist eines davon
# (`ruf.png`) trotzdem im Repo gelandet und bis auf den Server
# gewandert -- `git add -A` nimmt alles mit, was zu dem Zeitpunkt da
# ist, und die Loeschung kam eine Zeile zu spaet.
#
# Deshalb tragen solche Dateien ab jetzt das Praefix `zz-`, und git
# sieht sie gar nicht erst. Eine Regel, die im Werkzeug steht, ist
# besser als eine, an die ich mich erinnern muss.
zz-*
/*.png.tmp
# Arbeitsreste aus Pruef- und Umbaulaeufen (11.09.2026). Alles unter
# tools/_ ist Kladde: Ausgaben einzelner Laeufe, kurzlebige Patch-Skripte.
# Was davon bleiben soll, bekommt einen Namen ohne Unterstrich -- so
# ist die Entscheidung "gehoert das ins Verzeichnis?" ein Umbenennen
# und kein Vergessen.
tools/_*
# Der naechtliche Lauf schreibt hier seinen Zustand hin -- Rohausgabe,
# Vergleichszahlen und die Schlossdatei. Alles Laufzeit, nichts davon
# gehoert in die Geschichte: Es aendert sich jede Nacht, und im Repo
# waere es ein taeglicher Konflikt ohne Aussage. Das ERGEBNIS steht in
# der Vault-Notiz (02 Projekte/Pruefstand.md), die Werkzeuge selbst
# sind versioniert.
tools/.nachtlauf-*
# Zwischenstaende meiner Mess- und Sammellaeufe. Rohausgaben, die sich
# bei jedem Lauf aendern -- im Repo waeren sie taeglicher Konflikt ohne
# Aussage. Die Werkzeuge selbst sind versioniert.
tools/.sammellauf*
tools/.nachpruef*
tools/.handy-detail.txt
tools/.rest*
videos/
tools/.vid/
# Commit-Texte und Drehprotokolle sind Arbeitsmaterial, kein Code.
tools/.commit-*
tools/.dreh*
tools/.nach-*
tools/.messkopf.txt
# Das Arbeitsschloss gehoert dem Rechner, nicht dem Verlauf: Es sagt,
# wer GERADE arbeitet. Committet waere es eine Behauptung von gestern.
.arbeitsschloss
+9 -8
View File
@@ -3,9 +3,10 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/png" href="assets/img/favicon.png" /> <link rel="icon" type="image/png" href="/assets/img/app-symbole/universe-32.png?v=202610012001" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/universe-180.png?v=202610012001" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d10" /> <meta name="theme-color" content="#065f76" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="DOGFATHER UNIVERSE" /> <meta property="og:site_name" content="DOGFATHER UNIVERSE" />
<meta property="og:title" content="Seite nicht gefunden — DOGFATHER UNIVERSE" /> <meta property="og:title" content="Seite nicht gefunden — DOGFATHER UNIVERSE" />
@@ -18,10 +19,10 @@
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" /> <meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<title>Seite nicht gefunden — DOGFATHER UNIVERSE</title> <title>Seite nicht gefunden — DOGFATHER UNIVERSE</title>
<link rel="stylesheet" href="assets/css/main.css" /> <link rel="stylesheet" href="assets/css/main.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" /> <link rel="stylesheet" href="assets/css/theme-dogfather.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" /> <link rel="stylesheet" href="assets/css/theme-hasidog.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" /> <link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=202610012001" />
</head> </head>
<body> <body>
<div id="site-header"></div> <div id="site-header"></div>
@@ -41,7 +42,7 @@
</main> </main>
<div id="site-footer"></div> <div id="site-footer"></div>
<script src="assets/js/i18n-404.js"></script> <script src="assets/js/i18n-404.js?v=202610012001"></script>
<script src="assets/js/main.js"></script> <script src="assets/js/main.js?v=202610012001"></script>
</body> </body>
</html> </html>
+403 -46
View File
@@ -1,70 +1,427 @@
# DOGFATHER UNIVERSE — Go-Live-Anleitung # DOGFATHER UNIVERSE — Go-Live-Anleitung
## ✅ Status: bereits live, eigene Domain seit 03.08.2026 angeschlossen ## ⚠️ ARBEITET HIER GERADE SONST JEMAND? (seit 01.10.2026)
Die Website läuft — kostenlos, auf deinem eigenen Cloudflare-Account, unter drei Adressen An diesem Tag arbeiteten **zwei Claude-Sitzungen gleichzeitig** in diesem Verzeichnis,
gleichzeitig (alle zeigen auf denselben Worker): ohne voneinander zu wissen. Keine hat etwas falsch gemacht — sie konnten es nicht wissen.
Zweimal ist es nur gut gegangen:
- **Eigene Domain:** https://dogfather-universe.com * Beide haben `git add -A` benutzt. Hätte die eine unfestgeschriebene Arbeit der anderen
- **www-Variante:** https://www.dogfather-universe.com im Baum gehabt, wäre sie **mitcommittet** worden — unter fremdem Namen, in einer fremden
- **workers.dev (bleibt zusätzlich aktiv):** https://dogfather-universe.dogfather1608.workers.dev Begründung, und niemandem wäre es aufgefallen.
- **Bewerbungs-Postfach-Worker:** https://dogfather-universe-postfach.dogfather1608.workers.dev * Beide haben `tools/workspace-stempel.mjs` laufen lassen. Der schreibt 45 Dateien um. Wer
dort eine offen hatte, bekam sie **unter den Händen weg** geändert.
Domain-Anbindung lief über `routes` mit `custom_domain = true` in `wrangler.toml` — da die Zone Dasselbe hat in RunOne am 03.09.2026 sieben Minuten Ausfall gekostet.
`dogfather-universe.com` schon vorher auf Cloudflare lag, waren DNS + SSL-Zertifikat sofort beim
Deploy automatisch aktiv, kein manueller DNS-Schritt nötig. Alle
`REPLACE-WITH-YOUR-DOMAIN.tld`-Platzhalter im Code sind bereits durch die echte Domain ersetzt
(Social-Media-Vorschaubilder, Sitemap, robots.txt).
**Noch offen:** `assets/img/og-cover.jpg` (1200×630px Social-Preview-Bild) fehlt noch — optional, **Vor dem Arbeiten:**
nicht blockierend. CORS im Postfach-Worker ist weiterhin bewusst offen (`"*"`) statt auf die
Domain eingeschränkt, siehe TODO-Kommentar in `cloudflare-worker/src/lib/http.js` (eigener,
größerer Umbau nötig, um keine Login-/Zahlungsendpunkte zu riskieren).
## Änderungen künftig live schalten
Jede Änderung an den Dateien im Ordner `DogiHompage/` wird erst live, wenn erneut deployed
wird:
```bash ```bash
cd DogiHompage node tools/arbeitsschloss.mjs ansehen # arbeitet hier jemand?
npx wrangler deploy node tools/arbeitsschloss.mjs nehmen "was ich tue"
node tools/arbeitsschloss.mjs freigeben # am Ende
``` ```
Für Änderungen am Bewerbungs-Postfach-Worker selbst (`cloudflare-worker/src/worker.js`): Du musst nichts von Hand tun, wenn du nur stempelst oder committest — die beiden
Stempelwerkzeuge nehmen das Schloss selbst, und ein **git-Haken** (`tools/git-haken/pre-commit`)
bricht jeden Commit ab, solange **jemand anders** das Schloss hält.
**Was es NICHT tut** — das ist der wichtigere Teil:
* Es blockiert **nicht**, wenn das Schloss **deines** ist. Wer ordentlich abschließt, soll
nicht bestraft werden.
* Es **verfällt nach zwei Stunden**. Ein Schloss, das man vergessen kann, blockiert sonst
dauerhaft — und wird beim ersten Ärger umgangen. Ab da ist es wertlos.
* Es blockiert **nicht**, wenn es selbst kaputt oder nicht lesbar ist.
* Notausgang, falls du trotzdem musst: `SCHLOSS_ZWANG=ja git commit …`
**Nach einem frischen Klon einmal:** `node tools/arbeitsschloss.mjs einrichten`
(setzt `core.hooksPath`; `.git/hooks` wird nicht versioniert und wäre sonst leer).
`node server/pruef-arbeitsschloss.mjs` sagt dir, ob alles sitzt — 33 Prüfungen,
darunter ein echter Commit gegen ein fremdes Schloss.
**Und bei zwei Claude-Sitzungen:** Das Schloss macht die Gleichzeitigkeit sichtbar, es
ersetzt das Reden nicht. `SendMessage` an die andere Sitzung kostet zehn Sekunden.
---
## ⚠️ ZUERST LESEN: Die echte Seite läuft auf dem NETCUP-SERVER, nicht auf Cloudflare
Seit dem öffentlichen Start (21.08.2026) wird `dogfather-universe.com` vom **eigenen
Netcup-Server** ausgeliefert. Der alte Cloudflare-Worker existiert zwar noch und lässt sich
auch weiterhin deployen — **er erreicht die echte Domain aber nicht mehr.**
Das ist die gefährlichste Stelle im ganzen Projekt: `npx wrangler deploy` läuft ohne Fehler
durch und meldet „Deployed", die Änderung ist danach auf `…workers.dev` sichtbar — und auf
`dogfather-universe.com` passiert **nichts**. Genau so ist es am 22.08.2026 beim Sprachfenster-
Fix passiert (siehe unten). Wer nur die Erfolgsmeldung von Wrangler liest, meldet „ist live",
obwohl Filipe auf dem Handy weiterhin den kaputten Stand sieht.
| Adresse | Läuft wo | Wird von wo beliefert |
|---|---|---|
| **`dogfather-universe.com`** ← **die echte Seite** | **Netcup**, Caddy → `localhost:4100`, systemd-Dienst `dogiweb.service`, Verzeichnis `/home/dogiweb/dogfather-universe/` | Gitea `git.dogfather-universe.com/DogFatherGit/dogfather-universe`, Zweig `main` |
| `www.dogfather-universe.com` | dasselbe (Caddy nimmt beide Namen) | dasselbe |
| `dogfather-universe.dogfather1608.workers.dev` | Cloudflare Worker (Altbestand) | `npx wrangler deploy` |
Erkennungsmerkmal im Zweifel: `curl -sI https://dogfather-universe.com/ | grep -i via`
→ zeigt `via: 1.1 Caddy`, also Netcup. Käme die Seite von Cloudflare, stünde da kein Caddy.
## So wird eine Änderung wirklich live (der einzige gültige Weg)
```bash ```bash
cd DogiHompage/cloudflare-worker cd ~/Documents/Obelix/DogiHompage
npx wrangler deploy # 0. STEMPELN — sonst kommt die Änderung bei niemandem an (siehe unten)
node tools/workspace-stempel.mjs # wenn workspace/ angefasst wurde
node tools/seiten-stempel.mjs # wenn assets/ angefasst wurde
# 1. Änderung committen
git add <dateien> && git commit
# 2. In die Ablage schieben (Gitea ist die Quelle der Wahrheit)
git push gitea master:main
# 3. Auf dem Server holen
ssh dogfather-server "cd /home/dogiweb/dogfather-universe && git pull --ff-only origin main"
``` ```
## Alternative Hosting-Optionen (falls du weg von Cloudflare willst) ### ⚠️ Schritt 0 ist kein Beiwerk
Die Seite ist reines statisches HTML/CSS/JS und läuft überall. Configs liegen bereit: Der Server schickt zu Stilvorlagen, Skripten und Bildern:
- **Netlify:** `netlify.toml` liegt vor — Ordner `DogiHompage/` auf netlify.com hochladen ```
oder Repo verbinden. Cache-Control: public, max-age=31536000, immutable
- **GitHub Pages:** `.nojekyll` liegt vor — Repo pushen, unter **Settings → Pages** aktivieren. ```
In beiden Fällen bleibt der Bewerbungs-Postfach-Worker unabhängig auf Cloudflare bestehen (er ist `immutable` heißt: Der Browser **fragt nicht einmal nach**. Wer die Seite einmal geladen
eine reine API, kein Teil des Frontends) — `API_BASE_URL` in `assets/js/forms.js`, `index.html` hat, behält diese Dateien bis zu einem Jahr — oder bis sich ihre Adresse ändert. Genau
und `postfach.html` zeigt bereits dorthin. dafür hängt der Stempel (`?v=…`) daran.
## Git-Repo **Das ist schon passiert:** Auf der öffentlichen Website stand der Stempel vom 27.08.2026,
während sechs Commits `assets/` geändert hatten — darunter der Partnercode DOGI10 und der
komplette Sprachumbau. Fünf Wochen lang kam keine dieser Änderungen bei einem
wiederkehrenden Besucher an. Sie lagen auf dem Server, sie waren ausgeliefert, und niemand
sah sie.
Bereits eingerichtet (`DogiHompage/.git`), erster Commit vorhanden. Bei Bedarf zu GitHub `pruef-zwischenspeicher` prüft seit dem 30.09.2026, dass der Stempel **nicht älter ist als
pushen: die Dateien, auf die er zeigt** — nicht bloß, dass einer dasteht.
Statische Dateien (HTML/CSS/JS/Bilder) sind damit **sofort** live — der Express-Dienst liefert
das Verzeichnis direkt aus, ein Neustart ist dafür **nicht** nötig.
## ⚠️ ES GIBT ZWEI CHECKOUTS AUF DEM SERVER, NICHT EINEN
Am 22.08.2026 beim Ausrollen des Webdesign-Bereichs gefunden — diese Datei
beschrieb vorher nur den ersten und war damit unvollständig:
| Dienst | Checkout | Liefert |
|---|---|---|
| `dogiweb.service` (Port 4100) | `/home/dogiweb/dogfather-universe/` | die öffentliche Website + `server/` |
| `dogiintern.service` (Port 4200) | `/home/dogiintern/dogfather-universe/` | die API unter `postfach.dogfather-universe.com` + `server-internal/` |
**Ein `git pull` in `/home/dogiweb` ändert an `server-internal/` also gar nichts.**
Wer nur dort zieht und danach `dogiintern.service` neu startet, startet den
Dienst mit unverändertem Code neu und wundert sich, warum nichts passiert.
`claudian` hat auf `/home/dogiintern/` **keinen Zugriff** (weder lesend noch
über den begrenzten sudo). Änderungen an `server-internal/` muss deshalb
Filipe selbst ausrollen.
**Der Standard-Fall** (nur Code geändert, keine neuen/geänderten Pakete):
```bash ```bash
cd DogiHompage sudo -u dogiintern git -C /home/dogiintern/dogfather-universe pull --ff-only origin main
git remote add origin <repo-url> sudo systemctl restart dogiintern.service
git push -u origin main
``` ```
## Nach jedem Go-Live-Schritt prüfen **Der volle Fall** (auch `package.json`/`package-lock.json` geändert — dann MUSS
`npm ci` mit, sonst laufen Code und Pakete auseinander). Ein Block, bricht bei
jedem Fehler ab, und startet den Dienst erst neu, wenn Pull, Installation und
ein Lade-Test der nativen Module (better-sqlite3) durch sind — schlägt etwas
fehl, läuft der alte Dienst unberührt weiter:
- [ ] Website lädt: https://dogfather-universe.dogfather1608.workers.dev ```bash
- [ ] Bewerbungsformular sendet erfolgreich (im Postfach zeigt sich ein neuer Eintrag) sudo -u dogiintern git -C /home/dogiintern/dogfather-universe pull --ff-only origin main && \
- [ ] Live-Punkt auf der Startseite reagiert auf den Toggle im Postfach sudo -u dogiintern bash -c 'cd /home/dogiintern/dogfather-universe/server-internal && npm ci' && \
- [ ] Nach Domain-Wechsel: Link-Vorschau testen, z.B. mit dem sudo -u dogiintern node -e "require('/home/dogiintern/dogfather-universe/server-internal/node_modules/better-sqlite3'); console.log('native Module laden: ok')" && \
[Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) sudo systemctl restart dogiintern.service && \
sleep 6 && echo "Dienst:" $(systemctl is-active dogiintern.service) && \
curl -s -o /dev/null -w "health nach Neustart: %{http_code}\n" https://postfach.dogfather-universe.com/health
```
**Wichtig — kein führendes `cd`.** `/home/dogiintern/` steht auf 700; selbst
`dogi` darf per `cd` nicht hinein, nur der Benutzer `dogiintern` über `sudo -u`.
Deshalb `git -C <pfad>` (braucht kein cd) und das `npm ci` in einer
`sudo -u dogiintern bash -c 'cd … && npm ci'`-Shell, die den Wechsel als
dogiintern ausführt. Ein `cd` als erste Zeile scheitert an „Keine Berechtigung".
**Zwei Warnungen von `npm ci`, die HARMLOS sind (am 28.08.2026 verifiziert):**
1. `npm warn allow-scripts … better-sqlite3 … (install: prebuild-install || node-gyp rebuild)`
— better-sqlite3 baut sich normalerweise über ein Install-Skript. Die
allowScripts-Sperre auf dem Konto blockiert das, aber `prebuild-install`
lädt ein fertig kompiliertes Binary, das ohne den Build-Schritt funktioniert.
**Kontrolle:** Läuft der Dienst danach (`active`) und steht in den Logs
„… Einstellungen aus der Datenbank geladen", ist better-sqlite3 in Ordnung.
Der `native Module laden: ok`-Schritt im Block prüft genau das vorab.
2. `npm warn deprecated [email protected]` — nur ein Hinweis, kein Fehler.
**`sleep 6`, nicht 2.** Der Dienst braucht nach dem Neustart ein paar Sekunden,
bis er auf Port 4200 hört. Ein zu früher health-Check meldet sonst kurzzeitig
`502` (Caddy erreicht den Dienst noch nicht) und `Dienst: activating`, obwohl
gleich darauf alles läuft. Erst bei anhaltendem 502/activating ist wirklich
etwas kaputt — dann `sudo systemctl status dogiintern.service --no-pager` ansehen.
Erwartete letzte Zeilen: `native Module laden: ok`, `Dienst: active`,
`health nach Neustart: 200`. Kommt stattdessen ein Abbruch VOR dem Neustart,
ist nichts passiert — der alte Dienst läuft weiter, und der Fehler (meist ein
fehlgeschlagener `npm ci`) lässt sich in Ruhe ansehen.
## Server-Code geändert? Dann ist ein Neustart PFLICHT
Statische Dateien sind nach dem Pull sofort live. Server-Code **nicht** —
der läuft weiter mit dem alten Stand, bis der Dienst neu startet.
```bash
ssh dogfather-server "sudo systemctl restart dogiweb.service" # nach Änderungen in server/
ssh dogfather-server "sudo systemctl restart dogiintern.service" # nach Änderungen in server-internal/
```
**Warum das hier besonders steht (Vorfall 22.08.2026):** Nach dem Pull des
Webdesign-Bereichs war `/webdesign/` für einige Minuten **ohne Zugangsschutz
öffentlich erreichbar** (HTTP 200 statt der Umleitung zur Zugangswand). Die
HTML-Dateien waren durch den Pull sofort da — die Schranke in
`server/webdesign-gate.js` lief aber erst nach dem Neustart von
`dogiweb.service`. Bei einem Bereich, der ausdrücklich nicht öffentlich sein
soll, ist genau dieses Zeitfenster der gefährliche Teil eines Deploys.
Merksatz: **Erst neu starten, dann „ist live" melden** — und danach mit
`curl -I` prüfen, dass die Schranke wirklich greift:
```bash
curl -sI https://dogfather-universe.com/webdesign/ | grep -iE "^location|x-robots-tag"
# erwartet: location: /webdesign/zugang.html?next=... und x-robots-tag: noindex, ...
```
**Achtung bei Zweig-Namen:** lokal heißt der Zweig `master`, auf dem Server und in Gitea `main`.
Deshalb `master:main` beim Push. Ein blankes `git push` schiebt sonst nach `gitea/master` —
einen alten, abgehängten Zweig, den niemand ausliefert.
## Abhängigkeiten: `npm ci`, nicht `npm install`
Seit dem 26.08.2026 ist `package-lock.json` versioniert. Auf dem Server gilt
deshalb:
```bash
npm ci # richtig: installiert exakt das, was in der Lock-Datei steht
npm install # falsch: darf neuere Fassungen ziehen und schreibt die Datei um
```
**Warum der Unterschied zählt.** In `package.json` steht `"express": "^4.21.2"` —
das erlaubt alles unter 5.0. Vor dieser Umstellung lief auf dem Server deshalb
express **4.22.2**, während hier 4.21.2 stand. Geprüft wurde also nie ganz das,
was ausgeliefert wurde. Solche Unterschiede fallen nicht beim Deploy auf,
sondern im Betrieb — und dann sucht man den Fehler im eigenen Code.
`npm ci` löscht `node_modules` vorher vollständig und baut streng nach der
Lock-Datei neu auf. Es schreibt sie nie um; passt sie nicht zur `package.json`,
bricht es ab, statt still etwas anderes zu installieren.
**Die Lock-Datei war früher ausgeschlossen** (`.gitignore`), weil ein `git pull`
daran scheiterte: Git überschreibt keine unverfolgte Datei, auch wenn ihr Inhalt
derselbe ist. Das war ein formaler Konflikt, kein inhaltlicher — nachgemessen
waren beide Fassungen Byte für Byte identisch. Wenn dieser Fall irgendwo erneut
auftritt, ist die Lösung, die Datei auf dem Server **einmal** zu entfernen und
danach aus dem Repo zu holen:
```bash
ssh dogfather-server "rm -f /home/dogiweb/dogfather-universe/server/package-lock.json"
ssh dogfather-server "cd /home/dogiweb/dogfather-universe && git pull --ff-only origin main"
```
## Der Webdesign-Bereich: zwei Zahlen — seit 30.09.2026 automatisch
Die App speichert Dateien zwischen. Nach einer Änderung an `webdesign/`
oder `assets/` müssen **beide** Stellen hoch, sonst bekommen Geräte, die
die Seite schon einmal geöffnet haben, weiterhin den alten Stand:
```
webdesign/sw.js const CACHE_NAME = "dogfather-webdesign-<Stempel>";
assets/js/wd-core.js .register("/webdesign/sw.js?v=<Stempel>", …)
```
**Das macht `node tools/seiten-stempel.mjs` jetzt mit** — dieselbe Zahl wie
die Seiten. Von Hand muss hier nichts mehr gezählt werden.
> **Warum das nötig wurde.** Dieser Abschnitt stand seit dem 26.08.2026 hier,
> mit Begründung und Messwerten. Gemessen am 30.09.2026 standen beide Zahlen
> seit dem **27.08.** auf `v64`, während **sieben Commits** die Dateien
> geändert hatten, die der Service Worker vorhält — darunter
> `/assets/css/main.css`. Ein Kommentar, der vor einem Fehler warnt,
> verhindert ihn nicht. `pruef-zwischenspeicher` prüft jetzt, dass beide
> Zahlen gleich und nicht älter als die vorgehaltenen Dateien sind.
**Warum zwei und nicht eine.** `CACHE_NAME` wirft den Zwischenspeicher
weg, sobald der Service Worker startet. Die Nummer in der Adresse sorgt
dafür, dass er überhaupt neu geladen wird — und das ist hier nicht
selbstverständlich:
Gemessen am 26.08.2026: Der Server liefert `sw.js` mit
`Cache-Control: no-cache` aus. **Cloudflare ersetzt das durch
`max-age=14400`** — vier Stunden, auch bei `cf-cache-status: MISS`.
Ursache ist eine feste „Browser Cache TTL" in den Cloudflare-Einstellungen.
Ohne die Nummer in der Adresse erreicht jede Änderung am Service Worker
die Geräte also bis zu vier Stunden zu spät. Solange alles läuft, fällt
das nie auf; ist der Stand fehlerhaft, sind es vier Stunden ohne
Reparaturmöglichkeit.
## Was auf dem Server automatisch läuft
Beides über `/etc/cron.d/`, beides als root. Die Skripte liegen im Repo
und werden über den normalen `git pull` aktualisiert — ein eigener
Deploy-Schritt ist nicht nötig.
| Wann | Was | Skript |
|---|---|---|
| täglich 03:15 | Sicherung von Datenbank und Uploads | `server-internal/sicherung.sh` |
| alle 5 Minuten | Wächter über 19 Punkte (inkl. „läuft die Sicherung?") | `server-internal/waechter.mjs` |
**Sicherung.** Nutzt SQLites eigenen `.backup`-Befehl, keine Dateikopie —
die Datenbank ist 778 KB groß, ihr WAL 4,1 MB, eine Kopie der `.db`
allein wäre also weitgehend leer. 14 tägliche Stände, sonntags zusätzlich
ein Wochenstand (8 davon). Jeder Stand wird sofort nach dem Anlegen
geprüft. Wiederherstellung: `server-internal/wiederherstellen.sh`, zeigt
ohne Argument die verfügbaren Stände.
**Wächter.** Prüft sechs Dienste, neun Adressen, Plattenplatz und zwei
Zertifikatslaufzeiten. Meldet per Push, und zwar **nur bei
Zustandswechsel** — nicht alle fünf Minuten dasselbe. Läuft als root und
verschickt selbst; ein Wächter, der über den internen Dienst meldet,
wäre ausgerechnet dann still, wenn dieser das Problem ist.
Meldeweg prüfen, ohne auf eine Störung zu warten:
```bash
sudo /usr/local/bin/node /home/dogiweb/dogfather-universe/server-internal/waechter.mjs --probe
```
⚠️ **Grenze:** Ist der Server als Ganzes weg — Netz, Strom, Hardware —,
meldet auch der Wächter nichts. Dagegen hilft nur eine Überwachung
außerhalb der Maschine.
## Die Verwaltung ist eine eigene App
Seit dem 26.08.2026 hat `webdesign/verwaltung.html` ein **eigenes**
Manifest (`verwaltung.webmanifest`) mit eigener `id` und eigenem Symbol.
Ohne die unterschiedliche `id` hielten Browser beide für dieselbe App,
und die zweite Installation überschriebe die erste.
Das Manifest steht in der Ausnahmeliste von `server/webdesign-gate.js` —
ohne diesen Eintrag antwortet es mit 302 auf die Zugangswand, und der
Browser bietet „App installieren" gar nicht erst an.
## Pflicht-Prüfung nach JEDEM Deploy
Nicht auf die Erfolgsmeldung des Deploy-Befehls verlassen, sondern **die echte Domain fragen**:
```bash
# Kommt meine Änderung wirklich auf der Seite an, die Filipe benutzt?
curl -s https://dogfather-universe.com/assets/css/main.css | grep "<mein Merkmal>"
```
Erst wenn das anschlägt, gilt eine Änderung als erledigt. Bei optischen Änderungen zusätzlich
mit einem echten Browser im Handy-Format nachsehen (Playwright, Viewport 390×844) und einen
Screenshot machen — Text im Quelltext beweist noch nicht, dass es auch richtig aussieht.
## Der Cloudflare-Worker (Altbestand)
Bleibt vorerst bestehen, liefert aber nur noch `…workers.dev` aus. Ein Deploy dorthin ändert
an der echten Seite nichts. Der Versuch, die Domain per `wrangler` wieder anzubinden, schlägt
bewusst fehl:
```
Hostname 'dogfather-universe.com' already has externally managed DNS records
```
Das ist **kein Fehler, den man beheben sollte** — es ist die Schutzwirkung davon, dass die
Domain jetzt auf Netcup zeigt. `routes` mit `custom_domain = true` steht deshalb nur noch aus
historischen Gründen in `wrangler.toml`.
Der Bewerbungs-Postfach-Worker ist davon unabhängig und läuft weiter auf Cloudflare:
`https://dogfather-universe-postfach.dogfather1608.workers.dev` (`API_BASE_URL` in
`assets/js/forms.js`, `index.html`, `postfach.html`).
## Git-Ablage
- **Quelle der Wahrheit:** Gitea, `git.dogfather-universe.com/DogFatherGit/dogfather-universe`,
Zweig `main` (auf dem eigenen Server, kostenlos, in eigener Hand).
- Lokal heißt das Fernziel `gitea`, der Zweig `master`.
- Auf dem Server heißt das Fernziel `origin`, der Zweig `main`.
- `gitea/master` ist ein **alter, abgehängter Zweig** (Stand 44086b0) — nicht benutzen.
- Sicherungszweig `server-stand-vor-abgleich-22-08-2026` auf dem Server: der Stand, bevor die
beiden Fassungen am 22.08.2026 zusammengeführt wurden. Kann irgendwann weg, kostet nichts.
**Nie direkt auf dem Server Dateien bearbeiten, ohne sie danach in Gitea nachzutragen.** Genau
dadurch waren am 22.08.2026 zwei Reparaturen (Autofokus in `gate.html`, abgeschnittene
Öffnen-Knöpfe in `verwaltung.html`) nur auf dem Server vorhanden und wären beim nächsten
Deploy vom Rechner aus überschrieben worden.
## Offene Punkte
- **Server-Neustart steht aus (seit 28.08.2026).** `unattended-upgrades` hat
Kernel (6.12.105) und OpenSSL (3.5.7) eingespielt, aber es läuft noch der alte
Kernel (6.12.100) und die Dienste haben die alte libssl im Speicher.
`/var/run/reboot-required` steht. Kein Notfall (die OpenSSL-CVEs betreffen
PKCS7/CMS/QUIC-Pfade, die hier kaum aktiv sind — Caddys QUIC läuft über Go),
aber der Neustart gehört auf eine ruhige Zeit gelegt, während Filipe erreichbar
ist (Netcup-Konsole griffbereit). Danach prüfen: laufen alle sechs Dienste?
- **Server-internal-Deploy ausstehend (28.08.2026):** In Gitea liegen fertige,
getestete Änderungen an `server-internal/`, die noch nicht live sind
(Anfragebremse für `/submit` + `/testimonials/submit`; `package-lock.json` auf
multer 2.2.0 / node-cron 4.6.0). Ausrollen mit dem **vollen** Deploy-Block oben
(der mit `npm ci`), weil sich die Paketstände geändert haben. Getestet:
multer 2.2.0 fängt den DoS-Fall sauber ab, node-cron 4.x akzeptiert den
bestehenden Aufruf, alle Selbsttests grün.
- ~~Hintergrundbilder liegen nur auf dem Server~~ — **erledigt, nachgeprüft am
26.08.2026.** Alle genannten Dateien (`bg-bewerben-modi.jpg`, `bg-links-seite.jpg`,
`bg-medien-casper.jpg`, `bg-supporter.jpg`, `bg-modis.jpg`) und der Ordner
`assets/img/stimmen-avatare/` (8 Dateien) sind inzwischen versioniert.
`git status --untracked-files=all -- assets/` auf dem Server meldet **null**
unverfolgte Dateien.
Der Eintrag bleibt hier stehen, statt gelöscht zu werden: Eine Liste offener
Punkte, in der Erledigtes ungekennzeichnet steht, wird beim nächsten Mal gar
nicht mehr gelesen. Wer prüft, will sehen, dass geprüft wurde.
- **CORS steht auf `*`** — in `server-internal/index.js` (`app.use(cors())`) und im
Altbestand `cloudflare-worker/src/lib/http.js`.
**Eingeordnet am 26.08.2026, weniger dringend als der alte Hinweis klang:**
Die Antwort enthält *kein* `Access-Control-Allow-Credentials`, und die
Verwaltung weist sich über `Authorization: Bearer …` aus, nicht über ein
Cookie. Ein Browser schickt bei einer fremden Seite deshalb weder Cookies noch
das Token mit — eine fremde Seite erreicht damit nur die ohnehin öffentlichen
Endpunkte (Team, Events, Stimmen). An Kundendaten kommt sie nicht.
Sauberer wäre es trotzdem: eine feste Liste erlaubter Herkünfte
(`dogfather-universe.com`, `vans-diy-bastelbedarf.com`) statt `*`. Das ist
Härtung, keine Reparatur — und ein Eingriff in einen laufenden Dienst, der bei
zu enger Einstellung die Seite lahmlegt. Also als eigener Vorgang, mit
Live-Test danach.
- **express 5 vorbereitet, nicht umgestellt.** `pruef-express5.mjs` (Bestand
durchsuchen) und `server/test-express5.mjs` (echter Server gegen 5.2.1) sind
grün — der Umstieg wäre ohne Codeänderung möglich. Nicht durchgeführt, weil
express 4.22.2 gepflegt wird und `npm audit` null meldet. Ebenfalls offen:
dotenv 16→17, better-sqlite3 11→13 (dort muss die ABI zur Node-Fassung
passen; ein Fehlgriff legt den internen Dienst still).
- ~~Datenschutz-Endpunkte warten auf einen Pull~~ — **erledigt, live geprüft am
28.08.2026.** Alle drei (`/webdesign/admin/datenschutz/{auskunft,vorschau,
loeschen}`) antworten auf der echten Domain mit 401 (vorhanden und geschützt),
nicht mehr 404. Steht abgehakt hier, nicht gelöscht — wer prüft, will sehen,
dass geprüft wurde.
## Alternative Hosting-Optionen (nur als Notfall-Plan)
Die Seite ist reines statisches HTML/CSS/JS und läuft überall — `netlify.toml` und `.nojekyll`
liegen bereit. Relevant nur, falls der Netcup-Server einmal ausfällt.
+281
View File
@@ -0,0 +1,281 @@
# PayPal für den Webdesign-Bereich einrichten
Das ist der einzige Schritt, den ich nicht selbst machen kann: PayPal
lässt Zugangsdaten nur über dein eingeloggtes Konto erzeugen.
Alles andere steht bereits — Bestellungen, Einzug, Webhook mit
Signaturprüfung, Schutz gegen Doppelverbuchung, die gesetzlich nötige
Zustimmung vor der Anzahlung. Sobald die vier Werte eingetragen sind,
funktionieren die Bezahlknöpfe.
**Zeitbedarf:** etwa 20 Minuten. **Kosten:** keine — ein
PayPal-Geschäftskonto ist kostenlos, Gebühren fallen nur pro Zahlung an.
---
## Schritt 0 — Zuerst nachsehen, was schon da ist
**Du hast wahrscheinlich schon die Hälfte.** Das DogiCrew-Supporter-Abo
läuft über dasselbe PayPal-Konto und benutzt dieselbe Client ID und
dasselbe Secret. Wenn das Abo live funktioniert, sind sie bereits da.
So siehst du es — ohne Konsole:
1. Verwaltung öffnen: `https://dogfather-universe.com/webdesign/verwaltung.html`
2. Reiter **Zahlungen**
Oben steht der Stand, bei jedem Feld eine Marke:
| Was dort steht | Bedeutung |
|---|---|
| *hinterlegt (auf dem Server)* | kommt aus der `.env`, du musst nichts tun |
| *hinterlegt* | schon über dieses Formular eingetragen |
| *fehlt* | musst du eintragen |
Steht bei **Client ID** und **Secret** schon *hinterlegt*, brauchst du
nur **Schritt 4** (Webhook) und danach Schritt 6.
> Warum das wichtig ist: Wenn du eine **zweite** App anlegst, obwohl
> schon eine läuft, hast du zwei Sätze Zugangsdaten für dasselbe Konto.
> Das funktioniert zwar, macht aber später jede Fehlersuche doppelt so
> mühsam — und beim Erneuern eines Secrets bricht womöglich das
> DogiCrew-Abo weg.
---
## Bevor du anfängst
Du brauchst ein **PayPal-Geschäftskonto** (kein privates). Falls du noch
keins hast: Auf paypal.com anmelden → *Einstellungen* → *Kontoart
ändern* → auf Geschäftskonto umstellen. Das geht mit demselben Konto und
kostet nichts.
> **Wichtig:** Das Geld landet direkt auf **deinem** PayPal-Konto. Es
> geht zu keinem Zeitpunkt über einen Vermittler oder über mich.
---
## Schritt 1 — Bei den Entwickler-Einstellungen anmelden
1. Gehe auf **https://developer.paypal.com**
2. Oben rechts auf **Log in to Dashboard**
3. Melde dich mit deinen ganz normalen PayPal-Zugangsdaten an
(denselben wie auf paypal.com)
Du landest im *Developer Dashboard*.
---
## Schritt 2 — Auf „Live" umschalten
Oben auf der Seite gibt es einen Schalter mit zwei Stellungen:
```
Sandbox | Live
```
**Stelle ihn auf „Live".**
> Sandbox ist die Spielwiese mit Testgeld. Solange der Schalter dort
> steht, erzeugst du Zugangsdaten, mit denen **kein echtes Geld** fliesst.
> Das ist der häufigste Fehler bei dieser Einrichtung.
---
## Schritt 3 — App anlegen
1. Klicke links auf **Apps & Credentials**
2. Klicke auf **Create App**
3. **App Name:** `Dogfather Webdesign`
4. **Type:** `Merchant` (falls gefragt)
5. Klicke **Create App**
Du siehst jetzt zwei Werte:
| Feld | Was du siehst |
|---|---|
| **Client ID** | eine lange Zeichenkette, sofort sichtbar |
| **Secret** | daneben ein Link **Show** — draufklicken |
**Beide brauchst du gleich.** Kopier sie irgendwohin, wo du sie
wiederfindest — am besten direkt nach Bitwarden.
> **Das Secret ist wie ein Passwort.** Schick es mir **nicht** im Chat —
> dort stuende es dauerhaft im Verlauf, und eintragen koennte ich es
> trotzdem nicht. In Schritt 6 fuegst du es selbst ein.
---
## Schritt 4 — Webhook einrichten
Der Webhook ist die Leitung, über die PayPal uns meldet: *„Die Zahlung
ist durch."* Ohne ihn würde eine Zahlung nicht als bezahlt erscheinen,
wenn der Kunde das Fenster zu früh schliesst.
1. Auf derselben App-Seite nach unten scrollen zu **Webhooks**
2. Klicke **Add Webhook**
3. **Webhook URL** — genau das hier eintragen:
```
https://postfach.dogfather-universe.com/webdesign/paypal-webhook
```
4. Bei **Event types** wähle **diese vier** aus:
- [x] `Payment capture completed`
- [x] `Payment capture denied`
- [x] `Payment capture refunded`
- [x] `Billing subscription cancelled`
> Nicht „Select all" anklicken. Jedes zusätzliche Ereignis erzeugt
> Meldungen, die niemand auswertet — das macht die Suche nach einem
> echten Problem später unnötig schwer.
5. **Save**
6. Danach erscheint in der Liste eine **Webhook ID**. Die brauchst du
für Schritt 6.
> **Achtung, hier stand vorher etwas Falsches:** Die Webhook-ID beginnt
> **nicht** mit `WH-`. Sie sieht aus wie `0NH55953DH663215D` — rund
> 17 Zeichen, Buchstaben und Ziffern gemischt, ohne Vorsilbe.
>
> Das `WH-` steht auf den **Ereignis**-Kennungen, also den einzelnen
> Meldungen, die PayPal später schickt (`WH-3F562076HD293871E-…`). Die
> braucht man hier nicht.
---
## Schritt 5 — Nur falls du die monatliche Betreuung anbieten willst
Für einmalige Zahlungen — Anzahlung, Restbetrag, Zusatzleistungen — bist
du hier fertig. **Überspring diesen Schritt, wenn du kein monatliches
Abo verkaufst.** Du kannst ihn jederzeit nachholen.
> **Wichtig:** Abo-Pläne legst du **nicht** im Entwicklerbereich an,
> sondern in deinem normalen PayPal-Geschäftskonto. Deshalb findest du
> sie unter developer.paypal.com nicht.
1. Gehe auf **https://www.paypal.com/billing/plans**
(oder: paypal.com anmelden → Menü **Zahlungen** bzw.
**Bezahlen & bezahlt werden** → **Abonnements**)
2. **Plan erstellen** / *Create Plan*
3. Produkt anlegen: Name `Dogfather Betreuung`, Art **Dienstleistung**
4. Preis und Rhythmus: **monatlich**, dein Betreuungspreis
5. Speichern, dann **Plan aktivieren** (*Turn on plan*) — ohne das
ist er nicht nutzbar
6. Die **Plan-ID** notieren. Sie beginnt mit `P-`
---
## Schritt 6 — Werte in der Verwaltung eintragen
**Kein SSH, kein Texteditor, kein Neustart.**
1. Verwaltung öffnen: `https://dogfather-universe.com/webdesign/verwaltung.html`
2. Reiter **Zahlungen**
3. Die Felder ausfüllen:
| Feld | Woher |
|---|---|
| **Betriebsart** | *Echtbetrieb* anklicken |
| **Client ID** | aus Schritt 4 |
| **Secret** | aus Schritt 4 |
| **Webhook-Kennung** | aus Schritt 5 |
| **Plan für die Betreuung** | aus Schritt 5b — sonst leer lassen |
4. **Speichern**
> **Ein leeres Feld bedeutet „nicht anfassen", nicht „löschen".** Du
> kannst also einzeln nachtragen, ohne den Rest zu verlieren. Steht bei
> einem Feld schon *„hinterlegt (auf dem Server)"*, kommt der Wert aus
> der `.env` und du brauchst dort nichts einzugeben.
Die Werte werden verschlüsselt gespeichert und wirken sofort. Nach dem
Speichern leeren sich die Felder von selbst — ein Secret soll nicht
stehen bleiben, wenn jemand anders auf den Bildschirm schaut.
**Angezeigt wird ein gespeicherter Wert nie wieder.** Nur: *hinterlegt ·
80 Zeichen*. Wer ihn verliert, erzeugt bei PayPal einen neuen — das ist
sicherer, als ihn dauerhaft abrufbar zu halten.
---
## Schritt 7 — Verbindung testen
Gleich daneben steht der Knopf **Verbindung testen**. Draufklicken.
| Meldung | Bedeutung |
|---|---|
| „Anmeldung bei PayPal erfolgreich — Echtbetrieb." | Alles richtig, weiter zu Schritt 8 |
| „…aber im TESTMODUS" | Betriebsart auf *Echtbetrieb* stellen |
| „PayPal hat die Anmeldung abgelehnt" | Client ID und Secret stammen aus verschiedenen Apps oder aus dem Testbereich — beide aus **derselben** App neu kopieren |
> Der Test meldet sich probeweise bei PayPal an. **Es fließt kein Geld.**
> Aber erst er beweist, dass die Werte stimmen — *„hinterlegt"* heißt
> nur, dass etwas dasteht, nicht dass es richtig ist.
---
## Schritt 8 — Der erste echte Test mit 1 Euro
**Das ist der wichtigste Schritt.** Mach ihn, bevor ein echter Kunde
zahlt.
1. Verwaltung → Reiter **Kunden** → Testkunde anlegen (deine eigene
E-Mail genügt)
2. Dazu ein Projekt mit Preis **1,00 €**
3. Im Projekt eine Zahlung erzeugen
4. Den Einladungslink im eigenen Browser öffnen, Passwort setzen,
ins Portal gehen und bezahlen — mit VanVans PayPal oder per Karte
als Gast
5. Prüfen: Kommt das Geld auf deinem Konto an? Steht die Zahlung in der
Verwaltung auf **„bezahlt"**?
6. In PayPal wieder **erstatten**
7. Testkunde und Testprojekt löschen
> Der Testmodus verhält sich in Kleinigkeiten anders als der Echtbetrieb.
> Ein Durchlauf mit einem echten Euro ist der einzige Nachweis, der
> wirklich zählt — und er kostet dich nichts, weil du ihn zurückholst.
---
## Was passiert, wenn ein Kunde zahlt
1. Kunde klickt im Portal auf **Jetzt bezahlen**
2. Bei der **Anzahlung** muss er zuerst bestätigen, dass sofort begonnen
werden darf und er dadurch sein Widerrufsrecht verliert
(§ 356 Abs. 4 BGB — der genaue Wortlaut wird mit Zeitstempel
gespeichert, weil im Streit du beweisen musst, dass er zugestimmt hat)
3. Er wird zu PayPal geleitet und bezahlt
4. **Das Geld geht sofort auf dein Konto** — es gibt keine Zwischenstufe
5. Die Zahlung erscheint als „bezahlt", das Projekt vermerkt Anzahlung
bzw. Restbetrag als eingegangen
Schliesst der Kunde das Fenster zu früh, meldet der Webhook die Zahlung
trotzdem. Kommt dieselbe Meldung doppelt — was bei PayPal normal ist —
wird sie nur einmal verbucht.
---
## Wenn etwas nicht klappt
| Anzeichen | Ursache | Abhilfe |
|---|---|---|
| „noch nicht freigeschaltet" | Werte fehlen | Verwaltung → Zahlungen, dort steht welcher |
| Zahlung bleibt auf „freigegeben" | Webhook-Adresse falsch | Schritt 4 prüfen — die Adresse muss exakt stimmen |
| Kein echtes Geld | Schalter stand auf Sandbox | Schritt 2, dann neue Zugangsdaten erzeugen |
| PayPal meldet „invalid client" | Client ID und Secret aus verschiedenen Apps | beide aus derselben App neu kopieren |
---
## Zwei Dinge, die dauerhaft gelten
**Das Secret ist ein Passwort.** Es gehört nach Bitwarden, nicht in eine
Notiz, nicht in eine Nachricht, nicht ins Git. Wenn es je irgendwo
auftaucht, wo es nicht hingehört: in der App **Manage Credentials → new
secret** erzeugen und das alte löschen.
**Prüfe nach dem Umstellen auf Live einmal deinen Kontoauszug.** Nicht
weil zu erwarten wäre, dass etwas schiefgeht — sondern weil der Moment,
in dem zum ersten Mal echtes Geld fliessen kann, der richtige ist, um
einmal genau hinzusehen.
+206
View File
@@ -0,0 +1,206 @@
# Wiederherstellung des Creator Workspace
Für den Tag, an dem etwas kaputt ist. Geschrieben, damit sie auch dann
funktioniert, wenn man aufgeregt ist und keine Zeit zum Nachdenken hat.
**Der wichtigste Satz zuerst:** Die Datei `workspace.db` allein ist **nicht** die
Datenbank. Im WAL-Betrieb stehen die neuesten Änderungen in `workspace.db-wal`.
Wer nur die `.db` kopiert, kopiert unter Umständen **nichts** — genau das war am
31.08.2026 der Fall (Datenbank 4 KB, WAL 2,1 MB).
Deshalb: **Nie Dateien kopieren. Immer die fertigen Sicherungen benutzen.**
---
## Wo alles liegt
| Was | Wo |
|---|---|
| Datenbank | `/home/dogiweb/workspace-daten/workspace.db` |
| Hochgeladene Dateien | `/home/dogiweb/workspace-daten/dateien/` |
| Wissens-Bibliothek (PDFs) | `/home/dogiweb/workspace-daten/wissen/` |
| Sicherungen (Server) | `/home/dogiweb/workspace-daten/sicherungen/` |
| Sicherungen (dieser PC) | `~/Documents/Obelix/Sicherungen/workspace/` |
Aufgehoben werden **7 tägliche, 4 wöchentliche, 6 monatliche**. Geschrieben wird
jede Nacht ab 3 Uhr, geprüft direkt danach.
---
## Fall 0: „Ich komme nicht mehr rein"
Der häufigste Notfall — und der einzige, bei dem nichts kaputt ist. Passiert
am 02.09.2026: neuen Code für sich selbst erzeugt, im selben Moment abgemeldet,
Code weg, bevor er abgeschrieben war.
**Der alte Code ist nicht wiederherstellbar.** In der Datenbank steht nur seine
Prüfsumme, nirgends der Klartext — auch nicht in den Sicherungen. Es gibt nur
den Weg nach vorn: einen neuen setzen.
Auf dem Server, angemeldet als `dogi`, **ein Block**:
```
sudo -u dogiweb bash /home/dogiweb/dogfather-universe/tools/notfall-code.sh
```
Für jemand anderen den Namen anhängen, z. B.
`... notfall-code.sh "Cigdem"`. Ohne Namen nimmt es DogFather. Ein falscher
Name schadet nichts — das Skript listet dann auf, wen es gibt.
Das Skript setzt einen neuen Code, zeigt ihn an und löscht die Sperre nach
acht Fehlversuchen gleich mit (die hätte sonst 10 Minuten gekostet).
**Das `-u dogiweb` muss dranbleiben.** Als `root` ausgeführt gehören die
Hilfsdateien der Datenbank danach `root`, und der Dienst kann nicht mehr
schreiben — dann ist wirklich etwas kaputt.
Danach: Code **sofort nach Bitwarden**, nicht in eine Notiz, nicht in einen Chat.
**Warum es keinen fest hinterlegten Notfall-Code in der Anwendung gibt:** Der
wäre eine Hintertür, die dauerhaft offensteht — jeden Tag, für jeden, der sie
findet, ohne dass es auffällt. Dieser Weg verlangt Zugang zum Server,
hinterlässt einen Protokolleintrag, und es gibt nichts zu erraten.
**Seit dem 02.09.2026 sollte er kaum noch nötig sein:** Wer seinen eigenen Code
erneuert, bleibt in dieser Sitzung angemeldet (alle anderen Geräte fliegen
weiterhin hinaus), und der Kasten mit dem Code verschwindet nicht mehr von
selbst. Festgehalten in `server/pruef-code.mjs`.
---
## Fall 1: „Ich habe aus Versehen etwas gelöscht"
Nichts überstürzen. Die Sicherung von heute Nacht hat es noch.
**Erst nachsehen, ob es sich lohnt** — ohne irgendetwas anzufassen:
```
ssh dogfather-server "cd /home/dogiweb/workspace-daten/sicherungen && ls -la && for f in *.db; do echo \"--- \$f\"; sqlite3 \$f 'SELECT COUNT(*) FROM personen; SELECT COUNT(*) FROM aufgaben;'; done"
```
Dann weiter mit Fall 2.
---
## Fall 2: Datenbank zurückspielen
**Ein Block, von oben nach unten.** Er stoppt den Dienst, legt den kaputten Stand
zur Seite (nicht löschen — vielleicht braucht man ihn noch), spielt die Sicherung
ein, prüft sie und startet erst dann wieder.
`DATUM` vorher auf die gewünschte Sicherung ändern.
```
ssh dogfather-server 'DATUM=2026-08-31; S=/home/dogiweb/workspace-daten; sudo systemctl stop dogiweb.service && sleep 2 && mv $S/workspace.db $S/kaputt-$(date +%Y%m%d%H%M).db 2>/dev/null; rm -f $S/workspace.db-wal $S/workspace.db-shm; cp $S/sicherungen/taeglich-$DATUM.db $S/workspace.db && chown dogiweb:dogiweb $S/workspace.db && sqlite3 $S/workspace.db "PRAGMA integrity_check; PRAGMA foreign_key_check; SELECT COUNT(*) || \" Personen\" FROM personen;" && sudo systemctl start dogiweb.service && sleep 3 && systemctl is-active dogiweb.service'
```
Danach **auf der echten Domain nachsehen**, nicht nur auf die Erfolgsmeldung
vertrauen:
```
curl -s -o /dev/null -w "%{http_code}\n" https://dogfather-universe.com/workspace/ && curl -sI https://dogfather-universe.com/ | grep -i via
```
**Wichtig:** `mv` statt `rm`. Die kaputte Datei bleibt als `kaputt-…db` liegen.
Wenn sich herausstellt, dass die Sicherung älter war als gedacht, kann man
daraus noch Einzelnes herausholen. Später von Hand aufräumen.
---
## Fall 3: Der Server ist ganz weg
Dann liegt die letzte Sicherung auf diesem PC. Zuerst holen, was noch geht —
falls der Server noch antwortet:
```
bash ~/Documents/Obelix/DogiHompage/tools/sicherung-holen.sh
```
Wiederaufbau in dieser Reihenfolge:
1. Server neu aufsetzen, Benutzer `dogiweb` anlegen (**macht Filipe**, nicht ich —
siehe `CLAUDE.md`)
2. `git clone` von Gitea nach `/home/dogiweb/dogfather-universe`
3. Ordner `/home/dogiweb/workspace-daten/` anlegen
4. Neueste Sicherung von diesem PC hochladen:
```
scp ~/Documents/Obelix/Sicherungen/workspace/taeglich-*.db dogfather-server:/home/dogiweb/workspace-daten/workspace.db
```
5. `dogiweb.service` und Caddy einrichten, Dienst starten
6. Auf `https://dogfather-universe.com/workspace/` anmelden und prüfen
7. Hochgeladene Dateien und Bibliothek zurückspielen — die stecken **nicht** in
der Datenbanksicherung, sondern liegen als Dateien daneben:
```
scp -r ~/Documents/Obelix/Sicherungen/workspace/dateien/. dogfather-server:/home/dogiweb/workspace-daten/dateien/ && scp -r ~/Documents/Obelix/Sicherungen/workspace/wissen/. dogfather-server:/home/dogiweb/workspace-daten/wissen/
```
---
## Sicherungen auf diesen PC holen
**Das läuft von allein** — täglich um 13:30 über die Windows-Aufgabenplanung
(„Dogfather Workspace - Sicherung holen"). War der Rechner zu der Zeit aus, holt
Windows den Lauf beim nächsten Hochfahren nach.
Eingerichtet wurde das einmalig mit:
```
powershell -ExecutionPolicy Bypass -File ~/Documents/Obelix/DogiHompage/tools/sicherung-einrichten.ps1
```
Von Hand anstoßen geht trotzdem jederzeit:
```
bash ~/Documents/Obelix/DogiHompage/tools/sicherung-holen.sh
```
Holt **drei** Dinge: die Datenbanksicherungen, die hochgeladenen Dateien und die
PDFs der Bibliothek. Prüft danach jede Datenbankdatei sofort auf Unversehrtheit und
darauf, dass wirklich Personen darin stehen — und sagt es, wenn etwas nicht stimmt.
**Warum die Dateien nur hier landen und nicht auch auf dem Server:** Eine zweite
Kopie auf derselben Platte hilft gegen nichts, was die erste nicht schon überlebt
hätte. Und weil `scp` nie löscht, bleibt ein hier einmal geholtes PDF erhalten,
auch wenn es auf dem Server verschwindet.
---
## Von Hand sichern, bevor man etwas Größeres anfasst
Im Workspace unter **Automationen → Sicherung & Zustand → „Jetzt sichern"**.
Dauert Millisekunden. Oder über die Kommandozeile:
```
ssh dogfather-server "sudo systemctl status dogiweb.service --no-pager | head -3"
```
---
## Was noch fehlt
- **Nur ein Ort.** Server und dieser PC stehen beide bei uns. Gegen Feuer oder
Diebstahl hilft das nicht. Eine verschlüsselte Kopie an einem dritten Ort wäre
die Ausbaustufe — kostenlos möglich, aber eine eigene Entscheidung.
---
## Woran man sieht, dass es noch läuft
Im Workspace unter **Automationen → Sicherung & Zustand**. Dort steht in der Zeile
**„Kopie außer Haus"**, wann dieser Rechner zuletzt geholt hat.
Kommt zehn Tage lang nichts, wird der Kasten gelb und nennt den Grund. Das ist der
eigentliche Zweck der Rückmeldung: Eine Sicherung, die still aufhört zu laufen, ist
gefährlicher als gar keine — weil man sich auf sie verlässt.
Prüfen, ob die Aufgabe eingerichtet ist:
```
powershell -Command "Get-ScheduledTaskInfo -TaskName 'Dogfather Workspace - Sicherung holen' | Select-Object LastRunTime, LastTaskResult, NextRunTime"
```
`LastTaskResult` muss **0** sein. Jeder Lauf steht außerdem in
`~/Documents/Obelix/Sicherungen/workspace/lauf-protokoll.txt` — auch die
gescheiterten. Ohne das wäre hinterher nicht zu klären, ob die Aufgabe gar nicht
lief oder ob sie lief und scheiterte. Das sind zwei sehr verschiedene Fehler.
+302 -45
View File
@@ -5,9 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DogiCrew 🩵 — DOGFATHER UNIVERSE</title> <title>DogiCrew 🩵 — DOGFATHER UNIVERSE</title>
<meta name="description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." /> <meta name="description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<link rel="icon" type="image/png" href="assets/img/favicon.png" /> <link rel="icon" type="image/png" href="/assets/img/app-symbole/universe-32.png?v=202610012001" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/universe-180.png?v=202610012001" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d10" /> <meta name="theme-color" content="#065f76" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="DOGFATHER UNIVERSE" /> <meta property="og:site_name" content="DOGFATHER UNIVERSE" />
<meta property="og:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" /> <meta property="og:title" content="DogiCrew 🩵 — DOGFATHER UNIVERSE" />
@@ -19,10 +20,10 @@
<meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." /> <meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" /> <meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<link rel="stylesheet" href="assets/css/main.css" /> <link rel="stylesheet" href="assets/css/main.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" /> <link rel="stylesheet" href="assets/css/theme-dogfather.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" /> <link rel="stylesheet" href="assets/css/theme-hasidog.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" /> <link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=202610012001" />
<style> <style>
/* ===================================================================== /* =====================================================================
Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback
@@ -91,7 +92,7 @@
darunter sauber lesbar bleiben (Nutzer-Feedback: Logo lag vorher darunter sauber lesbar bleiben (Nutzer-Feedback: Logo lag vorher
über dem Namensfeld). */ über dem Namensfeld). */
position: absolute; top: 0; left: 0; right: 0; height: 420px; z-index: -1; pointer-events: none; position: absolute; top: 0; left: 0; right: 0; height: 420px; z-index: -1; pointer-events: none;
background-image: url('assets/img/logo-dogfather-transparent.png'); background-image: url('assets/img/logo-dogfather-transparent.png?v=202610012001');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center 6%; background-position: center 6%;
background-size: min(62%, 320px) auto; background-size: min(62%, 320px) auto;
@@ -216,6 +217,104 @@
.abo-switch a { color: var(--accent); cursor: pointer; font-weight: 600; } .abo-switch a { color: var(--accent); cursor: pointer; font-weight: 600; }
.abo-switch a:hover { text-decoration: underline; } .abo-switch a:hover { text-decoration: underline; }
/* Registrieren/Einloggen-Umschalter (21.08.2026, Nutzer-Wunsch: "die
sollen dann sofort immer den anmelde knopf auswählen können") — zwei
Segmente in einer Pille, aktiver Tab in Gold hervorgehoben, damit die
Wahl sofort ins Auge fällt, noch bevor überhaupt ein Formularfeld zu
sehen ist. Augenschonend: kein grelles Weiß, ruhiger Farbwechsel. */
/* =====================================================================
Aktionsleiste (21.08.2026) — EIN Element für beide Wege, statt vorher
doppeltem "Registrieren" (Umschalter oben + Knopf unten). Links die
eigentliche Aktion in Gold (unverändert im bestehenden Marken-Look),
rechts der Wechsel in Babyblau — der zweiten Hausfarbe der Seite
(theme-dogfather.css). Beide Hälften nutzen dieselbe Technik wie die
bestehenden Gold-Knöpfe (wandernder Verlauf per background-position +
ein durchlaufender Glanzstreifen als ::after) — dadurch wirken sie wie
ein zusammengehöriges Paar statt wie zwei fremde Knöpfe.
Augenschonend (Projektregel): kein Blinken/Flackern, nur ruhig
wandernde Verläufe, und bei prefers-reduced-motion steht alles still.
===================================================================== */
.abo-aktionsleiste {
display: flex; gap: .6rem; margin-top: .4rem;
}
/* flex-basis "auto" statt "0": jede Hälfte startet bei ihrer eigenen
Textbreite und wächst dann anteilig mit. Dadurch bekommt automatisch
die Seite mit dem längeren Text mehr Platz — egal ob das gerade links
("Login-Code anfordern") oder rechts ("Schon registriert? Einloggen")
ist. Mit fester 0-Basis wären beide exakt gleich breit gewesen und der
jeweils längere Text wäre auf zwei Zeilen umgebrochen. */
.abo-aktionsleiste > button {
position: relative; isolation: isolate; overflow: hidden;
flex: 1 1 auto; min-width: 0;
display: flex; align-items: center; justify-content: center; text-align: center;
padding: 1rem .95rem; border-radius: 14px;
font-weight: 800; font-size: .92rem; line-height: 1.25;
white-space: nowrap;
cursor: pointer;
transition: transform .2s ease, box-shadow .2s ease;
}
.abo-aktionsleiste > button::after {
content: ""; position: absolute; inset: 0; z-index: 1;
background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.85) 48%, transparent 66%);
background-size: 240% 100%;
mix-blend-mode: overlay;
animation: abo-btn-glare 3.2s ease-in-out infinite;
pointer-events: none;
}
.abo-aktionsleiste > button:hover { transform: translateY(-3px) scale(1.015); }
/* Links: Gold — exakt die bestehende Knopf-Optik der Seite. */
.abo-aktion-haupt {
color: #1a1408;
border: 1.5px solid rgba(255,233,168,.65);
background: linear-gradient(120deg, #ffe9a8 0%, #d4af37 30%, #ffe9a8 55%, #fff2c9 78%, #d4af37 100%);
background-size: 280% 100%;
animation: abo-btn-shine 6s ease-in-out infinite;
box-shadow: 0 10px 26px -12px rgba(212,175,55,.55);
}
.abo-aktion-haupt:hover {
box-shadow: 0 16px 34px -10px rgba(212,175,55,.65), 0 0 26px rgba(212,175,55,.4);
}
/* Babyblau — gleiche Machart, kräftigeres Sky-Blau statt des sehr
blassen Standard-Babyblaus, damit es neben dem Gold nicht untergeht
(dieselbe Lektion wie auf der Verwaltungsseite). Dunkler Tiefsee-Text
darauf für klaren Kontrast; zusätzlich ein sanft atmender Ring, der die
Kachel leicht leuchten lässt, ohne zu blenden.
Zwei Namen, eine Optik: ".abo-aktion-neben" ist der Wechsel-Knopf neben
einer Gold-Aktion (Registrierungs-Seite), ".abo-aktion-blau" ist ein
Knopf, der selbst DIE Hauptaktion ist und trotzdem blau sein soll
(Einloggen-Seite, Nutzer-Wunsch 21.08.2026). Bewusst getrennte Namen,
damit später klar bleibt, warum ein Knopf blau ist. */
.abo-aktion-neben,
.abo-aktion-blau {
color: #05202b;
border: 1.5px solid rgba(224,247,254,.7);
background: linear-gradient(120deg, #e0f7fe 0%, #38bdf8 30%, #7dd3fc 55%, #f0fbff 78%, #38bdf8 100%);
background-size: 280% 100%;
animation: abo-btn-shine 6s ease-in-out infinite, abo-blau-atem 4.5s ease-in-out infinite;
box-shadow: 0 10px 26px -12px rgba(56,189,248,.6), 0 0 0 0 rgba(125,211,252,.5);
}
.abo-aktion-neben:hover,
.abo-aktion-blau:hover {
box-shadow: 0 16px 34px -10px rgba(56,189,248,.75), 0 0 30px rgba(125,211,252,.55);
}
@keyframes abo-blau-atem {
0%, 100% { box-shadow: 0 10px 26px -12px rgba(56,189,248,.55), 0 0 14px rgba(125,211,252,.25); }
50% { box-shadow: 0 12px 30px -12px rgba(56,189,248,.75), 0 0 26px rgba(125,211,252,.5); }
}
@media (prefers-reduced-motion: reduce) {
.abo-aktionsleiste > button,
.abo-aktionsleiste > button::after { animation: none; }
}
/* Auf schmalen Handys untereinander statt gequetscht nebeneinander. */
@media (max-width: 430px) {
.abo-aktionsleiste { flex-direction: column; gap: .55rem; }
.abo-aktionsleiste > button { font-size: .92rem; }
}
.abo-oder { .abo-oder {
display: flex; align-items: center; gap: .8rem; display: flex; align-items: center; gap: .8rem;
color: var(--text-muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
@@ -246,12 +345,12 @@
.abo-vorteile li::before { content: "👑"; flex-shrink: 0; } .abo-vorteile li::before { content: "👑"; flex-shrink: 0; }
</style> </style>
</head> </head>
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-abonnieren.jpg');--page-bg-mobile:url('/assets/img/bg-abonnieren-mobile.jpg');"> <body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-abonnieren.jpg?v=202610012001');--page-bg-mobile:url('/assets/img/bg-abonnieren-mobile.jpg?v=202610012001');">
<div id="site-header"></div> <div id="site-header"></div>
<main> <main>
<section class="hero page-bg"> <section class="hero page-bg">
<div class="hero-banner"><img src="/assets/img/bg-abonnieren.jpg" alt="Dogfather Supporter-Abo" loading="eager" /></div> <div class="hero-banner"><img src="/assets/img/bg-abonnieren.jpg?v=202610012001" alt="Dogfather Supporter-Abo" loading="eager" /></div>
<div class="container"> <div class="container">
<span class="eyebrow" data-i18n="ab_eyebrow">👑 DogiCrew 🩵</span> <span class="eyebrow" data-i18n="ab_eyebrow">👑 DogiCrew 🩵</span>
<h1 data-i18n="ab_h1">Mehr als ein Abo — deine Unterstützung wird Teil unserer Geschichte</h1> <h1 data-i18n="ab_h1">Mehr als ein Abo — deine Unterstützung wird Teil unserer Geschichte</h1>
@@ -265,7 +364,12 @@
<div class="abo-logo-glut" aria-hidden="true"></div> <div class="abo-logo-glut" aria-hidden="true"></div>
<div class="abo-logo-wz" aria-hidden="true"></div> <div class="abo-logo-wz" aria-hidden="true"></div>
<span class="eyebrow" data-i18n="ab_preis_eyebrow">DogiCrew 🩵</span> <span class="eyebrow" data-i18n="ab_preis_eyebrow">DogiCrew 🩵</span>
<div class="abo-preis-zahl">4,99 € <small data-i18n="ab_preis_pro_monat">/ Monat</small></div> <!-- Bugfix/Nutzer-Wunsch 20.08.2026: Preis noch NICHT zeigen, solange die
Registrierung gesperrt ist (siehe .btn-gold-locked weiter unten) — sonst
wäre der Preis schon öffentlich, bevor überhaupt jemand abschließen kann.
Gleicher Chrome-Gold-Schimmer-Text wie beim gesperrten Knopf
(.btn-gold-locked-text), hier freistehend statt in einem Knopf. -->
<div class="abo-preis-zahl"><span class="btn-gold-locked-text" style="font-size:1em;" data-i18n="ab_kollektion_coming_soon">Coming soon…</span></div>
<p class="small muted" style="margin-top:-.6rem;margin-bottom:1rem;">Keine gesondert ausgewiesene MwSt. gemäß Kleinunternehmerregelung (Art. 57 des luxemburgischen TVA-Gesetzes) — keine weiteren Kosten.</p> <p class="small muted" style="margin-top:-.6rem;margin-bottom:1rem;">Keine gesondert ausgewiesene MwSt. gemäß Kleinunternehmerregelung (Art. 57 des luxemburgischen TVA-Gesetzes) — keine weiteren Kosten.</p>
<ul class="abo-bedingungen"> <ul class="abo-bedingungen">
<li data-i18n="ab_bed1">Monatliche automatische Zahlung über PayPal</li> <li data-i18n="ab_bed1">Monatliche automatische Zahlung über PayPal</li>
@@ -308,6 +412,12 @@
<!-- Zustand 2: Registrierung --> <!-- Zustand 2: Registrierung -->
<div class="abo-panel" id="panel-register" hidden> <div class="abo-panel" id="panel-register" hidden>
<!-- Bugfix/Nutzer-Wunsch 20.08.2026 (Nachpruefung): Nur der Knopf war
gesperrt, die drei Felder ließen sich trotzdem antippen und
beschreiben ("ich kann immer nur was rein tippen, soll garnicht
möglich sein"). Jetzt wie das E-Mail-Feld im Login-Panel: disabled
statt nur readonly, damit auch Tastatur-/Screenreader-Nutzung
korrekt "nicht bedienbar" meldet. -->
<div class="abo-field"> <div class="abo-field">
<label for="reg-name" data-i18n="ab_feld_name">Name oder Anzeigename</label> <label for="reg-name" data-i18n="ab_feld_name">Name oder Anzeigename</label>
<input type="text" id="reg-name" maxlength="60" /> <input type="text" id="reg-name" maxlength="60" />
@@ -320,23 +430,68 @@
<label for="reg-email" data-i18n="ab_feld_email">E-Mail-Adresse</label> <label for="reg-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
<input type="email" id="reg-email" maxlength="120" /> <input type="email" id="reg-email" maxlength="120" />
</div> </div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-register" data-i18n="ab_btn_register">Registrieren</button> <!-- Das Zugangscode-Feld stand bis 21.08.2026 hier, direkt neben den
Stammdaten. Es ist bewusst in einen eigenen, SPÄTEREN Schritt
gewandert (Nutzer-Wunsch: "bei der ersten registrierung sollen
die eine email bekommen mit einem einmaligen code damit wir auch
wissen dass email stimmt und danach wenn sie den code eingegeben
haben sollen die erst ihren zugangscode auswählen/eintippen
können"). Ablauf jetzt: hier Stammdaten -> Einmalcode per Mail
(#panel-code) -> Zugangscode festlegen (#panel-neuer-code). -->
<p class="small muted" style="margin:-.2rem 0 .2rem;" data-i18n="ab_reg_hinweis_bestaetigung">Wir schicken dir gleich einen 6-stelligen Code per E-Mail. Danach legst du deinen eigenen Zugangscode fest.</p>
<!-- Nutzer-Wunsch 21.08.2026: "die leute sollen sich auch schon
registrieren können, aber der abo soll noch zu sein, da soll
dann coming soon stehen." Registrierung/Login sind ab jetzt
offen -- Konten können angelegt werden. Gesperrt bleibt NUR
noch der eigentliche Zahlungsschritt danach (siehe
panel-subscribe weiter unten), weil ohne Dogis echte PayPal-
Business-Zugangsdaten niemand wirklich zahlen kann. Wieder
normaler .btn-primary-Stil statt .btn-gold-locked. -->
<!-- Aktionsleiste (21.08.2026, Nutzer-Wunsch: "bringt nichts 2 mal
registrieren da zu haben"). EIN Element statt vorher Umschalter
oben + Knopf unten: links die eigentliche Aktion in Gold,
rechts der Wechsel zum Einloggen in Babyblau. Beide Hälften
sind immer aktiv (kein Tab-Zustand) — links macht etwas,
rechts wechselt die Ansicht. -->
<div class="abo-aktionsleiste">
<button type="button" class="abo-aktion-haupt" id="btn-register" data-i18n="ab_btn_register">Registrieren</button>
<button type="button" class="abo-aktion-neben" id="tab-login" data-i18n="ab_tab_login">Schon registriert? Einloggen</button>
</div>
<p class="abo-fehler" id="register-fehler"></p> <p class="abo-fehler" id="register-fehler"></p>
<p class="abo-switch"><a id="switch-to-login" data-i18n="ab_switch_login">Schon Supporter? Hier einloggen</a></p>
</div> </div>
<!-- Zustand 3: Login (E-Mail-Code anfordern) --> <!-- Zustand 3: Einloggen mit E-Mail + eigenem Zugangscode.
Umgestellt 21.08.2026 (Nutzer-Wunsch: "wieso sollte ich wieder
ein code bekommen, mach die anmeldung einfach"): vorher wurde
auch hier bei JEDEM Login erst ein Einmalcode per E-Mail
verschickt — für längst registrierte Leute ein völlig
unnötiger Umweg. Der E-Mail-Weg existiert weiterhin, aber nur
noch als "Code vergessen?" (siehe Link unten). -->
<div class="abo-panel" id="panel-login" hidden> <div class="abo-panel" id="panel-login" hidden>
<div class="abo-field"> <div class="abo-field">
<label for="login-email" data-i18n="ab_feld_email">E-Mail-Adresse</label> <label for="login-email" data-i18n="ab_feld_email">E-Mail-Adresse</label>
<input type="email" id="login-email" maxlength="120" /> <input type="email" id="login-email" maxlength="120" autocomplete="email" />
</div>
<div class="abo-field">
<label for="login-code" data-i18n="ab_feld_code_eigen">Dein Zugangscode</label>
<input type="password" id="login-code" maxlength="200" autocomplete="current-password" />
</div>
<!-- Nutzer-Wunsch 21.08.2026: "da soll nur noch einloggen sein und
der knopf soll auch blau sein, der neu registriert soll weg."
Hier steht deshalb nur EIN Knopf, in Babyblau statt Gold —
wer auf dieser Ansicht gelandet ist, will einloggen; der Weg
zurück zur Registrierung führt über den Zurück-Knopf des
Browsers bzw. den blauen Knopf auf der Registrierungs-Seite. -->
<div class="abo-aktionsleiste">
<button type="button" class="abo-aktion-blau" id="btn-login" data-i18n="ab_btn_login">Einloggen</button>
</div> </div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-login-request" data-i18n="ab_btn_login_code">Login-Code anfordern</button>
<p class="abo-fehler" id="login-fehler"></p> <p class="abo-fehler" id="login-fehler"></p>
<p class="abo-switch"><a id="switch-to-register" data-i18n="ab_switch_register">Noch kein Konto? Jetzt registrieren</a></p> <p class="abo-switch"><a id="code-vergessen" data-i18n="ab_code_vergessen">Code vergessen?</a></p>
</div> </div>
<!-- Zustand 4: Code-Eingabe (nach Registrierung ODER Login-Anfrage) --> <!-- Zustand 4: Einmalcode aus der E-Mail eingeben. Kommt seit
21.08.2026 NUR noch im "Code vergessen?"-Weg vor — die normale
Registrierung/Anmeldung braucht ihn nicht mehr. -->
<div class="abo-panel" id="panel-code" hidden> <div class="abo-panel" id="panel-code" hidden>
<p class="small" id="code-hinweis" data-i18n="ab_code_hinweis">Wir haben dir einen 6-stelligen Code per E-Mail geschickt.</p> <p class="small" id="code-hinweis" data-i18n="ab_code_hinweis">Wir haben dir einen 6-stelligen Code per E-Mail geschickt.</p>
<div class="abo-field"> <div class="abo-field">
@@ -347,6 +502,20 @@
<p class="abo-fehler" id="code-fehler"></p> <p class="abo-fehler" id="code-fehler"></p>
</div> </div>
<!-- Zustand 4b: neuen dauerhaften Zugangscode festlegen. Letzter
Schritt des "Code vergessen?"-Weges — an dieser Stelle ist man
durch den Einmalcode bereits eingeloggt, es fehlt nur noch der
neue Code für künftige Anmeldungen. -->
<div class="abo-panel" id="panel-neuer-code" hidden>
<p class="small" data-i18n="ab_neuer_code_hinweis">Fast fertig — leg jetzt deinen neuen Zugangscode fest.</p>
<div class="abo-field">
<label for="neuer-code" data-i18n="ab_feld_code_neu">Dein Zugangscode (mindestens 6 Zeichen)</label>
<input type="password" id="neuer-code" maxlength="200" autocomplete="new-password" />
</div>
<button type="button" class="btn btn-primary" style="width:100%;" id="btn-neuer-code" data-i18n="ab_btn_code_speichern">Zugangscode speichern</button>
<p class="abo-fehler" id="neuer-code-fehler"></p>
</div>
<!-- Zustand 5: eingeloggt, noch kein Abo -> PayPal Smart Buttons. <!-- Zustand 5: eingeloggt, noch kein Abo -> PayPal Smart Buttons.
Zeigt automatisch alle für die Käuferin/den Käufer verfügbaren Zeigt automatisch alle für die Käuferin/den Käufer verfügbaren
Zahlarten (PayPal-Konto, Kreditkarte als Gast, je nach Land) — Zahlarten (PayPal-Konto, Kreditkarte als Gast, je nach Land) —
@@ -354,15 +523,35 @@
<div class="abo-panel" id="panel-subscribe" hidden> <div class="abo-panel" id="panel-subscribe" hidden>
<p class="abo-erfolg zeige" data-i18n="ab_eingeloggt_als">Eingeloggt.</p> <p class="abo-erfolg zeige" data-i18n="ab_eingeloggt_als">Eingeloggt.</p>
<!-- Button-Lösung (§ 312j BGB / entspr. Regelung): Preis- und <!-- Nutzer-Wunsch 21.08.2026: "die leute sollen sich schon registrieren
Zahlungspflicht-Hinweis unmittelbar vor der Zahlung. --> können, aber der abo soll noch zu sein, da soll dann coming soon
<p class="small" style="text-align:center;font-weight:700;margin-bottom:.8rem;">4,99 € / Monat · zahlungspflichtiges Abo · monatlich kündbar</p> stehen." Konto ist angelegt/Login hat geklappt -- aber die eigent-
liche Zahlung (PayPal) bleibt gesperrt, bis Dogis echte PayPal-
Business-Zugangsdaten stehen. Die echten Zahlungs-Elemente (Preis-
Hinweis, Widerrufs-Checkbox, PayPal-Container) bleiben unten UNVER-
ÄNDERT im DOM (nur per hidden versteckt), damit das Skript weiter
unten (Checkbox-Listener, ladePaypalButtons() usw.) unangetastet
funktioniert -- einfach das hidden am Wrapper unten entfernen,
sobald PayPal bereitsteht. -->
<div class="btn-gold-locked" style="width:100%;margin-top:.4rem;cursor:default;">
<span class="btn-gold-locked-lock" aria-hidden="true">🔒</span>
<span class="btn-gold-locked-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span>
</div>
<p class="small muted" style="text-align:center;margin-top:.9rem;" data-i18n="ab_subscribe_locked_hinweis">Dein Konto ist bereit — die Bezahlung startet, sobald das Abo offiziell live geht. Schau einfach bald wieder vorbei.</p>
<!-- Widerrufsrecht bei digitalen Inhalten (§ 356 Abs. 5 BGB / <!-- Nutzer-Wunsch 21.08.2026: "ich will dass jetzt alles verbunden
entspr. Regelung, siehe agb.html Ziffer 6): ohne aktives ist so dass man mit den klicks pro klick weiter kommt" — vorher
Ankreuzen bleibt der Zahlungsbereich gesperrt, es gibt keine war hier eine Sackgasse (kein Link/Knopf mehr nach dem Login).
Zahlung ohne diese ausdrückliche, nicht vorausgewählte Jetzt zwei klare Wege weiter: zurück zur Startseite, oder
Zustimmung. --> direkt zum Streamplan (naheliegendster nächster Klick für
jemanden, der sich gerade für Dogi interessiert). -->
<div class="btn-row" style="justify-content:center;margin-top:1.4rem;">
<a class="btn btn-outline" href="index.html" data-i18n="ab_weiter_startseite">Zur Startseite →</a>
<a class="btn btn-outline" href="streamplan.html" data-i18n="ab_weiter_streamplan">Zum Streamplan →</a>
</div>
<div hidden>
<p class="small" style="text-align:center;font-weight:700;margin-bottom:.8rem;">4,99 € / Monat · zahlungspflichtiges Abo · monatlich kündbar</p>
<label class="abo-widerruf-check" for="widerruf-consent"> <label class="abo-widerruf-check" for="widerruf-consent">
<input type="checkbox" id="widerruf-consent" /> <input type="checkbox" id="widerruf-consent" />
<span>Ich wünsche ausdrücklich, dass der Zugang zum Supporter-Bereich sofort mit Vertragsschluss beginnt, und weiß, dass mein 14-tägiges Widerrufsrecht dadurch erlischt, sobald der Zugang vollständig bereitgestellt ist (Details in den <a href="agb.html" target="_blank" rel="noopener">AGB</a>, Ziffer 6).</span> <span>Ich wünsche ausdrücklich, dass der Zugang zum Supporter-Bereich sofort mit Vertragsschluss beginnt, und weiß, dass mein 14-tägiges Widerrufsrecht dadurch erlischt, sobald der Zugang vollständig bereitgestellt ist (Details in den <a href="agb.html" target="_blank" rel="noopener">AGB</a>, Ziffer 6).</span>
@@ -373,6 +562,7 @@
<p class="small" id="paypal-laedt" data-i18n="ab_paypal_laedt" hidden>Zahlungsoptionen werden geladen …</p> <p class="small" id="paypal-laedt" data-i18n="ab_paypal_laedt" hidden>Zahlungsoptionen werden geladen …</p>
<p class="abo-fehler" id="subscribe-fehler"></p> <p class="abo-fehler" id="subscribe-fehler"></p>
</div> </div>
</div>
<!-- Zustand 6: bereits Supporter --> <!-- Zustand 6: bereits Supporter -->
<div class="abo-panel" id="panel-already" hidden> <div class="abo-panel" id="panel-already" hidden>
@@ -387,7 +577,10 @@
<div class="container grid grid-2"> <div class="container grid grid-2">
<div class="card"> <div class="card">
<p data-i18n="ab_text1">Dieses Abonnement ist kein gewöhnlicher Shop und kein einfacher Kauf. Es ist für die Menschen gedacht, die Dogfather dauerhaft unterstützen und ein besonderer Teil dieser gemeinsamen Reise sein möchten.</p> <p data-i18n="ab_text1">Dieses Abonnement ist kein gewöhnlicher Shop und kein einfacher Kauf. Es ist für die Menschen gedacht, die Dogfather dauerhaft unterstützen und ein besonderer Teil dieser gemeinsamen Reise sein möchten.</p>
<p data-i18n="ab_text2">Für 4,99 € im Monat erhältst du Zugang zu einem exklusiven Supporter-Bereich, besonderen Inhalten und einer persönlichen Treuekollektion. Mit jedem erfolgreich bezahlten Meilenstein wächst deine Sammlung: vom kleinen Hasen-Teddy über besondere Jubiläumsprämien bis zum exklusiven Hoodie nach 30 Monaten. Danach beginnt für dich eine neue Kollektion — mit neuen Designs, neuen Erinnerungen und derselben Bedeutung.</p> <!-- Bugfix/Nutzer-Wunsch 20.08.2026: "4,99 €" hier entfernt (nur die Zahl, Rest
des Satzes unverändert) — sonst hätte der eigentlich gesperrte Preis
weiter oben in der Preis-Box hier im Fließtext trotzdem gestanden. -->
<p data-i18n="ab_text2">Mit deinem monatlichen Beitrag erhältst du Zugang zu einem exklusiven Supporter-Bereich, besonderen Inhalten und einer persönlichen Treuekollektion. Mit jedem erfolgreich bezahlten Meilenstein wächst deine Sammlung: vom kleinen Hasen-Teddy über besondere Jubiläumsprämien bis zum exklusiven Hoodie nach 30 Monaten. Danach beginnt für dich eine neue Kollektion — mit neuen Designs, neuen Erinnerungen und derselben Bedeutung.</p>
<ul class="abo-vorteile"> <ul class="abo-vorteile">
<li data-i18n="ab_vorteil1">Exklusiver Supporter-Bereich</li> <li data-i18n="ab_vorteil1">Exklusiver Supporter-Bereich</li>
<li data-i18n="ab_vorteil2">Kleiner Hasen-Teddy nach 6 bezahlten Monaten</li> <li data-i18n="ab_vorteil2">Kleiner Hasen-Teddy nach 6 bezahlten Monaten</li>
@@ -403,7 +596,7 @@
<h2 data-i18n="ab_vanvan_h2">Die Teddy-Kollektion — in Kooperation mit VanVan</h2> <h2 data-i18n="ab_vanvan_h2">Die Teddy-Kollektion — in Kooperation mit VanVan</h2>
<p data-i18n="ab_vanvan_text">Die DogiCrew 🩵 gehört Dogfather. Die Hasen-Teddys und die dazugehörigen Sammlerkollektionen entstehen jedoch in Zusammenarbeit mit VanVan — der rechten Hand von Dogfather, seiner wichtigsten Vertrauensperson und einem festen Bestandteil der Team-Dogi-Familie. Sie stehen für ihre besondere Rolle, den Zusammenhalt innerhalb der Community und die Verbindung zwischen Dogfather, VanVan und allen Menschen, die diesen gemeinsamen Weg dauerhaft unterstützen.</p> <p data-i18n="ab_vanvan_text">Die DogiCrew 🩵 gehört Dogfather. Die Hasen-Teddys und die dazugehörigen Sammlerkollektionen entstehen jedoch in Zusammenarbeit mit VanVan — der rechten Hand von Dogfather, seiner wichtigsten Vertrauensperson und einem festen Bestandteil der Team-Dogi-Familie. Sie stehen für ihre besondere Rolle, den Zusammenhalt innerhalb der Community und die Verbindung zwischen Dogfather, VanVan und allen Menschen, die diesen gemeinsamen Weg dauerhaft unterstützen.</p>
<div style="display:flex;justify-content:flex-end;margin-top:1.4rem;"> <div style="display:flex;justify-content:flex-end;margin-top:1.4rem;">
<a class="btn-silver" href="#" aria-disabled="true" onclick="return false;"><span class="btn-silver-spark" aria-hidden="true">✨</span><span class="btn-silver-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span><span class="btn-silver-spark" aria-hidden="true">✨</span></a> <a class="btn-silver" aria-disabled="true"><span class="btn-silver-spark" aria-hidden="true">✨</span><span class="btn-silver-text" data-i18n="ab_kollektion_coming_soon">Coming soon…</span><span class="btn-silver-spark" aria-hidden="true">✨</span></a>
</div> </div>
</div> </div>
</div> </div>
@@ -411,13 +604,13 @@
</main> </main>
<div id="site-footer"></div> <div id="site-footer"></div>
<script src="assets/js/i18n-abonnieren.js"></script> <script src="assets/js/i18n-abonnieren.js?v=202610012001"></script>
<script src="assets/js/supporter.js"></script> <script src="assets/js/supporter.js?v=202610012001"></script>
<script src="assets/js/main.js"></script> <script src="assets/js/main.js?v=202610012001"></script>
<script> <script>
(function () { (function () {
const S = window.DogiSupporter; const S = window.DogiSupporter;
const panels = ["panel-lade", "panel-register", "panel-login", "panel-code", "panel-subscribe", "panel-already"]; const panels = ["panel-lade", "panel-register", "panel-login", "panel-code", "panel-neuer-code", "panel-subscribe", "panel-already"];
// panel-social-login (Google-Button) hängt sich an register/login dran, // panel-social-login (Google-Button) hängt sich an register/login dran,
// ist aber kein "richtiger" exklusiver Zustand — separat gesteuert. // ist aber kein "richtiger" exklusiver Zustand — separat gesteuert.
const SOCIAL_LOGIN_PANELS = ["panel-register", "panel-login"]; const SOCIAL_LOGIN_PANELS = ["panel-register", "panel-login"];
@@ -455,8 +648,14 @@
el.classList.remove("zeige"); el.classList.remove("zeige");
} }
let codePurpose = "verify_email"; // oder "login" // Merkt sich die E-Mail-Adresse zwischen "Code vergessen?" und der
// Eingabe des Einmalcodes (der frühere codePurpose-Schalter entfiel mit
// der Umstellung 21.08.2026 — es gibt nur noch diesen einen Code-Weg).
let codeEmail = ""; let codeEmail = "";
// Merkt sich, WARUM gerade ein Einmalcode eingegeben wird (21.08.2026):
// "register" = Erstbestätigung der E-Mail, "login" = "Code vergessen?".
// Steuert in btn-code-verify, welcher Endpunkt aufgerufen wird.
let codeZweck = "login";
async function pruefeStatus() { async function pruefeStatus() {
if (!S.getToken()) { if (!S.getToken()) {
@@ -468,11 +667,24 @@
const status = data.subscription?.status || "none"; const status = data.subscription?.status || "none";
S.cacheSubStatus(status); S.cacheSubStatus(status);
S.cacheDisplayName(data.profile?.displayName || ""); S.cacheDisplayName(data.profile?.displayName || "");
if (["active", "pending", "suspended", "cancelled"].includes(status)) { /* Nutzer-Wunsch 21.08.2026: "anstatt das was du jetzt auf dem screen
zeige("panel-already"); siehst, sollen die leute nicht mehr sehen wenn sie angemeldet sind.
} else { sie sollen die richtige seite sehen die wir schon mal vorbereitet
zeige("panel-subscribe"); hatten, wo sie ihre persönliche daten sehen und so."
}
Wer eingeloggt ist, gehört nicht mehr auf diese Anmeldeseite —
egal ob mit oder ohne bezahltes Abo. supporter.html zeigt in BEIDEN
Fällen das Richtige: persönliche Daten, Fortschritt mit allen
Prämien-Meilensteinen, Sammlungsarchiv, Profil bearbeiten,
Ausloggen — bei "kein Abo" eben mit entsprechendem Hinweis statt
echter Laufzeit. Vorher landete man hier stattdessen in einer
Sackgasse ("Coming soon…"), ohne je die eigentliche Seite zu sehen.
replace() statt href: die Anmeldeseite verschwindet damit aus dem
Verlauf — ein "Zurück" führt sonst sofort wieder hierher und von
hier wieder weiter, was sich wie eine Schleife anfühlt. */
location.replace("supporter.html");
return;
} catch (err) { } catch (err) {
// Token ungültig/abgelaufen -> zurück zur Registrierung/Login // Token ungültig/abgelaufen -> zurück zur Registrierung/Login
S.clearToken(); S.clearToken();
@@ -585,8 +797,10 @@
ladeHinweis.hidden = true; ladeHinweis.hidden = true;
} }
document.getElementById("switch-to-login").addEventListener("click", () => zeige("panel-login")); // Der frühere Gegenstück-Knopf "Neu registrieren" auf der Einloggen-Seite
document.getElementById("switch-to-register").addEventListener("click", () => zeige("panel-register")); // wurde am 21.08.2026 auf Wunsch entfernt — deshalb hier nur noch der eine
// Wechsel von der Registrierung zum Einloggen.
document.getElementById("tab-login").addEventListener("click", () => zeige("panel-login"));
// Widerrufsrecht-Checkbox: erst nach aktivem Ankreuzen werden die // Widerrufsrecht-Checkbox: erst nach aktivem Ankreuzen werden die
// PayPal-Zahlungsoptionen überhaupt geladen/klickbar (siehe agb.html // PayPal-Zahlungsoptionen überhaupt geladen/klickbar (siehe agb.html
@@ -615,24 +829,44 @@
const email = document.getElementById("reg-email").value.trim(); const email = document.getElementById("reg-email").value.trim();
if (!displayName || !email) return fehlerZeigen(el, "Bitte Name und E-Mail-Adresse angeben."); if (!displayName || !email) return fehlerZeigen(el, "Bitte Name und E-Mail-Adresse angeben.");
try { try {
// Schritt 1 von 3 (21.08.2026): /supporter/register legt nur das noch
// unbestätigte Konto an und verschickt einen Einmalcode -- es kommt
// bewusst KEIN Token zurück, eingeloggt ist man erst nach Schritt 2.
await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email }); await S.apiFetch("/supporter/register", { displayName, tiktokUsername, email });
codePurpose = "verify_email";
codeEmail = email; codeEmail = email;
codeZweck = "register";
zeige("panel-code"); zeige("panel-code");
} catch (err) { } catch (err) {
fehlerZeigen(el, err.message); fehlerZeigen(el, err.message);
} }
}); });
document.getElementById("btn-login-request").addEventListener("click", async () => { // Normale Anmeldung: E-Mail + eigener Zugangscode, ohne Umweg über E-Mail.
document.getElementById("btn-login").addEventListener("click", async () => {
const el = document.getElementById("login-fehler"); const el = document.getElementById("login-fehler");
fehlerVerstecken(el); fehlerVerstecken(el);
const email = document.getElementById("login-email").value.trim(); const email = document.getElementById("login-email").value.trim();
if (!email) return fehlerZeigen(el, "Bitte E-Mail-Adresse angeben."); const accessCode = document.getElementById("login-code").value;
if (!email || !accessCode) return fehlerZeigen(el, "Bitte E-Mail-Adresse und Zugangscode eingeben.");
try {
const data = await S.apiFetch("/supporter/login-code", { email, accessCode });
S.setToken(data.token);
await pruefeStatus();
} catch (err) {
fehlerZeigen(el, err.message);
}
});
// "Code vergessen?" — hier lebt der alte E-Mail-Einmalcode-Weg weiter.
document.getElementById("code-vergessen").addEventListener("click", async () => {
const el = document.getElementById("login-fehler");
fehlerVerstecken(el);
const email = document.getElementById("login-email").value.trim();
if (!email) return fehlerZeigen(el, "Bitte zuerst deine E-Mail-Adresse eingeben.");
try { try {
await S.apiFetch("/supporter/login-request", { email }); await S.apiFetch("/supporter/login-request", { email });
codePurpose = "login";
codeEmail = email; codeEmail = email;
codeZweck = "login";
zeige("panel-code"); zeige("panel-code");
} catch (err) { } catch (err) {
fehlerZeigen(el, err.message); fehlerZeigen(el, err.message);
@@ -645,9 +879,26 @@
const code = document.getElementById("code-input").value.trim(); const code = document.getElementById("code-input").value.trim();
if (!code) return fehlerZeigen(el, "Bitte Code eingeben."); if (!code) return fehlerZeigen(el, "Bitte Code eingeben.");
try { try {
const path = codePurpose === "login" ? "/supporter/verify-login" : "/supporter/verify-email"; // Dieselbe Code-Eingabe bedient zwei Wege (21.08.2026):
const data = await S.apiFetch(path, { email: codeEmail, code }); // "register" -> Erstbestätigung der E-Mail bei der Registrierung
// "login" -> "Code vergessen?"-Weg für bestehende Konten
// Beide enden gleich: eingeloggt, danach Zugangscode festlegen.
const endpunkt = codeZweck === "register" ? "/supporter/verify-email" : "/supporter/verify-login";
const data = await S.apiFetch(endpunkt, { email: codeEmail, code });
S.setToken(data.token); S.setToken(data.token);
zeige("panel-neuer-code");
} catch (err) {
fehlerZeigen(el, err.message);
}
});
document.getElementById("btn-neuer-code").addEventListener("click", async () => {
const el = document.getElementById("neuer-code-fehler");
fehlerVerstecken(el);
const accessCode = document.getElementById("neuer-code").value;
if (!accessCode) return fehlerZeigen(el, "Bitte leg einen Zugangscode fest.");
try {
await S.apiFetch("/supporter/set-access-code", { accessCode }, true);
await pruefeStatus(); await pruefeStatus();
} catch (err) { } catch (err) {
fehlerZeigen(el, err.message); fehlerZeigen(el, err.message);
@@ -662,6 +913,12 @@
} catch { } catch {
/* Konfiguration konnte nicht geladen werden — Google-Button/PayPal-Buttons bleiben dann aus. */ /* Konfiguration konnte nicht geladen werden — Google-Button/PayPal-Buttons bleiben dann aus. */
} }
/* Bugfix 20.08.2026, wieder aktiviert 21.08.2026: "Mit Google anmelden" war ein
dritter, bisher übersehener Weg, trotz gesperrtem Registrieren-/Login-Knopf
doch ein echtes Konto anzulegen bzw. sich einzuloggen. War deshalb deaktiviert,
solange die Registrierung selbst gesperrt war. Registrierung ist jetzt (Nutzer-
Wunsch 21.08.2026) bewusst offen -- Google-Login ist nur ein weiterer,
gleichwertiger Weg zum selben jetzt erlaubten Ziel, kein Schlupfloch mehr. */
initGoogleConsent(); initGoogleConsent();
await pruefeStatus(); await pruefeStatus();
} }
+10 -9
View File
@@ -5,9 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AGB — DogiCrew-Supporter-Abo — DOGFATHER UNIVERSE</title> <title>AGB — DogiCrew-Supporter-Abo — DOGFATHER UNIVERSE</title>
<meta name="description" content="Allgemeine Geschäftsbedingungen für das DogiCrew-Supporter-Abo von DOGFATHER UNIVERSE." /> <meta name="description" content="Allgemeine Geschäftsbedingungen für das DogiCrew-Supporter-Abo von DOGFATHER UNIVERSE." />
<link rel="icon" type="image/png" href="assets/img/favicon.png" /> <link rel="icon" type="image/png" href="/assets/img/app-symbole/universe-32.png?v=202610012001" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/universe-180.png?v=202610012001" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d10" /> <meta name="theme-color" content="#065f76" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="DOGFATHER UNIVERSE" /> <meta property="og:site_name" content="DOGFATHER UNIVERSE" />
<meta property="og:title" content="AGB — DogiCrew-Supporter-Abo — DOGFATHER UNIVERSE" /> <meta property="og:title" content="AGB — DogiCrew-Supporter-Abo — DOGFATHER UNIVERSE" />
@@ -20,10 +21,10 @@
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" /> <meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<link rel="stylesheet" href="assets/css/main.css" /> <link rel="stylesheet" href="assets/css/main.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" /> <link rel="stylesheet" href="assets/css/theme-dogfather.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" /> <link rel="stylesheet" href="assets/css/theme-hasidog.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" /> <link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=202610012001" />
</head> </head>
<body> <body>
<div id="site-header"></div> <div id="site-header"></div>
@@ -44,10 +45,10 @@
<p><strong>1. Geltungsbereich und Vertragspartner</strong><br> <p><strong>1. Geltungsbereich und Vertragspartner</strong><br>
Diese Allgemeinen Geschäftsbedingungen (AGB) gelten für den Abschluss und die Durchführung des Diese Allgemeinen Geschäftsbedingungen (AGB) gelten für den Abschluss und die Durchführung des
kostenpflichtigen „DogiCrew-Supporter-Abo" auf der Website dogfather-universe.com. Anbieter und kostenpflichtigen „DogiCrew-Supporter-Abo“ auf der Website dogfather-universe.com. Anbieter und
Vertragspartner ist:<br> Vertragspartner ist:<br>
Filipe Pereira Queiroz, 3, rue Arthur Thinnes, L-3919 Mondercange, Luxemburg — Filipe Pereira Queiroz, 3, rue Arthur Thinnes, L-3919 Mondercange, Luxemburg —
<a href="mailto:[email protected]">[email protected]</a> (im Folgenden „Anbieter"). <a href="mailto:[email protected]">[email protected]</a> (im Folgenden „Anbieter“).
Näheres siehe <a href="kontakt.html">Impressum</a>.</p> Näheres siehe <a href="kontakt.html">Impressum</a>.</p>
<p><strong>2. Leistungsbeschreibung</strong><br> <p><strong>2. Leistungsbeschreibung</strong><br>
@@ -134,6 +135,6 @@
</main> </main>
<div id="site-footer"></div> <div id="site-footer"></div>
<script src="assets/js/main.js"></script> <script src="assets/js/main.js?v=202610012001"></script>
</body> </body>
</html> </html>
+10 -9
View File
@@ -5,9 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aktion — DOGFATHER UNIVERSE</title> <title>Aktion — DOGFATHER UNIVERSE</title>
<meta name="description" content="Detailansicht einer Aktion oder eines Projekts von Team Dogi." /> <meta name="description" content="Detailansicht einer Aktion oder eines Projekts von Team Dogi." />
<link rel="icon" type="image/png" href="assets/img/favicon.png" /> <link rel="icon" type="image/png" href="/assets/img/app-symbole/universe-32.png?v=202610012001" />
<link rel="apple-touch-icon" href="/assets/img/app-symbole/universe-180.png?v=202610012001" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#0b0d10" /> <meta name="theme-color" content="#065f76" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="DOGFATHER UNIVERSE" /> <meta property="og:site_name" content="DOGFATHER UNIVERSE" />
<meta property="og:title" content="Aktion — DOGFATHER UNIVERSE" /> <meta property="og:title" content="Aktion — DOGFATHER UNIVERSE" />
@@ -19,10 +20,10 @@
<meta name="twitter:description" content="Detailansicht einer Aktion oder eines Projekts von Team Dogi." /> <meta name="twitter:description" content="Detailansicht einer Aktion oder eines Projekts von Team Dogi." />
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" /> <meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
<link rel="stylesheet" href="assets/css/main.css" /> <link rel="stylesheet" href="assets/css/main.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-dogfather.css" /> <link rel="stylesheet" href="assets/css/theme-dogfather.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-hasidog.css" /> <link rel="stylesheet" href="assets/css/theme-hasidog.css?v=202610012001" />
<link rel="stylesheet" href="assets/css/theme-spicymedia.css" /> <link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=202610012001" />
</head> </head>
<body> <body>
<div id="site-header"></div> <div id="site-header"></div>
@@ -51,9 +52,9 @@
</main> </main>
<div id="site-footer"></div> <div id="site-footer"></div>
<script src="assets/js/data-aktionen.js"></script> <script src="assets/js/data-aktionen.js?v=202610012001"></script>
<script src="assets/js/i18n-aktion-detail.js"></script> <script src="assets/js/i18n-aktion-detail.js?v=202610012001"></script>
<script src="assets/js/main.js"></script> <script src="assets/js/main.js?v=202610012001"></script>
<script> <script>
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
+1622 -56
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 KiB

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 KiB

After

Width:  |  Height:  |  Size: 482 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 413 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 413 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 403 KiB

Some files were not shown because too many files have changed in this diff Show More