Phase 1: Modul-System formalisiert (IModule + ModuleRegistry)

- Core/Modules/IModule.cs: Vertrag (Key, DisplayName, Description, Version,
  RegisterServices, InitializeAsync, GetWorkers, CreateWindow)
- Core/Modules/ModuleRegistry.cs
- CongressTradingModule auf IModule umgestellt (instanzbasiert, Platzhalter-Fenster)
- Program.cs iteriert ueber IModule[] + Registry; Form1 initialisiert Module ueber Registry
- Testbarkeit: WorkerBase DB-Log-Seam (virtuell); CapitolTradesScraper.ParseTradesFromHtml
  extrahiert (offline gegen ct_raw.html testbar)
- Tests: ModuleRegistry, CongressTradingModule, WorkerBase, CapitolTradesScraper -> 15/15 gruen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
This commit is contained in:
Richard
2026-07-27 10:07:47 +02:00
parent 9abad277c2
commit af398353f0
13 changed files with 449 additions and 35 deletions
+44
View File
@@ -0,0 +1,44 @@
using IBKRTrader.Core.Workers;
using Microsoft.Extensions.DependencyInjection;
namespace IBKRTrader.Core.Modules;
/// <summary>
/// Vertrag für ein eigenständiges Trading-Modul.
///
/// Architektur-Regel: Der Core kennt konkrete Module NICHT. Module hängen sich
/// ausschließlich über diesen Vertrag und den DI-Container ein
/// (Abhängigkeit nur Modul → Core, niemals umgekehrt).
///
/// Lebenszyklus:
/// 1. <see cref="RegisterServices"/> vor dem Bauen des DI-Containers
/// 2. <see cref="InitializeAsync"/> beim App-Start (Migrationen etc.)
/// 3. <see cref="GetWorkers"/> Worker werden der WorkerEngine übergeben
/// 4. <see cref="CreateWindow"/> Launcher öffnet das Modul-Fenster
/// </summary>
public interface IModule
{
/// <summary>Eindeutiges Modul-Kürzel, zugleich DB-Tabellen-Präfix (z. B. "CT").</summary>
string Key { get; }
/// <summary>Anzeigename im Launcher (z. B. "Congress Trading").</summary>
string DisplayName { get; }
/// <summary>Kurzbeschreibung der Strategie für den Launcher.</summary>
string Description { get; }
/// <summary>Modul-Version.</summary>
string Version { get; }
/// <summary>Registriert alle Modul-Services im DI-Container (vor dem Build).</summary>
void RegisterServices(IServiceCollection services);
/// <summary>Führt Modul-Migrationen und einmalige Initialisierung aus (beim Start).</summary>
Task InitializeAsync(IServiceProvider provider);
/// <summary>Liefert die Worker/Services des Moduls für die WorkerEngine.</summary>
IEnumerable<IWorker> GetWorkers(IServiceProvider provider);
/// <summary>Erzeugt das eigenständige Fenster des Moduls (vom Launcher geöffnet).</summary>
Form CreateWindow(IServiceProvider provider);
}
+22
View File
@@ -0,0 +1,22 @@
namespace IBKRTrader.Core.Modules;
/// <summary>
/// Zentrale Registry aller geladenen Module.
/// Wird in Program.cs mit den Modul-Instanzen befüllt und als Singleton
/// bereitgestellt, damit Launcher und Startup-Code über die Module iterieren
/// können, ohne konkrete Modultypen zu kennen.
/// </summary>
public class ModuleRegistry
{
private readonly List<IModule> _modules;
public ModuleRegistry(IEnumerable<IModule> modules)
=> _modules = modules?.ToList() ?? throw new ArgumentNullException(nameof(modules));
/// <summary>Alle registrierten Module in Registrierungsreihenfolge.</summary>
public IReadOnlyList<IModule> Modules => _modules;
/// <summary>Findet ein Modul anhand seines Kürzels (case-insensitive) oder null.</summary>
public IModule? Find(string key)
=> _modules.FirstOrDefault(m => string.Equals(m.Key, key, StringComparison.OrdinalIgnoreCase));
}