Files
Predictalytics/FIXPLAN-UI-Ranglisten.md
T
Richard 295752d778 @
UI-U1/U2/U4/U5: dashboard showcases + server-side leaderboard sort

- U1: render the /api/traders/showcases sections on the dashboard as
  clickable curated leaderboard cards (red_flags visually accented).
- U2: loadTraders() now sends the sort key to the API (real top-N),
  take raised to 200; only name/platform stay client-sorted.
- U4: #tradersSort dropdown extended with calmar/conviction/profitfactor/
  pnl30d; currentSort synced before building the query.
- U5: fix empty-state colspan 11 -> 10 (table has 10 columns).

Includes FIXPLAN-UI-Ranglisten.md documenting the plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 17:35:49 +02:00

9.5 KiB
Raw Blame History

FIXPLAN Teil UI — Ranglisten & Showcases sichtbar/korrekt machen

Eigenständiger Plan für die Web-UI (src/Predictalytics.Api/wwwroot/). Von oben nach unten abarbeiten. Nach jeder Aufgabe im Browser gegen die laufende API prüfen und committen.


0. Regeln (zuerst lesen)

  1. Backend-Test-Baseline bleibt grün. Vor Beginn einmal dotnet test src/Predictalytics.Application.Tests laufen lassen und die aktuelle Zahl (grün/übersprungen) notieren. Keine Aufgabe hier darf sie senken. Assertions bestehender Tests niemals ändern.
  2. Reine Frontend-Änderungen (index.html, app.js, style.css) brauchen keine Migration. Die zwei kleinen API-Ergänzungen (U3) sind additiv und nullable/optional.
  3. Nichts „drumherum" umbauen. Kleinste sichere Variante wählen. Bestehende Optik/Klassen (card, data-table, tier-badge, platform-select, CSS-Variablen) wiederverwenden, keine neuen Farbwelten erfinden.
  4. Zahlen: Prozente 0100, Beträge USD, Zeiten UTC — konsistent zum restlichen UI.
  5. Nach jeder Aufgabe: Browser-Check gegen page-dashboard bzw. page-traders, dann git commit.

Kontext — was ist kaputt (im Code verifiziert 2026-07-23)

Der Commit „Add showcase leaderboards endpoint + sortable trader list" hat das Backend erweitert, aber das Frontend nicht nachgezogen:

  • GET /api/traders/showcases liefert 7 kuratierte ShowcaseSection (copy_ready, smooth_operators, rising_stars, high_conviction, specialists, insider_watch, red_flags — siehe ShowcaseBuilder.cs). Kein Frontend-Code ruft das je auf → das Feature ist unsichtbar.
  • GetTradersAsync(sort) unterstützt serverseitig pnl, pnl30d, winrate, copytrading, calmar, conviction, profitfactor (AnalyticsService.cs:184). Das Frontend übergibt keinen sort-Param, holt stattdessen take=100 in Default-Order und sortiert clientseitig (app.js:392,420). → Die aussagekräftigen Metriken (Calmar, Conviction, Profit-Faktor) sind nicht wählbar, und jede Sortierung reiht nur die ersten 100 der Default-Order um statt die echten Top-N zu zeigen.
  • filterWinrateMin / filterCopyabilityMin filtern clientseitig nach dem take=100-Fetch (app.js:416) → ein passender Trader jenseits Rang 100 erscheint nie.
  • Zwei Sort-Dropdowns schreiben beide currentSort: global #sortSelect (app.js:121) und lokal #tradersSort (index.html:209), mit unterschiedlichen Optionssätzen.
  • Empty-State nutzt colspan="11" (app.js:407), die Tabelle hat aber 10 Spalten (index.html:270).

Aufgabe U1 — Showcases auf dem Dashboard rendern (größter Hebel)

Ziel: Die 7 kuratierten Sektionen sichtbar machen — je Sektion Titel, Beschreibung und die Top-Trader als klickbare Kacheln/Zeilen (Klick → viewTrader(id)).

  • HTML: In index.html im #page-dashboard einen Container <div id="showcaseSections"></div> ergänzen (unter den bestehenden Dashboard-Karten, vor/nach „Top Traders" — Platzierung so, dass es nicht mit den bestehenden Kacheln kollidiert).
  • JS: Neue Funktion loadShowcases() in app.js: - const sections = await api('/api/traders/showcases'); - Response-Shape (camelCase): [{ key, title, description, traders: [TraderDto, ...] }]. - Pro Sektion eine card rendern: title als Überschrift, description als page-subtitle-artiger Untertitel, darunter die Trader als kompakte Liste/Grid mit Name (+ 🤖 bei isSuspectedBot), Plattform, combinedScore, copytradingCopyabilityScore, totalPnl (via fmt.pnl), Trait-Chips (dieselbe Chip-Logik wie in loadTraders, getTraitDisplayName/Description/Class). - Leere Sektionen liefert das Backend gar nicht erst — kein Sonderfall nötig; aber wenn die ganze Antwort leer/null ist, freundlicher Empty-State. - Jede Trader-Zeile: onclick="viewTrader(${t.id})".
  • loadShowcases() in loadDashboard() aufrufen (bzw. beim Aktivieren von page-dashboard).
  • Optik: insider_watch und red_flags optisch abheben (z. B. Warn-Akzent für Red Flags über vorhandene CSS-Variablen --pnl-negative), aber im bestehenden Kartenstil bleiben.

U1 fertig, wenn: Dashboard zeigt die vom Backend gelieferten Sektionen; Klick auf einen Trader öffnet die Detailseite; keine Konsolenfehler. Commit: „UI-U1: render dashboard showcases".


Aufgabe U2 — Server-seitige Sortierung statt Client-Sort auf 100 Zeilen

