diff --git a/app/web/src/main.js b/app/web/src/main.js
index d4cd4a8..bd0d528 100644
--- a/app/web/src/main.js
+++ b/app/web/src/main.js
@@ -1652,4 +1652,22 @@ function analysisBadge(st) {
return '';
}
+// Der Aufnahmezustand lebt im Server (recorder.js `current`), nicht im Browser.
+// Ohne diesen Abgleich zeigt der Recorder nach jedem Neuladen 00:00, obwohl
+// parecord weiterläuft — und der Stop-Knopf ist unerreichbar, weil das Kopfband
+// dann den Start-Knopf malt.
+async function rehydrateRecording() {
+ try {
+ const h = await api.get('/api/health');
+ if (!h || !h.recording) return;
+ state.recording = true;
+ state.recStart = h.startedAt || Date.now();
+ state.markers = h.markers || [];
+ state.mkDraft = '';
+ render();
+ if (state.tab === 'recordings') { state.lastListSig = null; refreshRecList(); }
+ } catch (err) { /* Server nicht erreichbar: normale Ansicht, kein Toast */ }
+}
+
render();
+rehydrateRecording();
diff --git a/docs/03-aufnahme-pipeline.md b/docs/03-aufnahme-pipeline.md
index 87375bb..d73285c 100644
--- a/docs/03-aufnahme-pipeline.md
+++ b/docs/03-aufnahme-pipeline.md
@@ -110,10 +110,46 @@ linear — bei konstanter Bitrate exakt.
30,3 MB. Der Altbestand wurde einmalig mit `lab/recode-cbr.sh` umgeschrieben (Quelle: die WAV, wo noch
vorhanden — sonst die MP3 selbst, dann ohne erneute Filter).
+## Der Aufnahmezustand gehört dem Server (Reload-Sicherheit)
+
+Wer aufnimmt, weiß nur `recorder.js` — dort hält `current` den laufenden `parecord`-Prozess, den WAV-Pfad,
+den Startzeitpunkt und die Namensmarker. Die GUI ist reiner Betrachter: sie muss sich diesen Zustand beim
+Laden **holen**, denn ihr eigener `state.recording` ist nach jedem `F5`, Tab-Wechsel des Browsers oder auf
+einem zweiten Gerät wieder `false`.
+
+```mermaid
+flowchart TB
+ A["Seite lädt: render()"] --> B["rehydrateRecording()
GET /api/health"]
+ B --> C{"recording?"}
+ C -- nein --> D["Recorder zeigt ●, 00:00 — korrekt"]
+ C -- ja --> E["state.recording = true
recStart = startedAt (Server-Epoche)
markers = Server-Marker"]
+ E --> F["render(): ■ Stop, laufende Zeit,
Namensfeld, Marker-Chips, Live-Karte in der Liste"]
+```
+
+`GET /api/health` ist die einzige Quelle dafür und liefert genau das Nötige:
+
+```json
+{ "ok": true, "recording": true, "startedAt": 1786359542932, "source": "default",
+ "markers": [ { "t_ms": 8401, "name": "Markus Ufer" } ] }
+```
+
+- `recStart` kommt als **Server-Epoche**; der Timer rechnet `Date.now() - recStart`. Epoch-Werte sind
+ zeitzonenfrei (Board läuft auf UTC, Browser auf CEST) — nur eine echte Uhrabweichung würde verschieben.
+- Fehlschlag ist absichtlich still: kein Toast, die GUI startet dann einfach im Normalzustand.
+- Zweites Gerät bekommt dieselbe laufende Aufnahme angezeigt — der Zustand ist nicht mehr an einen Tab
+ gebunden.
+
+⚠️ **Warum das mehr als Kosmetik ist:** ohne den Abgleich malt das Kopfband nach dem Neuladen den
+Start-Knopf (●), der Stop-Knopf ist also unerreichbar, während `parecord` weiterschreibt. Ein Druck auf ●
+läuft in `recorder.js` gegen `if (current) throw new Error('already recording')` — es gibt keinen
+Datenverlust, aber auch keinen Weg mehr, die Aufnahme aus der GUI zu beenden. Notausgang ohne GUI bleibt
+`curl -X POST localhost:3000/api/record/stop` (speichert regulär und startet die Transkription).
+
## API-Endpunkte (Auszug)
| Endpunkt | Zweck |
|---|---|
+| `GET /api/health` | Läuft eine Aufnahme? (`recording`, `startedAt`, `source`, `markers`) — Grundlage der Reload-Wiederherstellung |
| `POST /api/recordings/:id/retranscribe` | Hängende/fehlgeschlagene Transkription neu starten |
| `POST /api/recordings/:id/reanalyze` `{numSpeakers?}` | Diarization **immer** neu (leer/0 = automatisch, Zahl = Anzahl gepinnt) + LLM neu |
| `POST /api/recordings/:id/reanalyze-llm` | Nur LLM neu, Diarization/Wörter bleiben |
diff --git a/docs/08-changelog.md b/docs/08-changelog.md
index e9a3c4c..3c2bb68 100644
--- a/docs/08-changelog.md
+++ b/docs/08-changelog.md
@@ -3,6 +3,39 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups).
+## 2026-08-10 — Recorder überlebt das Neuladen (GUI holt den Zustand vom Server)
+
+**Symptom:** während einer laufenden Aufnahme klickte der Nutzer in eine andere Aufnahme; danach stand der
+Recorder auf `00:00` und zeigte den Start-Knopf — auch nach `F5`. Die Aufnahme schien gestorben.
+
+**Sie lief die ganze Zeit.** Gemessen am Board: `parecord` PID 236484, Elternprozess = die Node-App, seit
+10:59:02 UTC; die WAV wuchs um ~32 kB/s (16 kHz mono s16 = korrekt); `GET /api/health` meldete
+`{"recording":true,"startedAt":1786359542932}` samt allen drei Namensmarkern.
+
+**Ursache:** `web/src/main.js` hielt `recording`/`recStart`/`markers` ausschließlich im Browser-`state`
+(Zeile 12, Startwert `false`/`0`) und fragte den Server **nie** danach — `grep -rn "api/health" web/src/`
+ergab null Treffer. Jedes Neuladen setzte die GUI also auf „keine Aufnahme" zurück, obwohl `recorder.js`
+weiter aufnahm. Fatal daran ist nicht die falsche Anzeige, sondern dass das Kopfband dann ● statt ■ malt:
+der Stop-Knopf war unerreichbar. Immerhin ohne Datenrisiko — `recorder.js:270`
+`if (current) throw new Error('already recording')` verhindert eine zweite Aufnahme über dieselbe WAV.
+
+**Fix:** neue Funktion `rehydrateRecording()` am Ende von `main.js`, aufgerufen direkt nach dem ersten
+`render()`. Sie liest `GET /api/health` und stellt `recording`, `recStart` (= `startedAt`, Server-Epoche)
+und `markers` wieder her, rendert neu und frischt die Aufnahmenliste auf (Live-Karte). Ein Fehler bleibt
+still (kein Toast), damit ein nicht erreichbarer Server nur die Normalansicht bedeutet. Nebeneffekt: ein
+zweites Gerät sieht die laufende Aufnahme jetzt ebenfalls.
+
+**Verifiziert:** `vite build` sauber (`dist/assets/index-B3z3XrMo.js`, `api/health` im Bundle enthalten,
+`dist/index.html` verweist darauf). **Kein `systemctl restart`** — nur statische Dateien getauscht, die
+laufende Aufnahme blieb unangetastet (`recording:true` vor und nach dem Build, Marker intakt).
+
+Dateien: `app/web/src/main.js` (Board-Backups `src/main.js.bak-rehydrate`, `web/dist.bak-rehydrate`),
+Kapitel 03 (neuer Abschnitt „Der Aufnahmezustand gehört dem Server" + `/api/health` in der Endpunkt-Tabelle).
+
+⚠️ **Nebenbefund, nicht behoben:** `enroll-from-recording failed: spk beendet` bei #107 und #85 — TitaNet
+stirbt im ONNX-`Where`-Knoten (`Attempting to broadcast an axis by a dimension other than 1. 12288 by
+30733`), das Stimmabdruck-Lernen aus langen Aufnahmen fällt also aus. Eigener Punkt.
+
## 2026-08-07 (3) — Eine Person darf mehrere Namen haben (und mehrere Stimmproben)
**Warum:** die Identität war der NAME. Derselbe Mensch, in einer Aufnahme „Sascha" und in der nächsten