Manual Setup

June 17, 2026 · View on GitHub

The backend is a uv-managed Python workspace (see backend/README.md). On macOS most of this is automated by setup/mac.sh; this document covers the manual steps and platform-specific notes.

Local machine, in docker

Note: Docker Compose and the VS Code dev container are currently unsupported and may be out of date — native setup (below) is the recommended and supported path. The docker steps are kept here for reference.

For local development with docker compose, copy the repo-root .env.example to the two files compose reads (see docker-compose.yml's env_file entries):

  • API: backend/packages/wps-api/src/app/.env.docker
  • Web: web/.env (sample at web/apps/wps-web/.env.example)
docker compose build

Local machine, running MacOS

For native (non-docker) local development, copy the repo-root .env.example to .env (at the repo root — python-decouple discovers it by walking up from the package directory). Then change the database hosts from the docker-compose service name to localhost:

POSTGRES_WRITE_HOST=localhost
POSTGRES_READ_HOST=localhost

NOTE: matching the exact version of postgresql/postgis with production on your local machine is not necessary — production runs in containers (CrunchyDB) and CI matches it there. Locally we use Homebrew's postgresql@17 + postgis.

Artifactory npm repo config

We currently publish the cffdrs_ts package to our internal artifactory instance. You need to configure credentials so npm can pull the cffdrs_ts package from this repo. To add the credentials to your global ~/.npmrc run:

npm config set @psu:registry https://artifacts.developer.gov.bc.ca/artifactory/api/npm/pe1e-psu-npm-local/
npm config set //artifacts.developer.gov.bc.ca/artifactory/api/npm/pe1e-psu-npm-local/:_authToken {artifactory_token}

Alternatively, you can create a project specific .npmrc at the root of the web directory and add the following: @psu:registry=https://artifacts.developer.gov.bc.ca/artifactory/api/npm/pe1e-psu-npm-local/ //artifacts.developer.gov.bc.ca/artifactory/api/npm/pe1e-psu-npm-local/:_authToken={artifactory_token}

The artifactory token is currently stored in Vault as gha_artifactory_token.

Java

Some of the unit tests use jnius to compare output against RedAPP. setup/mac.sh installs openjdk via brew; point JAVA_HOME at it (the default macOS Java is likely to cause segmentation errors when running the unit tests):

export JAVA_HOME="$(brew --prefix openjdk)/libexec/openjdk.jdk/Contents/Home"

Ensure the CLASSPATH environment variable in your .env points to the jar files in backend/packages/wps-api/libs/ (REDapp_Lib.jar, WTime.jar, hss-java.jar), or the RedAPP unit tests will fail.

Gdal

The python gdal binding is pinned in backend/packages/*/pyproject.toml and is built from source by uv sync against the system libgdal, which must be at least the pinned version. Install GDAL from Homebrew:

brew install gdal

We deliberately don't brew pin gdal: pinning the formula doesn't pin its dependencies (poppler, proj, geos, …), so a later brew upgrade can still move a dependency soname and break gdal. Letting homebrew keep gdal consistent with its deps avoids that; if gdal drifts ahead of the pinned version, uv sync fails loudly — that's the signal to bump.

Keep the ghcr.io/osgeo/gdal base-image tag (openshift/wps-api-base/docker/Dockerfile) and the three gdal== pyproject pins in step. To bump: update the base-image tag + the three pins, uv lock, then uv sync (run brew upgrade gdal first if your local gdal is behind).

wkhtmltopdf

wkhtmltopdf (used by pdfkit to generate HFI calculator PDFs) is discontinued and the Homebrew cask has been removed. setup/mac.sh installs it from the wkhtmltopdf packaging releases. Note that the production image uses the Linux 0.12.6.1-2 .deb, but that release has no macOS build — the newest macOS package is the older 0.12.6-2 x86_64 ("cocoa") .pkg, so on Apple Silicon it needs Rosetta 2:

softwareupdate --install-rosetta --agree-to-license
curl -L -o /tmp/wkhtmltox.pkg \
  https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-2/wkhtmltox-0.12.6-2.macos-cocoa.pkg
sudo installer -pkg /tmp/wkhtmltox.pkg -target /

PDF generation is not required for most backend work; the package is unsigned and the project is archived, so this is best-effort.

eccodes

The weather-model tests need the ecCodes library:

brew install eccodes
Python (pyenv) and uv

Match the latest version of python in our production environment (as of writing, 3.12.3):

brew install pyenv
pyenv install 3.12.3
pyenv global 3.12.3
brew install uv
Install project python requirements

Dependencies are installed for the whole workspace with uv sync — there is no per-package install step, and gdal/wps_shared are handled by the lockfile (no manual pip install needed).

psycopg2 builds from source, so pg_config must be on PATH. postgresql@17 is keg-only, so expose its bin dir first:

export PATH="$(brew --prefix postgresql@17)/bin:$PATH"
cd backend
uv sync --all-extras
Troubleshooting
psycopg2

If you get errors about pg_config not being found when building psycopg2, it means pg_config isn't on PATH — see the export above ($(brew --prefix postgresql@17)/bin).

GDAL

If the python gdal build complains about header files (likely if you've installed gdal manually rather than via brew), help it find them before running uv sync:

export CPLUS_INCLUDE_PATH=/usr/include/gdal
export C_INCLUDE_PATH=/usr/include/gdal

If gdal isn't building on a mac with errors like "no member named 'signbit' in the global namespace", then:

  • ensure you've applied the most recent OS updates
  • ensure XCode is updated
  • wipe your existing virtual environment (backend/.venv) and re-run uv sync

Local machine, running Linux

Ubuntu

The production base image (openshift/wps-api-base/docker/Dockerfile) is the authoritative list of system dependencies. On a comparable Ubuntu host:

sudo apt install python3 python3-pip python3-dev python-is-python3
# geospatial / build dependencies
sudo apt install libgdal-dev libproj-dev libgeos-dev libsqlite3-dev libxml2-dev cmake build-essential
# required by cffdrs
sudo apt install libudunits2-dev
# postgres client headers (for psycopg2)
sudo apt install libpq-dev
# the jdk (for running tests against RedAPP)
sudo apt install default-jdk

Install uv (https://docs.astral.sh/uv/) and run uv sync --all-extras from backend/. The python gdal package must match the system libgdal version.

Fedora

Install system dependencies:

sudo dnf install unixODBC-devel

Executing program

See the Makefile for docker examples and backend/README.md for running the API natively.

Install dependencies (required before running the program for the first time):

cd backend && uv sync --all-extras

Run the full stack in docker:

make docker-run        # docker compose up

Run the API natively (from backend/packages/wps-api):

uv run --package wps-api python -m app.main

To shell into the running docker containers: make docker-shell-api / make docker-shell-web.

Running the database locally

In Docker

make docker-db         # docker compose up db

Runs a local Postgres/PostGIS container and creates the wps database.

Natively

We use Homebrew postgresql@17 + postgis locally. (This became viable once the project's GDAL pin moved to current homebrew-core — brew postgis links the same libgdal the venv uses, so there is no longer a conflict. The older Postgres.app workaround is no longer required.)

brew install postgresql@17 postgis
brew services start postgresql@17

Then create the database, extension and users (these match the .env defaults):

psql -d postgres -c "create database wps;"
psql -d wps -c "create extension postgis;"
psql -d wps -c "
CREATE USER wps;
CREATE USER wpsread;
ALTER USER wps WITH LOGIN;
ALTER USER wpsread WITH LOGIN;
ALTER USER wps WITH SUPERUSER;
ALTER USER wps WITH PASSWORD 'wps';
grant connect on database wps to wpsread; grant usage on schema public to wpsread; grant select on all tables in schema public to wpsread;
"

\dx in psql -d wps should list postgis. Then run the migrations:

cd backend/packages/wps-api && uv run --package wps-api alembic upgrade head

The CI pipeline enforces migrations and tests with uv run pytest (see .github/workflows/integration.yml); run cd backend && uv run pytest locally to match.

Postgres.app (alternative)

If you'd rather not use Homebrew postgres, Postgres.app bundles Postgres + PostGIS. Create the database/users with the same SQL as above. Note that Postgres.app bundles its own older gdal-config; if you add its bin to PATH, append it rather than prepend, so it doesn't shadow Homebrew's gdal during uv sync.

ModuleNotFoundError: No module named 'pkg_resources'

cd backend && uv pip install --upgrade setuptools

New Workstation Setup

Required Software

The following is a list of required software applications and packages. Some of these can be installed automatically using the setup/mac.sh script.

  • VS Code (technically there are other options, but this is arguably the best)
    • using the "Python: Select Interpreter" command within VS Code, select backend/.venv/bin/python
  • Git CLI
  • GitHub CLI
  • Openshift CLI
  • Docker and Lima
  • Brew (for Mac)

The extensions listed here are shown exactly as they appear in the VS Code Extensions marketplace.

  • Copy without formatting
  • Dev Containers
  • Docker
  • ESLint
  • GitLens - Git supercharged
  • Jupyter
  • Jupyter Cell Tags
  • Jupyter Keymap
  • Jupyter Notebook Renderers
  • Jupyter Slide Show
  • Makefile Tools
  • Markdown All in One
  • markdownlint
  • Markdown Preview Enhanced
  • Markdown+Math
  • Math to Image
  • Prettier - Code formatter
  • Pylance
  • Python
  • Rainbow Brackets
  • Remote - SSH
  • Ruff
  • SonarLint
  • VS Code Counter