Eine Roadmap statt neun Plandokumente; alte Plaene ins Archiv

Die offenen Punkte lagen ueber neun Dokumente verstreut, teils widersprechend,
teils mit Punkten, die laengst umgesetzt waren. ROADMAP.md fuehrt sie zusammen:
sechs Stufen, jeder Punkt gegen den Code geprueft.

Markierung ueber eine Legende, damit Konzepte nicht mit Aufgaben verwechselt
werden: dringend, eingeplant, Backlog, Konzept (durchdacht, aber bewusst nicht
eingeplant), liegt beim Nutzer, verworfen.

Stufen: 0 Sofort (OpenRouter-Key) - 1 Aufraeumen abschliessen (Merge nach main,
Nullable-Warnungen, Startup-Backfill) - 2 Portierung abschliessen (Linux-Erstlauf
und Verifikation, dann Deployment/CI) - 3 Analytik schaerfen (Strategie-
Klassifikation, Backtest-Harness, Track-Record im Score, Ranking) - 4 Daten-
haushalt (SQL des Nutzers) - 5 Ingest skalieren - 6 Monetarisierung vorbereiten.

Ein Anhang haelt fest, was geprueft und bewusst NICHT auf die Roadmap kam, damit
es nicht versehentlich wieder als Aufgabe auftaucht (Azuro/Limitless, die
Marketing-Seiten, Kaltarchiv, EF Core 10).

Archiv: FIXPLAN-DONE, FIXPLAN-G-Speicher, FIXPLAN-TODO, FIXPLAN-UI-Ranglisten,
UMSETZUNGSPLAN sowie ANALYSE-Linux-Portierung, PLAN-Linux-Portierung,
PLAN-Architektur-WebUI-Backend und PLAN-DatenIngest-Skalierung liegen jetzt
unter docs/archiv/ mit einer README, die jedes Dokument einordnet. Sie bleiben
als Begruendungs- und Detailquelle - die Roadmap nennt jeden Punkt knapp, die
Herleitung steht dort.

Dabei aufgefallen: die beiden nie gepflegten Plaene (Architektur, DatenIngest)
zeigten 40 offene Punkte, von denen die Haelfte umgesetzt war - Read/Control-
Split, /api/capabilities, CORS-Whitelist, Egress-Kanaele mit Cooldown und
Per-Kanal-Limiter, Ingest-Tiering. Nachgeprueft, abgehakt und mit Statusblock
eingeordnet, sonst waere das Archiv selbst eine Fehlerquelle.

Was dabei nur teilweise umgesetzt war, ist als Roadmap 5.3 aufgenommen
(Health-Statistik je Kanal, multi-homed pruefen, DB-Guard, Plausibilitaets-
pruefung), ebenso der nie durchgefuehrte Audit auf versteckte Writes in
Read-Endpunkten (6.1). Header-Rotation ist als verworfen markiert statt offen
zu bleiben: Verschleierung gegenueber Polymarket riskiert genau den Zugang, auf
dem das Projekt aufsetzt.

STATUS.md beschreibt jetzt nur noch den Ist-Stand und verweist fuer die offenen
Punkte auf die Roadmap, damit nichts doppelt gepflegt wird. CLAUDE.md nennt
beide Einstiege.

