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>
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>
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>
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.
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
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.
#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.
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
- 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