Manual setup¶
Running the backend, database, Redis, Celery and frontend directly on your machine, without Docker. Useful if you want faster iteration on backend code than a bind-mounted container gives you, or if you're setting up on a host where Docker isn't available.
Prerequisites¶
- Python 3.12 or later:
backend/pyproject.tomldeclaresrequires-python = ">=3.12", andbackend/.python-versionpins3.12. - uv: the backend is managed with uv, not pip or a manually
created virtualenv.
uv syncreadsbackend/pyproject.tomlandbackend/uv.lockand creates a.venv/for you; every backend command in this guide runs viauv run <cmd>, which resolves that venv automatically. Install it once, system-wide:
django.db.backends.postgresql in
backend/crm/settings.py); Row-Level Security depends on it.
- Redis: used as the Celery broker and result backend.
- Node.js and pnpm: for the SvelteKit frontend in frontend/.
Backend¶
From backend/:
This creates .venv/ and installs everything listed in pyproject.toml's dependencies
(Django, DRF, Celery, djangorestframework-simplejwt, weasyprint, etc.) at the versions locked
in uv.lock.
Copy the example environment file and adjust it for your local database and Redis:
backend/crm/settings.py loads this file via python-dotenv (load_dotenv() at import time), so
anything you put in .env is picked up the next time you run a management command. At minimum,
review DBNAME, DBUSER, DBPASSWORD, DBHOST, DBPORT against the database role you create in
the next section.
Once .env points at a reachable database, apply migrations:
And run the dev server:
By default this serves on http://127.0.0.1:8000.
Database¶
The Django DATABASES setting (backend/crm/settings.py) reads DBNAME, DBUSER,
DBPASSWORD, DBHOST and DBPORT from the environment, defaulting to a local postgres
superuser connection if they're unset. Don't leave it on that default: the role Django connects
as must not be a PostgreSQL superuser, or Row-Level Security is bypassed for every query that
role makes, regardless of what the RLS policies say.
Create a dedicated, non-superuser role and database, for example:
CREATE DATABASE crm_db;
CREATE USER crm_user WITH PASSWORD 'crm_password';
GRANT ALL PRIVILEGES ON DATABASE crm_db TO crm_user;
\connect crm_db;
GRANT ALL ON SCHEMA public TO crm_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO crm_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO crm_user;
Then point .env at it (DBNAME=crm_db, DBUSER=crm_user, DBPASSWORD=crm_password,
DBHOST=localhost, DBPORT=5432) and run uv run python manage.py migrate.
You can confirm the role is configured correctly with the RLS management command:
Redis and Celery¶
Redis needs to be reachable at the URL in CELERY_BROKER_URL / CELERY_RESULT_BACKEND (both
default to redis://localhost:6379/0 in .env.example). Install it locally through your package
manager, or run the same image the Docker setup uses:
With Redis reachable, start a Celery worker from backend/:
backend/crm/celery.py also defines a set of periodic tasks (recurring-invoice generation,
overdue-invoice and expired-estimate checks, stale-opportunity and goal-milestone checks, SLA
breach scanning, notification and refresh-token cleanup) on cron-style schedules. To run those on
schedule you also need Celery beat, in a separate terminal:
Neither process is required for the API itself to respond to requests. They only matter for background and scheduled work.
Frontend¶
From frontend/:
Copy the example environment file:
At minimum, PUBLIC_DJANGO_API_URL should point at your backend (http://localhost:8000 if
you're following the ports in this guide). Then start the dev server:
This serves the SvelteKit app on http://localhost:5173 (vite dev under the hood, per the
dev script in frontend/package.json).
Running all three¶
A full local stack is four long-running processes across (at least) three terminals, all started from the state above:
# Terminal 1: from backend/
uv run python manage.py runserver
# Terminal 2: from backend/
uv run celery -A crm worker --loglevel=INFO
# Terminal 3: from frontend/
pnpm run dev
Redis and PostgreSQL need to already be running before any of these start (either installed
locally or run as standalone containers, as shown above). Add a fourth terminal for
uv run celery -A crm beat --loglevel=INFO from backend/ if you need scheduled tasks to fire.
Once all of this is up, see First sign-in for how to get an authenticated session, and Demo data and packs for loading sample data.