Initial commit: Predictalytics solution

Clean Architecture .NET 8 solution (Domain/Application/Infrastructure/Api/Worker/WinFormsHost)
for analyzing Polymarket traders for copytrading/strategy-replication candidates.

Includes EF Core InitialBaseline migration and DB secrets removed from source/config
in preparation for version control.
This commit is contained in:
Richard
2026-07-01 19:53:29 +02:00
commit afb251acfc
107 changed files with 9613 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
using System.Reflection;
using Predictalytics.WinFormsHost.Services;
using Serilog;
namespace Predictalytics.WinFormsHost;
public partial class MainForm : Form
{
private EmbeddedWebServer? _webServer;
private CancellationTokenSource? _workerCts;
private bool _workerRunning;
private bool _webServerRunning;
private AppSettings _settings = null!;
/// <summary>Exposes the terminal RichTextBox for the Serilog sink.</summary>
public RichTextBox Terminal => rtb_terminal;
public MainForm()
{
InitializeComponent();
this.Text = "Predictalytics Analytics — Backend Server";
rtb_terminal.BackColor = System.Drawing.Color.FromArgb(15, 15, 20);
rtb_terminal.ForeColor = System.Drawing.Color.FromArgb(180, 180, 180);
rtb_terminal.Font = new Font("Cascadia Code", 9.5f, FontStyle.Regular);
rtb_terminal.ReadOnly = true;
}
/// <summary>
/// Called after Serilog is configured. Initializes the embedded web server.
/// </summary>
public void Initialize()
{
_settings = AppSettings.Load();
pg_settings.SelectedObject = _settings;
pg_settings.PropertyValueChanged += (s, e) => {
_settings.Save();
if (_webServer != null)
{
_webServer.ConnectionString = _settings.ConnectionString;
_webServer.DbConnectionDebug = _settings.DbConnectionDebug;
}
};
_webServer = new EmbeddedWebServer();
_webServer.ConnectionString = _settings.ConnectionString;
_webServer.DbConnectionDebug = _settings.DbConnectionDebug;
// Build Version (Date of compilation/file creation)
try {
var buildDate = new FileInfo(this.GetType().Assembly.Location).LastWriteTime;
label_buildVersion.Text = $"Build: {buildDate:yyyy-MM-dd HH:mm:ss}";
} catch {
label_buildVersion.Text = "Build: Unknown";
}
UpdateStatusBar();
// Wire up button events
btn_serverstart.Click += Btn_serverstart_Click;
btn_localWebserver.Click += Btn_localWebserver_Click;
btn_syncmarkets.Click += syncMarketsaToolStripMenuItem_Click;
Log.Information("MainForm initialized. Ready.");
Log.Information("Press 'Start Server' to begin polling & discovery.");
Log.Information("Press 'Start Local Webserver' to launch the WebUI on http://localhost:{Port}", _settings.WebserverPort);
}
private async void Btn_serverstart_Click(object? sender, EventArgs e)
{
if (!_workerRunning)
{
// Start workers
_workerCts = new CancellationTokenSource();
_workerRunning = true;
btn_serverstart.Text = "⏹ Stop Server";
Log.Information("🚀 Starting background workers...");
try
{
_webServer!.ConnectionString = _settings.ConnectionString;
_webServer!.DbConnectionDebug = _settings.DbConnectionDebug;
await _webServer!.StartWorkersAsync(_workerCts.Token);
}
catch (OperationCanceledException) { }
catch (Exception ex) { Log.Error(ex, "Worker error"); }
}
else
{
// Stop workers
Log.Information("⏹ Stopping background workers...");
_workerCts?.Cancel();
_workerRunning = false;
btn_serverstart.Text = "▶ Start Server";
Log.Information("Workers stopped.");
}
UpdateStatusBar();
}
private async void Btn_localWebserver_Click(object? sender, EventArgs e)
{
if (!_webServerRunning)
{
try
{
Log.Information("🌐 Starting embedded Kestrel webserver on http://localhost:{Port}...", _settings.WebserverPort);
await _webServer!.StartWebServerAsync(_settings.WebserverPort);
_webServerRunning = true;
btn_localWebserver.Text = "⏹ Stop Webserver";
Log.Information("✅ WebUI available at http://localhost:{Port}", _settings.WebserverPort);
Log.Information("📄 Swagger API docs at http://localhost:{Port}/swagger", _settings.WebserverPort);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to start webserver");
_webServerRunning = false;
}
}
else
{
Log.Information("⏹ Stopping webserver...");
await _webServer!.StopWebServerAsync();
_webServerRunning = false;
btn_localWebserver.Text = "▶ Start Webserver";
Log.Information("Webserver stopped.");
}
UpdateStatusBar();
}
private void UpdateStatusBar()
{
var workerStatus = _workerRunning ? "[RUNNING] Workers" : "[STOPPED] Workers";
var serverStatus = _webServerRunning ? $"[RUNNING] Webserver :{_settings.WebserverPort}" : "[STOPPED] Webserver";
this.Text = $"Predictalytics Analytics — {workerStatus} | {serverStatus}";
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
_workerCts?.Cancel();
_webServer?.StopWebServerAsync().GetAwaiter().GetResult();
base.OnFormClosing(e);
}
private void btn_openbrowser_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start("explorer.exe", $"\"http://localhost:{_settings.WebserverPort}\"");
}
catch (Exception ex)
{
Serilog.Log.Error(ex, "Fehler beim Öffnen des Browsers");
MessageBox.Show("Browser konnte nicht gestartet werden.", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btn_logfolder_Click(object sender, EventArgs e)
{
try
{
var logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
if (Directory.Exists(logPath))
System.Diagnostics.Process.Start("explorer.exe", logPath);
else
System.Diagnostics.Process.Start("explorer.exe", Environment.CurrentDirectory);
}
catch (Exception ex)
{
Serilog.Log.Error(ex, "Fehler beim Öffnen des Log-Ordners");
}
}
private async void syncMarketsaToolStripMenuItem_Click(object sender, EventArgs e)
{
if (_workerRunning)
{
MessageBox.Show("Market sync cannot be started while background workers are running.",
"Workers Busy", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
btn_syncmarkets.Enabled = false;
Log.Information("Manual market sync triggered...");
// Use a temporary CTS for this operation
using var cts = new CancellationTokenSource();
await _webServer!.RunSingleMarketSyncAsync(cts.Token);
Log.Information("Manual market sync completed successfully.");
MessageBox.Show("Market sync completed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
Log.Error(ex, "Manual market sync failed");
MessageBox.Show($"Market sync failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
btn_syncmarkets.Enabled = true;
}
}
}