Docker

The repository ships with a production-style docker-compose.yml that brings up everything you need: Postgres, Redis, the Django backend, a Celery worker, and the SvelteKit frontend.

Minimum requirements

  • CPU: 2 vCPU (4 for production)
  • RAM: 2 GB (4 GB recommended)
  • Disk: 10 GB
  • OS: Anything that runs Docker — Linux, macOS, Windows with WSL2

Topology

┌────────────┐   ┌────────────┐   ┌─────────┐
│  frontend  │ → │  backend   │ → │   db    │
│  (sveltekit│   │  (django)  │   │ (psql)  │
│   :5173)   │   │   :8000    │   └─────────┘
└────────────┘   └────────────┘        │
                       │               │
                       ↓               │
                 ┌─────────┐           │
                 │  redis  │ ← worker ─┘
                 └─────────┘   (celery)

The frontend talks to the backend over HTTP. The backend uses Redis as the Celery broker and result store. Both backend and worker connect to Postgres through a non-superuser role so row-level security is enforced.

Running it

git clone https://github.com/MicroPyramid/Django-CRM.git
cd Django-CRM
cp .env.docker.example .env.docker          # set secrets here
docker compose up --build -d

docker compose exec backend python manage.py migrate
docker compose exec backend python manage.py seed_data    # optional

The frontend is now at http://localhost:5173, the API at http://localhost:8000/api/.

Production deployment

For production, run the stack behind a reverse proxy (Caddy, nginx, Traefik) that terminates TLS, and put the backend in DEBUG=False mode.

Key changes from the dev compose file:

  • Pin image tags rather than building from source.
  • Mount /app/media and the Postgres data dir on persistent volumes.
  • Set ALLOWED_HOSTS and CORS_ALLOWED_ORIGINS to your real domain.
  • Rotate DJANGO_SECRET_KEY and JWT_SIGNING_KEY to fresh values.
  • Run python manage.py manage_rls --status to confirm RLS policies are present.

Backups

There are two things to back up:

  1. The Postgres databasepg_dump --format=custom is enough. Take it nightly and offsite-replicate it.
  2. Uploaded media — anything under the backend's media/ directory (attachments on cases, contact avatars, etc).

Restore is a vanilla pg_restore plus copying the media directory back.