# 08 — Changelog Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum, Was, Warum, betroffene Dateien/Backups). ## 2026-08-17 — Systemanzeige in der Kopfzeile: Speicherring + Turbine **Wunsch:** zwischen dem Bluetooth-Tab und dem Hell/Dunkel-Schalter eine Anzeige, die den belegten Speicherplatz in Prozent zeigt, dazu ein zweites Symbol, das bei Mauskontakt CPU-Last, RAM und Temperatur aufklappt — als Turbine, die sich mit steigender Last schneller dreht. **Umsetzung:** - Neues Modul `sysstat.js` mit `status()`: Platte über `fs.statfsSync` (gemessen wird die Partition mit den Aufnahmen, Prozentwert wie `df` inklusive root-Reserve), RAM aus `/proc/meminfo` (`MemAvailable`, nicht `MemFree`), CPU-% aus der Differenz zweier `/proc/stat`-Messpunkte, Temperatur als wärmste SoC-/Core-/Center-/GPU-/NPU-Zone (WLAN-Zone `iwlwifi_1` ausgeschlossen). Eigener 2-s-Ticker (`unref()`), sonst wäre die erste CPU-Antwort nach jedem Start 0 %. - `GET /api/sysstat` in `server.js` — ohne `wrap()`/Warteschlange, weil es reine `/proc`-Lesevorgänge sind und die Abfrage keinen Prozess startet. - GUI (`web/src/main.js`): `sysmonMarkup()` zeichnet beide Chips, `paintSysmon()` schreibt die Werte ins DOM, `tickSysmon()` pollt alle 5 s (im Hintergrund-Tab ausgesetzt). Ein einziger Ticker für alle `render()`-Läufe; direkt nach `render()` werden die letzten Werte zurückgemalt, weil `render()` die Kopfzeile komplett neu schreibt und die Chips sonst bis zum nächsten Poll leer stünden. - Turbine: fünf Flügel als SVG-Pfade, Drehdauer per CSS-Variable `--spin`. Die Dauer läuft bewusst in **Stufen** (7 s Leerlauf … 0,35 s ab 90 %) — eine stufenlos nachgeführte `animation-duration` setzt die laufende Drehung bei jedem Poll neu an und ruckt sichtbar. `prefers-reduced-motion` stoppt sie. - Speicherring: `` (Umfang exakt 100) ⇒ `stroke-dasharray` = Prozentwert. - Ampel: grün < 75 %, gelb ab 75 %, rot ab 90 %; bei der Turbine zählt der schlimmste Wert aus CPU, RAM und Temperatur (45 °C → 0 %, 90 °C → 100 %). - Karten öffnen rein über CSS (`.sys-chip:hover .sys-pop`, zusätzlich `:focus-within` für Tastatur) — kein Handler, der einen `render()`-Durchlauf überleben müsste. **Dateien:** neu `app/sysstat.js`; geändert `app/server.js` (`.bak-sysmon`), `app/web/src/main.js` (`.bak-sysmon`), `app/web/src/style.css` (`.bak-sysmon`). Vite-Build + `systemctl restart callrec` (vorher geprüft: keine Analyse `pending`). Verifiziert: `/api/sysstat` liefert 52,4 % Platte (`df` sagt 53 %), 46 °C, 8 Kerne. Doku: Kapitel 07. ## 2026-08-17 — Kontext zum Gespräch: ein Freitextfeld nach dem Stop **Wunsch:** nach dem Beenden einer Aufnahme die Möglichkeit haben, Kontext zum gerade geführten Call/Meeting zu ergänzen — das verbessert die Analyse nach dem Transkript erheblich, weil das Modell Personen, Firmen, Anlass und Eigennamen nicht mehr aus fehlerbehaftetem ASR-Text erraten muss. **Entscheidung des Nutzers: EIN Freitextfeld, kein Formular.** Ein Vorschlag mit Teilnehmer-, Anlass-, Projekt- und Begriffsfeldern wurde ausdrücklich verworfen: die Box benutzen später auch technisch nicht versierte Menschen, und „Kontext hinzufügen“ ist eine Hürde weniger als vier Pflichtfelder. Geführt wird über den Platzhaltertext, die Struktur (Namen, Begriffe) zieht sich die Analyse selbst aus der Prosa. **Umsetzung:** - Neue Spalten `recordings.context_note` / `context_note_at` (`ensureSchema`), `db.setContextNote()` (Deckel 4 000 Zeichen, leerer Text löscht) und `db.getContextNote()`. - `PATCH /api/recordings/:id/context`. Die Antwort enthält `applies` und sagt damit **ehrlich**, ob die Notiz die laufende Verarbeitung noch erreicht: `auto` (wird noch transkribiert → fließt sicher ein), `running` (Analyse läuft schon, kann sie verpasst haben), `reanalyze` (fertig → nur ein neuer Lauf nutzt sie; die GUI fragt dann nach und startet `reanalyze-llm`). - `analyzeRecording()` liest die Notiz **erst kurz vor dem LLM-Aufruf** (`db.getContextNote`), nicht aus der Zeile vom Anfang: Sprecher-Erkennung und Transkription davor brauchen Minuten, und was der Nutzer in dieser Zeit tippt, soll noch mitzählen. - `llm.js`: neuer `contextBlock()` — die Notiz kommt in einem eigenen `"""`-Block mit der Auflage, sie **nur** für Schreibweisen, Zuordnung, Anlass und Gewichtung zu nutzen und daraus keine Aussagen, Ergebnisse oder Aufgaben abzuleiten. Eingespeist in alle Pfade: `analyzeSingle` (`PROMPT_CLEAN`, `PROMPT_CLEAN_LABELED`, `PROMPT_JSON`), `analyzeWhole` (`PROMPT_WHOLE_ANALYZE`) und `analyzeLong` (jeder Chunk-Prompt + Titel- und Überblick-Mikro-Call). Zwei Deckel: 1 200 Zeichen für die Prompts, die die Notiz einmal sehen, 600 für die Chunk-Prompts (dort landet sie in **jedem** Chunk von 3 200 Zeichen). Auf dem letzten von drei Chunk-Versuchen fällt sie mit dem `hint` weg. - GUI: Karte „📝 Kontext zum Gespräch“ über den Modulen der Detailansicht. Nach dem Stop steht sie offen und fokussiert (`state.ctxPromptFor`), sonst eingeklappt mit dem gespeicherten Text und „✏️ Bearbeiten“. Sie zeichnet sich **selbst** neu statt über `openRecording()` — ein Neuaufbau der Detailansicht setzt den `