A modern, open-source CRM platform built with Django REST Framework and SvelteKit.
https://github.com/user-attachments/assets/f384f25e-ab52-4069-afaf-f8e2f1f3f0e7
BottleCRM is a full-featured Customer Relationship Management system designed for startups and small businesses. It combines a powerful Django REST API backend with a modern SvelteKit frontend, featuring multi-tenant architecture with PostgreSQL Row-Level Security (RLS) for enterprise-grade data isolation.
Try it free: bottlecrm.io
The backend uses uv for Python dependency management — it reads pyproject.toml, installs from uv.lock, and creates the virtual environment for you. uv is much faster than pip and gives reproducible installs out of the box.
# Clone the repository
git clone https://github.com/MicroPyramid/Django-CRM.git
cd Django-CRM/backend
# Install uv (one time, system-wide)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or on macOS via Homebrew: brew install uv
# Install Python (matches the version in .python-version) and all deps into .venv/
uv sync
# Set up environment variables (see env.md for details)
cp .env.example .env
# Edit .env with your database and other settings
# Run migrations
uv run python manage.py migrate
# Create a superuser
uv run python manage.py createsuperuser
# Start the development server
uv run python manage.py runserver
uv run <cmd> resolves binaries from .venv/bin/ automatically — no need to source .venv/bin/activate. If you prefer the activate-then-run flow, that still works:
source .venv/bin/activate
python manage.py runserver # equivalent to `uv run python manage.py runserver`
Common dev commands (from backend/):
uv run pytest # run tests
uv run python manage.py makemigrations # create migrations
uv run celery -A crm worker --loglevel=INFO # background worker
uv add <package> # add a dependency (updates pyproject.toml + uv.lock)
uv add --group dev <package> # add a dev-only dependency
uv lock --upgrade # refresh the lockfile
# In a new terminal, from the project root
cd frontend
# Install dependencies
pnpm install
# Start the development server
pnpm run dev
# In a new terminal
cd backend
uv run celery -A crm worker --loglevel=INFO
Run the full stack (backend, frontend, PostgreSQL, Redis, Celery) with a single command:
# Start all services (first run will build images)
# An admin user (admin@localhost / admin) is created automatically
docker compose up --build
# (Optional) Load sample data
docker compose exec backend python manage.py seed_data --email [email protected]
Once running:
docker compose up # start all services (code changes auto-reload)
docker compose down # stop all services
docker compose down -v # stop and delete all data (full reset)
docker compose exec backend python manage.py migrate
docker compose exec backend python -m pytest
docker compose exec backend python manage.py manage_rls --status
The default env vars live in .env.docker (committed). To override locally without touching git:
.env.docker to .env.docker.localenv_file in docker-compose.yml to point to .env.docker.localDjango-CRM/
├── backend/ # Django REST API
│ ├── accounts/ # Accounts module
│ ├── cases/ # Cases module
│ ├── common/ # Shared models, utilities, RLS
│ ├── contacts/ # Contacts module
│ ├── invoices/ # Invoices module
│ ├── leads/ # Leads module
│ ├── opportunity/ # Opportunities module
│ ├── tasks/ # Tasks module
│ └── crm/ # Django project settings
├── frontend/ # SvelteKit frontend
│ ├── src/
│ │ ├── lib/ # Components, stores, utilities
│ │ └── routes/ # SvelteKit routes
│ │ ├── (app)/ # Authenticated app routes
│ │ └── (no-layout)/ # Auth pages (login, etc.)
│ ├── static/ # Static assets
│ └── Dockerfile # Frontend dev container
├── docker/ # Docker support files
│ ├── backend/
│ │ └── entrypoint.sh # DB wait + migrate + runserver
│ └── postgres/
│ └── init-rls-user.sql # Creates non-superuser for RLS
├── Dockerfile # Backend / Celery image
├── docker-compose.yml # Full-stack dev environment
└── .env.docker # Docker env vars (dev defaults)
BottleCRM uses PostgreSQL Row-Level Security (RLS) to ensure complete data isolation between organizations. Every database query is automatically filtered by organization context, providing enterprise-grade security.
# Check RLS status
python manage.py manage_rls --status
# Verify RLS user configuration
python manage.py manage_rls --verify-user
# Test data isolation
python manage.py manage_rls --test
cd backend
# Run all tests with coverage
pytest
# Run tests without coverage (faster)
pytest --no-cov -x
# Run a specific module's tests
pytest accounts/tests/
pytest leads/tests/test_leads_kanban.py
# Run tests matching a keyword
pytest -k "test_login"
# View coverage report in browser
open htmlcov/index.html
# Format code
black . && isort .
# Check dependencies
pipdeptree
pip-check -H
For local development you can mint a JWT for any user without going through Google sign-in. The command refuses to run unless DEBUG=True, and there's no web endpoint — it's only reachable through manage.py:
cd backend
# Mint tokens for an existing user (no org bound — same as the OAuth flow)
uv run python manage.py devlogin [email protected]
# Bind to a specific org so you skip the orgswitch step on first load
uv run python manage.py devlogin [email protected] --org "MicroPyramid"
# Create the user on the fly (random password) if they don't exist yet
uv run python manage.py devlogin [email protected] --create
The command prints the access/refresh tokens plus a ready-to-paste localStorage.setItem(...) snippet — drop it into the browser devtools console on http://localhost:5173 and reload to be signed in.
cd frontend
# Type checking
pnpm run check
# Linting
pnpm run lint
# Formatting
pnpm run format
The API follows RESTful conventions:
GET/POST /api/<module>/ # List/Create
GET/PUT/DELETE /api/<module>/<pk>/ # Detail/Update/Delete
GET/POST /api/<module>/comment/<pk>/ # Comments
GET/POST /api/<module>/attachment/<pk>/ # Attachments
Interactive API documentation is available at /swagger-ui/ when running the backend.
We welcome contributions! Please see our contributing guidelines for details.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
This project exists thanks to all the people who contributed.