Fix embedded-server endpoint drift, add Recalculate All Traders button

- Shared ApiConfiguration.MapPredictalyticsEndpoints() used by both the
  standalone API and the embedded WinForms Kestrel server: the embedded
  host was missing /api/watchlist and /api/dev (empty watchlist page),
  the standalone host was missing /api/search.
- New Development menu action "Recalculate All Traders": backfills
  ResolutionOutcome from snapped outcome prices, wipes derived analytics
  (snapshots, category stats, rebuildable positions), zeroes aggregates
  and marks every trader for re-analysis. Raw trades untouched.
- Static files now served with Cache-Control: no-cache in both hosts,
  plus ?v= cache-buster on app.js/style.css (stale browser JS masked
  earlier UI fixes).
- Watchlist hardened: endpoint null-safe, real Analytics.CopytradingScore,
  Platform field; repository includes Trader.Analytics; page shows a
  visible error row instead of staying silently blank.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-10 17:58:10 +02:00
co-authored by Claude Fable 5
parent 1787422243
commit 850c47a404
8 changed files with 155 additions and 30 deletions
@@ -233,6 +233,46 @@ public partial class MainForm : Form
}
}
private async void btn_recalcAll_Click(object? sender, EventArgs e)
{
if (_workerRunning)
{
MessageBox.Show("Recalculation cannot be started while background workers are running. Stop the server first.",
"Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var confirm = MessageBox.Show(
"This deletes all DERIVED analytics data (positions, daily snapshots, category stats) " +
"and marks every trader for full recalculation.\n\n" +
"Raw trades and markets are NOT touched.\n\n" +
"After this, start the server: the analytics worker rebuilds every trader with the current " +
"engine (runs in the background, can take several hours for large trader counts).\n\nContinue?",
"Recalculate All Traders", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (confirm != DialogResult.Yes) return;
try
{
btn_recalcAll.Enabled = false;
Log.Information("Manual full recalculation reset triggered...");
using var cts = new CancellationTokenSource();
var summary = await _webServer!.RunRecalculateAllTradersAsync(cts.Token);
MessageBox.Show($"Reset complete:\n\n{summary}\n\nNow start the server to rebuild the analytics.",
"Recalculate All Traders", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
Log.Error(ex, "Full recalculation reset failed");
MessageBox.Show($"Recalculation reset failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btn_recalcAll.Enabled = true;
}
}
private async Task UpdateDbSizeAsync()
{
try