# ToDo – appRobotHoming

Nächste Schritte für den Umbau zum statischen Frontend + HTTPS-BFF-Proxy.
Kontext/Architektur: siehe [`../README.md`](../README.md).

Reihenfolge ist grob nach Priorität sortiert. Offene Entscheidungen sind als
**Frage** markiert – die müssen vor der Umsetzung geklärt werden.

---

## 1. HTTPS wieder zum Laufen bringen (blockierend)

**Diagnose abgeschlossen (2026-06-08):**

- Backend läuft auf 2093, aber als **HTTP** (`http://…:2093/` → 200 + UI;
  `https://…:2093/` → keine Antwort). Es ist der **Container** (docker-compose):
  `/api/health` meldet `webcamUrl: http://appRobotWebcam:8444`.
- Der Code ist korrekt: `https/localhost.key` + `localhost.pem` mit Passphrase
  `abcd` laden lokal **einwandfrei** in `https.createServer`.
- **Root Cause:** Die Cert-Dateien **fehlen im Container**. `.gitignore` schließt
  `*.key`/`*.pem`/`*.pfx` aus → nicht in git → der Mount
  `/home/chk/Documents/appRobotHoming` auf `thinkcentre` hat sie nicht →
  `createHttpsServer()` scheitert an `fsPromises.access()` → **stiller
  HTTP-Fallback** (`server/server.js`, `createHttpsServer` → `return null`).

**Gewählte Lösung (Entscheidung): Cert reist mit dem Repo/Volume.**

Das self-signed Cert sichert nur den Hop **Proxy ↔ Backend** und hat keinen
echten Wert (nie öffentlich). Daher darf es mit ins Repo und kommt über den
bestehenden `/app`-Volume-Mount automatisch in den Container.

- [x] `.gitignore`: gezielte Ausnahme `!https/localhost.key` + `!https/localhost.pem`
      (Schutz für alle anderen Schlüssel bleibt bestehen). → erledigt.
- [ ] `https/localhost.key` + `https/localhost.pem` committen.
- [ ] Deploy-Host `thinkcentre:/home/chk/Documents/appRobotHoming/` aktualisieren
      (git pull bzw. Dateien bereitstellen), damit der Container sie sieht.
- [ ] Verifizieren: `https://thinkcentre.local:2093/api/health` antwortet über
      **HTTPS** (aktuell nur HTTP).

Optional (separat, nicht Teil der Entscheidung):

- [ ] Passphrase/Pfad konsequent aus dem Env (`HTTPS_KEY_PATH`/`HTTPS_CERT_PATH`/
      `HTTPS_PASSPHRASE`) statt hartkodiert.
- [ ] Stillen HTTP-Fallback lauter machen (klar loggen / hart abbrechen statt
      unbemerkt HTTP) – dieser Fallback hat den Bug verschleiert.
- [ ] Reverse-Proxy prüfen: Leitet er WSS-Upgrade-Header korrekt an
      `https://…:2093` weiter?

---

## 2. WebCam-Bilder über die dokumentierte API holen → **entschieden: Option B**

`server/server.js` ruft aktuell `WEBCAM_URL + /api/latest-snapshot` auf – diesen
Endpoint gibt es **nicht**. **Entscheidung:** Der Homing-Backend setzt das Bundle
selbst aus den dokumentierten Endpoints zusammen (kein neuer Endpoint im
WebCam-Service).

Service läuft und ist erreichbar unter `http://thinkcentre.local:8444`
(→ `WEBCAM_URL`). Real verifizierte Contracts:

- `GET /api/cameras` →
  ```json
  {"cameras":[
    {"id":"cam0","name":"Kamera 0","position":"front","stream":true,"hires":true, ...},
    {"id":"cam1","name":"Kamera 1","position":"left", "stream":true,"hires":true, ...},
    {"id":"cam2","name":"Kamera 2","position":"right","stream":true,"hires":true, ...}
  ]}
  ```
- `GET /api/snapshot/{id}/hires` → `200 image/jpeg` (cam0/cam1 ~1280px, cam2 1920px).
- `GET /health` → Status + `state`/`hasFrame` pro Kamera.

Umsetzung in `server/server.js` (`/api/latest-snapshot`):

- [ ] `GET {WEBCAM_URL}/api/cameras` holen → Kameraliste (mit `hires:true` filtern).
- [ ] Für jede Kamera **parallel** `GET {WEBCAM_URL}/api/snapshot/{id}/hires` →
      JPEG, als base64 + `id`/`position` ins Bundle.
- [ ] Bundle ans UI zurückgeben (statt der bisherigen CSV-Annahme). Reihenfolge/
      Zuordnung über `id`+`position` stabil halten (wichtig für §3).
