poduck 07f49cb457 Clear session and show login when non-platform users access platform subdomain
Instead of redirecting business users to their business subdomain when
they access the platform subdomain, clear their session and show the
platform login page. This is cleaner when masquerading changes tokens
to a tenant user - they can simply log back in as a platform user.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 12:02:16 -05:00

SmoothSchedule - Multi-Tenant Scheduling Platform

A production-ready multi-tenant SaaS platform for resource scheduling, appointments, and business management.

Features

  • Multi-Tenancy: PostgreSQL schema-per-tenant using django-tenants
  • 8-Tier Role Hierarchy: SUPERUSER, PLATFORM_MANAGER, PLATFORM_SALES, PLATFORM_SUPPORT, TENANT_OWNER, TENANT_MANAGER, TENANT_STAFF, CUSTOMER
  • Modern Stack: Django 5.2 + React 19 + TypeScript + Vite
  • Real-time Updates: Django Channels + WebSockets
  • Background Tasks: Celery + Redis
  • Auto SSL: Let's Encrypt certificates via Traefik
  • Cloud Storage: DigitalOcean Spaces (S3-compatible)
  • Docker Ready: Complete Docker Compose setup for dev and production

Project Structure

smoothschedule2/
├── frontend/                    # React + Vite + TypeScript
│   ├── src/
│   │   ├── api/                 # API client and hooks
│   │   ├── components/          # Reusable UI components
│   │   ├── hooks/               # React Query hooks
│   │   ├── pages/               # Page components
│   │   └── types.ts             # TypeScript interfaces
│   ├── nginx.conf               # Production nginx config
│   └── Dockerfile.prod          # Production frontend container
│
├── smoothschedule/              # Django backend
│   ├── config/                  # Django settings
│   │   └── settings/
│   │       ├── base.py          # Base settings
│   │       ├── local.py         # Local development
│   │       └── production.py    # Production settings
│   ├── smoothschedule/          # Django apps (domain-based)
│   │   ├── identity/            # Users, tenants, authentication
│   │   │   ├── core/            # Tenant, Domain, middleware
│   │   │   └── users/           # User model, MFA, auth
│   │   ├── scheduling/          # Core scheduling
│   │   │   ├── schedule/        # Resources, Events, Services
│   │   │   ├── contracts/       # E-signatures
│   │   │   └── analytics/       # Business analytics
│   │   ├── communication/       # Notifications, SMS, mobile
│   │   ├── commerce/            # Payments, tickets
│   │   └── platform/            # Admin, public API
│   ├── docker-compose.local.yml
│   └── docker-compose.production.yml
│
├── deploy.sh                    # Automated deployment script
└── CLAUDE.md                    # Development guide

Local Development Setup

Prerequisites

  • Docker and Docker Compose (for backend)
  • Node.js 22+ and npm (for frontend)
  • Git

Step 1: Clone the Repository

git clone https://github.com/your-repo/smoothschedule.git
cd smoothschedule

Step 2: Start the Backend (Django in Docker)

cd smoothschedule

# Start all backend services
docker compose -f docker-compose.local.yml up -d

# Wait for services to initialize (first time takes longer)
sleep 30

# Run database migrations
docker compose -f docker-compose.local.yml exec django python manage.py migrate

# Create a superuser (optional)
docker compose -f docker-compose.local.yml exec django python manage.py createsuperuser

Step 3: Start the Frontend (React with Vite)

cd ../frontend

# Install dependencies
npm install

# Start development server
npm run dev

Step 4: Access the Application

The application uses lvh.me (resolves to 127.0.0.1) for subdomain-based multi-tenancy:

URL Purpose
http://platform.lvh.me:5173 Platform admin dashboard
http://demo.lvh.me:5173 Demo tenant (if created)
http://lvh.me:8000/api/ Backend API
http://lvh.me:8000/admin/ Django admin

Why lvh.me? Browsers don't allow cookies with domain=.localhost, but lvh.me resolves to 127.0.0.1 and allows proper cookie sharing across subdomains.

