fix: pruneEvents lief nie von selbst -- und eine Liste, was noch ginge

DIE FUNKTION GIBT ES SEIT DEM ERSTEN TAG und sie raeumt Ereignisse aelter als
180 Tage weg. Aufgerufen wurde sie aber nur von /maintenance/prune-sessions --
einem Weg, den nicht einmal die Oberflaeche anbietet. Die dokumentierte
Aufbewahrung griff damit NIE, und die Tabelle wuchs fuer immer.

Zum Vergleich: pruneSessions haengt seit jeher an einem stuendlichen Takt. Das
eine war verdrahtet, das andere nicht, und der Unterschied fiel niemandem auf,
weil beide in derselben Zeile des Wartungswegs stehen.

Gemessen: nach EINEM Tag mit Umzug und Serienlauf standen 5355 Zeilen in
events. Laeuft jetzt taeglich, mit zwei Minuten Verzoegerung nach dem Start --
nicht stuendlich wie die Sitzungen, denn ein DELETE ueber ein halbes Jahr hat
es nicht eilig.

Dazu docs/ideen.md: was beim Bauen und Messen wirklich aufgefallen ist, nach
Dringlichkeit sortiert. Mit einem eigenen Abschnitt fuer das, was gemessen
wieder heruntergefallen ist -- Doppelte (0,0 MB verschwendet), Aufraeumen nach
Alter (alle Stufen auf 0), eine Grenze fuer Bildmasse (12000x12000 kostet 374 ms
und 47 MB, libvips streamt). Damit sie nicht beim naechsten Mal wieder
aufschlagen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 01:21:09 +02:00
co-authored by Claude Opus 5
parent e8efa2431d
commit a91c4261de
2 changed files with 150 additions and 1 deletions
+137
View File
@@ -0,0 +1,137 @@
# Was noch ginge
Stand 12.08.2026. Diese Liste ist **nicht** eine Sammlung von allem, was
denkbar wäre — sie ist das, was beim Bauen und Messen wirklich aufgefallen ist.
Was hier steht, hat einen Grund; was keinen hatte, steht am Ende unter
„Verworfen, mit Begründung".
Sortiert nach dem, was ich zuerst täte.
---
## 1 · Sicher wertvoll
### Die Oberfläche auf dem Telefon
**Gemessen:** 18 Umbruchpunkte (`sm:`/`lg:`/`xl:`) im ganzen Frontend. Die
Galerie ist ein Raster und passt sich an — die **vier Tabellen** in Verlauf,
Token, Konten und Papierkorb nicht. Auf einem Telefon laufen sie seitlich
heraus.
Der Umbau ist keine Kosmetik: Karten statt Tabellenzeilen unterhalb einer
Breite, so wie es die Galerie schon macht. Betrifft vier Dateien.
**Lohnt sich nur, wenn du das Dashboard mobil aufmachst.** Sonst ist es
Arbeit für einen Bildschirm, den niemand benutzt.
### Sitzungen beenden können
**Gemessen:** 86 offene Sitzungen, davon 82 von `admin` — meine Testanmeldungen
von heute. Sie laufen nach 30 Tagen aus, und `pruneSessions` räumt stündlich
die abgelaufenen weg. Was fehlt, ist ein Knopf **„alle anderen Sitzungen
beenden"** im Kontomenü.
Das ist mehr als Ordnung: wer sich an einem fremden Rechner angemeldet hat und
es später merkt, hat heute keine Möglichkeit, das zurückzunehmen — außer das
Passwort zu ändern und zu hoffen, dass das die Sitzungen mitnimmt (tut es
nicht, sie hängen an einer eigenen Tabelle).
### Was der Verlauf nicht sieht
**Gemessen:** `events` kennt `upload`, `replace`, `delete`, `move`, `rename`
alles über **Dateien**. Nichts über **Einstellungen**. Wer den Discord-Webhook
geändert hat, wer einen Token angelegt oder gelöscht hat, wer ein Konto
entfernt hat: steht nirgends.
Bei zwei Konten ist das verschmerzbar. Sobald ein drittes dazukommt — und über
die Discord-Rolle entsteht es von selbst — ist es die erste Frage, die man
stellt, wenn etwas anders ist als gestern.
---
## 2 · Nützlich, wenn der Fall eintritt
### Massen-Umbenennen
Suchen und Ersetzen über Pfade, mit Vorschau vor dem Zuschlagen. Bei 3578 Items
ist eine Umbenennung von Hand keine.
Der Anlass wäre etwa: `items/` nach `inventar/` verschieben, oder eine
Namenskonvention ändern. Heute geht das nur Datei für Datei oder gar nicht.
**Die Warnung wäre dieselbe wie beim Ordner-Umbenennen** — jede alte Adresse
gibt danach 404 —, nur mal tausend.
### Bilder beim Ablegen verkleinern
Eine Obergrenze für die Kantenlänge, einstellbar je Token. Wer ein 6000 × 4000
großes Foto hochlädt, bekommt es auf, sagen wir, 2048 gerechnet.
**Gemessen und deshalb keine Dringlichkeit:** ein 12000 × 12000 großes PNG hat
den Dienst *nicht* in Verlegenheit gebracht — Vorschau in 374 ms, Speicher bei
47 MB von 31 GB. libvips arbeitet kachelweise und dekodiert nie das ganze Bild.
Es geht also um Plattenplatz und Ladezeit beim Ausliefern, nicht um Stabilität.
### Fehlende Bilder finden
Eine Liste hereinreichen (Fahrzeugmodelle, Item-Namen) und beantwortet
bekommen: **wozu fehlt ein Bild?** Heute beantwortet das niemand — das
Fotostudio weiß, was es aufgenommen hat, der Dienst weiß, was liegt, und die
Differenz rechnet niemand aus.
Das wäre ein Endpunkt, der eine Liste entgegennimmt und die fehlenden
zurückgibt. Klein, und die Antwort auf „warum zeigt das Handy bei manchen
Autos kein Bild".
### Einstellungen aus- und einlesen
Discord-Zugang, Sicherungsziel, Vorlagen, Meldungsanlässe — alles steht in
`settings` und ist beim Neuaufsetzen von Hand nachzutragen. Ein Export als JSON
(**ohne** die Geheimnisse, oder mit einer ausdrücklichen Ansage) macht aus
einer Stunde Klickerei fünf Minuten.
---
## 3 · Wäre schön, drängt nicht
- **Verlauf als CSV** — der Export kann heute nur Medien, nicht Ereignisse.
- **Meldung bei Upload** — Discord-Nachricht, wenn über einen Token etwas
Neues ankommt. Nützlich für Bildschirmfotos aus dem Spiel, sinnlos für einen
Serienlauf über 900 Fahrzeuge; bräuchte also eine Drossel.
- **Papierkorb mit Größendeckel** — heute nur 30 Tage. Wer 200 GB löscht, hat
sie 30 Tage lang doppelt. Bei 910 GB frei ist das keine Not.
- **Mehrere Sicherungsziele** — die Archive liegen auf derselben Platte wie die
Daten, die Kopie in der Nextcloud ist die einzige Trennung.
---
## Verworfen, mit Begründung
Diese standen auf der Liste und sind **gemessen** wieder heruntergefallen. Sie
stehen hier, damit sie nicht beim nächsten Mal wieder aufschlagen.
| Idee | Warum nicht |
|---|---|
| Doppelte Dateien zusammenführen | 5 Gruppen, **0,0 MB** verschwendet. Es gibt nichts zu holen. |
| Aufräumen nach Alter | Alle vier Altersstufen im Bericht stehen auf **0 Dateien**. Es ist nichts alt. |
| Grenze für Bildmaße als *Schutz* | 12000 × 12000 → 374 ms, 47 MB. libvips streamt, die Gefahr gibt es nicht. |
| Plattenplatz-Wächter | **Gebaut.** 80/90/95 %, meldet nach Discord. |
| Kontingent je Token | **Gebaut**, auf beiden Upload-Wegen geprüft. |
| Eigene Statusseite bauen | `/status` reicht — der d4rkbot zeigt sie schon an. |
---
## Und was heute noch schnell repariert wurde
**`pruneEvents` lief nie von selbst.** Die Funktion gibt es seit dem ersten Tag
und sie räumt Ereignisse älter als 180 Tage weg — aufgerufen wurde sie aber nur
von `/maintenance/prune-sessions`, einem Weg, den nicht einmal die Oberfläche
anbietet. Die dokumentierte Aufbewahrung griff damit **nie**, und die Tabelle
wuchs für immer.
Zum Vergleich: `pruneSessions` hängt seit jeher an einem stündlichen Takt. Das
eine war verdrahtet, das andere nicht, und der Unterschied fiel niemandem auf,
weil beide in derselben Zeile stehen.
Gemessen: nach **einem** Tag mit Umzug und Serienlauf standen 5355 Zeilen in
`events`. Läuft jetzt täglich, mit zwei Minuten Verzögerung nach dem Start.
+13 -1
View File
@@ -28,7 +28,7 @@ import { Hono } from 'hono'
import { logger } from 'hono/logger' import { logger } from 'hono/logger'
import { config } from './config.js' import { config } from './config.js'
import { ensureAdmin } from './auth.js' import { ensureAdmin } from './auth.js'
import { pruneSessions, schreibeAbrufe, zaehleAbruf } from './db.js' import { pruneEvents, pruneSessions, schreibeAbrufe, zaehleAbruf } from './db.js'
import { pruefePlatte, pruefeSicherung } from './meldung.js' import { pruefePlatte, pruefeSicherung } from './meldung.js'
import { absolutePath, checkPath, lohntWebp, mimeFor, thumbPath, webpPfad } from './storage.js' import { absolutePath, checkPath, lohntWebp, mimeFor, thumbPath, webpPfad } from './storage.js'
import { uploadRoutes } from './routes/upload.js' import { uploadRoutes } from './routes/upload.js'
@@ -391,6 +391,18 @@ ensureAdmin()
pruneSessions() pruneSessions()
setInterval(pruneSessions, 3600_000).unref() setInterval(pruneSessions, 3600_000).unref()
// UND DIE EREIGNISSE, taeglich. Das stand bisher NUR an einem Wartungsweg
// (/maintenance/prune-sessions), den nicht einmal die Oberflaeche anbietet --
// die dokumentierten 180 Tage Aufbewahrung griffen damit nie, und die Tabelle
// wuchs fuer immer. Nach einem einzigen Tag mit Umzug und Serienlauf standen
// dort 5355 Zeilen.
//
// Nicht stuendlich wie die Sitzungen: ein DELETE ueber eine Zeitspanne von
// einem halben Jahr hat es nicht eilig, und 24 Stunden Verzoegerung beim
// Wegraeumen fallen niemandem auf.
setTimeout(() => pruneEvents(), 120_000).unref()
setInterval(() => pruneEvents(), 86_400_000).unref()
// Der Wachhund fuer die Sicherung. Beim Start mit Verzoegerung (der Dienst // Der Wachhund fuer die Sicherung. Beim Start mit Verzoegerung (der Dienst
// soll erst stehen) und danach stuendlich. // soll erst stehen) und danach stuendlich.
// //