Port all IPC handlers to HTTP endpoints so the UI and LLM use the same API. Adds routes/projects.js (scan, compare, init), routes/servers.js (CRUD, containers, logs), routes/docker.js (build, deploy, pull, vscode-diff). Enhanced ssh.js with full SSHService class (SFTP upload/download). Updated renderer api.js to use fetch instead of window.api IPC. Added concurrently for npm run dev (API + Vite + Electron). OpenAPI spec now covers all 24 endpoints. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
621 lines
21 KiB
JSON
621 lines
21 KiB
JSON
{
|
|
"openapi": "3.1.0",
|
|
"info": {
|
|
"title": "Docker Deployment & Coolify API",
|
|
"description": "REST API for managing Docker deployments, Coolify applications, Traefik routing, and server management. Used by both the desktop UI and LLM agents.",
|
|
"version": "2.0.0"
|
|
},
|
|
"servers": [
|
|
{ "url": "http://localhost:3100", "description": "Local dev" }
|
|
],
|
|
"tags": [
|
|
{ "name": "Projects", "description": "Local project scanning and comparison" },
|
|
{ "name": "Servers", "description": "Deployment server CRUD and remote scanning" },
|
|
{ "name": "Docker", "description": "Build, deploy, pull files" },
|
|
{ "name": "Coolify Apps", "description": "Coolify application management" },
|
|
{ "name": "Coolify Environment", "description": "App environment variables" },
|
|
{ "name": "Coolify Deploy", "description": "Deployment pipelines and drift checks" },
|
|
{ "name": "Coolify Infrastructure", "description": "Traefik routes and port management" },
|
|
{ "name": "System", "description": "Health checks and config" }
|
|
],
|
|
"paths": {
|
|
"/api/projects": {
|
|
"get": {
|
|
"operationId": "scanLocalProjects",
|
|
"summary": "Scan local projects",
|
|
"description": "Scans the configured projectsRoot directory for projects with Dockerfiles, docker-compose files, coolify.json, etc.",
|
|
"tags": ["Projects"],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Array of local project info",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/LocalProject" } } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/projects/compare": {
|
|
"post": {
|
|
"operationId": "compareProject",
|
|
"summary": "Compare local vs deployed files",
|
|
"description": "Compares docker-compose.yml, .env, data/, and additional configured files between local and remote.",
|
|
"tags": ["Projects"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string", "description": "Absolute local path to the project" },
|
|
"serverId": { "type": "string", "description": "Server ID to compare against" },
|
|
"remotePath": { "type": "string", "description": "Remote path (e.g. ~/containers/myapp)" }
|
|
},
|
|
"required": ["projectPath", "serverId", "remotePath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Comparison result with file-by-file diff statuses" }
|
|
}
|
|
}
|
|
},
|
|
"/api/projects/init": {
|
|
"post": {
|
|
"operationId": "initProject",
|
|
"summary": "Initialize a project with deployment config",
|
|
"tags": ["Projects"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string" }
|
|
},
|
|
"required": ["projectPath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Init result" }
|
|
}
|
|
}
|
|
},
|
|
"/api/servers": {
|
|
"get": {
|
|
"operationId": "listServers",
|
|
"summary": "List deployment servers",
|
|
"tags": ["Servers"],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Array of configured servers",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Server" } } } }
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"operationId": "saveServer",
|
|
"summary": "Add or update a server",
|
|
"tags": ["Servers"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Server" } } }
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Saved server" }
|
|
}
|
|
}
|
|
},
|
|
"/api/servers/{id}": {
|
|
"delete": {
|
|
"operationId": "deleteServer",
|
|
"summary": "Delete a server",
|
|
"tags": ["Servers"],
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Deletion confirmation" }
|
|
}
|
|
}
|
|
},
|
|
"/api/servers/{id}/scan": {
|
|
"get": {
|
|
"operationId": "scanServer",
|
|
"summary": "Scan remote server for deployed containers",
|
|
"description": "Lists ~/containers on the remote server and inspects each for docker-compose.yml, .env, data/, etc.",
|
|
"tags": ["Servers"],
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Array of deployed projects on the server" }
|
|
}
|
|
}
|
|
},
|
|
"/api/servers/{id}/containers": {
|
|
"get": {
|
|
"operationId": "getRunningContainers",
|
|
"summary": "List running Docker containers on server",
|
|
"tags": ["Servers"],
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Array of running containers",
|
|
"content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "containers": { "type": "array", "items": { "$ref": "#/components/schemas/Container" } } } } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/servers/{id}/logs": {
|
|
"get": {
|
|
"operationId": "getContainerLogs",
|
|
"summary": "Get container logs from server",
|
|
"tags": ["Servers"],
|
|
"parameters": [
|
|
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
|
|
{ "name": "containerName", "in": "query", "schema": { "type": "string" } },
|
|
{ "name": "remotePath", "in": "query", "schema": { "type": "string" } },
|
|
{ "name": "lines", "in": "query", "schema": { "type": "integer", "default": 100 } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Container logs" }
|
|
}
|
|
}
|
|
},
|
|
"/api/docker/build": {
|
|
"post": {
|
|
"operationId": "buildTar",
|
|
"summary": "Build Docker image tar for a project",
|
|
"description": "Runs the project's build-image-tar.ps1 script to create a .tar image file.",
|
|
"tags": ["Docker"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string" }
|
|
},
|
|
"required": ["projectPath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Build result with output" }
|
|
}
|
|
}
|
|
},
|
|
"/api/docker/deploy": {
|
|
"post": {
|
|
"operationId": "deployProject",
|
|
"summary": "Deploy project to server via SSH",
|
|
"description": "Uploads tar + compose + env files, loads Docker image, runs docker compose up. Includes health check polling.",
|
|
"tags": ["Docker"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string", "description": "Local project path" },
|
|
"serverId": { "type": "string", "description": "Target server ID" },
|
|
"remotePath": { "type": "string", "description": "Remote deploy path (e.g. ~/containers/myapp)" }
|
|
},
|
|
"required": ["projectPath", "serverId", "remotePath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Deploy result with health status",
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeployResult" } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/docker/pull": {
|
|
"post": {
|
|
"operationId": "pullFiles",
|
|
"summary": "Pull files from remote server",
|
|
"description": "Downloads files/directories from the remote server to local paths via SFTP.",
|
|
"tags": ["Docker"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"serverId": { "type": "string" },
|
|
"files": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"remotePath": { "type": "string" },
|
|
"localPath": { "type": "string" },
|
|
"type": { "type": "string", "enum": ["file", "directory"] }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"required": ["serverId", "files"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Pull result with pulled/errors arrays" }
|
|
}
|
|
}
|
|
},
|
|
"/api/docker/vscode-diff": {
|
|
"post": {
|
|
"operationId": "openVSCodeDiff",
|
|
"summary": "Open VS Code diff between local and remote file",
|
|
"tags": ["Docker"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"serverId": { "type": "string" },
|
|
"localPath": { "type": "string" },
|
|
"remoteFilePath": { "type": "string" }
|
|
},
|
|
"required": ["serverId", "localPath", "remoteFilePath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Success or error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/coolify/apps": {
|
|
"get": {
|
|
"operationId": "listCoolifyApps",
|
|
"summary": "List all Coolify apps",
|
|
"description": "Returns all applications from Coolify, enriched with HOST_PORT env vars.",
|
|
"tags": ["Coolify Apps"],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Array of Coolify applications",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/CoolifyApp" } } } }
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"operationId": "createCoolifyApp",
|
|
"summary": "Create a new Coolify application",
|
|
"tags": ["Coolify Apps"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCoolifyAppRequest" } } }
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Created app object" }
|
|
}
|
|
}
|
|
},
|
|
"/api/coolify/apps/find/{name}": {
|
|
"get": {
|
|
"operationId": "findCoolifyApp",
|
|
"summary": "Find Coolify app by name",
|
|
"tags": ["Coolify Apps"],
|
|
"parameters": [
|
|
{ "name": "name", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "App object or null" }
|
|
}
|
|
}
|
|
},
|
|
"/api/coolify/apps/{uuid}": {
|
|
"patch": {
|
|
"operationId": "updateCoolifyApp",
|
|
"summary": "Update an existing Coolify app",
|
|
"tags": ["Coolify Apps"],
|
|
"parameters": [
|
|
{ "name": "uuid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "type": "object" } } }
|
|
},
|
|
"responses": { "200": { "description": "Updated app" } }
|
|
},
|
|
"delete": {
|
|
"operationId": "deleteCoolifyApp",
|
|
"summary": "Delete a Coolify app",
|
|
"tags": ["Coolify Apps"],
|
|
"parameters": [
|
|
{ "name": "uuid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": { "200": { "description": "Deletion confirmation" } }
|
|
}
|
|
},
|
|
"/api/coolify/apps/{uuid}/envs": {
|
|
"get": {
|
|
"operationId": "listCoolifyEnvs",
|
|
"summary": "List env vars for a Coolify app",
|
|
"tags": ["Coolify Environment"],
|
|
"parameters": [
|
|
{ "name": "uuid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": { "200": { "description": "Array of env vars" } }
|
|
},
|
|
"post": {
|
|
"operationId": "setCoolifyEnv",
|
|
"summary": "Set an environment variable",
|
|
"tags": ["Coolify Environment"],
|
|
"parameters": [
|
|
{ "name": "uuid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"key": { "type": "string" },
|
|
"value": { "type": "string" }
|
|
},
|
|
"required": ["key", "value"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": { "200": { "description": "Env var created/updated" } }
|
|
}
|
|
},
|
|
"/api/coolify/apps/{uuid}/deploy": {
|
|
"post": {
|
|
"operationId": "deployCoolifyApp",
|
|
"summary": "Trigger Coolify deployment",
|
|
"tags": ["Coolify Deploy"],
|
|
"parameters": [
|
|
{ "name": "uuid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": { "200": { "description": "Deployment triggered" } }
|
|
}
|
|
},
|
|
"/api/coolify/servers": {
|
|
"get": {
|
|
"operationId": "listCoolifyServers",
|
|
"summary": "List all Coolify servers",
|
|
"tags": ["Coolify Infrastructure"],
|
|
"responses": { "200": { "description": "Array of Coolify servers" } }
|
|
}
|
|
},
|
|
"/api/coolify/next-port": {
|
|
"get": {
|
|
"operationId": "getNextPort",
|
|
"summary": "Get next available HOST_PORT",
|
|
"description": "Scans Coolify env vars and Traefik config to find the highest used port.",
|
|
"tags": ["Coolify Infrastructure"],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Next port info",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"nextPort": { "type": "integer" },
|
|
"usedPorts": { "type": "array", "items": { "type": "integer" } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/coolify/routes": {
|
|
"post": {
|
|
"operationId": "addTraefikRoute",
|
|
"summary": "Add a Traefik route via SSH",
|
|
"tags": ["Coolify Infrastructure"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"routeName": { "type": "string" },
|
|
"domain": { "type": "string" },
|
|
"port": { "type": "integer" }
|
|
},
|
|
"required": ["routeName", "domain", "port"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": { "200": { "description": "Route added or already exists" } }
|
|
}
|
|
},
|
|
"/api/coolify/drift": {
|
|
"post": {
|
|
"operationId": "checkDrift",
|
|
"summary": "Check drift between coolify.json and live state",
|
|
"tags": ["Coolify Deploy"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string" },
|
|
"appName": { "type": "string" }
|
|
},
|
|
"required": ["projectPath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": { "200": { "description": "Drift check result" } }
|
|
}
|
|
},
|
|
"/api/coolify/upsert": {
|
|
"post": {
|
|
"operationId": "upsertCoolifyApp",
|
|
"summary": "Full deploy pipeline: config → create/update → env → route → deploy",
|
|
"description": "Reads coolify.json, creates or updates the Coolify app, sets HOST_PORT, configures Traefik, writes changelog, and triggers deployment.",
|
|
"tags": ["Coolify Deploy"],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"projectPath": { "type": "string" },
|
|
"appName": { "type": "string" }
|
|
},
|
|
"required": ["projectPath"]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Upsert result with steps",
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertResult" } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/coolify/config": {
|
|
"get": {
|
|
"operationId": "readCoolifyConfig",
|
|
"summary": "Read coolify.json from a project",
|
|
"tags": ["System"],
|
|
"parameters": [
|
|
{ "name": "path", "in": "query", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": { "200": { "description": "Parsed coolify.json" } }
|
|
}
|
|
},
|
|
"/api/health": {
|
|
"get": {
|
|
"operationId": "healthCheck",
|
|
"summary": "Health check",
|
|
"tags": ["System"],
|
|
"responses": { "200": { "description": "Server status" } }
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"schemas": {
|
|
"LocalProject": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"path": { "type": "string" },
|
|
"hasDockerfile": { "type": "boolean" },
|
|
"hasDockerCompose": { "type": "boolean" },
|
|
"hasCoolifyJson": { "type": "boolean" },
|
|
"dockerStatus": { "type": "string", "enum": ["none", "partial", "configured"] },
|
|
"tarFile": { "type": "string", "nullable": true },
|
|
"serverId": { "type": "string", "nullable": true },
|
|
"remotePath": { "type": "string" }
|
|
}
|
|
},
|
|
"Server": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"name": { "type": "string" },
|
|
"host": { "type": "string" },
|
|
"username": { "type": "string" },
|
|
"useSudo": { "type": "boolean" }
|
|
}
|
|
},
|
|
"Container": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"status": { "type": "string" },
|
|
"ports": { "type": "string" }
|
|
}
|
|
},
|
|
"DeployResult": {
|
|
"type": "object",
|
|
"properties": {
|
|
"success": { "type": "boolean" },
|
|
"healthy": { "type": "boolean" },
|
|
"status": { "type": "string" },
|
|
"uploadedFiles": { "type": "array", "items": { "type": "string" } },
|
|
"message": { "type": "string" }
|
|
}
|
|
},
|
|
"CoolifyApp": {
|
|
"type": "object",
|
|
"properties": {
|
|
"uuid": { "type": "string" },
|
|
"name": { "type": "string" },
|
|
"build_pack": { "type": "string", "enum": ["dockercompose", "nixpacks", "dockerfile"] },
|
|
"git_repository": { "type": "string" },
|
|
"git_branch": { "type": "string" },
|
|
"status": { "type": "string" },
|
|
"fqdn": { "type": "string" },
|
|
"_host_port": { "type": "string", "nullable": true },
|
|
"_envs": { "type": "array" }
|
|
}
|
|
},
|
|
"CreateCoolifyAppRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"buildpack": { "type": "string", "enum": ["dockercompose", "nixpacks"], "default": "dockercompose" },
|
|
"gitRepo": { "type": "string" },
|
|
"gitBranch": { "type": "string", "default": "master" },
|
|
"isStatic": { "type": "boolean", "default": false },
|
|
"publishDir": { "type": "string", "default": "dist" },
|
|
"portsExposes": { "type": "string", "default": "3000" },
|
|
"baseDirectory": { "type": "string", "default": "/" },
|
|
"dockerComposeLocation": { "type": "string", "default": "/docker-compose.yml" },
|
|
"serverUuid": { "type": "string" }
|
|
},
|
|
"required": ["name", "gitRepo"]
|
|
},
|
|
"UpsertResult": {
|
|
"type": "object",
|
|
"properties": {
|
|
"success": { "type": "boolean" },
|
|
"uuid": { "type": "string" },
|
|
"domain": { "type": "string" },
|
|
"changelogEntry": { "type": "object" },
|
|
"steps": { "type": "array", "items": { "$ref": "#/components/schemas/Step" } }
|
|
}
|
|
},
|
|
"Step": {
|
|
"type": "object",
|
|
"properties": {
|
|
"step": { "type": "string" },
|
|
"status": { "type": "string", "enum": ["running", "done", "error", "skipped", "warn"] },
|
|
"detail": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|