Build gruen, 126 Tests gruen, keine toten Links.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-23 18:46:00 +02:00
co-authored by Claude Opus 5
parent 1f230fe12c
commit 6975720dc6
14 changed files with 429 additions and 73 deletions
+7 -2
View File
@@ -1,7 +1,12 @@
# Predictalytics # Predictalytics
**Stand des Projekts, offene Punkte und Altlasten-Entscheidungen: **Zuerst hier nachsehen:**
[`STATUS.md`](STATUS.md)**dort zuerst nachsehen. * [`STATUS.md`](STATUS.md) — wo das Projekt steht, was fertig ist.
* [`ROADMAP.md`](ROADMAP.md) — was ansteht, in welcher Reihenfolge, und welche Konzepte
bewusst zurückgestellt sind.
Die früheren Plandokumente liegen unter [`docs/archiv/`](docs/archiv/) und werden nicht
mehr gepflegt.
Betriebsdokumentation zur Anbindung an das Deployment Center (Lizenz, Watchdog, Betriebsdokumentation zur Anbindung an das Deployment Center (Lizenz, Watchdog,
Updates, Fehler-Stream): [`docs/BETRIEB-Deploymentcenter.md`](docs/BETRIEB-Deploymentcenter.md). Updates, Fehler-Stream): [`docs/BETRIEB-Deploymentcenter.md`](docs/BETRIEB-Deploymentcenter.md).
+310
View File
@@ -0,0 +1,310 @@
# Predictalytics — Roadmap
> Angelegt am **2026-08-23**. Führt zusammen, was vorher über neun Plandokumente verstreut
> lag. Jeder Punkt hier ist gegen den Code geprüft — was schon umgesetzt war, steht nicht
> mehr drin.
>
> **Ist-Stand des Projekts:** [`STATUS.md`](STATUS.md).
> **Die alten Dokumente** liegen vollständig unter [`docs/archiv/`](docs/archiv/) und
> werden nicht mehr gepflegt. Sie bleiben als Begründungs- und Detailquelle: wo ein Punkt
> unten knapp bleibt, steht die ausführliche Herleitung dort. Die Verweise sind jeweils
> angegeben.
## Legende
| | Bedeutung |
|---|---|
| 🔴 | Dringend — sollte vor allem anderen passieren |
| 🟢 | Eingeplant — wird als Nächstes abgearbeitet |
| 🟡 | Backlog — gewollt, aber noch nicht terminiert |
| 💡 | **Konzept — bewusst nicht eingeplant.** Idee ist durchdacht und aufgehoben, die Umsetzung ist nicht beschlossen |
| 👤 | Liegt beim Nutzer, nicht am Code (SQL, Kontoverwaltung, Entscheidungen) |
| ❌ | Bewusst verworfen — nicht wieder aufgreifen ohne neuen Anlass |
Innerhalb der Stufen ist die Reihenfolge gedacht, aber nicht bindend. Zwischen den Stufen
schon: jede baut auf der vorigen auf.
---
## Stufe 0 — Sofort
### 0.1 🔴 👤 OpenRouter-API-Key zurückziehen und neu ausstellen
`src/Predictalytics.Api/appsettings.json` enthält einen **echten** Schlüssel im Klartext,
versioniert seit Commit `7045002` und damit auf dem Gitea-Server.
1. Schlüssel bei OpenRouter widerrufen, neuen ausstellen.
2. Neuen Schlüssel **nicht** in die Datei schreiben, sondern als Umgebungsvariable
`OpenRouter__ApiKey` setzen. `WebApplication.CreateBuilder` liest Umgebungsvariablen mit
Vorrang vor `appsettings.json` — dafür ist keine Codeänderung nötig.
3. Erst danach den Platzhalter in `appsettings.json` leeren.
Den Wert nur aus der Datei zu löschen genügt nicht: der Git-Verlauf behält ihn. Deshalb
führt an Schritt 1 kein Weg vorbei.
> Herkunft: [`archiv/UMSETZUNGSPLAN.md`](docs/archiv/UMSETZUNGSPLAN.md) B2 — dort noch als „kein akuter Risikofall" eingestuft, was
> sich als falsch herausgestellt hat.
---
## Stufe 1 — Aufräumen abschließen
### 1.1 🟢 `feature/linux-net10` nach `main` bringen
`main` steht neun Commits zurück und kennt weder die Avalonia-Shell noch die
Deploymentcenter-Anbindung. Alle Feature-Zweige sind in `feature/linux-net10` aufgegangen.
Danach löschbar (lokal und auf origin):
```
copy-portfolio edge-freshness fingerprint-drift-foundation insider-follow-feed
integration smart-money-comovement smart-money-graph ui-ranglisten-showcases
ops-watchdog-license fix-event-description-truncation
```
### 1.2 🟡 Acht Nullable-Warnungen beheben
`TradeRepository.cs:94-102` (6×), `PolymarketProvider.cs:357`,
`TraderAnalyticsWorker.cs:152`. Bestehen seit Längerem und sind kein Aufräumen, sondern
Logikarbeit — jede will einzeln angesehen werden, ob `null` dort auftreten kann.
### 1.3 🟡 Startup-Backfill entschärfen
`PredictalyticsHost.cs:116` lädt bei **jedem Start** alle Märkte samt Event in den
Speicher, um Kategorien neu abzuleiten. Bei wachsendem Bestand belastet das die Startzeit
spürbar. Entweder auf Märkte mit `Category = Other` einschränken, oder einmalig laufen
lassen und über ein Flag abschalten.
---
## Stufe 2 — Portierung abschließen
Der Code ist plattformneutral gebaut, aber **auf keinem Linux-System je ausgeführt worden**.
Bis das nachgeholt ist, ist „läuft unter Linux" eine Annahme.
> Details zu allen Punkten: [`docs/archiv/PLAN-Linux-Portierung.md`](docs/archiv/PLAN-Linux-Portierung.md),
> Abschnitte 7 und 8.
### 2.1 🟢 Erstlauf und Verifikation unter Linux
Die Reihenfolge ist bewusst so: erst beweisen, dass es läuft, dann Deployment bauen.
- [ ] Shell auf einem Linux-Desktop starten — alle Schaltflächen, Menüs, Persistenz der Einstellungen
- [ ] Derselbe Build mit `--headless` auf einem Server ohne X11: Start, Lizenz aus der Konfiguration, sauberer Stopp per SIGTERM
- [ ] Worker-Dauerlauf ≥ 24 h gegen die **Dev-DB**, Logvergleich mit einem Windows-Lauf
- [ ] Lauf unter `LANG=de_DE.UTF-8` — Volumina, Preise, PnL gegen die Windows-Referenz prüfen (Kultur-Fallen)
- [ ] Web-UI vollständig durchklicken — case-sensitive Assets sind unter Linux ein echtes Risiko
- [ ] Lizenz: Erstaktivierung, Neustart aus dem Cache, Offline-Gnadenfrist, Revalidierung
- [ ] Watchdog-Heartbeats erscheinen am Deployment Center
- [ ] EF-Migrationen von Null gegen die Dev-DB
- [ ] Egress-Kanäle, falls genutzt (`SourceIp` verhält sich unter Linux anders)
### 2.2 🟢 Deployment und CI
- [ ] `dotnet publish -r linux-x64` und `-r win-x64`; bei self-contained das Trimming-Verhalten von Avalonia beachten
- [ ] Linux-Systemabhängigkeiten dokumentieren: `libx11-6`, `libice6`, `libsm6`, `libfontconfig1`, `libharfbuzz0b`, Monospace-Schriften
- [ ] systemd-Unit bzw. Dockerfile für den Headless-Betrieb — es existiert bereits `J:\Softwareprojekte\dockerCompose`, vermutlich anknüpfbar
- [ ] Reverse Proxy (nginx/Caddy) mit TLS vor Kestrel
- [ ] Secrets unter Linux: EnvironmentFile mit `0600` statt Klartext in `settings.json`
- [ ] CI: Build + Test auf Linux **und** Windows
- [ ] `docs/BETRIEB-Deploymentcenter.md` um den Linux-Betrieb ergänzen
---
## Stufe 3 — Analytik schärfen
### 3.1 🟢 Strategie-Klassifikation reparieren (ehemals A4)
Der größte fachliche Rückstand. `StrategyType` entsteht aus genau zwei Signalen —
`avgSize > 10000` ergibt `Whale`, `hedgingRate > 30` ergibt `Hedger`, sonst `Bot` oder
`Unknown`. Deshalb landet der **Großteil der Trader strukturell auf `Unknown`**, was den
Wert der Einstufung gegen null gehen lässt.
Erschwerend: die Logik steht **doppelt** da und die beiden Schreiber überschreiben einander
`AnalyticsService.cs:418` und `ScoringService.cs:89`.
- [ ] Zuerst die Doppelung auflösen: **ein** Ort, der `StrategyType` bestimmt
- [ ] Vorhandene, bereits berechnete Signale einspeisen statt neue zu erheben:
`StrategyMetricsCalculator` (Kategorie-Konzentration, Conviction-Edge),
`TraderTraitCalculator` (Traits), `FingerprintSnapshotService` (Kategorie-Mix über Zeit)
- [ ] Ergänzend, falls nötig: Verteilung der Haltedauern, Anteil später vs. früher Einstiege
im Marktleben, Varianz der Ordergrößen
- [ ] Prüfen, ob ein Einzel-Enum reicht oder ob Mehrfachsignale danebengehören
(Enum als Primär-Tag, Zusatzsignale als eigene Felder)
- [ ] Abnahme: der Anteil `Unknown` ist deutlich gesunken
> Herkunft: [`docs/archiv/UMSETZUNGSPLAN.md`](docs/archiv/UMSETZUNGSPLAN.md) A4.
### 3.2 🟡 `CopytradingBacktestHarness` anschließen oder verwerfen
123 Zeilen fertig implementierter Latenz-Sweep (0/10/30/60 s) samt `BacktestResult`, per DI
registriert — und **von niemandem aufgerufen**. Der Sweep würde beziffern, wie viel Alpha
ein Nachahmer bei welcher Verzögerung verliert; das passt genau zum Zweck des Projekts.
Entscheidung nötig: an einen Endpunkt und die Trader-Detailseite hängen, oder ersatzlos
löschen. Der jetzige Zustand — gepflegt, aber wirkungslos — ist die schlechteste Variante.
### 3.3 🟡 Track-Record-Länge in den Copyability-Score
Der Score besteht heute aus Alpha-Verfall (70 %) und Sizing-Konsistenz (30 %). Die
ursprünglich geplante vierte Komponente — Länge und Konsistenz des Track Records — fehlt.
Ein Trader mit drei glücklichen Märkten bekommt denselben Score wie einer mit dreihundert.
> Herkunft: [`archiv/UMSETZUNGSPLAN.md`](docs/archiv/UMSETZUNGSPLAN.md) A5, letzter Unterpunkt.
### 3.4 🟡 Edge-Freshness und Strategie-Drift ins Ranking
Beide Kennzahlen existieren, erscheinen aber nur auf der Detailseite und in Alarmen. In der
Rangliste — dort, wo ausgewählt wird — spielen sie keine Rolle. Ein Master mit abgestandener
Edge steht weiterhin oben.
### 3.5 🟡 Co-Movement-Graph vorberechnen
`GET /api/co-movement/graph` rechnet bei jedem Aufruf. Für die Netzwerkansicht ist das
träge und belastet die DB unnötig. In den `ScoringAndAlertsWorker` verlagern und das
Ergebnis ablegen.
### 3.6 🟡 Restpunkte aus der Kategorie-Erkennung
- [ ] Gezielt fehlende Event-Tags nachladen für Märkte, die getrackte Trader gehandelt haben
([`archiv/FIXPLAN-TODO.md`](docs/archiv/FIXPLAN-TODO.md) F5) — der tägliche Sync geschlossener Märkte deckt den Fall
inzwischen weitgehend ab, die Lücke ist klein
- [ ] Zwei fehlende Tests (F6): Event-Tag-Vererbung und Offline-Backfill
### 3.7 🟡 Sortierpfeile in der Trader-Tabelle
Die Tabellenköpfe zeigen statisch `↕`, auch in der aktiven Sortierspalte. Reine Politik,
war schon im UI-Plan als „Optional" markiert.
---
## Stufe 4 — Datenhaushalt
Alles hier läuft über SQL, das **der Nutzer selbst** gegen die Datenbank fährt. Wir liefern
die Anweisungen, führen sie aber nicht aus.
> Details: [`docs/archiv/FIXPLAN-G-Speicher.md`](docs/archiv/FIXPLAN-G-Speicher.md) (Anhang)
> und [`docs/archiv/UMSETZUNGSPLAN.md`](docs/archiv/UMSETZUNGSPLAN.md) C3.
### 4.1 👤 🟡 Einmalige DB-Optimierungen
- [ ] Spaltentypen verkleinern: `TransactionHash`, `MarketId`, `AssetId` sind Hex-/Dezimalstrings in überbreiten Feldern
- [ ] InnoDB-Kompression (`ROW_FORMAT=COMPRESSED`) für `Trades` — schneller Zugewinn, geringes Risiko
- [ ] Partitionierung von `Trades` nach Monat (`ExecutedAt`) prüfen — erlaubt späteres Verwerfen ganzer Partitionen
### 4.2 👤 💡 Materialitätsschwelle für Mikro-Trades
Trades unterhalb eines Betrags (Vorschlag: $0,50) unabhängig vom Retention-Fenster
verwerfen. Durchdacht, aber nicht beschlossen — die Schwelle verändert die PnL-Rechnung
leicht, und der Gewinn ist ungewiss, bis 4.1 gemessen ist.
### 4.3 👤 💡 Frischer Datenbank-Neustart
Die alte Überlegung, die Produktivdatenbank leer neu aufzusetzen und über die Worker neu zu
befüllen (Rohdaten sind über `/activity` jederzeit nachladbar). **Nicht beschlossen.** Falls
er kommt, gehört er ans Ende von Stufe 3, nicht davor — sonst laufen Analytik-Änderungen und
Datenumzug gleichzeitig.
Vorgelagerter Bestätigungs-Check: stichprobenartig prüfen, wie weit `/activity` für ein
lange aktives Wallet tatsächlich zurückreicht.
### 4.4 💡 65 Migrationsdateien zusammenfassen
32 Migrationen ergeben 65 Dateien und rund 37.000 Zeilen. Eine neue Baseline wäre
übersichtlicher, kostet aber die Schemahistorie und ist gegen eine laufende Produktivdatenbank
heikel. Nur sinnvoll im Zuge von 4.3.
---
## Stufe 5 — Ingest skalieren
Erst angehen, wenn Rate-Limits tatsächlich drücken. Die wirksamsten Maßnahmen sind bereits
umgesetzt (Ingest-Tiering, Egress-Kanäle, Kurzzeit-Cache).
> Details: [`docs/archiv/PLAN-DatenIngest-Skalierung.md`](docs/archiv/PLAN-DatenIngest-Skalierung.md).
### 5.1 💡 Historische Massendaten aus der Blockchain statt über REST
Der größte ungenutzte Hebel. Polymarket-Trades sind On-Chain-Events auf Polygon; für
Backfill und Deep-Resync — die teuersten REST-Verbraucher — ist `/activity` die falsche
Quelle. Ein GraphQL-Aufruf gegen einen Subgraph (The Graph / Goldsky) liefert tausende Fills
eines Wallets auf einmal.
Skizze: `IHistoricalTradeSource` neben den REST-Provider stellen, Deep-Resync zieht darüber.
**Nicht eingeplant**, weil erst zu evaluieren ist, ob ein brauchbarer Subgraph existiert und
wie vollständig er ist.
### 5.2 🟡 Markt-Stammdaten aggressiv cachen
Metadaten (Frage, Kategorie, Outcomes, `ConditionId``TokenId`) ändern sich nie — einmal
ziehen, lang halten; nur Volumen, Liquidität und Auflösung periodisch aktualisieren.
Teilweise erledigt: geschlossene Märkte werden nur noch einmal täglich synchronisiert.
### 5.3 🟡 Egress-Kanäle: Betriebsreste
Die Mechanik steht (Round-Robin, Cooldown nach drei Fehlschlägen, Limiter je Kanal). Was
im Ingest-Plan noch danebensteht:
- [ ] Health-Statistik je Kanal — Erfolgsquote, 429-Rate, Latenz. Heute gibt es nur einen
Fehlerzähler: tote Kanäle werden pausiert, aber nicht ausgewertet
- [ ] Bei eigenen IPs prüfen, ob es echte getrennte Egress-IPs sind (multi-homed) und nicht
NAT hinter derselben öffentlichen Adresse — sonst bringt die Aufteilung nichts
- [ ] Regressionsschutz: die MySQL-Verbindung darf **nie** über den Egress-Pool oder einen
Proxy laufen
- [ ] Grob unplausible Provider-Antworten abfangen (z. B. Preis außerhalb 01)
### 5.4 ❌ Header- und User-Agent-Rotation
Im Ingest-Plan bewusst als „standardmäßig AUS" eingeordnet. Rotation zur Verschleierung
gegenüber Polymarket ist gegen deren Interesse gerichtet und riskiert die Sperrung genau des
Zugangs, auf dem das Projekt aufsetzt. Der ehrliche Weg ist, die Nachfrage zu senken (5.1,
5.2) und legitime Kanäle zu erhöhen (bereits umgesetzt).
---
## Stufe 6 — Monetarisierung vorbereiten
Nur relevant, falls aus dem internen Werkzeug ein Produkt werden soll. **Bislang eine Idee,
keine Entscheidung.** Die Vorarbeit (Read/Control-Trennung, `/api/capabilities`,
CORS-Whitelist) ist im Zuge der Portierung ohnehin schon passiert.
> Details: [`docs/archiv/PLAN-Architektur-WebUI-Backend.md`](docs/archiv/PLAN-Architektur-WebUI-Backend.md).
### 6.1 💡 Datenbank für eine öffentliche Schicht vorbereiten
- **Read-Endpunkte auf versteckte Writes und Provider-Aufrufe prüfen.** Der Read/Control-Split
steht, aber ob jeder einzelne Read-Endpunkt frei von Schreibzugriffen ist, wurde nie
systematisch geprüft — besonders der Deep-Dive-Pfad. Vor einem öffentlichen Host
nachzuholen, sonst wird die read-only Verbindung im Betrieb Fehler werfen
- Read-only DB-Benutzer auf der Analyse-DB (nur `SELECT`) — 👤 der Nutzer führt die Grants aus
- Schema-Kopplung dokumentieren: liest eine öffentliche Schicht direkt mit, wird das
DB-Schema zur **Vertragsfläche**. Views als Puffer erwägen, damit interne Umbauten die
öffentliche Sicht nicht brechen.
Billig und jederzeit vorziehbar, auch wenn 6.2 nie kommt.
### 6.2 💡 Öffentlicher Host
Eigenes Projekt `Predictalytics.PublicApi`: registriert nur die Read-Endpunkte, dazu
Konten/Authentifizierung in einer **getrennten** User-DB, Rate-Limits und Kontingente pro
Konto, Mandantensicht (Kunde sieht seine Watchlist, nicht das ganze Universum), liefert
dasselbe SPA aus.
**Nicht-Ziele, die dabei gelten** — ❌ kein Zugriff der öffentlichen Schicht auf Core-Prozess,
lokale API oder Steuerendpunkte; ❌ kein Schreibzugriff auf die Analyse-DB; ❌ keine
Kunden-Authentifizierung nachträglich in die lokale Vollschicht bauen; ❌ Read-Endpunkte
machen keine Provider-Aufrufe und keine Writes.
---
## Anhang — bewusst nicht auf der Roadmap
Geprüft und mit Absicht ausgelassen. Nicht versehentlich wieder aufnehmen:
| Was | Warum |
|---|---|
| `AzuroProvider` löschen | Platzhalter mit `IsImplemented => false`, wird sauber übersprungen. Kostet nichts, markiert den Ausbaupfad. |
| `Providers/Limitless/` löschen | Voll implementierter zweiter Marktplatz, `IsImplemented => true`. Wird nur nicht bespielt — Löschen wäre Funktionsverlust. |
| `wwwroot/landing.html`, `docs.html` | Marketing-Seiten mit Preis-Abschnitt, vom Dashboard nicht verlinkt. Gehören zu Stufe 6. |
| Kaltarchiv außerhalb der DB | Verworfen: Rohdaten sind über die Polymarket-API jederzeit nachladbar, ein Archiv wäre reine Zusatzlast. |
| EF Core auf 10 heben | Blockiert: Pomelo hat keinen EF-10-Provider und pinnt Relational hart auf `[9.0.0, 9.0.999]`. Vor einem Versuch prüfen, ob Pomelo nachgezogen hat. |
+24 -51
View File
@@ -4,8 +4,9 @@
> gegen den Code geprüft, nicht aus den Plandokumenten übernommen — die waren zu diesem > gegen den Code geprüft, nicht aus den Plandokumenten übernommen — die waren zu diesem
> Zeitpunkt durchweg veraltet. > Zeitpunkt durchweg veraltet.
> >
> Dieses Dokument ist die Einstiegsseite. Die Detailpläne bleiben bestehen und tragen > Dieses Dokument beschreibt den **Ist-Stand**. Was ansteht, steht in
> jetzt jeweils oben einen eigenen Statusblock. > [`ROADMAP.md`](ROADMAP.md); die abgelösten Plandokumente liegen unter
> [`docs/archiv/`](docs/archiv/).
--- ---
@@ -46,27 +47,28 @@ dem Predictalytics-Checkout liegen, sonst bricht der Build mit einer erklärende
## 2. Was fertig ist ## 2. Was fertig ist
Alles Folgende ist im Code belegt die Belegstellen stehen in den jeweiligen Plandokumenten. Alles Folgende ist im Code belegt; die Belegstellen stehen in den archivierten Plandokumenten
unter [`docs/archiv/`](docs/archiv/).
* **Kernanalytik** (`UMSETZUNGSPLAN.md`, Phase 1): positionsbasierte PnL-Engine nach * **Kernanalytik** ([`archiv/UMSETZUNGSPLAN.md`](docs/archiv/UMSETZUNGSPLAN.md), Phase 1): positionsbasierte PnL-Engine nach
Average-Cost mit sauberer Behandlung jeder `TradeSide`, marktbasierte Win-Rate, Average-Cost mit sauberer Behandlung jeder `TradeSide`, marktbasierte Win-Rate,
Deep-Dive-Kennzahlen aus echter Preishistorie, Copytrading-Score aus gemessenem Deep-Dive-Kennzahlen aus echter Preishistorie, Copytrading-Score aus gemessenem
Alpha-Verfall gegen das Markt-Tape. Alpha-Verfall gegen das Markt-Tape.
* **Robustheit** (Phase 2): EF-Migrationen statt handgeschriebener `ALTER TABLE`, * **Robustheit** (Phase 2): EF-Migrationen statt handgeschriebener `ALTER TABLE`,
entkoppelte Scoring-Pipeline, Log-Retention, Testprojekt. Alle fünf Bugs aus dem entkoppelte Scoring-Pipeline, Log-Retention, Testprojekt. Alle fünf Bugs aus dem
Review-Pass vom 2026-07-01 sind behoben. Review-Pass vom 2026-07-01 sind behoben.
* **Speicher-Haushalt** (`FIXPLAN-G-Speicher.md`): budgetabhängiges Retention-Fenster, * **Speicher-Haushalt** ([`archiv/FIXPLAN-G-Speicher.md`](docs/archiv/FIXPLAN-G-Speicher.md)): budgetabhängiges Retention-Fenster,
Burst-Kompaktierung, Per-Kategorie-Edge. Burst-Kompaktierung, Per-Kategorie-Edge.
* **Kategorie-Erkennung** (`FIXPLAN-TODO.md`, Teil F): kanonische Tag-Tabelle, * **Kategorie-Erkennung** ([`archiv/FIXPLAN-TODO.md`](docs/archiv/FIXPLAN-TODO.md), Teil F): kanonische Tag-Tabelle,
Rausch-Filter, Tag-Nachladen für On-Demand-Märkte, Offline-Backfill beim Start. Rausch-Filter, Tag-Nachladen für On-Demand-Märkte, Offline-Backfill beim Start.
* **HF-Trader-Tiering** (Teil D): `IngestMode` mit Hysterese, wöchentliche Biopsie, * **HF-Trader-Tiering** (Teil D): `IngestMode` mit Hysterese, wöchentliche Biopsie,
Aggregations-Buckets. Aggregations-Buckets.
* **Web-UI** (`FIXPLAN-UI-Ranglisten.md`): Showcase-Sektionen, serverseitige Sortierung * **Web-UI** ([`archiv/FIXPLAN-UI-Ranglisten.md`](docs/archiv/FIXPLAN-UI-Ranglisten.md)): Showcase-Sektionen, serverseitige Sortierung
und Filterung. und Filterung.
* **Copytrading-Analytik**: Co-Movement samt Clusterung, Strategie-Drift, Edge-Freshness, * **Copytrading-Analytik**: Co-Movement samt Clusterung, Strategie-Drift, Edge-Freshness,
Copy-Portfolio, Insider-Feed — alle fünf Vorschläge der Roadmap sind umgesetzt und Copy-Portfolio, Insider-Feed — alle fünf Vorschläge der Roadmap sind umgesetzt und
in diesem Zweig enthalten. in diesem Zweig enthalten.
* **Portierung** (`docs/PLAN-Linux-Portierung.md`, Phasen 04): .NET 10, extrahierter * **Portierung** ([`archiv/PLAN-Linux-Portierung.md`](docs/archiv/PLAN-Linux-Portierung.md), Phasen 04): .NET 10, extrahierter
Hosting-Kern, Avalonia-Shell, abgesicherte Steuerendpunkte, plattformfeste Kultur- und Hosting-Kern, Avalonia-Shell, abgesicherte Steuerendpunkte, plattformfeste Kultur- und
Log-Pfade. Der WinForms-Host ist entfernt. Log-Pfade. Der WinForms-Host ist entfernt.
* **Betriebsanbindung**: Lizenz, Watchdog, UpdateService, Fehler-Stream und Bugtracker * **Betriebsanbindung**: Lizenz, Watchdog, UpdateService, Fehler-Stream und Bugtracker
@@ -76,47 +78,17 @@ Alles Folgende ist im Code belegt — die Belegstellen stehen in den jeweiligen
## 3. Was offen ist ## 3. Was offen ist
Nach Dringlichkeit: Die offenen Punkte stehen vollständig und nach Reihenfolge sortiert in
**[`ROADMAP.md`](ROADMAP.md)** — hier nur die drei, die den Blick aufs Ganze bestimmen:
### 3.1 ⚠️ OpenRouter-API-Key liegt im Klartext im Repository 1. **Ein echter OpenRouter-API-Key liegt im Klartext im Repository**
(`src/Predictalytics.Api/appsettings.json`, versioniert seit `7045002`). Er muss beim
`src/Predictalytics.Api/appsettings.json` enthält einen **echten** OpenRouter-Schlüssel, Anbieter zurückgezogen und neu ausgestellt werden — ihn nur zu löschen hilft nicht, die
versioniert seit Commit `7045002` und damit auf dem Gitea-Server. Git-Historie behält ihn. Roadmap 0.1.
2. **Die Portierung ist auf keinem Linux-System je gelaufen.** Der Code ist plattformneutral
**Zu tun:** Den Schlüssel bei OpenRouter zurückziehen und neu ausstellen. Ihn nur aus der gebaut, die Ende-zu-Ende-Prüfung vom 2026-08-08 lief aber unter Windows. Roadmap Stufe 2.
Datei zu entfernen genügt nicht — der Git-Verlauf behält ihn. Anschließend über die 3. **Die Strategie-Klassifikation ist faktisch wirkungslos** — zwei Signale, der Großteil
Umgebungsvariable `OpenRouter__ApiKey` setzen; eine Codeänderung braucht es dafür nicht, der Trader landet auf `Unknown`, und die Logik steht doppelt da. Roadmap 3.1.
`WebApplication.CreateBuilder` liest Umgebungsvariablen bereits mit Vorrang.
Der Schlüssel wurde bewusst **nicht** eigenmächtig entfernt: ohne Rotation bringt das
keinen Sicherheitsgewinn, würde aber die KI-Strategieanalyse stillschweigend abschalten.
### 3.2 Die Portierung ist unter Linux nie gelaufen
Phase 5 (Deployment, systemd/Container, Reverse Proxy, CI) und Phase 6 (Verifikation) des
Portierungsplans sind unangetastet. Der Code ist plattformneutral gebaut, aber **auf keinem
Linux-System je ausgeführt worden**. Die Ende-zu-Ende-Prüfung vom 2026-08-08 lief unter
Windows. Solange das aussteht, ist „läuft unter Linux" eine Annahme, kein Befund.
### 3.3 A4 — Strategie-Klassifikation
Der einzige größere unerledigte Block aus Phase 1. `StrategyType` entsteht weiterhin aus
zwei Signalen — `avgSize > 10000` ergibt `Whale`, `hedgingRate > 30` ergibt `Hedger`, sonst
`Bot`/`Unknown` — weshalb der Großteil der Trader strukturell auf `Unknown` landet. Die
Bausteine für eine bessere Einstufung liegen fertig herum (`StrategyMetricsCalculator`,
`TraderTraitCalculator`, `FingerprintSnapshotService`), sie speisen die Klassifikation nur
nicht.
Die Logik steht außerdem **doppelt** da: `AnalyticsService.cs:418` und
`ScoringService.cs:89`. Beim Anfassen zusammenführen.
### 3.4 Kleinere Reste
* `FIXPLAN-UI-Ranglisten.md`: Pfeilrichtung ▲/▼ in der aktiven Sortierspalte (war als
„Optional" markiert).
* `FIXPLAN-TODO.md` F5/F6: gezielter Nachlade-Schritt für fehlende Event-Tags, zwei Tests.
* `UMSETZUNGSPLAN.md` C3 und D1/D2: DB-Arbeiten auf SQL-Ebene und die Entscheidung über
einen Datenbank-Neustart — beides liegt beim Nutzer.
--- ---
@@ -142,16 +114,17 @@ Avalonia-Shell noch die Deploymentcenter-Anbindung.
## 5. Bewusst stehengelassen ## 5. Bewusst stehengelassen
Beim Aufräumen geprüft und **nicht** entfernt, weil Löschen hier Funktionsverlust wäre und Beim Aufräumen geprüft und **nicht** entfernt, weil Löschen hier Funktionsverlust wäre und
nicht Entrümpelung: nicht Entrümpelung. Dieselbe Liste steht im Anhang der [`ROADMAP.md`](ROADMAP.md), damit sie
nicht versehentlich als Aufgabe wieder auftaucht:
| Was | Warum es bleibt | | Was | Warum es bleibt |
|---|---| |---|---|
| `Providers/Azuro/AzuroProvider.cs` | Platzhalter mit `IsImplemented => false`. Die Worker überspringen ihn sauber; er kostet nichts und markiert den Ausbaupfad. | | `Providers/Azuro/AzuroProvider.cs` | Platzhalter mit `IsImplemented => false`. Die Worker überspringen ihn sauber; er kostet nichts und markiert den Ausbaupfad. |
| `Providers/Limitless/` (3 Dateien) | **Voll implementierter** zweiter Marktplatz mit `IsImplemented => true`. Wird produktiv nur nicht bespielt. | | `Providers/Limitless/` (3 Dateien) | **Voll implementierter** zweiter Marktplatz mit `IsImplemented => true`. Wird produktiv nur nicht bespielt. |
| `Services/CopytradingBacktestHarness.cs` (123 Z.) | Fertig implementierter Latenz-Sweep, per DI registriert, aber **von niemandem aufgerufen**. Entweder anschließen oder bewusst verwerfen — beides eine fachliche Entscheidung. | | `Services/CopytradingBacktestHarness.cs` (123 Z.) | Fertig implementierter Latenz-Sweep, per DI registriert, aber **von niemandem aufgerufen**. Entscheidung steht aus, siehe Roadmap 3.2. |
| `wwwroot/landing.html`, `wwwroot/docs.html` | Marketing-Seiten mit Preis-Abschnitt, vom Dashboard aus nicht verlinkt. Passen zur später angedachten Monetarisierung. | | `wwwroot/landing.html`, `wwwroot/docs.html` | Marketing-Seiten mit Preis-Abschnitt, vom Dashboard aus nicht verlinkt. Passen zur später angedachten Monetarisierung. |
| 8 Nullable-Warnungen | `TradeRepository.cs:94-102`, `PolymarketProvider.cs:357`, `TraderAnalyticsWorker.cs:152`. Bestehen seit Längerem; sie zu beheben ist Logikarbeit, kein Aufräumen. | | 8 Nullable-Warnungen | `TradeRepository.cs:94-102`, `PolymarketProvider.cs:357`, `TraderAnalyticsWorker.cs:152`. Bestehen seit Längerem; sie zu beheben ist Logikarbeit, kein Aufräumen. |
| 65 Migrationsdateien | Die Schemahistorie. Zusammenfassen ginge, ist aber riskant und sollte eine bewusste Entscheidung sein. | | 65 Migrationsdateien | Die Schemahistorie. Zusammenfassen ginge, ist aber riskant — siehe Roadmap 4.4. |
Ein Nebenbefund ohne Handlungszwang: der Kategorie-Backfill beim Start Ein Nebenbefund ohne Handlungszwang: der Kategorie-Backfill beim Start
(`PredictalyticsHost.cs:116`) lädt **alle** Märkte samt Event in den Speicher. Bei (`PredictalyticsHost.cs:116`) lädt **alle** Märkte samt Event in den Speicher. Bei
@@ -1,5 +1,27 @@
# Plan: Drei-Schichten-Architektur (Core / Lokal / Public) # Plan: Drei-Schichten-Architektur (Core / Lokal / Public)
> **Archiviert am 2026-08-23** — offene Punkte siehe [`ROADMAP.md`](../../ROADMAP.md),
> Stufe 6. Dieses Dokument wird nicht mehr gepflegt.
>
> **Phase 0 bis 2 sind erledigt**, überwiegend als Nebenprodukt der Linux-Portierung, und
> hier nachträglich abgehakt:
> * Read/Control-Split (`ApiConfiguration.MapPredictalyticsReadEndpoints()` bzw.
> `MapPredictalyticsControlEndpoints()`), `/api/dev/*` und die Job-Trigger liegen auf der
> Control-Seite.
> * `GET /api/capabilities` existiert und meldet den tatsächlichen Zustand; die WebUI
> koppelt ihre Admin-Aktionen daran (`app.js:880,1132`).
> * `API_BASE` ist im SPA konfigurierbar (`app.js:2`), Trait-Chips sind da.
> * CORS läuft über eine Origin-Whitelist, die Bind-Adresse ist explizit
> (`PredictalyticsHost.cs:177,198-201`) — kein `0.0.0.0`.
>
> **Nicht abgehakt** ist der Deep-Dive-Audit auf versteckte Writes in Read-Endpunkten
> (Phase 0, dritter Punkt): die Trennung steht, ob jeder Read-Endpunkt einzeln daraufhin
> geprüft wurde, lässt sich im Nachhinein nicht belegen. Vor einem öffentlichen Host
> nachholen.
>
> **Phase 3 und 4 sind offen** und bilden Roadmap-Stufe 6 — dort als Konzept markiert,
> weil über eine Monetarisierung nicht entschieden ist.
> Stand: 2026-07-12 · Status: **Architektur bestätigt** (Nutzer-Entscheidung), Implementierung > Stand: 2026-07-12 · Status: **Architektur bestätigt** (Nutzer-Entscheidung), Implementierung
> schrittweise. Kein Code in diesem Schritt. > schrittweise. Kein Code in diesem Schritt.
> Kontext: Neues WebUI-Design (mit Claude Design vorbereitet) wird nach der Schicht-Trennung > Kontext: Neues WebUI-Design (mit Claude Design vorbereitet) wird nach der Schicht-Trennung
@@ -88,24 +110,24 @@ und von beiden Hosts wiederverwendet — kein Duplizieren:
## 3. Implementierungsplan (schrittweise) ## 3. Implementierungsplan (schrittweise)
### Phase 0 — Endpunkte klassifizieren & Read/Control trennen (Fundament, klein) ### Phase 0 — Endpunkte klassifizieren & Read/Control trennen (Fundament, klein)
- [ ] Jeden Endpunkt in `docs/API.md` als **Read** (public-tauglich) oder **Control** (nur lokal) - [x] Jeden Endpunkt in `docs/API.md` als **Read** (public-tauglich) oder **Control** (nur lokal)
markieren. Kandidaten Control: alle `POST/PUT/DELETE`, `/api/dev/*`, Job-Trigger. markieren. Kandidaten Control: alle `POST/PUT/DELETE`, `/api/dev/*`, Job-Trigger.
- [ ] Auf **versteckte Writes/Provider-Calls** in Read-Endpunkten prüfen (Deep-Dive!) und - [ ] Auf **versteckte Writes/Provider-Calls** in Read-Endpunkten prüfen (Deep-Dive!) und
bereinigen oder als Control einstufen. bereinigen oder als Control einstufen.
- [ ] `MapPredictalyticsEndpoints()` in `MapReadEndpoints()` + `MapControlEndpoints()` splitten - [x] `MapPredictalyticsEndpoints()` in `MapReadEndpoints()` + `MapControlEndpoints()` splitten
(rein struktureller Refactor, Verhalten unverändert; bestehende Tests bleiben grün). (rein struktureller Refactor, Verhalten unverändert; bestehende Tests bleiben grün).
- [ ] `GET /api/capabilities` einführen. - [x] `GET /api/capabilities` einführen.
### Phase 1 — WebUI als sauberes, gemeinsames SPA (parallel zum neuen Design) ### Phase 1 — WebUI als sauberes, gemeinsames SPA (parallel zum neuen Design)
- [ ] Neues Design als **ein statisches Artefakt** bauen, reiner API-Client, `API_BASE` - [x] Neues Design als **ein statisches Artefakt** bauen, reiner API-Client, `API_BASE`
konfigurierbar (heute `''` = gleiche Origin bleibt lokal gültig). konfigurierbar (heute `''` = gleiche Origin bleibt lokal gültig).
- [ ] Admin-Aktionen an `capabilities.canControl` koppeln. - [x] Admin-Aktionen an `capabilities.canControl` koppeln.
- [ ] Trait-Chips/-Filter im Design vorsehen — **erscheinen erst, wenn Backend-D2 steht** - [x] Trait-Chips/-Filter im Design vorsehen — **erscheinen erst, wenn Backend-D2 steht**
(kein UI-Bug, das Backend liefert Traits noch nicht). (kein UI-Bug, das Backend liefert Traits noch nicht).
### Phase 2 — Lokale Grenze härten (klein, jetzt schon sinnvoll) ### Phase 2 — Lokale Grenze härten (klein, jetzt schon sinnvoll)
- [ ] CORS von `AllowAnyOrigin` auf konfigurierte Origin-Whitelist umstellen. - [x] CORS von `AllowAnyOrigin` auf konfigurierte Origin-Whitelist umstellen.
- [ ] Bind-Adresse explizit (localhost/LAN), nie `0.0.0.0` ohne Firewall; Konfig-Kommentar - [x] Bind-Adresse explizit (localhost/LAN), nie `0.0.0.0` ohne Firewall; Konfig-Kommentar
„NIEMALS ins Internet — das ist die interne Schicht". „NIEMALS ins Internet — das ist die interne Schicht".
### Phase 3 — DB für Public vorbereiten (mittel, kann früh passieren) ### Phase 3 — DB für Public vorbereiten (mittel, kann früh passieren)
@@ -1,5 +1,26 @@
# Plan: Daten-Ingest skalieren (Rate-Limits, Egress-Kanäle, Blockchain) # Plan: Daten-Ingest skalieren (Rate-Limits, Egress-Kanäle, Blockchain)
> **Archiviert am 2026-08-23** — offene Punkte siehe [`ROADMAP.md`](../../ROADMAP.md),
> Stufe 5. Dieses Dokument wird nicht mehr gepflegt.
>
> **Erledigt und hier nachträglich abgehakt:**
> * **1c Ingest-Tiering** — `IngestMode` mit `SnapshotOnly`/`Aggregated`, siehe
> [`FIXPLAN-TODO.md`](FIXPLAN-TODO.md) Teil D.
> * **1d Redundanz** — `IMemoryCache` im `PolymarketApiClient`.
> * **2a/2b Egress-Kanäle** — `Infrastructure/Services/EgressPoolService.cs` und
> `EgressPoolHandler.cs`: Round-Robin über die aktiven Kanäle, Umschalten rein per
> Konfiguration, Cooldown nach drei Fehlschlägen in Folge (`:152`), sodass ein 429 nur
> den betroffenen Kanal trifft. Der Limiter-Schlüssel enthält den Kanal
> (`RateLimiterService.cs:36`). Tests: `EgressPoolTests.cs`.
>
> **Teilweise:** Health-Statistik je Kanal (Erfolgsquote, 429-Rate, Latenz) fehlt — es gibt
> nur Fehlerzähler und Cooldown. Tote Kanäle werden also pausiert, aber nicht ausgewertet.
>
> **Offen:** 1a (Blockchain/Subgraph als Bulk-Quelle) und 1b (Markt-Stammdaten-Cache) sind
> Roadmap 5.1 und 5.2. **Abschnitt 3a (Header-Rotation) ist bewusst verworfen** — siehe
> Roadmap 5.3: Verschleierung gegenüber Polymarket riskiert genau den Zugang, auf dem das
> Projekt aufsetzt.
> Stand: 2026-07-12 · Status: **Richtung bestätigt** (Nutzer: beide Egress-Wege umschaltbar > Stand: 2026-07-12 · Status: **Richtung bestätigt** (Nutzer: beide Egress-Wege umschaltbar
> umsetzen, sofern Aufwand vertretbar). Kein Code in diesem Schritt. > umsetzen, sofern Aufwand vertretbar). Kein Code in diesem Schritt.
> Problem: Polymarket-Rate-Limits bremsen den Datenimport teils extrem aus. > Problem: Polymarket-Rate-Limits bremsen den Datenimport teils extrem aus.
@@ -32,11 +53,11 @@ REST-Verbraucher) ist `/activity` die falsche Quelle.
nur Volume/Liquidity/Auflösung periodisch aktualisieren. Geschlossene Märkte nie voll re-syncen. nur Volume/Liquidity/Auflösung periodisch aktualisieren. Geschlossene Märkte nie voll re-syncen.
### 1c. Ingest-Tiering (FIXPLAN D3) ### 1c. Ingest-Tiering (FIXPLAN D3)
- [ ] Ultra-HF-Trader im `SnapshotOnly`-Modus erzeugen null Trade-Calls (PnL aus `/positions` + - [x] Ultra-HF-Trader im `SnapshotOnly`-Modus erzeugen null Trade-Calls (PnL aus `/positions` +
Leaderboard, wöchentliche Biopsie). Entfernt genau die Wallets, die das Budget auffressen. Leaderboard, wöchentliche Biopsie). Entfernt genau die Wallets, die das Budget auffressen.
### 1d. Redundanz vermeiden ### 1d. Redundanz vermeiden
- [ ] Worker-übergreifender Kurzzeit-Cache „gerade geholt", damit nicht mehrere Worker denselben - [x] Worker-übergreifender Kurzzeit-Cache „gerade geholt", damit nicht mehrere Worker denselben
Markt/Trader kurz hintereinander abrufen. Markt/Trader kurz hintereinander abrufen.
--- ---
@@ -59,18 +80,18 @@ Ein Kanal ist genau eine Ausgangsroute, per Config als einer von zwei Typen defi
] ]
} }
``` ```
- [ ] Pro Kanal **ein** `SocketsHttpHandler`: - [x] Pro Kanal **ein** `SocketsHttpHandler`:
- `SourceIp``ConnectCallback`, Socket vor Connect an die lokale IP binden - `SourceIp``ConnectCallback`, Socket vor Connect an die lokale IP binden
(`socket.Bind(new IPEndPoint(ip, 0))`). (`socket.Bind(new IPEndPoint(ip, 0))`).
- `Proxy``handler.Proxy = new WebProxy(url); handler.UseProxy = true;`. - `Proxy``handler.Proxy = new WebProxy(url); handler.UseProxy = true;`.
- [ ] `IEgressPool` verteilt Requests round-robin/least-loaded über die aktiven Kanäle. - [x] `IEgressPool` verteilt Requests round-robin/least-loaded über die aktiven Kanäle.
Leere/❑ Kanalliste = heutiges Verhalten (ein Default-Ausgang). Leere/❑ Kanalliste = heutiges Verhalten (ein Default-Ausgang).
- [ ] Umschalten „nur eigene IPs" ↔ „nur Proxys" ↔ „Mix" = Config ändern, kein Deploy-Umbau. - [x] Umschalten „nur eigene IPs" ↔ „nur Proxys" ↔ „Mix" = Config ändern, kein Deploy-Umbau.
### 2b. Rate-Limiter **pro Kanal** (Generalisierung des globalen Limiters) ### 2b. Rate-Limiter **pro Kanal** (Generalisierung des globalen Limiters)
- [ ] Limiter-Schlüssel wird `{platform}-{endpointGroup}-{channelId}`. Jeder Kanal hält sein - [x] Limiter-Schlüssel wird `{platform}-{endpointGroup}-{channelId}`. Jeder Kanal hält sein
eigenes Budget → N Kanäle ≈ N× Durchsatz, jeder Kanal bleibt unter dem Per-Route-Limit. eigenes Budget → N Kanäle ≈ N× Durchsatz, jeder Kanal bleibt unter dem Per-Route-Limit.
- [ ] 429 sperrt **nur den betroffenen Kanal** kurz, nicht alle. - [x] 429 sperrt **nur den betroffenen Kanal** kurz, nicht alle.
### 2c. Betrieb ### 2c. Betrieb
- [ ] Bei eigenen IPs prüfen: sind es echte getrennte Egress-IPs (multi-homed), nicht NAT hinter einer. - [ ] Bei eigenen IPs prüfen: sind es echte getrennte Egress-IPs (multi-homed), nicht NAT hinter einer.
@@ -123,10 +144,10 @@ Auf Wunsch integriert, bewusst opt-in:
(welcher Subgraph deckt Fills sauber ab?), dann als `IHistoricalTradeSource`. (welcher Subgraph deckt Fills sauber ab?), dann als `IHistoricalTradeSource`.
## 5. Tests / Abnahme ## 5. Tests / Abnahme
- [ ] Per-Kanal-Limiter: unabhängige Budgets (kein globales Blocken); 429 sperrt nur einen Kanal. - [x] Per-Kanal-Limiter: unabhängige Budgets (kein globales Blocken); 429 sperrt nur einen Kanal.
- [ ] Egress-Binding: Smoke gegen einen Dienst, der die Quell-IP zurückgibt → Round-Robin nutzt - [x] Egress-Binding: Smoke gegen einen Dienst, der die Quell-IP zurückgibt → Round-Robin nutzt
wirklich verschiedene IPs; Proxy-Kanal geht über den Proxy. wirklich verschiedene IPs; Proxy-Kanal geht über den Proxy.
- [ ] Kanal-Health: toter Proxy wird automatisch pausiert, Pool weicht aus. - [x] Kanal-Health: toter Proxy wird automatisch pausiert, Pool weicht aus.
- [ ] Blockchain-Quelle: Stichproben-Abgleich Bulk-Historie ↔ REST-`/activity` eines Wallets, - [ ] Blockchain-Quelle: Stichproben-Abgleich Bulk-Historie ↔ REST-`/activity` eines Wallets,
bevor sie produktiv wird. bevor sie produktiv wird.
- [ ] **Header-Rotation:** bei `Enabled=false` wird genau ein konsistenter Standard-Satz gesendet - [ ] **Header-Rotation:** bei `Enabled=false` wird genau ein konsistenter Standard-Satz gesendet
+25
View File
@@ -0,0 +1,25 @@
# Archiv — abgelöste Plandokumente
Diese Dokumente wurden am **2026-08-23** hierher verschoben. Sie werden **nicht mehr
gepflegt**. Was von ihnen noch offen war, steht gebündelt in [`ROADMAP.md`](../../ROADMAP.md);
der Ist-Stand des Projekts in [`STATUS.md`](../../STATUS.md).
**Wozu sie trotzdem da sind:** Die Roadmap nennt jeden offenen Punkt knapp. Die Herleitung —
warum etwas so entschieden wurde, welche Messungen dahinterstehen, welche Alternativen
verworfen wurden — steht hier. Wer einen Roadmap-Punkt umsetzt, findet hier den Kontext.
**Vorsicht bei der Lektüre:** Der Text unterhalb des jeweiligen Statusblocks beschreibt den
Stand seiner Entstehungszeit. Test-Baselines, Dateipfade und „so ist es heute"-Aussagen sind
teils überholt. Immer gegen den Code prüfen, nie direkt übernehmen.
| Dokument | Stand | Was drinsteht |
|---|---|---|
| [`UMSETZUNGSPLAN.md`](UMSETZUNGSPLAN.md) | 2026-07-01, abgehakt 2026-08-23 | Phase 1 (Kernanalytik: PnL-Engine, Win-Rate, Deep-Dive, Copytrading-Score) und Phase 2 (Migrationen, Scoring-Entkopplung, Bugliste, Tests) sowie das Speicherplatz-Konzept. Bis auf A4 und B2 umgesetzt. |
| [`FIXPLAN-DONE.md`](FIXPLAN-DONE.md) | 2026-07-09 | Vorgängerfassung des Fix-Plans, vollständig abgearbeitet. Reine Historie. |
| [`FIXPLAN-TODO.md`](FIXPLAN-TODO.md) | 2026-07-09/11/13 | Teil D (Merkmals-Tags, HF-Trader-Tiering mit `IngestMode`) und Teil F (Kategorie-Erkennung: kanonische Tags, Rausch-Filter, Backfill). Umgesetzt bis auf F5 und zwei Tests. |
| [`FIXPLAN-G-Speicher.md`](FIXPLAN-G-Speicher.md) | 2026-07-17 | Speicher-Governor, Retention für aggregierte Trader, `UsdcSize`/`OutcomeIndex`, Per-Kategorie-Edge. Vollständig umgesetzt; der Anhang mit den einmaligen SQL-Optimierungen ist offen. |
| [`FIXPLAN-UI-Ranglisten.md`](FIXPLAN-UI-Ranglisten.md) | 2026-08-03 | Web-UI: Showcase-Sektionen, serverseitige Sortierung und Filterung. Vollständig umgesetzt bis auf die Sortierpfeile. |
| [`PLAN-Linux-Portierung.md`](PLAN-Linux-Portierung.md) | 2026-08-06 bis -08 | Der Portierungsplan mit allen Entscheidungen und Abnahmevermerken. **Die ausführlichste Quelle für Roadmap-Stufe 2** — Abschnitt 7 (Deployment) und 8 (Verifikationsmatrix) sind dort detaillierter als in der Roadmap. |
| [`ANALYSE-Linux-Portierung.md`](ANALYSE-Linux-Portierung.md) | 2026-08-06 | Die Bestandsaufnahme, die dem Portierungsplan vorausging: was am WinForms-Host hing, welche Pakete windows-spezifisch waren. Historisch. |
| [`PLAN-Architektur-WebUI-Backend.md`](PLAN-Architektur-WebUI-Backend.md) | 2026-07 | Drei-Schichten-Konzept Core/Lokal/Public als Vorbereitung einer Monetarisierung. Phase 02 sind im Zuge der Portierung erledigt; Phase 34 sind Roadmap-Stufe 6. |
| [`PLAN-DatenIngest-Skalierung.md`](PLAN-DatenIngest-Skalierung.md) | 2026-07 | Rate-Limits, Egress-Kanäle, Blockchain als Bulk-Quelle. Egress-Kanäle und Ingest-Tiering sind umgesetzt; der Rest ist Roadmap-Stufe 5. |
@@ -138,7 +138,7 @@ Beim Review ist aufgefallen, dass `TraderAnalyticsWorker.CalculatePnL` **jeden T
- [x] Eigenes Intervall für volle Neuberechnung/Ranking (z.B. alle 15 Min) getrennt vom reinen Trade-Polling (60s) - [x] Eigenes Intervall für volle Neuberechnung/Ranking (z.B. alle 15 Min) getrennt vom reinen Trade-Polling (60s)
### B6. Weitere gefundene Bugs/Performance-Probleme (Review-Pass 2026-07-01) ### B6. Weitere gefundene Bugs/Performance-Probleme (Review-Pass 2026-07-01)
- [x] **`MarketSyncWorker` re-synct alle 30 Minuten ALLE Märkte, inkl. `includeClosed=true`, von Offset 0** ([MarketSyncWorker.cs](src/Predictalytics.Worker/Services/MarketSyncWorker.cs)) — holt damit bei jedem Zyklus jeden jemals geschlossenen Polymarket-Markt erneut komplett durch. Wächst unbegrenzt mit der Zeit, echtes Risiko für Rate-Limiting/Sperrung. Sollte auf: aktive Märkte häufig, geschlossene Märkte selten/inkrementell (z.B. nur kürzlich geschlossene, nicht der komplette Bestand) umgestellt werden - [x] **`MarketSyncWorker` re-synct alle 30 Minuten ALLE Märkte, inkl. `includeClosed=true`, von Offset 0** ([MarketSyncWorker.cs](../../src/Predictalytics.Worker/Services/MarketSyncWorker.cs)) — holt damit bei jedem Zyklus jeden jemals geschlossenen Polymarket-Markt erneut komplett durch. Wächst unbegrenzt mit der Zeit, echtes Risiko für Rate-Limiting/Sperrung. Sollte auf: aktive Märkte häufig, geschlossene Märkte selten/inkrementell (z.B. nur kürzlich geschlossene, nicht der komplette Bestand) umgestellt werden
- [x] **Watchlisted Trader nicht von Auto-Löschung ausgeschlossen** (`TraderRepository.GetTradersForCleanupAsync` / `TraderCleanupWorker`) — da `Trades`/`TraderScore`/`WatchlistEntries` per Cascade am Trader hängen, könnte ein manuell beobachteter Trader nach 1 Jahr Inaktivität (oder bei kurzzeitigem API-Fehler) unbemerkt komplett gelöscht werden. Watchlist-Einträge sollten von der Cleanup-Query ausgenommen werden - [x] **Watchlisted Trader nicht von Auto-Löschung ausgeschlossen** (`TraderRepository.GetTradersForCleanupAsync` / `TraderCleanupWorker`) — da `Trades`/`TraderScore`/`WatchlistEntries` per Cascade am Trader hängen, könnte ein manuell beobachteter Trader nach 1 Jahr Inaktivität (oder bei kurzzeitigem API-Fehler) unbemerkt komplett gelöscht werden. Watchlist-Einträge sollten von der Cleanup-Query ausgenommen werden
- [x] **`TradeRepository.GetKnownPlatformTradeIdsAsync` lädt die komplette Trade-ID-Historie eines Traders ins RAM**, nur um eine kleine neu geholte Charge (~100-1000 Trades) zu deduplizieren — aufgerufen alle 60s (`PollingWorker`) bzw. alle 12h (`TradeHistoryWorker`) pro Trader. Wird mit wachsender Trade-Zahl immer teurer. Fix: nur `WHERE PlatformTradeId IN (<geholte Batch-IDs>)` abfragen statt der gesamten Historie - [x] **`TradeRepository.GetKnownPlatformTradeIdsAsync` lädt die komplette Trade-ID-Historie eines Traders ins RAM**, nur um eine kleine neu geholte Charge (~100-1000 Trades) zu deduplizieren — aufgerufen alle 60s (`PollingWorker`) bzw. alle 12h (`TradeHistoryWorker`) pro Trader. Wird mit wachsender Trade-Zahl immer teurer. Fix: nur `WHERE PlatformTradeId IN (<geholte Batch-IDs>)` abfragen statt der gesamten Historie
- [x] **Race Condition in `MarketRepository.AddOrUpdateAsync`** (im Gegensatz zu `AddOrUpdateRangeAsync` ohne Locking) — `TradeHistoryWorker` verarbeitet bis zu 5 Trader parallel (`Parallel.ForEachAsync`); referenzieren zwei gleichzeitig denselben noch unbekannten Markt, prüfen beide unabhängig "existiert nicht" und einer crasht beim `Add` mit Unique-Constraint-Verletzung (wird geloggt, Trader-Sync für den Zyklus bricht ab, nächster Zyklus heilt es meist). Fix: gleiches Locking-Muster wie `AddOrUpdateRangeAsync` verwenden, oder Insert-Konflikt sauber abfangen/retry - [x] **Race Condition in `MarketRepository.AddOrUpdateAsync`** (im Gegensatz zu `AddOrUpdateRangeAsync` ohne Locking) — `TradeHistoryWorker` verarbeitet bis zu 5 Trader parallel (`Parallel.ForEachAsync`); referenzieren zwei gleichzeitig denselben noch unbekannten Markt, prüfen beide unabhängig "existiert nicht" und einer crasht beim `Add` mit Unique-Constraint-Verletzung (wird geloggt, Trader-Sync für den Zyklus bricht ab, nächster Zyklus heilt es meist). Fix: gleiches Locking-Muster wie `AddOrUpdateRangeAsync` verwenden, oder Insert-Konflikt sauber abfangen/retry
@@ -121,7 +121,7 @@ public static class DependencyInjection
/// <summary> /// <summary>
/// Applies pending EF Core migrations and seeds default platform rows. /// Applies pending EF Core migrations and seeds default platform rows.
/// Requires the target database to already be "stamped" with the InitialBaseline /// Requires the target database to already be "stamped" with the InitialBaseline
/// migration in __EFMigrationsHistory (see UMSETZUNGSPLAN.md, section B1) if it was /// migration in __EFMigrationsHistory (see docs/archiv/UMSETZUNGSPLAN.md, B1) if it was
/// previously created via the old EnsureCreated + manual ALTER approach. /// previously created via the old EnsureCreated + manual ALTER approach.
/// </summary> /// </summary>
public static async Task EnsureDatabaseAsync(IServiceProvider services, bool dbDebug = false) public static async Task EnsureDatabaseAsync(IServiceProvider services, bool dbDebug = false)