openapi: 3.0.3
info:
  title: Shoehorn Operations API
  description: Workloads, deployment tracking, and GitOps management.
  version: 1.0.0

servers:
  - url: https://shoehorn.example.com/api/v1
    description: Production

paths:
  # --- Workloads ---
  /operations/workloads:
    get:
      summary: List all workloads
      description: Returns workloads across all registered K8s clusters.
      tags: [Workloads]
      parameters:
        - name: cluster_id
          in: query
          schema: { type: string }
        - name: namespace
          in: query
          schema: { type: string }
        - name: kind
          in: query
          schema: { type: string, enum: [Deployment, StatefulSet, DaemonSet, CronJob, Job] }
        - name: limit
          in: query
          schema: { type: integer, default: 20 }
        - name: cursor
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Paginated workloads

  /operations/workloads/stats:
    get:
      summary: Get workload statistics
      tags: [Workloads]
      responses:
        '200':
          description: Workload aggregate statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  total: { type: integer }
                  by_kind: { type: object, additionalProperties: { type: integer } }
                  by_cluster: { type: object, additionalProperties: { type: integer } }
                  healthy: { type: integer }
                  unhealthy: { type: integer }

  /operations/workloads/image-stats:
    get:
      summary: Get image usage statistics
      description: Returns aggregated container image statistics across workloads. All filters are optional and combine with AND.
      tags: [Workloads]
      parameters:
        - name: cluster
          in: query
          schema: { type: string }
        - name: namespace
          in: query
          schema: { type: string }
        - name: team
          in: query
          schema: { type: string }
        - name: owner
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Image statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  total_images: { type: integer }
                  unique_images: { type: integer }
                  by_registry: { type: object, additionalProperties: { type: integer } }
                  outdated: { type: integer, description: "Images older than the platform's freshness threshold" }
        '400':
          description: Invalid filter value

  /operations/workloads/replica-stats:
    get:
      summary: Get replica health statistics
      description: Returns aggregated replica health (desired vs ready) across workloads.
      tags: [Workloads]
      parameters:
        - name: cluster
          in: query
          schema: { type: string }
        - name: namespace
          in: query
          schema: { type: string }
        - name: team
          in: query
          schema: { type: string }
        - name: owner
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Replica statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  desired: { type: integer }
                  ready: { type: integer }
                  unavailable: { type: integer }
                  by_cluster: { type: object, additionalProperties: { type: object } }

  /operations/workloads/network-policy-stats:
    get:
      summary: Get network policy coverage statistics
      description: Returns the share of workloads in a cluster covered by at least one NetworkPolicy.
      tags: [Workloads]
      parameters:
        - name: cluster
          in: query
          required: true
          schema: { type: string, maxLength: 255 }
      responses:
        '200':
          description: Coverage statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  cluster: { type: string }
                  total_workloads: { type: integer }
                  covered: { type: integer }
                  uncovered: { type: integer }
                  coverage_percent: { type: number }
        '400':
          description: cluster query parameter missing or too long
        '503':
          description: Network policy service not configured

  /operations/workloads/{id}:
    get:
      summary: Get workload details
      tags: [Workloads]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Workload details including pods and events

  /operations/workloads/{id}/pods:
    get:
      summary: Get workload pods
      tags: [Workloads]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Pods belonging to workload

  /operations/workloads/{id}/events:
    get:
      summary: Get workload events
      tags: [Workloads]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Recent Kubernetes events for workload

  # --- Zombie Workloads ---
  /operations/zombies:
    get:
      summary: List zombie workloads
      description: Returns workloads that are not matched to any catalog entity (unowned).
      tags: [Workloads]
      parameters:
        - name: cluster_id
          in: query
          schema: { type: string }
        - name: namespace
          in: query
          schema: { type: string }
      responses:
        '200':
          description: Unowned workloads

  # --- GitOps ---
  /operations/gitops:
    get:
      summary: List GitOps resources
      description: Returns ArgoCD Applications and FluxCD resources across clusters.
      tags: [GitOps]
      parameters:
        - name: platform
          in: query
          schema: { type: string, enum: [argocd, fluxcd] }
        - name: cluster_id
          in: query
          schema: { type: string }
        - name: sync_status
          in: query
          schema: { type: string, enum: [synced, out_of_sync, unknown] }
        - name: health_status
          in: query
          schema: { type: string, enum: [healthy, degraded, progressing, missing, unknown] }
      responses:
        '200':
          description: GitOps resources

  /operations/gitops/stats:
    get:
      summary: Get GitOps statistics
      tags: [GitOps]
      responses:
        '200':
          description: Aggregate GitOps statistics

  /operations/gitops/{id}:
    get:
      summary: Get GitOps resource details
      tags: [GitOps]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: GitOps resource details

  /operations/gitops/{id}/sync:
    post:
      summary: Trigger GitOps sync
      description: Sends a sync command to the agent managing this resource.
      tags: [GitOps]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Sync command queued

  /operations/gitops/{id}/refresh:
    post:
      summary: Trigger GitOps refresh
      description: Sends a refresh command to re-evaluate desired state.
      tags: [GitOps]
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Refresh command queued

  # --- Network Flows (cluster-scoped) ---
  /operations/clusters/{clusterId}/network-flows:
    get:
      summary: List aggregated network flows for a cluster
      description: |
        Returns aggregated source-to-destination flows. Backed by the network flow service —
        returns `503` if that service is not configured.
      tags: [NetworkFlows]
      parameters:
        - name: clusterId
          in: path
          required: true
          schema: { type: string }
        - name: timeRange
          in: query
          description: "Window over which to aggregate. Examples: `15m`, `1h`, `24h`."
          schema: { type: string }
        - name: minConnections
          in: query
          description: "Drop edges below this connection count."
          schema: { type: integer, default: 0 }
        - name: page
          in: query
          schema: { type: integer, default: 1 }
        - name: pageSize
          in: query
          schema: { type: integer, default: 100 }
      responses:
        '200':
          description: Aggregated flows
          content:
            application/json:
              schema:
                type: object
                properties:
                  flows:
                    type: array
                    items:
                      type: object
                      properties:
                        sourceEntityId: { type: string }
                        destEntityId: { type: string }
                        destPort: { type: integer }
                        connectionCount: { type: integer }
                        lastSeenAt: { type: string, format: date-time }
                  meta:
                    type: object
                    properties:
                      timeRange: { type: string }
                      totalFlows: { type: integer }
        '400':
          description: clusterId missing
        '503':
          description: Network flow service not configured

  /operations/clusters/{clusterId}/network-flows/topology:
    get:
      summary: Get the network topology graph for a cluster
      description: Returns nodes, edges, and summary stats suitable for graph rendering.
      tags: [NetworkFlows]
      parameters:
        - name: clusterId
          in: path
          required: true
          schema: { type: string }
        - name: timeRange
          in: query
          schema: { type: string }
        - name: minConnections
          in: query
          schema: { type: integer, default: 0 }
        - name: page
          in: query
          schema: { type: integer, default: 1 }
        - name: pageSize
          in: query
          schema: { type: integer, default: 100 }
      responses:
        '200':
          description: Topology
          content:
            application/json:
              schema:
                type: object
                properties:
                  nodes: { type: array, items: { type: object } }
                  edges: { type: array, items: { type: object } }
                  stats: { type: object }
        '400':
          description: clusterId missing
        '503':
          description: Network flow service not configured

  /operations/clusters/{clusterId}/network-flows/stats:
    get:
      summary: Get summary statistics for a cluster's network flows
      tags: [NetworkFlows]
      parameters:
        - name: clusterId
          in: path
          required: true
          schema: { type: string }
        - name: timeRange
          in: query
          schema: { type: string }
        - name: minConnections
          in: query
          schema: { type: integer, default: 0 }
      responses:
        '200':
          description: Summary statistics
        '400':
          description: clusterId missing
        '503':
          description: Network flow service not configured

  # --- Agent GitOps Endpoints ---
  /k8s/gitops/push:
    post:
      summary: Push GitOps resources from agent
      description: Called by the K8s agent to push discovered GitOps resources.
      tags: [GitOps Agent]
      security:
        - AgentToken: []
      responses:
        '200':
          description: Resources received

  /k8s/{clusterId}/gitops/commands:
    get:
      summary: Get pending GitOps commands for agent
      tags: [GitOps Agent]
      security:
        - AgentToken: []
      parameters:
        - name: clusterId
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Pending commands (sync, refresh)

  /k8s/{clusterId}/gitops/commands/{commandId}:
    patch:
      summary: Update command status
      tags: [GitOps Agent]
      security:
        - AgentToken: []
      parameters:
        - name: clusterId
          in: path
          required: true
          schema: { type: string }
        - name: commandId
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Command status updated

components:
  securitySchemes:
    AgentToken:
      type: http
      scheme: bearer
