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> @
9.5 KiB
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)
- Backend-Test-Baseline bleibt grün. Vor Beginn einmal
dotnet test src/Predictalytics.Application.Testslaufen lassen und die aktuelle Zahl (grün/übersprungen) notieren. Keine Aufgabe hier darf sie senken. Assertions bestehender Tests niemals ändern. - Reine Frontend-Änderungen (
index.html,app.js,style.css) brauchen keine Migration. Die zwei kleinen API-Ergänzungen (U3) sind additiv und nullable/optional. - 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. - Zahlen: Prozente 0–100, Beträge USD, Zeiten UTC — konsistent zum restlichen UI.
- Nach jeder Aufgabe: Browser-Check gegen
page-dashboardbzw.page-traders, danngit 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/showcasesliefert 7 kuratierteShowcaseSection(copy_ready,smooth_operators,rising_stars,high_conviction,specialists,insider_watch,red_flags— sieheShowcaseBuilder.cs). Kein Frontend-Code ruft das je auf → das Feature ist unsichtbar.GetTradersAsync(sort)unterstützt serverseitigpnl,pnl30d,winrate,copytrading,calmar,conviction,profitfactor(AnalyticsService.cs:184). Das Frontend übergibt keinensort-Param, holt stattdessentake=100in 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/filterCopyabilityMinfiltern clientseitig nach demtake=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.htmlim#page-dashboardeinen 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()inapp.js: -const sections = await api('/api/traders/showcases');- Response-Shape (camelCase):[{ key, title, description, traders: [TraderDto, ...] }]. - Pro Sektion einecardrendern:titleals Überschrift,descriptionalspage-subtitle-artiger Untertitel, darunter die Trader als kompakte Liste/Grid mit Name (+🤖beiisSuspectedBot), Plattform,combinedScore,copytradingCopyabilityScore,totalPnl(viafmt.pnl), Trait-Chips (dieselbe Chip-Logik wie inloadTraders,getTraitDisplayName/Description/Class). - Leere Sektionen liefert das Backend gar nicht erst — kein Sonderfall nötig; aber wenn die ganze Antwort leer/nullist, freundlicher Empty-State. - Jede Trader-Zeile:onclick="viewTrader(${t.id})". loadShowcases()inloadDashboard()aufrufen (bzw. beim Aktivieren vonpage-dashboard).- Optik:
insider_watchundred_flagsoptisch 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 inloadTraders()entfernen bzw. nur noch als Fallback für die rein clientseitigen Keysname/platformbehalten (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.GetTradersAsyncund 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 schonhighlyCopyableundtraitFiltergefiltert) anwenden:if (minWinRate is > 0) traders = traders.Where(t => t.WinRate >= minWinRate).ToList();und analogt.Analytics?.CopytradingCopyabilityScore >= minCopyability. - Endpoint: In
TraderEndpoints.csdie/api/traders-Route um die zwei Query-Parameter durchreichen. - JS: In
loadTraders()filterWinrateMin/filterCopyabilityMinals 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/namebehalten. - JS: Klarstellen, welches Dropdown die Traders-Seite steuert.
#tradersSortbleibt maßgeblich fürpage-traders; das globale#sortSelect(falls es die Traders-Seite mitsteuert) entkoppeln oder auf denselben State spiegeln, sodass es kein widersprüchlichescurrentSortmehr gibt. - Sicherstellen, dass Header-Klick (
setTraderSort) und Dropdown denselbencurrentSortschreiben und beideloadTraders()(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) voncolspan="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
dotnet buildfehlerfrei;dotnet test= notierte Baseline weiter grün + neuer U3-Test grün.- Dashboard zeigt die 7 Showcase-Sektionen mit echten Tradern (U1).
- Sortierung nach Calmar/Conviction/Profit-Faktor zeigt Trader jenseits der alten Top-100 (U2/U4).
- Mindest-Filter schneiden nicht mehr an der Fetch-Grenze ab (U3).
- 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).