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

152 lines
6.0 KiB
Markdown

# 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
```bash
# 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)