{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://schemas.ctrlgecko.com/deploy/v1/schema.json",
  "title": "Ctrl+Gecko Deploy Schema v1",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "project",
    "source",
    "deploys"
  ],
  "properties": {
    "schema_version": {
      "const": 1
    },
    "project": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "name"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9._-]+$"
        },
        "name": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "source": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "checkout"
      ],
      "properties": {
        "checkout": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "mode"
          ],
          "properties": {
            "mode": {
              "enum": [
                "sparse",
                "full"
              ]
            },
            "paths": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "string",
                "minLength": 1
              },
              "uniqueItems": true
            }
          },
          "allOf": [
            {
              "if": {
                "properties": {
                  "mode": {
                    "const": "sparse"
                  }
                },
                "required": [
                  "mode"
                ]
              },
              "then": {
                "required": [
                  "paths"
                ]
              }
            },
            {
              "if": {
                "properties": {
                  "mode": {
                    "const": "full"
                  }
                },
                "required": [
                  "mode"
                ]
              },
              "then": {
                "not": {
                  "required": [
                    "paths"
                  ]
                }
              }
            }
          ]
        }
      }
    },
    "deploys": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/deploy"
      }
    }
  },
  "$defs": {
    "deploy": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "type",
        "config"
      ],
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9._-]+$"
        },
        "type": {
          "enum": [
            "apache_static",
            "hugo_static",
            "python_tool",
            "docker_compose"
          ]
        },
        "config": {
          "oneOf": [
            {
              "$ref": "#/$defs/apache_static_config"
            },
            {
              "$ref": "#/$defs/hugo_static_config"
            },
            {
              "$ref": "#/$defs/python_tool_config"
            },
            {
              "$ref": "#/$defs/docker_compose_config"
            }
          ]
        },
        "checks": {
          "$ref": "#/$defs/checks"
        },
        "lifecycle": {
          "$ref": "#/$defs/deploy_lifecycle"
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "type": {
                "const": "apache_static"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "config": {
                "$ref": "#/$defs/apache_static_config"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "hugo_static"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "config": {
                "$ref": "#/$defs/hugo_static_config"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "python_tool"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "config": {
                "$ref": "#/$defs/python_tool_config"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "docker_compose"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "properties": {
              "config": {
                "$ref": "#/$defs/docker_compose_config"
              }
            }
          }
        }
      ]
    },
    "apache_static_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "canonical_domain",
        "apache"
      ],
      "properties": {
        "canonical_domain": {
          "$ref": "#/$defs/domain"
        },
        "apache": {
          "$ref": "#/$defs/apache_config"
        },
        "redirects": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/redirect"
          }
        },
        "rewrites": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/rewrite"
          }
        },
        "keep_releases": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        },
        "certbot": {
          "$ref": "#/$defs/certbot_config"
        },
        "proxy_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/proxy_route"
          },
          "uniqueItems": true
        },
        "static_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/static_route"
          },
          "uniqueItems": true
        }
      }
    },
    "apache_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "document_root"
      ],
      "properties": {
        "aliases": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/domain"
          },
          "uniqueItems": true
        },
        "document_root": {
          "$ref": "#/$defs/relative_path"
        },
        "directories": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/apache_directory"
          }
        },
        "headers": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/apache_response_header"
          },
          "uniqueItems": true
        }
      }
    },
    "apache_directory": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path"
      ],
      "properties": {
        "path": {
          "$ref": "#/$defs/relative_path_or_dot"
        },
        "index": {
          "type": "string",
          "minLength": 1
        },
        "allow_override": {
          "type": "boolean"
        },
        "options": {
          "type": "array",
          "items": {
            "enum": [
              "FollowSymLinks",
              "Indexes",
              "MultiViews",
              "SymLinksIfOwnerMatch"
            ]
          },
          "uniqueItems": true
        }
      }
    },
    "redirect": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "source_domain",
        "target_path"
      ],
      "properties": {
        "source_domain": {
          "$ref": "#/$defs/domain"
        },
        "target_path": {
          "$ref": "#/$defs/absolute_path"
        },
        "preserve_path": {
          "type": "boolean",
          "default": false
        }
      }
    },
    "rewrite": {
      "oneOf": [
        {
          "$ref": "#/$defs/predefined_rewrite"
        },
        {
          "$ref": "#/$defs/custom_rewrite"
        }
      ]
    },
    "predefined_rewrite": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "enum": [
            "force_https",
            "redirect_www_to_canonical"
          ]
        }
      }
    },
    "custom_rewrite": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "rule"
      ],
      "properties": {
        "type": {
          "const": "custom"
        },
        "conditions": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          }
        },
        "rule": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "pattern",
            "target"
          ],
          "properties": {
            "pattern": {
              "type": "string",
              "minLength": 1
            },
            "target": {
              "type": "string",
              "minLength": 1
            },
            "flags": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1
              },
              "uniqueItems": true
            }
          }
        }
      }
    },
    "python_tool_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "install"
      ],
      "properties": {
        "package_manager": {
          "enum": [
            "uv"
          ],
          "default": "uv"
        },
        "python_version": {
          "type": "string",
          "minLength": 1
        },
        "install": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "executables"
          ],
          "properties": {
            "executables": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "executable",
                  "target"
                ],
                "properties": {
                  "executable": {
                    "type": "string",
                    "minLength": 1
                  },
                  "target": {
                    "$ref": "#/$defs/absolute_path"
                  }
                }
              }
            }
          }
        },
        "keep_releases": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        }
      }
    },
    "docker_compose_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "compose_file",
        "project_name",
        "env_file",
        "strategy"
      ],
      "properties": {
        "compose_file": {
          "$ref": "#/$defs/relative_path"
        },
        "project_name": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9._-]+$"
        },
        "env_file": {
          "$ref": "#/$defs/absolute_path"
        },
        "persistent_directories": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/persistent_directory"
          },
          "uniqueItems": true
        },
        "pull": {
          "type": "boolean",
          "default": true
        },
        "up": {
          "type": "boolean",
          "default": true
        },
        "remove_orphans": {
          "type": "boolean",
          "default": true
        },
        "health_check": {
          "$ref": "#/$defs/docker_compose_health_check"
        },
        "strategy": {
          "$ref": "#/$defs/docker_compose_strategy"
        },
        "reverse_proxy": {
          "$ref": "#/$defs/docker_reverse_proxy_config"
        },
        "keep_releases": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        },
        "proxy_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/proxy_route"
          },
          "uniqueItems": true
        },
        "static_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/static_route"
          },
          "uniqueItems": true
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "strategy": {
                "properties": {
                  "type": {
                    "const": "blue_green"
                  }
                },
                "required": [
                  "type"
                ]
              }
            },
            "required": [
              "strategy"
            ]
          },
          "then": {
            "required": [
              "health_check",
              "reverse_proxy"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "strategy": {
                "properties": {
                  "type": {
                    "const": "replace"
                  }
                },
                "required": [
                  "type"
                ]
              }
            },
            "required": [
              "strategy"
            ]
          },
          "then": {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "health_check"
                  ]
                },
                {
                  "required": [
                    "reverse_proxy"
                  ]
                },
                {
                  "required": [
                    "proxy_routes"
                  ]
                },
                {
                  "required": [
                    "static_routes"
                  ]
                }
              ]
            }
          }
        }
      ]
    },
    "docker_compose_health_check": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path"
      ],
      "properties": {
        "path": {
          "$ref": "#/$defs/absolute_path"
        },
        "expect_status": {
          "type": "integer",
          "minimum": 100,
          "maximum": 599,
          "default": 200
        }
      }
    },
    "docker_compose_strategy": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "enum": [
            "replace",
            "blue_green"
          ]
        },
        "state_file": {
          "$ref": "#/$defs/absolute_path"
        },
        "slots": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "green",
            "blue"
          ],
          "properties": {
            "green": {
              "$ref": "#/$defs/docker_compose_slot"
            },
            "blue": {
              "$ref": "#/$defs/docker_compose_slot"
            }
          }
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "type": {
                "const": "blue_green"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "required": [
              "state_file",
              "slots"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "replace"
              }
            },
            "required": [
              "type"
            ]
          },
          "then": {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "state_file"
                  ]
                },
                {
                  "required": [
                    "slots"
                  ]
                }
              ]
            }
          }
        }
      ]
    },
    "docker_compose_slot": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "host_port",
        "domain"
      ],
      "properties": {
        "host_port": {
          "type": "integer",
          "minimum": 1024,
          "maximum": 65535
        },
        "domain": {
          "$ref": "#/$defs/domain"
        }
      }
    },
    "docker_reverse_proxy_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "canonical_domain"
      ],
      "properties": {
        "canonical_domain": {
          "$ref": "#/$defs/domain"
        },
        "aliases": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/domain"
          },
          "uniqueItems": true
        },
        "certbot": {
          "$ref": "#/$defs/certbot_config"
        }
      }
    },
    "certbot_config": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "canonical": {
          "type": "boolean",
          "default": false
        },
        "aliases": {
          "type": "boolean",
          "default": false
        },
        "redirects": {
          "type": "boolean",
          "default": false
        },
        "extra_domains": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/domain"
          },
          "uniqueItems": true
        },
        "key_type": {
          "type": "string",
          "enum": [
            "rsa",
            "ecdsa"
          ]
        }
      }
    },
    "checks": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "http": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/http_check"
          }
        }
      }
    },
    "http_check": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "url"
      ],
      "properties": {
        "url": {
          "type": "string",
          "format": "uri"
        },
        "expect_status": {
          "type": "integer",
          "minimum": 100,
          "maximum": 599
        },
        "expect_redirect_to": {
          "type": "string",
          "format": "uri"
        },
        "preserve_path": {
          "type": "boolean"
        }
      },
      "oneOf": [
        {
          "required": [
            "expect_status"
          ]
        },
        {
          "required": [
            "expect_redirect_to"
          ]
        }
      ]
    },
    "domain": {
      "type": "string",
      "pattern": "^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$"
    },
    "relative_path": {
      "type": "string",
      "minLength": 1,
      "not": {
        "pattern": "^/"
      }
    },
    "relative_path_or_dot": {
      "type": "string",
      "minLength": 1,
      "anyOf": [
        {
          "const": "."
        },
        {
          "not": {
            "pattern": "^/"
          }
        }
      ]
    },
    "absolute_path": {
      "type": "string",
      "pattern": "^/"
    },
    "hugo_static_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "canonical_domain",
        "apache",
        "hugo"
      ],
      "properties": {
        "canonical_domain": {
          "$ref": "#/$defs/domain"
        },
        "site_key": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9._-]+$"
        },
        "source_dir": {
          "$ref": "#/$defs/relative_path"
        },
        "apache": {
          "$ref": "#/$defs/apache_config"
        },
        "hugo": {
          "$ref": "#/$defs/hugo_config"
        },
        "redirects": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/redirect"
          }
        },
        "rewrites": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/rewrite"
          }
        },
        "keep_releases": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        },
        "publish_only_if_changed": {
          "type": "boolean"
        },
        "certbot": {
          "$ref": "#/$defs/certbot_config"
        },
        "proxy_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/proxy_route"
          },
          "uniqueItems": true
        },
        "static_routes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/static_route"
          },
          "uniqueItems": true
        }
      }
    },
    "hugo_config": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "environment"
      ],
      "properties": {
        "environment": {
          "type": "string",
          "minLength": 1,
          "default": "production"
        },
        "destination": {
          "type": "string",
          "default": "public"
        }
      }
    },
    "proxy_route": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path",
        "target"
      ],
      "properties": {
        "path": {
          "type": "string",
          "minLength": 2,
          "pattern": "^/[^\\s?#]+$"
        },
        "target": {
          "type": "string",
          "pattern": "^https?://[^\\s]+$"
        }
      }
    },
    "persistent_directory": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path",
        "uid",
        "gid",
        "mode"
      ],
      "properties": {
        "path": {
          "$ref": "#/$defs/absolute_path"
        },
        "uid": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2147483647
        },
        "gid": {
          "type": "integer",
          "minimum": 0,
          "maximum": 2147483647
        },
        "mode": {
          "type": "string",
          "pattern": "^0[0-7]{3}$"
        }
      }
    },
    "static_route": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "path",
        "directory"
      ],
      "properties": {
        "path": {
          "type": "string",
          "minLength": 2,
          "pattern": "^/[^\\s?#]+$"
        },
        "directory": {
          "$ref": "#/$defs/absolute_path"
        },
        "index": {
          "type": "string",
          "minLength": 1
        },
        "allow_override": {
          "type": "boolean",
          "default": false
        },
        "options": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          }
        }
      }
    },
    "deploy_lifecycle": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "pause_during_deploy": {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9._-]+$"
          },
          "uniqueItems": true
        },
        "deploy_after_success": {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9._-]+$"
          },
          "uniqueItems": true
        }
      }
    },
    "apache_response_header": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "value"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1,
          "pattern": "^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"
        },
        "value": {
          "type": "string",
          "pattern": "^[^\r\n]*$"
        },
        "always": {
          "type": "boolean"
        }
      }
    }
  }
}
