Files
idea.llm.gitea.repo.docker.…/README.md
Clint Masden 5119c94b37 Fix Traefik route insertion placing routes in middlewares section
The route insertion logic split on `  services:` which placed new
router blocks after the middlewares section instead of in the routers
section. Now splits on `  middlewares:` first to insert routers in
the correct position. Also generates proper YAML format with HTTP
redirect routers for each new route.

Fixed live custom.yml: moved racker + timer routes to routers section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:29:55 -06:00

234 lines
8.7 KiB
Markdown

# Docker Deployment Manager
Unified REST API + Electron desktop app for managing Docker deployments across two servers via Gitea + Coolify. The API is the single source of truth — the UI, CLI, and LLM agents all use the same HTTP endpoints.
## Architecture
```
idea.llm.gitea.repo.docker.deployment/
├── api/ # Express API server (:3100)
│ ├── server.js # Entry point, Scalar docs at /reference
│ ├── routes/
│ │ ├── coolify.js # /api/coolify/* — Coolify app management
│ │ ├── projects.js # /api/projects/* — local scanning & comparison
│ │ ├── servers.js # /api/servers/* — server CRUD, containers, logs
│ │ └── docker.js # /api/docker/* — build, deploy, pull files
│ ├── lib/
│ │ ├── config.js # Loads Coolify + deployment configs
│ │ ├── coolify-client.js # coolifyFetch() — Coolify API wrapper
│ │ └── ssh.js # SSHService class (exec + SFTP)
│ └── openapi.json # OpenAPI 3.1 spec (24 endpoints)
├── app/
│ ├── main/ # Electron main process (legacy IPC)
│ ├── renderer/ # React UI (Vite + TanStack Query)
│ │ └── src/
│ │ ├── lib/api.js # All API calls via HTTP fetch
│ │ ├── hooks/ # React Query hooks
│ │ └── components/
│ │ ├── coolify/ # Coolify dashboard + deploy dialog
│ │ ├── projects/ # Project management
│ │ ├── servers/ # Server settings
│ │ └── dashboard/ # Overview
│ └── .env # SSH credentials (not committed)
├── cli/ # CLI tool for project scaffolding
├── deployment-config.json # Server list + project root config
└── package.json
```
## Quick Start
```bash
# Install dependencies
npm install
cd app/renderer && npm install && cd ../..
# Run everything (API + Vite + Electron)
npm run dev
# Or without Electron (browser only at http://localhost:5173)
npm run dev:no-electron
# API only
npm run api:dev
```
- **API server**: http://localhost:3100
- **Scalar API docs**: http://localhost:3100/reference
- **OpenAPI spec**: http://localhost:3100/openapi.json
- **Vite dev server**: http://localhost:5173 (proxies `/api/*` to :3100)
## API Endpoints (24 total)
All endpoints return JSON. The Vite dev server proxies `/api/*` to the API server, so the renderer uses relative paths.
### Projects
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/projects` | Scan local projects (finds Dockerfiles, coolify.json, etc.) |
| POST | `/api/projects/compare` | Compare local vs remote files (docker-compose, .env, data/) |
| POST | `/api/projects/init` | Initialize a project with deployment config via CLI |
### Servers
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/servers` | List configured deployment servers |
| POST | `/api/servers` | Add or update a server |
| DELETE | `/api/servers/:id` | Delete a server |
| GET | `/api/servers/:id/scan` | Scan remote ~/containers for deployed projects |
| GET | `/api/servers/:id/containers` | List running Docker containers (docker ps) |
| GET | `/api/servers/:id/logs` | Get container logs (query: containerName, remotePath, lines) |
### Docker Operations
| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/docker/build` | Build tar via build-image-tar.ps1 |
| POST | `/api/docker/deploy` | Upload files + docker load + docker compose up |
| POST | `/api/docker/pull` | Pull files/directories from remote server via SFTP |
| POST | `/api/docker/vscode-diff` | Download remote file and open VS Code diff |
### Coolify
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/coolify/apps` | List all Coolify apps (enriched with HOST_PORT) |
| GET | `/api/coolify/apps/find/:name` | Find app by name |
| POST | `/api/coolify/apps` | Create new Coolify application |
| PATCH | `/api/coolify/apps/:uuid` | Update existing app |
| DELETE | `/api/coolify/apps/:uuid` | Delete app |
| GET | `/api/coolify/apps/:uuid/envs` | List env vars |
| POST | `/api/coolify/apps/:uuid/envs` | Set env var |
| POST | `/api/coolify/apps/:uuid/deploy` | Trigger deployment |
| GET | `/api/coolify/servers` | List Coolify servers |
| GET | `/api/coolify/next-port` | Get next available HOST_PORT |
| POST | `/api/coolify/routes` | Add Traefik route via SSH |
| POST | `/api/coolify/drift` | Check drift between coolify.json and live state |
| POST | `/api/coolify/upsert` | Full pipeline: config → create/update → env → route → deploy |
| GET | `/api/coolify/config?path=...` | Read coolify.json from a project |
### System
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/health` | Health check |
| GET | `/openapi.json` | OpenAPI 3.1 spec |
| GET | `/reference` | Scalar interactive API docs |
## Configuration
### Coolify Config (`gitea.repo.management/config.json`)
Shared with the gitea.repo.management project. Contains Coolify API credentials, server UUIDs, SSH config:
```json
{
"coolify": {
"apiUrl": "http://192.168.69.4:2010",
"apiToken": "<bearer-token>",
"serverUuid": "c88okoc4g4css0c4ooo04ko4",
"projectUuid": "bcso4cocokswgo804gogoswo",
"privateKeyUuid": "j0w08woc8s8c0sgok8ccow4w",
"sshHost": "192.168.69.4",
"sshUser": "clint",
"sshPassword": "<password>",
"traefikPath": "/home/clint/containers/coolify/data/proxy/dynamic/custom.yml",
"targetIp": "192.168.69.5"
}
}
```
### Deployment Config (`deployment-config.json`)
Local to this project. Stores server list and project root:
```json
{
"servers": [
{ "id": "1771305558920", "name": "Repo Server", "host": "192.168.69.5", "username": "clint", "useSudo": true }
],
"projectsRoot": "C:\\.bucket\\repos.gitea"
}
```
### SSH Credentials (`app/.env`)
```
SSH_USERNAME=clint
SSH_PASSWORD=<password>
```
## Coolify Upsert Pipeline
The `POST /api/coolify/upsert` endpoint runs the full deploy pipeline:
1. **config** — Read coolify.json from the project
2. **server** — Resolve server name to UUID/IP via Coolify API
3. **check** — Find existing app by name
4. **validate** — Compare coolify.json vs live state, report diffs
5. **sync** — Create or update the Coolify application
6. **env** — Set HOST_PORT environment variable
7. **route** — Add Traefik route (remote) or set FQDN (local)
8. **changelog** — Write coolify.changelog.json to repo
9. **deploy** — Trigger Coolify deployment
## Docker Deploy Pipeline (Legacy/Direct)
The `POST /api/docker/deploy` endpoint handles tar-based deployment:
1. Connect to server via SSH
2. Create remote directory (mkdir -p)
3. Upload tar + docker-compose.yml + .env + additional files via SFTP
4. Run `docker load -i <name>.tar`
5. Run `docker compose down && docker compose up -d`
6. Poll health check (10 attempts, 2s apart)
## Infrastructure
| Server | IP | Role |
|--------|-----|------|
| box-stableapps | 192.168.69.4 | Coolify host, Gitea, Traefik |
| box-repoapps | 192.168.69.5 | Deployed apps |
### Port Allocation
| Port | App | Status |
|------|-----|--------|
| 2001 | Audio Events | Deployed |
| 2002 | Audio Capsule | Deployed |
| 2003 | Audio Sphere | Deployed |
| 2004 | Every Noise at Once | Deployed |
| 2005 | Learn X In Y | Deployed |
| 2006 | Actual Budget Report | Deployed |
| 2007 | dotrepo-timer | Pending |
| 2008 | dotrepo-travel | Pending |
| 2009 | dotrepo-racker | Deployed |
## LLM / Agent Usage
This API is designed to be called by LLMs and agents. Key endpoints for automation:
```bash
# List all Coolify apps with their ports and status
curl http://localhost:3100/api/coolify/apps
# Deploy a project from its coolify.json
curl -X POST http://localhost:3100/api/coolify/upsert \
-H "Content-Type: application/json" \
-d '{"projectPath": "C:/.bucket/repos.gitea/dotrepo.racker"}'
# Scan local projects
curl http://localhost:3100/api/projects
# Deploy via tar+SSH to a server
curl -X POST http://localhost:3100/api/docker/deploy \
-H "Content-Type: application/json" \
-d '{"projectPath": "C:/.bucket/repos.gitea/myapp", "serverId": "1771305558920", "remotePath": "~/containers/myapp"}'
# Get container logs
curl "http://localhost:3100/api/servers/1771305558920/logs?remotePath=~/containers/myapp&lines=50"
```
**Always use this API** to access/change Coolify and Gitea deployment state. Do not call the Coolify API directly — this API wraps it with enrichment (HOST_PORT), safety (drift detection, changelog), and routing (Traefik management).