feat(gui): Systemanzeige in der Kopfzeile (Speicherring + Turbine)

Zwei Symbole zwischen Bluetooth-Tab und Hell/Dunkel-Schalter: ein Ring mit
der Plattenbelegung in Prozent und eine Turbine, deren Drehzahl der CPU-Last
folgt. Beide klappen bei Mauskontakt eine Karte mit Zahlen auf (belegt/frei/
gesamt bzw. CPU, RAM, Temperatur).

Neues Modul sysstat.js liest alles aus /proc bzw. fs.statfsSync, damit die
GUI im Sekundentakt fragen kann, ohne df/top-Prozesse zu starten. CPU-% aus
zwei /proc/stat-Messpunkten mit eigenem 2-s-Ticker, RAM ueber MemAvailable,
Temperatur als waermste SoC-/Core-Zone.

Doku: Kapitel 07 + Changelog.
This commit is contained in:
Claude
2026-08-17 21:52:21 +02:00
parent 0f530b575a
commit 47288c0479
6 changed files with 334 additions and 1 deletions
+33
View File
@@ -3,6 +3,39 @@
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: `<circle r="15.9155">` (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