11 KiB
Plan: Drei-Schichten-Architektur (Core / Lokal / Public)
Stand: 2026-07-12 · Status: Architektur bestätigt (Nutzer-Entscheidung), Implementierung schrittweise. Kein Code in diesem Schritt. Kontext: Neues WebUI-Design (mit Claude Design vorbereitet) wird nach der Schicht-Trennung schrittweise implementiert. Public-Release ist noch fern, aber alles wird dafür vorbereitet.
0. Bestätigte Architektur
Drei Schichten mit genau einer Integrationsschnittstelle zwischen intern und öffentlich: der Datenbank.
┌─────────────────────────── LOKAL (eigener Rechner/LAN) ───────────────────────────┐
│ │
│ Schicht 1: CORE Schicht 2: LOKALE API + WebUI │
│ ───────────────── ─────────────────────────── │
│ Crawler, Worker, PnL-Engine, volle API (Read + Control), │
│ Analyse, Ingest keine Auth (localhost), │
│ │ schreibt serviert WebUI-SPA, │
│ ▼ zum Testen von Analysen & Design │
│ ┌──────────────────┐ liest/schreibt ▲ │
│ │ Analyse-DB │◄────────────────────────┘ │
│ └────────┬─────────┘ │
│ │ (nur SELECT-Grant) │
└────────────┼──────────────────────────────────────────────────────────────────────┘
│ ← EINZIGE Verbindung nach außen: read-only DB-Zugriff
┌────────────┼──────────────────────── EXTERNER WEBSERVER ───────────────────────────┐
│ ▼ │
│ Schicht 3: PUBLIC API + WebUI │
│ ──────────────────────────── │
│ nur Read-Endpunkte (identisch zur lokalen Read-Seite), │
│ Auth + Accounts, öffentliches Rate-Limiting, TLS, │
│ serviert dasselbe WebUI-SPA │
│ │ read-only │ read/write │
│ ▼ ▼ │
│ [Analyse-DB, RO] [User-DB (Accounts), separat] │
└────────────────────────────────────────────────────────────────────────────────────┘
Kernprinzipien (aus der Nutzer-Entscheidung):
- Core ist rein lokal und die einzige Instanz, die in die Analyse-DB schreibt.
- Public spricht ausschließlich mit der Datenbank — nie mit dem Core-Prozess, nie mit der lokalen API. Public bekommt einen read-only DB-User auf die Analyse-DB und eine separate User-DB für Accounts.
- Lokale und Public WebUI sind optisch UND funktional gleich (auf der Analyse-/Ansichtsseite), damit neue Analysen und Designs lokal getestet werden und 1:1 öffentlich aussehen.
1. Wie „identisch" technisch erreicht wird
Damit beide WebUIs garantiert gleich sind, wird die Read-/Analyse-Seite genau einmal gebaut und von beiden Hosts wiederverwendet — kein Duplizieren:
- Geteilte Read-API-Library.
Predictalytics.Apiist bereits eine Library. Die Endpoint-Registrierung wird in zwei Gruppen gespalten:MapReadEndpoints()— die Analyse-/Ansichts-Endpunkte (Trader-Liste/-Detail/-Profil/ -Positionen, Markets, Dashboard, Search, Watchlist-Ansicht, Traits). Wird von beiden Hosts registriert.MapControlEndpoints()— schreibende/steuernde Endpunkte (Jobs-Trigger,/api/dev, Trader-Anlage, Watchlist-Mutation, Priority, AI-Analyse-Trigger). Wird nur lokal registriert.
- Ein einziges WebUI-SPA-Artefakt. Dasselbe Build wird von der lokalen und der öffentlichen Schicht ausgeliefert. Es ist reiner API-Client (kein Server-Code, keine DB-Kenntnis).
- Capability-gesteuerte Admin-Bedienelemente. Da die Control-Endpunkte öffentlich fehlen,
fragt das SPA beim Start eine
GET /api/capabilitiesab ({ canControl: bool, authRequired: bool }) und blendet Admin-Aktionen (Sync/Analyze/Deep-Resync/Trader-Anlegen) nur ein, wenn vorhanden. → Analyse-Ansichten sind überall identisch; nur die lokalen Steuer-Buttons fehlen öffentlich.
Wichtiger Audit-Punkt vor dem Teilen: Manche „Read"-Endpunkte haben heute versteckte Nebenwirkungen. Beispiel:
GET /api/traders/{id}/deep-diveholt Preis-Historie vom Provider und speichert Snapshots — also ein Schreibzugriff und ein externer API-Call. Solche Endpunkte sind nicht public-tauglich (read-only DB verbietet den Write, und Public darf Polymarket nicht anrufen). Vor dem Aufnehmen inMapReadEndpoints()jeden Endpunkt auf versteckte Writes/Provider-Calls prüfen; die Public-Read-Seite muss rein aus persistierten Daten bedienbar sein (das/profile-Design aus FIXPLAN E ist genau deshalb „persisted-only").
2. Was heute wo läuft (Ist → Ziel)
- Heute: Core + Lokale API + WebUI sind ein Prozess (WinFormsHost/EmbeddedWebServer:
Worker + volle API +
wwwroot-SPA, localhost, keine Auth, CORS*). Public existiert nicht. - Ziel Lokal: bleibt bequem ein Prozess (Core-Worker + Lokale API + WebUI zusammen ist zum Testen praktisch). Wichtig ist nur die Code-Schichtung (Read-Library getrennt von Control/Core), damit Public die Read-Library ohne Core/Worker/Control referenzieren kann.
- Ziel Public: eigener schlanker Host (neues Projekt
Predictalytics.PublicApi), derMapReadEndpoints()+ Auth registriert, das SPA ausliefert, und nur die read-only Analyse-DB + die User-DB kennt.
3. Implementierungsplan (schrittweise)
Phase 0 — Endpunkte klassifizieren & Read/Control trennen (Fundament, klein)
- Jeden Endpunkt in
docs/API.mdals Read (public-tauglich) oder Control (nur lokal) markieren. Kandidaten Control: allePOST/PUT/DELETE,/api/dev/*, Job-Trigger. - Auf versteckte Writes/Provider-Calls in Read-Endpunkten prüfen (Deep-Dive!) und bereinigen oder als Control einstufen.
MapPredictalyticsEndpoints()inMapReadEndpoints()+MapControlEndpoints()splitten (rein struktureller Refactor, Verhalten unverändert; bestehende Tests bleiben grün).GET /api/capabilitieseinführen.
Phase 1 — WebUI als sauberes, gemeinsames SPA (parallel zum neuen Design)
- Neues Design als ein statisches Artefakt bauen, reiner API-Client,
API_BASEkonfigurierbar (heute''= gleiche Origin bleibt lokal gültig). - Admin-Aktionen an
capabilities.canControlkoppeln. - Trait-Chips/-Filter im Design vorsehen — erscheinen erst, wenn Backend-D2 steht (kein UI-Bug, das Backend liefert Traits noch nicht).
Phase 2 — Lokale Grenze härten (klein, jetzt schon sinnvoll)
- CORS von
AllowAnyOriginauf konfigurierte Origin-Whitelist umstellen. - Bind-Adresse explizit (localhost/LAN), nie
0.0.0.0ohne Firewall; Konfig-Kommentar „NIEMALS ins Internet — das ist die interne Schicht".
Phase 3 — DB für Public vorbereiten (mittel, kann früh passieren)
- Read-only DB-User auf der Analyse-DB anlegen (nur
SELECT). Der Nutzer führt das SQL selbst aus (Grant-Statements liefern wir). AppDbContextpublic-seitig read-only konfigurieren (read-only Connection; keine Migrations, kein SaveChanges). Sicherstellen, dass die Read-Endpunkte ohne Writes auskommen.- Schema-Kopplung dokumentieren: Weil Public direkt auf der Analyse-DB liest, ist das DB-Schema jetzt eine Vertragsfläche. Schema-Änderungen im Core müssen die Public-Read- Views berücksichtigen (Views/stabile Spalten als Puffer erwägen, damit interne Refactorings die öffentliche Sicht nicht brechen).
Phase 4 — Public-Host bauen (groß, wenn Release näher rückt)
- Neues Projekt
Predictalytics.PublicApi(eigener Host, TLS, öffentliche Bind-Adresse). MapReadEndpoints()+ Auth/Accounts (separate User-DB; Passwörter/Sessions nach Stand der Technik — Secret-Handling lebt nur hier, nie im Core).- Öffentliches Rate-Limiting & Quotas pro Account (getrennt vom internen Polymarket-Limiter).
- Mandanten-Sicht: Kunde sieht seine Watchlist/kopierten Master, nicht das gesamte Universum.
- Dasselbe WebUI-SPA ausliefern.
4. Explizite Nicht-Ziele / Fallen
- ❌ Public bekommt keinen Zugriff auf Core-Prozess, lokale API oder Control-Endpunkte.
- ❌ Public bekommt keinen Schreibzugriff auf die Analyse-DB (nur
SELECT). - ❌ Kein Nachrüsten von Kunden-Auth auf die lokale Vollschicht — Auth lebt nur im Public-Host.
- ❌ Read-Endpunkte machen keine Provider-Calls und keine Writes (sonst public-untauglich).
- ❌ WebUI kennt die DB nicht — immer nur über die API.
5. Reihenfolge / Aufwand
- Phase 0 (klein): Read/Control-Split + Capabilities + Deep-Dive-Audit. Jetzt — es ist die Voraussetzung dafür, dass das neue Design von Anfang an sauber sitzt.
- Phase 1+2 (klein, parallel): neues SPA als gemeinsames Artefakt, lokale Grenze härten.
- Phase 3 (mittel): read-only DB-User + Schema-als-Vertrag dokumentieren.
- Phase 4 (groß, später): Public-Host mit Auth/User-DB.
Phase 0–2 begleiten das neue Design sofort. Phase 3 kann jederzeit vorgezogen werden (billig). Phase 4 erst zum Release — aber durch 0–3 ist dann nichts mehr umzubauen, nur zu ergänzen.