morz-infoboard/docs/API-ENDPOINTS.md
Jesko Anschütz aff12a4d81 Doku-Sync: README, TODO, DEVELOPMENT und API-Docs auf Implementierungsstand nachgezogen
README, DEVELOPMENT und TODO spiegelten noch den Stand vor Ebene 1+2 wider.
Checkboxen in TODO von ~18 auf ~70 aktualisiert, drei neue API-Dokumentationsdateien ergänzt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 09:55:36 +01:00

836 lines
17 KiB
Markdown

# Info-Board Neu - API-Endpoints Vollständig
## Überblick
Die Backend-API unterteilt sich in mehrere Bereiche:
- **Health & Meta**: System-Status und API-Informationen
- **Player Status**: Status-Ingest und Diagnose vom Player
- **Screen Management**: CRUD und Registrierung von Screens
- **Playlists**: Abruf und Verwaltung von Wiedergabelisten
- **Media**: Upload und Verwaltung von Medien-Assets
- **Message Wall**: Auflösung von Nachrichten-Wand-Anfragen
- **Admin & UI**: Web-Formulare und Provisionierung
- **Provisioning**: Erstinstallation neuer Screens (geplant)
---
## Health & Meta
### GET /healthz
Health-Check für Monitoring.
**Response:**
```json
{
"status": "ok",
"service": "morz-infoboard-backend"
}
```
### GET /api/v1
API-Entrypoint mit Tools-Übersicht.
**Response:**
```json
{
"name": "morz-infoboard-backend",
"version": "dev",
"tools": [
"message-wall-resolve",
"screen-status-list",
"screen-status-detail",
"player-status-ingest",
"screen-status-delete"
]
}
```
### GET /api/v1/meta
Zusätzliche Metainformationen (noch nicht spezifiziert).
---
## Player Status (Diagnose)
Siehe separate Dokumentation in `PLAYER-STATUS-HTTP.md`.
Endpoints:
- `POST /api/v1/player/status` — Status-Ingest vom Player-Agent
- `GET /api/v1/screens/status` — Übersicht aller Screen-Status
- `GET /api/v1/screens/{screenId}/status` — Einzelner Screen-Status
- `DELETE /api/v1/screens/{screenId}/status` — Status löschen
### POST /api/v1/player/status
Der Player-Agent sendet seinen aktuellen Status an den Server.
**Request-Body:**
```json
{
"screen_id": "info01-dev",
"ts": "2026-03-22T16:00:00Z",
"status": "running",
"server_connectivity": "online",
"server_url": "http://127.0.0.1:8080",
"mqtt_broker": "tcp://127.0.0.1:1883",
"heartbeat_every_seconds": 30,
"started_at": "2026-03-22T15:59:30Z",
"last_heartbeat_at": "2026-03-22T16:00:00Z"
}
```
**Response:**
```json
{ "status": "accepted" }
```
---
## Screen Management (JSON API)
### POST /api/v1/screens/register
Agent-Selbstregistrierung — wird vom Player-Agent beim Hochfahren aufgerufen.
Der Agent upsert den Screen automatisch im Default-Tenant ("morz"), so dass alle deployt Screen automatisch im Admin-UI erscheinen.
**Request-Body:**
```json
{
"slug": "info10",
"name": "Info10 Bildschirm",
"orientation": "landscape"
}
```
**Response:**
```json
{
"id": "uuid...",
"tenant_id": "uuid...",
"slug": "info10",
"name": "Info10 Bildschirm",
"orientation": "landscape",
"created_at": "2026-03-22T16:00:00Z",
"updated_at": "2026-03-22T16:00:00Z"
}
```
**Status:**
- `200 OK` — Screen wurde erzeugt oder aktualisiert (upsert)
- `400 Bad Request` — Slug fehlt oder ungültig
- `500 Internal Server Error` — DB-Fehler oder Default-Tenant nicht vorhanden
---
### GET /api/v1/tenants/{tenantSlug}/screens
Listet alle Screens eines Tenants auf.
**Response:**
```json
[
{
"id": "uuid...",
"tenant_id": "uuid...",
"slug": "info10",
"name": "Info10 Bildschirm",
"orientation": "landscape",
"created_at": "2026-03-22T16:00:00Z",
"updated_at": "2026-03-22T16:00:00Z"
},
...
]
```
**Status:**
- `200 OK` — Liste erfolgreich abrufen
- `404 Not Found` — Tenant nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
---
### POST /api/v1/tenants/{tenantSlug}/screens
Erstellt einen neuen Screen für einen Tenant (Admin-API).
**Request-Body:**
```json
{
"slug": "new-screen",
"name": "New Display",
"orientation": "portrait"
}
```
**Response:**
```json
{
"id": "uuid...",
"tenant_id": "uuid...",
"slug": "new-screen",
"name": "New Display",
"orientation": "portrait",
"created_at": "2026-03-22T16:00:00Z",
"updated_at": "2026-03-22T16:00:00Z"
}
```
**Status:**
- `201 Created` — Screen erstellt
- `400 Bad Request` — Slug oder Name fehlt
- `404 Not Found` — Tenant nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
---
## Playlist Management (JSON API)
### GET /api/v1/screens/{screenId}/playlist
Abruf der aktiven Playlist für einen Screen (Player-Sync).
Der Player ruft diesen Endpoint auf, um die aktuellen Inhalte zu laden.
**Response:**
```json
{
"playlist_id": "uuid...",
"default_duration_seconds": 20,
"items": [
{
"id": "uuid...",
"type": "web",
"src": "http://example.com/page1",
"title": "Startseite",
"duration_seconds": 30,
"enabled": true,
"valid_from": null,
"valid_until": null
},
{
"id": "uuid...",
"type": "image",
"src": "/uploads/banner.jpg",
"title": "Werbebanner",
"duration_seconds": 20,
"enabled": true,
"valid_from": null,
"valid_until": null
}
]
}
```
Wenn keine Playlist vorhanden ist, wird eine leere Liste zurückgegeben:
```json
{
"items": []
}
```
**Status:**
- `200 OK` — Playlist abrufen
- `404 Not Found` — Screen nicht vorhanden
---
### GET /api/v1/playlists/{screenId}
Abrufen einer kompletten Playlist mit Metadaten.
**Response:**
```json
{
"playlist": {
"id": "uuid...",
"screen_id": "uuid...",
"tenant_id": "uuid...",
"name": "Hauptplaylist",
"is_active": true,
"default_duration_seconds": 20,
"fallback_enabled": true,
"fallback_dir": "/fallback",
"shuffle_enabled": false,
"created_at": "2026-03-22T16:00:00Z",
"updated_at": "2026-03-22T16:00:00Z"
},
"items": [
{
"id": "uuid...",
"playlist_id": "uuid...",
"type": "web",
"src": "http://example.com",
"title": "Example",
"duration_seconds": 20,
"enabled": true,
"created_at": "2026-03-22T16:00:00Z"
}
]
}
```
**Status:**
- `200 OK` — Erfolgreich abrufen
- `500 Internal Server Error` — DB-Fehler
---
### POST /api/v1/playlists/{playlistId}/items
Fügt ein Item zu einer Playlist hinzu.
**Request-Body (Optionen A: Aus Media-Library):**
```json
{
"media_asset_id": "uuid...",
"title": "Optional überschriebener Titel"
}
```
**Request-Body (Optionen B: Direkte URL):**
```json
{
"type": "web",
"src": "http://example.com/page",
"title": "Example Page",
"duration_seconds": 30,
"valid_from": "2026-03-22T09:00:00Z",
"valid_until": "2026-03-22T17:00:00Z"
}
```
**Response:**
```json
{
"id": "uuid...",
"playlist_id": "uuid...",
"type": "web",
"src": "http://example.com/page",
"title": "Example Page",
"duration_seconds": 30,
"enabled": true,
"valid_from": "2026-03-22T09:00:00Z",
"valid_until": "2026-03-22T17:00:00Z",
"created_at": "2026-03-22T16:00:00Z"
}
```
**Status:**
- `201 Created` — Item erstellt
- `400 Bad Request` — Type oder Src fehlt; Media-Asset nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
---
### PATCH /api/v1/items/{itemId}
Aktualisiert ein Playlist-Item (Titel, Dauer, Zeitfenster, aktiviert).
**Request-Body:**
```json
{
"title": "Neuer Titel",
"duration_seconds": 25,
"enabled": true,
"valid_from": "2026-03-22T09:00:00Z",
"valid_until": "2026-03-22T17:00:00Z"
}
```
**Status:**
- `204 No Content` — Erfolgreich aktualisiert
- `400 Bad Request` — Ungültige Dauer
- `500 Internal Server Error` — DB-Fehler
---
### DELETE /api/v1/items/{itemId}
Löscht ein Playlist-Item.
**Status:**
- `204 No Content` — Erfolgreich gelöscht
- `500 Internal Server Error` — DB-Fehler
---
### PUT /api/v1/playlists/{playlistId}/order
Reordnet die Items einer Playlist anhand einer geordneten Liste von Item-IDs.
**Request-Body:**
```json
[
"item-id-1",
"item-id-2",
"item-id-3"
]
```
**Status:**
- `204 No Content` — Erfolgreich reordert
- `400 Bad Request` — JSON-Array erwartet
- `500 Internal Server Error` — DB-Fehler
---
### PATCH /api/v1/playlists/{playlistId}/duration
Setzt die Standard-Dauer für neue Items einer Playlist.
**Request-Body (Form-Encoded):**
```
default_duration_seconds=25
```
**Status:**
- `204 No Content` — Erfolgreich aktualisiert
- `400 Bad Request` — Ungültige oder fehlende Dauer
- `500 Internal Server Error` — DB-Fehler
---
## Media Management (JSON API)
### GET /api/v1/tenants/{tenantSlug}/media
Listet alle Medien-Assets eines Tenants auf.
**Response:**
```json
[
{
"id": "uuid...",
"tenant_id": "uuid...",
"title": "Banner Image",
"description": null,
"type": "image",
"source_kind": "upload",
"storage_path": "/uploads/1234567890_banner.jpg",
"original_url": null,
"mime_type": "image/jpeg",
"size_bytes": 102400,
"enabled": true,
"created_at": "2026-03-22T16:00:00Z",
"updated_at": "2026-03-22T16:00:00Z"
},
{
"id": "uuid...",
"tenant_id": "uuid...",
"title": "External Website",
"type": "web",
"source_kind": "remote_url",
"original_url": "http://example.com",
"storage_path": null,
"enabled": true,
"created_at": "2026-03-22T16:00:00Z"
}
]
```
Wenn keine Assets vorhanden sind, wird eine leere Liste zurückgegeben.
**Status:**
- `200 OK` — Liste erfolgreich abrufen
- `404 Not Found` — Tenant nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
---
### POST /api/v1/tenants/{tenantSlug}/media
Registriert ein neues Medien-Asset (Datei-Upload oder externe URL).
**Request-Typ A: Datei-Upload (Multipart)**
```
Content-Type: multipart/form-data
type: image (oder video, pdf)
title: Mein Bild
file: <binary data>
```
**Request-Typ B: Externe URL (Multipart)**
```
Content-Type: multipart/form-data
type: web
title: Externe Website
url: http://example.com
```
**Response:**
```json
{
"id": "uuid...",
"tenant_id": "uuid...",
"title": "Mein Bild",
"type": "image",
"source_kind": "upload",
"storage_path": "/uploads/1234567890_mein_bild.jpg",
"mime_type": "image/jpeg",
"size_bytes": 102400,
"enabled": true,
"created_at": "2026-03-22T16:00:00Z"
}
```
**Status:**
- `201 Created` — Asset erstellt
- `400 Bad Request` — Ungültiger Type, fehlende Datei/URL, oder Request zu groß (>512 MB)
- `404 Not Found` — Tenant nicht vorhanden
- `500 Internal Server Error` — Datei-/DB-Fehler
---
### DELETE /api/v1/media/{id}
Löscht ein Medien-Asset (und physische Datei falls lokal gespeichert).
**Status:**
- `204 No Content` — Erfolgreich gelöscht
- `404 Not Found` — Asset nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
---
## Message Wall
### POST /api/v1/tools/message-wall/resolve
Spezialendpoint zur Auflösung von Nachrichten-Wand-Anfragen (noch in Entwicklung).
---
## Admin UI (Web-Formulare)
### GET /admin
Administrations-Dashboard mit Übersicht aller Screens und Tenants.
Rückgabe: HTML-Seite mit:
- Liste aller Screens
- Status-Information
- Provisioning-Formulare
- Screen-Verwaltung
---
### POST /admin/screens/provision
Startet einen Provisionierungs-Job für einen neuen oder bestehenden Screen.
**Request-Body (Form-Encoded oder JSON):**
```json
{
"screen_id": "uuid...",
"target_ip": "192.168.1.100",
"target_port": 22,
"remote_user": "root",
"auth_mode": "password",
"provided_secret_ref": "secret-key-123"
}
```
**Status:**
- `200 OK` — Job erfolgreich erstellt
- `400 Bad Request` — Fehlende oder ungültige Parameter
- `404 Not Found` — Screen nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
**Hinweis:** Der eigentliche Provisionierungs-Job läuft asynchron über einen Worker ab.
---
### POST /admin/screens
Erstellt einen neuen Screen über das Admin-Formular.
**Request-Body (Form-Encoded):**
```
slug=new-screen&name=Neuer+Bildschirm&orientation=landscape
```
**Status:**
- `200 OK` oder `201 Created` — Screen erstellt
- `400 Bad Request` — Fehlende Parameter
- `500 Internal Server Error` — DB-Fehler
Rückleitung zur Admin-Seite.
---
### POST /admin/screens/{screenId}/delete
Löscht einen Screen.
**Status:**
- `200 OK` — Screen gelöscht
- `404 Not Found` — Screen nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
Rückleitung zur Admin-Seite.
---
## Playlist Management UI (Web-Formulare)
### GET /manage/{screenSlug}
Verwaltungs-UI für die Playlist eines Screens.
Rückgabe: HTML-Seite mit:
- Liste der Medien-Assets
- Playlist-Editor
- Upload-Formular
- Item-Verwaltung
---
### POST /manage/{screenSlug}/upload
Datei-Upload über das Manage-Formular.
**Request (Multipart):**
```
type: image (oder video, pdf)
title: Neues Bild
file: <binary data>
```
**Status:**
- `201 Created` — Asset erfolgreich hochgeladen
- `404 Not Found` — Screen nicht vorhanden
- `500 Internal Server Error` — Fehler
Rückleitung zum Manage-Formular.
---
### POST /manage/{screenSlug}/items
Fügt ein Item zur Playlist hinzu (Formular).
**Request (Form-Encoded):**
```
media_asset_id=uuid...&duration_seconds=25
oder
type=web&src=http://example.com&duration_seconds=30
```
**Status:**
- `201 Created` — Item erstellt
- `404 Not Found` — Screen nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
Rückleitung zum Manage-Formular.
---
### POST /manage/{screenSlug}/items/{itemId}
Aktualisiert ein Item (Formular).
**Request (Form-Encoded):**
```
title=Neuer+Titel&duration_seconds=25&enabled=on
```
**Status:**
- `200 OK` oder `204 No Content` — Erfolgreich aktualisiert
- `404 Not Found` — Item nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
Rückleitung zum Manage-Formular.
---
### POST /manage/{screenSlug}/items/{itemId}/delete
Löscht ein Item (Formular).
**Status:**
- `204 No Content` — Erfolgreich gelöscht
- `404 Not Found` — Item nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
Rückleitung zum Manage-Formular.
---
### POST /manage/{screenSlug}/reorder
Reordert Items (Formular).
**Request (Form-Encoded mit Array-Syntax):**
```
items=item-id-1&items=item-id-2&items=item-id-3
```
**Status:**
- `204 No Content` — Erfolgreich reordert
- `500 Internal Server Error` — DB-Fehler
Rückleitung zum Manage-Formular.
---
### POST /manage/{screenSlug}/media/{mediaId}/delete
Löscht ein Medien-Asset (Formular).
**Status:**
- `204 No Content` — Erfolgreich gelöscht
- `404 Not Found` — Asset nicht vorhanden
- `500 Internal Server Error` — DB-Fehler
Rückleitung zum Manage-Formular.
---
## Datei-Serving
### GET /uploads/{filename}
Stellt hochgeladene Medien-Dateien bereit.
**Query-Parameter:**
- Keine
**Status:**
- `200 OK` — Datei gefunden
- `404 Not Found` — Datei nicht vorhanden
---
## Diagnostic Pages (HTML)
### GET /status
HTML-Diagnoseseite für den Browser mit Übersicht aller Screen-Status.
- Automatisches Refresh alle 15 Sekunden
- Shortcut-Links für Filter
- Filterformular (wie JSON-Read-Pfad)
- Direkte JSON-Detail-Links pro Screen
**Query-Parameter:** Dieselben wie `GET /api/v1/screens/status`
- `q` — Screen-ID Substring-Suche
- `derived_state``online`, `degraded`, `offline`
- `server_connectivity``online`, `degraded`, `offline`, `unknown`
- `stale``true`, `false`
- `updated_since` — RFC3339-Zeitstempel
- `limit` — positive Ganzzahl
---
### GET /status/{screenId}
HTML-Detailseite für einen einzelnen Screen.
Zeigt:
- Screen-Information
- Derived State
- Player Status
- Connectivity
- Freshness und Timestamps
- Endpunkte und Links
---
## Player Local UI (Agent)
### GET /player
Zeigt die lokale Player-UI (HTML) auf dem Gerät.
Rückgabe: HTML-Seite mit:
- Splash-Screen
- Systeminformationen-Overlay
- Verbindungsstatus-Punkt
- Basis für Playlist-Anzeige
---
### GET /api/now-playing
JSON-API des Player-Agents (lokal).
**Response:**
```json
{
"playlist": [
{
"src": "http://backend.local/api/v1/screens/info10/playlist",
"type": "web",
"title": "Startseite",
"duration_seconds": 30
}
],
"status": "running",
"connectivity": "online"
}
```
---
### GET /api/sysinfo
Systeminformationen des Player-Agents (lokal).
**Response:**
```json
{
"items": [
{
"label": "Hostname",
"value": "infoboard-01"
},
{
"label": "Uptime",
"value": "5d 2h 30m"
}
]
}
```
---
## Fehlerbehandlung
Alle JSON-Responses folgen diesem Fehlermodell (falls implementiert):
```json
{
"error": {
"code": "error_code_here",
"message": "Human-readable error message",
"details": null
}
}
```
Typische HTTP-Status:
- `200 OK` — Erfolgreiche Anfrage (Read)
- `201 Created` — Ressource erstellt
- `204 No Content` — Erfolgreiche Anfrage ohne Response-Body
- `400 Bad Request` — Eingabe-Validierung fehlgeschlagen
- `404 Not Found` — Ressource nicht vorhanden
- `500 Internal Server Error` — Server-Fehler
---
## Änderungshistorie
- **2026-03-23:** Initiale Dokumentation aller HTTP-Endpoints basierend auf Code-Review
- Alle Screen-Management-Endpoints dokumentiert
- Alle Playlist-Management-Endpoints dokumentiert
- Alle Media-Management-Endpoints dokumentiert
- Admin-UI und Manage-UI-Endpoints dokumentiert
- Player-Status-Diagnostik dokumentiert
- Player-Local-API dokumentiert