Files
Laufzettel/docs/issues/033-sse-live.md
T
florian.wilde b688e2ebc8
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s
docs(phase-2): Phase 2 in acht Meilensteine schneiden (#56)
2026-10-04 16:20:42 +00:00

2.9 KiB
Raw Blame History

#033 M20 – Live-Aktualisierung per SSE statt Polling

Status: offen Im Tracker: #53 Meilenstein: v0.2.0 Labels: phase-2, backend, frontend Geschätzt: 6 h Tatsächlich: –

Ziel

Die Abarbeitungsansicht fragt alle zehn Sekunden nach dem Zustand. Das reicht für zwei Techniker an einem Lauf, kostet aber bei zwanzig offenen Tabs zwanzig Abfragen je zehn Sekunden — und zehn Sekunden sind lang, wenn zwei Leute dieselbe Liste abhaken.

Die Vorleistung steht: das Polling liegt in genau einem Route Handler (/api/laeufe/[id]/zustand) und lässt sich tauschen.

Zu entscheiden

  • LISTEN/NOTIFY in Postgres als Signal — Empfehlung. Ein Trigger auf Schrittergebnis und Lauf schickt NOTIFY lauf_geaendert, '<laufId>'; der Route Handler hält eine Verbindung und schiebt weiter. Damit funktioniert es auch mit mehreren Instanzen der Anwendung, ohne einen zweiten Dienst. Die Alternative — der Server fragt selbst alle zwei Sekunden — wäre dasselbe Polling, nur an anderer Stelle.
  • Polling bleibt als Rückfall, nicht als zweite Wahrheit: derselbe Handler antwortet weiter auf eine gewöhnliche Anfrage. Wer kein EventSource hat oder hinter einem Proxy sitzt, der Ströme puffert, bekommt den alten Weg. Ein Rückfall, der nie geprüft wird, ist keiner — deshalb ein Test je Weg.

Aufgaben

  • Trigger und NOTIFY in einer handgeschriebenen Migration, mit dem üblichen Vermerk (Prisma kennt Trigger nicht und will sie löschen)
  • Route Handler liefert text/event-stream, schickt alle 25 s einen Kommentar als Herzschlag (sonst schließen Proxys die Verbindung) und beendet sauber bei abort
  • Der Handler prüft Recht und Mandant selbst — ein offener Strom ist ein Leseweg wie jeder andere (CLAUDE.md: Route Handler deckt die Hülle nicht ab)
  • Client: EventSource mit Wiederverbindung; bei versteckter Lasche pausieren wie heute; bei error auf Polling zurückfallen und das einmal melden, nicht bei jedem Versuch
  • docs/betrieb/reverse-proxy.md: proxy_buffering off für nginx, flush_interval -1 für Caddy — ohne das kommt kein Ereignis an, und die Seite sieht aus, als sei sie hängen geblieben
  • Obergrenze für gleichzeitige Ströme je Instanz, damit ein Browser mit vierzig Tabs die Verbindungen nicht aufbraucht

Akzeptanzkriterien

  • Test: zwei Sitzungen am selben Lauf — hakt die eine ab, sieht die andere es in unter einer Sekunde, ohne neu zu laden
  • Test: ohne Recht wird der Strom abgewiesen, bevor das erste Ereignis fließt
  • Test: ein Lauf eines fremden Kunden liefert keinen Strom
  • Test: der Rückfall auf Polling funktioniert — gefahren mit abgeschaltetem EventSource
  • Der Herzschlag kommt an: eine Verbindung überlebt 60 s ohne Änderung