Skip to content

mow backend

PR Quality Gate
Build Images
Release Please
Deploy: Stage
Deploy: Prod

Backend for Meals-on-Wheels Charlottesville operations: customers, routes, orders, reports, and portals (admin + volunteer).
Built with Python 3.13 / Django 5.2 LTS / DRF, packaged via Docker Compose, and shipped to AWS with GitHub Actions.

Project links:

• Main GitHub: https://github.com/thecodejim
• Backend repo: https://github.com/thecodejim/mow-backend
• Project website: https://mow.codejim.com
• Developer docs: https://developer.mow.codejim.com
• OpenAPI/Swagger: https://api.developer.mow.codejim.com


TL;DR — Get Started (macOS)

Windows guide is coming soon. For the full macOS guide, see macOS Development Environment Setup.

  1. Install prerequisites

  2. macOS 15+ with admin rights

  3. Xcode CLT: xcode-select --install
  4. Docker Desktop (includes Compose v2): https://docs.docker.com/desktop/setup/install/mac-install/

  5. Clone & enter the repo

git clone https://github.com/thecodejim/mow-backend.git
cd mow-backend
  1. Create your .env from the dev example
make env   # copies env.dev.example → .env and opens it

At minimum, confirm Postgres vars and set local secrets if you want (safe defaults exist for dev). See Environment files below for details.

  1. Build & run the dev stack
make build
make up
  1. (Optional) Create a superuser
make dj-createsuperuser
  1. Open local endpoints

  2. http://localhost (Caddy root)

  3. http://admin.localhost (Admin portal)
  4. http://portal.localhost (Volunteer portal)
  5. http://developer.localhost (Docs, if running)
  6. http://api.developer.localhost (Swagger UI, if enabled)
  7. http://grafana.localhost / http://prometheus.localhost
  8. http://localhost:5050 (pgAdmin)
  9. http://localhost:8025 (Mailpit)

Tip (macOS only): make open-all will open the common endpoints in Safari.


Why this project (and what it fixes)

This codebase replaces an older system that had hard limitations:

  • Data model now supports multiple pets and multiple diets per customer (no more 1-pet/1-diet constraint).
  • Immutable historical reporting preserves past facts even when current customer data changes.
  • Configurable domains and environment-driven settings (no hard-coded hostnames).
  • Safer defaults: CORS/CSRF locked down, non-root containers, security headers, no “allow all origins” in prod.

Architecture at a glance

  • App: Python 3.13, Django 5.2 LTS, DRF, JWT (simplejwt), Gunicorn
  • Data: PostgreSQL 17, Redis 8
  • Web/TLS: Caddy (static, TLS, CSP/HSTS)
  • Packaging: Docker + Compose (base/dev/prod overlays)
  • Docs: OpenAPI JSON in /api, MkDocs service for developer site
  • Observability: OpenTelemetry Collector → Prometheus, Loki, Tempo, Grafana
  • CI/CD: GitHub Actions → multi-arch images → ECR; Release-Please for versioning and changelogs; stage/prod deploy workflows
  • Project Mgmt: GitHub Issues + Projects, PR quality gates (lint, tests, commit checks)

For the full stack inventory, see the Master Technology Inventory in the project repo.


Developer workflow

Common Make targets

Run make help to see all targets with descriptions.

# Build & run (dev)
make build           # build dev containers
make up              # start dev stack (foreground)
make up-detach       # start in background
make logs            # follow logs
make down            # stop
make clean           # stop + delete volumes (⚠ deletes dev data)

# Django helpers
make dj-test         # run tests (spins up postgres/redis if needed)
make dj-coverage     # coverage report (console)
make dj-coverage-html# writes ./django/src/htmlcov/index.html
make dj-migrate      # run migrations
make dj-createsuperuser
make dj-openapi      # (re)generate OpenAPI → ./api/

