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]>
This commit is contained in:
2026-09-18 23:30:52 +02:00
co-authored by Claude Opus 5
parent 4ea7b37333
commit e43fe97550
35 changed files with 536 additions and 404 deletions
+59
View File
@@ -28,6 +28,10 @@ process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
/* Zwei Sekunden statt zwei Minuten -- sonst muesste Abschnitt 5e so
lange warten, und eine Pruefung, die zwei Minuten braucht, wird
abgeschaltet. Im Betrieb steht die Variable nirgends. */
process.env.ANRUF_KLINGELT_SEKUNDEN = "2";
/* Der Vermittlungsserver holt sein Geheimnis aus einer Datei. Hier muss
der Pfad UMGEBOGEN werden, bevor index.js geladen wird -- sonst
zeigte er auf die echte Datei unter /etc, und die Pruefung wuerde
@@ -267,6 +271,61 @@ melde("=== 5. Auflegen ===");
jetzt in `pushTextFuer()` -- eine Zeile weniger Verschachtelung und
eine Frage, die sich beantworten laesst.
======================================================================= */
/* =======================================================================
5e. EIN VERPASSTER ANRUF HINTERLAESST EINE SPUR
Bisher verschwand er lautlos. Wer zu spaet kam, oeffnete den Chat
und sah -- nichts. Keine Zeile, kein Hinweis, nicht einmal, DASS
jemand angerufen hat.
Genau das fuehlt sich an wie „es geht einfach nicht", auch wenn
technisch alles funktioniert hat: Der Anruf kam an, es klingelte,
niemand war schnell genug, und danach war es, als waere nie etwas
gewesen. Jedes Telefon der Welt zeigt einen verpassten Anruf.
======================================================================= */
melde("");
melde("=== 5e. Ein verpasster Anruf ===");
{
const raum = json(await roh("/workspace/api/chat/raeume", HAUS,
{ cookie: kDogi })).raeume?.[0];
if (!raum) {
unklar("kein Gespraech vorhanden -- nicht nachgesehen");
} else {
const vorher = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS,
{ cookie: kDogi })).nachrichten?.length ?? 0;
const start = await roh(`/workspace/api/anruf/${raum.id}/start`, HAUS,
{ cookie: kDogi }, { video: false });
ok(start.code === 200 || start.code === 201, `Anruf gestartet (${start.code})`);
/* Niemand geht ran. Nach ANRUF_KLINGELT_SEKUNDEN (hier 2) gilt er
als verpasst -- `aufraeumen()` laeuft bei der naechsten Anfrage
mit. */
await new Promise((r) => setTimeout(r, 2600));
await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand });
const nachher = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS,
{ cookie: kDogi })).nachrichten || [];
ok(nachher.length === vorher + 1,
`es steht genau EINE neue Zeile im Gespraech (${vorher} -> ${nachher.length})`);
const letzte = nachher[nachher.length - 1];
ok(/[Vv]erpasst/.test(letzte?.text || ""),
`und sie sagt, was los war („${letzte?.text}")`);
ok(letzte?.von_id !== undefined,
"sie steht beim Anrufer, nicht als Systemtext ohne Absender");
/* UND NICHT ZWEIMAL. `aufraeumen()` laeuft bei JEDER Anfrage --
ohne das Loeschen aus `laufend` staende hier bei jedem Aufruf
eine weitere Zeile. */
await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand });
await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand });
const nochmal = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS,
{ cookie: kDogi })).nachrichten || [];
ok(nochmal.length === nachher.length,
`und bleibt bei einer, auch nach weiteren Abfragen (${nochmal.length})`);
}
}
melde("");
melde("=== 5d. Was in der Benachrichtigung steht ===");
{