# Notifications API

REST endpoint für externe Systeme (z. B. Monitoring, IoT-Sensoren, Ticket-Gateways, LIMS-Adapter), um In-App-Benachrichtigungen an Nutzer der Organisation zu pushen.

Typischer Anwendungsfall: „Temperatur am Kühlschrank X überschritten" → Notification an alle Admins der Org.

## Auth

`Authorization: Bearer <api_key>` — API-Key mit **`write`**-Scope erforderlich (`read` genügt nur für GET).

## `POST /v1/notifications`

Erstellt eine Notification pro Ziel-Nutzer.

### Body

```json
{
  "title": "Temperaturalarm Kühlschrank K-04",
  "body": "Aktuell 12.3 °C — Soll ≤ 8 °C. Bitte prüfen.",
  "notification_type": "temperature_alarm",
  "link_url": "https://monitor.example.com/alerts/4711",
  "role": "admin"
}
```

| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| `title` | string (1–200) | ✅ | Kurze Überschrift, wird prominent angezeigt. |
| `body` | string (≤ 2000) | – | Freitext. |
| `notification_type` | string (≤ 64) | – | Kanal/Kategorie, Default `external`. Frei wählbar, z. B. `temperature_alarm`, `door_open`, `qc_out_of_spec`. |
| `link_url` | https-URL (≤ 2000) | – | Klick-Ziel. Nur `http(s)`. |
| `entry_id` | uuid | – | Optionaler Bezug auf einen ELN-Eintrag. |
| `user_id` | uuid | ⚠️ 1 von 3 | Ziel: einzelner Nutzer. |
| `user_ids` | uuid[] (1–500) | ⚠️ 1 von 3 | Ziel: Liste von Nutzern. |
| `role` | string | ⚠️ 1 von 3 | Ziel: alle Nutzer mit dieser Rolle in der Org (z. B. `admin`, `dept_admin`, `researcher`, `qm`). |

Genau eine der Zielangaben (`user_id` / `user_ids` / `role`) muss vorhanden sein. Nutzer, die nicht Mitglied der Org sind, werden serverseitig herausgefiltert.

### Response `201`

```json
{
  "data": {
    "created": 3,
    "notification_ids": ["...", "...", "..."]
  }
}
```

### Fehlercodes

| Status | Code | Ursache |
|---|---|---|
| 400 | `validation_failed` | Body-Validierung fehlgeschlagen. |
| 400 | `invalid_link_url` | `link_url` ist kein http(s)-Link. |
| 400 | `no_valid_targets` | Keiner der Empfänger ist Mitglied der Org. |
| 403 | `insufficient_scope` | Token ohne `write`-Scope. |
| 409 | `idempotency_key_conflict` | `Idempotency-Key` bereits mit anderem Body verwendet. |

### Idempotenz

Header `Idempotency-Key: <uuid>` unterstützt (24 h TTL). Wiederholte Requests mit gleichem Key und gleichem Body liefern die ursprüngliche Response mit `Idempotent-Replay: true` zurück.

## `GET /v1/notifications`

Listet die Notifications des aufrufenden Nutzers (nur sinnvoll bei Personal Access Tokens — API-Keys ohne Nutzerbindung erhalten eine leere Liste).

Query: `limit` (Default 50, max 200).

```json
{
  "data": [
    {
      "id": "...",
      "notification_type": "temperature_alarm",
      "title": "…",
      "body": "…",
      "link_url": "…",
      "entry_id": null,
      "read_at": null,
      "created_at": "2026-07-04T09:12:31Z"
    }
  ],
  "count": 1
}
```

## Beispiel: curl

```bash
curl -X POST "https://<project>.supabase.co/functions/v1/api-v1/v1/notifications" \
  -H "Authorization: Bearer $LABNOTE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f2f5e2c-7a11-4c8a-9a01-fridge-k04-2026-07-04T09-12" \
  -d '{
    "title": "Temperaturalarm Kühlschrank K-04",
    "body": "12.3 °C um 09:12 (Soll ≤ 8 °C)",
    "notification_type": "temperature_alarm",
    "link_url": "https://monitor.example.com/alerts/4711",
    "role": "admin"
  }'
```