Ziel: Die Rangliste zeigt die echten Top-N nach der gewählten Metrik, nicht nur eine Umsortierung der ersten 100.

  • JS: In loadTraders() den gewählten Sort als Query-Param an die API hängen: url += '&sort=' + encodeURIComponent(serverSortKey). Mapping UI→Server: score→ (leer/default), winrate→winrate, copyability→copytrading, pnl→pnl, pnl30d→pnl30d, calmar→calmar, conviction→conviction, profitfactor→profitfactor. (Der Server ordnet absteigend — das ist für alle diese Metriken die sinnvolle Richtung.)
  • JS: Den clientseitigen data.sort(...)-Block in loadTraders() entfernen bzw. nur noch als Fallback für die rein clientseitigen Keys name/platform behalten (die kennt der Server nicht).
  • take von 100 auf einen sinnvollen Wert erhöhen (z. B. 200) — die serverseitige Sortierung liefert jetzt die richtige Reihenfolge, die Tabelle kann eine echte Bestenliste zeigen.
  • Die Klick-Sortierung der Tabellenköpfe (setTraderSort, app.js:376) auf denselben Pfad umstellen: Sort setzen → loadTraders() (das nun serverseitig sortiert). Die -Header behalten.

U2 fertig, wenn: Auswahl „Calmar/Conviction/Profit-Faktor" (nach U4) verändert die Reihenfolge sichtbar und zeigt Trader, die vorher nicht in den ersten 100 waren. Commit: „UI-U2: server-side leaderboard sort".


Aufgabe U3 — Min-Filter serverseitig (Winrate/Copyability) — additive API-Ergänzung

Ziel: Die Kennzahl-Mindestfilter dürfen nicht an der 100/200-Grenze abschneiden.

  • API: IAnalyticsService.GetTradersAsync und die Implementierung (AnalyticsService.cs:165) um zwei optionale nullable Parameter erweitern: decimal? minWinRate = null, decimal? minCopyability = null. In der In-Memory-Filterkette (dort wird ohnehin schon highlyCopyable und traitFilter gefiltert) anwenden: if (minWinRate is > 0) traders = traders.Where(t => t.WinRate >= minWinRate).ToList(); und analog t.Analytics?.CopytradingCopyabilityScore >= minCopyability.
  • Endpoint: In TraderEndpoints.cs die /api/traders-Route um die zwei Query-Parameter durchreichen.
  • JS: In loadTraders() filterWinrateMin/filterCopyabilityMin als Query-Param senden statt clientseitig zu filtern; den clientseitigen Filter-Block entfernen.
  • Test: Kleiner Service-Test (SQLite-Muster wie vorhandene AnalyticsService/Repository-Tests): drei Trader mit WinRate 40/60/80, minWinRate=55 → nur zwei zurück. Baseline bleibt grün.

U3 fertig, wenn: Ein hoher Mindest-Copyability-Wert zeigt auch Trader, die in der Default-Order weit hinten stehen. Commit: „UI-U3: server-side min-winrate/min-copyability filters".


Aufgabe U4 — Sort-Dropdown vereinheitlichen & vervollständigen

Ziel: Ein einziges, vollständiges Sort-Steuerelement für die Rangliste.

  • HTML: #tradersSort (index.html:209) um die aussagekräftigen Metriken erweitern: pnl30d (PnL 30 T), calmar (Rendite/Drawdown), conviction (Conviction-Edge), profitfactor (Profit-Faktor), copyability (bereits da), score/winrate/pnl/name behalten.
  • JS: Klarstellen, welches Dropdown die Traders-Seite steuert. #tradersSort bleibt maßgeblich für page-traders; das globale #sortSelect (falls es die Traders-Seite mitsteuert) entkoppeln oder auf denselben State spiegeln, sodass es kein widersprüchliches currentSort mehr gibt.
  • Sicherstellen, dass Header-Klick (setTraderSort) und Dropdown denselben currentSort schreiben und beide loadTraders() (serverseitig, U2) auslösen.

U4 fertig, wenn: Alle Dropdown-Optionen sortieren korrekt (serverseitig), Header-Klick und Dropdown bleiben synchron. Commit: „UI-U4: unify + extend leaderboard sort control".


Aufgabe U5 — Kleinkram / Konsistenz

  • colspan-Fix: Empty-State in loadTraders() (app.js:407) von colspan="11" auf die echte Spaltenzahl 10 korrigieren.
  • Spalten-Parität: Prüfen, dass Tabellenkopf (index.html:270) und Zeilen-Template (app.js:435) dieselbe Spaltenzahl/-reihenfolge haben.
  • Optional: Aktive Sortierspalte im Header visuell markieren (Pfeilrichtung ▲/▼ statt neutralem ↕).

U5 fertig, wenn: Leere Tabelle rendert sauber über die volle Breite; kein Spaltenversatz. Commit: „UI-U5: leaderboard table consistency".


Gesamt-Abnahme

  1. dotnet build fehlerfrei; dotnet test = notierte Baseline weiter grün + neuer U3-Test grün.
  2. Dashboard zeigt die 7 Showcase-Sektionen mit echten Tradern (U1).
  3. Sortierung nach Calmar/Conviction/Profit-Faktor zeigt Trader jenseits der alten Top-100 (U2/U4).
  4. Mindest-Filter schneiden nicht mehr an der Fetch-Grenze ab (U3).
  5. Keine JS-Konsolenfehler; Tabelle ohne Spaltenversatz (U5).

Reihenfolge: U1 (Sichtbarkeit, reines Frontend) → U2 (Sort-Korrektheit) → U3 (Filter-Korrektheit, kleine API-Ergänzung) → U4 (Bedien-Konsistenz) → U5 (Politur).