kisenon

Event-Streams

Server-Sent Events für Org- und Projektaktivität.

Kisenon streamt Organisations- und Projektaktivität als Server-Sent Events. Öffnen Sie eine langlebige HTTP-Verbindung, setzen Sie Accept: text/event-stream, und die Control Plane pusht jedes Mal eine JSON-Hülle, wenn sich etwas ändert.

Die Konsole treibt ihre Live-Aktivitätsansichten aus genau demselben Stream.

Endpoints

Zwei Routen, beide SSE:

RouteScope
GET /v1/eventsJedes Projekt in der Organisation des Aufrufers.
GET /v1/projects/{id}/eventsEin einzelnes Projekt.

Beide liegen unter https://api.test.kisenon.com. Die projektbezogene Route gibt 404 zurück, wenn das Projekt nicht zu Ihrer Organisation gehört, sodass Existenz niemals über Orgs hinweg durchsickert.

Auth

Dieselbe Bearer-Anmeldeinformation wie bei jedem anderen Control-Plane-Aufruf: ein API-Schlüssel (nsk_…) oder ein cp-signiertes Web-JWT. Siehe Auth. Der Aufrufer muss Mitglied der Organisation sein; Nicht-Mitglieder erhalten ein 403.

Event-Hülle

Jedes Event ist ein JSON-Objekt mit einer stabilen Form:

FeldTypBedeutung
idstringULID (26 Zeichen). Monoton; dient zugleich als SSE-Event-ID.
typestringEvent-Typ, z. B. operation.updated.v1.
sourcestringErzeugendes Subsystem, z. B. operations.
org_idstringBesitzende Organisation (UUID-Text).
project_idstring?Besitzendes Projekt; bei Events auf Org-Ebene weggelassen.
region_idstringRegion, die das Event emittiert hat.
atstringRFC-3339-Zeitstempel.
dataobjectTypspezifische Payload.

Die Hüllenform ändert sich niemals inkompatibel. Neue Felder sind additiv, und neue Event-Varianten erhalten einen neuen type (z. B. ein zukünftiges operation.updated.v2), statt einen bestehenden zu mutieren.

Event-Typen

Heute publiziert die Control Plane einen Anwendungs-Event-Typ:

  • operation.updated.v1 (Quelle operations) — eine Operation hat ihren Lebenszyklus-Zustand geändert. data führt operation_id, action, status und, wenn die Zeile noch vorhanden ist, branch_id, endpoint_id, error und initiator mit.

Der Broker emittiert außerdem drei interne Kontroll-Events (Quelle _broker):

  • resume.gap.v1 — Ihre Last-Event-ID ist älter als der Puffer des Brokers; Events wurden verpasst. Holen Sie den vollständigen Zustand via REST neu, dann fahren Sie mit dem Streaming fort.
  • overflow.v1 — Ihr Client hat zu langsam gelesen und wurde verworfen; data.dropped zählt die verlorenen Events. Verbinden Sie sich neu und holen Sie den vollständigen Zustand neu.
  • error.v1 — ein produzentenseitiger Fehler-Marker.

Die Quellen audit, invitations und billing sind reserviert, emittieren aber noch keine Events; diese Liste wächst, sobald diese Tracks ausgeliefert werden.

Wiederaufnahme

Die id jedes Events ist seine SSE-ID, sodass ein nativer EventSource automatisch die letzte als Last-Event-ID-Header bei der Wiederverbindung erneut sendet, und der Broker spielt alles danach Gepufferte erneut ab. Sie können sie auch explizit übergeben:

Last-Event-ID: 01JX5N4R8ZT2W7Q9V3B1C6D8EF

Wenn die Lücke breiter ist als der In-Memory-Ring des Brokers, erhalten Sie einen resume.gap.v1 statt eines Replays. Behandeln Sie das (und overflow.v1) als „Sie haben Events verpasst": Holen Sie den betroffenen Zustand über die REST-API neu, dann nehmen Sie das Streaming ab der neuesten ID wieder auf.

Beispiel

curl -N -H "Authorization: Bearer $KISENON_API_KEY" \
  -H "Accept: text/event-stream" \
  https://api.test.kisenon.com/v1/events

Ein gestreamtes Event sieht so aus:

id: 01JX5N4R8ZT2W7Q9V3B1C6D8EF
event: operation.updated.v1
data: {"id":"01JX5N4R8ZT2W7Q9V3B1C6D8EF","type":"operation.updated.v1","source":"operations","org_id":"6f1d2c3b-4a59-4e87-9b10-2d3e4f5a6b7c","project_id":"prj_4c1d9e2a7b3f5c8d0e1f2a3b","region_id":"home-proxmox","at":"2026-06-03T12:00:00Z","data":{"operation_id":"op_77a1","action":"create_branch","status":"finished","branch_id":"br_91c2"}}

Zeilen, die mit : beginnen (z. B. : keepalive), sind Heartbeat-Kommentare; ignorieren Sie sie.

In der Konsole

Die Live-Aktivitätsansichten der Konsole konsumieren genau diesen Stream (proxiert durch den Konsolen-Origin, da ein Browser-EventSource keinen Authorization-Header setzen kann). Bei resume.gap.v1 oder overflow.v1 holt sie den vollständigen Zustand über REST neu — genau der Vertrag oben. Wenn Sie Ihren eigenen Consumer bauen, spiegeln Sie dieses Verhalten.

Verwandtes