emerson@netdevops:~/proxbox-api$ ./describe.sh proxbox-api
proxbox-api developer guide
Developer guide — FastAPI orchestration, SDK boundaries, contribution workflow and the Docker E2E matrix.
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.
›intro
emerson@netdevops:~/proxbox-api/developer$ cat README.md | head
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
emerson@netdevops:~/proxbox-api/developer$ tree -L 2 src/
- ├─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
emerson@netdevops:~/proxbox-api/developer$ ./describe-integrations
| › target | › protocol | › library |
|---|---|---|
| netbox-proxbox (NetBox plugin) | HTTP REST + SSE + WebSocket (inbound) | consumer — auth via X-Proxbox-API-Key |
| NetBox REST API (write target) | HTTP | netbox-sdk==0.0.8.post1 |
| Proxmox VE (read source) | HTTP | proxmox-sdk==0.0.3.post1 |
| Next.js admin UI | embedded | nextjs-ui/ (separate build) |
- › netbox-proxbox (NetBox plugin): Every Full Update click in the plugin lands here as a request to /full-update/stream.
- › NetBox REST API (write target): 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): Read-only — the workflow never POST/PUT/DELETEs back into Proxmox. Mock backend (MockBackend) used for fast tests.
- › Next.js admin UI: Manages bcrypt API keys, encrypted credentials and endpoint records via the same FastAPI surface.
›contributing
emerson@netdevops:~/proxbox-api/developer$ ./contributing --help
# dev install
# pre-PR checks
› lint
shelluv run ruff check .
› format
shelluv run ruff format --check .
› syntax compile
shelluv run python -m compileall proxbox_api tests
› type check (focused)
shelluv run ty check proxbox_api/types proxbox_api/utils/retry.py proxbox_api/schemas/sync.py
› unit + integration
shelluv run pytest tests
› Next.js admin UI
shellcd 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.
# issue tracker https://github.com/emersonfelipesp/proxbox-api/issues
›ci
emerson@netdevops:~/proxbox-api/developer$ gh workflow list
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.
# workflows
| › 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. |
# notes
- ├─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/).
›e2e
emerson@netdevops:~/proxbox-api/developer$ ./run-e2e --report
› 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
shelluv run pytest tests
› E2E (mock backend, fast)
shelluv run pytest tests/e2e -m mock_backend
› E2E (mock HTTP, PVE service)
shellPROXMOX_SERVICE=pve docker compose up -d && uv run pytest tests/e2e -m mock_http
› E2E (PBS service, schema-gated tests skipped)
shellPROXMOX_SERVICE=pbs docker compose up -d && uv run pytest tests/e2e -m mock_http
› E2E (PDM service, schema-gated tests skipped)
shellPROXMOX_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
›links
emerson@netdevops:~/proxbox-api/developer$ links
- 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