Quick reference for running the various local environments. For the first-time setup, see installation.md.
Common dev commands are wrapped in the repo-root Makefile. Run make help to see the full categorized command reference. The canonical-task-runner decision is in ADR-0014.
Make sure dev/dev.env exists with the right values (copy from dev/dev.env.example and fill in placeholders).
make docker-up # bring up the full dev stack (detached, with build)
make docker-watch # run compose watch (live host->container sync)
make docker-logs # stream the dev stack logs
make docker-down # stop the dev stackEndpoints:
- Frontend: http://localhost:3000 (Next.js dev server)
- Backend API: http://localhost:8000/api/
- Django admin: http://localhost:8000/admin/ (bootstrap an account with
make local-superuser) - Healthcheck: http://localhost:8000/api/healthcheck
Test that the backend is wired up:
curl http://localhost:8000/api/healthcheckA non-existent API endpoint returns a structured 404:
{"error": {"code": "not_found", "message": "The requested API endpoint does not exist."}}For one-shot commands inside running containers (migrations, package installs, etc.), see the Useful Docker commands section in devops.md.
Useful for debugging stack-specific issues. Requires Node.js 24, Python 3.13, and Poetry installed locally; Postgres still runs in Docker so you don't need a local install.
Start the database container, then install host dependencies:
make db-up # postgres only, in Docker
make local-install # install frontend (npm) + backend (poetry) depsRun backend in one terminal:
make local-run-backend # stops the docker django service, then runs Django on hostRun frontend in another terminal:
make local-run-frontend # stops the docker next service, then runs Next.js on hostFrontend on http://localhost:3000, backend on http://localhost:8000. The host-process targets auto-stop the matching Docker service first to avoid port conflicts.
Common DB targets (against the running dev stack):
make db-migrate # apply Django migrations
make db-makemigrations # create migration files
make db-reset # truncate all app data (keeps schema + migrations); prompts for 'yes'
make db-reset-hard # drop the volume and recreate the DB container; prompts for 'yes'
make db-grant-test-db-perms # grant the test runner CREATEDB permsmake local-test # backend + frontend
make local-test-backend # Django tests via Poetry on host
make local-test-frontend # vitest on hostmake docker-shell-backend # shell into the django container
make docker-shell-frontend # shell into the next container
make docker-shell-db # psql shell into the pgdb containerMirrors the deployed-stage three-container shape (production builds, no hot reload). Useful for verifying production-shape behavior before pushing; catches issues that only surface with production builds (collectstatic failures, env-var differences, etc.).
The Makefile doesn't currently wrap stage targets (the deployed shape is owned by the incubator repo and stage tooling is still settling). Run directly:
docker compose -f docker-compose.stage.yml upRequires stage/stage.env (copy from stage/stage.env.example). Stage and dev env files are not interchangeable; they carry different secrets, debug flags, and database names. See devops.md.
Lint normally runs automatically via pre-commit on git commit (see devops.md → Linting). To run the full suite manually:
make lint # delegates to pre-commit run --all-files
make install-hooks # install the pre-commit git hook (one-time)The full suite covers backend (ruff lint + ruff format + mypy + bandit) and frontend (eslint + stylelint + knip + tsc + prettier). To run individual tools (e.g. just ruff while iterating on Python), invoke them directly:
# backend
cd backend
poetry run ruff check .
poetry run ruff format .
poetry run mypy ctj_api backend
poetry run bandit -r ctj_api backend -c pyproject.toml
# frontend
cd frontend
npm run lint
npm run lint:css
npm run lint:dead
npm run lint:types
npm run formatruff does the linting + formatting + import sorting in one tool, replacing the legacy black + flake8 + isort chain. See backend.md → Local dev - lint and frontend-lint-guide.md for tool-specific config notes.
make local-clean # clear local build/cache artifacts (.next, node_modules, __pycache__)
make local-kill-ports # kill listeners on dev ports if a process is stuckReachable at https://stage.civictechjobs.org/. Built and deployed automatically on push to main. See deployment-infra.md for the deployment shape.