poduck a9719a5fd2 feat: Add comprehensive sandbox mode, public API system, and platform support
This commit adds major features for sandbox isolation, public API access, and platform support ticketing.

## Sandbox Mode
- Add sandbox mode toggle for businesses to test features without affecting live data
- Implement schema-based isolation for tenant data (appointments, resources, services)
- Add is_sandbox field filtering for shared models (customers, staff, tickets)
- Create sandbox middleware to detect and set sandbox mode from cookies
- Add sandbox context and hooks for React frontend
- Display sandbox banner when in test mode
- Auto-reload page when switching between live/test modes
- Prevent platform support tickets from being created in sandbox mode

## Public API System
- Full REST API for external integrations with businesses
- API token management with sandbox/live token separation
- Test tokens (ss_test_*) show full plaintext for easy testing
- Live tokens (ss_live_*) are hashed and secure
- Security validation prevents live token plaintext storage
- Comprehensive test suite for token security
- Rate limiting and throttling per token
- Webhook support for real-time event notifications
- Scoped permissions system (read/write per resource type)
- API documentation page with interactive examples
- Token revocation with confirmation modal

## Platform Support
- Dedicated support page for businesses to contact SmoothSchedule
- View all platform support tickets in one place
- Create new support tickets with simplified interface
- Reply to existing tickets with conversation history
- Platform tickets have no admin controls (no priority/category/assignee/status)
- Internal notes hidden for platform tickets (business can't see them)
- Quick help section with links to guides and API docs
- Sandbox warning prevents ticket creation in test mode
- Business ticketing retains full admin controls (priority, assignment, internal notes)

## UI/UX Improvements
- Add notification dropdown with real-time updates
- Staff permissions UI for ticket access control
- Help dropdown in sidebar with Platform Guide, Ticketing Help, API Docs, and Support
- Update sidebar "Contact Support" to "Support" with message icon
- Fix navigation links to use React Router instead of anchor tags
- Remove unused language translations (Japanese, Portuguese, Chinese)

## Technical Details
- Sandbox middleware sets request.sandbox_mode from cookies
- ViewSets filter data by is_sandbox field
- API authentication via custom token auth class
- WebSocket support for real-time ticket updates
- Migration for sandbox fields on User, Tenant, and Ticket models
- Comprehensive documentation in SANDBOX_MODE_IMPLEMENTATION.md

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 16:44:06 -05:00

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

chmod +x setup_project.sh
./setup_project.sh
cd smoothschedule

2. Configure Environment

Create .env file:

# 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

docker-compose build
docker-compose up -d

4. Run Migrations

# 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

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,
)
# 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:

{
  "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:

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:

TENANT_APPS = [
    'django.contrib.contenttypes',
    'appointments',   # Your app
    'resources',      # Your app
    'billing',        # Your app
]

Custom Domain Setup

domain = Domain.objects.create(
    domain="app.customdomain.com",
    tenant=tenant,
    is_custom_domain=True,
    route53_zone_id="Z1234567890ABC",
)

Then configure Route53 CNAME: app.customdomain.comsmoothschedule.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

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