# proxbox-api developer guide

Developer guide — FastAPI orchestration, SDK boundaries, contribution workflow and the Docker E2E matrix.

| Field |Value |
| --- | --- |
| Canonical URL | https://emersonfelipesp.com/proxbox-api/developer |
| Showcase | https://emersonfelipesp.com/proxbox-api |
| GitHub | https://github.com/emersonfelipesp/proxbox-api |
| Releases | https://emersonfelipesp.com/proxbox-api/releases |
| Release snapshot synced | 2026-06-21T12:43:39.047Z |

## Intro

proxbox-api is the FastAPI service that bridges Proxmox VE and NetBox. It owns the sync workflow that the netbox-proxbox plugin triggers from inside NetBox and exposes REST + Server-Sent Events + WebSocket endpoints to stream live progress back.

This page covers the layered architecture, what proxbox-api takes as a dependency vs. proxies at runtime, the contribution workflow, and the multi-mode E2E matrix that exercises every transport before a release ships.

## Architecture

- ASGI entrypoint: uvicorn proxbox_api.main:app. The app is assembled by proxbox_api.app.factory.create_app() — initializes the SQLite database (sqlmodel + aiosqlite), builds the default NetBox session, and registers the generated Proxmox proxy routes.
- Layers: routes/ (FastAPI routers — auth, dcim, extras, netbox, proxbox, proxmox, sync, virtualization) → services/sync/ (workflow orchestration) → schemas/ + enum/ (Pydantic 2 validation at every I/O boundary) → proxmox_to_netbox/ (transformation) → session/ (NetBox + Proxmox client factories as FastAPI dependencies).
- Sync runs stream Server-Sent Events plus optional WebSocket progress. /full-update/stream drives the complete chain: devices → storage → VMs → disks → backups → snapshots → interfaces → IPs → backup routines → replications.
- Auth: bcrypt-hashed API key in the X-Proxbox-API-Key header with brute-force lockout (proxbox_api/auth.py). Credentials at rest are Fernet-encrypted (PROXBOX_ENCRYPTION_KEY required in production).
- Persistence: SQLModel + aiosqlite for endpoint and key storage; no PostgreSQL dependency on the proxbox-api side.
- Concurrency knobs: PROXBOX_NETBOX_TIMEOUT (120s), PROXBOX_NETBOX_MAX_CONCURRENT (default 1, intentionally low), PROXBOX_VM_SYNC_MAX_CONCURRENCY, PROXBOX_NETBOX_GET_CACHE_TTL (60s GET cache, 0 disables), PROXBOX_RATE_LIMIT (60 req/min/IP via SlowAPI).
- Embedded admin UI: nextjs-ui/ — a Next.js frontend used to administer endpoints, separate build target.
- Generated proxy routes: proxbox_api/generated/ holds 646 typed Proxmox endpoints crawled from the Proxmox API Viewer. Do not edit by hand — regenerate from proxbox-api/proxmox_codegen/.

## Integrations

| Target |Protocol |Library |Notes |
| --- | --- | --- | --- |
| netbox-proxbox (NetBox plugin) | HTTP REST + SSE + WebSocket (inbound) | consumer — auth via X-Proxbox-API-Key | Every Full Update click in the plugin lands here as a request to /full-update/stream. |
| NetBox REST API (write target) | HTTP | netbox-sdk==0.0.8.post1 | Async aiohttp client sessions in proxbox_api/session/ + helpers in proxbox_api/netbox_rest.py. Cached GET layer (60s TTL) shared across the workflow. |
| Proxmox VE (read source) | HTTP | proxmox-sdk==0.0.3.post1 | Read-only — the workflow never POST/PUT/DELETEs back into Proxmox. Mock backend (MockBackend) used for fast tests. |
| Next.js admin UI | embedded | nextjs-ui/ (separate build) | Manages bcrypt API keys, encrypted credentials and endpoint records via the same FastAPI surface. |

## Contributing

Development install:

```shell
uv sync --extra test --group dev
```

Pre-PR checks:

- lint: `uv run ruff check .`
- format: `uv run ruff format --check .`
- syntax compile: `uv run python -m compileall proxbox_api tests`
- type check (focused): `uv run ty check proxbox_api/types proxbox_api/utils/retry.py proxbox_api/schemas/sync.py`
- unit + integration: `uv run pytest tests`
- Next.js admin UI: `cd nextjs-ui && npm run lint && npm run build`

Code style:

- Linter: ruff (select E4/E7/E9/F/I/ANN201/D103/W/C90, max complexity 10).
- Formatter: ruff format.
- Type checker: ty.
- PRs must include a passing run of all the checks above; the CI core job runs pytest tests/ -v --ignore=tests/e2e on every push and PR.

Issues: https://github.com/emersonfelipesp/proxbox-api/issues

## CI

The backend CI is layered: fast Python checks, Docker image startup checks, generated E2E matrix setup, NetBox image fallback handling, and full NetBox-backed sync validation.

