{
    "openapi": "3.1.0",
    "info": {
        "title": "Arevano Suite API",
        "version": "0.1.0",
        "description": "Maschinenschnittstelle der Arevano Suite.\n\nDie Pfade folgen dem Frontend: aus `/app/console/namespaces` wird `/api/console/namespaces`.\n\nAngemeldet wird mit `Authorization: Bearer <Token>`. Ein Token gehört zu einer Person oder einem Dienst und kann nie mehr als dessen Konto."
    },
    "servers": [
        {
            "url": "https://www.arevano.com"
        }
    ],
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Suite-Token (arv_…) oder Keycloak-Zugangstoken"
            }
        }
    },
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "paths": {
        "/api/me": {
            "get": {
                "summary": "Wer bin ich",
                "description": "Gibt die erkannte Identität zurück: Konto, Herkunft der Anmeldung, Organisation, Scopes des Tokens.",
                "tags": [
                    "Allgemein"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "user_id": 42,
                                    "name": "TriskelA Console",
                                    "quelle": "token",
                                    "token_id": 7,
                                    "organization": 3,
                                    "scopes": [
                                        "console"
                                    ],
                                    "rollen": []
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                }
            }
        },
        "/api/console/clusters": {
            "get": {
                "summary": "Cluster auflisten",
                "description": "Alle Cluster, die der Identität bekannt sind.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "id": 1,
                                            "name": "cluster0",
                                            "region": "hel1"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                }
            }
        },
        "/api/console/namespaces": {
            "get": {
                "summary": "Namespaces auflisten",
                "description": "Namespaces eines Clusters, auf die die Identität Zugriff hat, mit der jeweiligen Rolle.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "namespace": "triskela-softlanding-prod",
                                            "role": "admin"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "description": "Kennung des Clusters",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/console/resources": {
            "get": {
                "summary": "Ressourcen eines Namespace",
                "description": "Workloads, Dienste, Routen, Zertifikate, Daten und Speicher eines Namespace — dieselbe Sicht wie im Designer, inklusive Zustand.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "type": "deployment",
                                            "name": "softlanding-api",
                                            "state": {
                                                "level": "ok",
                                                "message": "1 von 1 bereit"
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "description": "Name des Namespace",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": false,
                        "description": "Auf einen Typ einschränken, etwa deployment oder service",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/console/resource": {
            "get": {
                "summary": "Manifest einer Ressource",
                "description": "Das Manifest als YAML, bereinigt um Zustand und clusterspezifische Felder. Bei Secrets werden nur die Schlüsselnamen genannt, nie die Werte.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "type": "deployment",
                                    "name": "softlanding-api",
                                    "yaml": "apiVersion: …"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "name",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/console/logs": {
            "get": {
                "summary": "Log eines Pods",
                "description": "Die letzten Zeilen eines Containers. Ohne Container wird der erste genommen; mit previous=1 die Ausgabe des abgestürzten Vorgängers.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "pod": "api-7cbb…",
                                    "container": "api",
                                    "text": "…"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "pod",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "container",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "tailLines",
                        "in": "query",
                        "required": false,
                        "description": "Standard 200, höchstens 2000",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "previous",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/console/workload": {
            "post": {
                "summary": "Workload steuern",
                "description": "Neu starten oder die Zahl der Replikate setzen. Jede Änderung landet im Audit-Log.\n\nBerechtigung: `console.write`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "ok": true,
                                    "message": "Deployment \"api\" wird neu ausgerollt."
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cluster": {
                                        "type": "integer"
                                    },
                                    "namespace": {
                                        "type": "string"
                                    },
                                    "type": {
                                        "type": "string",
                                        "description": "deployment oder statefulset"
                                    },
                                    "name": {
                                        "type": "string"
                                    },
                                    "action": {
                                        "type": "string",
                                        "description": "restart oder scale"
                                    },
                                    "replicas": {
                                        "type": "integer",
                                        "description": "nur bei action=scale, 0 bis 20"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/console/pods": {
            "get": {
                "summary": "Pods eines Namespace",
                "description": "Pods mit Zustand, Containern und dem Grund, falls einer nicht laeuft. Mit app=<wert> auf ein Label eingegrenzt.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "name": "api-7cbb…",
                                            "phase": "Running",
                                            "ready": "1/1",
                                            "reasons": []
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "app",
                        "in": "query",
                        "required": false,
                        "description": "Wert des Labels app",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/console/events": {
            "get": {
                "summary": "Ereignisse eines Namespace",
                "description": "Neueste zuerst. Mit name auf eine Ressource und ihre Kinder eingegrenzt. Der Cluster haelt Ereignisse nur etwa eine Stunde vor.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "time": "2026-09-22T08:40:33Z",
                                            "type": "Warning",
                                            "reason": "BackOff",
                                            "object": "Pod/api-7cbb…",
                                            "message": "Back-off pulling image"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "name",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Standard 50, hoechstens 200",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/console/manifest": {
            "post": {
                "summary": "Manifest schreiben oder loeschen",
                "description": "POST ohne `name` legt an, mit `name` wird per Server-Side-Apply geaendert; `pruefen: true` laesst den API-Server nur gegenlesen. DELETE entfernt eine Ressource und braucht zusaetzlich `console.delete`.\n\nSecrets werden hier nicht geschrieben — ein Manifest ohne `data` wuerde die Werte loeschen.\n\nBerechtigung: `console.write`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "ok": true,
                                    "name": "meine-app",
                                    "message": "Service \"meine-app\" angelegt."
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cluster": {
                                        "type": "integer"
                                    },
                                    "namespace": {
                                        "type": "string"
                                    },
                                    "type": {
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "string",
                                        "description": "leer = neu anlegen"
                                    },
                                    "yaml": {
                                        "type": "string",
                                        "description": "das Manifest; bei POST Pflicht"
                                    },
                                    "dryRun": {
                                        "type": "boolean",
                                        "description": "nur gegenlesen lassen, nichts schreiben"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "summary": "Manifest schreiben oder loeschen",
                "description": "POST ohne `name` legt an, mit `name` wird per Server-Side-Apply geaendert; `pruefen: true` laesst den API-Server nur gegenlesen. DELETE entfernt eine Ressource und braucht zusaetzlich `console.delete`.\n\nSecrets werden hier nicht geschrieben — ein Manifest ohne `data` wuerde die Werte loeschen.\n\nBerechtigung: `console.write`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "ok": true,
                                    "name": "meine-app",
                                    "message": "Service \"meine-app\" angelegt."
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cluster": {
                                        "type": "integer"
                                    },
                                    "namespace": {
                                        "type": "string"
                                    },
                                    "type": {
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "string",
                                        "description": "leer = neu anlegen"
                                    },
                                    "yaml": {
                                        "type": "string",
                                        "description": "das Manifest; bei POST Pflicht"
                                    },
                                    "dryRun": {
                                        "type": "boolean",
                                        "description": "nur gegenlesen lassen, nichts schreiben"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/console/app": {
            "post": {
                "summary": "Anwendung bereitstellen",
                "description": "Aus wenigen Angaben entstehen ConfigMap, Secret, PVC, Deployment, Service, Certificate und IngressRoute. Mit `dryRun: true` laeuft alles nur trocken gegen den API-Server.\n\nIst einer der Namen im Namespace belegt, wird nichts angelegt.\n\nBerechtigung: `console.write`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "ok": true,
                                    "objects": [
                                        {
                                            "type": "deployment",
                                            "name": "meine-app"
                                        }
                                    ],
                                    "message": "7 Bausteine angelegt."
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cluster": {
                                        "type": "integer"
                                    },
                                    "namespace": {
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "string"
                                    },
                                    "image": {
                                        "type": "string",
                                        "description": "vollstaendig mit Registry, etwa docker.io/library/nginx:1.27"
                                    },
                                    "port": {
                                        "type": "integer",
                                        "description": "Port im Container, Standard 8080"
                                    },
                                    "replicas": {
                                        "type": "integer"
                                    },
                                    "domain": {
                                        "type": "string",
                                        "description": "leer = nur clusterintern erreichbar"
                                    },
                                    "tls": {
                                        "type": "boolean"
                                    },
                                    "issuer": {
                                        "type": "string",
                                        "description": "ClusterIssuer, bei tls Pflicht"
                                    },
                                    "storage": {
                                        "type": "string",
                                        "description": "Groesse wie 5Gi, leer = kein Speicher"
                                    },
                                    "storagePath": {
                                        "type": "string"
                                    },
                                    "storageClass": {
                                        "type": "string"
                                    },
                                    "env": {
                                        "type": "array",
                                        "description": "Liste aus {name, value, secret} — geheime Werte landen im Secret"
                                    },
                                    "dryRun": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/console/duplicate": {
            "post": {
                "summary": "Anwendung duplizieren",
                "description": "Kopiert eine Anwendung in einen anderen Namespace: Namen, Labels, Selektoren und alle Verweise werden mitgezogen, die Domain auf Wunsch getauscht.\n\nGeheimnisse werden standardmaessig NICHT kopiert — die Secrets entstehen mit denselben Schluesseln und leeren Werten. Ohne `resources` sammelt der Server alles ein, was mit dem Namen der Anwendung beginnt.\n\nBerechtigung: `console.write`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "ok": true,
                                    "target": "triskela-softlanding-dev",
                                    "objects": [
                                        {
                                            "type": "deployment",
                                            "name": "api-dev"
                                        }
                                    ],
                                    "hints": [
                                        "Der Speicher startet leer — Daten werden nicht kopiert."
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "cluster": {
                                        "type": "integer"
                                    },
                                    "namespace": {
                                        "type": "string",
                                        "description": "Namespace der Quelle"
                                    },
                                    "targetNamespace": {
                                        "type": "string"
                                    },
                                    "source": {
                                        "type": "string",
                                        "description": "Name der bestehenden Anwendung"
                                    },
                                    "newName": {
                                        "type": "string"
                                    },
                                    "domain": {
                                        "type": "string"
                                    },
                                    "copySecretValues": {
                                        "type": "boolean",
                                        "description": "true kopiert auch die Werte der Secrets"
                                    },
                                    "resources": {
                                        "type": "array",
                                        "description": "Liste aus {type, name}; ohne Angabe sammelt der Server selbst"
                                    },
                                    "dryRun": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/console/jobs": {
            "get": {
                "summary": "Manuelle Aktionen",
                "description": "Was in diesem Namespace auf Anstoß laufen kann, mit den letzten Läufen und deren Pods. Angeboten wird nur, was im Cluster als Vorlage gekennzeichnet ist: CronJobs mit `arevano.com/manual-job=true`.\n\nPOST stößt eine Vorlage an und braucht `console.job.run` samt Schreibrolle im Namespace. Über `env` lassen sich Umgebungsvariablen für diesen einen Lauf setzen — als Text oder als Verweis `{\"ref\":\"secret\",\"name\":\"…\",\"key\":\"…\"}`. Im Audit-Log stehen nur die Namen, nie die Werte.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "cluster": 1,
                                    "namespace": "triskela-softlanding-prod",
                                    "items": [
                                        {
                                            "name": "softlanding-legacyimport",
                                            "title": "Legacy-Import",
                                            "suspended": true,
                                            "runs": [
                                                {
                                                    "name": "softlanding-legacyimport-260927-181500",
                                                    "state": "Erfolgreich",
                                                    "key": "succeeded"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "runs",
                        "in": "query",
                        "required": false,
                        "description": "Wie viele Läufe je Vorlage, Standard 5",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "template": {
                                        "type": "string",
                                        "description": "Pflicht bei POST: Name der Vorlage"
                                    },
                                    "env": {
                                        "type": "object",
                                        "description": "Umgebungsvariablen nur für diesen Lauf"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Manuelle Aktionen",
                "description": "Was in diesem Namespace auf Anstoß laufen kann, mit den letzten Läufen und deren Pods. Angeboten wird nur, was im Cluster als Vorlage gekennzeichnet ist: CronJobs mit `arevano.com/manual-job=true`.\n\nPOST stößt eine Vorlage an und braucht `console.job.run` samt Schreibrolle im Namespace. Über `env` lassen sich Umgebungsvariablen für diesen einen Lauf setzen — als Text oder als Verweis `{\"ref\":\"secret\",\"name\":\"…\",\"key\":\"…\"}`. Im Audit-Log stehen nur die Namen, nie die Werte.\n\nBerechtigung: `console`",
                "tags": [
                    "Console"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "cluster": 1,
                                    "namespace": "triskela-softlanding-prod",
                                    "items": [
                                        {
                                            "name": "softlanding-legacyimport",
                                            "title": "Legacy-Import",
                                            "suspended": true,
                                            "runs": [
                                                {
                                                    "name": "softlanding-legacyimport-260927-181500",
                                                    "state": "Erfolgreich",
                                                    "key": "succeeded"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "cluster",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "namespace",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "runs",
                        "in": "query",
                        "required": false,
                        "description": "Wie viele Läufe je Vorlage, Standard 5",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "template": {
                                        "type": "string",
                                        "description": "Pflicht bei POST: Name der Vorlage"
                                    },
                                    "env": {
                                        "type": "object",
                                        "description": "Umgebungsvariablen nur für diesen Lauf"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/organizations": {
            "get": {
                "summary": "Organisationen auflisten",
                "description": "Alle Organisationen, in denen diese Anmeldung mindestens ein Recht hat.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "items": [
                                        {
                                            "id": 3,
                                            "key": "triskela",
                                            "name": "TriskelA GmbH",
                                            "members": 12
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                }
            }
        },
        "/api/organization": {
            "get": {
                "summary": "Organisation ansehen",
                "description": "Stammdaten, Zahl der Mitglieder, Abteilungen und aktive Module.\n\nOhne `organization` nimmt der Server die Organisation des Tokens, sonst — falls es nur eine gibt — eben diese.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "id": 3,
                                    "key": "triskela",
                                    "name": "TriskelA GmbH",
                                    "members": 12,
                                    "departments": [
                                        {
                                            "id": 5,
                                            "name": "Entwicklung"
                                        }
                                    ],
                                    "apps": [
                                        "console",
                                        "cms"
                                    ],
                                    "darf": {
                                        "admin": true,
                                        "apps_toggle": true,
                                        "einladen": true
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "description": "Kennung der Organisation",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/organization/members": {
            "get": {
                "summary": "Mitglieder auflisten",
                "description": "Wer in dieser Organisation mindestens ein Recht hat, mit der Zahl seiner Rechte. Offene Einladungen stehen getrennt daneben.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "items": [
                                        {
                                            "user_id": 42,
                                            "username": "a.beispiel",
                                            "person_id": 17,
                                            "rechte": 6,
                                            "geaendert": "2026-09-20 14:02:11"
                                        }
                                    ],
                                    "einladungen": [
                                        {
                                            "id": 8,
                                            "email": "neu@example.com",
                                            "erstellt": "2026-09-24 09:15:00"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/organization/departments": {
            "get": {
                "summary": "Abteilungen auflisten",
                "description": "Die Abteilungen der Organisation. Sie dienen zugleich als Geltungsbereich, auf den ein Recht eingegrenzt sein kann.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "items": [
                                        {
                                            "id": 5,
                                            "name": "Entwicklung",
                                            "description": null
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/organization/apps": {
            "get": {
                "summary": "Module ein- und ausschalten",
                "description": "GET liefert alle Module der Suite, jeweils mit `enabled` für diese Organisation.\n\nPOST schaltet eines um und braucht dafür `organization.apps.toggle`. Jede Änderung landet im Audit-Log; war nichts zu tun, sagt `geaendert` false.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "app": "cms",
                                    "enabled": true,
                                    "geaendert": true
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "app": {
                                        "type": "string",
                                        "description": "Kennung des Moduls, etwa console oder cms (nur bei POST)"
                                    },
                                    "enabled": {
                                        "type": "boolean",
                                        "description": "Ziel-Zustand (nur bei POST)"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Module ein- und ausschalten",
                "description": "GET liefert alle Module der Suite, jeweils mit `enabled` für diese Organisation.\n\nPOST schaltet eines um und braucht dafür `organization.apps.toggle`. Jede Änderung landet im Audit-Log; war nichts zu tun, sagt `geaendert` false.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "app": "cms",
                                    "enabled": true,
                                    "geaendert": true
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "app": {
                                        "type": "string",
                                        "description": "Kennung des Moduls, etwa console oder cms (nur bei POST)"
                                    },
                                    "enabled": {
                                        "type": "boolean",
                                        "description": "Ziel-Zustand (nur bei POST)"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/organization/access": {
            "get": {
                "summary": "Rechte lesen und vergeben",
                "description": "GET zeigt die Rechte eines Kontos in dieser Organisation — ohne `user` die eigenen; fremde sieht nur, wer die Organisation verwaltet.\n\nPOST gibt oder nimmt ein Recht und braucht `organization.admin`. Zwei Grenzen gelten immer: vergeben kann man nur, was man selbst hat, und nur an Konten, die bereits Mitglied sind.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "user": {
                                        "user_id": 42,
                                        "username": "a.beispiel",
                                        "person_id": 17
                                    },
                                    "rechte": [
                                        "organization",
                                        "cms",
                                        "cms.page.publish"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "user",
                        "in": "query",
                        "required": false,
                        "description": "Kennung des Kontos; bei POST Pflicht",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "permission": {
                                        "type": "string",
                                        "description": "Pfad des Rechts, etwa cms.page.publish (nur bei POST)"
                                    },
                                    "action": {
                                        "type": "string",
                                        "description": "grant oder revoke (nur bei POST)"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Rechte lesen und vergeben",
                "description": "GET zeigt die Rechte eines Kontos in dieser Organisation — ohne `user` die eigenen; fremde sieht nur, wer die Organisation verwaltet.\n\nPOST gibt oder nimmt ein Recht und braucht `organization.admin`. Zwei Grenzen gelten immer: vergeben kann man nur, was man selbst hat, und nur an Konten, die bereits Mitglied sind.\n\nBerechtigung: `organization.view` oder `organization.admin`",
                "tags": [
                    "Organisation"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "user": {
                                        "user_id": 42,
                                        "username": "a.beispiel",
                                        "person_id": 17
                                    },
                                    "rechte": [
                                        "organization",
                                        "cms",
                                        "cms.page.publish"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "user",
                        "in": "query",
                        "required": false,
                        "description": "Kennung des Kontos; bei POST Pflicht",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "permission": {
                                        "type": "string",
                                        "description": "Pfad des Rechts, etwa cms.page.publish (nur bei POST)"
                                    },
                                    "action": {
                                        "type": "string",
                                        "description": "grant oder revoke (nur bei POST)"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cms/sites": {
            "get": {
                "summary": "Websites auflisten",
                "description": "Die Websites einer Organisation, jede mit ihren Kennzahlen.\n\nDas CMS muss für die Organisation freigeschaltet sein, sonst antworten alle Endpunkte dieser Gruppe mit 403 `module_disabled`.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "items": [
                                        {
                                            "id": 1,
                                            "name": "Hauptseite",
                                            "domain": "example.com",
                                            "default_language": "de",
                                            "status": "active",
                                            "stats": {
                                                "pages": 12,
                                                "published": 9
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "active, draft oder archived",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/cms/pages": {
            "get": {
                "summary": "Seiten auflisten und anlegen",
                "description": "Die Seiten einer Website, neueste Änderung zuerst. Ohne `site` nimmt der Server die einzige Website; gibt es mehrere, muss die Anfrage sich festlegen.\n\nDer Inhalt steht nicht in der Liste — dafür gibt es /api/cms/page.\n\nPOST legt eine Seite an und braucht `cms.write` (oder `cms.admin`). Ohne `status` entsteht ein Entwurf; direkt auf `published` zu gehen verlangt zusätzlich `cms.publish`. Kurzname und Sprache zusammen müssen frei sein, sonst antwortet der Server mit 409.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "site": {
                                        "id": 1,
                                        "name": "Hauptseite"
                                    },
                                    "stats": {
                                        "total": 12,
                                        "published": 9,
                                        "drafts": 3
                                    },
                                    "items": [
                                        {
                                            "id": 44,
                                            "slug": "ueber-uns",
                                            "title": "Über uns",
                                            "language": "de",
                                            "status": "published"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "site",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "published, draft oder archived",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "Zweibuchstabiges Kürzel, etwa de",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "required": false,
                        "description": "Sucht in Titel und Kurzname",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string",
                                        "description": "Pflicht bei POST"
                                    },
                                    "slug": {
                                        "type": "string",
                                        "description": "Pflicht bei POST; klein, ohne Leerzeichen und Umlaute"
                                    },
                                    "template": {
                                        "type": "string",
                                        "description": "Standard page"
                                    },
                                    "content": {
                                        "type": "string"
                                    },
                                    "meta_title": {
                                        "type": "string"
                                    },
                                    "meta_description": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Seiten auflisten und anlegen",
                "description": "Die Seiten einer Website, neueste Änderung zuerst. Ohne `site` nimmt der Server die einzige Website; gibt es mehrere, muss die Anfrage sich festlegen.\n\nDer Inhalt steht nicht in der Liste — dafür gibt es /api/cms/page.\n\nPOST legt eine Seite an und braucht `cms.write` (oder `cms.admin`). Ohne `status` entsteht ein Entwurf; direkt auf `published` zu gehen verlangt zusätzlich `cms.publish`. Kurzname und Sprache zusammen müssen frei sein, sonst antwortet der Server mit 409.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "site": {
                                        "id": 1,
                                        "name": "Hauptseite"
                                    },
                                    "stats": {
                                        "total": 12,
                                        "published": 9,
                                        "drafts": 3
                                    },
                                    "items": [
                                        {
                                            "id": 44,
                                            "slug": "ueber-uns",
                                            "title": "Über uns",
                                            "language": "de",
                                            "status": "published"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "site",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "description": "published, draft oder archived",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "description": "Zweibuchstabiges Kürzel, etwa de",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "required": false,
                        "description": "Sucht in Titel und Kurzname",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string",
                                        "description": "Pflicht bei POST"
                                    },
                                    "slug": {
                                        "type": "string",
                                        "description": "Pflicht bei POST; klein, ohne Leerzeichen und Umlaute"
                                    },
                                    "template": {
                                        "type": "string",
                                        "description": "Standard page"
                                    },
                                    "content": {
                                        "type": "string"
                                    },
                                    "meta_title": {
                                        "type": "string"
                                    },
                                    "meta_description": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cms/page": {
            "get": {
                "summary": "Seite ansehen und ändern",
                "description": "Eine einzelne Seite samt Inhalt — entweder über `id` oder über `slug` und `language`. Ohne `language` gilt die Standardsprache der Website.\n\nPOST ändert die Seite und braucht `id` sowie `cms.write`; geändert wird nur, was mitgeschickt wird. Der Sprung auf `published` verlangt `cms.publish` und setzt das Veröffentlichungsdatum, falls es noch fehlt.\n\nGelöscht wird über diese Schnittstelle nichts — dafür gibt es den Status `archived`, der sich zurücknehmen lässt.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "id": 44,
                                    "site": 1,
                                    "slug": "ueber-uns",
                                    "title": "Über uns",
                                    "language": "de",
                                    "status": "published",
                                    "content": "<h1>…</h1>"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "site",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "slug",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string"
                                    },
                                    "content": {
                                        "type": "string"
                                    },
                                    "status": {
                                        "type": "string",
                                        "description": "draft, published oder archived"
                                    },
                                    "meta_title": {
                                        "type": "string"
                                    },
                                    "meta_description": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "summary": "Seite ansehen und ändern",
                "description": "Eine einzelne Seite samt Inhalt — entweder über `id` oder über `slug` und `language`. Ohne `language` gilt die Standardsprache der Website.\n\nPOST ändert die Seite und braucht `id` sowie `cms.write`; geändert wird nur, was mitgeschickt wird. Der Sprung auf `published` verlangt `cms.publish` und setzt das Veröffentlichungsdatum, falls es noch fehlt.\n\nGelöscht wird über diese Schnittstelle nichts — dafür gibt es den Status `archived`, der sich zurücknehmen lässt.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "id": 44,
                                    "site": 1,
                                    "slug": "ueber-uns",
                                    "title": "Über uns",
                                    "language": "de",
                                    "status": "published",
                                    "content": "<h1>…</h1>"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "site",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "slug",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "language",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "title": {
                                        "type": "string"
                                    },
                                    "content": {
                                        "type": "string"
                                    },
                                    "status": {
                                        "type": "string",
                                        "description": "draft, published oder archived"
                                    },
                                    "meta_title": {
                                        "type": "string"
                                    },
                                    "meta_description": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cms/media": {
            "get": {
                "summary": "Mediathek auflisten",
                "description": "Die Einträge der Mediathek, seitenweise (höchstens 500 je Anfrage).\n\nDie Dateien selbst kommen nicht über diese Schnittstelle — sie liegen im Speicher der Website.\n\nBerechtigung: `cms.read`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "site": {
                                        "id": 1
                                    },
                                    "limit": 100,
                                    "offset": 0,
                                    "items": [
                                        {
                                            "id": 7,
                                            "filename": "logo.svg",
                                            "mime_type": "image/svg+xml",
                                            "size_bytes": 4218
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "site",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Standard 100, höchstens 500",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        },
        "/api/cms/domains": {
            "get": {
                "summary": "Domains auflisten",
                "description": "Die Domains der Organisation mit Zustand, Art der Zuordnung und dem letzten DNS-Befund.\n\nDas Merkmal zum Nachweis des Besitzes bleibt draußen: Es ist ein Geheimnis und gehört nicht in eine Liste.\n\nBerechtigung: `cms.domains.read` oder `cms.domains.write` oder `cms.admin`",
                "tags": [
                    "CMS"
                ],
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "organization": 3,
                                    "items": [
                                        {
                                            "id": 2,
                                            "host": "example.com",
                                            "status": "verified",
                                            "routing_type": "tenant",
                                            "tenant": "example",
                                            "dns_last_ok": true
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "organization",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/openapi.json": {
            "get": {
                "summary": "OpenAPI-Dokument",
                "description": "Beschreibung aller Endpunkte, maschinenlesbar (OpenAPI 3.1).",
                "tags": [
                    "Allgemein"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "openapi": "3.1.0"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                }
            }
        },
        "/api/status/summary": {
            "get": {
                "summary": "Systemstatus (Zusammenfassung)",
                "description": "Öffentlicher Gesamtzustand der Arevano-Plattform: Gruppen und Dienste mit Zustand (operational, degraded, outage, maintenance, no_data), Online seit, Ende der letzten Störung, Verfügbarkeit 24 h/30 T/90 T mit Abdeckung und 90 Tagesbalken, dazu laufende, angekündigte und letzte Meldungen (Texte de/en).\n\nOhne Anmeldung, jede Minute neu berechnet, `Cache-Control: public, max-age=30`, ETag/304. 503 `no_data`, solange es noch keine Messdaten gibt.",
                "tags": [
                    "Status"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "generated_at": "2026-10-12T12:05:03Z",
                                    "data_as_of": "2026-10-12T12:05:00Z",
                                    "measured_since": "2026-10-12",
                                    "derived_since": "2026-09-22",
                                    "overall": {
                                        "state": "operational"
                                    },
                                    "groups": [
                                        {
                                            "key": "suite",
                                            "name": {
                                                "de": "Arevano Suite",
                                                "en": "Arevano Suite"
                                            },
                                            "state": "operational",
                                            "components": [
                                                {
                                                    "key": "suite.web",
                                                    "name": {
                                                        "de": "Suite & Website",
                                                        "en": "Suite & website"
                                                    },
                                                    "state": "operational",
                                                    "online_since": "2026-10-02T08:14:00Z",
                                                    "last_outage_end": "2026-10-02T08:14:00Z",
                                                    "availability": {
                                                        "24h": 100,
                                                        "30d": 99.98,
                                                        "90d": 99.95
                                                    },
                                                    "coverage": {
                                                        "24h": 1,
                                                        "30d": 0.67,
                                                        "90d": 0.22
                                                    },
                                                    "days": [
                                                        {
                                                            "date": "2026-10-12",
                                                            "color": "green",
                                                            "availability": 100,
                                                            "down_min": 0,
                                                            "maintenance_min": 0,
                                                            "degraded_min": 0,
                                                            "source": "probe"
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ],
                                    "events": {
                                        "active": [],
                                        "scheduled": [],
                                        "recent": []
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                }
            }
        },
        "/api/status/history": {
            "get": {
                "summary": "Antwortzeiten eines Dienstes",
                "description": "Antwortzeitreihe (Median p50 und 95-%-Wert p95 in ms) eines öffentlichen Dienstes mit Bändern für Störung, Einschränkung und Wartung sowie Markierungen für Aktualisierungen. Nur öffentliche Schlüssel aus /api/status/summary; unbekannt oder nicht öffentlich → 404.",
                "tags": [
                    "Status"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "component": "suite.web",
                                    "range": "24h",
                                    "from": "2026-10-11T12:05:00Z",
                                    "to": "2026-10-12T12:05:00Z",
                                    "step_s": 300,
                                    "points": [
                                        {
                                            "t": "2026-10-12T12:00:00Z",
                                            "p50": 41,
                                            "p95": 88,
                                            "source": "probe"
                                        }
                                    ],
                                    "bands": [
                                        {
                                            "kind": "maintenance",
                                            "from": "2026-10-12T02:00:00Z",
                                            "to": "2026-10-12T02:20:00Z"
                                        }
                                    ],
                                    "markers": [
                                        {
                                            "kind": "update",
                                            "t": "2026-10-12T09:31:00Z",
                                            "title": {
                                                "de": "Aktualisierung",
                                                "en": "Update"
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "component",
                        "in": "query",
                        "required": true,
                        "description": "Schlüssel des Dienstes, z. B. suite.web oder mail.inbound",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "range",
                        "in": "query",
                        "required": false,
                        "description": "24h (Vorgabe), 7d, 30d oder 90d",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/status/events": {
            "get": {
                "summary": "Störungs- und Wartungsmeldungen",
                "description": "Öffentliche Meldungen mit Verlauf (Texte de/en): laufende (open), angekündigte Wartungen (scheduled) oder abgeschlossene der letzten 14 Tage (recent).",
                "tags": [
                    "Status"
                ],
                "security": [],
                "responses": {
                    "200": {
                        "description": "Erfolg",
                        "content": {
                            "application/json": {
                                "example": {
                                    "state": "scheduled",
                                    "items": [
                                        {
                                            "id": 12,
                                            "type": "maintenance",
                                            "severity": "maintenance",
                                            "state": "scheduled",
                                            "title": {
                                                "de": "Wartung E-Mail",
                                                "en": "Email maintenance"
                                            },
                                            "scheduled_start": "2026-10-14T20:00:00Z",
                                            "scheduled_end": "2026-10-14T21:00:00Z",
                                            "components": [
                                                "suite.mail"
                                            ],
                                            "updates": [
                                                {
                                                    "state": "scheduled",
                                                    "body": {
                                                        "de": "Kurze Unterbrechung möglich.",
                                                        "en": "Short interruption possible."
                                                    },
                                                    "created": "2026-10-12T10:00:00Z"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht angemeldet"
                    },
                    "403": {
                        "description": "Keine Berechtigung"
                    }
                },
                "parameters": [
                    {
                        "name": "state",
                        "in": "query",
                        "required": false,
                        "description": "open (Vorgabe), scheduled oder recent",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "description": "Standard 20, höchstens 100",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ]
            }
        }
    }
}