# 📖 REST-API Dokumentation – UTabwPLATTFORM Kartenverwaltung

Willkommen bei der offiziellen REST-API der **UTabwPLATTFORM** (Umwelttechnologie-Lernplattform).  
Diese API ermöglicht externen Anwendungen, Synchronisations-Tools, Admin-Skripten und KI-Agenten die vollständige Verwaltung der Karteikarten und Lerninhalte.

---

## 📑 Inhaltsverzeichnis
1. [Übersicht & Schnellstart](#1-übersicht--schnellstart)
2. [Authentifizierung & API-Key](#2-authentifizierung--api-key)
3. [Karten-Datenmodell & Felder](#3-karten-datenmodell--felder)
4. [Endpunkt-Referenz](#4-endpunkt-referenz)
   - [1. Liste aller Karten-IDs abfragen](#1-liste-aller-karten-ids-abfragen)
   - [2. Alle Karten herunterladen (Gesamtexport)](#2-alle-karten-herunterladen-gesamtexport)
   - [3. Einzelne Karte per ID abrufen](#3-einzelne-karte-per-id-abrufen)
   - [4. Neue Karte(n) anlegen (ID-Vergabe durch Server)](#4-neue-karten-anlegen-id-vergabe-durch-server)
   - [5. Karte per ID aktualisieren/updaten](#5-karte-per-id-aktualisierenupdaten)
   - [6. Karte löschen](#6-karte-löschen)
5. [Filter-Parameter (Query Params)](#5-filter-parameter-query-params)
6. [HTTP-Statuscodes & Fehlerbehandlung](#6-http-statuscodes--fehlerbehandlung)
7. [Code-Beispiele (curl, PowerShell, Python, JavaScript)](#7-code-beispiele)

---

## 1. Übersicht & Schnellstart

- **Basis-URL:** `http://localhost:12117/api/v1/cards`  
- **Datenformat:** `application/json` (UTF-8)
- **Authentifizierung:** Über API-Key
- **Wichtigste Regel:** Die API überträgt stets die **vollständigen Daten** jeder Karte. Ausschließlich die **`id`** ist unveränderlich und wird serverseitig vergeben.

---

## 2. Authentifizierung & API-Key

Jeder Aufruf der API erfordert einen gültigen API-Key.  
Der API-Key kann auf drei Arten übermittelt werden:

### Methode A: HTTP-Header `X-API-Key` (Empfohlen)
```http
GET /api/v1/cards/ids HTTP/1.1
Host: localhost:12117
X-API-Key: DEIN_API_KEY
```

### Methode B: HTTP-Header `Authorization: Bearer`
```http
GET /api/v1/cards/ids HTTP/1.1
Host: localhost:12117
Authorization: Bearer DEIN_API_KEY
```

### Methode C: URL Query-Parameter
```http
GET /api/v1/cards/ids?apiKey=DEIN_API_KEY HTTP/1.1
Host: localhost:12117
```

### Wo finde ich meinen API-Key?
1. **Im Admin-Bereich der Web-App:**  
   Navigiere als Administrator zu **Admin-Bereich ➔ Optionen & KI-Konfiguration ➔ REST-API Schnittstelle & API-Key**.  
   Dort kannst du den Schlüssel mit einem Klick kopieren oder bei Bedarf jederzeit neu generieren.
2. **Direkt in der Konfigurationsdatei:**  
   In `data/config.json` unter dem Schlüssel `"apiKey"`.

---

## 3. Karten-Datenmodell & Felder

Jede Karte besitzt die folgenden Attribute:

| Feld | Typ | Beschreibung | Mögliche / Typische Werte |
| :--- | :--- | :--- | :--- |
| **`id`** | `int` | Eindeutige Karten-ID. **Nur lesbar**, wird vom Server vergeben. | `1, 2, 3, ...` |
| **`side1`** | `string` | Vorderseite (Fachwort, Begriff oder Aufgabenstellung). *(Pflichtfeld)* | z. B. `"Nitrifikation"` |
| **`side2`** | `string` | Rückseite (Definition, Erklärung, Rechenweg, Musterhandlung). *(Pflichtfeld)* | z. B. `"Zweistufige biologische Umwandlung..."` |
| **`category`** | `string` | Modus / Hauptkategorie der Karte. | `"card"` (Fachbegriff), `"situation"` (Handlungssituation), `"math"` (Rechenaufgabe) |
| **`subCategory`** | `string` | Spezifischer Themenbereich / Unterkategorie. | z. B. `"Biologische Reinigung & Nährstoffe"`, `"Allgemein"`, `"Mechanische Reinigung"` |
| **`professions`** | `string` | Komma-separierte Liste der relevanten Ausbildungsberufe. | `"abwasser,wasser,kreislauf,rohr"` (oder Teilmengen) |
| **`year`** | `int` | Ausbildungsjahr (Lehrjahr). | `1`, `2` oder `3` (Standard: `1`) |
| **`status`** | `string` | Moderationsstatus der Karte. | `"approved"` (freigegeben), `"pending"` (in Prüfung), `"rejected"` |
| **`answerType`** | `string` | Antworttyp für Quiz- und Testgenerierung. | `"definition"` (Text), `"wert"` (Kennwert/Zahl), `"aufzaehlung"` |
| **`verificationLevel`** | `int` | **Sicherheitsstufe** der fachlichen Information. | `1` = Ungeprüft<br>`2` = KI-Geprüft<br>`3` = Geprüft (4-Augen)<br>`4` = Verifiziert |
| **`proposerIdentifier`** | `string` | Urheber / Ersteller der Karte. | z. B. `"Admin"`, `"System"`, `"API-Sync"` |
| **`createdAt`** | `string (ISO-8601)` | Erstellungsdatum & Zeitstempel. | z. B. `"2025-01-10T12:00:00.0000000Z"` |

---

## 4. Endpunkt-Referenz

### 1. Liste aller Karten-IDs abfragen
Ruft eine schlanke Liste aller vorhandenen Karten-IDs ab. Ideal zum Prüfen von Beständen oder für Delta-Synchronisierungen.

- **Methode:** `GET`
- **Pfad:** `/api/v1/cards/ids` (oder `/api/v1/cards?idsOnly=true`)
- **Query-Parameter:** Optional filterbar nach `category`, `status`, `profession`, `year`.

#### Antwort (HTTP 200 OK):
```json
{
  "count": 120,
  "ids": [1, 2, 3, 4, 5, 12, 15, 23, 42]
}
```

---

### 2. Alle Karten herunterladen (Gesamtexport)
Lädt alle Karten mit 100% aller Datenfelder in einem einzigen Batch-Aufruf herunter.

- **Methode:** `GET`
- **Pfad:** `/api/v1/cards/all` (oder `/api/v1/cards`)
- **Query-Parameter:** Optional filterbar nach `category`, `status`, `profession`, `year`.

#### Antwort (HTTP 200 OK):
```json
{
  "count": 2,
  "cards": [
    {
      "id": 1,
      "side1": "Nitrifikation",
      "side2": "Biologische Oxidation von Ammonium (NH4+) über Nitrit (NO2-) zu Nitrat (NO3-) durch autotrophe Bakterien unter O2-Verbrauch.",
      "category": "card",
      "subCategory": "Biologische Reinigung & Nährstoffe",
      "professions": "abwasser,wasser,kreislauf,rohr",
      "year": 2,
      "status": "approved",
      "answerType": "definition",
      "verificationLevel": 3,
      "proposerIdentifier": "System",
      "createdAt": "2025-01-10T10:00:00.0000000Z"
    },
    {
      "id": 2,
      "side1": "Trockensubstanz (TS)",
      "side2": "Der Anteil der festen Bestandteile einer Schlammprobe nach Trocknung bei 105 °C bis zur Gewichtskonstanz (in g/L oder %).",
      "category": "card",
      "subCategory": "Schlammbehandlung",
      "professions": "abwasser,kreislauf",
      "year": 1,
      "status": "approved",
      "answerType": "definition",
      "verificationLevel": 2,
      "proposerIdentifier": "Admin",
      "createdAt": "2025-01-12T14:30:00.0000000Z"
    }
  ]
}
```

---

### 3. Einzelne Karte per ID abrufen
Lädt die vollständigen Daten einer spezifischen Karte anhand ihrer eindeutigen ID herunter.

- **Methode:** `GET`
- **Pfad:** `/api/v1/cards/{id}` (z. B. `/api/v1/cards/42`)

#### Antwort (HTTP 200 OK):
```json
{
  "id": 42,
  "side1": "Denitrifikation",
  "side2": "Biologische Reduktion von Nitrat (NO3-) zu molekularem elementarem Stickstoff (N2) unter anoxischen Bedingungen durch heterotrophe Bakterien.",
  "category": "card",
  "subCategory": "Biologische Reinigung & Nährstoffe",
  "professions": "abwasser,wasser,kreislauf,rohr",
  "year": 2,
  "status": "approved",
  "answerType": "definition",
  "verificationLevel": 3,
  "proposerIdentifier": "System",
  "createdAt": "2025-01-15T08:00:00.0000000Z"
}
```

#### Fehler bei unbekannter ID (HTTP 404 Not Found):
```json
{
  "error": "Karte mit ID 9999 nicht gefunden."
}
```

---

### 4. Neue Karte(n) anlegen (ID-Vergabe durch Server)
Sendet neue Kartendaten an das System. Der Webserver vergibt automatisch die nächste freie eindeutige ID.

- **Methode:** `POST`
- **Pfad:** `/api/v1/cards`
- **Content-Type:** `application/json`

#### Variante A: Einzelne Karte anlegen
**Request-Body:**
```json
{
  "side1": "Faulgas-Zusammensetzung",
  "side2": "Typischerweise ca. 60–65 % Methan (CH4), 30–35 % Kohlendioxid (CO2), Spuren von Stickstoff, Wasserstoff und Schwefelwasserstoff (H2S).",
  "category": "card",
  "subCategory": "Schlammbehandlung",
  "professions": "abwasser,kreislauf",
  "year": 3,
  "status": "approved",
  "answerType": "definition",
  "verificationLevel": 3,
  "proposerIdentifier": "API-Tool"
}
```

**Antwort (HTTP 201 Created):**
```json
{
  "success": true,
  "message": "Karte erfolgreich angelegt.",
  "card": {
    "id": 145,
    "side1": "Faulgas-Zusammensetzung",
    "side2": "Typischerweise ca. 60–65 % Methan (CH4)...",
    "category": "card",
    "subCategory": "Schlammbehandlung",
    "professions": "abwasser,kreislauf",
    "year": 3,
    "status": "approved",
    "answerType": "definition",
    "verificationLevel": 3,
    "proposerIdentifier": "API-Tool",
    "createdAt": "2025-05-20T16:45:12.1234567Z"
  }
}
```

#### Variante B: Mehrere Karten im Batch anlegen
Der Body kann auch ein JSON-Array mit mehreren Kartenobjekten sein:
```json
[
  {
    "side1": "CSB (Chemischer Sauerstoffbedarf)",
    "side2": "Menge an Sauerstoff, die zur chemischen Oxidation der Wasserinhaltsstoffe mit Kaliumdichromat benötigt wird (in mg/L).",
    "category": "card",
    "subCategory": "Analytik & Labor",
    "verificationLevel": 3
  },
  {
    "side1": "BSB5 (Biochemischer Sauerstoffbedarf in 5 Tagen)",
    "side2": "Menge an gelöstem Sauerstoff, die aerobe Mikroorganismen in 5 Tagen bei 20 °C zum Abbau organischer Stoffe verbrauchen (in mg/L).",
    "category": "card",
    "subCategory": "Analytik & Labor",
    "verificationLevel": 3
  }
]
```

**Antwort (HTTP 201 Created):**
```json
{
  "success": true,
  "createdCount": 2,
  "cards": [
    { "id": 146, "side1": "CSB...", ... },
    { "id": 147, "side1": "BSB5...", ... }
  ]
}
```

---

### 5. Karte per ID aktualisieren/updaten
Aktualisiert eine existierende Karte vollständig anhand ihrer Ziel-ID.

- **Methode:** `PUT` (oder `POST`)
- **Pfad:** `/api/v1/cards/{id}` (z. B. `/api/v1/cards/42`)
- **Content-Type:** `application/json`

> **Wichtig:** Es werden die kompletten Kartendaten übertragen. Sollte im Request-Body ein `id`-Feld enthalten sein, wird dieses ignoriert – maßgeblich ist immer die Ziel-ID in der URL (`/api/v1/cards/{id}`).

**Request-Body:**
```json
{
  "side1": "Denitrifikation (Revidiert)",
  "side2": "Biologische Reduktion von Nitrat (NO3-) über Nitrit (NO2-) zu gasförmigem molekularem Stickstoff (N2) unter strikt anoxischen Bedingungen durch heterotrophe Mikroorganismen.",
  "category": "card",
  "subCategory": "Biologische Reinigung & Nährstoffe",
  "professions": "abwasser,wasser,kreislauf,rohr",
  "year": 2,
  "status": "approved",
  "answerType": "definition",
  "verificationLevel": 3,
  "proposerIdentifier": "Admin",
  "createdAt": "2025-01-15T08:00:00.0000000Z"
}
```

#### Antwort (HTTP 200 OK):
```json
{
  "success": true,
  "message": "Karte mit ID 42 erfolgreich aktualisiert.",
  "card": {
    "id": 42,
    "side1": "Denitrifikation (Revidiert)",
    "side2": "Biologische Reduktion von Nitrat...",
    "category": "card",
    "subCategory": "Biologische Reinigung & Nährstoffe",
    "professions": "abwasser,wasser,kreislauf,rohr",
    "year": 2,
    "status": "approved",
    "answerType": "definition",
    "verificationLevel": 3,
    "proposerIdentifier": "Admin",
    "createdAt": "2025-01-15T08:00:00.0000000Z"
  }
}
```

---

### 6. Karte löschen
Löscht die Karte mit der angegebenen ID dauerhaft aus der Datenbank.

- **Methode:** `DELETE`
- **Pfad:** `/api/v1/cards/{id}` (z. B. `/api/v1/cards/145`)

#### Antwort (HTTP 200 OK):
```json
{
  "success": true,
  "message": "Karte mit ID 145 wurde erfolgreich gelöscht."
}
```

---

## 5. Filter-Parameter (Query Params)

Bei den Endpunkten `GET /api/v1/cards/ids`, `GET /api/v1/cards/all` und `GET /api/v1/cards` können folgende URL-Parameter kombiniert werden:

| Parameter | Beispiel | Funktion |
| :--- | :--- | :--- |
| `category` | `?category=card` oder `?category=situation` | Filtert nach Hauptkategorie (`card`, `situation`, `math`). |
| `status` | `?status=approved` | Filtert nach Status (`approved`, `pending`, `rejected`). |
| `profession` | `?profession=abwasser` | Filtert nach Fachrichtung (`abwasser`, `wasser`, `kreislauf`, `rohr`). |
| `year` | `?year=2` | Filtert nach Lehrjahr (`1`, `2`, `3`). |
| `idsOnly` | `?idsOnly=true` | Liefert nur das Array von IDs statt der vollen Kartenobjekte. |

---

## 6. HTTP-Statuscodes & Fehlerbehandlung

Die API verwendet standardkonforme HTTP-Statuscodes:

- **`200 OK`**: Anfrage erfolgreich ausgeführt.
- **`201 Created`**: Neue Karte(n) erfolgreich angelegt.
- **`400 Bad Request`**: Ungültige Eingabedaten (z. B. Pflichtfelder `side1` oder `side2` fehlen, ungültiges JSON).
- **`401 Unauthorized`**: Fehlender oder falscher API-Key.
- **`404 Not Found`**: Die angeforderte Karten-ID existiert nicht.
- **`500 Internal Server Error`**: Unerwarteter Serverfehler.

Fehlermeldungen werden immer im JSON-Format zurückgegeben:
```json
{
  "error": "Ungültiger oder fehlender API-Key.",
  "message": "Authentifizierung fehlgeschlagen. Bitte API-Key im Header 'X-API-Key' oder 'Authorization: Bearer <key>' übermitteln."
}
```

---

## 7. Code-Beispiele

Ersetze `DEIN_API_KEY` durch deinen tatsächlichen Schlüssel und `12117` durch deinen konfigurierten Port.

### cURL (Bash / Linux / macOS)

#### 1. Alle Karten-IDs abfragen
```bash
curl -H "X-API-Key: DEIN_API_KEY" \
     http://localhost:12117/api/v1/cards/ids
```

#### 2. Karte Nr. 42 abrufen
```bash
curl -H "X-API-Key: DEIN_API_KEY" \
     http://localhost:12117/api/v1/cards/42
```

#### 3. Neue Karte anlegen
```bash
curl -X POST http://localhost:12117/api/v1/cards \
     -H "X-API-Key: DEIN_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "side1": "Sandfang",
       "side2": "Mechanische Reinigungsstufe zur Abscheidung mineralischer Stoffe wie Sand, Kies und Glassplitter durch Schwerkraft.",
       "category": "card",
       "subCategory": "Mechanische Reinigung",
       "verificationLevel": 3
     }'
```

#### 4. Karte Nr. 42 aktualisieren
```bash
curl -X PUT http://localhost:12117/api/v1/cards/42 \
     -H "X-API-Key: DEIN_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "side1": "Denitrifikation",
       "side2": "Biologischer Abbau von Nitrat zu Stickstoffgas.",
       "category": "card",
       "subCategory": "Biologische Reinigung & Nährstoffe",
       "verificationLevel": 3
     }'
```

---

### PowerShell

```powershell
$apiKey = "DEIN_API_KEY"
$baseUrl = "http://localhost:12117/api/v1/cards"
$headers = @{
    "X-API-Key" = $apiKey
    "Content-Type" = "application/json; charset=utf-8"
}

# 1. Alle Karten-IDs abrufen
$idsResponse = Invoke-RestMethod -Uri "$baseUrl/ids" -Headers $headers -Method Get
Write-Host "Vorhandene Karten-IDs: $($idsResponse.ids.Count)"

# 2. Eine Karte per ID abrufen
$card = Invoke-RestMethod -Uri "$baseUrl/1" -Headers $headers -Method Get
Write-Host "Vorderseite: $($card.side1)"
Write-Host "Sicherheitsstufe: $($card.verificationLevel)"

# 3. Neue Karte anlegen
$newCardData = @{
    side1 = "Vorklärbecken"
    side2 = "Absetzbecken zur Abtrennung absetzbarer organischer Stoffe vor der biologischen Stufe."
    category = "card"
    subCategory = "Mechanische Reinigung"
    verificationLevel = 3
    professions = "abwasser"
    year = 1
} | ConvertTo-Json

$created = Invoke-RestMethod -Uri $baseUrl -Headers $headers -Method Post -Body $newCardData
Write-Host "Neue Karte mit ID $($created.card.id) erstellt!"

# 4. Karte aktualisieren
$updateData = @{
    side1 = "Vorklärbecken (VK)"
    side2 = "Sedimentationsbecken zur Abtrennung von Primärschlamm."
    category = "card"
    subCategory = "Mechanische Reinigung"
    verificationLevel = 3
} | ConvertTo-Json

$updated = Invoke-RestMethod -Uri "$baseUrl/$($created.card.id)" -Headers $headers -Method Put -Body $updateData
Write-Host "Aktualisiert: $($updated.card.side1)"
```

---

### Python (`requests`)

```python
import requests

API_KEY = "DEIN_API_KEY"
BASE_URL = "http://localhost:12117/api/v1/cards"

headers = {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json"
}

# 1. Alle IDs abrufen
res = requests.get(f"{BASE_URL}/ids", headers=headers)
print("Karten-IDs:", res.json()["ids"])

# 2. Alle Karten herunterladen
all_cards = requests.get(f"{BASE_URL}/all", headers=headers).json()
print(f"Insgesamt {all_cards['count']} Karten heruntergeladen.")

# 3. Neue Karte anlegen
new_card = {
    "side1": "Faulturm",
    "side2": "Gasdichter, beheizter Reaktor zur anaeroben Schlammstabilisierung bei ca. 37 °C.",
    "category": "card",
    "subCategory": "Schlammbehandlung",
    "verificationLevel": 3,
    "professions": "abwasser,kreislauf",
    "year": 2
}
res_post = requests.post(BASE_URL, headers=headers, json=new_card)
created_id = res_post.json()["card"]["id"]
print(f"Karte angelegt mit ID: {created_id}")

# 4. Karte aktualisieren
updated_payload = {
    "side1": "Faulturm (Schlammfaulbehälter)",
    "side2": "Anaerobe Schlammfaulung zur Reduktion organischer Trockensubstanz und Gewinnung von Methangas.",
    "category": "card",
    "subCategory": "Schlammbehandlung",
    "verificationLevel": 3
}
res_put = requests.put(f"{BASE_URL}/{created_id}", headers=headers, json=updated_payload)
print("Aktualisiert:", res_put.json()["card"]["side1"])
```

---

### JavaScript / TypeScript / Node.js (`fetch`)

```javascript
const API_KEY = "DEIN_API_KEY";
const BASE_URL = "http://localhost:12117/api/v1/cards";

const headers = {
  "X-API-Key": API_KEY,
  "Content-Type": "application/json"
};

async function main() {
  // 1. Liste aller IDs
  const resIds = await fetch(`${BASE_URL}/ids`, { headers });
  const { ids } = await resIds.json();
  console.log("IDs:", ids);

  // 2. Einzelne Karte holen
  if (ids.length > 0) {
    const resCard = await fetch(`${BASE_URL}/${ids[0]}`, { headers });
    const card = await resCard.json();
    console.log(`Karte #${card.id}:`, card.side1, "->", card.side2);
  }

  // 3. Neue Karte erstellen
  const resCreate = await fetch(BASE_URL, {
    method: "POST",
    headers,
    body: JSON.stringify({
      side1: "Rechenanlage",
      side2: "Erste mechanische Stufe zur Rückhaltung von Grobstoffen (Feinrechen / Grobrechen).",
      category: "card",
      subCategory: "Mechanische Reinigung",
      verificationLevel: 3
    })
  });
  const { card: createdCard } = await resCreate.json();
  console.log("Erstellt:", createdCard.id, createdCard.side1);

  // 4. Karte aktualisieren
  const resUpdate = await fetch(`${BASE_URL}/${createdCard.id}`, {
    method: "PUT",
    headers,
    body: JSON.stringify({
      side1: "Rechenanlage (Grobrechen & Feinrechen)",
      side2: "Rückhaltung von Grobstoffen zur Vermeidung von Verstopfungen in Pumpen.",
      category: "card",
      subCategory: "Mechanische Reinigung",
      verificationLevel: 3
    })
  });
  const updatedResult = await resUpdate.json();
  console.log("Aktualisiert:", updatedResult.card);
}

main().catch(console.error);
```
