Commit Graph
35 Commits
Author SHA1 Message Date
Claude 51c1e0f675 fix(gui): Speicherkarte auf eine Zeile, Prozentzahl immer sichtbar
Klappkarte zeigt nur noch "Aufnahmen: x,y GB - n Dateien"; Balken, Restplatz,
Vorratsgroesse, Erklaertext und Partitions-Fusszeile sind raus.

Die Media-Query, die unter 900 px Fensterbreite die Prozentzahl neben dem
Ring ausblendete, ist entfernt - der Wert steht jetzt in jeder Breite.

Doku: Kapitel 07 + Changelog.
2026-08-17 22:17:42 +02:00
Claude db50c9616d fix(gui): Ventilator-Icon und Speicheranzeige auf Aufnahme-Vorrat
Das erste Icon las sich als Kleeblatt. Jetzt vier gebogene Pinwheel-Fluegel
in einem feststehenden Gehaeusering; nur die Fluegel drehen. Form vorab ohne
Browser geprueft (lab/preview_fan.py rendert die Bezier-Kandidaten als PNG).

Die Prozentzahl misst nicht mehr die Partition, sondern den Aufnahme-Vorrat:
100 % = freier Platz + alle Audiodateien unter recordings/, belegt = diese
Dateien. System, Modelle und node_modules fallen aus Zaehler und Nenner
heraus; der df-Wert steht als Fusszeile in der Klappkarte.

sysstat.js scannt recordings/ per readdir+stat (kein du-Prozess) und puffert
60 s; status() ist dadurch async, die Route laeuft ueber wrap().

Doku: Kapitel 07 + Changelog.
2026-08-17 22:03:17 +02:00
Claude 47288c0479 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.
2026-08-17 21:52:21 +02:00
Claude 0f530b575a feat(analyse): Kontextnotiz zum Gespraech nach dem Stop
Ein Freitextfeld ("Kontext zum Gespraech") in der Detailansicht, nach dem
Stop aufgeklappt. Der Text geht als Hintergrundwissen in die LLM-Analyse:
Personen, Firmen, Anlass und Eigennamen muessen nicht mehr aus dem
fehlerbehafteten ASR-Text erraten werden.

Bewusst EIN Feld statt eines Formulars mit Teilnehmer-/Anlass-/Begriffs-
feldern (Entscheidung des Nutzers): die Box benutzen auch technisch nicht
versierte Menschen. Gefuehrt wird ueber den Platzhaltertext, die Struktur
zieht die Analyse selbst aus der Prosa.

- recordings.context_note/-_at, db.setContextNote/getContextNote
- PATCH /api/recordings/:id/context; Antwort `applies` sagt ehrlich, ob die
  Notiz die laufende Verarbeitung noch erreicht (auto/running/reanalyze)
- analyzeRecording liest die Notiz erst kurz vor dem LLM-Aufruf, damit
  waehrend der minutenlangen Vorstufen Getipptes noch zaehlt