Local Development Commands

# Backend commands (always use docker compose)
cd smoothschedule

# View logs
docker compose -f docker-compose.local.yml logs -f django

# Run migrations
docker compose -f docker-compose.local.yml exec django python manage.py migrate

# Django shell
docker compose -f docker-compose.local.yml exec django python manage.py shell

# Run tests
docker compose -f docker-compose.local.yml exec django pytest

# Stop all services
docker compose -f docker-compose.local.yml down

# Frontend commands
cd frontend

# Run tests
npm test

# Type checking
npm run typecheck

# Lint
npm run lint

Creating a Test Tenant

cd smoothschedule
docker compose -f docker-compose.local.yml exec django python manage.py shell
from smoothschedule.identity.core.models import Tenant, Domain

# Create tenant
tenant = Tenant.objects.create(
    name="Demo Business",
    schema_name="demo",
)

# Create domain
Domain.objects.create(
    domain="demo.lvh.me",
    tenant=tenant,
    is_primary=True,
)

print(f"Created tenant: {tenant.name}")
print(f"Access at: http://demo.lvh.me:5173")

Production Deployment

Prerequisites

  • Ubuntu/Debian server with Docker and Docker Compose
  • Domain name with DNS configured:
    • A record: yourdomain.com → Server IP
    • A record: *.yourdomain.com → Server IP (wildcard)
  • SSH access to the server

Quick Deploy (Existing Server)

For routine updates to an existing production server:

# From your local machine
./deploy.sh user@yourdomain.com

# Or deploy specific services
./deploy.sh user@yourdomain.com nginx
./deploy.sh user@yourdomain.com django

Fresh Server Deployment

Step 1: Server Setup

SSH into your server and install Docker:

ssh user@yourdomain.com

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

# Logout and login for group changes
exit
ssh user@yourdomain.com

Step 2: Clone Repository

cd ~
git clone https://github.com/your-repo/smoothschedule.git smoothschedule
cd smoothschedule

Step 3: Configure Environment Variables

Create production environment files:

mkdir -p smoothschedule/.envs/.production

# Django configuration
cat > smoothschedule/.envs/.production/.django << 'EOF'
DJANGO_SECRET_KEY=your-random-secret-key-here
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=yourdomain.com,*.yourdomain.com

DJANGO_ADMIN_URL=your-secret-admin-path/
FRONTEND_URL=https://platform.yourdomain.com
PLATFORM_BASE_URL=https://platform.yourdomain.com

REDIS_URL=redis://redis:6379/0
CELERY_BROKER_URL=redis://redis:6379/0

# DigitalOcean Spaces (or S3)
DJANGO_AWS_ACCESS_KEY_ID=your-access-key
DJANGO_AWS_SECRET_ACCESS_KEY=your-secret-key
DJANGO_AWS_STORAGE_BUCKET_NAME=your-bucket
DJANGO_AWS_S3_ENDPOINT_URL=https://nyc3.digitaloceanspaces.com
DJANGO_AWS_S3_REGION_NAME=nyc3

# SSL
DJANGO_SECURE_SSL_REDIRECT=True
DJANGO_SESSION_COOKIE_SECURE=True
DJANGO_CSRF_COOKIE_SECURE=True

# Cloudflare (for wildcard SSL)
CF_DNS_API_TOKEN=your-cloudflare-api-token
EOF

# PostgreSQL configuration
cat > smoothschedule/.envs/.production/.postgres << 'EOF'
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=smoothschedule
POSTGRES_USER=smoothschedule_user
POSTGRES_PASSWORD=your-secure-database-password
EOF

Step 4: Build and Start

cd ~/smoothschedule/smoothschedule

# Build all images
docker compose -f docker-compose.production.yml build

# Start services
docker compose -f docker-compose.production.yml up -d

# Wait for startup
sleep 30

# Run migrations
docker compose -f docker-compose.production.yml exec django python manage.py migrate