- Hinweis: Die alte CSV/`_annotated.jpg`/JSON-Marker-Erkennung kommt **nicht**
  von der Webcam. Für den BodyTracker-Pfad ist sie ohnehin redundant
  (BodyTracker macht ArUco selbst); sie bleibt nur für den lokalen Fallback
  `public/calculateAngles.js` relevant.

---

## 3. Intrinsics-Fluss → **entschieden: WebCam liefert Intrinsics mit**

**Klarstellung der Datentypen** (im Altcode unter „Intrinsics" vermischt):

| Typ | Beispiel | Quelle | statisch |
|---|---|---|---|
| **Kamera-Intrinsics** (K, Distortion) | das echte „NPZ" | Kalibrierung | ✅ pro Kamera |
| **Extrinsics** (`position_mm`, `orientation_deg`) | in `_two_cam.json` | wird gelöst | ❌ Output |
| **Marker-3D-Posen** | in `_two_cam.json` | trianguliert | ❌ Output |

Das, was `server/server.js` heute als `robotIntrinsics` (= `_two_cam.json`)
schickt, sind **Extrinsics + triangulierte Marker** – also **BodyTracker-Output**,
fälschlich als Input verschickt. Muss raus.

Die WebCam liefert aktuell **kein** NPZ (alle Intrinsics-Endpoints → 404). Der
BodyTracker hält in `/v1/config` nur Solver-Parameter, keine Intrinsics.

**Entscheidung:** Die Kamera-Intrinsics leben beim **WebCam-Service** (Source of
Truth) und werden mitgeliefert. Homing reicht sie an den BodyTracker durch.

Aufgaben WebCam-Service:
- [x] **Kalibrierung vorhanden** (verifiziert 2026-06-10): `/api/cameras` liefert
      `calibrationUrl` für alle 3 Kameras (cam0/cam1/cam2). `.npz`-Abruf über
      `GET /api/cameras/{id}/calibration` → `application/octet-stream` funktioniert.
      Kein Neu-Kalibrieren nötig.

Aufgaben Homing-Backend (`server/server.js`):
- [ ] `robotIntrinsics`/`_two_cam.json`-Pfad aus `/api/estimate` entfernen.
- [ ] Pro Kamera Bild + zugehörige Intrinsics paaren (über `id`) und an
      `BODYTRACKER/v1/estimate` weiterreichen. **N Kameras** (aktuell 3), nicht
      fix 2.

Aufgaben BodyTracker (wir besitzen ihn):
- [ ] `/v1/estimate` so anpassen, dass er Intrinsics **als JSON je Kamera**
      annimmt (kein `.npz`-Zwang) – erspart NPZ-Erzeugung in Node. Format
      gemeinsam festzurren (K 3×3 oder fx/fy/cx/cy, dist k1,k2,p1,p2,k3,
      `image_size`).

---

## 4. Aufräumen (Altlasten aus der WSS/HTTPS-Server-Ära)

- [ ] `docker-compose.yaml`: `WSS_VIDEO_DRIVER`, `WSS_URL`, `HTTPS_PORT`-Doppelung
      und `depends_on: appRobotDriver` prüfen/entfernen. Behalten: `WEBCAM_URL`,
      `BODYTRACKER_URL`, Port-Mapping `2093`, Cert-Volume.
- [ ] `package.json` → `description` ist veraltet („verbindet zu WSS, sendet
      Befehle").
- [ ] Command-Buttons in `public/index.html` (HOME/STOP/STATUS/RESET/PING/
      GCodeMotor) rufen `window.sendCommand` – **das ist nirgends definiert**
      (alter WSS-Transport). Entweder neuen Transport anbinden (gehört zu
      Erweiterung „Pose an appRobotDriver") oder bis dahin deaktivieren.
- [ ] `public/snapshots` (Fallback) ist leer → `findLatestSnapshotFile()` liefert
      `null` → 404. Beispiel-Datensatz ablegen **oder** Fallback dokumentiert
      abschalten.

---

## 5. Frontend / UX (geplante Erweiterungen)

- [ ] Erkennungsergebnis + erkannte Pose klarer ausgeben (statt nur Roh-JSON).
- [ ] Manuelle Eingabe von `x, y, z, a, b, c, e`.
- [ ] Wenn Hand nicht erkannt: Vorschlag für bessere Arm-/Foto-Position.
- [ ] Pose an `appRobotDriver` weitergeben (neuer Schritt nach BodyTracker;
      ggf. der WSS-Pfad, für den HTTPS gebraucht wird).

---

## Definition of Done (erster Meilenstein)

1. `https://<host>:2093/` liefert das statische UI über **HTTPS**.
2. `GET /api/latest-snapshot` liefert reale Bilder/Daten vom WebCam-Service.
3. `POST /api/estimate` liefert eine Pose vom BodyTracker und zeigt sie im UI.
4. Keine toten Buttons / keine WSS-Altlasten in Compose & package.json.
