Ein Feld, ein Knopf, grosse Flaeche. Was ohne Netz erfasst wird, liegt in
IndexedDB, bis es hinausgeht — nicht in localStorage: Ein Eintrag, der
beim Aufraeumen des Speichers verschwindet, ist eine verlorene Aufgabe.
Erst anstellen, dann senden. Andersherum ginge der Eintrag verloren, wenn
der Browser mitten im Senden geschlossen wird. Jede Erfassung traegt eine
vom Geraet vergebene Kennung, damit eine doppelt zugestellte Nachricht
keine zweite Aufgabe ergibt.
Der Dienstarbeiter haelt genau diese eine Seite offline bereit und sonst
nichts. Ein halb veralteter Planer waere schlimmer als gar keiner — ein
Eingabefeld dagegen veraltet nicht, und ohne die Seite naehme die
Warteschlange im Geraet niemandem etwas ab.
Dazu das Manifest, damit sich der Planer als Anwendung ablegen laesst.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Push ueber VAPID, Mail ueber SMTP, beide unabhaengig zuschaltbar. Die
Schluessel eines Push-Geraets liegen verschluesselt in der Datenbank.
Ein Geraet, das der Push-Dienst mit 404 oder 410 ablehnt, wird sofort
entfernt; andere Fehler zaehlen hoch und fuehren nach fuenf Versuchen
zum selben Ergebnis. Eine Liste toter Abos putzt sich so von allein.
Der Nachweis wird vor dem Senden geschrieben, nicht danach: lieber eine
verpasste Nachricht als eine, die im Minutentakt erneut versucht wird.
Weder Endpunkt noch Schluessel noch Mailinhalt landen im Protokoll.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dreistufiges Dockerfile mit standalone-Ausgabe; im Laufzeitabbild liegen
weder Quelltext noch Bauwerkzeuge, und es läuft unter einem eigenen
Benutzer.
Die Migrationen erledigt ein eigener Einmaldienst aus der Bau-Stufe. Der
Versuch, nur die Prisma-CLI ins Laufzeitabbild zu kopieren, scheiterte an
ihren transitiven Modulen; sie alle mitzunehmen hätte das Abbild
aufgebläht. Der Dienst läuft vor der App und muss sauber durchlaufen.
Zwei Stellen mussten faul werden, weil Next beim Bauen Seitendaten
sammelt und dabei Module lädt, die es zur Bauzeit noch ohne
Umgebungsvariablen gibt:
- Der Prisma-Client entsteht erst beim ersten Zugriff, über einen Proxy.
- Die Auth.js-Konfiguration wird als Funktion übergeben.
Ebenso liest prisma.config.ts die URL über process.env statt über env(),
das beim Bauen ohne Datenbank abbricht.
Dazu backup.sh, update.sh mit Rückrollpfad und scripts/release.sh. Der
Dump wurde nachweislich in eine Wegwerf-Datenbank zurückgespielt und
stimmt zeilengenau mit dem Original überein. Alle Skripte sind
shellcheck-sauber.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>