# #033 M20 – Live-Aktualisierung per SSE statt Polling **Status:** offen **Im Tracker:** [#53](https://git.wilde-server.de/florian.wilde/Laufzettel/issues/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, ''`; 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