# todo · edumento – Bot-Schnittstelle (REST /api/v1)

Basis-URL: `https://todo.edumento.ch/api/v1`
Format: JSON (UTF-8). Zeiten in ISO 8601 (UTC), Datum `YYYY-MM-DD`, Uhrzeit `HH:MM` (Europe/Zurich gemeint).

## Anmeldung

Jeder Bot hat einen eigenen Schlüssel (`tdk_live_…`). Er wird in der App unter **Einstellungen → Bot-Schnittstelle** erzeugt, nur einmal angezeigt und nur als Hash gespeichert. Widerrufen geht dort jederzeit.

```
Authorization: Bearer tdk_live_…
```

Ein Schlüssel gehört genau einem Benutzer und sieht nur dessen To-dos. Hat der Schlüssel einen Standard-Bereich (z. B. `schule`), wird er beim Anlegen verwendet, wenn `area` fehlt. Limit: 120 Anfragen pro Minute und Schlüssel.

## Datenmodell `todo`

| Feld | Typ | Hinweis |
|---|---|---|
| `id` | UUID | fest, von der App vergeben |
| `ref` | string | Kurzkennung wie `T105` (für Menschen/Chat). **Seit 14.11.2026 zählen T-Nummern pro Bereich**, dieselbe Nummer kann es in mehreren Bereichen geben. |
| `area_ref` | string | neu 14.11.2026: eindeutige Kurzkennung `bereich:T105`, z. B. `schule:T105` |
| `area_id` | UUID | Bereich (wie bisher) |
| `external_id` | string \| null | eure eigene ID für den Abgleich (eindeutig pro Benutzer, max. 200 Zeichen) |
| `title` | string | 1–500 Zeichen |
| `area` | string (Slug) | Schlüssel des Bereichs. Die drei bestehenden Bots senden weiterhin `privat`, `edumental` bzw. `schule`. Weitere Slugs siehe `GET /areas`. |
| `status` | `offen` \| `arbeit` \| `wartet` \| `erledigt` | Standard `offen` |
| `prio` | `hoch` \| `mittel` \| `tief` | Standard `mittel` |
| `gemerkt` | boolean | optional, Standard `false`. «Merken»-Flagge aus der App (neu 11.11.2026; ältere Clients können das Feld ignorieren) |
| `due` | `YYYY-MM-DD` \| null | |
| `time` | `HH:MM` \| null | |
| `tags` | string[] | max. 20 |
| `notes` | string | max. 20 000 Zeichen |
| `subtasks` | `[{ "t": "Text", "done": false }]` | max. 100 |
| `source`, `source_label` | string | `bot` + Name des Schlüssels, `user` oder `ai` |
| `file_count` | number | Anzahl Anhänge |
| `created_at`, `updated_at`, `completed_at` | ISO-Zeit | |

## Endpunkte

| Methode | Pfad | Zweck |
|---|---|---|
| GET | `/me` | Prüft den Schlüssel (Name, Standard-Bereich) |
| GET | `/areas` | Bereiche des Kontos: `slug`, `name`, `sync_type` (`lokal`, `ki`, später `google`/`outlook`, erweiterbar) |
| GET | `/todos` | Liste. Filter: `area`, `status`, `updated_since` (ISO-Zeit), `external_id`, `limit` (max. 5000) |
| GET | `/todos/{id}` | Ein To-do inkl. `history` und `files`. `{id}` = UUID, `T105` oder `schule:T105` (siehe «Kennungen») |
| POST | `/todos` | Anlegen. `409`, wenn `external_id` schon existiert (Antwort enthält das bestehende To-do) |
| PUT | `/todos/external/{external_id}` | **Upsert**: anlegen oder ändern über eure ID (empfohlen für den Abgleich) |
| PATCH | `/todos/{id}` | Ändern (nur mitgeschickte Felder) |
| POST | `/todos/{id}/complete` | Abhaken |
| POST | `/todos/{id}/reopen` | Wieder öffnen |
| POST | `/todos/{id}/comments` | Eintrag im Verlauf: `{ "text": "…" }` |

## Kennungen `{id}` (T-Nummern pro Bereich, seit 14.11.2026)

