openapi: 3.0.0
info:
  version: 3.8.0
  title: Cloud Native Controller for Edge Native Workloads
paths:
  /live:
    get:
      tags:
        - Controller
      summary: Returns service liveness (process up)
      description: >-
        Kubernetes liveness probe. Returns 200 while the HTTP server is
        listening. Does not verify database, vault, or authentication readiness.
      operationId: getServiceLiveness
      responses:
        '200':
          description: Service is alive
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceStatusResponse'
        '500':
          description: Internal Server Error
  /status:
    get:
      tags:
        - Controller
      summary: Returns service readiness status
      description: >-
        Kubernetes readiness probe and Edgelet reconnect gate. Returns 200 when
        database, vault (if enabled), and auth subsystem checks pass. Returns
        503 with Retry-After when dependencies are not ready.
      operationId: getServiceStatus
      responses:
        '200':
          description: Service is ready for traffic
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceStatusResponse'
        '500':
          description: Internal Server Error
        '503':
          description: Service is alive but not ready
          headers:
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceReadinessFailureResponse'
  /architectures:
    get:
      tags:
        - Controller
      summary: Gets architecture list
      operationId: getArchitectures
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ArchitecturesResponse'
        '500':
          description: Internal Server Error
  /iofog-list:
    get:
      tags:
        - ioFog
      summary: Returns list of ioFog nodes
      operationId: getIOFogNodes
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IOFogNodesListFilters'
      responses:
        '200':
          description: List of ioFog nodes
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodesListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /iofog:
    post:
      tags:
        - ioFog
      summary: Creates a new ioFog node
      description: >-
        Platform reconcile is asynchronous. Poll GET /iofog/{uuid} for
        platformStatus, or POST /iofog/{uuid}/reconcile to retry after failure.
      operationId: createIOFogNode
      security:
        - authToken: []
      requestBody:
        $ref: '#/components/requestBodies/UpdateIOFogNodeRequestBody'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NewIOFogNodeResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /iofog/{uuid}:
    patch:
      tags:
        - ioFog
      summary: Updates existing ioFog node
      description: >-
        Platform reconcile is asynchronous. Poll GET /iofog/{uuid} for
        platformStatus, or POST /iofog/{uuid}/reconcile to retry after failure.
      operationId: updateIOFogNode
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        $ref: '#/components/requestBodies/UpdateIOFogNodeRequestBody'
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
    delete:
      tags:
        - ioFog
      summary: Deletes an ioFog node
      operationId: deleteIOFogNode
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
    get:
      tags:
        - ioFog
      summary: Gets ioFog node info
      operationId: getIOFogNode
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodeInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
  /iofog/{uuid}/reconcile:
    post:
      tags:
        - ioFog
      summary: Manually retries fog platform reconcile
      operationId: reconcileIOFogNode
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogUuidResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
  /iofog/{uuid}/provisioning-key:
    get:
      tags:
        - ioFog
      summary: Generates provisioning key for an ioFog node
      operationId: generateProvisioningKey
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '201':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProvisioningKeyResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
  /iofog/{uuid}/version/{versionCommand}:
    post:
      tags:
        - ioFog
      summary: Set change version command
      operationId: setVersionCommand
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
        - in: path
          name: versionCommand
          description: change version command
          required: true
          schema:
            type: string
            enum:
              - upgrade
              - rollback
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                semver:
                  type: string
                  description: Target semver for upgrade or rollback
                  pattern: >-
                    ^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:[+]([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
  /iofog/{uuid}/reboot:
    post:
      tags:
        - ioFog
      summary: remote reboot fog agent
      operationId: setRebootCommand
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /iofog/{uuid}/prune:
    post:
      tags:
        - ioFog
      summary: prune remote fog agent
      operationId: setPruneCommand
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /application:
    get:
      tags:
        - Application
      summary: Lists all applications
      operationId: listApplication
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationListResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    post:
      tags:
        - Application
      summary: Creates an application
      operationId: createApplication
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApplicationCreateRequest'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationCreateResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /application/system:
    get:
      tags:
        - Application
      summary: Lists all system applications
      operationId: listSystemApplication
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationListResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /application/system/{name}:
    get:
      tags:
        - Application
      summary: Gets an application details
      operationId: getApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationGetResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Application
      summary: Deletes a system application
      operationId: deleteSystemApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /application/yaml:
    post:
      tags:
        - Application
      summary: Creates an application using a YAML file
      operationId: createApplicationYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                application:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationCreateResponse'
        '400':
          description: Bad Request
        '500':
          description: Internal Server Error
  /application/{name}:
    put:
      tags:
        - Application
      summary: Updates an application state (microservices, etc.)
      operationId: updateApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApplicationUpdateRequest'
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Application
      summary: Updates an application metadata
      operationId: patchApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApplicationPatchRequest'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Application
      summary: Deletes an application
      operationId: deleteApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    get:
      tags:
        - Application
      summary: Gets an application details
      operationId: getApplication
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationGetResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /application/yaml/{name}:
    put:
      tags:
        - Application
      summary: Updates an application using a YAML file
      operationId: updateApplicationYAML
      parameters:
        - in: path
          name: name
          description: Application name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                application:
                  type: string
                  format: binary
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /cluster/controllers:
    get:
      tags:
        - Cluster
      summary: Lists cluster controllers (active replicas by default)
      operationId: listClusterControllers
      security:
        - authToken: []
      parameters:
        - in: query
          name: includeInactive
          description: >-
            When true, include inactive controller rows (historical replicas
            from past rollouts). Default false returns only active replicas.
          required: false
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClusterControllerListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /cluster/controllers/{uuid}:
    get:
      tags:
        - Cluster
      summary: Gets a cluster controller details
      operationId: getClusterController
      parameters:
        - in: path
          name: uuid
          description: Cluster controller UUID
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClusterControllerResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Cluster
      summary: Updates a cluster controller
      operationId: updateClusterController
      parameters:
        - in: path
          name: uuid
          description: Cluster controller UUID
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClusterControllerUpdateRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClusterControllerResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Cluster
      summary: Deletes a cluster controller
      operationId: deleteClusterController
      parameters:
        - in: path
          name: uuid
          description: Cluster controller UUID
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: No Content
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /applicationTemplates:
    get:
      tags:
        - Application Template
      summary: Lists all application templates
      operationId: listApplicationTemplates
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationTemplateListResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /applicationTemplate/yaml:
    post:
      tags:
        - Application Template
      summary: Creates an application template using a YAML file
      operationId: createApplicationTemplateYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                template:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationTemplateCreateResponse'
        '400':
          description: Bad Request
        '500':
          description: Internal Server Error
  /applicationTemplate/{name}:
    patch:
      tags:
        - Application Template
      summary: Patches an application template
      operationId: patchApplicationTemplate
      parameters:
        - in: path
          name: name
          description: Application template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApplicationTemplatePatchRequest'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Application Template
      summary: Deletes an application template
      operationId: deleteApplicationTemplate
      parameters:
        - in: path
          name: name
          description: Application template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    get:
      tags:
        - Application Template
      summary: Gets an application template
      operationId: getApplicationTemplate
      parameters:
        - in: path
          name: name
          description: Application template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationTemplateGetResponse'
        '400':
          description: Bad Request
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /applicationTemplate/yaml/{name}:
    put:
      tags:
        - Application Template
      summary: Updates or creates an application template
      operationId: updateOrCreateApplicationTemplateFromYaml
      parameters:
        - in: path
          name: name
          description: Application template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                template:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApplicationTemplateCreateResponse'
        '400':
          description: Bad Request
        '500':
          description: Internal Server Error
  /agent/provision:
    post:
      tags:
        - Agent
      summary: Provision agent with an ioFog node
      operationId: agentProvision
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentProvisioningRequest'
        required: true
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentProvisioningResponse'
        '400':
          description: Bad Request
        '401':
          description: Expired Provisioning Key
        '404':
          description: Invalid Provisioning Key
        '500':
          description: Internal Server Error
  /agent/deprovision:
    post:
      tags:
        - Agent
      summary: Deprovision agent
      operationId: agentDeprovision
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentDeprovisioningRequest'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/cert:
    get:
      tags:
        - Agent
      summary: Move Controller CA to Agent
      operationId: agentControllerCert
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/config:
    get:
      tags:
        - Agent
      summary: Get an ioFog node configuration
      operationId: getIOFogNodeConfig
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodeConfig'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Agent
      summary: Updates an ioFog node configuration
      operationId: updateIOFogNodeConfig
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IOFogNodeConfigRequest'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/config/gps:
    patch:
      tags:
        - Agent
      summary: Updates an ioFog node GPS configuration
      operationId: updateIOFogNodeGps
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IOFogNodeGpsRequest'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/config/changes:
    get:
      tags:
        - Agent
      summary: Gets ioFog node changes
      operationId: getIOFogNodeChanges
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodeConfigChanges'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Agent
      summary: Resets ioFog node changes list
      operationId: resetIOFogNodeChanges
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/status:
    put:
      tags:
        - Agent
      summary: Posts agent status to ioFog node
      operationId: postAgentStatus
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentStatus'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/controller/register:
    post:
      tags:
        - Agent
      summary: Register ControlPlane controller microservice
      description: >-
        Agent-only endpoint (fog token). Edgelet registers the controller
        workload on system fogs. Not available via user RBAC - do not add to
        rbac-resources.yaml user resources.
      operationId: registerControllerMicroservice
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControllerRegisterRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ControllerRegisterResponse'
        '400':
          description: Bad Request - invalid body or name other than controller
        '401':
          description: Not Authorized
        '403':
          description: Forbidden - authenticated fog is not a system fog
        '500':
          description: Internal Server Error
  /agent/microservices:
    get:
      tags:
        - Agent
      summary: Gets microservices running on an ioFog node
      operationId: getAgentMicroservicesList
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentMicroservicesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/microservices/{microserviceUuid}:
    get:
      tags:
        - Agent
      summary: Gets microservices running on an ioFog node
      operationId: getAgentMicroserviceInfo
      parameters:
        - in: path
          required: true
          name: microserviceUuid
          description: Microservice UUID
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentMicroservicesInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Microservice Uuid
        '500':
          description: Internal Server Error
  /agent/registries:
    get:
      tags:
        - Agent
      summary: Gets list of Docker registries
      operationId: getRegistriesList
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistriesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/models:
    get:
      tags:
        - Agent
      summary: Gets fleet models linked to this fog
      description: >-
        Fog-token only. Returns models linked to the authenticated fog. Rows
        missing uuid or name are omitted. A missing route is treated as an empty
        list by the agent.
      operationId: getAgentLinkedModels
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentModelsListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/knowledge:
    get:
      tags:
        - Agent
      summary: Gets fleet Knowledge linked to this fog
      description: >-
        Fog-token only. Returns Knowledge linked to the authenticated fog. Rows
        missing uuid or name are omitted. An unlinked fog returns { "knowledge":
        [] }. A missing route is treated as an empty list by the agent.
      operationId: getAgentLinkedKnowledge
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentKnowledgeListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/runtimeClasses:
    get:
      tags:
        - Agent
      summary: Gets RuntimeClasses linked to this fog
      description: >-
        Fog-token only. Returns RuntimeClasses linked to the authenticated fog.
        Rows missing name or handler are omitted. Docker and podman agents store
        the snapshot and do not apply it.
      operationId: getAgentLinkedRuntimeClasses
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentRuntimeClassesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/tunnel:
    get:
      tags:
        - Agent
      summary: Get an ioFog node tunnel configuration
      operationId: getIOFogNodeTunnelConfig
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodeTunnelConfigResponse'
        '401':
          description: Not Authorized
        '404':
          description: Tunnel Not Found
        '500':
          description: Internal Server Error
  /agent/version:
    get:
      tags:
        - Agent
      summary: Get change version command
      operationId: getChangeVersion
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VersionCommandResponse'
        '401':
          description: Not Authorized
        '404':
          description: Version Command Not Found
        '500':
          description: Internal Server Error
  /agent/delete-node:
    delete:
      tags:
        - Agent
      summary: Deletes an ioFog node
      operationId: deleteAgentNode
      security:
        - authToken: []
      responses:
        '204':
          description: No Content
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /agent/tracking:
    post:
      tags:
        - Agent
      summary: Post tracking info
      operationId: postTracking
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PostTrackingRequest'
        required: true
      responses:
        '204':
          description: Success
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /catalog/microservices:
    get:
      tags:
        - Catalog
      summary: Gets microservices catalog
      operationId: getMicroservicesCatalog
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroservicesCatalogResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Catalog
      summary: Creates a new microservice catalog item
      operationId: createMicroserviceCatalogItem
      security:
        - authToken: []
      requestBody:
        $ref: '#/components/requestBodies/CreateUpdateCatalogItemRequestBody'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
  /catalog/microservices/{id}:
    get:
      tags:
        - Catalog
      summary: Gets microservice catalog item info
      operationId: getMicroserviceCatalogItem
      parameters:
        - in: path
          name: id
          description: Catalog Item Id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Catalog Item Info
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogItemInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Catalog Item Id
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Catalog
      summary: Updates a microservice catalog item
      operationId: updateMicroserviceCatalogItem
      parameters:
        - in: path
          name: id
          description: Catalog Item Id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        $ref: '#/components/requestBodies/CreateUpdateCatalogItemRequestBody'
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Catalog Item Id
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Catalog
      summary: Deletes a microservice catalog item
      operationId: deleteMicroserviceCatalogItem
      parameters:
        - in: path
          name: id
          description: Catalog Item Id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Invalid Catalog Item Id
        '500':
          description: Internal Server Error
  /microservices:
    get:
      tags:
        - Microservices
      summary: Gets list of microservices
      operationId: getMicroservicesList
      parameters:
        - in: query
          name: application
          description: Application name
          required: false
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetMicroservicesResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Microservices
      summary: Creates a new microservice
      description: >-
        Optional template overlay: send template.name plus optional
        template.variables. Request fields name, application, and
        iofogUuid/agentName win over the template. Catalog models.items[].name
        are auto-linked to the target fog. Non-empty runtime must exist as a
        RuntimeClass row and be in the fog availableRuntimes list. registryId
        must resolve to type oci.
      operationId: createMicroservice
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewMicroserviceRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  uuid:
                    type: string
                  name:
                    type: string
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /microservices/yaml:
    post:
      tags:
        - Microservices
      summary: Creates a new microservice in an Application
      description: >-
        YAML kind Microservice. Optional spec.template applies the same overlay
        as JSON POST /microservices (template.name plus optional
        template.variables). Request fields metadata.name, spec.application, and
        spec.agent.name win over the template.
      operationId: createMicroserviceYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                microservice:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  uuid:
                    type: string
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
  /microservices/{uuid}:
    get:
      tags:
        - Microservices
      summary: Gets a microservice info
      operationId: getMicroserviceInfo
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Microservices
      summary: Deletes a microservice
      operationId: deleteMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Microservices
      summary: Updates a microservice
      operationId: updateMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Registry Id
        '500':
          description: Internal Server Error
  /microservices/system:
    get:
      tags:
        - Microservices
      summary: Gets list of system microservices
      operationId: getSystemMicroservicesList
      security:
        - authToken: []
      parameters:
        - in: query
          name: application
          description: Application name
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  microservices:
                    type: array
                    items:
                      type: object
                      properties:
                        uuid:
                          type: string
                        name:
                          type: string
                        config:
                          type: object
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}:
    get:
      tags:
        - Microservices
      summary: Gets a system microservice info
      operationId: getSystemMicroserviceInfo
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Microservices
      summary: Updates a system microservice
      operationId: updateSystemMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Registry Id
        '500':
          description: Internal Server Error
  /microservices/yaml/{uuid}:
    patch:
      tags:
        - Microservices
      summary: Updates a microservice
      operationId: updateMicroserviceYAML
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                microservice:
                  type: string
                  format: binary
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
  /microservices/{uuid}/config:
    get:
      tags:
        - Microservices
      summary: Gets a microservice config
      operationId: getMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/microservicesConfig'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Microservices
      summary: Updates a microservice config
      operationId: updateMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/microservicesConfig'
        description: information about microservice config
        required: true
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Microservices
      summary: Deletes a microservice config
      operationId: deleteMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/config:
    get:
      tags:
        - Microservices
      summary: Gets a system microservice config
      operationId: getSystemMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/microservicesConfig'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Microservices
      summary: Updates a system microservice config
      operationId: updateSystemMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/microservicesConfig'
        description: information about microservice config
        required: true
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Microservices
      summary: Deletes a system microservice config
      operationId: deleteSystemMicroserviceConfig
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/port-mapping:
    post:
      tags:
        - Microservices
      summary: Creates a port mapping for microservice
      operationId: createMicroservicePortMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortMappingsRequest'
        description: information about port mapping
        required: true
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortMappingsPublicResponse'
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    get:
      tags:
        - Microservices
      summary: Get a port mapping list for microservice
      operationId: getMicroservicePortMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortMappingsListResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/port-mapping:
    post:
      tags:
        - Microservices
      summary: Creates a port mapping for system microservice
      operationId: createSystemMicroservicePortMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortMappingsRequest'
        description: information about port mapping
        required: true
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortMappingsPublicResponse'
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/port-mapping/{internalPort}:
    delete:
      tags:
        - Microservices
      summary: Deletes a port mapping for microservice
      operationId: deleteMicroservicePortMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
        - in: path
          name: internalPort
          description: Internal Port
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/port-mapping/{internalPort}:
    delete:
      tags:
        - Microservices
      summary: Deletes a port mapping for system microservice
      operationId: deleteSystemMicroservicePortMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
        - in: path
          name: internalPort
          description: Internal Port
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/volume-mapping:
    post:
      tags:
        - Microservices
      summary: Creates a volume mapping for microservice
      operationId: createMicroserviceVolumeMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMapping'
        description: information about volume mapping
        required: true
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: number
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    get:
      tags:
        - Microservices
      summary: Get a volume mapping list for microservice
      operationId: getMicroserviceVolumeMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMappingResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/volume-mapping:
    post:
      tags:
        - Microservices
      summary: Creates a volume mapping for system microservice
      operationId: createSystemMicroserviceVolumeMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMapping'
        description: information about volume mapping
        required: true
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: number
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/volume-mapping/{id}:
    delete:
      tags:
        - Microservices
      summary: Deletes a volume mapping for microservice
      operationId: deleteMicroserviceVolumeMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
        - in: path
          name: id
          description: Volume id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/volume-mapping/{id}:
    delete:
      tags:
        - Microservices
      summary: Deletes a volume mapping for system microservice
      operationId: deleteSystemMicroserviceVolumeMapping
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
        - in: path
          name: id
          description: Volume id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Not Valid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/system/{uuid}/rebuild:
    patch:
      tags:
        - Microservices
      summary: Rebuilds a system microservice
      operationId: rebuildSystemMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/models:
    patch:
      tags:
        - Microservices
      summary: Updates the microservice model catalog
      description: >-
        Catalog-only update. Sets the microserviceModels change flag only (does
        not set microserviceList). Rebuilds the workload when the catalog goes
        empty to non-empty or non-empty to empty, or when bindPath or
        permissions change. Adding or removing items with the same bindPath and
        permissions does not rebuild when the catalog is already non-empty.
        Catalog items reference managed model names only.
      operationId: patchMicroserviceModels
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MicroserviceCatalog'
      responses:
        '204':
          description: Catalog updated
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/knowledge:
    patch:
      tags:
        - Microservices
      summary: Updates the microservice Knowledge catalog
      description: >-
        User microservices only. Catalog-only update. Sets the
        microserviceKnowledge change flag only (does not set microserviceList).
        Rebuilds the workload when the catalog goes empty to non-empty or
        non-empty to empty, or when bindPath or permissions change. Adding or
        removing items with the same bindPath and permissions does not rebuild
        when the catalog is already non-empty. Catalog items reference managed
        Knowledge names only. System and controller microservices are rejected.
      operationId: patchMicroserviceKnowledge
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/KnowledgeCatalog'
      responses:
        '204':
          description: Catalog updated
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/rebuild:
    patch:
      tags:
        - Microservices
      summary: Rebuilds a microservice
      operationId: rebuildMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/start:
    patch:
      tags:
        - Microservices
      summary: Starts a microservice
      operationId: startMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/{uuid}/stop:
    patch:
      tags:
        - Microservices
      summary: Stops a microservice
      operationId: stopMicroservice
      parameters:
        - in: path
          name: uuid
          description: Microservice Uuid
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microservices/exec/{microserviceUuid}:
    get:
      tags:
        - WebSocketSessions
      summary: User exec WebSocket (HTTP upgrade)
      description: >
        Upgrades to a binary MessagePack WebSocket for interactive exec.


        **Auth:** Bearer JWT in `Authorization` header or `?token=` query param.

        **RBAC:** `execSessions` on `microservices` resource.


        Pairing: user connects directly via WebSocket; Controller creates a
        per-session row

        in `MicroserviceExecSessions` and relays STDIN/STDOUT/STDERR by
        `sessionId`.

        No prior REST enable step is required (Plan 17). Max **5** concurrent
        exec sessions

        per microservice (close code **1008** when quota exceeded).


        On connect, Controller sends **ACTIVATION** (type 5) with JSON

        `{ sessionId, microserviceUuid }` in the `data` field and top-level
        `sessionId`,

        followed by STDERR "waiting for agent…". Relay frames use `execId` equal
        to `sessionId`.


        **HA:** Multi-replica deployments require a **relay backend** selected
        at startup by **`nats.enabled`**: AMQP router queues when `false`
        (default), NATS Core pub/sub on the platform hub when `true`.
        Cross-replica sessions fail fast with close code **1013** when the
        active relay backend is unavailable. See
        `docs/operations/ws-sessions.md`.


        See `#/components/schemas/WsExecMessageTypes` and
        `#/components/schemas/WsCloseCodes`.
      operationId: userMicroserviceExecWebSocket
      parameters:
        - in: path
          name: microserviceUuid
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: token
          description: Bearer JWT for browser clients (redact in ingress access logs)
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '101':
          description: Switching Protocols - WebSocket established
        '401':
          description: Not Authorized
        '403':
          description: RBAC denied
  /microservices/system/exec/{microserviceUuid}:
    get:
      tags:
        - WebSocketSessions
      summary: User system microservice exec WebSocket
      description: Same as user exec WS; **RBAC** `systemExecSessions`.
      operationId: userSystemMicroserviceExecWebSocket
      parameters:
        - in: path
          name: microserviceUuid
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: token
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '101':
          description: Switching Protocols
  /microservices/{uuid}/logs:
    get:
      tags:
        - WebSocketSessions
      summary: User microservice log streaming WebSocket
      description: >
        Upgrades to binary MessagePack log stream (agent → user after pairing).


        **RBAC:** `logs`. Max **5** concurrent user log WS per microservice.


        Query params control tail behaviour (see parameters). Live relay only -
        no log persistence.
      operationId: userMicroserviceLogsWebSocket
      parameters:
        - in: path
          name: uuid
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: token
          schema:
            type: string
        - in: query
          name: tail
          description: Number of tail lines (1–5000, default from config)
          schema:
            type: integer
            minimum: 1
            maximum: 5000
        - in: query
          name: follow
          description: Stream new lines after tail (default true)
          schema:
            type: boolean
            default: true
        - in: query
          name: since
          description: ISO 8601 timestamp - include lines after this time
          schema:
            type: string
            format: date-time
        - in: query
          name: until
          description: ISO 8601 timestamp - include lines before this time
          schema:
            type: string
            format: date-time
      security:
        - authToken: []
      responses:
        '101':
          description: Switching Protocols
  /microservices/system/{uuid}/logs:
    get:
      tags:
        - WebSocketSessions
      summary: User system microservice log WebSocket
      operationId: userSystemMicroserviceLogsWebSocket
      parameters:
        - in: path
          name: uuid
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: token
          schema:
            type: string
        - in: query
          name: tail
          schema:
            type: integer
            minimum: 1
            maximum: 5000
        - in: query
          name: follow
          schema:
            type: boolean
        - in: query
          name: since
          schema:
            type: string
            format: date-time
        - in: query
          name: until
          schema:
            type: string
            format: date-time
      security:
        - authToken: []
      responses:
        '101':
          description: Switching Protocols
  /iofog/{uuid}/logs:
    get:
      tags:
        - WebSocketSessions
      summary: User fog (node) log streaming WebSocket
      description: >-
        Node-level logs; **RBAC** `systemLogs`. Max **5** concurrent sessions
        per fog.
      operationId: userFogLogsWebSocket
      parameters:
        - in: path
          name: uuid
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: token
          schema:
            type: string
        - in: query
          name: tail
          schema:
            type: integer
            minimum: 1
            maximum: 5000
        - in: query
          name: follow
          schema:
            type: boolean
        - in: query
          name: since
          schema:
            type: string
            format: date-time
        - in: query
          name: until
          schema:
            type: string
            format: date-time
      security:
        - authToken: []
      responses:
        '101':
          description: Switching Protocols
  /agent/exec/sessions:
    get:
      tags:
        - Agent
      summary: List pending and active exec sessions for this agent
      description: >
        Returns exec sessions for microservices on the authenticated fog node.

        Poll when `GET /agent/changes` reports `execSessions: true` (Plan 17).


        Each entry includes `microserviceUuid`, `sessionId`, `status` (`PENDING`
        | `ACTIVE`),

        and `agentConnected`. Agent connects with

        `WS /agent/exec/microservice/{microserviceUuid}/{sessionId}`.
      operationId: getAgentExecSessions
      security:
        - fogToken: []
      responses:
        '200':
          description: Exec session list
          content:
            application/json:
              schema:
                type: object
                properties:
                  execSessions:
                    type: array
                    items:
                      type: object
                      properties:
                        microserviceUuid:
                          type: string
                          format: uuid
                        sessionId:
                          type: string
                          format: uuid
                        status:
                          type: string
                          enum:
                            - PENDING
                            - ACTIVE
                        agentConnected:
                          type: boolean
        '401':
          description: Not Authorized
  /agent/exec/microservice/{microserviceUuid}/{sessionId}:
    get:
      tags:
        - WebSocketSessions
      summary: Agent exec WebSocket (session-scoped)
      description: >
        Agent-side exec pairing for a specific session. **Auth:** fog token (not
        OIDC).


        Path includes the `sessionId` from `GET /agent/exec/sessions` or from
        user ACTIVATION.

        Controller validates the session row and strict `sessionId` /
        `microserviceUuid` match

        before relay. Legacy `WS /agent/exec/{microserviceUuid}` with initial
        MessagePack frame

        is **removed** (Plan 17, R96).


        Agent handlers validate fog token **before** accepting messages (R86).
      operationId: agentExecMicroserviceWebSocket
      parameters:
        - in: path
          name: microserviceUuid
          required: true
          schema:
            type: string
            format: uuid
        - in: path
          name: sessionId
          required: true
          schema:
            type: string
            format: uuid
      security:
        - fogToken: []
      responses:
        '101':
          description: Switching Protocols
  /agent/logs/microservice/{microserviceUuid}/{sessionId}:
    get:
      tags:
        - WebSocketSessions
      summary: Agent microservice log WebSocket
      operationId: agentMicroserviceLogsWebSocket
      parameters:
        - in: path
          name: microserviceUuid
          required: true
          schema:
            type: string
            format: uuid
        - in: path
          name: sessionId
          required: true
          schema:
            type: string
            format: uuid
      security:
        - fogToken: []
      responses:
        '101':
          description: Switching Protocols
  /agent/logs/iofog/{iofogUuid}/{sessionId}:
    get:
      tags:
        - WebSocketSessions
      summary: Agent fog log WebSocket
      operationId: agentFogLogsWebSocket
      parameters:
        - in: path
          name: iofogUuid
          required: true
          schema:
            type: string
            format: uuid
        - in: path
          name: sessionId
          required: true
          schema:
            type: string
            format: uuid
      security:
        - fogToken: []
      responses:
        '101':
          description: Switching Protocols
  /iofog/{uuid}/tunnel:
    patch:
      tags:
        - Tunnel
      summary: Opens/closes ssh tunnel
      operationId: openIOFogNodeSshTunnel
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ActionBody'
        required: true
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
    get:
      tags:
        - Tunnel
      summary: Gets current info about ioFog node ssh tunnel status
      operationId: getIOFogNodeSshTunnelStatusInfo
      parameters:
        - in: path
          name: uuid
          description: ioFog node id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IOFogNodeTunnelStatusInfoResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Node Id
        '500':
          description: Internal Server Error
  /registries:
    post:
      tags:
        - Registries
      summary: Creates new registry
      operationId: createRegistry
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegistryBody'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    get:
      tags:
        - Registries
      summary: Gets list of registries
      operationId: getRegistryList
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistriesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /registries/{id}:
    delete:
      tags:
        - Registries
      summary: Deletes a registry
      operationId: deleteRegistry
      parameters:
        - in: path
          name: id
          description: Registry id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Deleted
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Invalid Registry Id
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Registries
      summary: Updates a registry
      operationId: updateRegistry
      parameters:
        - in: path
          name: id
          description: Registry id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegistryBody'
        required: true
      responses:
        '204':
          description: Updated
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Invalid Registry Id
        '500':
          description: Internal Server Error
    get:
      tags:
        - Registries
      summary: Gets a registry
      operationId: getRegistry
      parameters:
        - in: path
          name: id
          description: Registry id
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistryResponse'
        '401':
          description: Not Authorized
        '404':
          description: Invalid Registry Id
        '500':
          description: Internal Server Error
  /user/login:
    post:
      tags:
        - User
      summary: Login
      operationId: login
      description: >
        CLI login. The `email` field is the login identifier (username or
        email); bootstrap admin may use a non-email username. User creation via
        POST /users still requires a valid email address.

        When the account has a temporary password (`mustChangePassword`), the
        access token includes JWT claim `password_change_required: true`. RBAC
        allows only `GET /user/profile` and `POST /user/change-password` until
        the password is changed.
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
        required: true
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginSuccessResponse'
        '400':
          description: bad request
        '401':
          description: incorrect credentials
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
  /user/refresh:
    post:
      tags:
        - User
      summary: Refresh accessToken with refreshToken
      operationId: refresh
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
        required: true
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefreshSuccessResponse'
        '400':
          description: bad request
        '401':
          description: incorrect credentials
  /user/logout:
    post:
      tags:
        - User
      summary: Logout
      operationId: logout
      security:
        - authToken: []
      responses:
        '204':
          description: Success
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /user/profile:
    get:
      tags:
        - User
      summary: Get current user profile data
      description: >
        In **embedded** auth mode, returns a flat profile object derived from
        the access token

        plus embedded MFA enrollment state (`mfaEnabled`).


        In **external** auth mode, returns the upstream IdP UserInfo payload
        (shape depends on the IdP).
      operationId: getUserProfile
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserProfileDetailsResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /user/change-password:
    post:
      tags:
        - User
      summary: Change password (authenticated or via reset token)
      operationId: changePassword
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChangePasswordRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: Embedded auth mode only
  /user/mfa/enroll:
    post:
      tags:
        - User
      summary: Begin MFA enrollment (embedded mode)
      operationId: enrollMfa
      security:
        - authToken: []
      description: Start TOTP enrollment for the authenticated user.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MfaEnrollResponse'
        '401':
          description: Not Authorized
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: Embedded auth mode only
  /user/mfa/confirm:
    post:
      tags:
        - User
      summary: Confirm MFA enrollment with TOTP code
      operationId: confirmMfa
      security:
        - authToken: []
      description: Complete TOTP enrollment for the authenticated user.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MfaConfirmRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '400':
          description: Bad Request
        '401':
          description: Invalid credentials or enrollment token
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: Embedded auth mode only
  /user/mfa:
    delete:
      tags:
        - User
      summary: Disable MFA for the current user
      operationId: disableMfa
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MfaDisableRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
  /user/oauth/authorize:
    get:
      tags:
        - User
      summary: Start OAuth authorization (BFF)
      operationId: oauthAuthorize
      description: >
        Browser OAuth BFF entry point for EdgeOps Console. EdgeOps Console Sign
        in performs a full-page redirect here; do **not** POST credentials from
        the browser.

        **External mode:** redirects to the external IdP authorize endpoint.

        **Embedded mode:** redirects to the in-process issuer at
        `{CONTROLLER_PUBLIC_URL}/oidc/auth`, which starts an OAuth interaction
        and redirects the browser to
        `{consoleUrl}{auth.oauthInteractionUrl}?interaction=<uid>` for
        Console-owned login/MFA steps.

        Redirect chain (external):

        `Console → GET /user/oauth/authorize → external IdP (login, MFA,
        password policy) → GET /user/oauth/callback → 302
        {consoleUrl}/login#accessToken=...&refreshToken=...`

        Redirect chain (embedded):

        `Console → GET /user/oauth/authorize → /oidc/auth →
        {consoleUrl}/login/oauth?interaction=<uid> → interaction APIs → GET
        /user/oauth/callback → 302 {consoleUrl}/login#tokens`

        OAuth callback redirect URI:
        `{CONTROLLER_PUBLIC_URL}/api/v3/user/oauth/callback`. Requires
        `CONSOLE_URL` in embedded mode. External mode requires
        `OIDC_ISSUER_URL`, `OIDC_CLIENT_ID`, and `OIDC_CLIENT_SECRET` for the
        confidential Controller client.
      responses:
        '302':
          description: Redirect to IdP or embedded issuer authorization endpoint
        '401':
          description: Auth not configured or OAuth session error
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: Embedded OAuth BFF requires CONSOLE_URL
  /user/oauth/callback:
    get:
      tags:
        - User
      summary: OAuth authorization callback (BFF)
      operationId: oauthCallback
      description: >
        Exchanges the authorization code for tokens using the confidential
        Controller OIDC client. Validates `state` and `nonce` from the server
        session (10-minute TTL). Works in **embedded** and **external** auth
        modes.

        When `CONSOLE_URL` is configured (recommended for browser login),
        responds with **302** to
        `{consoleUrl}/login#accessToken=...&refreshToken=...`. EdgeOps Console
        `/login` parses the URL fragment, stores tokens, clears the hash, and
        navigates to the app. When the issuer returns an OAuth error (e.g.
        `access_denied`), responds with **302** to
        `{consoleUrl}/login?oauthError=...` instead of JSON on the API port.
        When `CONSOLE_URL` is unset, returns JSON **200** `{ accessToken,
        refreshToken }` (CLI/automation only).

        **External forced password change** is enforced by the IdP during
        authorize (e.g. Keycloak required actions: `UPDATE_PASSWORD`).
        **Embedded forced password** uses the interaction `change-password`
        step.

        MFA in external browser login is IdP-owned; embedded browser MFA uses
        interaction endpoints.
      responses:
        '200':
          description: Token response when CONSOLE_URL is not configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginSuccessResponse'
        '302':
          description: >
            Redirect to EdgeOps Console `/login` with tokens in URL fragment on
            success, or `?oauthError=...` when the issuer returned an OAuth
            error (e.g. access_denied).
        '401':
          description: >-
            OAuth session expired, state/nonce mismatch, or authorization code
            exchange failed
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: Embedded OAuth BFF requires CONSOLE_URL
  /user/interaction/{uid}:
    get:
      tags:
        - User
      summary: Get embedded OAuth interaction status
      operationId: interactionStatus
      description: >
        **Embedded auth mode only.** Returns the next interaction step for the
        OAuth BFF flow. Unauthenticated - the interaction uid comes from the
        Viewer redirect query string (`?interaction=<uid>`). Steps: `login`,
        `mfa`, `enroll`, `confirm-enroll`, `change-password`, `complete`.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Current interaction step
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionStepResponse'
        '401':
          description: Interaction session not found or expired
        '501':
          description: External auth mode only (embedded interactions)
  /user/interaction/{uid}/login:
    post:
      tags:
        - User
      summary: Submit credentials for embedded OAuth interaction
      operationId: interactionLogin
      description: >
        **Embedded auth mode only.** Verifies email/login identifier and
        password for the OAuth interaction. Returns the next step on success.
        Failures return **401** (no custom MFA JSON).
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InteractionLoginRequest'
      responses:
        '200':
          description: Credentials accepted; returns next step
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionStepResponse'
        '400':
          description: Validation error
        '401':
          description: Invalid credentials or interaction expired
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /user/interaction/{uid}/mfa:
    post:
      tags:
        - User
      summary: Submit TOTP for embedded OAuth interaction
      operationId: interactionMfa
      description: >
        **Embedded auth mode only.** Verifies TOTP for admin users with MFA
        enabled during the OAuth interaction. Returns the next step on success.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InteractionMfaRequest'
      responses:
        '200':
          description: MFA verified; returns next step
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionStepResponse'
        '400':
          description: Validation error
        '401':
          description: Invalid MFA code or interaction expired
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /user/interaction/{uid}/enroll:
    post:
      tags:
        - User
      summary: Start MFA enrollment during embedded OAuth interaction
      operationId: interactionEnroll
      description: >
        **Embedded auth mode only.** Starts admin MFA enrollment during the
        browser OAuth interaction (browser-only first enrollment). Returns TOTP
        secret material for QR display.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Enrollment started
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionEnrollResponse'
        '400':
          description: Validation error
        '401':
          description: Interaction expired or credentials not verified
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /user/interaction/{uid}/confirm-enroll:
    post:
      tags:
        - User
      summary: Confirm MFA enrollment during embedded OAuth interaction
      operationId: interactionConfirmEnroll
      description: >
        **Embedded auth mode only.** Confirms MFA enrollment with a TOTP code
        during the browser OAuth interaction. Returns recovery codes on success.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InteractionMfaRequest'
      responses:
        '200':
          description: MFA enrollment confirmed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionConfirmEnrollResponse'
        '400':
          description: Validation error
        '401':
          description: Invalid code or interaction expired
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /user/interaction/{uid}/change-password:
    post:
      tags:
        - User
      summary: Forced password change during embedded OAuth interaction
      operationId: interactionChangePassword
      description: >
        **Embedded auth mode only.** Forced password change step before OAuth
        tokens are issued when `mustChangePassword` is true. Requires
        `currentPassword` and `newPassword` in the body.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChangePasswordRequest'
      responses:
        '200':
          description: Password changed; returns next step
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionStepResponse'
        '400':
          description: Validation error
        '401':
          description: Invalid credentials or interaction expired
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /user/interaction/{uid}/complete:
    post:
      tags:
        - User
      summary: Finish embedded OAuth interaction
      operationId: interactionComplete
      description: >
        **Embedded auth mode only.** Completes the oidc-provider interaction
        after all required steps are satisfied. Returns `{ redirectTo }` -
        Viewer should navigate the browser to this URL to resume the OAuth
        authorize flow and reach `/user/oauth/callback`.
      parameters:
        - name: uid
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Interaction finished; resume OAuth at redirectTo
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InteractionCompleteResponse'
        '400':
          description: Required interaction step not yet completed
        '401':
          description: Interaction expired or credentials invalid
        '429':
          $ref: '#/components/responses/AuthRateLimitExceeded'
        '501':
          description: External auth mode only
  /auth/migration/export:
    post:
      tags:
        - Auth Admin
      summary: Export embedded auth users for external IdP migration
      operationId: exportAuthMigration
      description: >-
        Admin-only. Exports user UUIDs, emails, and group memberships. No
        secrets or password hashes.
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthMigrationExportResponse'
        '401':
          description: Not Authorized
        '403':
          description: Forbidden
        '501':
          description: Embedded auth mode only
  /auth/jwks/rotate:
    post:
      tags:
        - Auth Admin
      summary: Rotate embedded OIDC signing keys (manual)
      operationId: rotateAuthJwks
      description: >
        Admin-only. Generates a new JWKS signing key and deactivates the
        previous active key. Restart Controller pods after rotation so the
        embedded issuer loads the new key.
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthJwksRotateResponse'
        '401':
          description: Not Authorized
        '403':
          description: Forbidden
        '501':
          description: Embedded auth mode only
  /users:
    get:
      tags:
        - Auth Users
      summary: List embedded auth users
      operationId: listAuthUsers
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AuthUserResponse'
        '401':
          description: Not Authorized
        '501':
          description: Embedded auth mode only
    post:
      tags:
        - Auth Users
      summary: Create embedded auth user
      operationId: createAuthUser
      description: >
        Admin-created users receive `mustChangePassword: true` so the first
        login forces a password change (browser interaction step or CLI JWT
        `password_change_required` gate).
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthUserCreateRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthUserResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Conflict
        '501':
          description: Embedded auth mode only
  /users/{id}:
    get:
      tags:
        - Auth Users
      summary: Get embedded auth user
      operationId: getAuthUser
      security:
        - authToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthUserResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
    patch:
      tags:
        - Auth Users
      summary: Update embedded auth user
      operationId: updateAuthUser
      security:
        - authToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthUserUpdateRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthUserResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
    delete:
      tags:
        - Auth Users
      summary: Soft-delete embedded auth user
      operationId: deleteAuthUser
      security:
        - authToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Deleted
        '401':
          description: Not Authorized
        '403':
          description: Forbidden
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
  /users/{id}/reset-password:
    post:
      tags:
        - Auth Users
      summary: Reset user password to a temporary value
      operationId: resetAuthUserPassword
      security:
        - authToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthUserResetPasswordResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
  /users/{id}/reset-token:
    post:
      tags:
        - Auth Users
      summary: Issue a one-time password reset token
      operationId: resetAuthUserToken
      security:
        - authToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthUserResetTokenResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
  /groups:
    get:
      tags:
        - Auth Groups
      summary: List auth groups
      operationId: listAuthGroups
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/AuthGroupResponse'
        '401':
          description: Not Authorized
        '501':
          description: Embedded auth mode only
    post:
      tags:
        - Auth Groups
      summary: Create custom auth group
      operationId: createAuthGroup
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthGroupCreateRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthGroupResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Conflict
        '501':
          description: Embedded auth mode only
  /groups/{name}:
    get:
      tags:
        - Auth Groups
      summary: Get auth group
      operationId: getAuthGroup
      security:
        - authToken: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
          description: Unique auth group name (e.g. viewer, platform-ops)
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthGroupResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
    patch:
      tags:
        - Auth Groups
      summary: Update auth group
      operationId: updateAuthGroup
      description: >
        Updates a custom auth group name and/or `mfaRequired`. System groups
        (`admin`, `sre`, `developer`, `viewer`) allow `mfaRequired` changes
        only; rename is forbidden. Requires RBAC `authGroups` resource with
        `patch` verb.
      security:
        - authToken: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
          description: Current auth group name
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthGroupUpdateRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthGroupResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '403':
          description: Forbidden
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
    delete:
      tags:
        - Auth Groups
      summary: Delete custom auth group
      operationId: deleteAuthGroup
      security:
        - authToken: []
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
          description: Auth group name
      responses:
        '204':
          description: Deleted
        '401':
          description: Not Authorized
        '403':
          description: Forbidden
        '404':
          description: Not Found
        '501':
          description: Embedded auth mode only
  /secrets:
    post:
      tags:
        - Secrets
      summary: Creates a new secret
      operationId: createSecret
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SecretCreate'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Secret Already Exists
        '500':
          description: Internal Server Error
    get:
      tags:
        - Secrets
      summary: Lists all secrets
      operationId: listSecrets
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /secrets/{name}:
    get:
      tags:
        - Secrets
      summary: Gets a secret by name
      operationId: getSecret
      parameters:
        - in: path
          name: name
          description: Secret name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretResponse'
        '401':
          description: Not Authorized
        '404':
          description: Secret Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Secrets
      summary: Updates an existing secret
      operationId: updateSecret
      parameters:
        - in: path
          name: name
          description: Secret name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SecretUpdate'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Secret Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Secrets
      summary: Deletes a secret
      operationId: deleteSecret
      parameters:
        - in: path
          name: name
          description: Secret name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
        '401':
          description: Not Authorized
        '404':
          description: Secret Not Found
        '500':
          description: Internal Server Error
  /secrets/yaml:
    post:
      tags:
        - Secrets
      summary: Create a secret from YAML file
      operationId: createSecretFromYAML
      security:
        - authToken: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                secret:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Secret Already Exists
        '500':
          description: Internal Server Error
  /secrets/yaml/{name}:
    patch:
      tags:
        - Secrets
      summary: Updates an existing secret using YAML
      operationId: updateSecretFromYAML
      parameters:
        - in: path
          name: name
          description: Secret name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                secret:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SecretResponse'
        '400':
          description: Bad Request
        '401':
          description: Unauthorized
        '404':
          description: Secret Not Found
  /certificates/ca/{name}:
    get:
      tags:
        - Certificates
      summary: Get a Certificate Authority (CA) by name
      operationId: getCA
      parameters:
        - in: path
          name: name
          description: CA name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CAResponse'
        '401':
          description: Unauthorized
        '404':
          description: CA not found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Certificates
      summary: Delete a Certificate Authority (CA) by name
      operationId: deleteCA
      parameters:
        - in: path
          name: name
          description: CA name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
        '401':
          description: Unauthorized
        '404':
          description: CA not found
        '500':
          description: Internal Server Error
  /certificates:
    post:
      tags:
        - Certificates
      summary: Create a new certificate
      operationId: createCertificate
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CertificateCreateRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateResponse'
        '400':
          description: Bad Request
        '401':
          description: Unauthorized
        '404':
          description: Not Found - Referenced CA not found
        '409':
          description: Conflict - Certificate already exists
    get:
      tags:
        - Certificates
      summary: List all certificates
      operationId: listCertificates
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateListResponse'
        '401':
          description: Unauthorized
        '500':
          description: Internal Server Error
  /certificates/expiring:
    get:
      tags:
        - Certificates
      summary: List certificates that will expire soon
      operationId: listExpiringCertificates
      parameters:
        - in: query
          name: days
          description: Number of days ahead to check for expiration (default 30)
          required: false
          schema:
            type: integer
            default: 30
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateListResponse'
        '400':
          description: Bad Request
        '401':
          description: Unauthorized
        '500':
          description: Internal Server Error
  /certificates/{name}:
    get:
      tags:
        - Certificates
      summary: Get a certificate by name
      operationId: getCertificate
      parameters:
        - in: path
          name: name
          description: Certificate name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateResponse'
        '401':
          description: Unauthorized
        '404':
          description: Certificate not found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Certificates
      summary: Delete a certificate by name
      operationId: deleteCertificate
      parameters:
        - in: path
          name: name
          description: Certificate name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
        '401':
          description: Unauthorized
        '404':
          description: Certificate not found
        '500':
          description: Internal Server Error
  /certificates/{name}/renew:
    post:
      tags:
        - Certificates
      summary: Renew a certificate
      operationId: renewCertificate
      parameters:
        - in: path
          name: name
          description: Certificate name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateRenewResponse'
        '400':
          description: Bad Request
        '401':
          description: Unauthorized
        '404':
          description: Certificate not found
        '500':
          description: Internal Server Error
  /certificates/yaml:
    post:
      tags:
        - Certificates
      summary: Create a certificate or CA from YAML file
      operationId: createCertificateFromYAML
      security:
        - authToken: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                certificate:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/CAResponse'
                  - $ref: '#/components/schemas/CertificateResponse'
        '400':
          description: Bad Request
        '401':
          description: Unauthorized
        '404':
          description: Not Found - Referenced CA not found
        '409':
          description: Conflict - Certificate or CA already exists
  /services:
    get:
      tags:
        - Services
      summary: Gets list of services
      operationId: getServicesList
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Service'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Services
      summary: Creates a new service
      operationId: createService
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Service'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
  /services/{name}:
    get:
      tags:
        - Services
      summary: Gets a service info
      operationId: getServiceInfo
      parameters:
        - in: path
          name: name
          description: Service name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Services
      summary: Deletes a service
      operationId: deleteService
      parameters:
        - in: path
          name: name
          description: Service name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Services
      summary: Patches a service
      operationId: patchService
      parameters:
        - in: path
          name: name
          description: Service name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Service'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /services/{name}/reconcile:
    post:
      tags:
        - Services
      summary: Manually retries service platform reconcile
      description: >-
        Enqueues a service platform reconcile task. When `provisioningStatus` is
        `failed`, resets it to `pending` and clears `provisioningError` before
        enqueue. Hub connector/listener, K8s Service, and ConfigMap updates run
        asynchronously in the platform reconcile worker.
        `provisioningStatus=ready` means hub provisioning completed
        successfully; tagged edge fogs receive bridge updates via separate fog
        platform reconcile tasks.
      operationId: reconcileService
      parameters:
        - in: path
          name: name
          description: Service name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /services/yaml:
    post:
      tags:
        - Services
      summary: Creates a new service from YAML
      operationId: createServiceYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                service:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: number
                  name:
                    type: string
                  type:
                    type: string
                  resource:
                    type: string
                  targetPort:
                    type: number
                  defaultBridge:
                    type: string
                  bridgePort:
                    type: number
                  updatedAt:
                    type: string
                    format: date-time
                  createdAt:
                    type: string
                    format: date-time
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Duplicate Name
        '500':
          description: Internal Server Error
  /services/yaml/{name}:
    patch:
      tags:
        - Services
      summary: Updates a service using YAML
      operationId: updateServiceYAML
      parameters:
        - in: path
          name: name
          description: Service name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                service:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Service'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /configmaps:
    post:
      tags:
        - ConfigMap
      summary: Creates a new ConfigMap
      operationId: createConfigMap
      security:
        - authToken: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigMapCreate'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: ConfigMap Already Exists
        '500':
          description: Internal Server Error
    get:
      tags:
        - ConfigMap
      summary: Lists all ConfigMaps
      operationId: listConfigMaps
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /configmaps/yaml:
    post:
      tags:
        - ConfigMap
      summary: Creates a new ConfigMap from YAML
      operationId: createConfigMapFromYaml
      security:
        - authToken: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                configMap:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: ConfigMap Already Exists
        '500':
          description: Internal Server Error
  /configmaps/{name}:
    get:
      tags:
        - ConfigMap
      summary: Gets a ConfigMap by name
      operationId: getConfigMap
      security:
        - authToken: []
      parameters:
        - in: path
          name: name
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapResponse'
        '401':
          description: Not Authorized
        '404':
          description: ConfigMap Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - ConfigMap
      summary: Updates a ConfigMap
      operationId: updateConfigMap
      security:
        - authToken: []
      parameters:
        - in: path
          name: name
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfigMapUpdate'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: ConfigMap Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - ConfigMap
      summary: Deletes a ConfigMap
      operationId: deleteConfigMap
      security:
        - authToken: []
      parameters:
        - in: path
          name: name
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: Not Authorized
        '404':
          description: ConfigMap Not Found
        '500':
          description: Internal Server Error
  /configmaps/yaml/{name}:
    patch:
      tags:
        - ConfigMap
      summary: Updates a ConfigMap from YAML
      operationId: updateConfigMapFromYaml
      security:
        - authToken: []
      parameters:
        - in: path
          name: name
          required: true
          schema:
            type: string
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                configMap:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfigMapResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: ConfigMap Not Found
        '500':
          description: Internal Server Error
  /volumeMounts:
    get:
      tags:
        - VolumeMounts
      summary: Returns list of volume mounts
      operationId: listVolumeMounts
      security:
        - authToken: []
      responses:
        '200':
          description: List of volume mounts
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/VolumeMount'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - VolumeMounts
      summary: Creates a new volume mount
      operationId: createVolumeMount
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMountCreate'
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /volumeMounts/yaml:
    post:
      tags:
        - VolumeMounts
      summary: Creates a new volume mount from YAML
      operationId: createVolumeMountYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/x-yaml:
            schema:
              type: string
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /volumeMounts/{name}:
    get:
      tags:
        - VolumeMounts
      summary: Gets volume mount info
      operationId: getVolumeMount
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - VolumeMounts
      summary: Updates existing volume mount
      operationId: updateVolumeMount
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMountUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - VolumeMounts
      summary: Deletes a volume mount
      operationId: deleteVolumeMount
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /volumeMounts/yaml/{name}:
    patch:
      tags:
        - VolumeMounts
      summary: Updates existing volume mount from YAML
      operationId: updateVolumeMountYaml
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/x-yaml:
            schema:
              type: string
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /volumeMounts/{name}/link:
    get:
      tags:
        - VolumeMounts
      summary: Gets volume mount link info
      operationId: getVolumeMountLink
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  fogUuids:
                    type: array
                    items:
                      type: string
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    post:
      tags:
        - VolumeMounts
      summary: Links volume mount to fog nodes
      operationId: linkVolumeMount
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMountLink'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - VolumeMounts
      summary: Unlinks volume mount from fog nodes
      operationId: unlinkVolumeMount
      parameters:
        - in: path
          name: name
          description: Volume mount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VolumeMountUnlink'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VolumeMount'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /models:
    get:
      tags:
        - Models
      summary: Returns fleet models
      operationId: listModels
      security:
        - authToken: []
      responses:
        '200':
          description: List of fleet models
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelsListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Models
      summary: Creates a fleet model
      description: Server generates uuid. Name is unique and immutable after create.
      operationId: createModel
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModelCreate'
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /models/yaml:
    post:
      tags:
        - Models
      summary: Creates a fleet model from YAML
      operationId: createModelYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                model:
                  type: string
                  format: binary
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /models/{name}:
    get:
      tags:
        - Models
      summary: Gets a fleet model
      description: Does not include linked fog uuids. Use GET /models/{name}/link.
      operationId: getModel
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Models
      summary: Updates a fleet model
      description: Name is immutable.
      operationId: updateModel
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ModelUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Models
      summary: Deletes a fleet model
      description: Refused when any microservice binds the model name.
      operationId: deleteModel
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Model is bound by a microservice
        '500':
          description: Internal Server Error
  /models/yaml/{name}:
    put:
      tags:
        - Models
      summary: Creates or updates a fleet model from YAML
      operationId: upsertModelYaml
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                model:
                  type: string
                  format: binary
      responses:
        '200':
          description: Upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Conflict
        '500':
          description: Internal Server Error
  /models/{name}/link:
    get:
      tags:
        - Models
      summary: Gets fogs linked to a fleet model
      operationId: getModelLink
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    post:
      tags:
        - Models
      summary: Links a fleet model to fog nodes
      operationId: linkModel
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Models
      summary: Unlinks a fleet model from fog nodes
      description: Refused when a microservice on that fog still binds the model name.
      operationId: unlinkModel
      parameters:
        - in: path
          name: name
          description: Model name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Model is bound by a microservice on the fog
        '500':
          description: Internal Server Error
  /knowledge:
    get:
      tags:
        - Knowledge
      summary: Returns fleet Knowledge
      operationId: listKnowledge
      security:
        - authToken: []
      responses:
        '200':
          description: List of fleet Knowledge
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KnowledgeListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Knowledge
      summary: Creates fleet Knowledge
      description: >-
        Server generates uuid. Name is unique and immutable after create. Names
        are a separate namespace from Models. Hugging Face pulls use the dataset
        API. files is Hugging Face only; a non-empty files array on an OCI
        registry is rejected. format is an optional soft hint (see
        Knowledge.format).
      operationId: createKnowledge
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/KnowledgeCreate'
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Knowledge'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /knowledge/yaml:
    post:
      tags:
        - Knowledge
      summary: Creates fleet Knowledge from YAML
      description: >-
        kind Knowledge. spec.registry is an alias of registryId. apiVersion
        iofog.org/v3 or datasance.com/v3.
      operationId: createKnowledgeYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                knowledge:
                  type: string
                  format: binary
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Knowledge'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /knowledge/{name}:
    get:
      tags:
        - Knowledge
      summary: Gets fleet Knowledge
      description: Does not include linked fog uuids. Use GET /knowledge/{name}/link.
      operationId: getKnowledge
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Knowledge'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Knowledge
      summary: Updates fleet Knowledge
      description: Name is immutable. format follows the same soft-hint rules as create.
      operationId: updateKnowledge
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/KnowledgeUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Knowledge'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Knowledge
      summary: Deletes fleet Knowledge
      description: Refused when any microservice binds the Knowledge name.
      operationId: deleteKnowledge
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Knowledge is bound by a microservice
        '500':
          description: Internal Server Error
  /knowledge/yaml/{name}:
    put:
      tags:
        - Knowledge
      summary: Creates or updates fleet Knowledge from YAML
      operationId: upsertKnowledgeYaml
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                knowledge:
                  type: string
                  format: binary
      responses:
        '200':
          description: Upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Knowledge'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Conflict
        '500':
          description: Internal Server Error
  /knowledge/{name}/link:
    get:
      tags:
        - Knowledge
      summary: Gets fogs linked to fleet Knowledge
      operationId: getKnowledgeLink
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    post:
      tags:
        - Knowledge
      summary: Links fleet Knowledge to fog nodes
      operationId: linkKnowledge
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Knowledge
      summary: Unlinks fleet Knowledge from fog nodes
      description: Refused when a microservice on that fog still binds the Knowledge name.
      operationId: unlinkKnowledge
      parameters:
        - in: path
          name: name
          description: Knowledge name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Knowledge is bound by a microservice on the fog
        '500':
          description: Internal Server Error
  /runtimeClasses:
    get:
      tags:
        - RuntimeClasses
      summary: Returns fleet RuntimeClasses
      operationId: listRuntimeClasses
      security:
        - authToken: []
      responses:
        '200':
          description: List of RuntimeClasses
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClassesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - RuntimeClasses
      summary: Creates a RuntimeClass
      description: Name plus handler. Built-in catalog rows are not seeded.
      operationId: createRuntimeClass
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RuntimeClassCreate'
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClass'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /runtimeClasses/yaml:
    post:
      tags:
        - RuntimeClasses
      summary: Creates a RuntimeClass from YAML
      operationId: createRuntimeClassYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                runtimeClass:
                  type: string
                  format: binary
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClass'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /runtimeClasses/{name}:
    get:
      tags:
        - RuntimeClasses
      summary: Gets a RuntimeClass
      description: Does not include linked fog uuids. Use GET /runtimeClasses/{name}/link.
      operationId: getRuntimeClass
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClass'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - RuntimeClasses
      summary: Updates a RuntimeClass
      description: Name is immutable. Non-catalog handlers may bounce the data plane.
      operationId: updateRuntimeClass
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RuntimeClassUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClass'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - RuntimeClasses
      summary: Deletes a RuntimeClass
      description: Refused when any microservice pins runtime to this name.
      operationId: deleteRuntimeClass
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: RuntimeClass is pinned by a microservice
        '500':
          description: Internal Server Error
  /runtimeClasses/yaml/{name}:
    put:
      tags:
        - RuntimeClasses
      summary: Creates or updates a RuntimeClass from YAML
      operationId: upsertRuntimeClassYaml
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                runtimeClass:
                  type: string
                  format: binary
      responses:
        '200':
          description: Upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RuntimeClass'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Conflict
        '500':
          description: Internal Server Error
  /runtimeClasses/{name}/link:
    get:
      tags:
        - RuntimeClasses
      summary: Gets fogs linked to a RuntimeClass
      operationId: getRuntimeClassLink
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    post:
      tags:
        - RuntimeClasses
      summary: Links a RuntimeClass to fog nodes
      description: >-
        Attach is refused when fog containerEngine is not edgelet or when the
        RuntimeClass name is not in the fog availableRuntimes list.
      operationId: linkRuntimeClass
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Fog is not edgelet, or request invalid
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - RuntimeClasses
      summary: Unlinks a RuntimeClass from fog nodes
      description: Refused when a microservice on that fog still pins runtime to this name.
      operationId: unlinkRuntimeClass
      parameters:
        - in: path
          name: name
          description: RuntimeClass name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FogLinkRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FogLinkSet'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: RuntimeClass is pinned by a microservice on the fog
        '500':
          description: Internal Server Error
  /microserviceTemplates:
    get:
      tags:
        - Microservice Templates
      summary: Returns microservice templates
      operationId: listMicroserviceTemplates
      security:
        - authToken: []
      responses:
        '200':
          description: List of microservice templates
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplatesListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Microservice Templates
      summary: Creates a microservice template
      operationId: createMicroserviceTemplate
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MicroserviceTemplateCreate'
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplate'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /microserviceTemplates/yaml:
    post:
      tags:
        - Microservice Templates
      summary: Creates a microservice template from YAML
      operationId: createMicroserviceTemplateYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                template:
                  type: string
                  format: binary
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplate'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Name already exists
        '500':
          description: Internal Server Error
  /microserviceTemplates/{name}:
    get:
      tags:
        - Microservice Templates
      summary: Gets a microservice template
      operationId: getMicroserviceTemplate
      parameters:
        - in: path
          name: name
          description: Template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplate'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Microservice Templates
      summary: Updates a microservice template
      description: Name is immutable.
      operationId: updateMicroserviceTemplate
      parameters:
        - in: path
          name: name
          description: Template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MicroserviceTemplateUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplate'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Microservice Templates
      summary: Deletes a microservice template
      operationId: deleteMicroserviceTemplate
      parameters:
        - in: path
          name: name
          description: Template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '202':
          description: Accepted
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /microserviceTemplates/yaml/{name}:
    put:
      tags:
        - Microservice Templates
      summary: Creates or updates a microservice template from YAML
      operationId: upsertMicroserviceTemplateYaml
      parameters:
        - in: path
          name: name
          description: Template name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                template:
                  type: string
                  format: binary
      responses:
        '200':
          description: Upserted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MicroserviceTemplate'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '409':
          description: Conflict
        '500':
          description: Internal Server Error
  /events:
    get:
      tags:
        - Events
      summary: List audit events
      description: Retrieve audit events with optional filters and pagination.
      operationId: listEvents
      security:
        - authToken: []
      parameters:
        - in: query
          name: limit
          description: Maximum number of events to return (default 200, max 1000)
          schema:
            type: integer
            minimum: 1
            maximum: 1000
          required: false
        - in: query
          name: offset
          description: Number of events to skip before collecting results
          schema:
            type: integer
            minimum: 0
          required: false
        - in: query
          name: startTime
          description: Start of time range (Unix timestamp in ms or ISO 8601)
          schema:
            type: string
          required: false
        - in: query
          name: endTime
          description: End of time range (Unix timestamp in ms or ISO 8601)
          schema:
            type: string
          required: false
        - in: query
          name: endpointType
          description: Filter by endpoint type (agent or user)
          schema:
            type: string
          required: false
        - in: query
          name: resourceType
          description: Filter by resource type (agent, microservice, etc.)
          schema:
            type: string
          required: false
        - in: query
          name: status
          description: Filter by status (SUCCESS or FAILED)
          schema:
            type: string
          required: false
        - in: query
          name: method
          description: Filter by HTTP/WS method(s)
          schema:
            type: array
            items:
              type: string
          style: form
          explode: true
          required: false
        - in: query
          name: actorId
          description: Filter by actor identifier (username or fog UUID)
          schema:
            type: string
          required: false
        - in: query
          name: eventType
          description: Filter by event type (HTTP, WS_CONNECT, WS_DISCONNECT)
          schema:
            type: string
          required: false
      responses:
        '200':
          description: Events list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Events
      summary: Delete audit events
      description: >-
        Delete all events when `days` is 0, or delete events older than the
        provided number of days.
      operationId: deleteEvents
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventDeleteRequest'
      responses:
        '200':
          description: Deletion summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventDeleteResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /roles:
    get:
      tags:
        - Roles
      summary: Lists all roles
      operationId: listRoles
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - Roles
      summary: Creates a new role
      operationId: createRole
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleCreateRequest'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Role Already Exists
        '500':
          description: Internal Server Error
  /roles/yaml:
    post:
      tags:
        - Roles
      summary: Create a role from YAML file
      operationId: createRoleFromYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                role:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Role Already Exists
        '500':
          description: Internal Server Error
  /roles/{name}:
    get:
      tags:
        - Roles
      summary: Gets a role by name
      operationId: getRole
      parameters:
        - in: path
          name: name
          description: Role name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '401':
          description: Not Authorized
        '404':
          description: Role Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - Roles
      summary: Updates an existing role
      operationId: updateRole
      parameters:
        - in: path
          name: name
          description: Role name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleCreateRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Role Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - Roles
      summary: Deletes a role
      operationId: deleteRole
      parameters:
        - in: path
          name: name
          description: Role name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: Role Not Found
        '500':
          description: Internal Server Error
  /roles/yaml/{name}:
    patch:
      tags:
        - Roles
      summary: Updates an existing role using YAML
      operationId: updateRoleFromYAML
      parameters:
        - in: path
          name: name
          description: Role name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                role:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Role Not Found
        '500':
          description: Internal Server Error
  /rolebindings:
    get:
      tags:
        - RoleBindings
      summary: Lists all role bindings
      operationId: listRoleBindings
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - RoleBindings
      summary: Creates a new role binding
      operationId: createRoleBinding
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleBindingCreateRequest'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: RoleBinding Already Exists
        '500':
          description: Internal Server Error
  /rolebindings/yaml:
    post:
      tags:
        - RoleBindings
      summary: Create a role binding from YAML file
      operationId: createRoleBindingFromYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                rolebinding:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: RoleBinding Already Exists
        '500':
          description: Internal Server Error
  /rolebindings/{name}:
    get:
      tags:
        - RoleBindings
      summary: Gets a role binding by name
      operationId: getRoleBinding
      parameters:
        - in: path
          name: name
          description: RoleBinding name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingResponse'
        '401':
          description: Not Authorized
        '404':
          description: RoleBinding Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - RoleBindings
      summary: Updates an existing role binding
      operationId: updateRoleBinding
      parameters:
        - in: path
          name: name
          description: RoleBinding name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleBindingCreateRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: RoleBinding Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - RoleBindings
      summary: Deletes a role binding
      operationId: deleteRoleBinding
      parameters:
        - in: path
          name: name
          description: RoleBinding name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: RoleBinding Not Found
        '500':
          description: Internal Server Error
  /rolebindings/yaml/{name}:
    patch:
      tags:
        - RoleBindings
      summary: Updates an existing role binding using YAML
      operationId: updateRoleBindingFromYAML
      parameters:
        - in: path
          name: name
          description: RoleBinding name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                rolebinding:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleBindingResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: RoleBinding Not Found
        '500':
          description: Internal Server Error
  /network-topology/summary:
    get:
      tags:
        - NetworkTopology
      summary: Network topology summary counts
      operationId: getNetworkTopologySummary
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NetworkTopologySummaryResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/router/overview:
    get:
      tags:
        - NetworkTopology
      summary: Router topology overview
      operationId: getRouterTopologyOverview
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterTopologyOverviewResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/nats/overview:
    get:
      tags:
        - NetworkTopology
      summary: NATS topology overview
      operationId: getNatsTopologyOverview
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsTopologyOverviewResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/router/nodes:
    get:
      tags:
        - NetworkTopology
      summary: List router topology nodes
      operationId: listRouterTopologyNodes
      security:
        - authToken: []
      parameters:
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
        - $ref: '#/components/parameters/NetworkTopologyOffsetParam'
        - $ref: '#/components/parameters/NetworkTopologyRouterRoleParam'
        - $ref: '#/components/parameters/NetworkTopologyDeploymentTargetParam'
        - $ref: '#/components/parameters/NetworkTopologySearchParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterTopologyNodeListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/nats/nodes:
    get:
      tags:
        - NetworkTopology
      summary: List NATS topology nodes
      operationId: listNatsTopologyNodes
      security:
        - authToken: []
      parameters:
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
        - $ref: '#/components/parameters/NetworkTopologyOffsetParam'
        - $ref: '#/components/parameters/NetworkTopologyNatsRoleParam'
        - $ref: '#/components/parameters/NetworkTopologyDeploymentTargetParam'
        - $ref: '#/components/parameters/NetworkTopologySearchParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsTopologyNodeListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/router/nodes/{id}:
    get:
      tags:
        - NetworkTopology
      summary: Get a router topology node
      operationId: getRouterTopologyNode
      security:
        - authToken: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: Router node id (`default-router` or agent iofog UUID)
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterTopologyNodeDetail'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /network-topology/nats/nodes/{id}:
    get:
      tags:
        - NetworkTopology
      summary: Get a NATS topology node
      operationId: getNatsTopologyNode
      security:
        - authToken: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: NATS node id (`default-nats-hub` or agent iofog UUID)
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsTopologyNodeDetail'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /network-topology/router/nodes/{id}/connections:
    get:
      tags:
        - NetworkTopology
      summary: Get router node connections
      operationId: getRouterTopologyNodeConnections
      security:
        - authToken: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopologyNodeConnectionsResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /network-topology/nats/nodes/{id}/connections:
    get:
      tags:
        - NetworkTopology
      summary: Get NATS node connections
      operationId: getNatsTopologyNodeConnections
      security:
        - authToken: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopologyNodeConnectionsResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /network-topology/router/connections:
    get:
      tags:
        - NetworkTopology
      summary: List router topology connections
      operationId: listRouterTopologyConnections
      security:
        - authToken: []
      parameters:
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
        - $ref: '#/components/parameters/NetworkTopologyOffsetParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterTopologyConnectionListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/nats/connections:
    get:
      tags:
        - NetworkTopology
      summary: List NATS topology connections
      operationId: listNatsTopologyConnections
      security:
        - authToken: []
      parameters:
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
        - $ref: '#/components/parameters/NetworkTopologyOffsetParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsTopologyConnectionListResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /network-topology/router/subgraph:
    get:
      tags:
        - NetworkTopology
      summary: Get router topology subgraph
      operationId: getRouterTopologySubgraph
      security:
        - authToken: []
      parameters:
        - in: query
          name: center
          required: true
          schema:
            type: string
        - in: query
          name: depth
          schema:
            type: integer
            minimum: 1
            maximum: 2
            default: 1
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopologySubgraphResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /network-topology/nats/subgraph:
    get:
      tags:
        - NetworkTopology
      summary: Get NATS topology subgraph
      operationId: getNatsTopologySubgraph
      security:
        - authToken: []
      parameters:
        - in: query
          name: center
          required: true
          schema:
            type: string
        - in: query
          name: depth
          schema:
            type: integer
            minimum: 1
            maximum: 2
            default: 1
        - $ref: '#/components/parameters/NetworkTopologyLimitParam'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TopologySubgraphResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
        '500':
          description: Internal Server Error
  /router:
    get:
      tags:
        - Router
      summary: Gets the default network router configuration
      operationId: getDefaultRouter
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DefaultRouterResponse'
        '401':
          description: Not Authorized
        '404':
          description: Default router not found
        '500':
          description: Internal Server Error
    put:
      tags:
        - Router
      summary: Creates or updates the default network router
      operationId: upsertDefaultRouter
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DefaultRouterUpsertRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DefaultRouterRecordResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
  /serviceaccounts:
    get:
      tags:
        - ServiceAccounts
      summary: Lists all service accounts
      operationId: listServiceAccounts
      parameters:
        - in: query
          name: applicationName
          description: Filter by application name
          required: false
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountListResponse'
        '401':
          description: Not Authorized
        '500':
          description: Internal Server Error
    post:
      tags:
        - ServiceAccounts
      summary: Creates a new service account
      operationId: createServiceAccount
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ServiceAccountCreateRequest'
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: ServiceAccount Already Exists
        '500':
          description: Internal Server Error
  /serviceaccounts/yaml:
    post:
      tags:
        - ServiceAccounts
      summary: Create a service account from YAML file
      description: >
        The YAML file must include metadata.applicationName (application name
        this service account belongs to),

        metadata.name (service account name), and roleRef with a name. Example:

        kind: ServiceAccount

        metadata:
          name: my-sa
          applicationName: my-app
        roleRef:
          kind: Role
          name: microservice
      operationId: createServiceAccountFromYAML
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                serviceaccount:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: ServiceAccount Already Exists
        '500':
          description: Internal Server Error
  /serviceaccounts/{appName}/{name}:
    get:
      tags:
        - ServiceAccounts
      summary: Gets a service account by application name and service account name
      operationId: getServiceAccount
      parameters:
        - in: path
          name: appName
          description: Application name
          required: true
          schema:
            type: string
        - in: path
          name: name
          description: ServiceAccount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountResponse'
        '401':
          description: Not Authorized
        '404':
          description: ServiceAccount Not Found
        '500':
          description: Internal Server Error
    patch:
      tags:
        - ServiceAccounts
      summary: Updates an existing service account
      operationId: updateServiceAccount
      parameters:
        - in: path
          name: appName
          description: Application name
          required: true
          schema:
            type: string
        - in: path
          name: name
          description: ServiceAccount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ServiceAccountCreateRequest'
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: ServiceAccount Not Found
        '500':
          description: Internal Server Error
    delete:
      tags:
        - ServiceAccounts
      summary: Deletes a service account
      operationId: deleteServiceAccount
      parameters:
        - in: path
          name: appName
          description: Application name
          required: true
          schema:
            type: string
        - in: path
          name: name
          description: ServiceAccount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
        '401':
          description: Not Authorized
        '404':
          description: ServiceAccount Not Found
        '409':
          description: Conflict - ServiceAccount is referenced by a microservice
        '500':
          description: Internal Server Error
  /serviceaccounts/yaml/{appName}/{name}:
    patch:
      tags:
        - ServiceAccounts
      summary: Updates an existing service account using YAML
      operationId: updateServiceAccountFromYAML
      parameters:
        - in: path
          name: appName
          description: Application name
          required: true
          schema:
            type: string
        - in: path
          name: name
          description: ServiceAccount name
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                serviceaccount:
                  type: string
                  format: binary
      responses:
        '200':
          description: Success
          headers:
            X-Timestamp:
              description: FogController server timestamp
              schema:
                type: number
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceAccountResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: ServiceAccount Not Found
        '500':
          description: Internal Server Error
  /nats/operator:
    get:
      tags:
        - NATS
      summary: Gets current NATS operator metadata
      operationId: getNatsOperator
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsOperatorResponse'
        '401':
          description: Not Authorized
  /nats/operator/rotate:
    post:
      tags:
        - NATS
      summary: Rotates NATS operator keys and JWT
      description: >-
        Schedules account/user re-sign and resolver reconciliation in background
        after operator rotation is accepted.
      operationId: rotateNatsOperator
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsOperatorResponse'
        '401':
          description: Not Authorized
  /nats/bootstrap:
    get:
      tags:
        - NATS
      summary: >-
        Returns NATS operator and hub system user bootstrap data for K8s
        installer
      operationId: getNatsBootstrap
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsBootstrapResponse'
        '401':
          description: Not Authorized
        '403':
          description: >-
            Forbidden (only available when Controller runs on Kubernetes control
            plane)
        '404':
          description: Not Found (bootstrap data or secrets missing)
  /nats/hub:
    get:
      tags:
        - NATS
      summary: Gets default NATS hub configuration
      operationId: getNatsHub
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsHubResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
    put:
      tags:
        - NATS
      summary: Creates or updates default NATS hub
      operationId: upsertNatsHub
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsHubRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsHubResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
  /nats/users:
    get:
      tags:
        - NATS
      summary: Lists all NATS users across accounts
      operationId: listAllNatsUsers
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAllUsersListResponse'
        '401':
          description: Not Authorized
  /nats/accounts:
    get:
      tags:
        - NATS
      summary: Lists NATS accounts
      operationId: listNatsAccounts
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAccountsListResponse'
        '401':
          description: Not Authorized
  /nats/accounts/{appName}:
    get:
      tags:
        - NATS
      summary: Gets NATS account for application
      operationId: getNatsAccountByApp
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAccountResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
    post:
      tags:
        - NATS
      summary: Ensures NATS account for application
      operationId: ensureNatsAccountByApp
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsAccountEnsureRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAccountResponse'
        '400':
          description: >-
            Bad Request (e.g. application already has NATS enabled or unknown
            rule name)
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/accounts/{appName}/users:
    get:
      tags:
        - NATS
      summary: Lists NATS users for application account
      operationId: listNatsUsersByApp
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsUsersListResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
    post:
      tags:
        - NATS
      summary: Creates NATS user for application account
      operationId: createNatsUserByApp
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsUserCreateRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsUserResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/accounts/{appName}/users/{userName}/creds:
    get:
      tags:
        - NATS
      summary: Gets NATS creds for specific account user
      description: >
        Returns base64-encoded `.creds` file content for the user.


        Path `{appName}` is an **application name** for app-linked accounts, or
        a **NATS account name** for platform/system accounts (`SYS`, leaf
        accounts, **`controller`**).
      operationId: getNatsUserCreds
      parameters:
        - in: path
          name: appName
          required: true
          description: Application name or NATS account name (e.g. `SYS`, `controller`)
          schema:
            type: string
        - in: path
          name: userName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsCredsResponse'
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/accounts/{appName}/users/{userName}:
    delete:
      tags:
        - NATS
      summary: Deletes NATS account user
      operationId: deleteNatsUserByApp
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
        - in: path
          name: userName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: No Content
        '400':
          description: Bad Request (e.g. user linked to existing microservice)
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/accounts/{appName}/mqtt-bearer:
    post:
      tags:
        - NATS
      summary: Creates MQTT bearer NATS user JWT
      operationId: createNatsMqttBearer
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsUserCreateRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsUserResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/accounts/{appName}/mqtt-bearer/{userName}:
    delete:
      tags:
        - NATS
      summary: Deletes MQTT bearer NATS user
      operationId: deleteNatsMqttBearer
      parameters:
        - in: path
          name: appName
          required: true
          schema:
            type: string
        - in: path
          name: userName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: No Content
        '400':
          description: Bad Request (e.g. not a bearer user or user linked to microservice)
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/account-rules:
    get:
      tags:
        - NATS
      summary: Lists NATS account rules
      operationId: listNatsAccountRules
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAccountRuleListResponse'
        '401':
          description: Not Authorized
    post:
      tags:
        - NATS
      summary: Creates NATS account rule
      operationId: createNatsAccountRule
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsAccountRulePayload'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsAccountRulePayload'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
  /nats/account-rules/yaml:
    post:
      tags:
        - NATS
      summary: Creates NATS account rule from YAML
      operationId: createNatsAccountRuleYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                natsAccountRule:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
  /nats/account-rules/{ruleName}:
    patch:
      tags:
        - NATS
      summary: Updates NATS account rule
      description: >-
        Returns updated rule immediately and schedules downstream account JWT
        reissue/reconciliation in background.
      operationId: updateNatsAccountRule
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsAccountRulePayload'
      responses:
        '200':
          description: Success
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
    delete:
      tags:
        - NATS
      summary: Deletes NATS account rule
      description: >-
        Rebinds applications using this rule to default rule and schedules
        account JWT reissue/reconciliation in background.
      operationId: deleteNatsAccountRule
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Deleted
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/account-rules/yaml/{ruleName}:
    patch:
      tags:
        - NATS
      summary: Updates NATS account rule from YAML
      description: >-
        Returns updated rule immediately and schedules downstream account JWT
        reissue/reconciliation in background.
      operationId: updateNatsAccountRuleYaml
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                natsAccountRule:
                  type: string
                  format: binary
      responses:
        '200':
          description: Updated
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/user-rules:
    get:
      tags:
        - NATS
      summary: Lists NATS user rules
      operationId: listNatsUserRules
      security:
        - authToken: []
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsUserRuleListResponse'
        '401':
          description: Not Authorized
    post:
      tags:
        - NATS
      summary: Creates NATS user rule
      operationId: createNatsUserRule
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsUserRulePayload'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NatsUserRulePayload'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
  /nats/user-rules/yaml:
    post:
      tags:
        - NATS
      summary: Creates NATS user rule from YAML
      operationId: createNatsUserRuleYaml
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                natsUserRule:
                  type: string
                  format: binary
      responses:
        '201':
          description: Created
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
  /nats/user-rules/{ruleName}:
    patch:
      tags:
        - NATS
      summary: Updates NATS user rule
      description: >-
        Returns updated rule immediately and schedules bound user JWT+creds
        reissue/reconciliation in background.
      operationId: updateNatsUserRule
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NatsUserRulePayload'
      responses:
        '200':
          description: Updated
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
    delete:
      tags:
        - NATS
      summary: Deletes NATS user rule
      description: >-
        Rebinds microservices using this rule to default rule and schedules user
        JWT+creds reissue/reconciliation in background.
      operationId: deleteNatsUserRule
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      responses:
        '204':
          description: Deleted
        '401':
          description: Not Authorized
        '404':
          description: Not Found
  /nats/user-rules/yaml/{ruleName}:
    patch:
      tags:
        - NATS
      summary: Updates NATS user rule from YAML
      description: >-
        Returns updated rule immediately and schedules bound user JWT+creds
        reissue/reconciliation in background.
      operationId: updateNatsUserRuleYaml
      parameters:
        - in: path
          name: ruleName
          required: true
          schema:
            type: string
      security:
        - authToken: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                natsUserRule:
                  type: string
                  format: binary
      responses:
        '200':
          description: Updated
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '404':
          description: Not Found
tags:
  - name: Controller
    description: Manage your controller
  - name: ioFog
    description: Manage your agents
  - name: Application
    description: Manage your applications
  - name: Application Template
    description: Manage your application templates
  - name: Catalog
    description: Manage your catalog
  - name: Registries
    description: Manage your registries
  - name: Microservices
    description: Manage your microservices
  - name: NATS
    description: Manage NATS operator, hub, accounts, users, and rules
  - name: Tunnel
    description: Manage ssh tunnels
  - name: Agent
    description: Used by your agents to communicate with your controller
  - name: WebSocketSessions
    description: >
      Interactive exec and log streaming WebSocket endpoints (MessagePack
      binary).

      Multi-replica HA requires a relay backend per **`nats.enabled`** (AMQP
      when `false`, NATS Core when `true`) - see operations/ws-sessions.md.
  - name: User
    description: Manage your users
  - name: Secrets
    description: Manage your secrets
  - name: Certificates
    description: Manage your certificates
  - name: Services
    description: Manage your services
  - name: VolumeMounts
    description: Manage your volume mounts
  - name: Models
    description: Manage your AI Model Catalogs
  - name: Knowledge
    description: Manage fleet Knowledge artifacts (documents, datasets, and vector indexes)
  - name: RuntimeClasses
    description: Manage your runtime classes
  - name: ConfigMap
    description: Manage your config maps
  - name: Events
    description: Manage audit events
  - name: Roles
    description: Manage RBAC roles
  - name: RoleBindings
    description: Manage RBAC role bindings
  - name: Router
    description: Manage the default router configuration
  - name: NetworkTopology
    description: Read-only router and NATS network topology for visualization
  - name: ServiceAccounts
    description: Manage RBAC service accounts
servers:
  - url: http://localhost:51121/api/v3
components:
  securitySchemes:
    authToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
    fogToken:
      type: http
      scheme: bearer
      description: Edgelet fog provisioning token (agent routes)
  parameters:
    NetworkTopologyLimitParam:
      in: query
      name: limit
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 500
        default: 100
    NetworkTopologyOffsetParam:
      in: query
      name: offset
      required: false
      schema:
        type: integer
        minimum: 0
        default: 0
    NetworkTopologyDeploymentTargetParam:
      in: query
      name: deploymentTarget
      required: false
      schema:
        type: string
        enum:
          - kubernetes
          - remote
          - edgelet
    NetworkTopologySearchParam:
      in: query
      name: search
      required: false
      schema:
        type: string
    NetworkTopologyRouterRoleParam:
      in: query
      name: role
      required: false
      schema:
        type: string
        enum:
          - default
          - edge
          - interior
    NetworkTopologyNatsRoleParam:
      in: query
      name: role
      required: false
      schema:
        type: string
        enum:
          - hub
          - leaf
          - server
  responses:
    AuthRateLimitExceeded:
      description: Too many authentication requests from this IP address
      headers:
        Retry-After:
          description: Seconds until the current rate-limit window resets
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitExceededResponse'
  requestBodies:
    UpdateIOFogNodeRequestBody:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UpdateIOFogNodeRequestBody'
      required: true
    CreateUpdateCatalogItemRequestBody:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CreateUpdateCatalogItemRequestBody'
      description: Microservice Catalog Item Info
      required: true
    ApplicationTemplateCreateRequest:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApplicationTemplateCreateRequest'
      required: true
  schemas:
    WsExecMessageTypes:
      type: object
      description: MessagePack frame types for exec sessions
      properties:
        types:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              value:
                type: integer
              direction:
                type: string
      example:
        types:
          - name: STDIN
            value: 0
            direction: user → agent
          - name: STDOUT
            value: 1
            direction: agent → user
          - name: STDERR
            value: 2
            direction: agent → user
          - name: CONTROL
            value: 3
            direction: both
          - name: CLOSE
            value: 4
            direction: both
          - name: ACTIVATION
            value: 5
            direction: controller → user (session announce); controller → agent (optional
            shell live): null
    WsLogMessageTypes:
      type: object
      description: MessagePack frame types for log sessions (R82)
      example:
        types:
          - name: LOG_LINE
            value: 6
            direction: agent → user
          - name: LOG_START
            value: 7
            direction: both
          - name: LOG_STOP
            value: 8
            direction: agent → user
          - name: LOG_ERROR
            value: 9
            direction: agent → user
    WsCloseCodes:
      type: object
      description: WebSocket close codes used by Controller exec/log sessions
      properties:
        codes:
          type: array
          items:
            type: object
            properties:
              code:
                type: integer
              reason:
                type: string
              when:
                type: string
      example:
        codes:
          - code: 1000
            reason: Normal closure
            when: Session ended cleanly
          - code: 1001
            reason: Server draining
            when: SIGTERM / k8s preStop (R85)
          - code: 1008
            reason: Policy violation
            when: RBAC deny
            exec/log quota (5 per MS): null
            invalid tail params: null
            pending timeout: null
            sessionId mismatch: null
          - code: 1013
            reason: Router unavailable for cross-replica session
            when: AMQP router down (R84)
    EventRecord:
      type: object
      properties:
        id:
          type: integer
        timestamp:
          type: integer
          format: int64
        eventType:
          type: string
        endpointType:
          type: string
        actorId:
          type: string
          nullable: true
        method:
          type: string
          nullable: true
        resourceType:
          type: string
          nullable: true
        resourceId:
          type: string
          nullable: true
        endpointPath:
          type: string
        ipAddress:
          type: string
          nullable: true
        status:
          type: string
        statusCode:
          type: integer
          nullable: true
        statusMessage:
          type: string
          nullable: true
        requestId:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - timestamp
        - eventType
        - endpointType
        - endpointPath
        - status
        - createdAt
        - updatedAt
    EventListResponse:
      type: object
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/EventRecord'
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
      required:
        - events
        - total
        - limit
        - offset
    EventDeleteRequest:
      type: object
      properties:
        days:
          type: integer
          minimum: 0
          maximum: 365
      required:
        - days
    EventDeleteResponse:
      type: object
      properties:
        deletedCount:
          type: integer
        deletedBefore:
          type: string
          format: date-time
          nullable: true
        deletedAt:
          type: string
          format: date-time
        deletedAll:
          type: boolean
      required:
        - deletedCount
        - deletedAt
        - deletedAll
    ApplicationCreateFromTemplateRequest:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        isActivated:
          type: boolean
        template:
          type: object
          properties:
            name:
              type: string
            variables:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                  value:
                    type: string
    ApplicationSpecBody:
      type: object
      properties:
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/NewMicroserviceRequest'
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
    ApplicationCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        description:
          type: string
        isActivated:
          type: boolean
        isSystem:
          type: boolean
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/NewMicroserviceRequest'
          description: >-
            Nested microservice objects use the same schema as POST
            /microservices. The application field on each item is set from the
            parent application name.
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
    ApplicationUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: >-
            Application resource name is immutable; must match path name if
            provided.
        description:
          type: string
        isActivated:
          type: boolean
        isSystem:
          type: boolean
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/NewMicroserviceRequest'
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
    ApplicationPatchRequest:
      type: object
      properties:
        name:
          type: string
          description: >-
            Application resource name is immutable; must match path name if
            provided.
        description:
          type: string
        isActivated:
          type: boolean
        isSystem:
          type: boolean
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
    ApplicationCreateResponse:
      type: object
      properties:
        id:
          type: number
        name:
          type: string
    ApplicationGetResponse:
      type: object
      properties:
        id:
          type: number
        name:
          type: string
        description:
          type: string
        isActivated:
          type: boolean
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceInfoResponse'
    ApplicationListResponse:
      type: object
      properties:
        applications:
          type: array
          items:
            $ref: '#/components/schemas/ApplicationGetResponse'
    ApplicationTemplateCreateRequest:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        variables:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              description:
                type: string
              defaultValue:
                type: string
        application:
          $ref: '#/components/schemas/ApplicationSpecBody'
    ApplicationTemplateCreateResponse:
      type: object
      properties:
        id:
          type: number
        name:
          type: string
    ApplicationTemplatePatchRequest:
      type: object
      properties:
        description:
          type: number
        name:
          type: string
    ApplicationTemplateGetResponse:
      type: object
      properties:
        id:
          type: number
        name:
          type: string
        description:
          type: string
        application:
          $ref: '#/components/schemas/ApplicationSpecBody'
    ApplicationTemplateListResponse:
      type: object
      properties:
        applicationTemplates:
          type: array
          items:
            $ref: '#/components/schemas/ApplicationTemplateGetResponse'
    ServiceStatusResponse:
      type: object
      properties:
        status:
          type: string
          example: online
        timestamp:
          type: number
        uptimeSec:
          type: number
        versions:
          type: object
          properties:
            controller:
              type: string
            ecnViewer:
              type: string
    ServiceReadinessFailureResponse:
      allOf:
        - $ref: '#/components/schemas/ServiceStatusResponse'
        - type: object
          required:
            - error
            - code
            - message
            - retryable
          properties:
            error:
              type: string
              example: ServiceUnavailable
            code:
              type: string
              example: CONTROLLER_NOT_READY
            message:
              type: string
            retryable:
              type: boolean
              example: true
    ArchitecturesResponse:
      type: object
      properties:
        architectures:
          type: array
          items:
            $ref: '#/components/schemas/Architecture'
    Architecture:
      type: object
      properties:
        id:
          type: number
        name:
          type: string
        image:
          type: string
        description:
          type: string
    IOFogNodesListFilters:
      type: array
      items:
        type: object
        properties:
          key:
            type: string
          value:
            type: string
          condition:
            type: string
    IOFogNodesListResponse:
      type: object
      properties:
        fogs:
          type: array
          items:
            $ref: '#/components/schemas/IOFogNodeInfoResponse'
    IOFogNodeInfoResponse:
      type: object
      properties:
        lastActive:
          type: number
        daemonOperatingDuration:
          type: number
        daemonLastStart:
          type: number
        repositoryCount:
          type: number
        systemTime:
          type: number
        lastStatusTime:
          type: number
          description: >-
            Controller receipt time in milliseconds of the last successful agent
            status PUT. Not the agent's clock.
        lastCommandTime:
          type: number
        logFileCount:
          type: number
        uuid:
          type: string
        name:
          type: string
        location:
          type: string
        gpsMode:
          type: string
        latitude:
          type: number
        longitude:
          type: number
        description:
          type: string
        daemonStatus:
          type: string
        memoryUsage:
          type: number
        diskUsage:
          type: number
          description: Edgelet data-directory usage in GiB, not host filesystem total.
        cpuUsage:
          type: number
        memoryViolation:
          type: boolean
        diskViolation:
          type: boolean
        cpuViolation:
          type: boolean
        systemAvailableDisk:
          type: integer
          description: Free space on the agent diskDirectory filesystem in bytes.
        systemAvailableMemory:
          type: integer
          description: Host RAM available in bytes.
        systemTotalCpu:
          type: number
          description: Host CPU busy percentage 0–100, not logical core count.
        systemCpus:
          type: integer
          description: Host logical CPU count.
        systemTotalMemory:
          type: integer
          description: Host RAM capacity in bytes.
        systemTotalDisk:
          type: integer
          description: diskDirectory filesystem size in bytes.
        systemOs:
          type: string
          description: Host OS family (linux, darwin, windows, …).
        systemOsVersion:
          type: string
          description: Human-oriented distro or release; empty string when unknown.
        systemKernelVersion:
          type: string
          description: Linux kernel release; empty string on non-Linux.
        catalogItemStatus:
          type: string
        repositoryStatus:
          type: string
        ipAddress:
          type: string
        ipAddressExternal:
          type: string
        networkInterface:
          type: string
        containerEngineUrl:
          type: string
        containerEngine:
          type: string
          enum:
            - edgelet
            - docker
            - podman
        deploymentType:
          type: string
        diskLimit:
          type: number
        diskDirectory:
          type: string
        memoryLimit:
          type: number
        cpuLimit:
          type: number
          minimum: 5
          maximum: 400
        logLimit:
          type: number
        logDirectory:
          type: string
        version:
          type: string
        isReadyToUpgrade:
          type: boolean
        isReadyToRollback:
          type: boolean
        statusFrequency:
          type: number
        changeFrequency:
          type: number
        tunnel:
          type: string
        watchdogEnabled:
          type: boolean
        pruningFrequency:
          type: number
        availableDiskThreshold:
          type: number
        logLevel:
          type: string
        isSystem:
          type: boolean
        routerId:
          type: number
        createAt:
          type: number
        updatedAt:
          type: number
        archId:
          type: number
        arch:
          $ref: '#/components/schemas/Architecture'
        availableRuntimes:
          type: array
          items:
            type: string
        routerMode:
          type: string
          enum:
            - none
            - edge
            - interior
        messagingPort:
          type: number
        upstreamRouters:
          type: array
          items:
            type: string
        natsMode:
          type: string
          enum:
            - none
            - leaf
            - server
        natsServerPort:
          type: number
        natsLeafPort:
          type: number
        natsClusterPort:
          type: number
        natsMqttPort:
          type: number
        natsHttpPort:
          type: number
        jsStorageSize:
          type: string
          description: JetStream max file store (e.g. 10g). Units m, mb, g, gb, t, tb.
        jsMemoryStoreSize:
          type: string
          description: JetStream max memory store (e.g. 1g). Units m, mb, g, gb, t, tb.
        upstreamNatsServers:
          type: array
          items:
            type: string
        runtimeClasses:
          type: string
          description: >-
            JSON string of applied RuntimeClasses (array of { name, handler,
            source }). Empty array when none.
        availableCdiDevices:
          type: string
          description: JSON string of unique sorted fully-qualified CDI names.
        modelStatus:
          type: string
          description: >-
            JSON string of local and managed model status items. Parse for
            display. Managed rows include uuid; local rows omit uuid.
        activeModels:
          type: integer
          description: Count of managed fleet models only.
        modelLastUpdate:
          type: integer
          description: Unix milliseconds; 0 when the managed list is empty.
        knowledgeStatus:
          type: string
          description: >-
            JSON string of local and managed Knowledge status items. Parse for
            display. Managed rows include uuid; local rows omit uuid and set
            source to local. source is local or managed. activeKnowledge is the
            managed count, not the length of this array.
        activeKnowledge:
          type: integer
          description: >-
            Count of managed fleet Knowledge only, not the knowledgeStatus row
            count.
        knowledgeLastUpdate:
          type: integer
          description: Unix milliseconds; 0 when the managed list is empty.
        platformStatus:
          description: Present on GET single fog only; omitted on list responses
          allOf:
            - $ref: '#/components/schemas/PlatformStatus'
    PlatformStatus:
      type: object
      properties:
        phase:
          type: string
          enum:
            - Pending
            - Progressing
            - Ready
            - Failed
            - Deleting
        generation:
          type: integer
          description: Desired spec generation from FogPlatformSpecs
        observedGeneration:
          type: integer
          description: Generation last reconciled successfully
        lastError:
          type: string
          nullable: true
        lastTransitionAt:
          type: string
          format: date-time
        conditions:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              status:
                type: string
              reason:
                type: string
              message:
                type: string
    UpdateIOFogNodeRequestBody:
      type: object
      properties:
        name:
          type: string
        location:
          type: string
        latitude:
          type: number
        longitude:
          type: number
        description:
          type: string
        containerEngineUrl:
          type: string
          default: unix:///run/edgelet/contaienrd.sock
        containerEngine:
          type: string
          enum:
            - edgelet
            - docker
            - podman
          default: docker
        deploymentType:
          type: string
          default: native
        diskLimit:
          type: number
          default: 50
        diskDirectory:
          type: string
          default: /var/lib/edgelet/
        memoryLimit:
          type: number
          default: 4096
          format: MB
        cpuLimit:
          type: number
          default: 80
          minimum: 5
          maximum: 400
          format: percent
        logLimit:
          type: number
          default: 10
          format: GB
        logDirectory:
          type: string
          default: /var/log/iofog
        logFileCount:
          type: number
          default: 10
        statusFrequency:
          type: number
          default: 10
          format: seconds
        changeFrequency:
          type: number
          default: 20
          format: seconds
        watchdogEnabled:
          type: boolean
          default: true
        archId:
          type: number
          minimum: 0
          maximum: 4
        pruningFrequency:
          type: number
        availableDiskThreshold:
          type: number
        logLevel:
          type: string
          default: info
        isSystem:
          type: boolean
        routerMode:
          type: string
          default: edge
          enum:
            - none
            - edge
            - interior
        messagingPort:
          type: number
        interRouterPort:
          type: number
        edgeRouterPort:
          type: number
        natsMode:
          type: string
          enum:
            - none
            - leaf
            - server
        natsServerPort:
          type: number
        natsLeafPort:
          type: number
        natsClusterPort:
          type: number
        natsMqttPort:
          type: number
        natsHttpPort:
          type: number
        jsStorageSize:
          type: string
          description: JetStream max file store (e.g. 10g). Units m, mb, g, gb, t, tb.
        jsMemoryStoreSize:
          type: string
          description: JetStream max memory store (e.g. 1g). Units m, mb, g, gb, t, tb.
        upstreamNatsServers:
          type: array
          items:
            type: string
        host:
          type: string
        tags:
          type: array
          items:
            type: string
        upstreamRouters:
          type: array
          items:
            type: string
        networkRouter:
          type: string
    NewIOFogNodeResponse:
      type: object
      properties:
        id:
          type: string
    IOFogUuidResponse:
      type: object
      properties:
        uuid:
          type: string
          description: ioFog node id
    ProvisioningKeyResponse:
      type: object
      properties:
        key:
          type: string
        expirationTime:
          type: number
        caCert:
          type: string
          description: >-
            Base64-encoded PEM of the controller CA for Edgelet trust store;
            empty when a public CA is used
    AgentProvisioningRequest:
      type: object
      required:
        - type
        - key
      properties:
        type:
          type: number
          minimum: 0
          maximum: 4
          description: |
            Architecture code
             * '0': auto
             * '1': amd64
             * '2': arm64
             * '3': riscv64
             * '4': arm
        engine:
          type: string
          enum:
            - edgelet
            - docker
            - podman
          description: Container engine selected at provision time
        key:
          type: string
          description: provisioning key
    AgentProvisioningResponse:
      type: object
      properties:
        id:
          type: string
          description: ioFog Node Id
        token:
          type: string
          description: Agent token
    AgentDeprovisioningRequest:
      type: object
      properties:
        microserviceUuids:
          type: array
          items:
            type: string
    IOFogNodeConfigChanges:
      type: object
      properties:
        config:
          type: boolean
        version:
          type: boolean
        reboot:
          type: boolean
        deleteNode:
          type: boolean
        microserviceList:
          type: boolean
        microserviceConfig:
          type: boolean
        registries:
          type: boolean
        tunnel:
          type: boolean
        prune:
          type: boolean
        routerChanged:
          type: boolean
        volumeMounts:
          type: boolean
        execSessions:
          type: boolean
        microserviceLogs:
          type: boolean
        fogLogs:
          type: boolean
        models:
          type: boolean
        runtimeClasses:
          type: boolean
        microserviceModels:
          type: boolean
          description: >-
            Catalog-only refresh; agent uses GET microservices (no dedicated
            GET).
        knowledge:
          type: boolean
          description: Replace managed Knowledge from GET /agent/knowledge.
        microserviceKnowledge:
          type: boolean
          description: >-
            Catalog-only refresh; agent uses GET microservices (no dedicated
            GET).
    IOFogNodeConfig:
      type: object
      properties:
        networkInterface:
          type: string
        containerEngineUrl:
          type: string
        containerEngine:
          type: string
          enum:
            - edgelet
            - docker
            - podman
        deploymentType:
          type: string
        diskLimit:
          type: number
        diskDirectory:
          type: string
        memoryLimit:
          type: number
        cpuLimit:
          type: number
          minimum: 5
          maximum: 400
        logLimit:
          type: number
        logDirectory:
          type: string
        logFileCount:
          type: number
        statusFrequency:
          type: number
        changeFrequency:
          type: number
        watchdogEnabled:
          type: boolean
        latitude:
          type: number
        longitude:
          type: number
        logLevel:
          type: string
        availableDiskThreshold:
          type: number
        pruningFrequency:
          type: number
        routerHost:
          type: string
        routerPort:
          type: number
    IOFogNodeConfigRequest:
      type: object
      properties:
        networkInterface:
          type: string
        containerEngineUrl:
          type: string
        containerEngine:
          type: string
          enum:
            - edgelet
            - docker
            - podman
        deploymentType:
          type: string
        diskLimit:
          type: number
        diskDirectory:
          type: string
        memoryLimit:
          type: number
        cpuLimit:
          type: number
          minimum: 5
          maximum: 400
        logLimit:
          type: number
        logDirectory:
          type: string
        logFileCount:
          type: number
        statusFrequency:
          type: number
        changeFrequency:
          type: number
        watchdogEnabled:
          type: boolean
        latitude:
          type: number
        longitude:
          type: number
        gpsMode:
          type: string
        logLevel:
          type: string
        availableDiskThreshold:
          type: number
        pruningFrequency:
          type: number
    IOFogNodeGpsRequest:
      type: object
      properties:
        latitude:
          type: number
        longitude:
          type: number
    AgentStatus:
      type: object
      properties:
        daemonStatus:
          type: string
        warningMessage:
          type: string
        daemonOperatingDuration:
          type: number
        daemonLastStart:
          type: number
        memoryUsage:
          type: number
        diskUsage:
          type: number
          description: Edgelet data-directory usage in GiB, not host filesystem total.
        cpuUsage:
          type: number
        memoryViolation:
          type: boolean
        diskViolation:
          type: boolean
        cpuViolation:
          type: boolean
        systemAvailableDisk:
          type: integer
          description: Free space on the agent diskDirectory filesystem in bytes.
        systemAvailableMemory:
          type: integer
          description: Host RAM available in bytes.
        systemTotalCpu:
          type: number
          description: Host CPU busy percentage 0–100, not logical core count.
        systemCpus:
          type: integer
          description: Host logical CPU count.
        systemTotalMemory:
          type: integer
          description: Host RAM capacity in bytes.
        systemTotalDisk:
          type: integer
          description: diskDirectory filesystem size in bytes.
        systemOs:
          type: string
          description: Host OS family (linux, darwin, windows, …).
        systemOsVersion:
          type: string
          description: Human-oriented distro or release; empty string when unknown.
        systemKernelVersion:
          type: string
          description: Linux kernel release; empty string on non-Linux.
        securityStatus:
          type: string
        securityViolationInfo:
          type: string
        microserviceStatus:
          type: string
          description: >-
            JSON array of per-microservice observed status objects. Items may
            include additive lastError, lastErrorAt, and restartCount. Unknown
            keys must not fail this PUT.
        repositoryCount:
          type: number
        repositoryStatus:
          type: string
        systemTime:
          type: number
        lastStatusTime:
          type: number
          description: >-
            Agent-supplied timestamp in milliseconds. Controller liveness uses
            the PUT receipt time instead of this value.
        ipAddress:
          type: string
        ipAddressExternal:
          type: string
        lastCommandTime:
          type: number
        availableRuntimes:
          type: array
          items:
            type: string
        runtimeAgentPhase:
          type: string
        controlPlaneQuiesced:
          type: boolean
        tunnelStatus:
          type: string
        version:
          type: string
        isReadyToUpgrade:
          type: boolean
        isReadyToRollback:
          type: boolean
        activeVolumeMounts:
          type: number
        volumeMountLastUpdate:
          type: number
        gpsStatus:
          type: string
        runtimeClasses:
          type: array
          description: Applied RuntimeClasses only, sorted by name. Docker/podman send [].
          items:
            type: object
            properties:
              name:
                type: string
              handler:
                type: string
              source:
                type: string
                enum:
                  - local
                  - managed
        availableCdiDevices:
          type: array
          items:
            type: string
          description: Unique sorted fully-qualified CDI names (nvidia.com/gpu=0).
        modelStatus:
          type: string
          description: JSON string of local and managed model status items.
        activeModels:
          type: integer
          description: Count of managed fleet models only.
        modelLastUpdate:
          type: integer
          description: Unix milliseconds; 0 when the managed list is empty.
        knowledgeStatus:
          type: string
          description: >-
            JSON string of local and managed Knowledge status items. Managed
            rows include uuid; local rows omit uuid. source is local or managed.
        activeKnowledge:
          type: integer
          description: >-
            Count of managed fleet Knowledge only, not the knowledgeStatus row
            count.
        knowledgeLastUpdate:
          type: integer
          description: Unix milliseconds; 0 when the managed list is empty.
    IOFogNodeTunnelConfigResponse:
      type: object
      properties:
        username:
          type: string
        password:
          type: string
        host:
          type: string
        remotePort:
          type: number
        localPort:
          type: number
        rsaKey:
          type: string
        closed:
          type: boolean
    AgentMicroservicesListResponse:
      type: object
      properties:
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/AgentMicroservicesInfoResponse'
    AgentMicroservicesInfoResponse:
      type: object
      properties:
        uuid:
          type: string
        imageId:
          type: string
        config:
          type: string
        annotations:
          type: string
        rebuild:
          type: boolean
        hostNetworkMode:
          type: boolean
        isPrivileged:
          type: boolean
        logSize:
          type: number
        registryId:
          type: number
        portMappings:
          type: array
          items:
            $ref: '#/components/schemas/PortMappingAgentRequest'
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMapping'
        delete:
          type: boolean
        deleteWithCleanUp:
          type: boolean
        env:
          type: array
          items:
            $ref: '#/components/schemas/AgentEnvRequest'
        runAsUser:
          type: string
        platform:
          type: string
        runtime:
          type: string
        cdiDevices:
          type: array
          items:
            type: string
        capAdd:
          type: array
          items:
            type: string
        capDrop:
          type: array
          items:
            type: string
        cmd:
          type: array
          items:
            type: string
          description: Alias of commands. commands wins when both are present.
        commands:
          type: array
          items:
            type: string
        entrypoint:
          type: array
          items:
            type: string
        runAsGroup:
          type: string
        readOnlyRootFilesystem:
          type: boolean
        workingDir:
          type: string
        cpus:
          type: number
        memoryReservation:
          type: integer
        memorySwap:
          type: integer
        shmSize:
          type: integer
        sysctls:
          type: object
        ulimits:
          type: object
        devices:
          type: array
          items:
            $ref: '#/components/schemas/ContainerDevice'
        tmpfs:
          type: array
          items:
            $ref: '#/components/schemas/ContainerTmpfs'
        models:
          $ref: '#/components/schemas/MicroserviceCatalog'
        knowledge:
          $ref: '#/components/schemas/KnowledgeCatalog'
          description: >-
            Fleet Knowledge bound at {bindPath}/{name}/. Items are Knowledge
            names only.
        idConsumer:
          type: boolean
        isRouter:
          type: boolean
          description: True when microservice is the system router
        isNats:
          type: boolean
          description: True when microservice is the system NATS broker
        isController:
          type: boolean
          description: >-
            True when microservice is the ControlPlane controller workload (DB
            column)
    ControllerRegisterRequest:
      type: object
      description: >-
        Edgelet ControlPlane controller workload register body. Accepts the same
        container/workload fields as user microservice deploy (excluding
        application, serviceAccount, and natsConfig). Ownership fields
        (iofogUuid, application) are derived from the authenticated system fog.
      required:
        - uuid
        - images
        - registryId
      properties:
        uuid:
          type: string
          description: Edgelet-generated stable uuid for the controller microservice
        name:
          type: string
          enum:
            - controller
          description: Must be controller (default controller if omitted)
        images:
          type: array
          minItems: 1
          maxItems: 4
          items:
            $ref: '#/components/schemas/MicroserviceContainerImage'
        registryId:
          type: integer
        config:
          type: string
        annotations:
          type: string
        hostNetworkMode:
          type: boolean
        isPrivileged:
          type: boolean
        logSize:
          type: integer
          minimum: 0
        runtime:
          type: string
        pidMode:
          type: string
        ipcMode:
          type: string
        runAsUser:
          type: string
        platform:
          type: string
        cpuSetCpus:
          type: string
        memoryLimit:
          type: integer
        ports:
          type: array
          items:
            $ref: '#/components/schemas/PortMappingsResponse'
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMappingRequest'
        extraHosts:
          type: array
          items:
            type: object
            required:
              - name
              - address
            properties:
              name:
                type: string
              address:
                type: string
        env:
          type: array
          items:
            $ref: '#/components/schemas/AgentEnvRequest'
        cmd:
          type: array
          items:
            type: string
        cdiDevices:
          type: array
          items:
            type: string
        capAdd:
          type: array
          items:
            type: string
        capDrop:
          type: array
          items:
            type: string
        healthCheck:
          type: object
          required:
            - test
          properties:
            test:
              type: array
              items:
                type: string
            interval:
              type: integer
            timeout:
              type: integer
            startPeriod:
              type: integer
            startInterval:
              type: integer
            retries:
              type: integer
        schedule:
          type: integer
          enum:
            - 0
          description: Optional; controller workload schedule is always 0 (server-enforced)
    ControllerRegisterResponse:
      type: object
      properties:
        uuid:
          type: string
          description: Same uuid as the register request
    AgentEnvRequest:
      type: object
      properties:
        key:
          type: string
        value:
          type: string
    ReceiverMicroservices:
      type: array
      items:
        type: string
    VolumeMapping:
      type: object
      properties:
        hostDestination:
          type: string
          example: /var/dest
        containerDestination:
          type: string
          example: /var/dest
        accessMode:
          type: string
          example: rw
        scope:
          type: string
          enum:
            - private
            - shared
          default: private
          description: >-
            Meaningful only when type is volume. Omit, null, or empty stores
            private. Unknown values on type volume return 400. Other mapping
            types always store private. Runtime accepts any case and stores
            lowercase.
          example: private
    VolumeMappingResponse:
      type: object
      properties:
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMappingRequest'
    VolumeMappingRequest:
      type: object
      properties:
        id:
          type: number
        hostDestination:
          type: string
          description: >-
            When type is volume, a managed volume name
            ([a-zA-Z0-9][a-zA-Z0-9_.-]*). When type is bind (default), an
            absolute host path (Unix or Windows drive path).
          example: /var/dest
        containerDestination:
          type: string
          example: /var/dest
        accessMode:
          type: string
          example: rw
        type:
          type: string
          example: bind
        scope:
          type: string
          enum:
            - private
            - shared
          default: private
          description: >-
            Meaningful only when type is volume. Omit, null, or empty stores
            private. Unknown values on type volume return 400. Other mapping
            types always store private. Runtime accepts any case and stores
            lowercase. GET always returns private or shared in lowercase.
          example: private
    PortMappingsResponse:
      type: object
      properties:
        internal:
          type: number
        external:
          type: number
        protocol:
          type: string
          enum:
            - tcp
            - udp
      required:
        - internal
        - external
        - protocol
    PortMappingsRequest:
      type: object
      properties:
        internal:
          type: number
        external:
          type: number
        protocol:
          type: string
          enum:
            - tcp
            - udp
      required:
        - internal
        - external
    PortMappingsPublicResponse:
      type: object
      properties:
        internal:
          type: number
        external:
          type: number
        protocol:
          type: string
          enum:
            - tcp
            - udp
      required:
        - internal
        - external
        - protocol
    PortMappingsListResponse:
      type: object
      properties:
        ports:
          type: array
          items:
            $ref: '#/components/schemas/PortMappingsItemResponse'
    PortMappingsItemResponse:
      type: object
      properties:
        internal:
          type: number
        external:
          type: number
        protocol:
          type: string
          enum:
            - tcp
            - udp
      required:
        - internal
        - external
        - protocol
    PortMappingAgentRequest:
      type: object
      properties:
        portInternal:
          type: string
          example: 80
        portExternal:
          type: string
          example: 80
    microservicesConfig:
      type: string
    RegistriesListResponse:
      type: object
      properties:
        registries:
          type: array
          items:
            $ref: '#/components/schemas/RegistryResponse'
    RegistryResponse:
      type: object
      properties:
        id:
          type: number
        url:
          type: string
        isPublic:
          type: boolean
        username:
          type: string
        password:
          type: string
        userEmail:
          type: string
        type:
          type: string
          enum:
            - oci
            - hf
          default: oci
        ca:
          type: string
          description: Optional base64-encoded PEM CA bundle
        insecure:
          type: boolean
          default: false
    RegistryBody:
      type: object
      description: >-
        type defaults to oci. Microservice and catalog-item registryId must be
        type oci. Hugging Face registries are for fleet models. ca is additional
        trust and does not replace system CAs. insecure true allows http and
        skips TLS verify. Image-pull ca/insecure apply on edgelet only.
      properties:
        url:
          type: string
        isPublic:
          type: boolean
        username:
          type: string
        password:
          type: string
        email:
          type: string
        type:
          type: string
          enum:
            - oci
            - hf
          default: oci
        ca:
          type: string
          description: Optional base64-encoded PEM CA bundle
        insecure:
          type: boolean
          default: false
    ActionBody:
      type: object
      properties:
        action:
          type: string
          enum:
            - open
            - close
    MicroservicesCatalogResponse:
      type: object
      properties:
        catalogItems:
          type: array
          items:
            $ref: '#/components/schemas/CatalogItemInfoResponse'
    CatalogItemInfoResponse:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
        category:
          type: string
        publisher:
          type: string
        diskRequired:
          type: number
        ramRequired:
          type: number
        picture:
          type: string
        isPublic:
          type: boolean
        registryId:
          type: number
        inputType:
          $ref: '#/components/schemas/InfoTypeResponse'
        outputType:
          $ref: '#/components/schemas/InfoTypeResponse'
        configExample:
          type: string
        images:
          $ref: '#/components/schemas/MicroserviceContainerImages'
    InfoTypeResponse:
      type: object
      properties:
        infoType:
          type: string
        infoFormat:
          type: string
    MicroserviceContainerImages:
      type: array
      items:
        $ref: '#/components/schemas/MicroserviceContainerImage'
    MicroserviceContainerImage:
      type: object
      properties:
        containerImage:
          type: string
        archId:
          type: number
          enum:
            - 1
            - 2
            - 3
            - 4
    CreateUpdateCatalogItemRequestBody:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        category:
          type: string
        images:
          $ref: '#/components/schemas/MicroserviceContainerImages'
        publisher:
          type: string
        diskRequired:
          type: number
        ramRequired:
          type: number
        picture:
          type: string
        isPublic:
          type: boolean
        registryId:
          type: number
        inputType:
          $ref: '#/components/schemas/InfoTypeResponse'
        outputType:
          $ref: '#/components/schemas/InfoTypeResponse'
        configExample:
          type: string
    GetMicroservicesResponse:
      type: object
      properties:
        microservices:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceInfoResponse'
    MicroserviceInfoResponse:
      type: object
      properties:
        uuid:
          type: string
        name:
          type: string
        application:
          type: string
        flowId:
          type: integer
          description: Deprecated alias of applicationId for API retrocompatibility.
        config:
          type: string
        annotations:
          type: string
        catalogItemId:
          type: integer
        registryId:
          type: integer
        hostNetworkMode:
          type: boolean
        isPrivileged:
          type: boolean
        logSize:
          type: number
        rebuild:
          type: boolean
        isActivated:
          type: boolean
        schedule:
          type: integer
          minimum: 0
          maximum: 100
        images:
          type: array
          items:
            properties:
              containerImage:
                type: string
              archId:
                type: integer
        iofogUuid:
          type: string
        env:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceEnvVar'
        extraHosts:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceExtraHost'
        runAsUser:
          type: string
        runAsGroup:
          type: string
        readOnlyRootFilesystem:
          type: boolean
        platform:
          type: string
        runtime:
          type: string
        pidMode:
          type: string
        ipcMode:
          type: string
        cpuSetCpus:
          type: string
        memoryLimit:
          type: integer
        cpus:
          type: number
        memoryReservation:
          type: integer
        memorySwap:
          type: integer
        shmSize:
          type: integer
        cdiDevices:
          type: array
          items:
            type: string
        capAdd:
          type: array
          items:
            type: string
        capDrop:
          type: array
          items:
            type: string
        cmd:
          type: array
          items:
            type: string
        commands:
          type: array
          items:
            type: string
        entrypoint:
          type: array
          items:
            type: string
        workingDir:
          type: string
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMappingRequest'
        ports:
          type: array
          items:
            $ref: '#/components/schemas/PortMappingsResponse'
        healthCheck:
          $ref: '#/components/schemas/MicroserviceHealthCheck'
        natsAccess:
          type: boolean
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
        status:
          type: object
          properties:
            status:
              type: string
              description: >-
                Observed runtime state such as RUNNING, STOPPING, STOPPED,
                UNKNOWN, or FAILED. Operator stop or application deactivate sets
                STOPPING immediately, before the agent confirms STOPPED.
            operatingDuration:
              type: number
              description: Live while status is RUNNING; otherwise 0.
            startTime:
              type: number
              description: Live while status is RUNNING; otherwise 0.
            cpuUsage:
              type: number
              description: >-
                CPU sample for this microservice. Live only when status is
                RUNNING (0 is valid while running). Otherwise 0.
            memoryUsage:
              type: number
              description: >-
                Memory sample for this microservice. Live only when status is
                RUNNING (0 is valid while running). Otherwise 0.
            containerId:
              type: string
            podId:
              type: string
              description: >-
                Pause/sandbox id on edgelet. Same as containerId on
                docker/podman when set. Omitted when unknown.
            errorMessage:
              type: string
              description: >-
                Current failure text. Agent keeps this populated while the
                workload is failing, restarting, or has been RUNNING for less
                than 30 seconds after a crash. After 30 seconds of continuous
                RUNNING the agent sends an empty string so this field clears.
            lastError:
              type: string
              description: >-
                Last crash text. Not cleared on recovery. Empty string when
                Controller has never stored a crash for this microservice.
            lastErrorAt:
              type: integer
              description: Unix milliseconds for lastError. 0 when lastError is empty.
            restartCount:
              type: integer
              description: >-
                Restart events since the last operator rebuild. 0 after rebuild
                leftover history or when never restarted. May drop to 1 after an
                agent process restart if the container is still crashed (new
                episode).
        execStatus:
          type: object
        models:
          $ref: '#/components/schemas/MicroserviceCatalog'
        knowledge:
          $ref: '#/components/schemas/KnowledgeCatalog'
          description: >-
            Fleet Knowledge bound at {bindPath}/{name}/. Items are Knowledge
            names only. User microservices only.
        sysctls:
          type: object
        ulimits:
          type: object
        devices:
          type: array
          items:
            $ref: '#/components/schemas/ContainerDevice'
        tmpfs:
          type: array
          items:
            $ref: '#/components/schemas/ContainerTmpfs'
        serviceAccount:
          type: object
          nullable: true
          properties:
            roleRef:
              $ref: '#/components/schemas/RoleRef'
          additionalProperties: false
    MicroserviceEnvVar:
      type: object
      required:
        - key
      properties:
        key:
          type: string
        value:
          type: string
        valueFromSecret:
          type: string
          description: Format secret-name/key
        valueFromConfigMap:
          type: string
          description: Format configmap-name/key
    MicroserviceExtraHost:
      type: object
      required:
        - name
        - address
      properties:
        name:
          type: string
        address:
          type: string
        value:
          type: string
          description: Present on GET responses when address is a template expression.
    MicroserviceHealthCheck:
      type: object
      required:
        - test
      properties:
        test:
          type: array
          items:
            type: string
        interval:
          type: integer
        timeout:
          type: integer
        startPeriod:
          type: integer
        startInterval:
          type: integer
        retries:
          type: integer
    NewMicroserviceRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        config:
          type: string
        annotations:
          type: string
        catalogItemId:
          type: integer
        registryId:
          type: integer
        images:
          type: array
          maxItems: 4
          minItems: 1
          items:
            properties:
              containerImage:
                type: string
              archId:
                type: integer
        application:
          type: string
        iofogUuid:
          type: string
        agentName:
          type: string
        hostNetworkMode:
          type: boolean
        isPrivileged:
          type: boolean
        logSize:
          type: integer
          minimum: 0
        rebuild:
          type: boolean
        schedule:
          type: integer
          minimum: 0
          maximum: 100
        pidMode:
          type: string
        ipcMode:
          type: string
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMapping'
        ports:
          type: array
          items:
            $ref: '#/components/schemas/PortMappingsRequest'
        env:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceEnvVar'
        extraHosts:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceExtraHost'
        runAsUser:
          type: string
        runAsGroup:
          type: string
        readOnlyRootFilesystem:
          type: boolean
        platform:
          type: string
        runtime:
          type: string
        cpuSetCpus:
          type: string
        memoryLimit:
          type: integer
        cpus:
          type: number
        memoryReservation:
          type: integer
          minimum: 1
        memorySwap:
          type: integer
        shmSize:
          type: integer
          minimum: 1
        cdiDevices:
          type: array
          items:
            type: string
        capAdd:
          type: array
          items:
            type: string
        capDrop:
          type: array
          items:
            type: string
        cmd:
          type: array
          items:
            type: string
          description: Alias of commands. commands wins when both are present.
        commands:
          type: array
          items:
            type: string
        entrypoint:
          type: array
          items:
            type: string
        workingDir:
          type: string
        sysctls:
          type: object
        ulimits:
          type: object
        devices:
          type: array
          items:
            $ref: '#/components/schemas/ContainerDevice'
        tmpfs:
          type: array
          items:
            $ref: '#/components/schemas/ContainerTmpfs'
        healthCheck:
          $ref: '#/components/schemas/MicroserviceHealthCheck'
        models:
          $ref: '#/components/schemas/MicroserviceCatalog'
        knowledge:
          $ref: '#/components/schemas/KnowledgeCatalog'
          description: >-
            Fleet Knowledge bound at {bindPath}/{name}/. Items are Knowledge
            names only. User microservices only.
        template:
          $ref: '#/components/schemas/MicroserviceTemplateRef'
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
        natsEnabled:
          type: boolean
          description: YAML alias for natsConfig.natsAccess
        serviceAccount:
          type: object
          properties:
            roleRef:
              $ref: '#/components/schemas/RoleRef'
          additionalProperties: false
    UpdateMicroserviceRequest:
      type: object
      properties:
        name:
          type: string
        config:
          type: string
        annotations:
          type: string
        rebuild:
          type: boolean
        iofogUuid:
          type: string
        agentName:
          type: string
        hostNetworkMode:
          type: boolean
        isPrivileged:
          type: boolean
        logSize:
          type: integer
          minimum: 0
        schedule:
          type: integer
          minimum: 0
          maximum: 100
        pidMode:
          type: string
        ipcMode:
          type: string
        volumeMappings:
          type: array
          items:
            $ref: '#/components/schemas/VolumeMapping'
        images:
          type: array
          maxItems: 4
          items:
            properties:
              containerImage:
                type: string
              archId:
                type: integer
        env:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceEnvVar'
        extraHosts:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceExtraHost'
        runAsUser:
          type: string
        runAsGroup:
          type: string
        readOnlyRootFilesystem:
          type: boolean
        platform:
          type: string
        runtime:
          type: string
        cpuSetCpus:
          type: string
        memoryLimit:
          type: integer
        cpus:
          type: number
        memoryReservation:
          type: integer
          minimum: 1
        memorySwap:
          type: integer
        shmSize:
          type: integer
          minimum: 1
        cdiDevices:
          type: array
          items:
            type: string
        capAdd:
          type: array
          items:
            type: string
        capDrop:
          type: array
          items:
            type: string
        cmd:
          type: array
          items:
            type: string
          description: Alias of commands. commands wins when both are present.
        commands:
          type: array
          items:
            type: string
        entrypoint:
          type: array
          items:
            type: string
        workingDir:
          type: string
        sysctls:
          type: object
        ulimits:
          type: object
        devices:
          type: array
          items:
            $ref: '#/components/schemas/ContainerDevice'
        tmpfs:
          type: array
          items:
            $ref: '#/components/schemas/ContainerTmpfs'
        healthCheck:
          $ref: '#/components/schemas/MicroserviceHealthCheck'
        models:
          $ref: '#/components/schemas/MicroserviceCatalog'
        knowledge:
          $ref: '#/components/schemas/KnowledgeCatalog'
          description: >-
            Fleet Knowledge bound at {bindPath}/{name}/. Items are Knowledge
            names only. User microservices only.
        template:
          $ref: '#/components/schemas/MicroserviceTemplateRef'
        natsConfig:
          $ref: '#/components/schemas/NatsConfigObject'
        natsEnabled:
          type: boolean
          description: YAML alias for natsConfig.natsAccess
        serviceAccount:
          type: object
          properties:
            roleRef:
              $ref: '#/components/schemas/RoleRef'
          additionalProperties: false
    NatsConfigObject:
      type: object
      properties:
        natsAccess:
          type: boolean
        natsRule:
          type: string
      additionalProperties: false
    NatsHubRequest:
      type: object
      required:
        - host
      properties:
        host:
          type: string
        serverPort:
          type: integer
        clusterPort:
          type: integer
        leafPort:
          type: integer
        mqttPort:
          type: integer
        httpPort:
          type: integer
        jsStorageSize:
          type: string
          description: JetStream max file store (e.g. 10g, 1t). Units m, mb, g, gb, t, tb.
        jsMemoryStoreSize:
          type: string
          description: JetStream max memory store (e.g. 1g). Units m, mb, g, gb, t, tb.
    NatsHubResponse:
      $ref: '#/components/schemas/NatsHubRequest'
    NatsOperatorResponse:
      type: object
      properties:
        name:
          type: string
        publicKey:
          type: string
        jwt:
          type: string
    NatsBootstrapResponse:
      type: object
      properties:
        operatorJwt:
          type: string
        operatorPublicKey:
          type: string
        operatorSeed:
          type: string
        systemAccountJwt:
          type: string
        systemAccountPublicKey:
          type: string
        sysUserCredsBase64:
          type: string
    NatsAccountResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        publicKey:
          type: string
        jwt:
          type: string
        isSystem:
          type: boolean
        applicationId:
          type: integer
    NatsAccountsListResponse:
      type: object
      properties:
        accounts:
          type: array
          items:
            $ref: '#/components/schemas/NatsAccountResponse'
    NatsUserCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        expiresIn:
          type: string
          pattern: ^[0-9]+[hdm]$
          example: 7d
        natsRule:
          type: string
    NatsUserResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        publicKey:
          type: string
        jwt:
          type: string
        isBearer:
          type: boolean
    NatsUserWithContextResponse:
      type: object
      description: NATS user with account and application context (for list-all response)
      properties:
        id:
          type: integer
        name:
          type: string
        publicKey:
          type: string
        jwt:
          type: string
        isBearer:
          type: boolean
        accountId:
          type: integer
        accountName:
          type: string
        applicationId:
          type: integer
        applicationName:
          type: string
        microserviceUuid:
          type: string
          format: uuid
    NatsUsersListResponse:
      type: object
      properties:
        users:
          type: array
          items:
            $ref: '#/components/schemas/NatsUserResponse'
    NatsAllUsersListResponse:
      type: object
      properties:
        users:
          type: array
          items:
            $ref: '#/components/schemas/NatsUserWithContextResponse'
    NatsAccountEnsureRequest:
      type: object
      properties:
        natsRule:
          type: string
          description: Account rule name (defaults to default-account if omitted)
    NatsCredsResponse:
      type: object
      properties:
        credsBase64:
          type: string
          description: NATS credentials file content encoded as base64
    NatsAccountRulePayload:
      type: object
      description: NATS account rule (authorization policy for an account)
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
        infoUrl:
          type: string
        maxConnections:
          type: integer
          minimum: -1
        maxLeafNodeConnections:
          type: integer
          minimum: -1
        maxData:
          type: integer
          minimum: -1
        maxExports:
          type: integer
          minimum: -1
        maxImports:
          type: integer
          minimum: -1
        maxMsgPayload:
          type: integer
          minimum: -1
        maxSubscriptions:
          type: integer
          minimum: -1
        exportsAllowWildcards:
          type: boolean
        disallowBearer:
          type: boolean
        responsePermissions:
          type: object
          properties:
            maxMsgs:
              type: integer
              minimum: 0
            expires:
              type: integer
              minimum: 0
        respMax:
          type: integer
          minimum: 0
        respTtl:
          type: integer
          minimum: 0
        imports:
          type: array
          description: Stream/service imports (NATS account policy)
          items:
            type: object
            properties:
              name:
                type: string
              subject:
                type: string
              type:
                type: string
                enum:
                  - stream
                  - service
              account:
                type: string
              token:
                type: string
              to:
                type: string
              local_subject:
                type: string
              share:
                type: boolean
        exports:
          type: array
          description: Stream/service exports (NATS account policy)
          items:
            type: object
            properties:
              name:
                type: string
              subject:
                type: string
              type:
                type: string
                enum:
                  - stream
                  - service
              description:
                type: string
              info_url:
                type: string
              token_req:
                type: boolean
              response_type:
                type: string
                enum:
                  - Singleton
                  - Stream
                  - Chunked
              account_token_position:
                type: integer
        memStorage:
          type: integer
          minimum: -1
          description: JetStream memory storage limit in bytes
        diskStorage:
          type: integer
          minimum: -1
          description: JetStream disk storage limit in bytes
        streams:
          type: integer
          minimum: -1
          description: JetStream max streams
        consumer:
          type: integer
          minimum: -1
          description: JetStream max consumers
        maxAckPending:
          type: integer
          minimum: -1
        memMaxStreamBytes:
          type: integer
          minimum: -1
        diskMaxStreamBytes:
          type: integer
          minimum: -1
        maxBytesRequired:
          type: boolean
        tieredLimits:
          type: object
          additionalProperties: true
        pubAllow:
          type: array
          items:
            type: string
        pubDeny:
          type: array
          items:
            type: string
        subAllow:
          type: array
          items:
            type: string
        subDeny:
          type: array
          items:
            type: string
    NatsAccountRuleListResponse:
      type: object
      properties:
        rules:
          type: array
          items:
            $ref: '#/components/schemas/NatsAccountRulePayload'
    NatsUserRulePayload:
      type: object
      description: NATS user rule (authorization policy for a user)
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
        maxSubscriptions:
          type: integer
          minimum: -1
        maxPayload:
          type: integer
          minimum: -1
        maxData:
          type: integer
          minimum: -1
        bearerToken:
          type: boolean
        proxyRequired:
          type: boolean
        allowedConnectionTypes:
          type: array
          items:
            type: string
            enum:
              - STANDARD
              - WEBSOCKET
              - LEAFNODE
              - LEAFNODE_WS
              - MQTT
              - MQTT_WS
              - IN_PROCESS
        src:
          type: array
          items:
            type: string
          description: Allowed client connection source IP/CIDR
        times:
          type: array
          items:
            type: object
            properties:
              start:
                type: string
              end:
                type: string
          description: Allowed time windows for connections
        timesLocation:
          type: string
        respMax:
          type: integer
          minimum: 0
        respTtl:
          type: integer
          minimum: 0
        pubAllow:
          type: array
          items:
            type: string
        pubDeny:
          type: array
          items:
            type: string
        subAllow:
          type: array
          items:
            type: string
        subDeny:
          type: array
          items:
            type: string
        tags:
          type: array
          items:
            type: string
    NatsUserRuleListResponse:
      type: object
      properties:
        rules:
          type: array
          items:
            $ref: '#/components/schemas/NatsUserRulePayload'
    IOFogNodeTunnelStatusInfoResponse:
      type: object
      properties:
        username:
          type: string
        host:
          type: string
        remotePort:
          type: number
        localPort:
          type: number
        status:
          type: string
    LoginRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          minLength: 1
          description: >-
            Login identifier (email for normal users; bootstrap admin may use a
            non-email username)
        password:
          type: string
        totp:
          type: string
          description: >-
            TOTP or recovery code when MFA is enabled (optional otherwise; CLI
            may send empty string)
    MfaEnrollResponse:
      type: object
      properties:
        secret:
          type: string
        otpauthUrl:
          type: string
    MfaConfirmRequest:
      type: object
      required:
        - code
      properties:
        code:
          type: string
    MfaDisableRequest:
      type: object
      required:
        - password
      properties:
        password:
          type: string
        code:
          type: string
    RefreshRequest:
      type: object
      required:
        - refreshToken
      properties:
        refreshToken:
          type: string
    LoginSuccessResponse:
      type: object
      required:
        - accessToken
        - refreshToken
      properties:
        accessToken:
          type: string
          description: >
            JWT access token (`token_use=access`). Includes
            `password_change_required: true` when the account must change its
            password before full API access.
        refreshToken:
          type: string
          description: >-
            JWT refresh token (`token_use=refresh`). Use only with POST
            /user/refresh.
    InteractionStepResponse:
      type: object
      required:
        - step
      properties:
        step:
          type: string
          enum:
            - login
            - mfa
            - enroll
            - confirm-enroll
            - change-password
            - complete
    InteractionLoginRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          description: Login identifier (not required to be an email address)
        password:
          type: string
    InteractionMfaRequest:
      type: object
      required:
        - code
      properties:
        code:
          type: string
    InteractionEnrollResponse:
      type: object
      required:
        - step
        - secret
        - otpauthUrl
      properties:
        step:
          type: string
        secret:
          type: string
        otpauthUrl:
          type: string
    InteractionConfirmEnrollResponse:
      type: object
      required:
        - step
        - recoveryCodes
      properties:
        step:
          type: string
        recoveryCodes:
          type: array
          items:
            type: string
    InteractionCompleteResponse:
      type: object
      required:
        - redirectTo
        - step
      properties:
        redirectTo:
          type: string
          description: OAuth resume URL; navigate browser here after all steps complete
        step:
          type: string
          enum:
            - complete
    RefreshSuccessResponse:
      type: object
      required:
        - accessToken
        - refreshToken
      properties:
        accessToken:
          type: string
        refreshToken:
          type: string
    UserProfileDetailsResponse:
      type: object
      description: >
        Embedded auth mode response. External auth mode returns the IdP UserInfo
        object instead

        (may include different fields; `mfaEnabled` is not supplied by
        Controller in external mode).
      properties:
        sub:
          type: string
        email:
          type: string
          description: >-
            Omitted when the login identifier has no `@` (e.g. bootstrap
            username).
        preferred_username:
          type: string
        groups:
          type: array
          items:
            type: string
        password_change_required:
          type: boolean
          description: Present when JWT claim `password_change_required` is true
        mfaEnabled:
          type: boolean
          description: >-
            Embedded auth only - whether the user has enrolled TOTP MFA (login
            requires TOTP when true, except bootstrap)
    ChangePasswordRequest:
      type: object
      required:
        - newPassword
      properties:
        currentPassword:
          type: string
        newPassword:
          type: string
        resetToken:
          type: string
    StatusResponse:
      type: object
      properties:
        status:
          type: string
    RateLimitExceededResponse:
      type: object
      required:
        - name
        - message
      properties:
        name:
          type: string
          example: RateLimitExceededError
        message:
          type: string
          example: Too many authentication requests from this IP address
    AuthUserCreateRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
        password:
          type: string
        groups:
          type: array
          items:
            type: string
    AuthUserUpdateRequest:
      type: object
      properties:
        email:
          type: string
        groups:
          type: array
          items:
            type: string
    AuthUserResponse:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        groups:
          type: array
          items:
            type: string
        mustChangePassword:
          type: boolean
        mfaEnabled:
          type: boolean
        isBootstrap:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    AuthUserResetPasswordResponse:
      type: object
      properties:
        temporaryPassword:
          type: string
        mustChangePassword:
          type: boolean
    AuthUserResetTokenResponse:
      type: object
      properties:
        resetToken:
          type: string
        expiresIn:
          type: integer
    AuthGroupCreateRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        mfaRequired:
          type: boolean
          default: false
          description: >-
            When true, members of this group must enroll and use TOTP MFA at
            login
    AuthGroupUpdateRequest:
      type: object
      description: At least one of `name` or `mfaRequired` is required
      properties:
        name:
          type: string
        mfaRequired:
          type: boolean
          description: >-
            When true, members of this group must enroll and use TOTP MFA at
            login
    AuthGroupResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        isSystem:
          type: boolean
        mfaRequired:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    AuthMigrationExportResponse:
      type: object
      properties:
        exportedAt:
          type: string
          format: date-time
        authMode:
          type: string
          enum:
            - embedded
        users:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              email:
                type: string
              groups:
                type: array
                items:
                  type: string
        groups:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
              isSystem:
                type: boolean
    AuthJwksRotateResponse:
      type: object
      properties:
        kid:
          type: string
        rotatedAt:
          type: string
          format: date-time
        restartRequired:
          type: boolean
    VersionCommandResponse:
      type: object
      required:
        - versionCommand
        - provisionKey
        - expirationTime
      properties:
        versionCommand:
          type: string
        provisionKey:
          type: string
        expirationTime:
          type: string
        semver:
          type: string
          description: Target semver for upgrade or rollback
          pattern: >-
            ^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:[+]([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
    PostTrackingRequest:
      type: array
      items:
        $ref: '#/components/schemas/TrackingEvent'
    TrackingEvent:
      type: object
      required:
        - uuid
      properties:
        uuid:
          type: string
        sourceType:
          type: string
        timestamp:
          type: number
        type:
          type: string
        data:
          type: object
    SecretCreate:
      type: object
      required:
        - name
        - type
        - data
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        type:
          type: string
          enum:
            - Opaque
            - tls
        data:
          type: object
    SecretUpdate:
      type: object
      required:
        - data
      properties:
        data:
          type: object
    SecretResponse:
      type: object
      required:
        - id
        - name
        - type
        - data
        - created_at
        - updated_at
      properties:
        id:
          type: integer
        name:
          type: string
        type:
          type: string
          enum:
            - Opaque
            - tls
        data:
          type: object
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    SecretListResponse:
      type: object
      required:
        - secrets
      properties:
        secrets:
          type: array
          items:
            type: object
            required:
              - id
              - name
              - type
              - created_at
              - updated_at
            properties:
              id:
                type: integer
              name:
                type: string
              type:
                type: string
                enum:
                  - Opaque
                  - tls
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
    CACreateRequest:
      type: object
      required:
        - name
        - subject
        - type
      properties:
        name:
          type: string
          description: Name of the CA
        subject:
          type: string
          description: Subject of the CA (CN)
        expiration:
          type: integer
          description: Expiration time in milliseconds
        type:
          type: string
          enum:
            - k8s-secret
            - direct
            - self-signed
          description: Type of CA
        secretName:
          type: string
          description: Name of the secret (required for direct type)
    CAResponse:
      type: object
      properties:
        name:
          type: string
          description: Name of the CA
        subject:
          type: string
          description: Subject of the CA
        is_ca:
          type: boolean
          description: True if this is a CA
        valid_from:
          type: string
          format: date-time
          description: Validity start date
        valid_to:
          type: string
          format: date-time
          description: Validity end date
        serial_number:
          type: string
          description: Certificate serial number
        data:
          type: object
          properties:
            certificate:
              type: string
              description: PEM encoded certificate
            private_key:
              type: string
              description: PEM encoded private key
    CAListResponse:
      type: object
      properties:
        cas:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                description: Name of the CA
              subject:
                type: string
                description: Subject of the CA
              valid_from:
                type: string
                format: date-time
                description: Validity start date
              valid_to:
                type: string
                format: date-time
                description: Validity end date
              days_remaining:
                type: integer
                description: Days until expiration
              is_expired:
                type: boolean
                description: True if certificate is expired
    CertificateCreateRequest:
      type: object
      required:
        - name
        - subject
        - hosts
      properties:
        name:
          type: string
          description: Name of the certificate
        subject:
          type: string
          description: Subject of the certificate (CN)
        hosts:
          type: string
          description: Comma-separated list of hosts
        expiration:
          type: integer
          description: Expiration time in milliseconds
        ca:
          type: object
          properties:
            type:
              type: string
              enum:
                - k8s-secret
                - direct
                - self-signed
              description: Type of CA
            secretName:
              type: string
              description: Name of the CA secret
            cert:
              type: string
              description: PEM encoded certificate (for direct type)
            key:
              type: string
              description: PEM encoded private key (for direct type)
    CertificateResponse:
      type: object
      properties:
        name:
          type: string
          description: Name of the certificate
        subject:
          type: string
          description: Subject of the certificate
        hosts:
          type: string
          description: Comma-separated list of hosts
        is_ca:
          type: boolean
          description: True if this is a CA
        valid_from:
          type: string
          format: date-time
          description: Validity start date
        valid_to:
          type: string
          format: date-time
          description: Validity end date
        serial_number:
          type: string
          description: Certificate serial number
        ca_name:
          type: string
          description: Name of the signing CA
        certificate_chain:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
              subject:
                type: string
        days_remaining:
          type: integer
          description: Days until expiration
        is_expired:
          type: boolean
          description: True if certificate is expired
        data:
          type: object
          properties:
            certificate:
              type: string
              description: PEM encoded certificate
            private_key:
              type: string
              description: PEM encoded private key
    CertificateListResponse:
      type: object
      properties:
        certificates:
          type: array
          items:
            type: object
            properties:
              name:
                type: string
                description: Name of the certificate
              subject:
                type: string
                description: Subject of the certificate
              hosts:
                type: string
                description: Comma-separated list of hosts
              is_ca:
                type: boolean
                description: True if this is a CA
              valid_from:
                type: string
                format: date-time
                description: Validity start date
              valid_to:
                type: string
                format: date-time
                description: Validity end date
              days_remaining:
                type: integer
                description: Days until expiration
              is_expired:
                type: boolean
                description: True if certificate is expired
              ca_name:
                type: string
                description: Name of the signing CA
    CertificateRenewResponse:
      type: object
      properties:
        name:
          type: string
          description: Name of the certificate
        subject:
          type: string
          description: Subject of the certificate
        hosts:
          type: string
          description: Comma-separated list of hosts
        valid_from:
          type: string
          format: date-time
          description: New validity start date
        valid_to:
          type: string
          format: date-time
          description: New validity end date
        renewed:
          type: boolean
          description: True if certificate was successfully renewed
    Service:
      type: object
      properties:
        name:
          type: string
        type:
          type: string
        resource:
          type: string
        defaultBridge:
          type: string
        bridgePort:
          type: number
        targetPort:
          type: number
        servicePort:
          type: number
        k8sType:
          type: string
          description: >-
            K8s Service type when running on a Kubernetes control plane (e.g.
            LoadBalancer)
        serviceEndpoint:
          type: string
          description: Hub-facing endpoint hostname or LoadBalancer IP after reconcile
        provisioningStatus:
          type: string
          enum:
            - pending
            - ready
            - failed
          description: >-
            Hub provisioning lifecycle. `pending` after create/update/delete
            enqueue or manual retry; `ready` after hub connector/listener and
            K8s Service reconcile succeed; `failed` after max worker attempts
            (use POST reconcile to retry). Edge fog bridge updates are tracked
            separately via fog platform reconcile.
        provisioningError:
          type: string
          nullable: true
          description: Last hub reconcile error when `provisioningStatus` is `failed`
        tags:
          type: array
          items:
            type: string
    ConfigMapCreate:
      type: object
      required:
        - name
        - data
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        data:
          type: object
    ConfigMapUpdate:
      type: object
      required:
        - data
      properties:
        data:
          type: object
    ConfigMapResponse:
      type: object
      required:
        - id
        - name
        - data
        - created_at
        - updated_at
      properties:
        id:
          type: integer
        name:
          type: string
        data:
          type: object
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ConfigMapListResponse:
      type: object
      required:
        - configMaps
      properties:
        configMaps:
          type: array
          items:
            type: object
            required:
              - id
              - name
              - created_at
              - updated_at
            properties:
              id:
                type: integer
              name:
                type: string
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
    VolumeMount:
      type: object
      properties:
        uuid:
          type: string
        name:
          type: string
        secretName:
          type: string
        configMapName:
          type: string
        version:
          type: integer
      required:
        - uuid
        - name
        - version
    VolumeMountCreate:
      type: object
      properties:
        name:
          type: string
        secretName:
          type: string
        configMapName:
          type: string
      required:
        - name
      oneOf:
        - required:
            - secretName
        - required:
            - configMapName
    VolumeMountUpdate:
      type: object
      properties:
        name:
          type: string
        secretName:
          type: string
        configMapName:
          type: string
      oneOf:
        - required:
            - secretName
        - required:
            - configMapName
    VolumeMountLink:
      type: object
      properties:
        fogUuids:
          type: array
          items:
            type: string
          minItems: 1
      required:
        - fogUuids
    VolumeMountUnlink:
      type: object
      properties:
        fogUuids:
          type: array
          items:
            type: string
          minItems: 1
      required:
        - fogUuids
    FogLinkRequest:
      type: object
      properties:
        fogUuids:
          type: array
          items:
            type: string
          minItems: 1
      required:
        - fogUuids
    FogLinkSet:
      type: object
      properties:
        fogUuids:
          type: array
          items:
            type: string
    Model:
      type: object
      properties:
        uuid:
          type: string
        name:
          type: string
        repo:
          type: string
          description: Upstream path without host
        revision:
          type: string
          description: Pin. Empty means latest (OCI) or main (HF).
        registryId:
          type: integer
        files:
          type: array
          items:
            type: string
          description: Hugging Face only. Ignored for OCI registries.
        format:
          type: string
          enum:
            - gguf
            - safetensors
            - onnx
            - pytorch
            - tensorrt
            - unknown
    ModelsListResponse:
      type: object
      properties:
        models:
          type: array
          items:
            $ref: '#/components/schemas/Model'
    AgentModelsListResponse:
      type: object
      properties:
        models:
          type: array
          items:
            $ref: '#/components/schemas/Model'
    ModelCreate:
      type: object
      required:
        - name
        - repo
        - registryId
      properties:
        name:
          type: string
        repo:
          type: string
        revision:
          type: string
        registryId:
          type: integer
        files:
          type: array
          items:
            type: string
        format:
          type: string
          enum:
            - gguf
            - safetensors
            - onnx
            - pytorch
            - tensorrt
            - unknown
    ModelUpdate:
      type: object
      properties:
        repo:
          type: string
        revision:
          type: string
        registryId:
          type: integer
        files:
          type: array
          items:
            type: string
        format:
          type: string
          enum:
            - gguf
            - safetensors
            - onnx
            - pytorch
            - tensorrt
            - unknown
    Knowledge:
      type: object
      properties:
        uuid:
          type: string
        name:
          type: string
          description: >-
            DNS-1123. Unique on the controller and immutable. Separate namespace
            from Models.
        repo:
          type: string
          description: Hub dataset id or OCI path without host
        revision:
          type: string
          description: Optional pin. Empty means latest (OCI) or main (HF).
        registryId:
          type: integer
          description: Registry row. Hugging Face uses the dataset API. OCI uses ORAS.
        files:
          type: array
          items:
            type: string
          description: >-
            Hugging Face only. Empty or omitted means the full dataset.
            Non-empty files on an OCI registry is rejected.
        format:
          type: string
          description: >-
            Optional soft hint. Known values persist lowercase: markdown, pdf,
            jsonl, parquet, arrow, sqlite, faiss, chroma, lance. Any other
            non-empty string is stored as unknown. Omit, null, or empty stays
            omitted. Unknown format is not rejected.
    KnowledgeListResponse:
      type: object
      properties:
        knowledge:
          type: array
          items:
            $ref: '#/components/schemas/Knowledge'
    AgentKnowledgeListResponse:
      type: object
      properties:
        knowledge:
          type: array
          items:
            $ref: '#/components/schemas/Knowledge'
    KnowledgeCreate:
      type: object
      required:
        - name
        - repo
        - registryId
      properties:
        name:
          type: string
        repo:
          type: string
        revision:
          type: string
        registryId:
          type: integer
        files:
          type: array
          items:
            type: string
        format:
          type: string
          description: >-
            Optional soft hint. Known values persist lowercase: markdown, pdf,
            jsonl, parquet, arrow, sqlite, faiss, chroma, lance. Any other
            non-empty string is stored as unknown. Omit, null, or empty stays
            omitted. Unknown format is not rejected.
    KnowledgeUpdate:
      type: object
      properties:
        repo:
          type: string
        revision:
          type: string
        registryId:
          type: integer
        files:
          type: array
          items:
            type: string
        format:
          type: string
          description: >-
            Optional soft hint. Known values persist lowercase: markdown, pdf,
            jsonl, parquet, arrow, sqlite, faiss, chroma, lance. Any other
            non-empty string is stored as unknown. Omit, null, or empty stays
            omitted. Unknown format is not rejected.
    KnowledgeCatalogItem:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Managed fleet Knowledge name. Never uuid or a host path.
    KnowledgeCatalog:
      type: object
      properties:
        bindPath:
          type: string
          description: >-
            Required when items is non-empty. A non-empty bindPath requires at
            least one item. Absolute container path. Projection is
            {bindPath}/{name}/.
        permissions:
          type: string
          enum:
            - ro
            - rw
          default: ro
        items:
          type: array
          items:
            $ref: '#/components/schemas/KnowledgeCatalogItem'
    RuntimeClass:
      type: object
      properties:
        name:
          type: string
        handler:
          type: string
    RuntimeClassesListResponse:
      type: object
      properties:
        runtimeClasses:
          type: array
          items:
            $ref: '#/components/schemas/RuntimeClass'
    AgentRuntimeClassesListResponse:
      type: object
      properties:
        runtimeClasses:
          type: array
          items:
            $ref: '#/components/schemas/RuntimeClass'
    RuntimeClassCreate:
      type: object
      required:
        - name
        - handler
      properties:
        name:
          type: string
        handler:
          type: string
    RuntimeClassUpdate:
      type: object
      properties:
        handler:
          type: string
    MicroserviceCatalogItem:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Managed fleet model name. Never uuid or a host path.
    MicroserviceCatalog:
      type: object
      properties:
        bindPath:
          type: string
          description: >-
            Required when items is non-empty. A non-empty bindPath requires at
            least one item. Absolute container path.
        permissions:
          type: string
          enum:
            - ro
            - rw
          default: ro
        items:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceCatalogItem'
    ContainerDevice:
      type: object
      required:
        - hostPath
        - containerPath
      properties:
        hostPath:
          type: string
        containerPath:
          type: string
        permissions:
          type: string
    ContainerTmpfs:
      type: object
      required:
        - containerPath
      properties:
        containerPath:
          type: string
        size:
          type: integer
        mode:
          type: string
    MicroserviceTemplateVariable:
      type: object
      required:
        - key
      properties:
        key:
          type: string
        description:
          type: string
        defaultValue: {}
    MicroserviceTemplate:
      type: object
      properties:
        name:
          type: string
        description:
          type: string
        variables:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceTemplateVariable'
        microservice:
          type: object
          description: Microservice spec without instance identity fields.
    MicroserviceTemplatesListResponse:
      type: object
      properties:
        microserviceTemplates:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceTemplate'
    MicroserviceTemplateCreate:
      type: object
      required:
        - name
        - microservice
      properties:
        name:
          type: string
        description:
          type: string
        variables:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceTemplateVariable'
        microservice:
          type: object
    MicroserviceTemplateUpdate:
      type: object
      properties:
        description:
          type: string
        variables:
          type: array
          items:
            $ref: '#/components/schemas/MicroserviceTemplateVariable'
        microservice:
          type: object
    MicroserviceTemplateRef:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        variables:
          description: Map of key to value, or array of { key, value }.
          oneOf:
            - type: object
              additionalProperties: true
            - type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                  value: {}
                required:
                  - key
    RbacRule:
      type: object
      properties:
        apiGroups:
          type: array
          items:
            type: string
        resources:
          type: array
          items:
            type: string
        verbs:
          type: array
          items:
            type: string
        resourceNames:
          type: array
          items:
            type: string
          nullable: true
      required:
        - apiGroups
        - resources
        - verbs
    RoleRef:
      type: object
      required:
        - kind
        - name
      properties:
        kind:
          type: string
        name:
          type: string
        apiGroup:
          type: string
    Subject:
      type: object
      required:
        - kind
        - name
      properties:
        kind:
          type: string
        name:
          type: string
        apiGroup:
          type: string
    Role:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        rules:
          type: array
          items:
            $ref: '#/components/schemas/RbacRule'
      required:
        - name
        - apiVersion
        - kind
        - rules
    RoleCreateRequest:
      type: object
      properties:
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        rules:
          type: array
          items:
            $ref: '#/components/schemas/RbacRule'
      required:
        - name
        - rules
    RoleResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        rules:
          type: array
          items:
            $ref: '#/components/schemas/RbacRule'
      required:
        - name
        - apiVersion
        - kind
        - rules
    RoleListResponse:
      type: array
      items:
        $ref: '#/components/schemas/RoleResponse'
    RoleBinding:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        roleRef:
          $ref: '#/components/schemas/RoleRef'
        subjects:
          type: array
          items:
            $ref: '#/components/schemas/Subject'
      required:
        - name
        - apiVersion
        - kind
        - roleRef
        - subjects
    RoleBindingCreateRequest:
      type: object
      properties:
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        roleRef:
          $ref: '#/components/schemas/RoleRef'
        subjects:
          type: array
          items:
            $ref: '#/components/schemas/Subject'
      required:
        - name
        - roleRef
        - subjects
    RoleBindingResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        apiVersion:
          type: string
        kind:
          type: string
        roleRef:
          $ref: '#/components/schemas/RoleRef'
        subjects:
          type: array
          items:
            $ref: '#/components/schemas/Subject'
      required:
        - name
        - apiVersion
        - kind
        - roleRef
        - subjects
    RoleBindingListResponse:
      type: array
      items:
        $ref: '#/components/schemas/RoleBindingResponse'
    ServiceAccount:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        applicationName:
          type: string
          description: Application name this service account belongs to
        roleRef:
          $ref: '#/components/schemas/RoleRef'
      required:
        - name
        - roleRef
    ServiceAccountCreateRequest:
      type: object
      properties:
        name:
          type: string
        applicationName:
          type: string
          description: Application name this service account belongs to
        roleRef:
          $ref: '#/components/schemas/RoleRef'
      required:
        - name
        - applicationName
        - roleRef
    ServiceAccountResponse:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        applicationName:
          type: string
          description: Application name this service account belongs to
        roleRef:
          $ref: '#/components/schemas/RoleRef'
      required:
        - name
        - roleRef
    ServiceAccountListResponse:
      type: array
      items:
        $ref: '#/components/schemas/ServiceAccountResponse'
    ClusterControllerResponse:
      type: object
      properties:
        uuid:
          type: string
        host:
          type: string
          nullable: true
        processId:
          type: integer
          nullable: true
        lastHeartbeat:
          type: string
          format: date-time
          nullable: true
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - uuid
        - isActive
    ClusterControllerListResponse:
      type: array
      items:
        $ref: '#/components/schemas/ClusterControllerResponse'
    ClusterControllerUpdateRequest:
      type: object
      properties:
        host:
          type: string
      additionalProperties: false
    DefaultRouterResponse:
      type: object
      properties:
        host:
          type: string
        messagingPort:
          type: integer
        edgeRouterPort:
          type: integer
          nullable: true
        interRouterPort:
          type: integer
          nullable: true
      required:
        - host
        - messagingPort
    DefaultRouterUpsertRequest:
      type: object
      required:
        - host
      properties:
        host:
          type: string
        messagingPort:
          type: integer
          minimum: 1
          maximum: 65535
          description: Defaults to 5671 when omitted
        edgeRouterPort:
          type: integer
          minimum: 1
          maximum: 65535
          description: Defaults to 45671 when omitted
        interRouterPort:
          type: integer
          minimum: 1
          maximum: 65535
          description: Defaults to 55671 when omitted
      additionalProperties: true
    DefaultRouterRecordResponse:
      type: object
      properties:
        id:
          type: integer
        isEdge:
          type: boolean
        messagingPort:
          type: integer
        edgeRouterPort:
          type: integer
          nullable: true
        interRouterPort:
          type: integer
          nullable: true
        host:
          type: string
        isDefault:
          type: boolean
        iofogUuid:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
      required:
        - id
        - isEdge
        - messagingPort
        - host
        - isDefault
    NetworkTopologyDeploymentTarget:
      type: string
      enum:
        - kubernetes
        - remote
        - edgelet
    NetworkTopologyConnection:
      type: object
      properties:
        id:
          type: integer
        source:
          type: string
        dest:
          type: string
      required:
        - id
        - source
        - dest
    NetworkTopologyNodeBase:
      type: object
      properties:
        id:
          type: string
        iofogUuid:
          type: string
          nullable: true
        fogName:
          type: string
          nullable: true
        host:
          type: string
          nullable: true
        deploymentTarget:
          $ref: '#/components/schemas/NetworkTopologyDeploymentTarget'
        displayName:
          type: string
        role:
          type: string
        mode:
          type: string
      required:
        - id
        - deploymentTarget
        - displayName
        - role
        - mode
    RouterTopologyNode:
      allOf:
        - $ref: '#/components/schemas/NetworkTopologyNodeBase'
    NatsTopologyNode:
      allOf:
        - $ref: '#/components/schemas/NetworkTopologyNodeBase'
    RouterTopologyNodeDetail:
      allOf:
        - $ref: '#/components/schemas/RouterTopologyNode'
        - type: object
          properties:
            messagingPort:
              type: integer
            edgeRouterPort:
              type: integer
              nullable: true
            interRouterPort:
              type: integer
              nullable: true
            isDefault:
              type: boolean
    NatsTopologyNodeDetail:
      allOf:
        - $ref: '#/components/schemas/NatsTopologyNode'
        - type: object
          properties:
            serverPort:
              type: integer
              nullable: true
            leafPort:
              type: integer
              nullable: true
            clusterPort:
              type: integer
              nullable: true
            mqttPort:
              type: integer
              nullable: true
            httpPort:
              type: integer
              nullable: true
            jsStorageSize:
              type: string
              nullable: true
            jsMemoryStoreSize:
              type: string
              nullable: true
            isHub:
              type: boolean
    NetworkTopologySummaryResponse:
      type: object
      properties:
        controlPlane:
          type: string
          enum:
            - kubernetes
            - remote
        router:
          type: object
          properties:
            totalNodes:
              type: integer
            totalConnections:
              type: integer
            byRole:
              type: object
              additionalProperties:
                type: integer
        nats:
          type: object
          properties:
            totalNodes:
              type: integer
            totalConnections:
              type: integer
            byRole:
              type: object
              additionalProperties:
                type: integer
    TopologySpokeGroup:
      type: object
      properties:
        upstreamOf:
          type: string
        role:
          type: string
        count:
          type: integer
      required:
        - upstreamOf
        - role
        - count
    RouterTopologyOverviewResponse:
      type: object
      properties:
        defaultNode:
          $ref: '#/components/schemas/RouterTopologyNode'
          nullable: true
        interiorNodes:
          type: array
          items:
            $ref: '#/components/schemas/RouterTopologyNode'
        spokeGroups:
          type: array
          items:
            $ref: '#/components/schemas/TopologySpokeGroup'
    NatsTopologyOverviewResponse:
      type: object
      properties:
        defaultNode:
          $ref: '#/components/schemas/NatsTopologyNode'
          nullable: true
        serverNodes:
          type: array
          items:
            $ref: '#/components/schemas/NatsTopologyNode'
        spokeGroups:
          type: array
          items:
            $ref: '#/components/schemas/TopologySpokeGroup'
    PaginatedListMeta:
      type: object
      properties:
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
      required:
        - total
        - limit
        - offset
    RouterTopologyNodeListResponse:
      allOf:
        - $ref: '#/components/schemas/PaginatedListMeta'
        - type: object
          properties:
            nodes:
              type: array
              items:
                $ref: '#/components/schemas/RouterTopologyNode'
    NatsTopologyNodeListResponse:
      allOf:
        - $ref: '#/components/schemas/PaginatedListMeta'
        - type: object
          properties:
            nodes:
              type: array
              items:
                $ref: '#/components/schemas/NatsTopologyNode'
    RouterTopologyConnectionListResponse:
      allOf:
        - $ref: '#/components/schemas/PaginatedListMeta'
        - type: object
          properties:
            connections:
              type: array
              items:
                $ref: '#/components/schemas/NetworkTopologyConnection'
    NatsTopologyConnectionListResponse:
      allOf:
        - $ref: '#/components/schemas/PaginatedListMeta'
        - type: object
          properties:
            connections:
              type: array
              items:
                $ref: '#/components/schemas/NetworkTopologyConnection'
    TopologyNodeConnectionsResponse:
      type: object
      properties:
        upstream:
          type: array
          items:
            $ref: '#/components/schemas/NetworkTopologyConnection'
        downstream:
          type: array
          items:
            $ref: '#/components/schemas/NetworkTopologyConnection'
    TopologySubgraphResponse:
      type: object
      properties:
        nodes:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/RouterTopologyNode'
              - $ref: '#/components/schemas/NatsTopologyNode'
        connections:
          type: array
          items:
            $ref: '#/components/schemas/NetworkTopologyConnection'
