poduck c36025f018 feat: Add description field to PluginTemplateListSerializer
The description field is now included in marketplace listing responses,
allowing the frontend to display full plugin descriptions with formatting,
bullet points, and detailed benefits.

All 6 platform plugins now return complete information:
- Name, author (Smooth Schedule), version (1.0.0)
- Short description (one-line summary)
- Full description (multi-paragraph with bullets)
- Category, ratings, install count

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:58:57 -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%