diff --git a/docs/ui-flow-view-sollmodell.md b/docs/ui-flow-view-sollmodell.md new file mode 100644 index 0000000..70ae75b --- /dev/null +++ b/docs/ui-flow-view-sollmodell.md @@ -0,0 +1,1029 @@ +# UI-Sollmodell – ferrite.fm Signal Flow View + +Status: Entwurf / Arbeitsgrundlage +Zweck: Neuer zusätzlicher UI-View neben der bestehenden Control-Plane-Oberfläche +Arbeitsname: `Flow View` + +--- + +## 1. Zielbild + +Der neue View soll **nicht** die bestehende UI sofort ersetzen, sondern eine zweite, domänengerechtere Hauptansicht für professionelle Broadcast- und Signalpfad-Arbeit liefern. + +Die Grundidee: +- Statt primär Formulare, Panels und technische Gruppierungen zu zeigen, visualisiert der View den **realen Signalfluss** der Applikation. +- Das UI wird damit näher an Broadcast-, Routing-, Audio- und DSP-Systemen. +- Der Nutzer soll auf einen Blick sehen: + - **wo** sich das Signal gerade befindet, + - **welche Stufe** gesund / degradiert / fehlerhaft / inaktiv ist, + - **welches Modul** welchen Einfluss auf das On-Air-Signal hat, + - **wo** eine Störung tatsächlich sitzt, + - und **wo** man für Eingriffe klicken muss. + +Kurzform: +**Weniger Settings-App, mehr Signal- und Sendeweg-Konsole.** + +--- + +## 2. Produktprinzipien + +### 2.1 Operator-first +Der View muss innerhalb von 1–2 Sekunden lesbar sein. +Keine dekorative Technikgrafik, kein animiertes Spielzeug, kein "Dashboard um des Dashboards willen". + +### 2.2 Systemmodell statt Menüstruktur +Die Oberfläche bildet nicht zuerst Menüpunkte ab, sondern die tatsächliche Kette: +**Input → Buffer/Ingest → Audio → Processing → Stereo/RDS/MPX → TX** + +### 2.3 Status ist primär, Settings sekundär +Die erste Funktion des Views ist Verstehen und Überwachen. +Die zweite Funktion ist Eingreifen. +Darum gilt: +- **Farbe und Form** zeigen Zustand. +- **Hover** erklärt. +- **Click** öffnet Steuerung. + +### 2.4 Bestehende UI bleibt erhalten +Die aktuelle tab-basierte Oberfläche bleibt vorerst als: +- Detailansicht +- Fallback +- Vollkonfigurationsraum +- Diagnose-/Engineering-Oberfläche + +Der neue Flow View ist also ein **zusätzlicher View**, kein sofortiger kompletter Ersatz. + +--- + +## 3. Hauptnutzen des Views + +Der View soll drei Dinge gleichzeitig leisten: + +1. **Observability** + Wo steht das System? Welche Stufe ist gesund? Was ist degradet? Wo liegt der Fehler? + +2. **Navigation** + Klick auf ein Modul führt direkt zur passenden Steuerung, statt Tabs/Panels suchen zu müssen. + +3. **Control** + Häufige und domänennah passende Eingriffe können direkt am jeweiligen Modul stattfinden. + +--- + +## 4. Platz im Produkt + +## Top-Level-Position +Empfohlene Tabs / Hauptviews: +- `Flow` +- `Control` +- `Diagnostics` +- `Activity` + +Dabei gilt: +- **Flow** = Hauptansicht für Operatoren und für systemisches Verständnis +- **Control** = Form-/Panel-basierte Bearbeitung und Vollkonfiguration +- **Diagnostics** = tiefe Runtime-/Health-/Audit-Ansicht +- **Activity** = Logs / Historie + +Der neue View soll also idealerweise als erster oder linker Haupttab erscheinen. + +--- + +## 5. Grundlayout des Flow Views + +## 5.1 Grundstruktur +Der View besteht aus vier Zonen: + +### A. Top Status Bar +Persistente Betriebsleiste mit: +- Markenname `ferrite.fm` +- TX-Status (`ON AIR`, `OFF AIR`, `DEGRADED`, `FAULT`) +- Frequency (Applied / Target) +- Connection / Control-Plane-Status +- Last issue / active alarm +- Emergency Actions (`Stop TX`, `Reset Fault`) + +### B. Horizontale Signalfluss-Zeile +Die zentrale Fläche des Views. +Hier liegen die Module als horizontale Pipeline mit Verbindungsstrecken dazwischen. + +### C. Detail / Popover-Ebene +Nicht dauerhaft offen. Öffnet sich: +- per Hover als kompakte Statusblase +- per Klick als interaktiver Popover / Inspector + +### D. Optionaler Bottom Strip / Runtime Summary +Schmale sekundäre Leiste für: +- aktive Warnings +- Queue Health +- Ingest state +- last change +- runtime age + +--- + +## 6. Die Module im Signalfluss + +Der Flow View soll echte, betrieblich relevante Knoten zeigen. +Keine dekorativen Zwischenboxen. + +Empfohlene Basiskette: + +1. **Source** +2. **Ingest / Buffer** +3. **Audio** +4. **Processing** +5. **Stereo** +6. **RDS** +7. **Composite / MPX** +8. **TX / RF** + +### 6.1 Source +**Bedeutung:** Ursprungsquelle des Programmsignals. + +**Mögliche Zustände:** +- no source / idle +- connected +- reconnecting +- missing +- blocked + +**Beispiele für Daten:** +- `ingest.kind` +- active origin / URL / stream name +- stream title (falls relevant) +- transport / codec +- connected / disconnected + +**Popover-Steuerung:** +- Source kind +- Source URL / stream target +- Decoder mode +- grundlegende source-spezifische Optionen +- Link zur vollen Ingest-Konfiguration + +### 6.2 Ingest / Buffer +**Bedeutung:** Annahme, Vorpufferung, Runtime-Stabilisierung. + +**Mögliche Zustände:** +- healthy +- low buffer +- write blocked +- reconnecting +- stalled +- critical + +**Beispiele für Daten:** +- prebuffer state +- buffered seconds +- reconnect count +- source state +- runtime state +- last chunk time + +**Popover-Steuerung:** +- Prebuffer +- reconnect settings +- ggf. source-related runtime controls +- Link zu tiefer Diagnose + +### 6.3 Audio +**Bedeutung:** Programmaudio-Grundparameter vor Stereo-/MPX-Pfaden. + +**Mögliche Zustände:** +- active +- tone mode active +- muted / no input +- warning if gain/levels suspicious + +**Beispiele für Daten:** +- input gain +- tone left / right / amplitude +- source activity summary + +**Popover-Steuerung:** +- input gain +- tone controls +- ggf. source audio mode + +### 6.4 Processing +**Bedeutung:** Eingriffe in Klangbearbeitung und Compliance-nahe Audio-/Processing-Stufen. + +**Mögliche Zustände:** +- healthy +- limiter active +- compliance pending restart +- clipper active +- warning if inconsistent config/runtime impact exists + +**Beispiele für Daten:** +- limiter enabled / ceiling +- pre-emphasis +- BS.412 enabled +- composite clipper enabled / iterations / knee / lookahead + +**Popover-Steuerung:** +- limiter +- ceiling +- pre-emphasis +- compliance settings +- composite clipper settings + +### 6.5 Stereo +**Bedeutung:** Stereo-Multiplex-Aufbereitung. + +**Mögliche Zustände:** +- stereo on +- mono / stereo disabled +- pilot warning +- degraded if stereo mode or pilot abnormal + +**Beispiele für Daten:** +- stereo enabled +- stereo mode +- pilot level + +**Popover-Steuerung:** +- stereo on/off +- stereo mode +- pilot level + +### 6.6 RDS +**Bedeutung:** Metadaten- und RDS-Subsystem. + +**Mögliche Zustände:** +- active +- disabled +- active text relay +- degraded if metadata mismatch / relay issue / config inconsistency + +**Beispiele für Daten:** +- RDS enabled +- PI / PTY +- PS / RadioText +- TP / TA +- active on-air text +- RDS2 summary if enabled + +**Popover-Steuerung:** +- enable/disable +- PI / PTY +- PS / RT +- TP / TA +- RDS features shortcut + +### 6.7 Composite / MPX +**Bedeutung:** Endstufe des zusammengesetzten Multiplexsignals vor TX. + +**Mögliche Zustände:** +- healthy +- high injection +- compliance risk +- degraded if MPX gain / injection values suspicious + +**Beispiele für Daten:** +- pilot level +- RDS injection +- MPX gain +- clipper state +- BS.412 state + +**Popover-Steuerung:** +- pilot +- RDS injection +- MPX gain +- clipper toggle shortcut + +### 6.8 TX / RF +**Bedeutung:** Ausgang / SDR / Sendezustand. + +**Mögliche Zustände:** +- on air +- idle +- arming +n- degraded +- muted +- faulted +- stopping + +**Beispiele für Daten:** +- applied frequency +- desired frequency +- runtime state +- queue health +- underruns +- last fault +- backend / driver + +**Popover-Steuerung:** +- start / stop TX +- reset fault +- frequency +- quick runtime summary + +--- + +## 7. Statusmodell + +Farben und Zustände müssen über alle Module konsistent sein. + +### 7.1 Primäre Modulzustände +- **Green** → active / healthy / normal +- **Amber** → degraded / warning / pending / attention needed +- **Red** → fault / error / blocked / disconnected in fault-relevant stage +- **Gray** → disabled / bypassed / inactive / not configured +- **Blue outline** → selected / focused in UI + +### 7.2 Zustandslogik +Nicht jedes Modul nutzt dieselben Regeln, aber dieselbe Farbe bedeutet denselben operativen Charakter. + +Beispiele: +- Source disconnected = rot, wenn ingest erwartet wird +- RDS disabled = grau, nicht rot +- TX idle = grau oder neutral, nicht rot +- queue critical = rot +- restart required = amber indicator, aber nicht automatisch roter Modulstatus + +### 7.3 Zusätzliche Marker +Neben der Grundfarbe kann ein Modul kleine sekundäre Marker tragen: +- `pending` indicator +- `restart required` +- `reload required` +- `draft exists` + +Diese Marker sollen aber klein und sekundär bleiben. + +--- + +## 8. Hover-Verhalten + +Hover soll eine **kompakte Statusblase** öffnen. + +### Prinzipien +- Schnell erfassbar +- Kein Formular +- Kein Scrollmonster +- Max. 5–7 Zeilen +- Klare Typografie + +### Inhalt pro Hover-Blase +1. Modulname +2. Zustand in Klartext +3. 2–5 wichtigste Metriken / Werte +4. optional letzter Hinweis / letzter Fehler +5. evtl. Zeitbezug (`updated 4s ago`) + +### Beispiel RDS Hover +- RDS +- Status: Active +- PI: BEEF +- PS: FERRITE +- RT: Now playing ... +- TP/TA: off / off +- updated 2s ago + +### Beispiel TX Hover +- TX / RF +- State: Running +- Applied: 99.5 MHz +- Target: 99.5 MHz +- Queue: normal (67%) +- Underruns: 0 +- Runtime age: 18m + +--- + +## 9. Click-Verhalten / Popover + +Ein Klick auf ein Modul öffnet einen **Popover / Inspector**, nicht sofort ein Fullscreen-Modal. + +## 9.1 Ziel +- Schnell editierbare Kernparameter +- Kontext bleibt sichtbar +- Fokus bleibt auf dem Signalfluss + +## 9.2 Struktur des Popovers +- Modulname + Statuskopf +- kleine Summary +- relevante Einstellfelder +- Apply-/Action-Bereich +- Link / Button zu "Open full controls" + +## 9.3 Regeln +- Nur die wichtigsten Bedienelemente inline +- Tiefe Spezialkonfiguration weiter in der bestehenden Control-View +- Kritische Aktionen klar trennen + +### Beispiele + +#### TX Popover +- Start TX / Stop TX +- Reset Fault +- Frequency field +- Applied / target summary + +#### RDS Popover +- Enable RDS +- PI +- PTY +- PS +- RT +- TP/TA + +#### Processing Popover +- Limiter on/off +- Ceiling +- Pre-emphasis +- BS.412 on/off +- Composite clipper toggle + +--- + +## 10. Navigations- und Wechselmodell + +Der Flow View soll sich nicht isoliert anfühlen. +Jedes Modul kann zusätzlich einen Übergang in die bestehende UI bieten: +- `Open full controls` +- `Open diagnostics` +- `Open ingest panel` +- direkter Link zum **entsprechenden Tab bzw. Panel** der bestehenden Detail-UI + +So wird der Flow View zur Primärnavigation, ohne alles selbst lösen zu müssen. + +### Festlegung +Popover bleiben **Quick Control** und sollen bewusst flach bleiben. Für tiefere Arbeit gibt es immer einen direkten Sprung in die bestehende Detail-UI an die passende Stelle. + +--- + +## 11. Visual Language + +## 11.1 Stilprinzipien +- nüchtern +- präzise +- professionell +- ruhig +- hohe Informationsdichte ohne Chaos + +## 11.2 Look & Feel +- heller bis neutraler Hintergrund bleibt möglich +- weniger Card-Sammlung, mehr zusammenhängende technische Arbeitsfläche +- Module als klar definierte Knoten mit Verbindungslinien +- Verbindungslinien dezent, aber lesbar +- Symbole sachlich und funktional, nicht verspielt + +## 11.3 Symbolik +Jedes Modul erhält ein einfaches, wiedererkennbares Icon, z. B.: +- Source → Stecker / Input / Antenne / Link +- Buffer → Stack / Queue / Reservoir +- Audio → Waveform / Fader +- Processing → Filter / dynamics / knob cluster +- Stereo → linked channels / L-R icon +- RDS → text / metadata / broadcast tag +- Composite → multiplex / spectrum-like icon +- TX → antenna / RF output + +Wichtig: +Icons unterstützen, ersetzen aber nie die Lesbarkeit. + +--- + +## 12. Responsive Verhalten + +Der View ist primär Desktop-/Operator-first. +Mobile ist sekundär, aber nicht ignoriert. + +### Desktop +- horizontale Kette in einer Zeile +- Popover seitlich / unterhalb des aktiven Moduls + +### Tablet / kleinere Fenster +- Kette darf umbrechen in 2 Zeilen, aber logisch lesbar bleiben +- Verbindungslogik optisch erhalten + +### Mobile +- keine ambitionierte Vollsimulation der Horizontalkonsole +- stattdessen vereinfachte vertikale Step-Ansicht +- Hover-Konzept wird zu Tap-Details + +--- + +## 13. Technische Datenquellen + +Der View soll möglichst aus bereits vorhandenen Daten gespeist werden. + +### Bereits vorhanden / nutzbar +- `/status` +- `/runtime` +- `/config` +- bestehende Draft-/Apply-Logik in `ui.html` + +### Erwartete Zuordnung +- Source / Ingest / Buffer ← `runtime.ingest`, `config.ingest` +- Audio / Processing / Stereo / RDS / MPX ← `config`, `runtime.engine`, teilweise `status` +- TX / RF ← `runtime.engine`, `runtime.driver`, `status` + +### Wichtige Designregel +Der View darf zunächst **read-mostly + selectively writable** sein. +Nicht alles muss in Version 1 voll editierbar sein. + +--- + +## 14. MVP-Scope + +Für eine erste brauchbare Version reichen: + +### Muss enthalten +- neuer `Flow`-Tab +- horizontale Modulkette +- Statusfarben pro Modul +- Hover-Details pro Modul +- Click öffnet kompakten Popover +- pro Modul 1–3 relevante Kernaktionen +- klare Verbindung zur bestehenden Control-Ansicht + +### Darf zunächst fehlen +- hochkomplexe Inline-Editoren +- Drag & Drop +- Mini-Sparklines in jedem Modul +- Animationen entlang des Flows +- komplette Mobile-Perfektion + +--- + +## 15. Anti-Ziele + +Der Flow View soll **nicht** werden: +- eine dekorative Netzwerkgraph-Spielerei +- eine überanimierte "wow"-Fläche +- ein unlesbares Technikposter +- ein Vollersatz für jede Detailkonfiguration in Version 1 +- eine Oberfläche, bei der Farbe das einzige Statussignal ist + +--- + +## 16. Nächste Umsetzungsstufe + +### Stufe 1 — UX-Skelett +- neuen Tab `Flow` anlegen +- statische Modulkette rendern +- Icons + Titel + Statusfarben +- ausgewählte Runtime-/Config-Werte anbinden + +### Stufe 2 — Interaktion +- Hover-Bubbles +- Click-Popover +- Quick actions für TX / RDS / Frequency / Source + +### Stufe 3 — Integration +- Draft-/Apply-Mechanik für Kernmodule +- Übergänge zu bestehender Detail-UI +- sauberer Pending-/Restart-/Reload-Status + +### Stufe 4 — Broadcast-Polish +- strengere visuelle Hierarchie +- Alarm-Layer +- optional Operator-/Engineering-Abstufung + +--- + +## 17. Getroffene Designentscheidungen + +### 17.1 Stereo und RDS +**Entscheidung:** `Stereo` und `RDS` werden als **getrennte Knoten** dargestellt. + +**Begründung:** +- fachlich klarer +- RDS bleibt als eigenes Broadcast-Subsystem sichtbar +- Fehlerursachen werden präziser lesbar +- passt besser zu einer professionellen Broadcast-/Signalpfad-Sicht + +### 17.2 Composite / MPX +**Entscheidung:** `Composite / MPX` wird als **eigener Knoten** dargestellt. + +**Begründung:** +- Broadcast-technisch zentrale Stufe +- trennt Audio-/Processing-Welt sauber von der Multiplex-/Deviation-Ebene +- macht Pilot, RDS-Injection, MPX Gain und Composite-Verhalten sichtbar an der richtigen Stelle + +### 17.3 Popover-Tiefe +**Entscheidung:** Popover bleiben **Quick Control**. + +**Regel:** +- wenige Kernaktionen / Kernfelder direkt im Popover +- keine Vollkonfiguration im Flow View +- tiefe Bearbeitung erfolgt über direkten Link in den passenden Tab bzw. das passende Panel der bestehenden Detail-UI + +### 17.4 Globaler Alarm-Banner +**Entscheidung:** Ein globaler Alarm-Banner oberhalb des Flows ist sinnvoll, aber **nur kontextuell sichtbar**. + +**Regel:** +- sichtbar bei aktiven Faults / relevanten Degraded-Zuständen / betrieblich relevanten Warnings +- nicht als permanentes Alarmband +- kompakt, klar, operator-first + +### 17.5 Stil +**Entscheidung:** Der View wird **technisch-klar mit leichter visueller Abstraktion** umgesetzt. + +**Regel:** +- echte Modulnamen +- echte Signalpfad-Logik +- präzise Zustände +- nüchterne, moderne technische Konsole statt Spielerei oder retro-technischer Härte + +--- + +## 18. Festgelegte Architektur für die erste Realisierung + +Empfehlung für die erste Realisierung: +- eigener `Flow`-Tab +- acht klare Knoten +- strikte Statusfarben +- Hover für Status +- Click für kleine Popover +- Popover als Quick Control +- direkter Link in passende Detail-Tabs/Panels +- globaler Alarm-Banner nur bei Relevanz +- bestehende UI bleibt Vollkonfigurations-/Fallback-Ebene + +### Festgelegte Modulkette +- `Source` +- `Ingest / Buffer` +- `Audio` +- `Processing` +- `Stereo` +- `RDS` +- `Composite / MPX` +- `TX / RF` + +Das ist der pragmatischste Weg zu einer professionelleren Broadcast-Oberfläche, ohne die vorhandene UI sofort wegzuwerfen. + +--- + +## 19. Konkretes Modul- und Wireframe-Schema + +Dieser Abschnitt definiert den ersten baubaren MVP des Flow Views. + +## 19.1 Gesamt-Wireframe + +### Obere Leiste +Von links nach rechts: +1. `ferrite.fm` Wortmarke / Produktname +2. globaler TX-Zustand +3. Applied / Target Frequency +4. Source Summary +5. Active Alarm / Warning Banner (nur wenn relevant) +6. Emergency Actions (`Stop TX`, `Reset Fault`) + +### Flow-Zeile +Eine horizontale Kette mit 8 Modulknoten. +Jeder Knoten besitzt: +- Icon +- Namen +- Statusfarbe +- 1 kurze Sekundärzeile +- Hover-Bubble +- Click-Popover + +### Verbindungssegmente +Zwischen den Knoten liegen simple horizontale Linien / Segmente. +Optional können Segmente dieselbe Statusfarbe wie der nachfolgende Knoten aufnehmen oder neutral bleiben. Für MVP besser neutral und ruhig halten. + +### Untere Sekundärzone +Schmale Zeile für: +- queue health +- ingest state +- runtime age +- last update + +Keine große zweite Dashboard-Wand. Nur kompakte Betriebszusammenfassung. + +--- + +## 19.2 Knoten-Spezifikation + +## A. Source +### Icon +- Input / link / connector symbol + +### Primärlabel +- `Source` + +### Sekundärzeile +- aktiver Typ, z. B. `icecast`, `srt`, `aes67`, `stdin`, `http-raw`, `none` + +### Primärstatuslogik +- green → connected / active source +- amber → reconnecting / degraded +- red → source expected but disconnected / failed +- gray → no source / none configured + +### Hover-Inhalt +- Source kind +- Origin / endpoint / stream name +- Transport / codec (falls verfügbar) +- Connection state +- Reconnect count / last error (falls vorhanden) + +### Quick-Control-Popover +- source kind (read-only oder einfacher selector nur wenn sinnvoll) +- URL / endpoint (wenn einfache Bearbeitung vertretbar) +- decoder mode (bei icecast) +- reconnect enabled +- Button: `Open Input details` + +### Linkziel im Detail-UI +- Tab: `Ingest` +- Fokus: `Ingest Config` + +--- + +## B. Ingest / Buffer +### Icon +- queue / buffer / stacked blocks + +### Primärlabel +- `Ingest / Buffer` + +### Sekundärzeile +- z. B. `1.5s buffered`, `prebuffering`, `write blocked`, `healthy` + +### Primärstatuslogik +- green → healthy ingest runtime +- amber → low buffer / reconnecting / prebuffering / delayed +- red → critical / stalled / write blocked with active fault relevance +- gray → ingest inactive + +### Hover-Inhalt +- Runtime state +- Buffered seconds +- Prebuffer state +- Last chunk age +- Reconnect count +- Write blocked yes/no + +### Quick-Control-Popover +- prebuffer ms +- reconnect enabled +- initial/max backoff +- Button: `Open Ingest config` +- Button: `Open Diagnostics` + +### Linkziel im Detail-UI +- Tab: `Ingest` +- Fokus: `Ingest Config` + +--- + +## C. Audio +### Icon +- waveform / fader + +### Primärlabel +- `Audio` + +### Sekundärzeile +- z. B. `gain 1.00`, `tones off`, `tones active` + +### Primärstatuslogik +- green → active / healthy +- amber → unusual tone mode / suspicious gain / weak signal condition +- red → no usable audio in relevant runtime state +- gray → inactive / no source + +### Hover-Inhalt +- input gain +- tone left/right +- tone amplitude +- audio activity summary + +### Quick-Control-Popover +- input gain +- tone left +- tone right +- tone amplitude +- Button: `Open Audio controls` + +### Linkziel im Detail-UI +- Tab: `TX Control` +- Fokus: `Audio & Drive` + +--- + +## D. Processing +### Icon +- filter / dynamics / processor block + +### Primärlabel +- `Processing` + +### Sekundärzeile +- z. B. `limiter on`, `pre-emphasis 50µs`, `BS.412 off` + +### Primärstatuslogik +- green → healthy / nominal +- amber → restart required / compliance attention / unusual setting combination +- red → critical processing/compliance state (nur falls wirklich fault-relevant) +- gray → inactive / bypassed if such mode exists + +### Hover-Inhalt +- limiter on/off + ceiling +- pre-emphasis +- BS.412 enabled + threshold +- clipper enabled summary + +### Quick-Control-Popover +- limiter enabled +- limiter ceiling +- pre-emphasis +- BS.412 enabled +- Button: `Open Processing controls` + +### Linkziel im Detail-UI +- Tab: `TX Control` +- Fokus: `Audio & Drive` oder `MPX Compliance` + +--- + +## E. Stereo +### Icon +- linked L/R or stereo channels icon + +### Primärlabel +- `Stereo` + +### Sekundärzeile +- z. B. `DSB`, `stereo on`, `mono` + +### Primärstatuslogik +- green → stereo enabled and healthy +- amber → non-default mode / pilot attention / pending state +- gray → stereo disabled / mono +- red → only if runtime actually indicates a fault-worthy stereo stage problem + +### Hover-Inhalt +- stereo enabled +- stereo mode +- pilot level + +### Quick-Control-Popover +- stereo enabled +- stereo mode +- pilot level +- Button: `Open Stereo controls` + +### Linkziel im Detail-UI +- Tab: `TX Control` +- Fokus: `Switches` + +--- + +## F. RDS +### Icon +- metadata / text / radio-data symbol + +### Primärlabel +- `RDS` + +### Sekundärzeile +- z. B. `PS FERRITE`, `RT active`, `disabled` + +### Primärstatuslogik +- green → enabled and active +- amber → enabled but metadata stale / pending / mixed runtime impact / relay mismatch +- gray → disabled +- red → only if a real operational RDS fault state is surfaced + +### Hover-Inhalt +- enabled / disabled +- PI +- PTY +- PS +- active RT +- TP / TA +- RDS2 summary if applicable + +### Quick-Control-Popover +- enable RDS +- PI +- PTY +- PS +- RT +- TP / TA +- Button: `Open RDS details` + +### Linkziel im Detail-UI +- Tab: `RDS` +- Fokus: `Station Identity` or `On-Air Text` + +--- + +## G. Composite / MPX +### Icon +- multiplex / layered-spectrum symbol + +### Primärlabel +- `Composite / MPX` + +### Sekundärzeile +- z. B. `pilot 9%`, `RDS 4%`, `mpx 1.00` + +### Primärstatuslogik +- green → nominal multiplex state +- amber → high injection / compliance attention / restart pending / unusual MPX values +- red → critical compliance or composite issue if surfaced +- gray → inactive when TX chain inactive + +### Hover-Inhalt +- pilot level +- RDS injection +- MPX gain +- composite clipper state +- BS.412 state + +### Quick-Control-Popover +- pilot level +- RDS injection +- MPX gain +- clipper enabled shortcut +- Button: `Open MPX controls` + +### Linkziel im Detail-UI +- Tab: `TX Control` or `RDS` +- Fokus: `MPX Compliance` or `Injection Levels` + +--- + +## H. TX / RF +### Icon +- antenna / RF output / transmitter symbol + +### Primärlabel +- `TX / RF` + +### Sekundärzeile +- z. B. `99.5 MHz`, `ON AIR`, `idle`, `faulted` + +### Primärstatuslogik +- green → running / on air +- amber → arming / degraded / muted / stopping +- red → faulted +- gray → idle / off air + +### Hover-Inhalt +- runtime state +- applied frequency +- target frequency +- queue health +- underruns +- backend / driver +- last fault summary + +### Quick-Control-Popover +- start TX / stop TX +- reset fault +- frequency +- refresh runtime +- Button: `Open TX control` + +### Linkziel im Detail-UI +- Tab: `Overview` or `TX Control` +- Fokus: `Frequency` / Hero area + +--- + +## 19.3 Globale Interaktion + +### Hover +- Öffnet kompakte Bubble +- bubble schließt automatisch beim Verlassen +- kein interaktives Formular im Hover + +### Click +- öffnet Popover am Knoten +- nur ein Popover gleichzeitig offen +- Klick außerhalb schließt Popover +- ESC schließt Popover + +### Statusbanner +- erscheint oberhalb des Flows nur bei Relevanz +- enthält Severity + Kurztext + optionalen Deep-Link + +--- + +## 19.4 MVP-Bauplan + +### Phase MVP-1 +- statischer `Flow`-Tab +- acht Knoten +- Statusfarben +- Sekundärzeilen +- read-only Hover-Bubbles + +### Phase MVP-2 +- interaktive Popover +- erste Quick Controls für TX, RDS, Source, Processing +- Deep-Links in bestehende Tabs/Panels + +### Phase MVP-3 +- Draft-/Apply-Anbindung +- konsistente Pending-/Restart-/Reload-Marker +- Alarm-Banner diff --git a/internal/control/ui.html b/internal/control/ui.html index 2c6ea18..6d710a9 100644 --- a/internal/control/ui.html +++ b/internal/control/ui.html @@ -39,6 +39,59 @@ button,input,select{font:inherit}button{user-select:none} .led.on-amber{background:var(--amber);box-shadow:0 0 0 3px rgba(183,121,31,.14)} .led.on-blue{background:var(--accent);box-shadow:0 0 0 3px rgba(31,77,157,.14)} .status-text{font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.08em} +.flow-banner{display:none;align-items:center;gap:10px;margin:0 0 14px;padding:10px 12px;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);box-shadow:var(--shadow)} +.flow-banner.show{display:flex} +.flow-banner.good{border-color:rgba(13,148,74,.25);background:var(--green-soft)} +.flow-banner.warn{border-color:rgba(183,121,31,.3);background:var(--amber-soft)} +.flow-banner.err{border-color:rgba(176,48,48,.32);background:var(--red-soft)} +.flow-banner-title{font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase} +.flow-banner-text{font-size:12px;color:var(--text-dim)} +.flow-board{padding:16px;display:flex;flex-direction:column;gap:16px} +.flow-topbar{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px} +.flow-summary{padding:12px;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface2)} +.flow-summary-label{font-size:9px;text-transform:uppercase;letter-spacing:.08em;color:var(--text-dim);margin-bottom:6px} +.flow-summary-value{font-size:16px;font-weight:700} +.flow-chain{display:grid;grid-template-columns:repeat(8,minmax(120px,1fr));gap:16px;align-items:stretch} +.flow-node{position:relative;display:flex;flex-direction:column;gap:8px;min-height:136px;padding:14px 14px 16px;border:1px solid var(--border);border-radius:12px;background:linear-gradient(180deg,#ffffff 0%, #f7f9fc 100%);box-shadow:0 10px 26px rgba(15,23,42,.08);cursor:pointer;transition:border-color .16s,transform .16s,box-shadow .16s} +.flow-node::after{content:'';position:absolute;top:50%;right:-17px;width:18px;height:2px;background:linear-gradient(90deg,var(--border-strong),rgba(188,197,206,.2));transform:translateY(-50%)} +.flow-node:last-child::after{display:none} +.flow-node:hover{transform:translateY(-1px);border-color:var(--border-strong);box-shadow:0 14px 30px rgba(15,23,42,.11)} +.flow-node.selected{outline:2px solid rgba(31,77,157,.22);outline-offset:0;box-shadow:0 0 0 4px rgba(31,77,157,.06),0 14px 30px rgba(15,23,42,.12)} +.flow-node.good{border-color:rgba(13,148,74,.3);background:linear-gradient(180deg,#fff 0%, rgba(13,148,74,.045) 100%)} +.flow-node.warn{border-color:rgba(183,121,31,.32);background:linear-gradient(180deg,#fff 0%, rgba(183,121,31,.06) 100%)} +.flow-node.err{border-color:rgba(176,48,48,.34);background:linear-gradient(180deg,#fff 0%, rgba(176,48,48,.07) 100%)} +.flow-node.idle{border-color:var(--border);background:linear-gradient(180deg,#fff 0%, #f8fafc 100%)} +.flow-node-head{display:flex;align-items:center;justify-content:space-between;gap:10px} +.flow-node-icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:8px;border:1px solid var(--border);background:var(--surface2);font-size:16px;line-height:1} +.flow-node-state{width:10px;height:10px;border-radius:50%;flex-shrink:0} +.flow-node.good .flow-node-state{background:var(--green);box-shadow:0 0 0 3px rgba(13,148,74,.14)} +.flow-node.warn .flow-node-state{background:var(--amber);box-shadow:0 0 0 3px rgba(183,121,31,.14)} +.flow-node.err .flow-node-state{background:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.14)} +.flow-node.idle .flow-node-state{background:#9aa5b1;box-shadow:0 0 0 3px rgba(154,165,177,.15)} +.flow-node-title{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em} +.flow-node-sub{font-size:12px;color:var(--text-dim);min-height:34px;font-weight:600} +.flow-node-detail{font-size:11px;color:var(--text-muted);line-height:1.35} +.flow-node-actions{margin-top:auto;padding-top:8px;border-top:1px solid rgba(188,197,206,.45);font-size:10px;color:var(--accent);text-transform:uppercase;letter-spacing:.08em} +.flow-bottom{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px} +.flow-tooltip{position:fixed;z-index:1500;display:none;max-width:280px;padding:12px;border:1px solid var(--border);border-radius:10px;background:rgba(255,255,255,.98);box-shadow:0 14px 34px rgba(15,23,42,.16);pointer-events:none} +.flow-tooltip.show{display:block} +.flow-tooltip-title{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px} +.flow-tooltip-status{font-size:11px;font-weight:700;margin-bottom:6px} +.flow-tooltip-lines{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--text-dim)} +.flow-popover{position:fixed;z-index:1600;display:none;width:min(360px,calc(100vw - 24px));padding:14px;border:1px solid var(--border-strong);border-radius:12px;background:linear-gradient(180deg,rgba(255,255,255,.995) 0%, rgba(245,248,252,.995) 100%);box-shadow:0 20px 42px rgba(15,23,42,.2)} +.flow-popover.show{display:block} +.flow-popover-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid rgba(188,197,206,.45)} +.flow-popover-title{font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.08em} +.flow-popover-status{font-size:11px;color:var(--text-dim);margin-top:2px;text-transform:uppercase;letter-spacing:.08em} +.flow-popover-close{min-height:32px;padding:0 10px;border-radius:8px;border:1px solid var(--border);background:var(--surface2);cursor:pointer;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em} +.flow-popover-lines{display:flex;flex-direction:column;gap:5px;margin-bottom:12px;font-size:11px;color:var(--text-dim)} +.flow-popover-lines div{display:flex;justify-content:space-between;gap:12px;padding:2px 0;border-bottom:1px dashed rgba(188,197,206,.35)} +.flow-popover-lines div:last-child{border-bottom:none} +.flow-popover-fields{display:flex;flex-direction:column;gap:10px} +.flow-popover-row{display:flex;flex-direction:column;gap:5px} +.flow-popover-row label{font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.08em} +.flow-popover-row input,.flow-popover-row select{width:100%} +.flow-popover-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px} /* Tabs */ .tab-bar{display:flex;gap:2px;border-bottom:1px solid var(--border);margin:0 0 20px;flex-wrap:wrap;position:sticky;top:0;background:rgba(247,248,251,.95);backdrop-filter:blur(8px);z-index:10} .tab-btn{border:none;border-bottom:3px solid transparent;border-radius:0;background:transparent;color:var(--text-dim);font-size:13px;font-weight:700;padding:12px 14px 11px;cursor:pointer;transition:color .16s,border-color .16s} @@ -220,8 +273,8 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1 .toast.ok{background:var(--green);color:var(--bg)}.toast.err{background:var(--accent);color:#fff} .toast.warn{background:var(--amber);color:#141414}.toast.info{background:var(--text-dim);color:#fff} /* Responsive */ -@media(max-width:980px){.tab-columns.two{grid-template-columns:1fr}.tx-bar{grid-template-columns:1fr}.tx-state-wrap{align-items:flex-start}.status-hint{text-align:left}.quick-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.signal-grid{grid-template-columns:1fr}} -@media(max-width:640px){.app{padding:12px}.header{flex-direction:column;gap:10px}.header h1{font-size:22px}.badge{width:100%;justify-content:space-between}.badge strong{max-width:52%;overflow:hidden;text-overflow:ellipsis}.quick-grid{grid-template-columns:1fr 1fr;gap:8px}.ctrl-row{flex-direction:column;align-items:stretch}.ctrl-label-wrap{min-width:auto}.ctrl-input{flex-wrap:wrap}.ingest-grid{grid-template-columns:1fr}input[type="number"]{width:100%;text-align:left}.actions-row,.tx-actions{flex-direction:column}.tx-btn,.ghost-btn,.apply-btn,.preset-btn,.danger-btn{width:100%}.freq-display{font-size:31px}.shortcuts-grid{grid-template-columns:1fr}} +@media(max-width:980px){.tab-columns.two{grid-template-columns:1fr}.tx-bar{grid-template-columns:1fr}.tx-state-wrap{align-items:flex-start}.status-hint{text-align:left}.quick-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.signal-grid{grid-template-columns:1fr}.flow-topbar,.flow-bottom{grid-template-columns:repeat(2,minmax(0,1fr))}.flow-chain{grid-template-columns:repeat(4,minmax(140px,1fr))}} +@media(max-width:640px){.app{padding:12px}.header{flex-direction:column;gap:10px}.header h1{font-size:22px}.badge{width:100%;justify-content:space-between}.badge strong{max-width:52%;overflow:hidden;text-overflow:ellipsis}.quick-grid{grid-template-columns:1fr 1fr;gap:8px}.ctrl-row{flex-direction:column;align-items:stretch}.ctrl-label-wrap{min-width:auto}.ctrl-input{flex-wrap:wrap}.ingest-grid{grid-template-columns:1fr}input[type="number"]{width:100%;text-align:left}.actions-row,.tx-actions{flex-direction:column}.tx-btn,.ghost-btn,.apply-btn,.preset-btn,.danger-btn{width:100%}.freq-display{font-size:31px}.flow-topbar,.flow-bottom,.flow-chain{grid-template-columns:1fr}}
@@ -243,7 +296,12 @@ input.input-error{border-color:var(--red);box-shadow:0 0 0 3px rgba(176,48,48,.1