Creating Your SaaS Guide
A simple guide to building features inside this boilerplate.
1. General
When deploying your application, refer to the deployments.md
file. This file contains optimal server configurations to ensure efficient resource utilization, along with estimated concurrent user counts to help you choose the right server for your needs.
Need Help? If you encounter any issues, please don't hesitate to contact me. I'll respond as quickly as possible, and your feedback helps improve the documentation for future users.
2. Authentication Middleware
By default, this boilerplate uses Django's built-in authentication middleware (introduced in newer Django versions) that requires users to be logged in to access all pages. This provides a secure-by-default approach for SaaS applications where most functionality should be behind authentication.
Default Behavior
All pages require authentication: Users must be logged in to access any view in your application.
- • Unauthenticated users are automatically redirected to the login page
- • This applies to all views across your entire application
- • Provides secure-by-default behavior for SaaS applications
-
• Eliminates the need to add
@login_required
to every view
Making Pages Public
If you need some pages to be accessible without authentication (e.g., landing pages, pricing, contact), you have two options:
Option 1: Remove Authentication Middleware (Recommended for Public Sites)
Remove the authentication middleware from your settings and manually add decorators to protected views:
-
Comment out or remove the authentication middleware in
config/settings/base.py
-
Add
@login_required
decorator to views that need authentication -
Use
@method_decorator(login_required)
for class-based views
# Example: Protecting a view manually
from django.contrib.auth.decorators import login_required
@login_required
def protected_view(request):
# This view requires authentication
pass
Option 2: Use Login Not Required Decorator
Keep the authentication middleware active but use the @login_not_required
decorator on specific views that should be publicly accessible. This approach maintains the secure-by-default behavior while allowing specific public pages.
# Example: Making a view public
from django.contrib.auth.decorators import login_not_required
@login_not_required
def public_view(request):
# This view is accessible without authentication
pass
Use this decorator on landing pages, pricing pages, contact forms, or any other views that should be publicly accessible.
Important: When removing the authentication middleware, remember to protect sensitive views with appropriate decorators. Don't forget views that handle user data, admin functionality, or payment processing.
3. Stripe Configuration
To ensure proper payment processing, you'll need both a webhook secret and a Stripe secret key. First, create a Stripe account and switch to sandbox mode to obtain your test secret key.
Setting up Stripe CLI
Install the Stripe CLI and run the following command to generate your webhook secret:
stripe listen --forward-to localhost:8000/payments/webhook
This command will generate a webhook secret. Copy this secret and add it to the WEBHOOK_SECRET
variable in .envs/local/django.env
. After adding the secrets, rebuild your container to apply the environment changes.
Setting Up Price ID
In addition to the secret key and webhook secret, you'll need a price_id
. To obtain one:
- Create a product in your Stripe dashboard
- Copy the generated price ID
- Search for TODO comments in the codebase that indicate where to add it
The price ID tells Stripe which product or subscription package the user is purchasing.
⚠️ Important: Production Environment
In production, you must use Stripe's live environment (not sandbox mode) and add your production secrets to .envs/production/django.env
.
To obtain your production webhook secret, refer to the Stripe webhook documentation. Your webhook endpoint must listen for the following events:
-
checkout.session.completed
- Grants membership after successful payment -
checkout.session.async_payment_succeeded
- Handles delayed payment confirmations -
customer.subscription.deleted
- Removes membership when subscription ends -
customer.subscription.updated
- Updates membership status based on subscription changes -
customer.subscription.paused
- Pauses membership access -
customer.subscription.resumed
- Resumes membership access -
charge.dispute.created
- Handles chargebacks by pausing membership -
invoice.upcoming
- Optional: For sending payment reminders
Your production webhook endpoint will be: https://yourdomain.com/payments/webhook
4. AI-Assisted Coding
Before starting with your AI assistant, ensure it follows the guidelines in the AGENTS.md
or CLAUDE.md
file.
Important: While AI agents can access these files, they may not always follow them consistently. When this happens, you'll need to add the instructions directly to your AI assistant's configuration.
Configuration Examples
- For Cursor: Add this rule: "You must always follow the AGENTS.md guide"
- For prompts: Begin with: "Following the AGENTS.md file, implement [feature name]"
Recommended: Run your AI agent inside the dev container for best results. Code editors like Cursor handle this automatically. For Claude, install Claude Code directly in the container and launch it from there.
5. Coding by Yourself
If you prefer to code without AI assistance, you should have at least basic Django knowledge. If you're new to Django (beyond knowing it's Python-based), start with the official Django documentation or explore tutorial videos on YouTube to build foundational skills.
Creating New Features
Before building a feature, determine whether it warrants its own Django app. For example, when creating a todo CRUD feature:
-
Create a new app:
python manage.py startapp todo
-
Register it in
config/settings/base.py
Template Organization
By default, all templates are centralized in the project_name/templates
folder. To store templates within individual apps instead, set APP_DIRS = True
in the templates configuration in base.py
.
Database Migrations
After modifying any models.py
file, apply the changes to your database:
python manage.py makemigrations
python manage.py migrate
Always run makemigrations
first to create migration files, then run migrate
to apply them to the database.
Ready to Deploy?
Before deploying, ensure you have generated the lock file for uv by running:
docker compose -f docker-compose.local.yml run --rm django uv lock
After generating the lock file, check the Deployment Guide for step-by-step instructions on deploying your SaaS to production.
You're All Set!
This provides the basics, now it's your time to build. If you encounter issues, don't hesitate to contact me.
Need Help?
If you encounter any issues while building your SaaS or have questions about implementing features, I'm here to help!
I typically respond within 24 hours. Include details about your development environment and any error messages for faster troubleshooting.
6. Social Login Integration
Adding social login to your application improves user experience by allowing quick sign-up and sign-in through existing accounts. This guide covers integrating Google authentication with Django using the django-allauth package.
Step 1: Configure Django Settings
Add the following to your
config/settings/base.py
:# Add to INSTALLED_APPS
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google', # For Google
# Provider specific settings
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
}
}
}
Step 2: Google OAuth Setup
http://localhost:8000/accounts/google/login/callback/
(development)https://yourdomain.com/accounts/google/login/callback/
Step 3: Admin Setup
Run migrations and configure the social app in Django admin:
python manage.py migrate
# Create superuser if not exists
python manage.py createsuperuser
Then, in Django Admin (
/admin
):Security Considerations
GitHub Authentication Setup
Here's how to set up GitHub authentication alongside Google:
Step 1: Update Django Settings
Add GitHub provider to your
config/settings/base.py
:# Add to INSTALLED_APPS
'allauth.socialaccount.providers.github', # Add this line
# Update SOCIALACCOUNT_PROVIDERS
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': ['profile', 'email'],
'AUTH_PARAMS': {'access_type': 'online'},
'APP': {
'client_id': env('GOOGLE_CLIENT_ID', default=''),
'secret': env('GOOGLE_CLIENT_SECRET', default=''),
'key': ''
}
},
'github': {
'SCOPE': ['user:email'],
'APP': {
'client_id': env('GITHUB_CLIENT_ID', default=''),
'secret': env('GITHUB_CLIENT_SECRET', default=''),
}
}
}
Step 2: GitHub OAuth App Setup
http://localhost:8000
(development)http://localhost:8000/accounts/github/login/callback/
https://yourdomain.com/accounts/github/login/callback/
Step 3: Add GitHub Credentials to Admin
In Django Admin, create another Social Application:
Adding Other Providers
Django-allauth supports many social providers. To add others like Facebook, Twitter, or LinkedIn:
'allauth.socialaccount.providers.github'
{% provider_login_url 'github' %}
Tip: For more detailed social account configurations and a complete list of supported providers, check out the django-allauth guide. The documentation covers advanced features like custom providers, OAuth scopes, and provider-specific settings.