# Smooth Schedule - Multi-Tenant SaaS Platform A production-grade Django skeleton with **strict data isolation** and **high-trust security** for resource orchestration. ## ๐ŸŽฏ Features - โœ… **Multi-Tenancy**: PostgreSQL schema-per-tenant using django-tenants - โœ… **8-Tier Role Hierarchy**: From SUPERUSER to CUSTOMER with strict permissions - โœ… **Secure Masquerading**: django-hijack with custom permission matrix - โœ… **Full Audit Trail**: Structured logging of all masquerade activity - โœ… **Headless API**: Django Rest Framework (no server-side HTML) - โœ… **Docker Ready**: Complete Docker Compose setup via cookiecutter-django - โœ… **AWS Integration**: S3 storage + Route53 DNS for custom domains ## ๐Ÿ“‹ Prerequisites - Python 3.9+ - PostgreSQL 14+ - Docker & Docker Compose - Cookiecutter (`pip install cookiecutter`) ## ๐Ÿš€ Quick Start ### 1. Run Setup Script ```bash chmod +x setup_project.sh ./setup_project.sh cd smoothschedule ``` ### 2. Configure Environment Create `.env` file: ```env # Database POSTGRES_DB=smoothschedule_db POSTGRES_USER=smoothschedule_user POSTGRES_PASSWORD=your_secure_password # Django DJANGO_SECRET_KEY=your_secret_key_here DJANGO_DEBUG=True DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1 # AWS AWS_ACCESS_KEY_ID=your_aws_key AWS_SECRET_ACCESS_KEY=your_aws_secret AWS_STORAGE_BUCKET_NAME=smoothschedule-media AWS_ROUTE53_HOSTED_ZONE_ID=your_zone_id ``` ### 3. Start Services ```bash docker-compose build docker-compose up -d ``` ### 4. Run Migrations ```bash # Shared schema docker-compose run --rm django python manage.py migrate_schemas --shared # Create superuser docker-compose run --rm django python manage.py createsuperuser ``` ### 5. Create First Tenant ```python docker-compose run --rm django python manage.py shell from core.models import Tenant, Domain tenant = Tenant.objects.create( name="Demo Company", schema_name="demo", subscription_tier="PROFESSIONAL", ) Domain.objects.create( domain="demo.smoothschedule.local", tenant=tenant, is_primary=True, ) ``` ```bash # Run tenant migrations docker-compose run --rm django python manage.py migrate_schemas ``` ## ๐Ÿ—๏ธ Architecture ### Multi-Tenancy Model ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ PostgreSQL Database โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ public (shared schema) โ”‚ โ”‚ โ”œโ”€ Tenants โ”‚ โ”‚ โ”œโ”€ Domains โ”‚ โ”‚ โ”œโ”€ Users โ”‚ โ”‚ โ””โ”€ PermissionGrants โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ tenant_demo (schema for Demo Company) โ”‚ โ”‚ โ”œโ”€ Appointments โ”‚ โ”‚ โ”œโ”€ Resources โ”‚ โ”‚ โ””โ”€ Customers โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ tenant_acme (schema for Acme Corp) โ”‚ โ”‚ โ”œโ”€ Appointments โ”‚ โ”‚ โ”œโ”€ Resources โ”‚ โ”‚ โ””โ”€ Customers โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### Role Hierarchy | Role | Level | Access Scope | |---------------------|----------|---------------------------| | SUPERUSER | Platform | All tenants (god mode) | | PLATFORM_MANAGER | Platform | All tenants | | PLATFORM_SALES | Platform | Demo accounts only | | PLATFORM_SUPPORT | Platform | Tenant users | | TENANT_OWNER | Tenant | Own tenant (full access) | | TENANT_MANAGER | Tenant | Own tenant | | TENANT_STAFF | Tenant | Own tenant (limited) | | CUSTOMER | Tenant | Own data only | ### Masquerading Matrix | Hijacker Role | Can Masquerade As | |--------------------|----------------------------------| | SUPERUSER | Anyone | | PLATFORM_SUPPORT | Tenant users | | PLATFORM_SALES | Demo accounts (`is_temporary=True`) | | TENANT_OWNER | Staff in same tenant | | Others | No one | **Security Rules:** - Cannot hijack yourself - Cannot hijack SUPERUSERs (except by other SUPERUSERs) - Maximum depth: 1 (no hijack chains) - All attempts logged to `logs/masquerade.log` ## ๐Ÿ“ Project Structure ``` smoothschedule/ โ”œโ”€โ”€ config/ โ”‚ โ””โ”€โ”€ settings.py # Multi-tenancy & security config โ”œโ”€โ”€ core/ โ”‚ โ”œโ”€โ”€ models.py # Tenant, Domain, PermissionGrant โ”‚ โ”œโ”€โ”€ permissions.py # Hijack permission matrix โ”‚ โ”œโ”€โ”€ middleware.py # Masquerade audit logging โ”‚ โ””โ”€โ”€ admin.py # Django admin for core models โ”œโ”€โ”€ users/ โ”‚ โ”œโ”€โ”€ models.py # Custom User with 8-tier roles โ”‚ โ””โ”€โ”€ admin.py # User admin with hijack button โ”œโ”€โ”€ logs/ โ”‚ โ”œโ”€โ”€ security.log # General security events โ”‚ โ””โ”€โ”€ masquerade.log # Hijack activity (JSON) โ””โ”€โ”€ setup_project.sh # Automated setup script ``` ## ๐Ÿ” Security Features ### Audit Logging All masquerade activity is logged in JSON format: ```json { "timestamp": "2024-01-15T10:30:00Z", "action": "HIJACK_START", "hijacker_email": "support@smoothschedule.com", "hijacked_email": "customer@demo.com", "ip_address": "192.168.1.1", "session_key": "abc123..." } ``` ### Permission Grants (30-Minute Window) Time-limited elevated permissions: ```python from core.models import PermissionGrant grant = PermissionGrant.create_grant( grantor=admin_user, grantee=support_user, action="view_billing", reason="Customer requested billing support", duration_minutes=30, ) # Check if active if grant.is_active(): # Perform privileged action pass ``` ## ๐Ÿงช Testing Masquerading 1. Access Django Admin: `http://localhost:8000/admin/` 2. Create test users with different roles 3. Click "Hijack" button next to a user 4. Verify audit logs: `docker-compose exec django cat logs/masquerade.log` ## ๐Ÿ“Š Admin Interface - **Tenant Management**: View tenants, domains, subscription tiers - **User Management**: Color-coded roles, masquerade buttons - **Permission Grants**: Active/expired/revoked status, bulk revoke - **Domain Verification**: AWS Route53 integration status ## ๐Ÿ› ๏ธ Development ### Adding Tenant Apps Edit `config/settings.py`: ```python TENANT_APPS = [ 'django.contrib.contenttypes', 'appointments', # Your app 'resources', # Your app 'billing', # Your app ] ``` ### Custom Domain Setup ```python domain = Domain.objects.create( domain="app.customdomain.com", tenant=tenant, is_custom_domain=True, route53_zone_id="Z1234567890ABC", ) ``` Then configure Route53 CNAME: `app.customdomain.com` โ†’ `smoothschedule.yourhost.com` ## ๐Ÿ“– Key Files Reference | File | Purpose | |------|---------| | `setup_project.sh` | Automated project initialization | | `config/settings.py` | Multi-tenancy, middleware, security config | | `core/models.py` | Tenant, Domain, PermissionGrant models | | `core/permissions.py` | Masquerading permission matrix | | `core/middleware.py` | Audit logging for masquerading | | `users/models.py` | Custom User with 8-tier roles | ## ๐Ÿ“ Important Notes - **Django Admin**: The ONLY HTML interface (everything else is API) - **Middleware Order**: `TenantMainMiddleware` must be first, `MasqueradeAuditMiddleware` after `HijackUserMiddleware` - **Tenant Isolation**: Each tenant's data is in a separate PostgreSQL schema - **Production**: Update `SECRET_KEY`, database credentials, and AWS keys via environment variables ## ๐Ÿ› Troubleshooting **Cannot create tenant users:** - Error: "Users with role TENANT_STAFF must be assigned to a tenant" - Solution: Set `user.tenant = tenant_instance` before saving **Hijack button doesn't appear:** - Check `HIJACK_AUTHORIZATION_CHECK` in settings - Verify `HijackUserAdminMixin` in `users/admin.py` - Ensure user has permission per matrix rules **Migrations fail:** - Run shared migrations first: `migrate_schemas --shared` - Then run tenant migrations: `migrate_schemas` ## ๐Ÿ“„ License MIT ## ๐Ÿค Contributing This is a production skeleton. Extend `TENANT_APPS` with your business logic. --- **Built with โค๏ธ for multi-tenant SaaS perfection**