# Collect static files
docker compose -f docker-compose.production.yml exec django python manage.py collectstatic --noinput

# Create superuser
docker compose -f docker-compose.production.yml exec django python manage.py createsuperuser

Step 5: Verify Deployment

# Check all containers are running
docker compose -f docker-compose.production.yml ps

# View logs
docker compose -f docker-compose.production.yml logs -f

# Test endpoints
curl https://yourdomain.com/api/health/

Production URLs

URL Purpose
https://yourdomain.com Marketing site
https://platform.yourdomain.com Platform admin
https://*.yourdomain.com Tenant subdomains
https://api.yourdomain.com API (if configured)
https://yourdomain.com:5555 Flower (Celery monitoring)

Production Management Commands

ssh user@yourdomain.com
cd ~/smoothschedule/smoothschedule

# View logs
docker compose -f docker-compose.production.yml logs -f django

# Restart services
docker compose -f docker-compose.production.yml restart

# Run migrations
docker compose -f docker-compose.production.yml exec django python manage.py migrate

# Django shell
docker compose -f docker-compose.production.yml exec django python manage.py shell

# Database backup
docker compose -f docker-compose.production.yml exec postgres pg_dump -U smoothschedule_user smoothschedule > backup.sql

Architecture

Multi-Tenancy Model

PostgreSQL Database
├── public (shared schema)
│   ├── Tenants
│   ├── Domains
│   ├── Users
│   └── PermissionGrants
├── demo (tenant schema)
│   ├── Resources
│   ├── Events
│   ├── Services
│   └── Customers
└── acme (tenant schema)
    ├── Resources
    ├── Events
    └── ...

Role Hierarchy

Role Level Access
SUPERUSER Platform All tenants (god mode)
PLATFORM_MANAGER Platform All tenants
PLATFORM_SALES Platform Demo accounts only
PLATFORM_SUPPORT Platform Can masquerade as tenant users
TENANT_OWNER Tenant Full tenant access
TENANT_MANAGER Tenant Most tenant features
TENANT_STAFF Tenant Limited tenant access
CUSTOMER Tenant Own data only

Request Flow

Browser → Traefik (SSL) → nginx (frontend) or django (API)
                              ↓
                         React SPA
                              ↓
                    /api/* → django:5000
                    /ws/*  → django:5000 (WebSocket)

Configuration Files

Backend

File Purpose
smoothschedule/docker-compose.local.yml Local Docker services
smoothschedule/docker-compose.production.yml Production Docker services
smoothschedule/.envs/.local/ Local environment variables
smoothschedule/.envs/.production/ Production environment variables
smoothschedule/config/settings/ Django settings
smoothschedule/compose/production/traefik/traefik.yml Traefik routing config

Frontend

File Purpose
frontend/.env.development Local environment variables
frontend/.env.production Production environment variables
frontend/nginx.conf Production nginx config
frontend/vite.config.ts Vite bundler config

Troubleshooting

Backend won't start

# Check Docker logs
docker compose -f docker-compose.local.yml logs django

# Common issues:
# - Database not ready: wait longer, then restart django
# - Missing migrations: run migrate command
# - Port conflict: check if 8000 is in use

Frontend can't connect to API

# Verify backend is running
curl http://lvh.me:8000/api/

# Check CORS settings in Django
# Ensure CORS_ALLOWED_ORIGINS includes http://platform.lvh.me:5173

WebSockets disconnecting

# Check nginx has /ws/ proxy configured
# Verify django is running ASGI (Daphne)
# Check production traefik/nginx logs

Multi-tenant issues

# Check tenant exists
docker compose exec django python manage.py shell
>>> from smoothschedule.identity.core.models import Tenant, Domain
>>> Tenant.objects.all()
>>> Domain.objects.all()

Additional Documentation


License

MIT

Description
No description provided
Readme 111 MiB
Languages
TypeScript 58.2%
Python 21.8%
HTML 18.8%
JavaScript 0.4%
Shell 0.3%
Other 0.4%