What it solves:
- Boilerplate code for paid SaaS products
- Vendor lock-in with single payment provider
- Weeks rebuilding common SaaS features
- Multi-tenant organization management complexity
- Payment gateway integration from scratch
How it solves:
- Production-ready Django starter with batteries included
- Pluggable payment gateway abstraction layer
- Built-in multi-tenancy with org/team RBAC
- Razorpay integration ready out-of-box
- Switch payment providers in one line
Example use case: You're building a project management SaaS. Clone this repo, configure Razorpay keys, and you instantly get user auth, organization management, subscription billing, and team invitations - launch your MVP in hours instead of weeks.
- Python 3.12 (required)
- PostgreSQL (or SQLite for quick testing)
- Redis (for Celery background tasks)
- Clone and enter project:
git clone <repo-url>
cd django-saas-launchpad- Create virtual environment:
python3.12 -m venv saas_env
source saas_env/bin/activate # On Windows: saas_env\Scripts\activate- Install dependencies:
pip install -r requirements.txt- Set up pre-commit hooks:
pre-commit install- Set up environment variables:
cp .env.example .envAdd to .env:
SECRET_KEY=your-secret-key-here
DEBUG=True
DATABASE_URL=postgresql://user:password@localhost:5432/saas_db # Or sqlite:///db.sqlite3
REDIS_URL=redis://localhost:6379/0
# Razorpay (use test keys for development)
RAZORPAY_KEY_ID=rzp_test_your_key_here
RAZORPAY_KEY_SECRET=your_secret_here
RAZORPAY_WEBHOOK_SECRET=whsec_your_webhook_secret
DEFAULT_PAYMENT_GATEWAY=razorpay
# Email (console backend for local dev)
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
- Run migrations:
python manage.py migrate- Create superuser:
python manage.py createsuperuser
# Email: [email protected]
# Password: admin123- Run development server:
python manage.py runserver- Run tests:
# All tests
pytest
# Specific app tests
pytest accounts/tests/
pytest organizations/tests/
pytest billing/tests/
# With coverage
pytest --cov=. --cov-report=htmldjango-saas-launchpad/
├── accounts/ # User auth, JWT, magic links
├── organizations/ # Multi-tenancy, teams, invitations
├── billing/ # Payment gateways, subscriptions
│ └── gateways/ # Pluggable payment providers
├── feature_flags/ # Feature toggles (planned)
├── analytics/ # Usage metrics (planned)
└── config/ # Django settings
Automated security checks run on every PR:
- Secret detection (Gitleaks, TruffleHog)
- Dependency vulnerabilities (Safety, pip-audit)
- SAST (Bandit, Semgrep)
- Code quality (Ruff, Black, Pylint, Radon)
Install Gitleaks (one-time):
cd /tmp
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz
tar -xzf gitleaks_8.18.0_linux_x64.tar.gz
mkdir -p ~/bin
mv gitleaks ~/bin/
rm gitleaks_8.18.0_linux_x64.tar.gzRun locally:
~/bin/gitleaks detect --config .gitleaks.toml
safety check --file requirements.txt
bandit -r . -ll -x './saas_env/*,./venv/*,./tests/*'
radon cc . -a --total-averageConfig files: .gitleaks.toml, .bandit, .pylintrc
-
Install pre-commit (if not already installed):
pip install pre-commit
-
Install the git hooks:
pre-commit install
This installs hooks that will run automatically on every commit.
-
Test the setup:
pre-commit run --all-files
This runs all hooks on all files to ensure everything is working.
Once installed, the hooks run automatically when you commit:
git add .
git commit -m "Your commit message"
# Hooks run automatically hereIf any hook fails, fix the issues and commit again. The hooks will re-run.
If you need to bypass hooks (not recommended):
git commit --no-verify -m "Emergency commit"
git push --no-verifyWarning: Only bypass hooks when absolutely necessary. Security checks are important!
- What it does: Automatically formats Python code to a consistent style
- Config:
pyproject.toml - Auto-fixes: Yes (reformats code automatically)
- Line length: 88 characters
- Target: Python 3.11
- What it does:
- Lints code for errors (pycodestyle, pyflakes)
- Formats code (alternative to Black)
- Sorts imports
- Config:
pyproject.toml - Auto-fixes: Yes (safe fixes only)
- Rules enabled:
E: pycodestyle errorsF: pyflakesW: warningsI: import sorting
- What it does: Deep code analysis for bugs, code smells, and style issues
- Config:
.pylintrc - Auto-fixes: No (reports issues only)
- Ignores: migrations, venv, tests
- Disabled rules: Docstrings, naming conventions, some Django-specific patterns
- What it does: Static type checking for Python
- Config: Uses project defaults
- Auto-fixes: No (reports type errors only)
- What it does: Scans for common security issues in Python code
- Config:
bandit.yml - Severity: HIGH
- Confidence: HIGH
- Excludes: tests, venv, .venv
- What it does: Detects hardcoded secrets, API keys, passwords in your code
- Config:
.gitleaks.toml,.gitleaksignore - Auto-fixes: No (blocks commit if secrets found)
- Scans: Only changed files (diff between HEAD~1 and HEAD)
- Custom rules: Razorpay keys, Django SECRET_KEY, AWS keys
- Ignored files:
.secrets.baseline, test files, venv
- What it does: Another tool for detecting secrets
- Config:
.detect-secrets.yaml,.secrets.baseline - Auto-fixes: No
- Baseline: Uses
.secrets.baselineto track known false positives - Excludes: tests, venv, cache directories
If gitleaks or detect-secrets flags something that's not actually a secret:
For Gitleaks:
- Get the fingerprint from the error message
- Add it to
.gitleaksignore:echo "fingerprint:file:rule:line" >> .gitleaksignore
- Commit the change
For detect-secrets:
- Update the baseline:
detect-secrets scan --update .secrets.baseline
Problem: Bandit flags code that's safe.
Solutions:
-
Add inline ignore:
# nosec B601 # Bandit ignore for this line subprocess.run(command)
-
Update bandit.yml to exclude specific paths or tests
Problem: Pylint doesn't understand Django patterns.
Solution: Already configured in .pylintrc - Django-specific rules are disabled. If you see new issues, they may be legitimate.
Problem: Gitleaks/detect-secrets flag test data.
Solutions:
- Already configured: Test directories are in allowlists
- If still flagged: Add specific fingerprint to ignore files
- For detect-secrets: Update baseline with
detect-secrets scan --update .secrets.baseline
Problem: Ruff and Black format code differently.
Solution: They're configured to be compatible. If conflicts occur:
- Run Black first:
black . - Then Ruff:
ruff format . - Or use Ruff format only (it's faster)
pre-commit run --all-files# Run only Black
pre-commit run black --all-files
# Run only Bandit
pre-commit run bandit --all-files
# Run only Gitleaks
pre-commit run gitleaks --all-filespre-commit run --files accounts/views.py organizations/models.py# Black
black .
# Ruff (lint)
ruff check .
# Ruff (format)
ruff format .
# Ruff (fix)
ruff check --fix .
# Pylint
pylint --rcfile=.pylintrc accounts/
# Bandit
bandit -c bandit.yml -r .
# Gitleaks
gitleaks detect --source . --config .gitleaks.toml --gitleaks-ignore-path .gitleaksignore
# detect-secrets
detect-secrets scan --baseline .secrets.baseline
# Pyright
pyright .Secret Detection
- TruffleHog: Verified secrets
- Gitleaks: Any secrets Dependency Vulnerabilities
- Safety: ANY vulnerabilities
- pip-audit: ANY vulnerabilities Code Security (SAST)
- Bandit: Medium/High severity issues (-ll flag)
- Semgrep: Any security findings
Code Quality
- Ruff: Code style issues
- Black: Formatting issues
- Pylint: Code smells
- Radon: Complexity metrics
Note: This is an active development project. More features (subscriptions, invoices, feature flags, analytics) coming soon.