2026-02-12 15:46:57 -08:00
# Phoenix Deploy API
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
Gitea webhook receiver and deploy endpoint for Gitea → Phoenix / Proxmox deployment integration.
2026-02-12 15:46:57 -08:00
## Endpoints
| Method | Path | Description |
|--------|------|-------------|
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
| POST | /webhook/gitea | Receives Gitea push/tag/PR webhooks; executes deploys only when `PHOENIX_WEBHOOK_DEPLOY_ENABLED=1` |
| POST | /api/deploy | Deploy request (repo, branch, target); resolves a target from `deploy-targets.json` and runs its command |
| GET | /api/deploy-targets | Lists configured deploy targets and whether each has a health check |
2026-03-11 12:58:00 -07:00
| GET | /api/v1/infra/nodes | Cluster nodes (Proxmox; stub if PROXMOX_* unset) |
| GET | /api/v1/infra/storage | Storage pools (Proxmox; stub if unset) |
| GET | /api/v1/ve/vms | List VMs/CTs (optional `?node=` ) |
| GET | /api/v1/ve/vms/:node/:vmid/status | VM/CT status (`?type=lxc` for containers) |
| POST | /api/v1/ve/vms/:node/:vmid/start, stop, reboot | VM/CT lifecycle (set PHOENIX_VE_LIFECYCLE_ENABLED=1) |
| GET | /api/v1/health/metrics | Prometheus query proxy (`?query=<PromQL>` ) |
| GET | /api/v1/health/alerts | Active alerts (optional PROMETHEUS_ALERTS_URL) |
| GET | /api/v1/health/summary | Aggregated health for Portal |
2026-03-27 18:50:54 -07:00
| GET | /api/v1/public-sector/programs | Public-sector / eIDAS program manifest (JSON; **no API key ** ) |
2026-02-12 15:46:57 -08:00
| GET | /health | Health check |
2026-03-27 18:50:54 -07:00
All `/api/v1/*` routes except * * `GET /api/v1/public-sector/programs` ** accept optional partner API key when `PHOENIX_PARTNER_KEYS` is set (`X-API-Key` or `Authorization: Bearer <key>` ).
2026-03-11 12:58:00 -07:00
2026-02-12 15:46:57 -08:00
## Environment
Copy `.env.example` to `.env` and set `GITEA_TOKEN` (and optionally `PHOENIX_DEPLOY_SECRET` ).
| Variable | Default | Description |
|----------|---------|-------------|
| PORT | 4001 | Listen port |
| GITEA_URL | https://gitea.d-bis.org | Gitea instance URL |
| GITEA_TOKEN | | Token for commit status API |
| PHOENIX_DEPLOY_SECRET | | Optional secret for webhook/deploy auth |
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
| PHOENIX_WEBHOOK_DEPLOY_ENABLED | 0 | Set to 1 to allow `/webhook/gitea` to execute the default target on matching pushes |
| PROXMOX_HOST | proxmox-api.d-bis.org | Proxmox host (IP or hostname) for API Railing |
2026-03-11 12:58:00 -07:00
| PROXMOX_PORT | 8006 | Proxmox API port |
| PROXMOX_USER | root@pam | Proxmox API user |
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
| PROXMOX_TOKEN_NAME | | Proxmox API token name; bare token name preferred, full token id also accepted |
2026-03-11 12:58:00 -07:00
| PROXMOX_TOKEN_VALUE | | Proxmox API token secret |
| PROXMOX_TLS_VERIFY | 1 | Set to 0 to allow self-signed Proxmox certs |
| PHOENIX_VE_LIFECYCLE_ENABLED | 0 | Set to 1 to enable VM/CT start/stop/reboot |
| PROMETHEUS_URL | http://localhost:9090 | Prometheus base URL for Health API |
| PROMETHEUS_ALERTS_URL | (PROMETHEUS_URL)/api/v1/alerts | Optional; use Alertmanager URL for firing alerts |
| PHOENIX_WEBHOOK_URL | | Outbound webhook URL; POST deploy events with X-Phoenix-Signature |
| PHOENIX_WEBHOOK_SECRET | | Secret to sign webhook payloads (HMAC-SHA256) |
| PHOENIX_PARTNER_KEYS | | Comma-separated API keys for /api/v1/* (optional) |
2026-03-27 18:50:54 -07:00
| PUBLIC_SECTOR_MANIFEST_PATH | | Override JSON path for `/api/v1/public-sector/programs` |
| PHOENIX_REPO_ROOT | | Proxmox repo root; loads `config/public-sector-program-manifest.json` if present |
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
| DEPLOY_TARGETS_PATH | | Override deploy target file; default is `phoenix-deploy-api/deploy-targets.json` |
2026-03-27 18:50:54 -07:00
**Program manifest:** From a full repo checkout, the file is `config/public-sector-program-manifest.json` . `scripts/install-systemd.sh` copies it next to `server.js` on `/opt/phoenix-deploy-api` so the endpoint works without a full tree.
2026-02-12 15:46:57 -08:00
## Gitea Webhook Configuration
In Gitea: Repository → Settings → Webhooks → Add Webhook
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
- **URL:** `https://phoenix-api-host/webhook/gitea` (or your Phoenix API URL)
2026-02-12 15:46:57 -08:00
- **Content type:** application/json
- **Events:** Push events, Tag creation (and optionally Pull requests)
- **Secret:** Optional, set PHOENIX_DEPLOY_SECRET to match
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
Use webhook-triggered deploys only for repos that are not already deploying through Gitea Actions, unless you intentionally want both paths.
2026-02-12 15:46:57 -08:00
## Deploy API (Trigger from Gitea Actions)
```bash
curl -X POST "https://phoenix-api-host/api/deploy" \
-H "Authorization: Bearer $PHOENIX_DEPLOY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"repo":"d-bis/proxmox","branch":"main","sha":"abc123","target":"default"}'
```
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
The API returns `404` when no matching deploy target exists for `{repo, branch, target}` and `500` when the target command fails.
If a target defines `healthcheck` , the deploy is only marked successful after the post-deploy URL check passes.
## Deploy target configuration
Targets live in [`deploy-targets.json` ](deploy-targets.json ). Each entry maps a `{repo, branch, target}` tuple to a command array and working directory.
Example:
```json
{
"repo": "d-bis/proxmox",
"branch": "main",
"target": "default",
"cwd": "${PHOENIX_REPO_ROOT}",
"command": ["bash", "scripts/deployment/deploy-phoenix-deploy-api-to-dev-vm.sh", "--apply", "--start-ct"],
"required_env": ["PHOENIX_REPO_ROOT"]
}
```
Use this to promote different repos to different VMIDs or CTs by adding more entries.
Optional per-target health check:
```json
{
"healthcheck": {
"url": "http://192.168.11.59:4001/health",
"expect_status": 200,
"expect_body_includes": "phoenix-deploy-api",
"attempts": 8,
"delay_ms": 3000,
"timeout_ms": 10000
}
}
```
## Manual smoke trigger
From the repo root:
```bash
bash scripts/dev-vm/trigger-phoenix-deploy.sh
```
This calls `/api/deploy` directly using `PHOENIX_DEPLOY_URL` and `PHOENIX_DEPLOY_TOKEN` from root `.env` .
2026-02-12 15:46:57 -08:00
## Integration with Sankofa Phoenix
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts
Made-with: Cursor
2026-04-21 22:01:33 -07:00
This service is still standalone, but it now executes real target commands. If you later fold it into the Sankofa Phoenix API (VMID 8600), keep the same target-file pattern so repo-to-VM routing stays declarative.
2026-02-12 15:46:57 -08:00
2026-03-11 12:58:00 -07:00
## OpenAPI / Swagger
- **Spec:** [openapi.yaml ](openapi.yaml )
- **HTML doc:** [docs/index.html ](docs/index.html ) — static Swagger UI; open locally or serve from `phoenix-deploy-api/docs/` (loads `../openapi.yaml` ). To serve in-app, add `swagger-ui-express` and mount at e.g. `/api-docs` .
2026-02-12 15:46:57 -08:00
## Run
```bash
npm install
GITEA_TOKEN=xxx npm start
```