The publish workflow validates TestPyPI first, promotes PyPI release candidates only after candidate checks, then publishes Docker images and runs post-publish E2E against the released artifacts.

| Workflow |Trigger |Purpose |
| --- | --- | --- |
| ci.yml | push + pull_request + release + manual | Runs core pytest checks, Python 3.11 floor checks, free-threaded smoke, Docker bind smoke, and the NetBox E2E matrix. |
| publish-testpypi.yml | version tags + GitHub releases + manual | Publishes TestPyPI, PyPI rc/final, Docker images, and validates exact installs plus pre/post-publish E2E. |
| docker-hub-publish.yml | workflow_call + manual | Builds and publishes raw, nginx, and granian Docker image variants. |
| release-docker-verify.yml | release + manual | Pulls published Docker tags and verifies each container variant starts. |
| nightly-schema-refresh.yml | schedule + manual | Refreshes generated Proxmox schemas and opens a PR when artifacts change. |

- E2E jobs wait up to 20 minutes for NetBox migrations/search indexing and require /api/status/ before token setup.
- The E2E job pulls public NetBox images first and downloads the source-built artifact only when registry pull fails.
- Docker-backed Proxmox E2E uses mock_http and rotates proxmox-sdk service tags (pve, pbs, pdm) per matrix cell; the in-process MockBackend pass uses mock_backend and runs once on the main × pve cell.
- The public MkDocs source of truth is docs/development/e2e-proxmox-service-matrix.md (pt-BR mirror under docs/pt-BR/).

## End-to-end tests

Framework: pytest + pytest-asyncio + httpx.AsyncClient. Two marker modes — mock_backend (in-process, no HTTP) and mock_http (against a running proxmox-sdk container).

The fast loop runs entirely in-process against MockBackend; no Docker, no network. The full loop fans out across a three-axis GitHub Actions matrix — transport × NetBox version × proxmox_service — pulling a dedicated proxmox-sdk mock per cell.

Each proxmox_service value (pve, pbs, pdm) pulls the matching tag — emersonfelipesp/proxmox-sdk:latest-pve, :latest-pbs, :latest-pdm — so PVE clusters, Proxmox Backup Server, and Proxmox Datacenter Manager surfaces are exercised in parallel.

PVE-only specs (VM sync, device sync, backup sync) are gated behind the requires_pve_schema session fixture and auto-skip on pbs/pdm cells; the test_proxmox_mock_health.py smoke runs against /health on every cell so a broken mock image fails fast.

The release workflow is staged: normal and post tags publish to TestPyPI, PyPI release candidates use vX.Y.ZrcN, and the final PyPI package plus Docker images publish only after package reinstall validation and E2E gates pass.

Commands:

- all unit + integration: `uv run pytest tests`
- E2E (mock backend, fast): `uv run pytest tests/e2e -m mock_backend`
- E2E (mock HTTP, PVE service): `PROXMOX_SERVICE=pve docker compose up -d && uv run pytest tests/e2e -m mock_http`
- E2E (PBS service, schema-gated tests skipped): `PROXMOX_SERVICE=pbs docker compose up -d && uv run pytest tests/e2e -m mock_http`
- E2E (PDM service, schema-gated tests skipped): `PROXMOX_SERVICE=pdm docker compose up -d && uv run pytest tests/e2e -m mock_http`

Coverage:

- Spec files: tests/e2e/conftest.py, test_vm_sync.py, test_devices_sync.py, test_backups_sync.py, test_demo_auth.py, test_proxmox_mock_health.py.
- Markers: @pytest.mark.mock_backend (in-process MockBackend) and @pytest.mark.mock_http (proxmox-sdk Docker container on ports 8006/8007). The requires_pve_schema session fixture auto-skips PVE-only tests on pbs/pdm cells.
- Auth helpers in proxbox_api/e2e/ are the only place Playwright is used in the backend; the proxmox_sdk_mock fixture switches container tags based on the PROXMOX_SERVICE env var.
- CI: ci.yml runs the core test job (pytest excluding tests/e2e) plus a 7 × 3 × 3 (transport × NetBox × service) E2E Docker matrix with fail-fast disabled. The mock_backend pass is gated to main + pve so it runs exactly once.
- Release gate: publish-testpypi.yml validates TestPyPI installs first, then PyPI rc/final installs, Docker image publish, and post-publish E2E across the same service matrix.

CI workflow: .github/workflows/ci.yml (https://github.com/emersonfelipesp/proxbox-api/blob/main/.github/workflows/ci.yml)

## Links

| Label |URL |
| --- | --- |
| repo | https://github.com/emersonfelipesp/proxbox-api |
| docs | https://emersonfelipesp.com/proxbox-api/docs/ |
| plugin | https://github.com/emersonfelipesp/netbox-proxbox |
| netbox-sdk | https://github.com/emersonfelipesp/netbox-sdk |
| proxmox-sdk | https://github.com/emersonfelipesp/proxmox-sdk |
| issues | https://github.com/emersonfelipesp/proxbox-api/issues |