π οΈ Local Development SetupΒΆ
This guide walks through getting ADL running on your local machine for development. The stack runs entirely in Docker so the only hard requirements on your host are Docker, Docker Compose, Git, and Make.
PrerequisitesΒΆ
Docker 20.10 or later
Docker Compose v2 or later (
docker compose, notdocker-compose)make
Verify your versions:
docker --version
docker compose version
make --version
How the dev stack worksΒΆ
ADL uses two compose files:
File |
Purpose |
|---|---|
|
Base service definitions β used in production and as the foundation for dev |
|
Dev overrides β switches to the |
The Dockerfile has three build stages:
Stage |
Used by |
Description |
|---|---|---|
|
Both |
Installs all Python dependencies into |
|
|
Copies the built venv and app code into the image |
|
|
Copies only the venv β source code is bind-mounted from your host, enabling live reload |
The Makefile wraps common commands for both stacks. Use make <target> for
production and make dev-<target> for development.
1. Clone the RepositoryΒΆ
git clone https://github.com/wmo-raf/adl.git
cd adl
2. Create the Docker NetworkΒΆ
ADLβs services communicate over a dedicated external Docker network. Create it once:
docker network create adl
3. Configure Environment VariablesΒΆ
Copy the sample environment file and edit it:
cp .env.sample .env
The minimum values you must set:
Variable |
Description |
Example |
|---|---|---|
|
Django secret key β any long random string |
|
|
PostgreSQL username |
|
|
PostgreSQL password |
|
|
PostgreSQL database name |
|
|
Your host user ID |
|
|
Your host group ID |
|
Find your UID and GID:
id -u # UID
id -g # GID
Setting these ensures files written by the container (static files, media, backups) are owned by your host user rather than root.
4. Build the Dev ImageΒΆ
make dev-build
This builds the dev target from the Dockerfile. The builder stage installs
all Python dependencies into /adl/venv. The dev stage copies only the venv
β your local ./adl directory is bind-mounted into the container at runtime
so code changes are reflected immediately without rebuilding.
If you hit a BuildKit error such as:
failed to solve: adl:latest: pull access denied
Disable BuildKit and retry:
DOCKER_BUILDKIT=0 make dev-build
5. Start the Dev StackΒΆ
make dev-up
This starts the full stack using both compose files
(docker-compose.yml + docker-compose.dev.yml). The following services
start:
Service |
Description |
|---|---|
|
TimescaleDB (PostgreSQL + PostGIS + TimescaleDB) |
|
Redis β Celery broker and Django cache |
|
Django development server ( |
|
Celery worker with |
|
Celery beat scheduler |
|
Nginx β serves static files and proxies to the app |
|
pg_tileserv β vector tiles from PostGIS |
On first startup the adl container automatically runs migrations and
collects static files. The services wait for the database and Redis to be
ready before starting (WAIT_TIMEOUT defaults to 120 seconds).
Check that everything is up:
make dev-ps
6. Create a SuperuserΒΆ
make dev-createsuperuser
7. Access the ApplicationΒΆ
Open http://localhost:8000 in your browser.
The Django development server is exposed directly on port 8000 in the dev
stack (bypassing Nginx), which makes it easier to see Django debug pages and
error tracebacks.
The Wagtail admin is at /adl-admin/ by default (configurable via
ADL_ADMIN_URL_PATH in .env).
8. Daily Development WorkflowΒΆ
Viewing logsΒΆ
make dev-logs # all services
make dev-app-logs # Django server only
make dev-worker-logs # Celery worker only
make dev-beat-logs # Celery beat only
Opening a shellΒΆ
make dev-shell # bash in the app container
make dev-worker-shell # bash in the celery worker container
Running management commandsΒΆ
make dev-migrate # python manage.py migrate
make dev-makemigrations # python manage.py makemigrations
Or run any arbitrary Django command:
docker compose -f docker-compose.yml -f docker-compose.dev.yml \
exec adl adl <command>
Code changes and auto-reloadΒΆ
Django server β reloads automatically when any Python file under
./adl/changes (standardrunserverbehaviour).Celery worker β reloads automatically via
watchfileswhen any Python file under/adl/app/src/changes. No manual restart needed.Celery beat β does not auto-reload; restart it manually if you change task schedules:
make dev-restart
9. Stopping and Cleaning UpΒΆ
make dev-stop # stop containers, preserve volumes
make dev-down # stop and remove containers
To also wipe the database (use with care):
docker compose -f docker-compose.yml -f docker-compose.dev.yml down -v
10. Running the Production Stack LocallyΒΆ
If you need to test the production build locally (gunicorn, no bind-mount):
make build
make up
make createsuperuser
make logs
The production stack uses only docker-compose.yml and the prod build
target. The app is accessible via Nginx on port 80 (or ADL_WEB_PROXY_PORT).
Project LayoutΒΆ
The key directories you will work in:
adl/
βββ src/adl/
β βββ config/ # Django settings, URLs, WSGI/ASGI
β βββ core/ # Core models, plugin registry, QC, admin
β βββ monitoring/ # Task and activity monitoring
β βββ api/ # REST API
β βββ viewer/ # Data viewer
βββ requirements.txt # Python dependencies
βββ pyproject.toml # Package metadata
Makefile ReferenceΒΆ
Command |
Description |
|---|---|
|
Build the dev image |
|
Start the dev stack |
|
Stop and remove dev containers |
|
Stop dev containers |
|
Restart dev containers |
|
List running dev containers |
|
Tail logs for all dev services |
|
Tail Django server logs |
|
Tail Celery worker logs |
|
Tail Celery beat logs |
|
Open bash in the app container |
|
Open bash in the worker container |
|
Run database migrations |
|
Create new migrations |
|
Create an admin user |
|
Build the production image |
|
Start the production stack |
|
Stop the production stack |
|
Tail production logs |
|
Open bash in the production app container |
|
Run migrations in production |
TroubleshootingΒΆ
Services not starting β waiting for database
The adl container waits for adl_db:5432 before starting. If the database
takes longer than WAIT_TIMEOUT (default 120 seconds), increase it in .env:
WAIT_TIMEOUT=300
Static files returning 404
Run collectstatic manually:
docker compose -f docker-compose.yml -f docker-compose.dev.yml \
exec adl adl collectstatic --noinput
Permission errors on mounted volumes
Confirm UID and GID in .env match your host user, then rebuild:
echo "UID=$(id -u)" >> .env
echo "GID=$(id -g)" >> .env
make dev-build
make dev-up
Port 8000 already in use
Another process is using port 8000. Find and stop it, or change the exposed
port in docker-compose.dev.yml.
Developing pluginsΒΆ
This guide covers developing the ADL core. If you want to develop a plugin (a data source adapter), see Plugin Development Setup β plugins have their own isolated docker-compose environment and a separate workflow for integration testing against the full ADL stack.