- `{id}` darf sein: UUID (immer eindeutig, empfohlen für gespeicherte Verweise), `T105` / `105`, oder mit Bereich `schule:T105` bzw. `<bereich-uuid>:T105`. Statt im Pfad kann der Bereich auch als `?area=schule` (Slug oder Bereichs-UUID) mitgeschickt werden.
- Neue To-dos bekommen die nächste freie Nummer **in ihrem Bereich** (eindeutig pro Bereich). Bestehende Nummern wurden nicht geändert.
- **Schlüssel mit Standard-Bereich** (alle drei bestehenden To-do-Bots) suchen `T105` nur in ihrem Bereich – für sie ändert sich nichts.
- **Schlüssel ohne Bereich:** Gibt es `T105` in mehreren sichtbaren Bereichen, antwortet die API mit `409` und `{ "error": "…", "candidates": [{ "id", "ref", "area_ref", "area", "area_id", "title" }] }`. Dann mit `schule:T105`, `?area=schule` oder der UUID wiederholen.
- Wird ein To-do in einen anderen Bereich verschoben, behält es seine Nummer, wenn sie dort frei ist, sonst bekommt es die nächste freie (Verlaufseintrag «Kennung T105 → T231»). Die UUID bleibt immer gleich.

Jede Änderung durch einen Bot erscheint im Verlauf des To-dos («Bot To-do · Schule: Fällig → Fr 14.11.»).

## Idempotenz

Für `POST`, `PUT`, `PATCH` kann der Header `Idempotency-Key: <8–200 Zeichen>` mitgeschickt werden. Wiederholt der Bot dieselbe Anfrage mit demselben Schlüssel (z. B. nach einem Timeout), wird nichts doppelt angelegt: Die App liefert die gespeicherte Antwort zurück (Header `Idempotent-Replay: true`). Schlüssel gelten 24 Stunden. Derselbe Schlüssel für eine andere Anfrage → `422`.

## Beispiele

```bash
KEY=tdk_live_…
# Prüfen
curl -s https://todo.edumento.ch/api/v1/me -H "Authorization: Bearer $KEY"

# Anlegen oder aktualisieren über eigene ID (empfohlen)
curl -s -X PUT https://todo.edumento.ch/api/v1/todos/external/mail-1a177862 \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: mail-1a177862-v1" \
  -d '{"title":"Digitec: Bestellnummer nachreichen","area":"edumental","prio":"hoch","due":"2026-11-12","tags":["Digitec"],"notes":"Ref. 26147260"}'

# Seit dem letzten Abgleich geänderte To-dos holen
curl -s "https://todo.edumento.ch/api/v1/todos?updated_since=2026-11-11T17:00:00Z" -H "Authorization: Bearer $KEY"

# Abhaken
curl -s -X POST https://todo.edumento.ch/api/v1/todos/T105/complete -H "Authorization: Bearer $KEY"
```

## Fehler

`{ "error": "Text", "details": [...] }` mit Status `400` (ungültig), `401` (Schlüssel fehlt/ungültig/widerrufen), `403` (Konto gesperrt), `404`, `409` (external_id doppelt oder T-Nummer mehrdeutig), `422` (Idempotency-Key-Konflikt), `429` (Limit).


## Bereiche

Bereiche sind pro Konto. `area` ist der unveränderliche Schlüssel (Slug), nicht der Anzeigename. `GET /areas` liefert die aktuelle Liste. Die drei To-do-Bots bleiben rückwärtskompatibel: sie senden weiter `privat` / `edumental` / `schule`. Ein unbekannter Slug wird mit `400` abgelehnt. `sync_type` beschreibt die Herkunft (`lokal`, `ki`, vorbereitet: `google`, `outlook`); die Bot-API ändert daran nichts.

## Empfohlener Abgleich für die drei To-do-Bots

1. Jeder Bot nutzt seinen eigenen Schlüssel (Privat / Schule / edumental) mit passendem Standard-Bereich.
2. Neue oder geänderte Aufgaben: `PUT /todos/external/{eure-id}` mit `Idempotency-Key`.
3. Änderungen von Roy in der App abholen: periodisch `GET /todos?updated_since=<letzter Abgleich>` und lokal übernehmen (z. B. erledigt, verschoben).
4. Wichtige Ereignisse ohne Feldänderung: `POST /todos/{id}/comments`.
