Commit Graph
8 Commits
Author SHA1 Message Date
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 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 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 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 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 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