zPodFactory Core Engine
Complete the following steps to set up your development environment:
-
Install Docker and Docker Compose
-
Install uv:
curl -LsSf https://astral.sh/uv/install.sh | shuv will manage the Python toolchain for you — no separate pyenv step is required. Each subproject pins its own
requires-python, anduv syncwill download the matching interpreter automatically. -
Create each subproject virtualenv. In
/zpodapi,/zpodengine,/zpodcli, and/zpodsdk, run:uv sync
Each subproject is released independently and keeps its own
uv.lock. -
Configure Environment Variables. (See
/zpodapi/src/zpodapi/lib/settings.pyfile for all available settings) In the root directory, run:cp .env.default .env vim .env
-
For Visual Studios Code, do the following:
a. Configure the zpodcore.code-workspace. In
/run:cp zpodcore.code-workspace.default zpodcore.code-workspace
Make sure that the port variable in launch.configurations.connect.port matches the port stored in the
ZPODAPI_DEBUG_HOSTPORTenvironment variable. -
Build the Docker containers. In the root directory, run:
docker compose build
-
Start the environment. In the root directory, run:
just zpodcore-start
-
Verify that zpodapi is working by opening a browser and going to
http://localhost:[8000 or ZPODAPI_HOSTPORT]andhttp://localhost:[8000 or ZPODAPI_HOSTPORT]/docs -
Create Deployments
just zpodengine-deploy-all
The monorepo is split into independently-released subprojects, each with its own
pyproject.toml and uv.lock:
| Subproject | Role | Python | Released |
|---|---|---|---|
zpodsdk/ |
Generated API client | >=3.8.1 |
PyPI |
zpodcli/ |
zcli Typer CLI (depends on zpodsdk) |
>=3.10 |
PyPI |
zpodapi/ |
FastAPI service | ==3.12.1 |
Docker |
zpodengine/ |
Prefect flows | ==3.12.1 |
Docker |
zpodsdk_builder/ |
Regenerates zpodsdk from OpenAPI spec |
>=3.10,<3.13 |
Docker (internal tool) |
zpodcommon/ |
Shared source tree — no pyproject.toml, consumed via PYTHONPATH |
n/a | — |
There is no uv workspace: each subproject locks and releases independently. The
root pyproject.toml only holds ruff config and the [tool.bumpversion] table used
by just zpod-release.
just zpod-release <version> uses bump-my-version
(invoked via uvx, no install needed) to update the version string across all
subproject pyproject.toml + __init__.py files in a single commit + tag, then
runs uv build / uv publish for zpodsdk and zpodcli. The old sed dance that
toggled zpodcli's zpodsdk dep between a path dependency and a pinned version is
gone — [tool.uv.sources] handles the dev path override, and uv build ignores
those sources so published wheels pin zpodsdk==<version> from PyPI automatically.
The monorepo moved from Poetry to uv in a single branch. A few things worth knowing if you are resuming a branch older than the migration or troubleshooting an unexpected pin:
- Local
uv syncforzpodapi/zpodenginerequires bothgccandlibpq-devon the host because those projects pinpsycopg2(source-only). psycopg2'ssetup.pyshells out toccand includes libpq headers. On Debian/Ubuntu:sudo apt install gcc libpq-dev. If you only want the lockfile without building, runuv lockinstead ofuv sync— resolution alone doesn't compile anything. Full installs still happen inside the Docker builder stages, which install bothlibpq-devandgccbeforeuv sync. zpodsdk_buildernow pinsclick<8.2. This was masked bypoetry.lock(which hadclick 8.1.8).openapi-python-client 0.20.0viatyper <0.13is incompatible withclick 8.2+(TypeError: Secondary flag is not valid for non-boolean flag). Bumpopenapi-python-clientitself if/when dropping this pin.- Dev path dep on
zpodsdkis now inzpodcli/pyproject.tomlunder[tool.uv.sources], not in[project.dependencies]. Do not re-add apath=entry to the main dependency list — it would be embedded in the published wheel. - Build backend is
hatchlingfor the two publishable projects (zpodsdk,zpodcli).zpodapi,zpodengine, andzpodsdk_builderare all[tool.uv] package = false— they have no build target because their source is either bind-mounted in dev orCOPY'd into the Docker image in prod. - Dockerfiles no longer set
POETRY_VENV/POETRY_VERSION. They now pulluvfromghcr.io/astral-sh/uv:0.10and write to/opt/venv(kept at that path viaUV_PROJECT_ENVIRONMENT=/opt/venvfor operator familiarity). uv.lockreplacespoetry.lock. Commit it. It is cross-platform and deterministic. If you see apoetry.lockreappear in a PR, it is stale.