# Sessionplan Snapshot API – Anleitung für KI-Tools

**Basis-URL:** `https://sessionplan.de`

Die API erstellt und liest unveränderliche Snapshot-Links für Workshops,
Trainings, Meetings und Events. Jeder Aufruf ist zustandslos und benötigt weder
Konto noch Authentifizierung. Session-Daten werden zur Verarbeitung an den Server
übertragen, aber nicht als Workshop gespeichert. Snapshot-Inhalte und Referrer
werden nicht in die Snapshot-Analytics-Ereignisse übernommen.

## Verbindlicher Datenvertrag

- [JSON-Schema](https://sessionplan.de/data/sessionplan.schema.json): maßgebliche Strukturdefinition.
- [Import-Anleitung mit vollständigen Beispielen](https://sessionplan.de/import-schema.md): Felder und Planungsregeln.
- [OpenAPI 3.1](https://sessionplan.de/data/openapi.yaml): HTTP-Operationen; Datenmodelle werden aus dem JSON-Schema erzeugt.
- [MCP-Schnittstelle](https://sessionplan.de/mcp.md): dieselben Operationen als Tools.

Erzeuge oder errate niemals selbst einen Snapshot-Link. Verwende den Encoder und
gib dessen `link` unverändert als klickbare URL zurück. Zum Lesen oder Ändern eines
bestehenden Snapshots immer zuerst den Decoder aufrufen.

## Session in einen Link umwandeln

```http
POST /data/encode.php
Content-Type: application/json
```

Body: das **vollständige Sessionplan-Dokument**, ohne umschließendes `session`-Feld.

```json
{
  "version": "1.0",
  "workshop": {
    "title": "Produkt-Retrospektive",
    "description": "Rückblick auf den letzten Sprint",
    "date": "2026-09-15",
    "startTime": "10:00"
  },
  "blockTypes": [
    { "id": "discussion", "name": "Diskussion", "color": "#A855F7" }
  ],
  "persons": [],
  "items": [
    {
      "id": "b1",
      "type": "block",
      "blockTypeId": "discussion",
      "title": "Was lief gut?",
      "duration": 20,
      "notes": "",
      "material": ""
    }
  ]
}
```

Erfolgsantwort (HTTP 200; der Link ist hier nur ein Platzhalter):

```json
{
  "link": "https://sessionplan.de/#data=v2:...",
  "summary": { "title": "Produkt-Retrospektive", "blockCount": 1, "totalDuration": 20 }
}
```

`blockCount` zählt alle `block`-Items im gesamten Baum, ohne Container.
`totalDuration` summiert die expliziten `duration`-Werte der **Top-Level-Items**.
Gruppen und Breakouts tragen ihre eigene Dauer einmal bei; der Encoder berechnet
sie nicht aus den Kindern neu. Zeitlücken durch `fixedStartTime` sind nicht enthalten.

## Link zurück in JSON umwandeln

Bevorzugter Aufruf:

```http
POST /data/decode.php
Content-Type: application/json
```

Body: `{ "link": "<vollständiger Snapshot-Link>" }`.
Akzeptiert werden der vollständige URL-Link, der Hash `#data=v2:...` oder der Code
`v2:...`. Der Decoder liest den eingebetteten Snapshot und ruft die URL nicht ab.
Dynamische Server-Links und ältere Snapshot-Codes ohne `v2:` werden nicht unterstützt.

Die Antwort ist das vollständige Sessionplan-Dokument als Top-Level-Objekt,
**ohne** umschließendes `session`-Feld. MCP liefert es dagegen unter
`result.structuredContent.session`.

### GET für bestehende Integrationen

`GET /data/decode.php?link=<URL-kodierter Wert>` bleibt verfügbar. Den kompletten
Parameterwert einschließlich `#` und `+` kodieren. Beispiel in JavaScript:

```js
const query = new URLSearchParams({ link: snapshotLink });
const response = await fetch(`https://sessionplan.de/data/decode.php?${query}`);
```

POST vermeidet, dass der Snapshot in Anfrage-URLs, Browser-Verläufen oder
Webserver-Zugriffslogs erscheint. `Cache-Control: no-store` verhindert keine
Zugriffsprotokollierung. Beide Methoden akzeptieren zusätzlich die älteren Aliasse
`hash`, `code` und `data`; bei mehreren Angaben gilt die Reihenfolge
`link`, `hash`, `code`, `data`. Der gewählte Wert muss ein String sein.

## Änderung eines Plans

1. Bestehenden Snapshot dekodieren.
2. Das vollständige Dokument ändern.
3. Das vollständige Dokument erneut kodieren.
4. Den neuen `link` exakt wie empfangen zurückgeben.

Der vorherige Snapshot bleibt unverändert. Es gibt keine Patch-Operation, keine
Liste gespeicherter Sessions und keine Löschoperation für Snapshot-Links.

## Validierung und Kompatibilität

Erzeuge vollständige Dokumente gemäß dem veröffentlichten Schema. Datum und
Uhrzeit der Session sind optional; verwende `null`, wenn sie nicht feststehen.
Angegebene Datums- und Zeitwerte müssen gültig sein.
Die Dokumentversion `1.0`,
der Link-Codec `v2` und MCP-Protokollversionen sind voneinander unabhängig.

- Oben: `block`, `group` oder `breakout`.
- Gruppen: `children` mit Blöcken oder Breakouts; keine Untergruppen.
- Breakouts: `children` ausschließlich mit Blöcken.
- Blöcke: kein `children`-Feld.
- Container: ein `children`-Array angeben.
- Item-IDs sind im gesamten Baum eindeutig; Blocktyp- und Personen-IDs innerhalb
  ihrer jeweiligen Liste. Alle referenzierten Kategorien und Personen müssen
  in `blockTypes` bzw. `persons` angegeben werden.
- `lanePersons` bleibt ein JSON-Objekt mit nichtnegativen Lane-Schlüsseln und
  Arrays von Personen-IDs. `lanes` liegt zwischen 1 und 10 (Standard: 2), `laneIndex` ist standardmäßig 0.
  Indizes müssen kleiner als die Lane-Anzahl sein. Bei `sameInAllBreakouts: true`
  liegen alle Kinder auf Lane 0.

Gib immer `version`, `workshop`, `blockTypes`, `persons` und `items` an. Verwende
`"1.0"` als Version und `[]` für ungenutzte Kategorie-/Personenlisten. `workshop`
enthält `title` und `description`. Jedes Item enthält `id`, `type`, `blockTypeId`,
`title`, `duration`, `notes` und `material`. Für eine nicht zugewiesene Kategorie
verwende `null`, für leere Beschreibung, Notizen und Material `""`. Kategorien und
Personen enthalten jeweils `id`, `name` und `color`. Verwende nur dokumentierte Felder.

Der Server verarbeitet Bestandsdaten nachsichtig. Diese Kompatibilitätsbehandlung
ist keine Vorlage für neu erzeugte Dokumente. Decoder-Antworten können erhaltene
Bestandsfelder enthalten und haben deshalb ein eigenes Antwortschema. Beim Erzeugen
oder Überarbeiten einer Session gilt das kanonische Eingabeschema.

## Limits und HTTP-Fehler

- Höchstens **500 Items im gesamten Baum**, einschließlich aller Container und Kinder.
- Request-Body und unkomprimiertes Session-JSON: jeweils höchstens **2.000.000 Bytes**.
- Komprimierter Payload nach `v2:`: höchstens **750.000 Zeichen**.
- Zusätzliche Codec-Budgets: 4.000.000 Bytes UTF-16-Arbeitsausgabe, 65.536 Dictionary-
  Einträge und 8.000.000 Bytes Dictionary-Inhalt. Auch diese können einen Größenfehler auslösen.
- Pro Endpunkt und IP: **60 Anfragen pro 60-Sekunden-Fenster**.

Alle Antworten sind JSON und tragen `Cache-Control: no-store`. Fehler haben die
Form `{ "error": "Beschreibung" }`. Validierungsfehler nennen den Feldpfad,
z. B. `session.items[0].duration`. Fehlermeldungstexte sind keine stabilen Fehlercodes.

| HTTP | Bedeutung | Reaktion |
|---|---|---|
| 400 | Ungültiges JSON, Dokument oder Snapshot | Angegebenes Feld bzw. Eingabe korrigieren |
| 405 | HTTP-Methode nicht erlaubt | Encode: POST; Decode: POST oder GET |
| 413 | Größen- oder Codec-Limit erreicht | Session kürzen oder aufteilen |
| 415 | Content-Type bei POST fehlt oder ist falsch | `application/json` verwenden |
| 429 | Rate-Limit erreicht | `Retry-After: 60` beachten |
| 500 | Interner Verarbeitungsfehler | Später erneut versuchen |
| 503 | Rate-Limit-Speicher nicht verfügbar | Später erneut versuchen |

Browser-CORS ist für `https://sessionplan.de` freigegeben; bei `SP_ENV=development`
zusätzlich für HTTP(S) localhost und 127.0.0.1 mit optionalem Port. Serverseitige
Integrationen benötigen keinen Origin-Header. OPTIONS liefert HTTP 204.

Vor der Ausgabe einer KI-generierten Agenda Gesamtdauer, Pausen und Reihenfolge
prüfen. Der Nutzer kann den fertigen Plan anschließend im Browser bearbeiten.
