Admin Web Dashboard - Telemetrie #1
Labels
No labels
blocked
claude
in-progress
needs-review
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
aiways/Backend#1
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Die Tabellenansicht im Admin Web Dashboard Telemetrie Tab ist aktuell sehr statisch. Damit kann man wenig anfangen. Die Einträge sollte Filterbar und Sortierbar sein
Umgesetzt in
73d9e58(release) — CI grün, deployt und gegen die Live-Instanz verifiziert.Was die Telemetrie-Tabelle jetzt kann
80,>80,>=80,<80,<=80,10..50(Bereich, inklusive),leer(nur Nullwerte). Komma als Dezimaltrenner geht auch.2026-08-27oder10:03.>) wird rot markiert und ignoriert, statt die Tabelle leerzufiltern.Von/Bis(Zeitfenster) undLimit.Backend
GET /vehicles/:id/timeserieskennt jetztlimit(jüngste N Punkte, Default 5000, max 50000; die Antwort bleibt aufsteigend nachts).from/towerden validiert und fallen bei Unsinn auf den Default zurück, statt einen 500er zu werfen;everyist auf 1..100000 geklemmt.Entscheidungen (proceed-with-default)
every/Limit. Das ist bei ein paar tausend Zeilen sofort responsiv und spart eine Rundreise pro Klick. Wenn du später über wirklich große Zeiträume filtern willst, wäre serverseitiges Filtern der nächste Schritt.limithat einen Default von 5000. Vorher lieferte der Endpunkt unbegrenzt viele Zeilen. Falls irgendwo ein Client mehr als 5000 Punkte am Stück erwartet, muss erlimitjetzt explizit mitgeben.tbodyneu gerendert, damit die Filter-Eingaben Fokus und Cursorposition behalten.Verifikation
src/routes/selftest.ts— laufen ab jetzt in der CI mit. Dafür liegen die reinen Helfer als exportierterFILTER_JS-String vor; das Dashboard-JS ist fürtscsonst komplett unsichtbar.limit=3liefert die 3 jüngsten Punkte in aufsteigender Reihenfolge,every=10sampled korrekt, kaputtesfromgibt 200 statt 500,limit=0wird auf 1 geklemmt./healthok, das ausgelieferte Dashboard enthält die neue Filter-/Sortier-UI,/vehicles/:id/timeseriesantwortet unauthentifiziert korrekt mit 401.Sieht jetzt auf jeden Fall viel besser aus! Aber:
⚠️ Der vorige Bearbeitungslauf lief in den 30-Min-Timeout (Task zu groß). Zurück in die Queue gesetzt; ich nehme den Faden mit erhöhtem Zeitlimit wieder auf.
Umgesetzt in
5d9efb4+d45b7d8(release) — CI grün, deployt, gegen die Live-Instanz verifiziert.1. Tabellenkopf bleibt stehen
Die Tabelle sitzt jetzt in einem eigenen Scroll-Container; beide Kopfzeilen kleben oben — die Sortierzeile bei
top:0, die Filterzeile direkt darunter. Nur der Inhalt scrollt.2. Filtern und Sortieren laufen im Backend per SQL
Komplett umgebaut — das Frontend filtert nichts mehr selbst.
GET /vehicles/:id/timeserieskennt jetzt:f_<spalte>f_soc=>80,f_speed=10..50,f_gear=D,f_range_km=leersort+dirasc/desclimitoffseteveryDie Trefferzahl über den gesamten Bestand steht im Header
X-Total-Count. Weillimitjetzt eine Seitengröße statt eines Deckels ist, hat die Tabelle zurück/weiter-Buttons und eine Fußzeile „Zeile 101–200 von 4711" bekommen — sonst käme man an alles jenseits der ersten 100 Zeilen nicht mehr heran. Jede Änderung an Filter, Sortierung oder Zeitfenster springt zurück auf Seite 1; Tippen im Filter ist um 300 ms entprellt.Zur Sicherheit: Spaltennamen kommen ausschließlich aus einer Whitelist, die Operatoren aus einer festen Alternativenliste, und jeder Wert geht als Bind-Parameter raus. Ein
?sort=soc; DROP TABLE telemetryfällt auf die Default-Sortierung zurück, einf_gear=D'; DROP TABLE telemetry; --landet als harmloser Suchstring. Beides ist live geprüft — die Tabelle stand danach unverändert da.3. Charts: eins pro Messgröße, Typ frei wählbar
Das Dropdown ist weg. Stattdessen eine Chart-Leiste, in der du dir dein Set selbst zusammenstellst: + Chart, je Zeile eine Messgröße (SoC, Packspannung, Packstrom, Speed, Odometer, Reichweite, Höhe, Kurs) und ein Typ (Linie / Fläche / Balken / Punkte),
×entfernt. Die Zusammenstellung wird im Browser gespeichert und ist beim nächsten Login wieder da; Standard setzt zurück.Interaktiv sind die Charts über ein Fadenkreuz mit Tooltip: Maus über das Diagramm zeigt Wert + Zeitstempel des nächstgelegenen Punktes, Lücken (Nullwerte) werden übersprungen. Bewusst weiter ohne Chart-Bibliothek — das Dashboard wird als eine Datei ohne Frontend-Build ausgeliefert, und eine externe Lib würde diese Eigenschaft aufgeben. Falls du echtes Zoomen/Pannen willst, sag Bescheid, dann hole ich uPlot o. ä. dazu.
Unterwegs gefunden und mitgefixt
Ich habe die neue SQL-Schicht gegen eine echte Postgres-Instanz mit dem Produktivschema getestet, nicht nur gegen die Unit-Tests — und dabei einen Fehler gefunden, den die Tests nicht sehen konnten:
socistSMALLINT,speed/odometersindREAL. Ohne expliziten Cast leitet Postgres den Typ des Bind-Parameters aus der Spalte ab, und ein Filter wiesoc > 80.5brach mitinvalid input syntax for type smallintals 500er ab. Behoben ind45b7d8($n::numeric), Regressionstest ergänzt.Verifikation (echte DB, Produktivschema, 500 Zeilen)
>80→ 95 Treffer,10..50→ 164,gear=D→ 166,range_km=leer→ 71 (genau die Nullwerte), Zeitstempel-Textsuche → 60.X-Total-Countstimmt auch mit Downsampling:every=5→ 100,every=5+f_soc=>80→ 19 (= ⌊95/5⌋).f_soc=>) → sauberer 400 statt 500./healthok, Dashboard liefert den neuen Stand aus,/vehicles/1/timeseriesohne Token weiterhin 401.Anmerkung
Ein Detail, das sich aus serverseitigem Sortieren zwangsläufig ergibt: sortierst du nach z. B. SoC absteigend, zeigen die Charts die geladene Seite — also die 100 höchsten SoC-Werte, chronologisch aufgetragen — und nicht mehr einen zusammenhängenden Zeitverlauf. Für einen sauberen Verlauf nach
tssortieren (Default). Sag Bescheid, wenn die Charts stattdessen unabhängig von der Tabellenseite immer das volle Zeitfenster zeichnen sollen — das wäre eine zweite, gröber gesampelte Abfrage.Ja, das ist jetzt schon richtig nützlich! Kannst du jetzt noch die Seite etwas responsive machen? Also dass sie sich an die Display-Größe anpasst und die Charts sollten auch drei verschiedene Größen unterstüzen (klein mittel groß -> wobei groß ist das was es jetzt ist)
Umgesetzt in
99e9ec4(release) — CI grün, deployt, live verifiziert.Charts in drei Größen
Je Chart eine dritte Auswahl neben Messgröße und Typ: klein / mittel / groß.
großist genau die bisherige Darstellung. Die Größe steuert beides — Breite im Raster und Höhe in Pixeln:Drei kleine Charts liegen also nebeneinander. Die Auswahl wird wie Messgröße und Typ im Browser gespeichert; deine bereits eingerichteten Charts laufen als
großweiter, da ändert sich nichts.Dabei einen Darstellungsfehler behoben
Die Charts wurden bisher in einen festen 900×200-Raum gezeichnet und per CSS auf die Breite gestreckt. Sobald ich Höhen frei wählbar machte, wäre daraus eine nicht-uniforme Skalierung geworden — Achsenbeschriftung und Punkte hätten sich verzogen.
Jetzt wird stattdessen die tatsächliche Pixelbreite des Containers gemessen und das SVG in genau dieser Größe aufgebaut. Eine SVG-Einheit ist damit ein Pixel: nichts wird gestreckt, in keiner Größe und bei keiner Fensterbreite. Bei Größenänderung des Fensters wird neu vermessen und gezeichnet (entprellt, damit das Ziehen am Fensterrand nicht den ganzen Satz pro Pixel neu rendert). Bei den kleinen Charts sind zusätzlich Rand, Schriftgröße, Linienstärke und Punktradius etwas reduziert — sonst bliebe von der Zeichenfläche kaum etwas übrig.
Responsiv
maindarf 1400 px breit werden statt 1000 und ist zentriert — auf einem breiten Monitor war vorher rechts viel Luft.Verifikation
width/height/viewBoxstimmen exakt überein, alle erzeugten Koordinaten liegen innerhalb der Zeichenfläche, keinNaNund keinundefinedim Ergebnis./healthok, alle neuen Marker (Größenklassen, Media-Queries, Größen-Auswahl) sind im ausgelieferten Dashboard vorhanden.Ansehen kannst du dir das am besten, indem du das Fenster einmal schmal ziehst — und ein paar Charts auf klein stellst, dann liegen sie zu dritt nebeneinander.