{
  "$defs": {
    "App": {
      "additionalProperties": false,
      "properties": {
        "annotations": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        "autoscaling": {
          "$ref": "#/$defs/Autoscaling"
        },
        "command": {
          "description": "Overrides the image's start command.",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "displayName": {
          "type": "string"
        },
        "domains": {
          "description": "Hostnames served by this app.",
          "items": {
            "$ref": "#/$defs/Domain"
          },
          "type": "array"
        },
        "env": {
          "items": {
            "$ref": "#/$defs/Env"
          },
          "type": "array"
        },
        "image": {
          "description": "Image to run. Exclusive with source.",
          "type": "string"
        },
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        "name": {
          "type": "string"
        },
        "ports": {
          "items": {
            "$ref": "#/$defs/Port"
          },
          "type": "array"
        },
        "preDeployCommand": {
          "description": "Runs before every rollout; a failure leaves the old version serving.",
          "type": "string"
        },
        "probes": {
          "$ref": "#/$defs/Probes"
        },
        "publicPorts": {
          "description": "Raw TCP or UDP ports opened to the internet for this app, for protocols an HTTP hostname cannot carry. Needs a cluster with a public address.",
          "items": {
            "$ref": "#/$defs/PublicPort"
          },
          "type": "array"
        },
        "pullSecret": {
          "description": "Name of the registry credential used to pull a private image.",
          "type": "string"
        },
        "replicas": {
          "type": "integer"
        },
        "resources": {
          "$ref": "#/$defs/Resources"
        },
        "secrets": {
          "description": "Whole secrets injected as env or mounted as files.",
          "items": {
            "$ref": "#/$defs/SecretUse"
          },
          "type": "array"
        },
        "shareWith": {
          "description": "Other projects allowed to reach this app across the network isolation baseline.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "sidecars": {
          "items": {
            "$ref": "#/$defs/Sidecar"
          },
          "type": "array"
        },
        "source": {
          "allOf": [
            {
              "$ref": "#/$defs/Source"
            }
          ],
          "description": "Build from a repository instead of running an image. Exclusive with image."
        },
        "volumes": {
          "items": {
            "$ref": "#/$defs/Volume"
          },
          "type": "array"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "Autoscaling": {
      "additionalProperties": false,
      "properties": {
        "maxReplicas": {
          "type": "integer"
        },
        "minReplicas": {
          "type": "integer"
        },
        "targetCPU": {
          "description": "Average CPU utilisation percent that adds a replica.",
          "type": "integer"
        },
        "targetMemory": {
          "description": "Average memory utilisation percent that adds a replica.",
          "type": "integer"
        }
      },
      "type": "object"
    },
    "Domain": {
      "additionalProperties": false,
      "properties": {
        "host": {
          "type": "string"
        },
        "path": {
          "description": "Defaults to /.",
          "type": "string"
        },
        "port": {
          "description": "Which of the app's ports serves it. Defaults to the first.",
          "type": "integer"
        }
      },
      "required": [
        "host"
      ],
      "type": "object"
    },
    "Env": {
      "additionalProperties": false,
      "properties": {
        "fromSecret": {
          "allOf": [
            {
              "$ref": "#/$defs/SecretKey"
            }
          ],
          "description": "One key of a secret. The value never enters the app spec."
        },
        "fromService": {
          "allOf": [
            {
              "$ref": "#/$defs/ServiceKey"
            }
          ],
          "description": "One connection key of a managed service, e.g. DATABASE_URL."
        },
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "Port": {
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string"
        },
        "port": {
          "type": "integer"
        },
        "protocol": {
          "description": "TCP (default) or UDP.",
          "type": "string"
        }
      },
      "required": [
        "port"
      ],
      "type": "object"
    },
    "Probe": {
      "additionalProperties": false,
      "properties": {
        "failureThreshold": {
          "type": "integer"
        },
        "initialDelaySeconds": {
          "type": "integer"
        },
        "path": {
          "description": "HTTP path to probe; unset probes the port with TCP.",
          "type": "string"
        },
        "periodSeconds": {
          "type": "integer"
        },
        "port": {
          "type": "integer"
        },
        "successThreshold": {
          "type": "integer"
        },
        "timeoutSeconds": {
          "type": "integer"
        }
      },
      "type": "object"
    },
    "Probes": {
      "additionalProperties": false,
      "properties": {
        "liveness": {
          "$ref": "#/$defs/Probe"
        },
        "readiness": {
          "$ref": "#/$defs/Probe"
        },
        "startup": {
          "$ref": "#/$defs/Probe"
        }
      },
      "type": "object"
    },
    "PublicPort": {
      "additionalProperties": false,
      "properties": {
        "port": {
          "description": "The public port, unique on the cluster per protocol.",
          "type": "integer"
        },
        "protocol": {
          "description": "TCP (default) or UDP.",
          "type": "string"
        },
        "target": {
          "description": "Which of the app's ports it reaches. Defaults to the same number.",
          "type": "integer"
        },
        "via": {
          "description": "How the port reaches the internet: loadBalancer or nodePort. Unset lets the console choose what the cluster serves for free, and fail on a cloud where a load balancer costs money until you pick.",
          "type": "string"
        }
      },
      "required": [
        "port"
      ],
      "type": "object"
    },
    "Resources": {
      "additionalProperties": false,
      "properties": {
        "limits": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        "requests": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "cpu and memory the scheduler reserves, e.g. cpu: 250m, memory: 256Mi.",
          "type": "object"
        }
      },
      "type": "object"
    },
    "Secret": {
      "additionalProperties": false,
      "properties": {
        "generate": {
          "description": "Keys apply fills with a random value when the secret lacks them, such as a signing key. Never overwritten once set.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "keys": {
          "description": "Keys the project reads. Apply fails when the secret lacks one.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "name": {
          "type": "string"
        },
        "type": {
          "description": "Opaque (default), kubernetes.io/tls, kubernetes.io/basic-auth, kubernetes.io/ssh-auth or kubernetes.io/dockerconfigjson.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "SecretKey": {
      "additionalProperties": false,
      "properties": {
        "key": {
          "type": "string"
        },
        "secret": {
          "type": "string"
        }
      },
      "required": [
        "key",
        "secret"
      ],
      "type": "object"
    },
    "SecretUse": {
      "additionalProperties": false,
      "properties": {
        "mountPath": {
          "description": "Where the files go, with use: volume.",
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "prefix": {
          "description": "Prepended to every key, with use: env.",
          "type": "string"
        },
        "use": {
          "description": "env (default) or volume.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "Service": {
      "additionalProperties": false,
      "properties": {
        "config": {
          "description": "The service's own settings, as the catalog defines them.",
          "type": "object"
        },
        "deletionProtection": {
          "type": "boolean"
        },
        "name": {
          "type": "string"
        },
        "type": {
          "description": "Catalog id: postgres, mysql, redis, mongodb, …",
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ],
      "type": "object"
    },
    "ServiceKey": {
      "additionalProperties": false,
      "properties": {
        "key": {
          "type": "string"
        },
        "service": {
          "type": "string"
        }
      },
      "required": [
        "key",
        "service"
      ],
      "type": "object"
    },
    "Sidecar": {
      "additionalProperties": false,
      "properties": {
        "env": {
          "items": {
            "$ref": "#/$defs/Env"
          },
          "type": "array"
        },
        "image": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "ports": {
          "items": {
            "$ref": "#/$defs/Port"
          },
          "type": "array"
        },
        "resources": {
          "$ref": "#/$defs/Resources"
        }
      },
      "required": [
        "image",
        "name"
      ],
      "type": "object"
    },
    "Source": {
      "additionalProperties": false,
      "properties": {
        "autoDeploy": {
          "description": "Rebuild and roll out on every push. Defaults to true.",
          "type": "boolean"
        },
        "branch": {
          "description": "Defaults to main.",
          "type": "string"
        },
        "build": {
          "description": "auto (default), dockerfile or buildpack.",
          "type": "string"
        },
        "buildEnv": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Build-time variables.",
          "type": "object"
        },
        "dockerfile": {
          "description": "Path to the Dockerfile, with build: dockerfile.",
          "type": "string"
        },
        "path": {
          "description": "Directory inside the repository to build.",
          "type": "string"
        },
        "registry": {
          "description": "Registry credential builds push through.",
          "type": "string"
        },
        "repo": {
          "description": "Repository URL, or owner/name on GitHub.",
          "type": "string"
        }
      },
      "required": [
        "repo"
      ],
      "type": "object"
    },
    "Task": {
      "additionalProperties": false,
      "properties": {
        "annotations": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        "app": {
          "description": "Run with this app's image, env and secrets. Exclusive with image.",
          "type": "string"
        },
        "args": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "command": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "concurrencyPolicy": {
          "description": "Allow, Forbid or Replace, for a run that overlaps the previous one.",
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "displayName": {
          "type": "string"
        },
        "env": {
          "items": {
            "$ref": "#/$defs/Env"
          },
          "type": "array"
        },
        "historyLimit": {
          "type": "integer"
        },
        "image": {
          "description": "Run this image on its own. Exclusive with app.",
          "type": "string"
        },
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object"
        },
        "name": {
          "type": "string"
        },
        "resources": {
          "$ref": "#/$defs/Resources"
        },
        "retries": {
          "type": "integer"
        },
        "schedule": {
          "description": "Cron expression. Unset means a one-off run, started by hand.",
          "type": "string"
        },
        "suspend": {
          "type": "boolean"
        },
        "timeoutSeconds": {
          "type": "integer"
        },
        "timezone": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "Volume": {
      "additionalProperties": false,
      "properties": {
        "mountPath": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "size": {
          "description": "e.g. 10Gi.",
          "type": "string"
        },
        "storageClass": {
          "description": "Unset takes the cluster's default class.",
          "type": "string"
        }
      },
      "required": [
        "mountPath",
        "name",
        "size"
      ],
      "type": "object"
    }
  },
  "$id": "https://anyport.dev/schema/anyport.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "description": "A project in a file: apps, managed services, secret names, tasks, variables and domains. Secret values never belong here.",
  "properties": {
    "apiVersion": {
      "description": "Manifest contract version. Always anyport.dev/v1alpha1.",
      "type": "string"
    },
    "apps": {
      "items": {
        "$ref": "#/$defs/App"
      },
      "type": "array"
    },
    "description": {
      "type": "string"
    },
    "displayName": {
      "description": "Human-readable name shown in the console.",
      "type": "string"
    },
    "environment": {
      "description": "production, staging or development.",
      "type": "string"
    },
    "kind": {
      "description": "Always Project.",
      "type": "string"
    },
    "name": {
      "description": "Project name: lowercase letters, digits and dashes. Also the namespace prefix on the cluster.",
      "type": "string"
    },
    "secrets": {
      "description": "Secrets the project needs, by name and key. Values are set out of band and never live in this file.",
      "items": {
        "$ref": "#/$defs/Secret"
      },
      "type": "array"
    },
    "services": {
      "description": "Managed services from the catalog.",
      "items": {
        "$ref": "#/$defs/Service"
      },
      "type": "array"
    },
    "tasks": {
      "description": "Scheduled and one-off jobs.",
      "items": {
        "$ref": "#/$defs/Task"
      },
      "type": "array"
    },
    "variables": {
      "additionalProperties": {
        "type": "string"
      },
      "description": "Project variables, referenced from env values as ${{ NAME }}. Plaintext: never put a credential here.",
      "type": "object"
    }
  },
  "required": [
    "apiVersion",
    "kind",
    "name"
  ],
  "title": "Anyport project manifest",
  "type": "object"
}
