Files
appRobotDriver/doc/ToDo_14_robot_json_service.md
2026-06-11 22:05:45 +02:00

173 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap: robot.json als zentraler Service
## Ist-Zustand (Problem)
`robot.json` existiert aktuell an mindestens zwei unabhängigen Orten:
| App | Pfad | Rolle |
|-----|------|-------|
| `appRobotHoming` | `scripts/robot_<ts>.json` (Env: `ROBOT_JSON`) | Lesen + Schreiben (editRobot.js) |
| `appRobotRendering` | `data/robot/robot.json` | Lesen (Rendering) |
| `appRobotDriver` | — | Armlängen hardcodiert (`250, 264, 100`) |
Es gibt keine Versionierung, keinen Single Point of Truth, und wenn Homing die Geometrie kalibriert, bekommen Driver und Rendering davon nichts mit.
---
## Ziel-Architektur
`appRobotDriver` ist das **Zentrum des Systems** (er steuert die Hardware). Er besitzt daher auch die `robot.json` und stellt sie über einen REST-Endpunkt bereit. Alle anderen Apps lesen/schreiben ausschließlich über diesen Endpunkt.
```
appRobotDriver
└── data/robot/
├── robot.json ← aktueller Stand (Single Source of Truth)
├── robot_20260101_143522.json ← Snapshot vor jeder Änderung
└── robot_20260115_091010.json
appRobotHoming ──GET/PUT──► appRobotDriver :2098/api/robot
appRobotRendering ──GET──────► appRobotDriver :2098/api/robot
appRobotSimulation ──GET────► appRobotDriver :2098/api/robot
```
Der InfoServer (Port 2098) bekommt die neuen Endpunkte. Der WebSocket-Server (Port 2095) bleibt unverändert.
---
## API-Design
Alle Endpunkte unter dem bereits laufenden InfoServer auf Port 2098.
```
GET /api/robot → robot.json als JSON (kein Auth nötig)
PUT /api/robot → ersetzt robot.json, legt vorher Snapshot an (Auth nötig)
GET /api/robot/history → Liste aller Snapshots [{ filename, timestamp }]
GET /api/robot/history/:ts → einen bestimmten Snapshot abrufen
```
### Sicherheit (trivial, da Netz sicher)
PUT-Requests brauchen einen statischen API-Key als HTTP-Header:
```
Authorization: Bearer <ROBOT_API_KEY>
```
Key wird per Umgebungsvariable konfiguriert (`ROBOT_API_KEY`). Fehlt die Variable, wird ein zufälliger Key generiert und beim Start geloggt. Für GET braucht es keinen Key — Lesen ist überall erlaubt.
Das ist die einzige Absicherung. Kein JWT, keine Sessions, kein Rate-Limiting — Netz ist sicher, und ein versehentlicher Schreib-Request aus einem Browser soll trotzdem nicht funktionieren.
---
## Status
| Schritt | Bereich | Status |
|---------|---------|--------|
| 1 — Datei anlegen | appRobotDriver | ✅ erledigt |
| 2 — RobotConfigService | appRobotDriver | ✅ erledigt |
| 3 — Registrierung InfoServer | appRobotDriver | ✅ erledigt |
| 4 — Driver liest Armlängen | appRobotDriver | ✅ erledigt |
| 5 — appRobotHoming umstellen | appRobotHoming | ⬜ offen |
| 6 — appRobotRendering umstellen | appRobotRendering | ⬜ offen |
| 7 — Aufräumen | alle Repos | ⬜ offen |
Die Schritte 14 betreffen ausschließlich `appRobotDriver` und sind vollständig umgesetzt.
Schritte 57 betreffen `appRobotHoming` und `appRobotRendering` — separate Tickets/Sessions.
---
## Umsetzungsschritte
### Schritt 1 — Datei anlegen (appRobotDriver) ✅
- Verzeichnis `data/robot/` anlegen
- Default-`robot.json` wird vom Nutzer geliefert und dort abgelegt
- `.gitignore`-Eintrag für `data/robot/robot_*.json` (Snapshots gehören nicht ins Repo, `robot.json` selbst schon)
- Driver startet mit Defaults (`l1: 250, l2: 264, l3: 100`) wenn Datei fehlt, loggt Warnung
### Schritt 2 — RobotConfigService (appRobotDriver) ✅
Neue, **in sich geschlossene** Datei `server/RobotConfigService.js`. Sie hat keine Abhängigkeiten auf andere Teile des Drivers und kann in jeden Express- oder `https.createServer`-basierten Server mit einer Zeile eingehängt werden:
```js
const robotConfigService = require('./server/RobotConfigService');
robotConfigService.register(app, { apiKey: process.env.ROBOT_API_KEY });
// fertig — alle /api/robot*-Routen sind registriert
```
Das Modul kapselt intern:
```
readRobotJson() → Promise<object>
writeRobotJson(data) → Promise<{ snapshotFile }> // legt robot_<ts>.json an + pruning
listHistory() → Promise<{ filename, day, timestamp }[]>
readSnapshot(ts) → Promise<object>
pruneSnapshots() → löscht überschüssige Snapshots (s. Regel unten)
```
**Snapshot-Pruning-Regel:** Pro Tag maximal 100 Snapshots. Sind es mehr, wird nur der neueste des Tages behalten. Diese Bereinigung läuft automatisch nach jedem Schreibvorgang.
Timestamp-Format: `YYYYMMDD_HHmmss` (konsistent mit appRobotHoming).
**API-Key:** Wird per Option übergeben. Fehlt der Key (undefined), generiert das Modul beim ersten Start einen zufälligen Key, loggt ihn einmalig und speichert ihn in `data/robot/.apikey` (nicht im Repo). So funktioniert es ohne Konfiguration, ist aber trotzdem nicht offen.
### Schritt 3 — Registrierung in InfoServer.js (appRobotDriver) ✅
Eine Zeile in `server/InfoServer.js` am Anfang der Request-Handler:
```js
robotConfigService.register(httpsServer, { apiKey });
```
Da `InfoServer.js` kein Express nutzt (rohes `https.createServer`), bekommt `RobotConfigService` intern einen minimalen Router, der url-Matching selbst macht — oder `InfoServer.js` wird auf Express umgestellt (kleiner Schritt, bringt mehr Flexibilität für spätere Endpunkte).
### Schritt 4 — Driver liest Armlängen aus robot.json ✅
`startRobot.js` liest beim Start arm-lengths aus `data/robot/robot.json`.
Fallback auf `{ l1: 250, l2: 264, l3: 100 }` mit Log-Warnung wenn Datei fehlt oder Keys fehlen.
```js
// links.Arm1.size[1] → l1
// links.Arm2.size[1] → l2
// links.Ellbow.size[0] → l3
```
### Schritt 5 — appRobotHoming auf Driver-API umstellen ⬜
`server/server.js` in appRobotHoming:
- `ROBOT_JSON`-Env-Variable durch `ROBOT_DRIVER_URL` ersetzen (z.B. `https://appRobotDriver:2098`)
- Neue Hilfsfunktionen `fetchRobotJson()` / `pushRobotJson(data)` (HTTP GET/PUT mit API-Key)
- Alle `fsPromises.readFile(ROBOT_JSON)`-Aufrufe durch `await fetchRobotJson()` ersetzen
- Nach jeder editRobot.js-Transformation: `await pushRobotJson(updated)`
- `editRobot.js` bleibt unverändert (pure Transformationen, kein File-IO)
### Schritt 6 — appRobotRendering auf Driver-API umstellen ⬜
`robot.json` wird einmalig beim Start vom Driver geholt und gecacht. Cache wird per `GET /api/robot` aktualisierbar. Env-Variable `ROBOT_DRIVER_URL`.
### Schritt 7 — Aufräumen ⬜
- Lokale `robot.json`-Kopien in appRobotHoming und appRobotRendering entfernen
- `.gitignore`-Einträge in den betroffenen Repos anpassen
- `ROBOT_JSON`-Env-Variable aus docker-compose-Dateien entfernen, `ROBOT_DRIVER_URL` hinzufügen
---
## Entschiedene Punkte
| Frage | Entscheidung |
|-------|-------------|
| Driver-Start ohne robot.json | Mit Defaults starten + Warnung loggen |
| Snapshot-Limit | Max. 100 pro Tag; danach pro Tag nur die letzte Version behalten |
| Caching in Clients | Ja, erlaubt — Ziel ist API-only-Zugriff, kein direktes File-IO |
| Port InfoServer | 2098 bleibt; weitere Endpunkte werden dort angehängt |
---
## Nicht in dieser Roadmap
- Konflikte bei gleichzeitigen Schreibzugriffen (mutex) — vorerst nicht nötig, Homing ist der einzige Schreiber
- Diff-Anzeige zwischen Snapshots
- Rollback-Endpunkt (kann manuell über `GET /api/robot/history/:ts` + `PUT /api/robot` gemacht werden)