# 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:

1. **Geteilte Read-API-Library.** `Predictalytics.Api` ist 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.
2. **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).
3. **Capability-gesteuerte Admin-Bedienelemente.** Da die Control-Endpunkte öffentlich fehlen,
   fragt das SPA beim Start eine `GET /api/capabilities` ab (`{ 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-dive` **holt 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 in `MapReadEndpoints()` 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`), der
  `MapReadEndpoints()` + 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.md` als **Read** (public-tauglich) oder **Control** (nur lokal)
      markieren. Kandidaten Control: alle `POST/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()` in `MapReadEndpoints()` + `MapControlEndpoints()` splitten
      (rein struktureller Refactor, Verhalten unverändert; bestehende Tests bleiben grün).
- [ ] `GET /api/capabilities` einführen.

### Phase 1 — WebUI als sauberes, gemeinsames SPA (parallel zum neuen Design)
- [ ] Neues Design als **ein statisches Artefakt** bauen, reiner API-Client, `API_BASE`
      konfigurierbar (heute `''` = gleiche Origin bleibt lokal gültig).
- [ ] Admin-Aktionen an `capabilities.canControl` koppeln.
- [ ] 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 `AllowAnyOrigin` auf konfigurierte Origin-Whitelist umstellen.
- [ ] Bind-Adresse explizit (localhost/LAN), nie `0.0.0.0` ohne 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).
- [ ] `AppDbContext` public-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
1. **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.
2. **Phase 1+2** (klein, parallel): neues SPA als gemeinsames Artefakt, lokale Grenze härten.
3. **Phase 3** (mittel): read-only DB-User + Schema-als-Vertrag dokumentieren.
4. **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.
