docs(phase-2): Phase 2 in acht Meilensteine schneiden
Phase 2 stand bisher nur als acht Stichpunkte im Epic. Jetzt je Meilenstein eine Datei mit Ziel, Aufgaben und Akzeptanzkriterien, dazu im Tracker gespiegelt: #48 bis #55, zusammen 76 h geschaetzt. Die Reihenfolge ist nicht beliebig. M15 fuehrt die Quellenart ein, die M16 braucht; M17 legt die Zusammensetzung fest, auf der M18 aufsitzt. Die anderen vier haengen an nichts und koennen jederzeit dazwischen. Drei Entscheidungen fallen vor dem Code und stehen je Meilenstein als erste Aufgabe mit Empfehlung: - Wie ein Baustein die Unveraenderlichkeit einer veroeffentlichten Version ueberlebt (Verweis im Entwurf, tiefe Kopie beim Veroeffentlichen). Ein Lauf sieht weiterhin konkrete Schritte und muss nichts lernen. - Wo Anhaenge liegen (Dateisystem, Metadaten in der Datenbank) -- mit der Folge, dass Compose-Stand, native Installation und sicherung.md ein Volume brauchen. Eine Sicherung, die nur die Datenbank mitnimmt, verliert ab dort Daten. - Was eine Selbstauskunft zeigt: Titel, Status, Zeitraum, Geraet, aber keine Schritte, Notizen, Kommentare oder Anhaenge. In einem Lauf stehen Arbeitsnotizen ueber Menschen; eine Selbstauskunft ist keine Akteneinsicht. Refs #2
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# #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, '<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
|
||||
Reference in New Issue
Block a user