# API des Chronolite Data Hub

Basis-URL: `http://localhost:4000` — WebSocket: `ws://localhost:4000/ws`

Alle Endpunkte sprechen JSON. Fehler werden als `{ "error": "…" }` mit passendem
HTTP-Statuscode (400/404) beantwortet. Der Hub kennt keine personenbezogenen Daten;
sämtliche Nutzerdaten hängen an anonymen, zufällig vergebenen IDs.

## Nutzer

### `POST /api/users` — anonyme Registrierung

Registriert eine neue App-Instanz und liefert die anonyme Nutzer-ID, die die App lokal
(Local Storage) speichert.

```bash
curl -X POST http://localhost:4000/api/users
```

```json
{ "userId": "4a3093d0-65b8-4872-8d19-7be536dbea7e" }
```

## Präferenzen

### `PUT /api/users/:userId/preferences` — Präferenzen speichern

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `chronotype` | number (0–12) | Chronotyp als MSFsc-Wert in Uhr-Stunden (per MCTQ ermittelt) |
| `birthYear` | number | Geburtsjahr; der Hub leitet daraus das Alter ab |
| `cctPreference` | number (−1…+1) | Lichtfarb-Präferenz: −1 „mag sehr kaltes/blaues Licht nicht", 0 neutral, +1 „mag kühles Licht" |

```bash
curl -X PUT http://localhost:4000/api/users/$USER_ID/preferences \
  -H 'Content-Type: application/json' \
  -d '{"chronotype": 6, "birthYear": 1960, "cctPreference": -0.5}'
```

### `GET /api/users/:userId/preferences` — Präferenzen abrufen

Liefert die gespeicherten Präferenzen oder `null`, wenn noch keine gesetzt wurden.

## Routinen

### `POST /api/users/:userId/routines` — Routine anlegen

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `time` | string `"HH:MM"` | Uhrzeit der Routine |
| `label` | string | Tätigkeit (frei wählbar) |
| `category` | `"activity"` \| `"relaxation"` | Aktivität → lokal kühleres Licht, Entspannung → lokal wärmeres Licht |

```bash
curl -X POST http://localhost:4000/api/users/$USER_ID/routines \
  -H 'Content-Type: application/json' \
  -d '{"time": "20:00", "label": "Lesen", "category": "relaxation"}'
```

```json
{ "id": "c01fcf0f-…", "time": "20:00", "label": "Lesen", "category": "relaxation" }
```

### `GET /api/users/:userId/routines` — Routinen auflisten

### `DELETE /api/users/:userId/routines/:routineId` — Routine löschen (`204`)

## Räume & Anwesenheit

### `GET /api/rooms` — Raumliste

Die Referenzimplementierung nutzt eine statische Liste von drei Demo-Räumen an einem
Flughafen (im realen System werden Räume über eine API bzw. ein Portal registriert).

```bash
curl http://localhost:4000/api/rooms
```

```json
[
  { "id": "gate", "name": "Flughafen-Gate", "description": "…", "occupantCount": 0 },
  { "id": "cubicle", "name": "Ruhe-Cubicle", "description": "…", "occupantCount": 0 },
  { "id": "train", "name": "Bahnwaggon", "description": "…", "occupantCount": 0 }
]
```

### `POST /api/rooms/:roomId/presence` — Anwesenheit melden

Meldet, dass eine Nutzer-ID den Raum betreten hat (im realen Einsatz ausgelöst durch
QR-Scan, GPS oder BLE-Beacon). Eine ID kann nur in einem Raum gleichzeitig anwesend
sein; ein Betreten verlässt implizit alle anderen Räume.

```bash
curl -X POST http://localhost:4000/api/rooms/gate/presence \
  -H 'Content-Type: application/json' \
  -d "{\"userId\": \"$USER_ID\"}"
```

### `DELETE /api/rooms/:roomId/presence/:userId` — Verlassen melden (`204`)

Beide Presence-Endpunkte lösen eine `presenceChanged`-Nachricht an alle
WebSocket-Abonnenten des Raums aus.

## Beleuchtungskurven

### `GET /api/rooms/:roomId/curves?date=YYYY-MM-DD` — Tageskurven abrufen

Liefert die beiden Kurven des Raums für den angegebenen Tag (Standard: heute) als
stückweise Polynomfunktionen — personalisiert für die **erste** anwesende Person mit
Präferenzen, sonst die Basiskurven (Details: [ALGORITHMEN.md](ALGORITHMEN.md)).

```bash
curl "http://localhost:4000/api/rooms/gate/curves?date=2025-01-15"
```

```json
{
  "roomId": "gate",
  "date": "2025-01-15",
  "basedOnUser": "4a3093d0-…",
  "occupantCount": 1,
  "medi": {
    "segments": [
      { "coeffs": [1.36, 0, 0], "start": 0, "end": 420 },
      { "coeffs": [57.99, -0.607, 0.00112], "start": 420, "end": 510 }
    ]
  },
  "cct": { "segments": ["…"] }
}
```

Auswertung eines Segments: `wert = Σ coeffs[i] · x^i` für die Tagesminute
`start ≤ x ≤ end` (0 = 00:00, 1439 = 23:59). Die Bibliothek `@chronolite/curves`
stellt dafür `evaluateSegments(segments, minuteOfDay)` bereit.

## WebSocket-Protokoll

Endpunkt: `ws://localhost:4000/ws` — alle Nachrichten sind JSON.

| Richtung | Nachricht | Bedeutung |
| --- | --- | --- |
| Client → Hub | `{ "type": "subscribe", "roomId": "gate" }` | Anwesenheitsänderungen eines Raums abonnieren |
| Hub → Client | `{ "type": "subscribed", "roomId": "gate" }` | Bestätigung des Abonnements |
| Hub → Client | `{ "type": "presenceChanged", "roomId": "gate", "occupantCount": 1 }` | Anwesenheit hat sich geändert → Kurven neu laden |
| Hub → Client | `{ "type": "error", "error": "…" }` | Ungültige Nachricht oder unbekannter Raum |

Beispiel mit `wscat` (oder einem beliebigen WebSocket-Client):

```
$ wscat -c ws://localhost:4000/ws
> {"type":"subscribe","roomId":"gate"}
< {"type":"subscribed","roomId":"gate"}
< {"type":"presenceChanged","roomId":"gate","occupantCount":1}
```
