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]>
This commit is contained in:
@@ -63,6 +63,24 @@ import { fileURLToPath } from "node:url";
|
|||||||
const REPO = join(dirname(fileURLToPath(import.meta.url)), "..");
|
const REPO = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
const lies = (p) => readFileSync(join(REPO, p), "utf8");
|
const lies = (p) => readFileSync(join(REPO, p), "utf8");
|
||||||
|
|
||||||
|
/* ---- NUR DER CODE, OHNE DIE ERZAEHLUNG DRUMHERUM (03.10.2026) -------
|
||||||
|
|
||||||
|
Diese Datei prueft Quelltext mit Mustern. Das ist schnell und
|
||||||
|
braucht keinen Server -- hat aber eine Luecke, die heute
|
||||||
|
aufgefallen ist: Die Pruefung "und zwar an derselben Bedingung wie
|
||||||
|
die Nachtruhe" war gruen, OBWOHL die Zeile aus dem Code
|
||||||
|
verschwunden war. Sie stand nur noch in einem Kommentar, der die
|
||||||
|
alte Fassung zitiert -- und ein Muster sieht den Unterschied
|
||||||
|
nicht.
|
||||||
|
|
||||||
|
Das ist die dritte Sorte gruener Haken: nicht uebersprungen, nicht
|
||||||
|
falsch geprueft, sondern am Beleg vorbei. Deshalb werden
|
||||||
|
Kommentare vorher entfernt. Was hier geprueft wird, muss laufender
|
||||||
|
Code sein. */
|
||||||
|
const nurCode = (t) => t
|
||||||
|
.replace(/\/\*[\s\S]*?\*\//g, " ")
|
||||||
|
.replace(/(^|[^:])\/\/.*/g, "$1");
|
||||||
|
|
||||||
let ok = 0, fehl = 0;
|
let ok = 0, fehl = 0;
|
||||||
const pruef = (name, bedingung, zusatz = "") => {
|
const pruef = (name, bedingung, zusatz = "") => {
|
||||||
if (bedingung) { ok++; console.log(` OK ${name}`); }
|
if (bedingung) { ok++; console.log(` OK ${name}`); }
|
||||||
@@ -104,29 +122,47 @@ pruef("und für alles andere bleibt es ruhig",
|
|||||||
/* =====================================================================
|
/* =====================================================================
|
||||||
2. DER VERSAND — Dringlichkeit und Haltbarkeit
|
2. DER VERSAND — Dringlichkeit und Haltbarkeit
|
||||||
===================================================================== */
|
===================================================================== */
|
||||||
const krypto = lies("server/workspace-push-krypto.js");
|
const krypto = nurCode(lies("server/workspace-push-krypto.js"));
|
||||||
const versand = lies("server/workspace-push.js");
|
const versand = nurCode(lies("server/workspace-push.js"));
|
||||||
|
|
||||||
pruef("der Transport kennt überhaupt eine Dringlichkeit",
|
pruef("der Transport kennt überhaupt eine Dringlichkeit",
|
||||||
/dringend\s*=\s*false\s*\}\s*=\s*\{\}/.test(krypto),
|
/eilig\s*=\s*false/.test(krypto),
|
||||||
"vorher stand Urgency fest auf \"normal\"");
|
"vorher stand Urgency fest auf \"normal\"");
|
||||||
|
|
||||||
pruef("ein dringender Push geht mit Urgency: high hinaus",
|
pruef("ein eiliger Push geht mit Urgency: high hinaus",
|
||||||
/Urgency:\s*dringend\s*\?\s*"high"\s*:\s*"normal"/.test(krypto));
|
/Urgency:\s*eilig\s*\?\s*"high"\s*:\s*"normal"/.test(krypto));
|
||||||
|
|
||||||
pruef("und verfällt, wenn der Anruf vorbei ist",
|
pruef("und verfällt, wenn der Anruf vorbei ist",
|
||||||
/TTL:\s*String\(dringend\s*\?\s*Math\.min\(ttl,\s*\d+\)/.test(krypto),
|
/TTL:\s*String\(kurzlebig\s*\?\s*Math\.min\(ttl,\s*\d+\)/.test(krypto),
|
||||||
"sonst ploppt ein Anruf von vor einer Stunde nachträglich auf");
|
"sonst ploppt ein Anruf von vor einer Stunde nachträglich auf");
|
||||||
|
|
||||||
pruef("der Anruf wird als dringend verschickt",
|
pruef("der Anruf wird eilig UND kurzlebig verschickt",
|
||||||
/schicken\(a,\s*inhalt,\s*paar,\s*ABSENDER,\s*\{\s*dringend\s*\}\)/.test(versand));
|
/schicken\(a,\s*inhalt,\s*paar,\s*ABSENDER,\s*\{\s*eilig,\s*kurzlebig\s*\}\)/.test(versand));
|
||||||
|
|
||||||
/* DIESELBE BEDINGUNG WIE BEI DER RUHEZEIT. „Darf das nachts stören?"
|
/* ---- ZWEI FRAGEN, ZWEI FELDER (geändert 03.10.2026) -----------------
|
||||||
und „darf das warten?" haben dieselbe Antwort -- zwei getrennte
|
|
||||||
Bedingungen wären die, die beim nächsten Nachschärfen auseinander
|
Hier stand bis heute das Gegenteil: „Darf das nachts stören?" und
|
||||||
laufen. */
|
„darf das warten?" hätten dieselbe Antwort, zwei getrennte
|
||||||
pruef("und zwar an derselben Bedingung wie die Nachtruhe",
|
Bedingungen wären die, die auseinanderlaufen. Die Vorhersage war
|
||||||
/const dringend = art === "test" \|\| art === "anruf";/.test(versand));
|
richtig, nur in die andere Richtung — sie laufen auseinander, WEIL
|
||||||
|
es zwei Fragen sind:
|
||||||
|
|
||||||
|
Chat um 3 Uhr nachts -> nicht stören (Ruhezeit greift)
|
||||||
|
Chat um 14 Uhr -> nicht warten (eilig)
|
||||||
|
|
||||||
|
Genau diese Gleichsetzung hat Dienes Meldung verursacht: Weil der
|
||||||
|
Chat nicht nachts stören darf, bekam er auch tagsüber
|
||||||
|
`Urgency: normal` — und Android legt das beiseite, bis jemand die
|
||||||
|
App öffnet. Das Zusammenlegen war die Ursache, nicht der Schutz.
|
||||||
|
|
||||||
|
Auseinanderlaufen können die beiden trotzdem nicht: Sie stehen als
|
||||||
|
`eilig` und `ruhe` in DERSELBEN Zeile derselben Artenliste. */
|
||||||
|
pruef("der Anruf ist eilig und kurzlebig, beides in einer Zeile",
|
||||||
|
/\{\s*schluessel:\s*"anruf",\s*eilig:\s*true,[^}]*ruhe:\s*"nie"/.test(versand));
|
||||||
|
|
||||||
|
pruef("und die Dringlichkeit wird aus der Artenliste abgeleitet",
|
||||||
|
/const eilig = eiligRegel\(art\);/.test(versand),
|
||||||
|
"nicht aus einer zweiten Aufzählung daneben");
|
||||||
|
|
||||||
/* =====================================================================
|
/* =====================================================================
|
||||||
3. DER WEG DORTHIN — wird beim Anruf überhaupt geweckt?
|
3. DER WEG DORTHIN — wird beim Anruf überhaupt geweckt?
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/* =====================================================================
|
||||||
|
WECKT DIE MELDUNG DAS TELEFON -- oder darf sie warten?
|
||||||
|
|
||||||
|
WARUM ES DIESE PRUEFUNG GIBT (03.10.2026).
|
||||||
|
|
||||||
|
Diene hat gemeldet: "Die Benachrichtigungen werden nicht angezeigt,
|
||||||
|
wenn neue Nachrichten reinkommen. Erst, wenn man die App oeffnet."
|
||||||
|
|
||||||
|
Alles, was wir bis dahin messen konnten, war gruen: Der Service
|
||||||
|
Worker zeigt die Meldung (pruef-push-zu, 13 Pruefungen), jede
|
||||||
|
Anmeldung im Haus stand auf `fehler = 0`, und der Push-Dienst
|
||||||
|
quittierte jede Zustellung mit 201. Nur hat niemand den Kopf
|
||||||
|
gemessen, der auf dem Weg mitgeht:
|
||||||
|
|
||||||
|
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, wenn
|
||||||
|
jemand entsperrt oder die App oeffnet. Apple/APNs nennt es
|
||||||
|
"verzoegert, gebuendelt oder gedrosselt". Das ist Dienes Satz, Wort
|
||||||
|
fuer Wort, und es stand als Vorgabe in unserem eigenen Quelltext.
|
||||||
|
|
||||||
|
`zuletzt_ok` konnte das nie zeigen: Es beweist, dass der DIENST
|
||||||
|
angenommen hat (201), nicht dass das GERAET etwas angezeigt hat.
|
||||||
|
Zwischen beidem liegt genau dieser Kopf.
|
||||||
|
|
||||||
|
WAS HIER GEMESSEN WIRD, und warum in dieser Reihenfolge:
|
||||||
|
|
||||||
|
1. Die ENTSCHEIDUNG je Art -- und zwar unabhaengig notiert, nicht
|
||||||
|
aus der Artenliste abgelesen. Eine Pruefung, die ihre Erwartung
|
||||||
|
aus derselben Tabelle holt, die sie prueft, ist ein Spiegel:
|
||||||
|
Sie ist immer gruen, auch wenn jemand die Tabelle falsch
|
||||||
|
aendert.
|
||||||
|
2. VOLLSTAENDIGKEIT -- jede Art muss unten eine Entscheidung
|
||||||
|
haben. Wer eine neue eintraegt, ohne sich zu entscheiden,
|
||||||
|
bekommt einen Fehler statt stillschweigend "darf warten".
|
||||||
|
3. Der KOPF AUF DER LEITUNG, durch `benachrichtige` hindurch bis
|
||||||
|
zu einem nachgebauten Push-Dienst. Nur das beweist, dass die
|
||||||
|
Entscheidung auch ankommt.
|
||||||
|
4. Dass Dringlichkeit und HALTBARKEIT getrennt bleiben. Das war
|
||||||
|
die Falle beim Beheben: Beides hing an einem Schalter, und ein
|
||||||
|
eiliger Chat haette damit TTL 150 bekommen -- wer sein Telefon
|
||||||
|
drei Minuten aus hat, haette die Nachricht dann GAR nicht mehr
|
||||||
|
bekommen. Aus "zu spaet" waere "nie" geworden.
|
||||||
|
|
||||||
|
GEGENPROBE: Der alte Name `dringend` muss krachen, und eine nicht
|
||||||
|
eilige Art muss nachweislich "normal" bekommen -- sonst koennte
|
||||||
|
diese Pruefung gar nichts anderes als "high" sehen.
|
||||||
|
|
||||||
|
DREI AUSGAENGE: 0 in Ordnung · 1 Befunde · 2 konnte nicht nachsehen.
|
||||||
|
===================================================================== */
|
||||||
|
|
||||||
|
/* ---- DIE UHR IST HIER EINE EINGABE, KEINE ANNAHME --------------------
|
||||||
|
`istRuhezeit` fragt `Date.getHours()`, also die Zeitzone dieses
|
||||||
|
Prozesses. Liefe die Pruefung um 23 Uhr, wuerde `benachrichtige` zu
|
||||||
|
Recht nichts verschicken, und alles unten saehe nach Befund aus,
|
||||||
|
ohne dass etwas kaputt waere -- eine Zeitbombe wie die
|
||||||
|
Gate-Pruefung vom 06.09. Deshalb wird die Zone so gewaehlt, dass
|
||||||
|
JETZT auf 12 Uhr mittags faellt, egal wann der Lauf startet. */
|
||||||
|
const utcStunde = new Date().getUTCHours();
|
||||||
|
const versatz = ((12 - utcStunde + 12) % 24) - 12; /* -12 .. +11 */
|
||||||
|
process.env.TZ = versatz === 0 ? "Etc/GMT"
|
||||||
|
: `Etc/GMT${versatz > 0 ? "-" : "+"}${Math.abs(versatz)}`; /* POSIX: Vorzeichen umgekehrt */
|
||||||
|
|
||||||
|
import { mkdtempSync, rmSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { createServer } from "node:http";
|
||||||
|
import { createECDH, randomBytes } from "node:crypto";
|
||||||
|
|
||||||
|
const ordner = mkdtempSync(join(tmpdir(), "ws-eilig-"));
|
||||||
|
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
|
||||||
|
|
||||||
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
const { eigenerPort } = await import("./helfer-port.mjs");
|
||||||
|
const PORT = await eigenerPort(import.meta, "pruef-push-eilig", 0);
|
||||||
|
const PORT_DIENST = await eigenerPort(import.meta, "pruef-push-eilig (Push-Dienst)", 1);
|
||||||
|
process.env.PORT = `${PORT}`;
|
||||||
|
process.env.SITE_ACCESS_SECRET = "lokaler-test";
|
||||||
|
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
|
||||||
|
|
||||||
|
await import("./index.js");
|
||||||
|
notbremse(120_000, "pruef-push-eilig");
|
||||||
|
await new Promise((r) => setTimeout(r, 900));
|
||||||
|
|
||||||
|
let fehler = 0, geprueft = 0;
|
||||||
|
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
|
||||||
|
const abbruch = (grund) => {
|
||||||
|
console.log(`\n KONNTE NICHT NACHSEHEN: ${grund}`);
|
||||||
|
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
|
||||||
|
process.exit(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const push = await import("./workspace-push.js");
|
||||||
|
const { b64u } = await import("./workspace-push-krypto.js");
|
||||||
|
const { DatabaseSync } = await import("node:sqlite");
|
||||||
|
|
||||||
|
/* =====================================================================
|
||||||
|
DIE ENTSCHEIDUNG -- von Hand notiert, nicht abgelesen.
|
||||||
|
|
||||||
|
Massstab: eilig ist, was durch Warten WERTLOS wird. Nicht eilig
|
||||||
|
ist, was auch eine halbe Stunde spaeter noch stimmt. Waere alles
|
||||||
|
eilig, waere nichts mehr eilig -- die Geraete duerfen uns die
|
||||||
|
Dringlichkeit glauben, sonst drosseln sie uns, und der Akku zahlt.
|
||||||
|
===================================================================== */
|
||||||
|
const ERWARTET = {
|
||||||
|
/* --- weckt das Geraet: jemand wartet, oder es ist gleich vorbei --- */
|
||||||
|
anruf: true, /* klingelt 120 Sekunden */
|
||||||
|
test: true, /* jemand steht davor und tippt "Probe" */
|
||||||
|
chat_nachricht: true, /* jemand wartet auf eine Antwort */
|
||||||
|
chat_erwaehnung: true, /* jemand meint DICH */
|
||||||
|
support: true, /* Meldung oder Antwort darauf */
|
||||||
|
hilfe: true, /* vertrauliche Meldung */
|
||||||
|
termin_gleich: true, /* in einer Stunde -- danach wertlos */
|
||||||
|
termin_wecker: true, /* selbst gestellt; ein spaeter Wecker ist keiner */
|
||||||
|
dogfather_live: true, /* "jetzt" oder gar nicht */
|
||||||
|
reaktion_live: true, /* dito */
|
||||||
|
/* --- darf warten: stimmt spaeter auch noch ----------------------- */
|
||||||
|
aufgabe_faellig: false, /* morgen faellig */
|
||||||
|
aufgabe_ueberfaellig: false, /* ist es schon */
|
||||||
|
protokoll_fehlt: false,
|
||||||
|
followup: false,
|
||||||
|
bewerbung_neu: false,
|
||||||
|
bewerbung_antwort: false,
|
||||||
|
manager_ziele: false,
|
||||||
|
tagesruf: false, /* Tagesuebersicht */
|
||||||
|
befinden: false, /* alle zwei Wochen */
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("\n=== Die Entscheidung je Art ===");
|
||||||
|
{
|
||||||
|
const arten = push.ARTEN.map((a) => a.schluessel);
|
||||||
|
/* Vollstaendigkeit in BEIDE Richtungen -- eine neue Art ohne
|
||||||
|
Entscheidung ist ein Fehler, und eine Entscheidung ohne Art ist
|
||||||
|
ein Rest, der niemanden mehr schuetzt. */
|
||||||
|
const ohneEntscheidung = arten.filter((a) => !(a in ERWARTET));
|
||||||
|
const ohneArt = Object.keys(ERWARTET).filter((a) => !arten.includes(a));
|
||||||
|
ok(arten.length > 0 && ohneEntscheidung.length === 0,
|
||||||
|
ohneEntscheidung.length
|
||||||
|
? `OHNE ENTSCHEIDUNG: ${ohneEntscheidung.join(", ")} -- eilig oder nicht?`
|
||||||
|
: `alle ${arten.length} Arten haben eine Entscheidung`);
|
||||||
|
ok(ohneArt.length === 0,
|
||||||
|
ohneArt.length ? `Entscheidung ohne Art: ${ohneArt.join(", ")}` : "keine Karteileiche");
|
||||||
|
|
||||||
|
let stimmt = 0;
|
||||||
|
for (const [art, soll] of Object.entries(ERWARTET)) {
|
||||||
|
if (push.eiligRegel(art) === soll) stimmt++;
|
||||||
|
else ok(false, `${art}: erwartet ${soll ? "eilig" : "darf warten"}, ist es nicht`);
|
||||||
|
}
|
||||||
|
const anzahl = Object.keys(ERWARTET).length;
|
||||||
|
ok(anzahl > 0 && stimmt === anzahl, `${stimmt} von ${anzahl} Arten wie entschieden`);
|
||||||
|
|
||||||
|
const eilige = arten.filter((a) => push.eiligRegel(a)).length;
|
||||||
|
ok(eilige > 0 && eilige < arten.length,
|
||||||
|
`${eilige} von ${arten.length} sind eilig -- geteilt, nicht pauschal`);
|
||||||
|
ok(push.eiligRegel("gibtsnicht") === false,
|
||||||
|
"eine unbekannte Art ist NICHT eilig (im Zweifel nicht wecken)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================================
|
||||||
|
Der Kopf auf der Leitung
|
||||||
|
===================================================================== */
|
||||||
|
console.log("\n=== Was wirklich beim Push-Dienst ankommt ===");
|
||||||
|
|
||||||
|
const empfangen = [];
|
||||||
|
const dienst = createServer((q, a) => {
|
||||||
|
q.on("data", () => {});
|
||||||
|
q.on("end", () => { empfangen.push(q.headers); a.writeHead(201); a.end(); });
|
||||||
|
});
|
||||||
|
await new Promise((r) => dienst.listen(PORT_DIENST, "127.0.0.1", r));
|
||||||
|
|
||||||
|
const browser = createECDH("prime256v1");
|
||||||
|
browser.generateKeys();
|
||||||
|
|
||||||
|
let d;
|
||||||
|
try { d = new DatabaseSync(process.env.WORKSPACE_DB); }
|
||||||
|
catch (e) { abbruch(`die Testdatenbank laesst sich nicht oeffnen: ${e.message}`); }
|
||||||
|
|
||||||
|
const jetzt = new Date().toISOString();
|
||||||
|
/* Der Zugangscode ist hier BEDEUTUNGSLOS -- angemeldet wird sich
|
||||||
|
nicht, gemessen wird der Weg nach draussen. Die Spalten sind nur
|
||||||
|
NOT NULL, also stehen dort Zufallsbytes: kein echter Code, kein
|
||||||
|
erfundener, und keiner, der jemandem Zugang gaebe. */
|
||||||
|
const fuellung = randomBytes(32).toString("hex");
|
||||||
|
d.prepare(`INSERT INTO personen
|
||||||
|
(name, rolle, code_hash, code_salt, code_n, aktiv, erstellt)
|
||||||
|
VALUES (?,?,?,?,?,1,?)`)
|
||||||
|
.run("Probeperson", "admin", fuellung, fuellung.slice(0, 32), 32768, jetzt);
|
||||||
|
const personId = d.prepare("SELECT id FROM personen WHERE name = 'Probeperson'").get().id;
|
||||||
|
d.prepare(`INSERT INTO push_anmeldungen
|
||||||
|
(endpunkt, person_id, p256dh, auth, geraet, erstellt, zuletzt_ok, fehler)
|
||||||
|
VALUES (?,?,?,?,?,?,NULL,0)`)
|
||||||
|
.run(`http://127.0.0.1:${PORT_DIENST}/push/probe`, personId,
|
||||||
|
b64u(browser.getPublicKey()), b64u(Buffer.alloc(16, 7)), "Pruefgeraet", jetzt);
|
||||||
|
d.close();
|
||||||
|
|
||||||
|
/** Verschickt EINE Meldung und gibt den Kopf zurueck, der ankam. */
|
||||||
|
const kopfVon = async (art) => {
|
||||||
|
const vorher = empfangen.length;
|
||||||
|
const e = await push.benachrichtige(personId, art, {
|
||||||
|
titel: "Probe", text: art, ziel: "/workspace/start.html",
|
||||||
|
});
|
||||||
|
if (e.verschickt !== 1) return { grund: e.grund };
|
||||||
|
return { kopf: empfangen[vorher], grund: e.grund };
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Je ein Vertreter beider Seiten -- beide mit `ruhe: "immer"`, damit
|
||||||
|
die Messung nicht an der Ruhezeit haengt (die oben auf Mittag
|
||||||
|
festgenagelt ist). */
|
||||||
|
const eilig = await kopfVon("chat_nachricht");
|
||||||
|
const ruhig = await kopfVon("aufgabe_faellig");
|
||||||
|
|
||||||
|
if (!eilig.kopf || !ruhig.kopf) {
|
||||||
|
abbruch("es ging nichts hinaus "
|
||||||
|
+ `(chat_nachricht: ${eilig.grund}, aufgabe_faellig: ${ruhig.grund}) `
|
||||||
|
+ "-- ohne eine zugestellte Meldung ist der Kopf nicht messbar");
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(eilig.kopf.urgency === "high",
|
||||||
|
`chat_nachricht geht mit Urgency: ${eilig.kopf.urgency} hinaus (muss "high" sein)`);
|
||||||
|
ok(ruhig.kopf.urgency === "normal",
|
||||||
|
`aufgabe_faellig geht mit Urgency: ${ruhig.kopf.urgency} hinaus (muss "normal" sein)`);
|
||||||
|
/* DIE GEGENPROBE: Saehe diese Pruefung grundsaetzlich nur "high",
|
||||||
|
waere die Zeile darueber wertlos. Dass sich die beiden Koepfe
|
||||||
|
UNTERSCHEIDEN, ist der Beweis, dass gemessen und nicht geraten
|
||||||
|
wird. */
|
||||||
|
ok(eilig.kopf.urgency !== ruhig.kopf.urgency,
|
||||||
|
"die beiden unterscheiden sich -- es wird wirklich gemessen");
|
||||||
|
|
||||||
|
/* HALTBARKEIT: der eigentliche Grund, warum es zwei Felder sind.
|
||||||
|
Ein eiliger Chat darf NICHT nebenbei kurzlebig werden. */
|
||||||
|
ok(eilig.kopf.ttl === "3600",
|
||||||
|
`chat_nachricht bleibt ${eilig.kopf.ttl} s gueltig (muss 3600 sein, nicht 150)`);
|
||||||
|
ok(ruhig.kopf.ttl === "3600", `aufgabe_faellig: TTL ${ruhig.kopf.ttl}`);
|
||||||
|
|
||||||
|
/* Und das, was kurzlebig sein SOLL, ist es noch: ein Anruf von vor
|
||||||
|
einer Stunde darf nicht nachtraeglich aufploppen. */
|
||||||
|
const anruf = await kopfVon("anruf");
|
||||||
|
if (!anruf.kopf) abbruch(`der Anruf ging nicht hinaus (${anruf.grund})`);
|
||||||
|
ok(anruf.kopf.urgency === "high", `anruf: Urgency ${anruf.kopf.urgency}`);
|
||||||
|
ok(anruf.kopf.ttl === "150",
|
||||||
|
`anruf verfaellt nach ${anruf.kopf.ttl} s -- eilig UND kurzlebig, beides zugleich`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =====================================================================
|
||||||
|
Gegenprobe: der alte Name darf nicht still durchrutschen
|
||||||
|
===================================================================== */
|
||||||
|
console.log("\n=== Der alte Schalter ist weg -- und zwar laut ===");
|
||||||
|
{
|
||||||
|
const { schicken, schluesselErzeugen } = await import("./workspace-push-krypto.js");
|
||||||
|
let krachte = false;
|
||||||
|
try {
|
||||||
|
await schicken({ endpunkt: `http://127.0.0.1:${PORT_DIENST}/alt`,
|
||||||
|
p256dh: b64u(browser.getPublicKey()), auth: b64u(Buffer.alloc(16, 7)) },
|
||||||
|
"{}", schluesselErzeugen(), "mailto:[email protected]",
|
||||||
|
{ dringend: true });
|
||||||
|
} catch { krachte = true; }
|
||||||
|
ok(krachte,
|
||||||
|
"schicken({ dringend: true }) bricht ab -- sonst gaebe es klaglos \"normal\" zurueck");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- SAUBER ZUMACHEN, SONST IST GRUEN TROTZDEM ROT ------------------
|
||||||
|
`fetch` haelt die Verbindungen zum nachgebauten Dienst offen
|
||||||
|
(keep-alive). Wer dann `process.exit()` ruft, reisst libuv ein
|
||||||
|
Handle mitten im Schliessen weg, und Windows antwortet mit
|
||||||
|
|
||||||
|
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)
|
||||||
|
|
||||||
|
-- Rueckgabewert 127 NACH "13 Pruefungen, 0 Fehler". Genau das ist
|
||||||
|
am 05.09. schon einmal passiert. Eine Pruefung, die inhaltlich
|
||||||
|
besteht und trotzdem rot meldet, ist das Schlimmste von beidem:
|
||||||
|
Man gewoehnt sich an, das Rot zu uebersehen. Also erst die
|
||||||
|
Verbindungen kappen, dann zumachen, dann einen Takt warten. */
|
||||||
|
dienst.closeAllConnections?.();
|
||||||
|
await new Promise((r) => dienst.close(r));
|
||||||
|
await new Promise((r) => setTimeout(r, 250));
|
||||||
|
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ }
|
||||||
|
console.log(`\n${geprueft} Pruefungen, ${fehler} Fehler`);
|
||||||
|
console.log(fehler === 0 ? "ALLES IN ORDNUNG" : "NICHT IN ORDNUNG");
|
||||||
|
process.exit(fehler ? 1 : 0);
|
||||||
@@ -223,7 +223,21 @@ export function vapidKopf(endpunkt, paar, absender, stunden = 12) {
|
|||||||
* soll NICHT nachtraeglich aufploppen. Deshalb bekommt er eine kurze
|
* soll NICHT nachtraeglich aufploppen. Deshalb bekommt er eine kurze
|
||||||
* TTL -- ist er vorbei, verfaellt auch die Meldung. */
|
* TTL -- ist er vorbei, verfaellt auch die Meldung. */
|
||||||
export async function schicken(anmeldung, text, paar, absender,
|
export async function schicken(anmeldung, text, paar, absender,
|
||||||
{ ttl = 3600, dringend = false } = {}) {
|
{ ttl = 3600, eilig = false, kurzlebig = false,
|
||||||
|
...rest } = {}) {
|
||||||
|
/* DER ALTE NAME MUSS KRACHEN, NICHT DURCHRUTSCHEN (03.10.2026).
|
||||||
|
|
||||||
|
Bis heute hiess beides zusammen `dringend`. Wer den alten Namen
|
||||||
|
weitergibt, bekaeme sonst klaglos `Urgency: normal` -- also genau
|
||||||
|
den Fehler zurueck, der gerade behoben wurde, und niemand saehe
|
||||||
|
es. Ein unbekannter Schluessel ist hier deshalb ein Absturz. */
|
||||||
|
const unbekannt = Object.keys(rest);
|
||||||
|
if (unbekannt.length) {
|
||||||
|
throw new Error(
|
||||||
|
`schicken(): unbekannte Angabe ${unbekannt.join(", ")} -- ` +
|
||||||
|
`aus "dringend" wurden "eilig" (weckt das Geraet) und ` +
|
||||||
|
`"kurzlebig" (verfaellt nach 150 s).`);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const koerper = verschluesseln(text, anmeldung.p256dh, anmeldung.auth);
|
const koerper = verschluesseln(text, anmeldung.p256dh, anmeldung.auth);
|
||||||
const kopf = vapidKopf(anmeldung.endpunkt, paar, absender);
|
const kopf = vapidKopf(anmeldung.endpunkt, paar, absender);
|
||||||
@@ -232,8 +246,10 @@ export async function schicken(anmeldung, text, paar, absender,
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
...kopf,
|
...kopf,
|
||||||
TTL: String(dringend ? Math.min(ttl, 150) : ttl),
|
/* Haltbarkeit und Dringlichkeit sind zwei Fragen -- siehe
|
||||||
Urgency: dringend ? "high" : "normal",
|
`eiligRegel` in workspace-push.js. */
|
||||||
|
TTL: String(kurzlebig ? Math.min(ttl, 150) : ttl),
|
||||||
|
Urgency: eilig ? "high" : "normal",
|
||||||
},
|
},
|
||||||
body: koerper,
|
body: koerper,
|
||||||
/* Ein haengender Push-Dienst darf den Lauf nicht aufhalten. */
|
/* Ein haengender Push-Dienst darf den Lauf nicht aufhalten. */
|
||||||
|
|||||||
+69
-19
@@ -113,19 +113,19 @@ const jetzt = () => new Date().toISOString();
|
|||||||
export const ARTEN = [
|
export const ARTEN = [
|
||||||
{ schluessel: "aufgabe_faellig", name: "Aufgabe wird morgen fällig", vorgabe: true },
|
{ schluessel: "aufgabe_faellig", name: "Aufgabe wird morgen fällig", vorgabe: true },
|
||||||
{ schluessel: "aufgabe_ueberfaellig", name: "Aufgabe ist überfällig", vorgabe: true },
|
{ schluessel: "aufgabe_ueberfaellig", name: "Aufgabe ist überfällig", vorgabe: true },
|
||||||
{ schluessel: "termin_gleich", name: "Termin in einer Stunde", vorgabe: true },
|
{ schluessel: "termin_gleich", eilig: true, name: "Termin in einer Stunde", vorgabe: true },
|
||||||
/* DER WECKER (07.09.2026). Bewusst eine EIGENE Art neben
|
/* DER WECKER (07.09.2026). Bewusst eine EIGENE Art neben
|
||||||
"termin_gleich": Die eine ist eine Vorgabe des Hauses fuer jeden
|
"termin_gleich": Die eine ist eine Vorgabe des Hauses fuer jeden
|
||||||
Termin, der andere ist eine Entscheidung DIESER Person fuer DIESEN
|
Termin, der andere ist eine Entscheidung DIESER Person fuer DIESEN
|
||||||
Termin. Wer die feste Stunden-Erinnerung abschaltet, will damit
|
Termin. Wer die feste Stunden-Erinnerung abschaltet, will damit
|
||||||
nicht seine selbst gesetzten Wecker verlieren. */
|
nicht seine selbst gesetzten Wecker verlieren. */
|
||||||
{ schluessel: "termin_wecker", name: "Selbst gesetzter Wecker", vorgabe: true },
|
{ schluessel: "termin_wecker", eilig: true, name: "Selbst gesetzter Wecker", vorgabe: true },
|
||||||
{ schluessel: "protokoll_fehlt", name: "Gespräch ohne Protokoll", vorgabe: true },
|
{ schluessel: "protokoll_fehlt", name: "Gespräch ohne Protokoll", vorgabe: true },
|
||||||
{ schluessel: "followup", name: "Follow-up in der Pipeline fällig", vorgabe: true },
|
{ schluessel: "followup", name: "Follow-up in der Pipeline fällig", vorgabe: true },
|
||||||
/* Chat (06.09.2026). Steht bewusst VOR der Probe: Es ist die Art,
|
/* Chat (06.09.2026). Steht bewusst VOR der Probe: Es ist die Art,
|
||||||
die am haeufigsten kommt, und wer die Liste ueberfliegt, sucht
|
die am haeufigsten kommt, und wer die Liste ueberfliegt, sucht
|
||||||
zuerst sie. */
|
zuerst sie. */
|
||||||
{ schluessel: "chat_nachricht", name: "Neue Nachricht im Chat", vorgabe: true },
|
{ schluessel: "chat_nachricht", eilig: true, name: "Neue Nachricht im Chat", vorgabe: true },
|
||||||
/* ---- ANGESPROCHEN WERDEN IST EINE EIGENE ART (20.09.2026) ------
|
/* ---- ANGESPROCHEN WERDEN IST EINE EIGENE ART (20.09.2026) ------
|
||||||
|
|
||||||
Filipe: "ich will das man die leute mit @ markieren kann im chat."
|
Filipe: "ich will das man die leute mit @ markieren kann im chat."
|
||||||
@@ -144,7 +144,7 @@ export const ARTEN = [
|
|||||||
KEINE Ausnahme von der Ruhezeit: Ein Anruf wartet auf eine
|
KEINE Ausnahme von der Ruhezeit: Ein Anruf wartet auf eine
|
||||||
Antwort, ein "@Anna" nicht. Wer um halb vier angesprochen wird,
|
Antwort, ein "@Anna" nicht. Wer um halb vier angesprochen wird,
|
||||||
liest es um sieben -- das reicht. */
|
liest es um sieben -- das reicht. */
|
||||||
{ schluessel: "chat_erwaehnung", name: "Jemand erwähnt dich im Chat (@)", vorgabe: true },
|
{ schluessel: "chat_erwaehnung", eilig: true, name: "Jemand erwähnt dich im Chat (@)", vorgabe: true },
|
||||||
|
|
||||||
/* ---- BEWERBUNGEN (23.09.2026) -----------------------------------
|
/* ---- BEWERBUNGEN (23.09.2026) -----------------------------------
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ export const ARTEN = [
|
|||||||
|
|
||||||
NICHT DRINGEND: Ein kaputter Knopf weckt niemanden um drei Uhr
|
NICHT DRINGEND: Ein kaputter Knopf weckt niemanden um drei Uhr
|
||||||
nachts; die Ruhezeit gilt. */
|
nachts; die Ruhezeit gilt. */
|
||||||
{ schluessel: "support",
|
{ schluessel: "support", eilig: true,
|
||||||
name: "Support: neue Meldung oder Antwort darauf", vorgabe: true },
|
name: "Support: neue Meldung oder Antwort darauf", vorgabe: true },
|
||||||
|
|
||||||
/* ---- MANAGER-ZIELE (02.10.2026) ---------------------------------
|
/* ---- MANAGER-ZIELE (02.10.2026) ---------------------------------
|
||||||
@@ -224,7 +224,7 @@ export const ARTEN = [
|
|||||||
Eine eigene Art und nicht "termin_gleich": Das eine ist ein
|
Eine eigene Art und nicht "termin_gleich": Das eine ist ein
|
||||||
Kalendereintrag, das andere ein Stream, der JETZT laeuft. Wer das
|
Kalendereintrag, das andere ein Stream, der JETZT laeuft. Wer das
|
||||||
eine stumm stellt, meint selten das andere. */
|
eine stumm stellt, meint selten das andere. */
|
||||||
{ schluessel: "dogfather_live", name: "DogFather ist live", vorgabe: true,
|
{ schluessel: "dogfather_live", eilig: true, name: "DogFather ist live", vorgabe: true,
|
||||||
/* „spaet", nicht „immer": Ein Stream, der um 22:05 anfaengt, ist um
|
/* „spaet", nicht „immer": Ein Stream, der um 22:05 anfaengt, ist um
|
||||||
22:05 interessant. Mit der alten Regel waere er stumm geblieben,
|
22:05 interessant. Mit der alten Regel waere er stumm geblieben,
|
||||||
und die Meldung, die Filipe ausdruecklich bestellt hat („die
|
und die Meldung, die Filipe ausdruecklich bestellt hat („die
|
||||||
@@ -257,7 +257,7 @@ export const ARTEN = [
|
|||||||
|
|
||||||
`ruhe: "spaet"` aus demselben Grund wie oben: Eine Reaction um
|
`ruhe: "spaet"` aus demselben Grund wie oben: Eine Reaction um
|
||||||
22:30 ist der Normalfall, keine Ausnahme. */
|
22:30 ist der Normalfall, keine Ausnahme. */
|
||||||
{ schluessel: "reaktion_live",
|
{ schluessel: "reaktion_live", eilig: true,
|
||||||
name: "Die Reaction geht auf Sendung", vorgabe: true, ruhe: "spaet" },
|
name: "Die Reaction geht auf Sendung", vorgabe: true, ruhe: "spaet" },
|
||||||
/* ---- ANRUFE SIND EINE EIGENE ART (18.09.2026) ------------------
|
/* ---- ANRUFE SIND EINE EIGENE ART (18.09.2026) ------------------
|
||||||
|
|
||||||
@@ -283,7 +283,7 @@ export const ARTEN = [
|
|||||||
ist kein Telefon. Wer nachts nicht gestoert werden will, schaltet
|
ist kein Telefon. Wer nachts nicht gestoert werden will, schaltet
|
||||||
jetzt diese Art ab -- eine Entscheidung, die man selbst trifft,
|
jetzt diese Art ab -- eine Entscheidung, die man selbst trifft,
|
||||||
statt einer Regel, die man nicht kennt. */
|
statt einer Regel, die man nicht kennt. */
|
||||||
{ schluessel: "anruf", name: "Jemand ruft an", vorgabe: true, ruhe: "nie" },
|
{ schluessel: "anruf", eilig: true, name: "Jemand ruft an", vorgabe: true, ruhe: "nie" },
|
||||||
/* DER TAGESRUF (08.09.2026, screen10). Filipe: "eine taetige meldung
|
/* DER TAGESRUF (08.09.2026, screen10). Filipe: "eine taetige meldung
|
||||||
einmal am tag zu aktivieren wenn noch aufgaben auf sind."
|
einmal am tag zu aktivieren wenn noch aufgaben auf sind."
|
||||||
|
|
||||||
@@ -323,10 +323,10 @@ export const ARTEN = [
|
|||||||
|
|
||||||
IM TEXT STEHT NIE, WORUM ES GEHT. Eine Benachrichtigung erscheint
|
IM TEXT STEHT NIE, WORUM ES GEHT. Eine Benachrichtigung erscheint
|
||||||
auf einem Sperrbildschirm, den auch andere sehen. */
|
auf einem Sperrbildschirm, den auch andere sehen. */
|
||||||
{ schluessel: "hilfe", name: "Vertrauliche Meldung: neu oder beantwortet", vorgabe: true },
|
{ schluessel: "hilfe", eilig: true, name: "Vertrauliche Meldung: neu oder beantwortet", vorgabe: true },
|
||||||
/* Die Probe beantwortet „kommt ueberhaupt etwas an?" -- und die
|
/* Die Probe beantwortet „kommt ueberhaupt etwas an?" -- und die
|
||||||
stellt man sich auch um 23 Uhr. */
|
stellt man sich auch um 23 Uhr. */
|
||||||
{ schluessel: "test", name: "Probe-Benachrichtigung", vorgabe: true, ruhe: "nie" },
|
{ schluessel: "test", eilig: true, name: "Probe-Benachrichtigung", vorgabe: true, ruhe: "nie" },
|
||||||
];
|
];
|
||||||
const ARTEN_SCHLUESSEL = new Set(ARTEN.map((a) => a.schluessel));
|
const ARTEN_SCHLUESSEL = new Set(ARTEN.map((a) => a.schluessel));
|
||||||
|
|
||||||
@@ -382,6 +382,49 @@ export function ruheRegel(art) {
|
|||||||
return ARTEN.find((a) => a.schluessel === art)?.ruhe || "immer";
|
return ARTEN.find((a) => a.schluessel === art)?.ruhe || "immer";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Ist diese Art EILIG -- also wertlos, wenn sie zu spaet kommt?
|
||||||
|
*
|
||||||
|
* WARUM DAS EINE EIGENE FRAGE IST (03.10.2026, nach Dienes Meldung).
|
||||||
|
*
|
||||||
|
* Diene hat gemeldet: "Die Benachrichtigungen werden nicht angezeigt,
|
||||||
|
* wenn neue Nachrichten reinkommen. Erst, wenn man die App oeffnet."
|
||||||
|
* Das war kein Fehler an ihrem Geraet und keiner am Service Worker --
|
||||||
|
* es war der Kopf `Urgency`, den wir mitschicken.
|
||||||
|
*
|
||||||
|
* Beide Push-Dienste behandeln "normal" ausdruecklich als "darf
|
||||||
|
* warten": Android/FCM haelt solche Meldungen zurueck, solange das
|
||||||
|
* Telefon doest, und stellt sie zu, wenn es aufwacht -- typischerweise,
|
||||||
|
* wenn jemand das Geraet entsperrt oder die App oeffnet. Apple/APNs
|
||||||
|
* nennt es "verzoegert, gebuendelt oder gedrosselt". Beschrieben ist
|
||||||
|
* damit genau Dienes Satz, Wort fuer Wort.
|
||||||
|
*
|
||||||
|
* Bis hierher hing die Dringlichkeit an der RUHEREGEL:
|
||||||
|
*
|
||||||
|
* const dringend = regel === "nie";
|
||||||
|
*
|
||||||
|
* Daneben stand die Begruendung, eine zweite Bedingung sei die, "die
|
||||||
|
* beim naechsten Nachschaerfen auseinanderlaeuft". Die Vorhersage war
|
||||||
|
* richtig, nur in die andere Richtung: Die zwei Fragen haben eben
|
||||||
|
* NICHT dieselbe Antwort.
|
||||||
|
*
|
||||||
|
* "Darf das nachts stoeren?" -> Chat: nein.
|
||||||
|
* "Darf das warten?" -> Chat: auch nein.
|
||||||
|
*
|
||||||
|
* Eine Nachricht um drei Uhr nachts soll schweigen -- um zwei Uhr
|
||||||
|
* nachmittags aber nicht vierzig Minuten liegen bleiben. Deshalb zwei
|
||||||
|
* Felder, aber in DERSELBEN Liste: auseinanderlaufen koennen sie nur,
|
||||||
|
* wenn sie an zwei Orten stehen.
|
||||||
|
*
|
||||||
|
* MASSSTAB: eilig ist, was durch Warten WERTLOS wird -- ein Anruf, ein
|
||||||
|
* Wecker, eine Nachricht, auf die jemand wartet, ein "wir sind live".
|
||||||
|
* Nicht eilig ist, was auch spaeter noch stimmt -- eine Aufgabe, die
|
||||||
|
* morgen faellig ist, der Tagesruf, eine Bewerbung. Waere alles eilig,
|
||||||
|
* waere nichts mehr eilig: Die Geraete duerfen uns die Dringlichkeit
|
||||||
|
* glauben, sonst drosseln sie uns -- und der Akku zahlt es mit. */
|
||||||
|
export function eiligRegel(art) {
|
||||||
|
return ARTEN.find((a) => a.schluessel === art)?.eilig === true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Ist gerade Ruhezeit -- fuer diese Regel?
|
/** Ist gerade Ruhezeit -- fuer diese Regel?
|
||||||
*
|
*
|
||||||
* `regel` steht hinten und hat eine Vorgabe, damit vorhandene
|
* `regel` steht hinten und hat eine Vorgabe, damit vorhandene
|
||||||
@@ -598,7 +641,21 @@ export async function benachrichtige(personId, art, { titel, text, ziel, merkmal
|
|||||||
schlafendes Geraet dafuer aufwacht. Das gilt fuer den Anruf und
|
schlafendes Geraet dafuer aufwacht. Das gilt fuer den Anruf und
|
||||||
die Probe -- nicht fuer eine Einladung: Die soll ankommen, wenn
|
die Probe -- nicht fuer eine Einladung: Die soll ankommen, wenn
|
||||||
das Geraet ohnehin wach wird, und keinen Akku dafuer verbrennen. */
|
das Geraet ohnehin wach wird, und keinen Akku dafuer verbrennen. */
|
||||||
const dringend = regel === "nie";
|
const eilig = eiligRegel(art);
|
||||||
|
/* KURZLEBIG IST NICHT DASSELBE WIE EILIG -- und das Zusammenlegen
|
||||||
|
waere hier der teure Fehler gewesen (03.10.2026).
|
||||||
|
|
||||||
|
Bis heute steuerte EIN Schalter beides: `dringend` hat das Geraet
|
||||||
|
geweckt UND die Haltbarkeit auf 150 Sekunden gesetzt. Haette ich
|
||||||
|
den Chat einfach auf `dringend` gestellt, waere aus "kommt vierzig
|
||||||
|
Minuten zu spaet" ein "kommt gar nicht mehr" geworden: Wer sein
|
||||||
|
Telefon drei Minuten aus hat, haette die Nachricht dann verloren.
|
||||||
|
Schlimmer als der Fehler, den ich beheben wollte.
|
||||||
|
|
||||||
|
Kurz haltbar bleibt deshalb genau das, was von selbst vorbei ist
|
||||||
|
-- der Anruf, der 120 Sekunden klingelt, und die Probe, bei der
|
||||||
|
jemand davorsteht. Das ist unveraendert `ruhe: "nie"`. */
|
||||||
|
const kurzlebig = regel === "nie";
|
||||||
|
|
||||||
/* Schon einmal geschickt? */
|
/* Schon einmal geschickt? */
|
||||||
if (merkmal) {
|
if (merkmal) {
|
||||||
@@ -633,14 +690,7 @@ export async function benachrichtige(personId, art, { titel, text, ziel, merkmal
|
|||||||
|
|
||||||
let raus = 0;
|
let raus = 0;
|
||||||
for (const a of anmeldungen) {
|
for (const a of anmeldungen) {
|
||||||
/* EIN ANRUF IST DRINGEND, ALLES ANDERE NICHT (19.09.2026).
|
const e = await schicken(a, inhalt, paar, ABSENDER, { eilig, kurzlebig });
|
||||||
|
|
||||||
`dringend` ist hier dasselbe `art === "anruf"`, das zwanzig
|
|
||||||
Zeilen weiter oben schon ueber die Ruhezeit entscheidet -- die
|
|
||||||
Frage „darf das nachts stoeren?" und „darf das warten?" haben
|
|
||||||
dieselbe Antwort. Eine zweite Bedingung waere die, die beim
|
|
||||||
naechsten Nachschaerfen auseinanderlaeuft. */
|
|
||||||
const e = await schicken(a, inhalt, paar, ABSENDER, { dringend });
|
|
||||||
if (e.ok) {
|
if (e.ok) {
|
||||||
raus++;
|
raus++;
|
||||||
db().prepare("UPDATE push_anmeldungen SET zuletzt_ok = ?, fehler = 0 WHERE endpunkt = ?")
|
db().prepare("UPDATE push_anmeldungen SET zuletzt_ok = ?, fehler = 0 WHERE endpunkt = ?")
|
||||||
|
|||||||
Reference in New Issue
Block a user