Files
smoothschedule/smoothschedule/SANDBOX_MODE_IMPLEMENTATION.md
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

6.0 KiB

Sandbox Mode Implementation Summary

Overview

Sandbox/Test mode provides complete data isolation for testing. Users can toggle between Live and Test modes via a switch in the header. Each mode has its own:

  • Database schema (for tenant-specific data like appointments, resources, services)
  • Customer records (filtered by is_sandbox flag on User model)

Architecture

Backend Components

  1. Tenant Model (core/models.py)

    • sandbox_schema_name: PostgreSQL schema for sandbox data (e.g., demo_sandbox)
    • sandbox_enabled: Boolean to enable/disable sandbox for tenant
    • Auto-generates sandbox schema name on save
  2. SandboxModeMiddleware (core/middleware.py:16-118)

    • Switches database schema based on:
      • API token prefix (ss_test_* = sandbox, ss_live_* = live)
      • X-Sandbox-Mode: true header
      • Session value sandbox_mode
    • Sets request.sandbox_mode = True/False for views to use
    • MUST run AFTER SessionMiddleware in middleware order
  3. User Model (smoothschedule/users/models.py)

    • is_sandbox: Boolean field to mark sandbox customers
    • Live customers have is_sandbox=False, test customers have is_sandbox=True
  4. API Endpoints (schedule/api_views.py)

    • GET /api/sandbox/status/ - Get current sandbox state
    • POST /api/sandbox/toggle/ - Toggle sandbox mode (sets session)
  5. CustomerViewSet (schedule/views.py:199-249)

    • Filters customers by request.sandbox_mode
    • perform_create sets is_sandbox based on current mode
  6. StaffViewSet (schedule/views.py:302-366)

    • Filters staff by request.sandbox_mode
    • Staff created via invitations inherit sandbox mode from request
  7. TicketViewSet (tickets/views.py:65-167)

    • Filters tickets by request.sandbox_mode (except PLATFORM tickets)
    • perform_create sets is_sandbox based on current mode
    • PLATFORM tickets are always created in live mode
  8. PublicCustomerViewSet (public_api/views.py:888-968)

    • Also filters by sandbox mode for API customers
  9. APIToken Model (public_api/models.py)

    • is_sandbox: Boolean for token type
    • Key prefixes: ss_test_* (sandbox) or ss_live_* (live)

Frontend Components

  1. SandboxContext (contexts/SandboxContext.tsx)

    • Provides isSandbox, sandboxEnabled, toggleSandbox, isToggling
    • Syncs state to localStorage for API client
  2. SandboxToggle (components/SandboxToggle.tsx)

    • Toggle switch component with Live/Test labels
  3. SandboxBanner (components/SandboxBanner.tsx)

    • Orange warning banner shown in test mode
  4. API Client (api/client.ts:23-51)

    • Reads localStorage.getItem('sandbox_mode')
    • Adds X-Sandbox-Mode: true header when in sandbox
  5. BusinessLayout (layouts/BusinessLayout.tsx)

    • Wrapped with SandboxProvider
    • Shows SandboxBanner when in test mode
  6. TopBar (components/TopBar.tsx)

    • Includes SandboxToggle component

Configuration

  1. CORS (config/settings/local.py:75-78)

    • x-sandbox-mode added to CORS_ALLOW_HEADERS
  2. Middleware Order (config/settings/multitenancy.py:89-122)

    • SandboxModeMiddleware MUST come AFTER SessionMiddleware

Database Schemas

Each tenant has two schemas:

  • {tenant_name} - Live data (e.g., demo)
  • {tenant_name}_sandbox - Test data (e.g., demo_sandbox)

Schemas created via: python manage.py create_sandbox_schemas

What's Isolated

Data Type Isolation Method
Appointments/Events Schema switching (automatic)
Resources Schema switching (automatic)
Services Schema switching (automatic)
Payments Schema switching (automatic)
Notifications Schema switching (automatic)
Communication Schema switching (automatic)
Customers is_sandbox field on User model
Staff Members is_sandbox field on User model
Tickets (CUSTOMER/STAFF_REQUEST/INTERNAL) is_sandbox field on Ticket model
Tickets (PLATFORM) NOT isolated (always live - platform support)
Business Settings (Tenant) NOT isolated (shared between modes)

Key Files Modified

Backend

  • core/models.py - Tenant sandbox fields
  • core/middleware.py - SandboxModeMiddleware
  • smoothschedule/users/models.py - User.is_sandbox field
  • smoothschedule/users/api_views.py - accept_invitation_view sets is_sandbox
  • schedule/views.py - CustomerViewSet and StaffViewSet sandbox filtering
  • schedule/api_views.py - sandbox_status_view, sandbox_toggle_view
  • tickets/models.py - Ticket.is_sandbox field
  • tickets/views.py - TicketViewSet sandbox filtering
  • public_api/models.py - APIToken.is_sandbox
  • public_api/views.py - PublicCustomerViewSet sandbox filtering
  • config/settings/local.py - CORS headers
  • config/settings/multitenancy.py - Middleware order, tickets in SHARED_APPS

Frontend

  • src/api/sandbox.ts - API functions
  • src/api/client.ts - X-Sandbox-Mode header
  • src/hooks/useSandbox.ts - React Query hooks
  • src/contexts/SandboxContext.tsx - Context provider
  • src/components/SandboxToggle.tsx - Toggle UI
  • src/components/SandboxBanner.tsx - Warning banner
  • src/components/TopBar.tsx - Added toggle
  • src/layouts/BusinessLayout.tsx - Provider + banner
  • src/i18n/locales/en.json - Translations

Migrations

# Migrations for User.is_sandbox and Ticket.is_sandbox fields
cd /home/poduck/Desktop/smoothschedule2/smoothschedule
docker compose -f docker-compose.local.yml exec django python manage.py migrate

Current State

  • Sandbox mode toggle works
  • CORS configured for X-Sandbox-Mode header
  • Customer isolation by is_sandbox field implemented
  • Staff isolation by is_sandbox field implemented
  • Ticket isolation by is_sandbox field implemented (except PLATFORM tickets)
  • Appointments/Events/Resources/Services automatically isolated via schema switching
  • Existing users are is_sandbox=False (live)
  • Existing tickets are is_sandbox=False (live)
  • Test mode shows empty data (clean sandbox)