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]>
This commit is contained in:
2026-10-03 13:03:29 +02:00
co-authored by Claude Opus 5
parent 73f9b24793
commit e349de0040
3 changed files with 146 additions and 2 deletions
+58 -2
View File
@@ -614,7 +614,48 @@ export function hausFuerMeldung(personId, ziel) {
}
}
export async function benachrichtige(personId, art, { titel, text, ziel, merkmal, zahl }) {
/** Verschickt eine Meldung -- und schreibt auf, was dabei herauskam.
*
* WARUM DAS PROTOKOLL AUSSEN SITZT (03.10.2026).
*
* `versenden` hat sieben Ausgaenge: unbekannte_art, abgeschaltet,
* ruhezeit, schon_geschickt, keine_geraete, nicht_zugestellt, ok.
* Haette jeder davon seine eigene Protokollzeile, waere das eine
* Liste zum Pflegen -- und der achte Ausgang, den jemand naechstes
* Jahr einbaut, wuerde sie stillschweigend umgehen. Genau so sind
* die Spalten beim Tabellenumbau am 11.09. verlorengegangen.
*
* Hier wird deshalb nichts aufgezaehlt: Was `versenden` auch immer
* zurueckgibt, wird festgehalten. Ein neuer Ausgang steht ohne
* Zutun mit drin.
*
* UND WARUM UEBERHAUPT: Als Diene meldete, sie bekomme nichts,
* konnte niemand nachsehen, ob je etwas hinausging. Die Frage
* "warum kommt es nicht an?" setzt voraus, dass "wurde es
* abgeschickt?" schon beantwortet ist -- im Shop hat das Ueberspringen
* dieser Reihenfolge am 06.09. zwei Stunden gekostet.
*
* Das Schreiben darf den Versand nie aufhalten: Eine Meldung, die
* ankommt, ist wichtiger als die Notiz darueber. Deshalb steht es
* in einem try -- aber mit Ausgabe, denn ein Protokoll, das
* heimlich nichts schreibt, ist schlimmer als keins. */
export async function benachrichtige(personId, art, sache) {
const e = await versenden(personId, art, sache);
try {
db().prepare(
"INSERT INTO push_versand (zeit, person_id, art, grund, geraete, zugestellt) "
+ "VALUES (?,?,?,?,?,?)")
.run(jetzt(), personId, art, e.grund || "unbekannt",
e.geraete || 0, e.verschickt || 0);
} catch (fehler) {
console.error("[push] Versand nicht protokolliert:", fehler?.message || fehler);
}
return e;
}
/* Der eigentliche Versand. Umhuellt von `benachrichtige` -- siehe
dort, warum das Protokoll aussen sitzt und nicht hier drin. */
async function versenden(personId, art, { titel, text, ziel, merkmal, zahl }) {
if (!ARTEN_SCHLUESSEL.has(art)) return { verschickt: 0, grund: "unbekannte_art" };
if (!willHaben(personId, art)) return { verschickt: 0, grund: "abgeschaltet" };
@@ -715,7 +756,7 @@ export async function benachrichtige(personId, art, { titel, text, ziel, merkmal
Nachricht aufmachen zu muessen -- derselbe Gedanke wie beim
Ziel. */
return { verschickt: raus, grund: raus ? "ok" : "nicht_zugestellt",
ziel: zielEcht, haus };
geraete: anmeldungen.length, ziel: zielEcht, haus };
}
/* ---------------------------------------------------------------------
@@ -1057,6 +1098,21 @@ export async function laufen() {
mehr, und die Tabelle soll nicht ewig wachsen. */
const grenze = new Date(Date.now() - 60 * 86400_000).toISOString();
d.prepare("DELETE FROM push_verschickt WHERE zeit < ?").run(grenze);
/* Das Sendeprotokoll ebenso -- 30 Tage.
Die Frist ist kuerzer als oben, weil die beiden Tabellen
verschiedene Fragen beantworten: push_verschickt verhindert
Doppelmeldungen und muss deshalb so lange halten wie die Sache
selbst. Das Protokoll beantwortet "kam letzte Woche etwas an?"
-- wer danach noch fragt, fragt nach etwas anderem.
Gemessen statt geschaetzt: rund 16 Chat-Nachrichten am Tag an
bis zu acht angemeldete Geraete, also hoechstens ein paar
tausend Zeilen im Monat. Die Tabelle bleibt klein genug, dass
niemand sie je bemerkt. */
d.prepare("DELETE FROM push_versand WHERE zeit < ?")
.run(new Date(Date.now() - 30 * 86400_000).toISOString());
} catch (fehler) {
console.error("[push] Lauf:", fehler?.message);
}