Restructured 13 Django apps from flat/mixed organization into 5 logical
domain packages following cookiecutter-django conventions:
- identity/: core (tenant/domain models, middleware, mixins), users
- scheduling/: schedule, contracts, analytics
- communication/: notifications, credits, mobile, messaging
- commerce/: payments, tickets
- platform/: admin, api
Key changes:
- Moved all apps to smoothschedule/smoothschedule/{domain}/{app}/
- Updated all import paths across the codebase
- Updated settings (base.py, multitenancy.py, test.py)
- Updated URL configuration in config/urls.py
- Updated middleware and permission paths
- Preserved app_label in AppConfig for migration compatibility
- Updated CLAUDE.md documentation with new structure
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9.6 KiB
Smooth Schedule - Installation & Setup Guide
🎉 Project Structure Created Successfully!
Your Smooth Schedule multi-tenant SaaS platform has been initialized with:
- ✅ Cookiecutter-Django base structure
- ✅ Multi-tenancy with django-tenants 3.9.0
- ✅ Masquerading security with django-hijack 3.7.4
- ✅ Custom 8-tier role hierarchy
- ✅ Audit logging middleware
- ✅ PostgreSQL schema-per-tenant architecture
📁 Project Location
/home/poduck/Desktop/smoothschedule2/smoothschedule/
🚀 Next Steps to Get Running
1. Navigate to Project Directory
cd /home/poduck/Desktop/smoothschedule2/smoothschedule
2. Configure Environment Variables
Create .envs/.local/.django file:
mkdir -p .envs/.local
cat > .envs/.local/.django << 'EOF'
# General
# ------------------------------------------------------------------------------
DJANGO_SETTINGS_MODULE=config.settings.local
DJANGO_SECRET_KEY=your-secret-key-here-change-in-production
DJANGO_DEBUG=True
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,.localhost,.127.0.0.1
USE_DOCKER=yes
# Database
# ------------------------------------------------------------------------------
DATABASE_URL=postgres://postgres:changeme@postgres:5432/smoothschedule
# Redis
# ------------------------------------------------------------------------------
REDIS_URL=redis://redis:6379/0
#AWS
# ------------------------------------------------------------------------------
DJANGO_AWS_ACCESS_KEY_ID=
DJANGO_AWS_SECRET_ACCESS_KEY=
DJANGO_AWS_STORAGE_BUCKET_NAME=smoothschedule-media
DJANGO_AWS_S3_REGION_NAME=us-east-1
EOF
Create .envs/.local/.postgres file:
cat > .envs/.local/.postgres << 'EOF'
# PostgreSQL
# ------------------------------------------------------------------------------
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=smoothschedule
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changeme
EOF
3. Build and Start Docker Containers
# Build the Docker images
docker-compose -f docker-compose.local.yml build
# Start all services (Django, PostgreSQL, Redis, Celery)
docker-compose -f docker-compose.local.yml up -d
# Check logs
docker-compose -f docker-compose.local.yml logs -f
4. Run Database Migrations
IMPORTANT: With django-tenants, you must run migrations in a specific order:
# 1. Create the shared schema (public) FIRST
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas --shared
# 2. Create a superuser (in the public schema)
docker-compose -f docker-compose.local.yml run --rm django python manage.py createsuperuser
5. Create Your First Tenant
Open Django shell:
docker-compose -f docker-compose.local.yml run --rm django python manage.py shell
In the shell, create a tenant:
from core.models import Tenant, Domain
# Create the tenant
tenant = Tenant.objects.create(
name="Demo Company",
schema_name="demo", # This will be the PostgreSQL schema name
subscription_tier="PROFESSIONAL",
max_users=50,
max_resources=100,
)
# Create a domain for the tenant
domain = Domain.objects.create(
domain="demo.localhost", # For local development
tenant=tenant,
is_primary=True,
)
print(f"Created tenant: {tenant.name} with schema: {tenant.schema_name}")
print(f"Domain: {domain.domain}")
Exit the shell (exit() or Ctrl+D).
6. Run Tenant Migrations
Now migrate all tenant schemas:
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas
7. Access the Application
-
Django Admin: http://localhost:8000/admin/
- Login with the superuser you created
- You can manage tenants, users, and permission grants here
-
API Documentation: http://localhost:8000/api/schema/swagger-ui/
- DRF Spectacular auto-generated API docs
-
Tenant Access:
- Add entry to
/etc/hosts:127.0.0.1 demo.localhost - Access tenant at: http://demo.localhost:8000/
- Add entry to
🔐 Creating Users with Roles
In Django shell or admin, create users with different roles:
from smoothschedule.identity.users.models import User
from core.models import Tenant
# Get the tenant
tenant = Tenant.objects.get(schema_name="demo")
# Create a Tenant Owner
owner = User.objects.create_user(
email="owner@demo.com",
password="secure-password",
role=User.Role.TENANT_OWNER,
tenant=tenant,
first_name="John",
last_name="Owner",
)
# Create a Tenant Staff member
staff = User.objects.create_user(
email="staff@demo.com",
password="secure-password",
role=User.Role.TENANT_STAFF,
tenant=tenant,
first_name="Jane",
last_name="Staff",
)
# Create a demo account (for sales)
demo_user = User.objects.create_user(
email="demo@demo.com",
password="demo-password",
role=User.Role.TENANT_OWNER,
tenant=tenant,
is_temporary=True, # Sales can masquerade as this user
first_name="Demo",
last_name="Account",
)
# Create a Platform Support user
support = User.objects.create_user(
email="support@smoothschedule.com",
password="support-password",
role=User.Role.PLATFORM_SUPPORT,
tenant=None, # Platform users have no tenant
is_staff=True, # Needed for admin access
first_name="Support",
last_name="Team",
)
🎭 Testing Masquerading
- Login to admin as a superuser or support user
- Go to Users section
- Click the "Hijack" button next to a user you can masquerade as
- You'll now see the interface as that user
- Check
logs/masquerade.logfor audit trail:
docker-compose -f docker-compose.local.yml exec django cat logs/masquerade.log
📊 Understanding the Architecture
Multi-Tenancy
Each tenant gets their own PostgreSQL schema:
PostgreSQL Database: smoothschedule
├── public (shared schema)
│ ├── core_tenant
│ ├── core_domain
│ ├── users_user
│ └── core_permissiongrant
├── demo (tenant schema for "Demo Company")
│ └── (your tenant-scoped apps go here)
└── acme (tenant schema for "Acme Corp")
└── (completely isolated data)
Role Hierarchy
| Role | Level | Can Hijack |
|---|---|---|
| SUPERUSER | Platform | Everyone |
| PLATFORM_SUPPORT | Platform | Tenant users |
| PLATFORM_SALES | Platform | Demo accounts only |
| TENANT_OWNER | Tenant | Staff in same tenant |
| TENANT_MANAGER | Tenant | - |
| TENANT_STAFF | Tenant | - |
| CUSTOMER | Tenant | - |
🛠️ Development Workflow
Adding Tenant-Scoped Apps
-
Create your app:
docker-compose -f docker-compose.local.yml run --rm django python manage.py startapp myapp -
Add to
TENANT_APPSinconfig/settings/multitenancy.py:TENANT_APPS = [ 'django.contrib.contenttypes', 'myapp', # Your new app ] -
Run migrations:
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas
Useful Commands
# View logs
docker-compose -f docker-compose.local.yml logs -f django
# Shell access
docker-compose -f docker-compose.local.yml run --rm django python manage.py shell
# Create migrations
docker-compose -f docker-compose.local.yml run --rm django python manage.py makemigrations
# Migrate all tenants
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas
# Collect static files
docker-compose -f docker-compose.local.yml run --rm django python manage.py collectstatic --noinput
📝 Key Files Reference
| File | Purpose |
|---|---|
config/settings/multitenancy.py |
Multi-tenancy configuration |
config/settings/local.py |
Local development settings |
smoothschedule/core/ |
Tenant, Domain, PermissionGrant models |
smoothschedule/users/models.py |
Custom User with 8 roles |
core/permissions.py |
Masquerading permission matrix |
core/middleware.py |
Audit logging middleware |
🐛 Troubleshooting
Problem: "django_tenants not found"
Solution: Rebuild the Docker image:
docker-compose -f docker-compose.local.yml build --no-cache django
Problem: "relation does not exist"
Solution: Run migrations in correct order:
# 1. Shared schema first
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas --shared
# 2. Then tenant schemas
docker-compose -f docker-compose.local.yml run --rm django python manage.py migrate_schemas
Problem: Cannot access tenant URL
Solution: Add to /etc/hosts:
echo "127.0.0.1 demo.localhost" | sudo tee -a /etc/hosts
Problem: Hijack button doesn't appear
Solution:
- Ensure user has appropriate role (see permission matrix)
- Check that
HijackUserAdminMixinis inusers/admin.py - Verify middleware order in settings
🎯 Production Deployment
Before deploying to production:
- Update SECRET_KEY: Use environment variable
- Set DEBUG=False: In production settings
- Configure ALLOWED_HOSTS: Add your domain
- Update Database Credentials: Use secure passwords
- Configure AWS: Set real S3 and Route53 credentials
- Enable HTTPS: Set
SECURE_SSL_REDIRECT = True - Review Security Settings: Check
config/settings/production.py
📚 Additional Resources
- django-tenants Documentation
- django-hijack Documentation
- cookiecutter-django Documentation
- Django REST Framework
Your multi-tenant SaaS platform is ready! 🚀