Getting Started — anza-elt
This guide gets the anza-elt project running on Windows or macOS, including Dev Containers, PostgreSQL, pgAdmin 4, and Dagster.
Table of contents
1. Prerequisites
-
Git
-
VS Code or Cursor with the Dev Containers extension
-
Docker (via Docker Desktop; on Windows you’ll use WSL 2)
2. Windows: WSL 2 and Docker
The project runs inside a Dev Container. On Windows you need WSL 2 and Docker Desktop using the WSL 2 backend.
Install WSL 2
- Open PowerShell as Administrator and run:
wsl --install
This installs WSL 2 and a default Linux distro (e.g. Ubuntu).
-
Restart your machine if prompted.
-
(Optional) Set WSL 2 as the default:
wsl --set-default-version 2
- Confirm WSL is running and on version 2:
wsl --list --verbose
wsl --status
Install Docker Desktop and enable WSL 2
- Download Docker Desktop for Windows:
https://www.docker.com/products/docker-desktop
-
Run the installer and leave “Use WSL 2 instead of Hyper-V” (or “Install required components for WSL 2”) checked.
-
After installation, open Docker Desktop → Settings (gear icon).
-
Go to General and ensure “Use the WSL 2 based engine” is enabled.
-
In Resources → WSL Integration, enable integration for your WSL distro (e.g. Ubuntu).
-
Click Apply & Restart.
-
Confirm Docker works in WSL (open Ubuntu from the Start menu):
docker --version
docker run hello-world
Once this works, you can open the repo in Cursor/VS Code and use “Reopen in Container” as in §4.
3. macOS: Docker
- Download Docker Desktop for Mac:
https://www.docker.com/products/docker-desktop
-
Install and open Docker Desktop. Allow the privileged helper when prompted.
-
Confirm Docker works:
docker --version
docker run hello-world
- For Apple Silicon (M1/M2/M3): the project’s Dev Container uses
arm64by default (see.devcontainer/devcontainer.json). No extra steps needed.
4. Open the project in a Dev Container
- Clone the repo (if you haven’t already):
git clone <repo-url> anza-elt
cd anza-elt
- Open the folder in Cursor or VS Code:
code anza-elt
# or
cursor anza-elt
-
When prompted, choose “Reopen in Container” (or use Command Palette → “Dev Containers: Reopen in Container”).
-
Wait for the container to build and start. The first time can take several minutes (Python, Node, GDAL, etc.).
-
The Dev Container mounts (see
.devcontainer/devcontainer.json): -
~/data/→_data(e.g. election/census data) -
~/Downloads/igs→igs(optional; comment out if you don’t use it)
Create these on the host if you use them:
-
Windows (WSL): e.g.
mkdir -p ~/data ~/Downloads/igs -
macOS:
mkdir -p ~/data ~/Downloads/igs
5. Environment and data paths
- Copy the env template and edit as needed:
cp env.template .env
-
In
.env, the important variables for Postgres and Dagster are: -
PG_HOST,PG_PORT,PG_USER,PG_PWD,PG_DB -
When running inside the Dev Container, use
PG_HOST=host.docker.internalso the container can reach Postgres on your host (Windows or macOS). -
Create any directories your
.envreferences (e.g._data/elec,_data/census,_data/igs) or adjust paths in.envto match your layout. -
For elec tests, the README asks for fixture data under
ingestion/elec/tests/fixtures/elec/(e.g. fromg22.zip). Add those if you run elec ingestion/tests.
6. PostgreSQL and PostGIS
The pipeline expects a PostgreSQL database with PostGIS (and optionally postgis_topology). Run this on your host (or in a separate Postgres container), not inside the Dev Container.
Option A: PostgreSQL on the host (Windows WSL or macOS)
- Windows (WSL): Install Postgres and PostGIS inside your WSL distro (e.g. Ubuntu):
sudo apt update && sudo apt install -y postgresql postgresql-contrib postgis
sudo service postgresql start
- macOS: Install with Homebrew:
brew install postgresql@16 postgis
brew services start postgresql@16
Or use Postgres.app and add PostGIS.
Create the database and extensions using the project’s SQL script:
# From the project root (host or WSL), with psql in PATH:
psql -U postgres -f ingestion/precincts/postgis_setup/precinct_topology_db.sql
If your setup uses a different locale (e.g. WSL without en_US.UTF-8), use the second CREATE DATABASE block in that file (the one without LC_COLLATE/LC_CTYPE/ICU_LOCALE).
Option B: PostgreSQL in Docker (host)
Run Postgres + PostGIS on the host so the Dev Container can reach it via host.docker.internal:
docker run -d --name anza-postgres \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=precinct_topology \
-p 5432:5432 \
postgis/postgis:16-3.4
Then create extensions and schema (connect with psql or pgAdmin and run the contents of ingestion/precincts/postgis_setup/precinct_topology_db.sql as needed).
Use PG_HOST=host.docker.internal and PG_PORT=5432 in .env inside the Dev Container.
7. pgAdmin 4
pgAdmin 4 is a GUI for managing PostgreSQL. Use it to inspect the precinct_topology database and run SQL.
Install pgAdmin 4
- Windows:
https://www.pgadmin.org/download/pgadmin-4-windows/
- macOS:
https://www.pgadmin.org/download/pgadmin-4-macos/
Or: brew install --cask pgadmin4
Connect to your database
- Open pgAdmin 4.
- Right‑click Servers → Register → Server.
- General tab: set a name (e.g.
anza-elt). - Connection tab:
- Host:
localhost(orhost.docker.internalif you’re inside a container and want to reach host Postgres). - Port:
5432(or yourPG_PORT). - Maintenance database:
postgres. - Username:
postgres - Password: your
postgres
- Host:
- Save.
You can then browse the precinct_topology database, run precinct_topology_db.sql or parts of it, and inspect tables/schemas (e.g. postgis, anza_geom, staging schemas).
8. Dagster
Dagster runs the pipeline (ingestion assets, dbt, etc.) and serves the Dagster UI. The Dev Container is configured so Dagster runs inside the container.
Configuration
- DAGSTER_HOME is set in the Dev Container to
/root/.dagster_home(see.devcontainer/devcontainer.json). - Dagster config is in
.devcontainer/dagster.yaml(e.g. SQLite storage, no run retries).
Environment variables
Ensure the same Postgres variables are available where Dagster runs (Dev Container). The container should load .env or you can set:
PG_HOST,PG_DB,PG_USER,PG_PWD,PG_PORT- Optionally:
PG_GEOM_SCHEMA,PG_STAGING_SCHEMA,CENSUS_ROOT, etc., as inenv.template.
Run Dagster (inside the Dev Container)
- Reopen the project in the Dev Container (§4).
- In a terminal inside the container:
Or, if you use the legacy CLI:
uv sync dg devdagster dev - The Dagster UI is forwarded to port 3000. Open: http://localhost:3000
- In the UI you can launch runs, view assets, and inspect the dbt and precinct ingestion jobs.
If the Dagster UI doesn’t open
- Confirm port 3000 is forwarded (Dev Container “Ports” panel or
.devcontainer/devcontainer.json). - Ensure Postgres is reachable from the container (
PG_HOST=host.docker.internalwhen Postgres is on the host).
9. Project directory reference
| Directory | Description |
|---|---|
.devcontainer/ |
Dev Container definition: Dockerfile (Python, Node, GDAL, mapshaper, Dagster env), devcontainer.json (mounts, ports, extensions), and dagster.yaml used as DAGSTER_HOME config. |
dagster_project/ |
Dagster code: definitions.py (asset and resource wiring), resources.py (e.g. Postgres connection), precincts/assets.py (precinct/PostGIS and mapshaper assets), and defs/ for dbt components (e.g. dbt_postgres, dbt_duckdb). |
ingestion/ |
Data ingestion: elec/ (election file validation and load; pipeline, ingest, duckdb, data models, tests) and precincts/ (preprocessing, PostGIS/topology ingest, tests; postgis_setup/ has SQL for the precinct_topology DB and PostGIS; postgis_topo_ingest/ for topology-focused ingest). |
transform/ |
dbt project: models/ (elec and precincts), macros/, seeds/, snapshots/, analyses/, tests/. Builds with dbt run / Dagster dbt assets; profiles.yml uses env vars (e.g. PG_*) for the Postgres target. |
__ingestion_local_writes/ |
Default local output directory for ingestion writes (referenced in env.template as INGESTION_LOCAL_WRITE_DIR). |
.venv/ |
Python virtual environment (uv/poetry); used for uv run and make targets. |
.tmp_dagster_home_*/ |
Temporary Dagster home directories (e.g. from local runs); can be ignored or removed. |
_data/ |
Intended mount for data (e.g. elec, census, igs); created on host and mounted via Dev Container (see .devcontainer/devcontainer.json). |
igs/ |
Optional mount for IGS data; same as above. |
Quick checklist
- WSL 2 + Docker Desktop (Windows) or Docker Desktop (macOS)
- Cursor/VS Code + Dev Containers extension
- Repo cloned,
.envcreated fromenv.template,PG_HOST=host.docker.internalwhen using host Postgres - PostgreSQL + PostGIS installed or running (Docker/host),
precinct_topologyDB created (and extensions/schema fromprecinct_topology_db.sql) - pgAdmin 4 installed and connected to
precinct_topology - Project reopened in Dev Container;
uv syncanddg dev(ordagster dev); Dagster UI at http://localhost:3000
For more on elec ingestion, fixtures, and precincts workflow, see the main README.md.