- llm.contextBlock: eigener """-Block mit Verbot, daraus Aussagen, Ergebnisse
  oder Aufgaben abzuleiten (sonst schreibt das 4B-Modell die Notiz als
  Gesagtes zurueck); eingespeist in Single-, Whole- und Sektions-Pfad
- zwei Deckel: 1200 Zeichen fuer Prompts, die die Notiz einmal sehen,
  600 fuer die Chunk-Prompts (dort landet sie in jedem Chunk von 3200)
- GUI-Karte zeichnet sich selbst neu (kein openRecording -> Audio laeuft
  weiter), ungespeicherter Text ueberlebt den Neuaufbau nach der Analyse

Verifiziert an #97: Kontext greift (korrekte Namen, richtiges Thema), die
absichtlich eingelegten Fremdfakten der Testnotiz erscheinen nicht in der
Zusammenfassung. Alte Analyse danach zurueckgeschrieben.

Doku: Kapitel 05 (neuer Abschnitt + Flussdiagramm + Deckel-Tabelle),
Kapitel 03 (Sequenzdiagramm + API), Changelog 2026-08-17.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 16:10:38 +02:00
Sascha 3d628b4b96 feat(projekt): Anheftungen per Drag & Drop zwischen Unterreitern verschieben
Pin-Zeilen in der Ordneransicht sind draggable, die Reiter sind Ablageziele.
Ein Drop schickt PATCH /api/projects/:id/pins/:pinId {tab_id}; movePin schreibt
project_pins.tab_id um. Verschoben wird nur die Referenz.

- Zielebene hat die Aufnahme schon: Quell-Pin loeschen statt an UNIQUE uniq_pin
  scheitern (merged:true)
- Zielreiter serverseitig gegen den Ordner pruefen, sonst 404
- .ptab-n braucht pointer-events:none, sonst flackert die Ablagemarkierung

Verifiziert gegen die laufende App inkl. 404- und Merge-Faellen; Testdaten
zurueckgesetzt. Doku: Kapitel 10 + Changelog.
2026-08-14 14:52:14 +02:00
SaschaandClaude Opus 5 2be938c91b fix(gui): Recorder-Zustand nach Neuladen vom Server holen
Die GUI hielt `recording`/`recStart`/`markers` nur im Browser-State und fragte
den Server nie danach. Nach jedem F5 stand der Recorder auf 00:00, obwohl
parecord weiterlief — und das Kopfband malte den Start- statt des Stop-Knopfes,
die laufende Aufnahme war aus der GUI also nicht mehr beendbar.

`rehydrateRecording()` liest nach dem ersten render() `GET /api/health` und
stellt Laufzeit, Namensmarker und Live-Karte wieder her; Fehler bleiben still.
Nebeneffekt: ein zweites Gerät sieht die laufende Aufnahme ebenfalls.

Doku: Kapitel 03 neuer Abschnitt + /api/health in der Endpunkt-Tabelle,
Changelog-Eintrag 2026-08-10.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 13:18:11 +02:00
Sascha 2228c57522 feat(persons): eine Person, mehrere Namen und mehrere Stimmproben
Die Identitaet war der NAME. Derselbe Mensch, einmal "Sascha" und einmal
"Sascha Wolf" benannt, existierte zweimal und konnte zwei Cluster benennen
-- Aufnahme #101 (34 s, zwei Menschen) zeigte Michael/Sascha/Sprecher 3/
Sascha Wolf. Der Vornamens-Trick in diar.js hat das ueberdeckt, setzte aber
auch "Markus Ufer" und "Markus Witsch" gleich (Kosinus 0,241).

Neu: persons + person_names (Name = PK, gehoert genau einer Person),
voiceprints.person_id. Mehrere Proben pro Person (max. 8) statt eines
laufenden Mittels; bewertet wird die beste Probe. Score UND Abstand rechnen
zwischen Personen -- vorher rissen zwei Abdruecke desselben Menschen (0,928)
die Abstandspruefung, womit die Zwangsbedingung faktisch aus war.
diar.identityKey bildet Marker-Namen und Abdruecke auf p<person_id> ab.

GUI "Stimmen" zeigt Personen mit Namens-Chips: Namen hinzufuegen/entfernen,
Personen zusammenfuehren, Proben verwerfen.

Altbestand geleert (Dump in backup/), weil lab/vpcos.mjs neben echten
Dubletten (Jens ~ Jens Kuppler = 1,000) auch kontaminierte Abdruecke zeigte:
Johannes lag mit 0,912 an Sascha Wolf, aber 0,115 an Johannes Jeckel.

Verifiziert an #101: Sascha Wolf als zweiter Name derselben Person ->
Re-Diarisierung benennt nur noch Michael + Sascha statt drei Namen fuer zwei
Menschen. GUI mit Playwright geprueft, keine JS-Fehler.
2026-08-07 16:18:33 +02:00
schakal00783andClaude Opus 5 aa0098ae01 fix: Knoepfe rutschten aus der Zeile; verwaiste Audiodateien raeumen
1. Aufnahmenliste: bei schmaler Spalte schob ein langer Titel die Knoepfe aus
der Zeile, der Papierkorb-Knopf war nicht mehr erreichbar. Flex-Kinder haben
min-width: auto, der Textblock schrumpft also nie unter seine Inhaltsbreite.
Mit der dritten Schaltflaeche (Stecknadel) reichte der Platz nicht mehr.

2. 23 sichtbare Aufnahmen = 46 Dateien, im Ordner lagen 152: 106 verwaiste mit
242 MB, Rueckstand des alten deleteRecording, das nur die DB-Zeile entfernte.
Einmalig geraeumt (Gegenprobe: keine der 106 stand in einer Zeile, danach
fehlt keine benoetigte Datei) und sweepOrphans haelt es sauber -- laeuft hinter
sweepTrash beim Start und taeglich, mit 2-h-Altersgrenze, weil eine Aufnahme
erst verschoben und dann in die DB geschrieben wird.

Die Papierkorb-Kette selbst war korrekt, mit einer Wegwerf-Zeile nachgewiesen:
loeschen -> Papierkorb (Dateien bleiben), endgueltig -> Zeile und beide Dateien
weg.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 23:53:54 +02:00
schakal00783andClaude Opus 5 3496b4a2df feat(gui): gruene Nadel bei angehefteter Aufnahme, Logo fuehrt zu den Aufnahmen
Der Anheften-Knopf zeigte bei angehefteter Aufnahme nur die Zahl, die Nadel
blieb rot. Sie ist jetzt gruen (--ok, wie das "KI ✓"-Abzeichen). Dafuer
ersetzt ein SVG mit currentColor (ICON_PIN, gleiches Muster wie ICON_TABLE)
das 📌-Emoji: ein Farb-Emoji rendert immer rot, color greift daran nicht.

Klick auf Wellen-Logo und Schriftzug wechselt auf den Reiter "Aufnahmen".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 23:14:41 +02:00
schakal00783andClaude Opus 5 d0e02eb976 feat(gui): Ordner-Ebene eines Projekts umbenennbar
Der erste Reiter hieß fest "Ordner" und trägt jetzt einen frei wählbaren
Namen. Er steht in der neuen Spalte projects.root_tab_name (NULL = "Ordner")
statt als Zeile in project_tabs: die Ordner-Ebene ist kein echter Reiter --
es gibt sie immer, sie hat keine eigene id und ist nicht löschbar. Eine
eigene Zeile hätte eine id gebraucht, die in project_pins.tab_id landen
müsste, womit die "0 = Ordner-Ebene"-Regel und damit der UNIQUE-Index
gefallen wären.

PATCH /api/projects/:id/tabs/0 fängt die 0 ab und schreibt ins Projekt;
leerer Name setzt auf "Ordner" zurück. Ebenen-Auswahl im Pin-Dialog und die
Liste bestehender Anheftungen zeigen den Namen mit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 23:11:12 +02:00
schakal00783andClaude Opus 5 772385713e feat(gui): Projektansicht mit Ordnern, Unterreitern und angehefteten Aufnahmen
Neuer Reiter neben "Aufnahmen": Projektordner bündeln Aufnahmen zweistufig
(Ordner + Unterreiter), auf beiden Ebenen anheftbar. Anheften geht aus dem
Projekt heraus (Dropdown mit Filter) oder über den 📌-Knopf in der
Aufnahmenliste, der Ordner und Ebene abfragt, neue Ordner anlegt und
bestehende Anheftungen zum Lösen zeigt. Klick auf eine angeheftete Aufnahme
springt in die Aufnahmen-Ansicht.

Ein Pin ist eine Referenz, kein Besitz: die Aufnahme bleibt unverändert in
der Liste und darf in mehreren Ordnern hängen.

project_pins.tab_id ist INT NOT NULL DEFAULT 0 (0 = Ordner-Ebene) statt NULL,
weil MariaDB NULL von UNIQUE-Indizes ausschließt — sonst ließe sich dieselbe
Aufnahme mehrfach auf dieselbe Ebene anheften. So macht INSERT IGNORE das
Anheften idempotent.

purgeRecording räumt project_pins mit ab; getProject blendet Aufnahmen im
Papierkorb aus, ohne deren Pin zu löschen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 23:05:07 +02:00
Sascha 914ab2ddc8 feat(gui): Abschnittstitel der Zusammenfassung fett
Die Section-Zusammenfassung kommt als "Titel:\nFliesstext"-Bloecke zurueck, wurde aber
als flache Textwand gerendert. renderSummary() setzt Titelzeilen jetzt fett.

Im Renderer statt in der DB, damit es sofort fuer alle vorhandenen Zusammenfassungen
gilt, ohne 22 Aufnahmen je 20 Minuten neu zu analysieren.

Regel /^[^.!?]{3,90}:$/ = kurze, alleinstehende Zeile mit Doppelpunkt am Ende. Gegen
die echten Zusammenfassungen #85/#79/#74 geprueft: 37 Titel erkannt, keine
Fliesstextzeile falsch fett, keine Doppelpunkt-Zeile uebersehen.
2026-07-31 13:43:54 +00:00
Sascha d5b9733e78 feat(gui+search): Inhaltssuche mit Zeitstempel-Verweis, Papierkorb (30 Tage), Titel umbenennen
Drei vom Nutzer angeforderte Funktionen.

Titel umbenennen: PATCH /api/recordings/:id/title. Neue Spalte recordings.title_locked,
damit eine spaetere KI-Analyse einen von Hand gesetzten Titel nicht wieder ueberschreibt.

Papierkorb: DELETE setzt nur noch deleted_at, nichts wird angefasst. Wiederherstellen,
endgueltig loeschen, Aufraeumlauf beim Boot und taeglich (Boot-Lauf, weil das Board oft
tagelang aus ist). Behebt nebenbei einen Altfehler: das bisherige Loeschen liess die
words-Zeilen verwaist in der DB und die WAV/MP3-Dateien auf der Karte zurueck.

Inhaltssuche: neue Tabelle passages (1689 Zeilen aus 22 Aufnahmen) mit Sprecher und
Zeitfenster je Passage. Trefferliste kommt aus SQL in Millisekunden, die formulierte
Antwort mit Belegen [1][2] wird nachgereicht (Qwen3-4B, ~140 s) - deshalb zweistufig.
Hybrid: MariaDB FULLTEXT + Passage-Embedding + Dokument-Embedding aus Titel/Zusammenfassung
(multilingual-e5-small, ONNX/CPU, taskset A55). Ohne Modell degradiert die Suche sauber
auf Volltext statt auszufallen.

Gemessene Grenzen sind dokumentiert statt geschoent: e5-small trennt auf verrauschtem
ASR-Text schwach (Kosinus-Spanne aller Passagen nur 0,8085-0,8560; eine irrelevante
Passage schlug die richtige Antwort). Dokument-Ebene und IDF-Wertung heben die richtige
Passage auf Rang 11 von 296, aber nicht in die Top-8, die das LLM liest. Naechster Hebel
waere multilingual-e5-base.

Relative Datumsangaben werden deterministisch aufgeloest, nicht vom LLM - ein falsches
Kalenderfenster waere schlimmer als gar keins.

Neu: app/search.js, app/emb.js, app/inference/embed_text.py, docs/09-suche-und-verwaltung.md
Board-Backups: .bak-search
2026-07-31 13:20:20 +00:00
Claude c76f26abaf GUI: alle Tabs nutzen volle Fensterbreite (kein .wide-Sonderfall mehr) 2026-07-28 00:05:07 +02:00
Claude 448e2b0726 Namen nachtraeglich in fertige Zusammenfassung uebernehmen
speaker_labels speichert das Label jedes Clusters im LLM-Text; relabelAnalysis()
ersetzt beim Umbenennen wortgenau in summary/todos/transcript_clean und baut die
Teilnehmerliste neu. #74: keine 'Sprecher N' mehr.
2026-07-27 23:52:28 +02:00
Claude 48fa6b4f9e Diarization v2: Fenster-Clustering mit gelernter Schwelle + Live-Namensmarker
#74 (22 Teilnehmer) ergab automatisch 44 Sprecher, dieselbe Stimme mehrfach.
Ursache gemessen: ein Zentroid pro sherpa-Cluster aus max. 3 Schnitten, fester
Kosinus auf rohen Embeddings (Kreuz-Turn-Kosinus ~0,4 = keine Trennschaerfe).

v2: sherpa liefert nur Turn-Grenzen, Identitaet aus 3-s-Fenster-Embeddings,
Mittelwert-Zentrierung, Average-Linkage-AHC, Weak-Fold, Schwelle pro Aufnahme
per 2-Gauss-EM gelernt. Validiert: #74 44->20, #70 ->4, #68 ->2.

Live-Namensmarker: Namen waehrend der Aufnahme tippen; Zeitstempel benennt
spaeter den Cluster und dient als must-/cannot-link-Zwangsbedingung.
2026-07-27 17:00:45 +02:00
schakal00783andClaude Fable 5 b33b555fa7 GUI: Record-Button in Kopfzeile (Aufnahme-Tab entfernt) + Live-Karte; lame-Stille-Fix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 02:18:39 +02:00
schakal00783andClaude Fable 5 aef50dda64 GUI: Scrollbalken im Akzent-Kupfer (scrollbar-color + webkit)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 02:04:08 +02:00
schakal00783andClaude Fable 5 2c9015dd7c GUI: Splitter zwischen Liste und Detail (340-680px, persistent)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 02:00:03 +02:00
schakal00783andClaude Fable 5 f7c50b2b6b GUI: Kupfer-Tageszaehler, Wellenform-Favicon, Tab-Reihenfolge (BT ans Ende)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:54:43 +02:00
schakal00783andClaude Fable 5 46f8327832 GUI: Aufnahmen-Liste startet mit nur dem neuesten Tag geoeffnet
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:49:27 +02:00
schakal00783andClaude Fable 5 d55442a41f GUI: alle Module inkl. Transkript-Panel spaltenuebergreifend verschiebbar
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:44:36 +02:00
schakal00783andClaude Fable 5 40602779ce GUI: Sprecher-Modul entfernt; Umbenennen/Lernen via Popover am Spur-Label
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:36:03 +02:00
schakal00783andClaude Fable 5 6a51699e90 GUI: Blasen-Oeffnung positionsgenau zum Sprecher (--ax aus Sitzposition)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:26:57 +02:00
schakal00783andClaude Fable 5 55f03e7389 GUI: Tisch-Blase fix, Oeffnung wandert zum Sprecher
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:21:16 +02:00
schakal00783andClaude Fable 5 1975bfe696 GUI: Sprechblase am Sprecher, Wort-Highlight + internes Mitscrollen + Klick-Seek
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:17:52 +02:00
schakal00783andClaude Fable 5 7586a707ca GUI: Konferenztisch-Ansicht als Alternative zum Transkript
Umschalter (3-Personen-Icon <-> Textblatt); Figuren in Sprecherfarben um
abgerundeten Tisch, Sprechblase mit Live-Text zeigt zum Sprecher, alle
anderen schauen hin, Mund animiert. Sitzlayouts 1-6, localStorage-persistent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:10:00 +02:00
schakal00783andClaude Fable 5 35b4999b6c GUI: Aufnahmen-Tab nutzt volle Fensterbreite (1180px-Deckel entfernt)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 01:01:19 +02:00
schakal00783andClaude Fable 5 60fdff460a GUI: Live-Text-Box neben den Spuren entfernt (redundant zum Transkript)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:58:09 +02:00
schakal00783andClaude Fable 5 d9ae8f819b GUI: Sprecher-Verlauf als Vollbreiten-Streifen unter dem Player
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:55:15 +02:00
schakal00783andClaude Fable 5 62e1dec960 GUI: Transkript als eigene sticky Scroll-Spalte rechts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:51:04 +02:00
schakal00783andClaude Fable 5 4500e03ae4 GUI: Sprecher-Verlauf (farbige Spuren + Playhead + Live-Text) und Drag&Drop-Module
Detail-Ansicht modular: Zusammenfassung/Verlauf/ToDos/Sprecher/Transkript
per Grip umsortierbar (localStorage). Verlauf: Spur je Sprecher, Klick=Seek,
aktive Spur pulsiert, Live-Box zeigt aktuellen Redebeitrag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:46:27 +02:00
schakal00783andClaude Fable 5 63c7d30b5e GUI: Weggezogen-Bug (stale detail poll) gefixt + Redesign mit Dark/Light-Switch
- Detail-Poll bricht bei Auswahlwechsel ab, pollt nur Status, EIN Rebuild
  bei Fertigstellung mit Player-Restore
- Themes via CSS-Variablen (data-theme, localStorage, OS-Default),
  Kupfer-Akzent, Wellenform-Wortmarke, Pill-Tabs, focus-visible,
  prefers-reduced-motion

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:34:23 +02:00
schakal00783andClaude Fable 5 1016eaa095 Glossar: Eintraege bearbeitbar (PUT /api/glossary/:id + GUI-Editier-Flow)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-16 23:55:27 +02:00
Claude f9e1eb82c4 feat: komplette Codebase vom Board ins Repo gespiegelt
app/ = /opt/callrec (Node-Backend, Vite-Frontend, Python-Inferenz,
Audio-Skripte, rkllm_server.cpp), system/ = systemd-Units,
WirePlumber/PipeWire-Drop-ins, sudoers. Modelle, Binaries, Aufnahmen
und node_modules bleiben draussen (.gitignore).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 11:18:29 +02:00