# Linting & formatting (Ruff)
make dj-lint
make dj-format
make dj-lint-diff    # CI-style diff check

# Env file management
make env             # dev .env (copies env.dev.example)
make prod-env        # prod .env (copies env.prod.example)

# Secrets (generated inside containers)
make dj-secret       # Django SECRET_KEY (50 chars)
make token-32        # 32-byte hex token
make token-64        # 64-byte hex token

# Utilities
make pg-conninfo     # psql \conninfo inside postgres
make pg-tables       # list tables
make open-all        # open common local endpoints (macOS)

Environment files

  • Dev: make env to copy env.dev.example.env and edit.
  • Stage/Prod: make prod-env to copy env.prod.example.env and edit with real hostnames and secrets.

Use Make targets to generate secrets inside containers:

make dj-secret   # SECRET_KEY
make token-32    # e.g. HEALTH_CHECK_TOKEN
make token-64    # e.g. OTEL_WRITE_TOKEN

Key sections to review for stage/prod:

  • ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS
  • DOMAIN_NAME, ADMIN_DOMAIN, PORTAL_DOMAIN
  • Database credentials, TLS email, docs settings, OpenAPI path/URLs

For the complete guide, see Environment Files for Dev, Stage, and Prod.


Documentation

Generate/refresh local OpenAPI files:

make dj-openapi     # writes ./api/openapi-admin.json and openapi-volunteer.json

CI/CD & releases

  • PR Quality Gate (.github/workflows/pr-quality-gate.yml): Ruff lint, tests, commit message checks (Conventional Commits).
  • Build ImagesECR (build-images.yml), multi-arch (amd64/arm64).
  • Release Please (release-please.yml): automated GitHub Releases + CHANGELOG from Conventional Commits.
  • Deploy: deploy-stage.yml (pre-release) and deploy-prod.yml (release). OIDC to AWS; no long-lived keys.

Contributing

We use GitHub Issues and GitHub Projects for planning. PRs must pass the quality gate.

Conventional Commits are required. Examples:

feat(reports): add immutable history for meal changes
fix(auth): prevent CSRF double submit on login
chore(ci): speed up ruff cache

Local checklist before opening a PR:

make dj-lint
make dj-format
make dj-test

Security

  • Non-root containers, CSP + HSTS via Caddy, strict CORS/CSRF in prod.
  • No hard-coded domains or “allow all origins” in prod.
  • Secrets are injected via .env in dev and SSM Parameter Store in stage/prod.

To report a vulnerability, please open a private security advisory or contact the maintainers.


Local endpoints (dev)

  • Root: http://localhost
  • Admin portal: http://admin.localhost
  • Volunteer portal: http://portal.localhost
  • Docs: http://developer.localhost
  • API docs: http://api.developer.localhost
  • Grafana: http://grafana.localhost
  • Prometheus: http://prometheus.localhost
  • pgAdmin: http://localhost:5050
  • Mailpit (dev email): http://localhost:8025
  • Django admin (via admin portal): http://admin.localhost/dj-admin

If using Caddy’s local CA on macOS, you can trust it with:

bash make caddy-mac-trust


Troubleshooting

  • Docker says volumes/ports in usemake prune-orphans or make clean (⚠ deletes dev data).
  • Health check 403 → use the external token: make dj-test-health-external.
  • Static files missingmake dj-collectstatic.
  • Docs not rebuilding → ensure DOCS_BUILD_TOKEN is set and mkdocs service is running, or trigger: make mk-build.

License

TBD — see LICENSE (or open an issue if missing).


Acknowledgements

This project is a modern rewrite addressing long-standing data model, reporting, configurability, and security gaps found in earlier systems. Thank you to all community contributors and partners who informed this effort.


Happy hacking! If anything in this README seems off, please open an issue or PR.


Note: This file is the root README.md for the mow-backend GitHub repository. The links below are for navigating the mkdocs developer site.

< Backend — Overview

Next: Backend — Changelog >