Files
smoothschedule/README.md
poduck 2e111364a2 Initial commit: SmoothSchedule multi-tenant scheduling platform
This commit includes:
- Django backend with multi-tenancy (django-tenants)
- React + TypeScript frontend with Vite
- Platform administration API with role-based access control
- Authentication system with token-based auth
- Quick login dev tools for testing different user roles
- CORS and CSRF configuration for local development
- Docker development environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 01:43:20 -05:00

295 lines
8.7 KiB
Markdown

# 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**