Add showcase leaderboards endpoint + sortable trader list

- GET /api/traders/showcases: curated dashboard sections (copy-ready, smooth
  operators, rising stars, high conviction, specialists, insider watch, red
  flags), each encoding a selection funnel over the persisted analytics/traits.
  Pure ShowcaseBuilder holds the ranking logic (+6 unit tests).
- GET /api/traders?sort=: leaderboard sort keys (pnl, pnl30d, winrate,
  copytrading, calmar, conviction, profitfactor) over the loaded set.
Read-only, persisted-data-only (public-tier safe). 76 tests, 1 skip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-23 09:43:11 +02:00
co-authored by Claude Opus 4.8
parent eaccdadddf
commit 02c5a4d6f4
5 changed files with 256 additions and 5 deletions
@@ -13,8 +13,12 @@ public static class TraderEndpoints
{
var group = routes.MapGroup("/api/traders").WithTags("Traders");
group.MapGet("/", async (IAnalyticsService svc, int? skip, int? take, string? platform, bool? highlyCopyable, string? trait, CancellationToken ct) =>
Results.Ok(await svc.GetTradersAsync(skip ?? 0, take ?? 50, platform, highlyCopyable ?? false, trait, ct)));
group.MapGet("/", async (IAnalyticsService svc, int? skip, int? take, string? platform, bool? highlyCopyable, string? trait, string? sort, CancellationToken ct) =>
Results.Ok(await svc.GetTradersAsync(skip ?? 0, take ?? 50, platform, highlyCopyable ?? false, trait, sort, ct)));
// Curated dashboard showcases (leaderboards). Read-only, persisted data only.
group.MapGet("/showcases", async (IAnalyticsService svc, CancellationToken ct) =>
Results.Ok(await svc.GetShowcasesAsync(ct)));
group.MapGet("/traits", async (Predictalytics.Infrastructure.Data.AppDbContext db, CancellationToken ct) =>
Results.Ok(await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(db.TraderTraits.Select(t => t.Trait).Distinct(), ct)));