A modern, scalable multi-tenant Human Resource Management System API built with Django 5.2.7 and django-tenants. Each tenant (company) operates in its own PostgreSQL schema, ensuring complete data isolation and security.
- Multi-tenant Architecture: Complete data isolation using PostgreSQL schema-per-tenant approach
- JWT Authentication: Secure token-based authentication with refresh token rotation
- Employee Management: Comprehensive employee profiles with personal details
- Team & Title Management: Organizational structure management
- Async Task Processing: Celery + Redis for background jobs
- API Documentation: Auto-generated OpenAPI/Swagger documentation
- Docker Support: Full containerization for easy deployment
- Comprehensive Testing: High test coverage with parallel CI pipeline
- Tenant-aware File Storage: Isolated media storage per tenant
- Python 3.13
- Django 5.2.7 - Web framework
- Django REST Framework 3.16.1 - REST API
- django-tenants 3.9.0 - Multi-tenancy support
- django-tenant-users 2.2.1 - User management for tenants
- PostgreSQL 16 - Database (schema-per-tenant)
- djangorestframework-simplejwt 5.5.1 - JWT authentication
- bcrypt 5.0.0 - Password hashing
- django-cors-headers 4.9.0 - CORS handling
- Celery 5.5.3 - Distributed task queue
- Redis - Message broker and result backend
- uv - Fast Python package manager
- Black - Code formatter
- isort - Import sorter
- coverage - Test coverage
- model-bakery - Test fixtures
- drf-spectacular - OpenAPI schema generation
- Python 3.13+
- PostgreSQL 15+
- Redis
- Docker & Docker Compose (optional, for containerized setup)
- uv package manager
-
Clone the repository
git clone <repository-url> cd multi-tenant-boilerplate
-
Create environment file
cp .env.example .env # Edit .env with your configuration -
Start services
docker-compose up -d
-
Run migrations
# Shared apps migrations docker-compose exec web uv run python manage.py migrate_schemas --shared # Tenant apps migrations docker-compose exec web uv run python manage.py migrate_schemas
-
Create public tenant (first-time setup)
docker-compose exec web uv run python manage.py shell>>> from tenant_users.tenants.utils import create_public_tenant >>> create_public_tenant(domain_url="localhost", owner_email="admin@localhost.com") >>> exit()
-
Access the API
-
Install dependencies
uv sync --extra dev
-
Configure environment
cp .env.example .env # Edit .env with your PostgreSQL and Redis credentials -
Run migrations
uv run python manage.py migrate_schemas --shared uv run python manage.py migrate_schemas
-
Create public tenant
uv run python manage.py shell
>>> from tenant_users.tenants.utils import create_public_tenant >>> create_public_tenant(domain_url="localhost", owner_email="admin@localhost.com") >>> exit()
-
Start development server
uv run python manage.py runserver
-
Start Celery worker (in a separate terminal)
uv run celery -A config worker -l info
Create a .env file in the project root with the following variables:
# Django
SECRET_KEY=your-secret-key-here
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
DB_NAME=hrm_db
DB_USER=hrm_user
DB_PASSWORD=your-secure-password
DB_HOST=localhost
DB_PORT=5432
# JWT
JWT_ACCESS_TOKEN_LIFETIME=60
JWT_REFRESH_TOKEN_LIFETIME=1440
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8000
# Email (Gmail example)
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
DEFAULT_FROM_EMAIL=your-email@gmail.com
# Celery
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0The project uses PostgreSQL with schema-per-tenant architecture:
- Public Schema: Contains shared apps (tenants, users)
- Tenant Schemas: Each tenant has its own schema (employees, titles, teams)
- Swagger UI: http://localhost:8000/api/v1/schema/swagger-ui/
- ReDoc: http://localhost:8000/api/v1/schema/redoc/
- OpenAPI Schema: http://localhost:8000/api/v1/schema/
POST /api/v1/auth/register/- User registrationPOST /api/v1/auth/login/- User loginPOST /api/v1/auth/refresh/- Refresh access tokenPOST /api/v1/auth/verify-email/- Verify email addressPOST /api/v1/auth/resend-verification/- Resend verification emailPOST /api/v1/auth/password-reset/- Request password resetPOST /api/v1/auth/password-reset-confirm/- Confirm password reset
-
GET /api/v1/employees/- List employees -
POST /api/v1/employees/- Create employee -
GET /api/v1/employees/{id}/- Get employee details -
PUT /api/v1/employees/{id}/- Update employee -
DELETE /api/v1/employees/{id}/- Delete employee -
GET /api/v1/titles/- List job titles -
POST /api/v1/titles/- Create job title -
GET /api/v1/titles/{id}/- Get title details -
PUT /api/v1/titles/{id}/- Update title -
DELETE /api/v1/titles/{id}/- Delete title -
GET /api/v1/teams/- List teams -
POST /api/v1/teams/- Create team -
GET /api/v1/teams/{id}/- Get team details -
PUT /api/v1/teams/{id}/- Update team -
DELETE /api/v1/teams/{id}/- Delete team
All tenant endpoints require JWT authentication. Include the token in the Authorization header:
Authorization: Bearer <access_token># Run all tests
uv run python manage.py test
# Run tests for specific module
uv run python manage.py test employees
uv run python manage.py test auth
# Run with coverage
uv run coverage run --source=employees manage.py test employees
uv run coverage report
# Generate HTML coverage report
uv run coverage html
open htmlcov/index.htmlMinimum coverage rates:
- auth: 85%
- employees: 80%
- titles: 95%
- teams: 95%
The project includes a GitHub Actions CI pipeline that:
- Checks code formatting
- Runs tests in parallel for each module
- Enforces coverage thresholds
multi-tenant-boilerplate/
βββ auth/ # Authentication app
β βββ services.py # Business logic
β βββ views.py # API endpoints
β βββ serializers.py # Request/response serializers
β βββ tests/ # Test suite
βββ config/ # Django settings
β βββ settings.py # Main configuration
β βββ urls.py # Tenant URLs
β βββ public_urls.py # Public URLs
βββ employees/ # Employee management
βββ teams/ # Team management
βββ titles/ # Job title management
βββ tenants/ # Tenant management
βββ users/ # User model
βββ utils/ # Shared utilities
β βββ models.py # BaseModel
β βββ services.py # BaseService
β βββ storages.py # Tenant-aware storage
βββ templates/ # Email templates
βββ docs/ # Documentation
βββ docker-compose.yml # Docker configuration
βββ pyproject.toml # Project dependencies
The project uses schema-per-tenant architecture:
- Each tenant has its own PostgreSQL schema
- Complete data isolation between tenants
- Shared schema for tenant and user management
- Domain-based routing via custom middleware
Business logic is separated into service classes:
from utils.interfaces import BaseService
class EmployeeService(BaseService):
def create_object(self, user, first_name, last_name, **kwargs):
"""Creates a new employee."""
return Employee.objects.create(...)All models extend BaseModel which provides:
created_on- Creation timestampupdated_on- Last update timestampattributes- JSON field for flexible data
# Format code
uv format
# Check formatting
uv format --check# Create migration
uv run python manage.py makemigrations <app_name>
# Apply migrations (tenant-aware)
uv run python manage.py migrate_schemas --shared # Shared apps first
uv run python manage.py migrate_schemas # Tenant apps# Enter Django shell
uv run python manage.py shell
# Work with tenant context
from django_tenants.utils import tenant_context
from tenants.models import Client
tenant = Client.objects.get(schema_name="company")
with tenant_context(tenant):
employees = Employee.objects.all()# Start services
docker-compose up -d
# View logs
docker-compose logs -f web
docker-compose logs -f celery_worker
# Execute commands
docker-compose exec web uv run python manage.py <command>
docker-compose exec web bash
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -vAdditional documentation is available in the docs/ directory:
- Setup Guide
- Multi-Tenant Architecture
- Migrations Guide
- Docker Deployment
- CI Pipeline
- Create Company Flow
- Tenant-Aware Storage
- JWT Tokens: Access token (60 min), Refresh token (24 hours)
- Token Rotation: New token generated on each refresh
- Password Hashing: bcrypt with secure defaults
- Schema Isolation: Complete data separation per tenant
- CORS: Configurable allowed origins
- Rate Limiting: Throttling on sensitive endpoints
- Set
DEBUG=Falsein environment - Configure
ALLOWED_HOSTS - Set secure
SECRET_KEY - Configure production database
- Set up SSL/TLS certificates
- Configure email backend
- Set up static file serving
- Configure Celery workers
- Set up monitoring and logging
# Build production image
docker-compose -f docker-compose.prod.yml build
# Start services
docker-compose -f docker-compose.prod.yml up -d
# Run migrations
docker-compose exec web uv run python manage.py migrate_schemas --shared
docker-compose exec web uv run python manage.py migrate_schemas
# Collect static files
docker-compose exec web uv run python manage.py collectstatic --noinput- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes following the code style guidelines
- Write tests for new functionality
- Ensure all tests pass and coverage meets thresholds
- Format code with
uv format - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Black formatting (line-length=88)
- Use isort for import sorting
- Add type hints where possible
- Write docstrings in Google style
- Follow Django best practices
This project is licensed under the terms specified in the LICENSE file.
- Yusuf Ziya CIVAN - yusufziyacivan@gmail.com
- Django Tenants community
- Django REST Framework team
- All contributors
For issues and questions:
- Open an issue on GitHub
- Check the documentation in
docs/ - Review
AGENTS.mdfor development guidelines
Version: 0.1.0
Last Updated: 2025-01-26
Python: 3.13
Django: 5.2.7