Aktualisiere Doku und gleiche /api/v1-Toolsliste mit /api/v1/meta an
- docs/PLAYER-STATUS-HTTP.md vollstaendig neu strukturiert: q=, derived_state=, DELETE-Endpoint und Datei-Persistenz ergaenzt, Abgrenzung "keine dauerhafte Speicherung" entfernt - GET /api/v1 listet jetzt dieselben 5 Tools wie /api/v1/meta (player-status-ingest und screen-status-delete ergaenzt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
56635554c7
commit
a99f8a5784
3 changed files with 121 additions and 75 deletions
|
|
@ -4,42 +4,45 @@
|
|||
|
||||
Dieses Dokument beschreibt den ersten bewusst kleinen Statuspfad zwischen `player/agent` und `server/backend`.
|
||||
|
||||
Er ist fuer die aktuelle Entwicklungsstufe gedacht und noch kein finales Persistenz-, Authentifizierungs- oder MQTT-Modell.
|
||||
Er ist fuer die aktuelle Entwicklungsstufe gedacht und noch kein finales Authentifizierungs- oder MQTT-Modell.
|
||||
|
||||
## V1-Dev-Entscheidung
|
||||
|
||||
- der Agent sendet zunaechst Statusdaten per HTTP an das Backend
|
||||
- das Backend validiert und bestaetigt den Request und haelt den letzten bekannten Status pro Screen in-memory vor
|
||||
- das Backend validiert und bestaetigt den Request und haelt den letzten bekannten Status pro Screen vor
|
||||
- der Pfad dient als erste echte Backend-Agent-Integration vor Registration, Sync und MQTT
|
||||
|
||||
## Endpoint
|
||||
## Endpoints im Ueberblick
|
||||
|
||||
- `POST /api/v1/player/status`
|
||||
| Methode | Pfad | Beschreibung |
|
||||
|----------|---------------------------------------|-------------------------------------|
|
||||
| POST | /api/v1/player/status | Statusingest vom Player-Agent |
|
||||
| GET | /api/v1/screens/status | JSON-Uebersicht aller Screens |
|
||||
| GET | /api/v1/screens/{screenId}/status | JSON-Detail fuer einen Screen |
|
||||
| DELETE | /api/v1/screens/{screenId}/status | Screen-Eintrag loeschen |
|
||||
| GET | /status | HTML-Diagnoseseite (Uebersicht) |
|
||||
| GET | /status/{screenId} | HTML-Diagnoseseite (Einzelscreen) |
|
||||
|
||||
## Request-Felder
|
||||
## POST /api/v1/player/status
|
||||
|
||||
Mindestens enthalten:
|
||||
### Request-Felder
|
||||
|
||||
Pflichtfelder:
|
||||
|
||||
- `screen_id`
|
||||
- `ts`
|
||||
- `status`
|
||||
|
||||
Fuer die aktuelle Entwicklungsstufe sind zulaessig:
|
||||
|
||||
- `ts` (RFC3339-Zeitstempel)
|
||||
- `status`: `starting`, `running`, `stopped`
|
||||
- `heartbeat_every_seconds` (positive Ganzzahl)
|
||||
|
||||
Optionale Felder:
|
||||
|
||||
- `server_connectivity`: `unknown`, `online`, `degraded`, `offline`
|
||||
- `heartbeat_every_seconds`: positive Ganzzahl
|
||||
|
||||
Aktuell zusaetzlich enthalten:
|
||||
|
||||
- `server_connectivity`
|
||||
- `server_url`
|
||||
- `mqtt_broker`
|
||||
- `heartbeat_every_seconds`
|
||||
- `started_at`
|
||||
- `last_heartbeat_at`
|
||||
- `started_at` (RFC3339-Zeitstempel)
|
||||
- `last_heartbeat_at` (RFC3339-Zeitstempel)
|
||||
|
||||
## Beispiel
|
||||
### Beispiel
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -55,99 +58,132 @@ Aktuell zusaetzlich enthalten:
|
|||
}
|
||||
```
|
||||
|
||||
## Antwort
|
||||
|
||||
Bei gueltigem Request liefert das Backend aktuell:
|
||||
### Antwort
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "accepted"
|
||||
}
|
||||
{ "status": "accepted" }
|
||||
```
|
||||
|
||||
Bei ungueltigen Requests wird wie bei den anderen API-Endpunkten der gemeinsame Fehlerumschlag verwendet.
|
||||
Bei ungueltigen Requests wird der gemeinsame Fehlerumschlag verwendet.
|
||||
|
||||
## Aktueller Read-Pfad
|
||||
## GET /api/v1/screens/status
|
||||
|
||||
Zusätzlich zur Write-Route gibt es in dieser Stufe:
|
||||
Liefert eine Uebersicht aller bisher berichtenden Screens mit ihrem jeweils letzten bekannten Datensatz.
|
||||
|
||||
- `GET /status`
|
||||
- `GET /api/v1/screens/status`
|
||||
- `GET /api/v1/screens/{screenId}/status`
|
||||
Die Antwort enthaelt:
|
||||
|
||||
`GET /status` liefert eine kleine serverseitig gerenderte HTML-Statusseite fuer den Browser.
|
||||
Sie nutzt dieselbe in-memory Statusuebersicht wie die JSON-Endpunkte und ist als erste sichtbare Diagnoseoberflaeche gedacht.
|
||||
- `summary` mit kompakten Counts fuer `total`, `online`, `degraded`, `offline`, `stale`
|
||||
- `screens` sortiert nach Prioritaet: zuerst `offline`, dann `degraded`, dann `online`; innerhalb derselben Gruppe nach `screen_id`
|
||||
|
||||
Die Seite bietet aktuell bewusst nur leichte Diagnosehilfen auf Basis des bestehenden Read-Pfads:
|
||||
Die `summary` beschreibt immer den gesamten bekannten Statusbestand, unabhaengig von aktiven Filtern.
|
||||
Die `screens`-Liste wird durch die Query-Parameter eingeschraenkt.
|
||||
|
||||
- automatisches Refresh alle 15 Sekunden
|
||||
- Shortcut-Links fuer Connectivity- und Freshness-Filter wie `server_connectivity=offline|degraded` sowie `stale=true|false`
|
||||
- ein kleines Filterformular fuer dieselben Uebersichtsparameter wie im JSON-Read-Pfad
|
||||
- direkte JSON-Detail-Links pro Screen auf `GET /api/v1/screens/{screenId}/status`
|
||||
- einen Link zur aktuell gefilterten JSON-Uebersicht auf `GET /api/v1/screens/status`
|
||||
### Query-Parameter
|
||||
|
||||
`GET /api/v1/screens/status` liefert eine kleine Uebersicht aller bisher berichtenden Screens mit ihrem jeweils letzten bekannten Datensatz.
|
||||
Die Rueckgabe wird aktuell fuer Diagnosezwecke priorisiert sortiert: zuerst `offline`, dann `degraded`, dann `online`, innerhalb derselben Gruppe nach `screen_id`.
|
||||
Zusaetzlich enthaelt die Antwort eine `summary` mit kompakten Counts fuer `total`, `online`, `degraded`, `offline` und `stale`.
|
||||
| Parameter | Erlaubte Werte | Fehlercode bei Verstoß |
|
||||
|---------------------|-----------------------------------------|-------------------------------------|
|
||||
| `q` | beliebig (Substring-Suche, case-insen.) | – |
|
||||
| `derived_state` | `online`, `degraded`, `offline` | `invalid_derived_state` |
|
||||
| `server_connectivity` | `online`, `degraded`, `offline`, `unknown` | `invalid_server_connectivity` |
|
||||
| `stale` | `true`, `false` | `invalid_stale` |
|
||||
| `updated_since` | RFC3339-Zeitstempel | `invalid_updated_since` |
|
||||
| `limit` | positive Ganzzahl | `invalid_limit` |
|
||||
|
||||
Aktuell unterstuetzte Query-Parameter fuer die Uebersicht:
|
||||
`q` filtert nach Screen-ID-Substring (Gross-/Kleinschreibung wird ignoriert).
|
||||
|
||||
- `server_connectivity=<value>` zum Filtern nach Reachability-Zustand; erlaubte Werte: `online`, `offline`, `degraded`, `unknown`; ungueltige Werte liefern 400 (`invalid_server_connectivity`)
|
||||
- `stale=true|false` zum Filtern nach serverseitiger Veraltet-Einschaetzung; ungueltige Werte liefern 400 (`invalid_stale`)
|
||||
- `updated_since=<RFC3339>` zum Filtern nach `received_at`; ungueltige Zeitstempel liefern 400 (`invalid_updated_since`)
|
||||
- `limit=<positive integer>` zum Begrenzen der Anzahl zurueckgelieferter Screens; nicht-positive Werte liefern 400 (`invalid_limit`)
|
||||
Dieselben Parameter koennen sowohl an `GET /api/v1/screens/status` als auch an `GET /status` uebergeben werden, damit Browser-Ansicht und JSON-Uebersicht dieselbe Diagnosesicht teilen.
|
||||
|
||||
Die Query-Parameter beeinflussen die Liste in `screens`; die `summary` beschreibt weiterhin den gesamten aktuell bekannten Statusbestand.
|
||||
Dieselben Parameter koennen aktuell sowohl an `GET /api/v1/screens/status` als auch an `GET /status` verwendet werden, damit Browser-Ansicht und JSON-Uebersicht dieselbe Diagnose-Sicht teilen.
|
||||
## GET /api/v1/screens/{screenId}/status
|
||||
|
||||
`GET /status/{screenId}` liefert eine HTML-Detailseite fuer einen einzelnen Screen.
|
||||
Sie zeigt denselben Datensatz wie der JSON-Endpunkt – Derived State, Player-Status, Connectivity, Frische, Timestamps und Endpoints – in derselben visuellen Sprache wie die Uebersichtsseite.
|
||||
Bei unbekanntem Screen liefert sie 404 mit einer erklaerenden HTML-Fehlermeldung und einem Rueck-Link auf `/status`.
|
||||
|
||||
Fehlerfall bei ungueltigem Query-Parameter auf `/status` (z.B. `?stale=banana`): statt rohem JSON liefert der Endpunkt jetzt eine HTML-Fehlerseite mit erklaerenden Hinweisen und einem Rueck-Link.
|
||||
|
||||
`GET /api/v1/screens/{screenId}/status` liefert den zuletzt akzeptierten Status fuer einen einzelnen Screen zurueck.
|
||||
Liefert den zuletzt akzeptierten Status fuer einen einzelnen Screen.
|
||||
Wenn fuer den Screen noch kein Status vorliegt, liefert das Backend `404` mit dem gemeinsamen Fehlerumschlag.
|
||||
|
||||
Der aktuell zurueckgelieferte Datensatz enthaelt damit sowohl den Lifecycle-Status (`status`) als auch den vom Agenten lokal abgeleiteten Reachability-Zustand (`server_connectivity`).
|
||||
Der Datensatz enthaelt neben den gespeicherten Feldern:
|
||||
|
||||
Zusaetzlich fuegt das Backend im Read-Pfad derzeit hinzu:
|
||||
- `received_at` – serverseitiger Annahmezeitpunkt des letzten gueltigen Reports
|
||||
- `stale` – ob der letzte Report bereits veraltet wirkt (mehr als zwei Heartbeat-Intervalle ohne neuen Report)
|
||||
- `derived_state` – zusammengefasste Diagnoseeinschaetzung (s.u.)
|
||||
|
||||
- `received_at` als serverseitigen Annahmezeitpunkt des letzten gueltigen Reports
|
||||
- `stale` als einfache serverseitige Einordnung, ob der letzte Report bereits veraltet wirkt
|
||||
- `derived_state` als zusammengefasste Diagnoseeinschaetzung fuer Konsumenten des Read-Pfads
|
||||
## DELETE /api/v1/screens/{screenId}/status
|
||||
|
||||
`stale` ist aktuell bewusst nur eine kleine Diagnosehilfe fuer die Entwicklungsstufe und noch kein vollstaendiges Online-/Offline-Modell fuer spaetere Admin-Oberflaechen.
|
||||
Die Schwelle wird derzeit einfach aus dem gemeldeten `heartbeat_every_seconds` abgeleitet: mehr als zwei Intervalle ohne neuen Report gelten als veraltet.
|
||||
Loescht den gespeicherten Statuseintrag fuer einen Screen endgueltig.
|
||||
Wenn kein Eintrag vorhanden ist, liefert das Backend `404`.
|
||||
|
||||
`derived_state` wird aktuell bewusst einfach abgeleitet:
|
||||
### Antwort
|
||||
|
||||
```json
|
||||
{ "status": "deleted" }
|
||||
```
|
||||
|
||||
## GET /status
|
||||
|
||||
Serverseitig gerenderte HTML-Diagnoseseite fuer den Browser.
|
||||
Nutzt dieselbe Statusuebersicht wie der JSON-Endpunkt.
|
||||
|
||||
- automatisches Refresh alle 15 Sekunden
|
||||
- Shortcut-Links fuer Connectivity- und Freshness-Filter
|
||||
- kleines Filterformular fuer dieselben Parameter wie beim JSON-Read-Pfad
|
||||
- direkte JSON-Detail-Links pro Screen
|
||||
|
||||
Bei ungueltigen Query-Parametern liefert `/status` eine HTML-Fehlerseite (kein JSON), damit Browser-Aufrufe direkt lesbare Hinweise erhalten.
|
||||
|
||||
## GET /status/{screenId}
|
||||
|
||||
HTML-Detailseite fuer einen einzelnen Screen.
|
||||
Zeigt denselben Datensatz wie `GET /api/v1/screens/{screenId}/status` (Derived State, Player-Status, Connectivity, Frische, Timestamps, Endpoints).
|
||||
|
||||
Bei unbekanntem Screen: 404 mit HTML-Fehlermeldung und Rueck-Link auf `/status`.
|
||||
|
||||
## Serverseitig abgeleitete Felder
|
||||
|
||||
### stale
|
||||
|
||||
Die Schwelle wird aus dem gemeldeten `heartbeat_every_seconds` abgeleitet: mehr als zwei Intervalle ohne neuen Report gelten als veraltet.
|
||||
|
||||
`stale` ist aktuell eine Diagnosehilfe fuer die Entwicklungsstufe und noch kein vollstaendiges Online-/Offline-Modell fuer Admin-Oberflaechen.
|
||||
|
||||
### derived_state
|
||||
|
||||
- `offline` bei `stale = true` oder `server_connectivity = offline`
|
||||
- `degraded` bei `server_connectivity = degraded|unknown` oder wenn `status` nicht `running` ist
|
||||
- `online` in den verbleibenden Faellen
|
||||
|
||||
## Persistenz
|
||||
|
||||
Der Status-Store kann dateibasiert betrieben werden.
|
||||
|
||||
Konfiguration ueber die Umgebungsvariable:
|
||||
|
||||
- `MORZ_INFOBOARD_STATUS_STORE_PATH` – Pfad zur JSON-Datei; leer lassen fuer reinen In-Memory-Betrieb
|
||||
|
||||
Beim Datei-Store gilt:
|
||||
|
||||
- beim Start wird die Datei eingelesen, falls sie vorhanden ist (fehlende Datei ist kein Fehler)
|
||||
- bei jedem `Save` und `Delete` wird der Inhalt atomar in die Datei geschrieben (write + rename)
|
||||
- nach einem Neustart des Backends bleibt der letzte bekannte Statusbestand erhalten
|
||||
|
||||
## Agentseitige Connectivity-Ableitung
|
||||
|
||||
Agent-seitig wird die Server-Erreichbarkeit lokal als `unknown`, `online`, `degraded` oder `offline` aus dem Erfolg der HTTP-Reports abgeleitet.
|
||||
|
||||
Fuer den transportierten Wert im erfolgreichen HTTP-Report gilt:
|
||||
|
||||
- wenn ein Report vom Backend akzeptiert wurde, wird dieser Report selbst als `server_connectivity = online` gespeichert
|
||||
- anhaltende Ausfaelle werden primaer ueber lokale Agent-Zustaende und serverseitige `stale`-Ableitung sichtbar
|
||||
|
||||
## Abgrenzung
|
||||
|
||||
Noch nicht Teil dieser Stufe:
|
||||
|
||||
- dauerhafte Speicherung in Datenbank oder State-Store
|
||||
- Screen-Authentifizierung
|
||||
- MQTT-Heartbeat oder MQTT-Status
|
||||
- Admin-UI-Anzeige des letzten Status
|
||||
- Retry-Queue oder lokale Zwischenspeicherung im Agent
|
||||
|
||||
Agent-seitig wird die Server-Erreichbarkeit aktuell lokal als `unknown`, `online`, `degraded` oder `offline` aus dem Erfolg der HTTP-Reports abgeleitet.
|
||||
|
||||
Fuer den transportierten Wert im erfolgreichen HTTP-Report gilt aktuell bewusst einfach:
|
||||
|
||||
- wenn ein Report vom Backend akzeptiert wurde, wird dieser Report selbst als `server_connectivity = online` gespeichert
|
||||
- anhaltende Ausfaelle werden primaer ueber lokale Agent-Zustaende und serverseitige `stale`-Ableitung sichtbar
|
||||
|
||||
## Folgeschritte
|
||||
|
||||
Auf diesem Pfad bauen spaeter auf:
|
||||
|
||||
- Screen-Identitaet und Authentifizierung
|
||||
- persistierter letzter Heartbeat und letzter Status auf dem Server
|
||||
- Trennung zwischen HTTP-Snapshot und MQTT-Heartbeat
|
||||
- Admin-Vorschau fuer Online-/Offline- und Degraded-Zustaende
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ func NewRouter(store playerStatusStore) http.Handler {
|
|||
"message-wall-resolve",
|
||||
"screen-status-list",
|
||||
"screen-status-detail",
|
||||
"player-status-ingest",
|
||||
"screen-status-delete",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func TestRouterBaseAPI(t *testing.T) {
|
|||
t.Fatalf("version = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if got, want := len(response.Tools), 3; got != want {
|
||||
if got, want := len(response.Tools), 5; got != want {
|
||||
t.Fatalf("len(tools) = %d, want %d", got, want)
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +81,14 @@ func TestRouterBaseAPI(t *testing.T) {
|
|||
if got, want := response.Tools[2], "screen-status-detail"; got != want {
|
||||
t.Fatalf("tool[2] = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if got, want := response.Tools[3], "player-status-ingest"; got != want {
|
||||
t.Fatalf("tool[3] = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if got, want := response.Tools[4], "screen-status-delete"; got != want {
|
||||
t.Fatalf("tool[4] = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterMeta(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue