Open Source CRM for Startups — Django REST + SvelteKit · Self-hosted · Multi-tenant · Free forever
BottleCRM
A modern, open-source CRM platform built with Django REST Framework and SvelteKit.
https://github.com/user-attachments/assets/f384f25e-ab52-4069-afaf-f8e2f1f3f0e7
Overview
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
Features
Core CRM Modules
- Leads - Track and manage sales leads through your pipeline
- Accounts - Manage company/organization records
- Contacts - Store and organize contact information
- Opportunities - Track deals and sales opportunities
- Cases - Customer support case management
- Tasks - Task management with calendar and Kanban board views
- Invoices - Create and manage invoices
Platform Features
- Multi-Tenant Architecture - PostgreSQL RLS for secure data isolation between organizations
- JWT Authentication - Secure token-based authentication
- Team Management - Organize users into teams with role-based access
- Activity Tracking - Comprehensive audit logs and activity history
- Comments & Attachments - Collaborate with comments and file attachments on any record
- Tags - Flexible tagging system for organizing records
- Email Integration - AWS SES integration for transactional emails
- Background Tasks - Celery + Redis for async task processing
- AI Agents (MCP) - Built-in Model Context Protocol server (
mcpserver/) lets Claude, Cursor, Codex, Gemini and any MCP client search, create and update records via a personal access token — acting as you, with your role and permissions. Seemcp_server/README.md.
Tech Stack
Backend
- Django 5.x with Django REST Framework
- PostgreSQL with Row-Level Security (RLS)
- Redis for caching and Celery broker
- Celery for background task processing
- JWT for authentication
- AWS S3 for file storage
- AWS SES for email delivery
Frontend
- SvelteKit 2.x with Svelte 5 (runes)
- TailwindCSS 4 for styling
- shadcn-svelte UI components
- Zod for schema validation
- Axios for API communication
- Lucide icons
Quick Start
Prerequisites
- Python 3.10+
- Node.js 18+ with pnpm
- PostgreSQL 14+
- Redis
Backend Setup
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
Frontend Setup
# In a new terminal, from the project root
cd frontend
Install dependencies
pnpm install
Start the development server
pnpm run dev
Start Celery Worker
# In a new terminal
cd backend
uv run celery -A crm worker --loglevel=INFO
Access the Application
- Frontend: http://localhost:5173
- API Documentation: http://localhost:8000/swagger-ui/
- Admin Panel: http://localhost:8000/admin/
Connect your AI agent (MCP)
Let Claude, Cursor, Codex, Gemini, or any MCP client work in your CRM:
- In the app, go to Settings → API Tokens and create a personal access token (shown once).
- Register the
bcrm-mcpserver in your AI client, passingBCRMBASEURL(your API host, e.g.http://localhost:8000) andBCRM_TOKEN(the token). The token page shows ready-to-paste config for each client. - Restart the client and start asking.
mcp_server/README.md.
Docker Setup
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 admin@example.com
Once running:
- Frontend: http://localhost:5173
- API / Swagger: http://localhost:8000/swagger-ui/
- PostgreSQL: localhost:5432
- Redis: localhost:6379
Daily workflow
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)
Running commands inside containers
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
Custom environment overrides
The default env vars live in .env.docker (committed). To override locally without touching git:
- Copy
.env.dockerto.env.docker.local - Edit values as needed
- Update
env_fileindocker-compose.ymlto point to.env.docker.local
Project Structure
Django-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
├── mcp_server/ # MCP server (bcrm-mcp) for AI agents
│ └── src/bcrm_mcp/ # FastMCP tools over the REST API (stdio transport)
├── 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)
Multi-Tenancy & Security
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
Development
Testing
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/testleadskanban.py
Run tests matching a keyword
pytest -k "test_login"
View coverage report in browser
open htmlcov/index.html
Backend Commands
# Format code
black . && isort .
Check dependencies
pipdeptree
pip-check -H
Dev login (skip the Google OAuth flow)
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 aswin.1231@gmail.com
Bind to a specific org so you skip the orgswitch step on first load
uv run python manage.py devlogin aswin.1231@gmail.com --org "MicroPyramid"
Create the user on the fly (random password) if they don't exist yet
uv run python manage.py devlogin newdev@example.com --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.
Frontend Commands
cd frontend
Type checking
pnpm run check
Linting
pnpm run lint
Formatting
pnpm run format
API Documentation
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.
Contributing
We welcome contributions! Please see our contributing guidelines for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Community
- Issues: GitHub Issues
- Twitter: @micropyramid
- Commercial Support: Contact us
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributors
This project exists thanks to all the people who contributed.