- Switched production start script from Gunicorn to Daphne to support WebSockets.
- Updated VITE_API_URL in frontend production env to 'https://api.smoothschedule.com', removing the '/api' prefix to align with the backend URL refactor.
- Implemented TenantHeaderMiddleware to switch the database tenant schema based on the 'X-Business-Subdomain' request header.
- This allows API requests directed to the centralized 'api' subdomain (e.g., api.lvh.me) to correctly access tenant-specific data when the header is present.
- Registered the middleware in multitenancy settings after TenantMainMiddleware.
The Timeline component was using a raw axios instance with hardcoded URLs, causing it to bypass authentication and tenant context headers. This resulted in empty or failed data fetches. Updated it to use the configured 'apiClient', ensuring that the authentication token and 'X-Business-Subdomain' headers are correctly sent, allowing the backend to return the appropriate tenant-specific resources and appointments.
The email verification link was incorrectly including a hash fragment (/#/), which caused the React Router (using BrowserRouter) to misinterpret the path as the root path, leading to a redirect to the default 'email-verification-required' page instead of the 'verify-email' page. This commit removes the hash, ensuring the link correctly points to /verify-email.
- Updated all API endpoint strings in 'frontend/src' (via sed and manual fixes) to remove the '/api/' prefix.
- Manually fixed 'Timeline.tsx' absolute URLs to use the 'api' subdomain and correct path.
- Manually fixed 'useAuth.ts' logout fetch URLs.
- Updated 'HelpApiDocs.tsx' sandbox URL.
- This change, combined with the backend URL update, fully transitions the application to use subdomain-based routing (e.g., 'http://api.lvh.me:8000/resource/') instead of path-prefix routing (e.g., 'http://api.lvh.me:8000/api/resource/').
- Removed '/api/' prefix from endpoint paths in auth.ts, notifications.ts, oauth.ts, and platform.ts to align with the backend URL reconfiguration.
- Updated 'API_BASE_URL' in config.ts to remove the '/api' suffix, ensuring that API requests are correctly routed to the root of the 'api' subdomain (e.g., http://api.lvh.me:8000/).
- Included improvements to login redirect logic in client.ts.
This commit addresses the persistent WebSocket disconnection and reconnection
problem experienced with ticket updates. The root cause was identified as the
Django backend not running as an ASGI server, which is essential for WebSocket
functionality, and incorrect WebSocket routing.
The following changes were made:
- **Frontend ():**
- Updated to append the from cookies to the WebSocket URL's
query parameter for authentication, ensuring the token is sent with the
WebSocket connection request.
- **Backend Configuration:**
- **:** Modified to explicitly
start the Daphne ASGI server using instead
of . This ensures the backend runs in ASGI
mode, capable of handling WebSocket connections.
- **:** Removed 'daphne' from
. Daphne is an ASGI server, not a traditional Django
application, and its presence in was causing application
startup failures.
- **:**
- Removed from as it
conflicts with Channels' ASGI server takeover.
- Explicitly set to ensure
the ASGI entry point is correctly referenced.
- **:** Added 'channels'
to , ensuring the Channels application is correctly loaded
within the multi-tenant setup, enabling ASGI functionality.
- **Backend Middleware & Routing:**
- **:** Implemented a custom
to authenticate WebSocket connections using an
from either a query parameter or cookies. This middleware
ensures proper user authentication for WebSocket sessions. Debugging
prints with were added for better visibility.
- **:** Adjusted WebSocket URL regexes
to for robustness, ensuring correct matching
regardless of leading/trailing slashes in the path.
These changes collectively ensure that WebSocket connections are properly
initiated by the frontend, authenticated by the backend, and served by
an ASGI-compliant server, resolving the frequent disconnection/reconnection
issue.
Root cause: CorsMiddleware was positioned after TenantMainMiddleware, which
prevented CORS headers from being set. The tenant middleware processes requests
before CORS middleware could add the necessary headers.
Changes:
- Moved CorsMiddleware to first position in MIDDLEWARE stack
- Added CORS_ALLOW_ALL_ORIGINS configuration (for testing only)
- Updated production CORS regex to match both base and subdomains
- Created public tenant and registered production domains
- Re-enabled CORS_URLS_REGEX for API security
This fix ensures proper CORS headers are sent for cross-origin requests from
smoothschedule.com domains to api.smoothschedule.com.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Platform users need to send notifications to business tenants, so the
notifications app must be in SHARED_APPS (public schema) rather than
TENANT_APPS (tenant-specific schemas).
Changes:
- Moved notifications from TENANT_APPS to SHARED_APPS in multitenancy.py
- Run migrations on public schema to create notifications tables
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added http://lvh.me:5173 and http://lvh.me:5174 to CORS_ALLOWED_ORIGINS
- Added regex pattern to allow all *.lvh.me subdomains in CORS_ALLOWED_ORIGIN_REGEXES
- This allows frontend at lvh.me:5173 to make requests to API at api.lvh.me:8000
- CORS preflight requests now return proper Access-Control-Allow-Origin headers
- Quick login and all API calls from frontend now work without CORS errors
Testing confirmed:
✓ OPTIONS request to /api/auth-token/ returns 200 OK with CORS headers
✓ Access-Control-Allow-Origin: http://lvh.me:5173
✓ Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed VITE_API_URL from localhost:8000 to api.lvh.me:8000
- Registered api.lvh.me domain in database pointing to public schema
- This maintains consistency between development and production where
api subdomain is used for API access
- All test users can now authenticate via quick login
The development setup now mirrors production:
- Production: api.smoothschedule.com → Django API
- Development: api.lvh.me:8000 → Django API (via docker container)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Settings Refactoring Fixes:
- Add minimal LOGGING structure to base.py for multitenancy.py to extend
- Restore LOGGING import in multitenancy.py
- Add development LOGGING configuration to local.py
- This allows multitenancy.py to extend LOGGING configuration properly
Quick Login Fix:
- Update frontend .env.development to use VITE_API_URL=http://localhost:8000
- Previous configuration tried to access api.lvh.me which failed due to
django-tenants not recognizing that hostname
- Using localhost:8000 directly bypasses subdomain routing and accesses
the public schema where auth endpoints are available
Both fixes restore full functionality:
- Django now starts without import errors in local development
- Quick login API calls now succeed and return authentication tokens
- Frontend can authenticate users for development/testing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Move CORS_ALLOWED_ORIGINS to base.py, configurable via DJANGO_CORS_ALLOWED_ORIGINS env var
- Move CORS_ALLOWED_ORIGIN_REGEXES to base.py, configurable via DJANGO_CORS_ALLOWED_ORIGIN_REGEXES
- Move CSRF_TRUSTED_ORIGINS to base.py, configurable via DJANGO_CSRF_TRUSTED_ORIGINS
- Remove duplicate CORS/CSRF config from local.py (now inherits from base)
- Remove production-specific CORS config (now uses env vars from base)
- Allows development and production to use same settings with different .env variables
- Add CORS_ALLOWED_ORIGINS configurable via DJANGO_CORS_ALLOWED_ORIGINS env var
- Add CORS_ALLOWED_ORIGIN_REGEXES for wildcard subdomains
- Add CSRF_TRUSTED_ORIGINS for production domain
- Support custom domains via DJANGO_DOMAIN_NAME env var
- Use corsheaders.defaults for standard CORS headers
- Add custom headers: x-business-subdomain, x-sandbox-mode
This commit adds all previously untracked files and modifications needed for production deployment:
- New marketing components (BenefitsSection, CodeBlock, PluginShowcase, PricingTable)
- Platform admin components (EditPlatformEntityModal, PlatformListRow, PlatformListing, PlatformTable)
- Updated deployment configuration and scripts
- Various frontend API and component improvements
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed double /api/api/ issue in production
- Updated all API files to remove /api/ prefix since baseURL already includes it
- Files fixed: platform.ts, oauth.ts, customDomains.ts, domains.ts, business.ts, sandbox.ts
- Production build will need to be rebuilt after pulling these changes
When VITE_API_URL=/api, axios baseURL is already set to /api. However, all endpoint calls included the /api/ prefix, creating double paths like /api/api/auth/login/.
Removed /api/ prefix from 81 API endpoint calls across 22 files:
- src/api/auth.ts - Fixed login, logout, me, refresh, hijack endpoints
- src/api/client.ts - Fixed token refresh endpoint
- src/api/profile.ts - Fixed all profile, email, password, MFA, sessions endpoints
- src/hooks/*.ts - Fixed all remaining API calls (users, appointments, resources, etc)
- src/pages/*.tsx - Fixed signup and email verification endpoints
This ensures API requests use the correct path: /api/auth/login/ instead of /api/api/auth/login/
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Add OAuthCredential model for storing Google/Microsoft OAuth tokens
- Add email provider auto-detection endpoint (Gmail, Outlook, Yahoo, etc.)
- Add EmailConfigWizard frontend component with step-by-step setup
- Add OAuth flow endpoints for Google and Microsoft XOAUTH2
- Update production settings to make AWS, Sentry, Mailgun optional
- Update Traefik config for wildcard subdomain routing
- Add logo resize utility script
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add SMTP fields to TicketEmailSettings model (host, port, TLS/SSL, credentials, from email/name)
- Update serializers with SMTP fields and is_smtp_configured flag
- Add TicketEmailTestSmtpView for testing SMTP connections
- Update frontend API types and hooks for SMTP settings
- Add collapsible IMAP and SMTP configuration sections with "Configured" badges
- Fix TypeScript errors in mockData.ts (missing required fields, type mismatches)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add GlobalEventPlugin model for auto-attaching plugins to all events
- Create signals for auto-attachment on new events and rescheduling
- Add API endpoints for global event plugins (CRUD, toggle, reapply)
- Update CreateTaskModal with "Scheduled Task" vs "Event Automation" choice
- Add option to apply to all events or future events only
- Display event automations in Tasks page alongside scheduled tasks
- Add EditEventAutomationModal for editing trigger and timing
- Handle event reschedule - update Celery task timing on time/duration changes
- Add Marketplace to Plugins menu in sidebar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Backend Changes:
- Enhanced PluginTemplate.save() to auto-parse template variables from plugin code
- Updated PluginInstallationSerializer to expose template metadata (description, category, version, author, logo, template_variables)
- Fixed template variable parser to handle nested {{ }} braces in default values
- Added brace-counting algorithm to properly extract variables with insertion codes
- Fixed explicit type parameter detection (textarea, text, email, etc.)
- Made scheduled_task optional on PluginInstallation model
- Added EventPlugin through model for event-plugin relationships
- Added Event.execute_plugins() method for plugin automation
## Frontend Changes:
- Created Tasks.tsx page for managing scheduled tasks
- Enhanced MyPlugins page with clickable plugin cards
- Added edit configuration modal with dynamic form generation
- Implemented escape sequence handling (convert \n, \', etc. for display)
- Added plugin logos to My Plugins page
- Updated type definitions for PluginInstallation interface
- Added insertion code documentation to Plugin Docs
## Plugin System:
- All platform plugins now have editable email templates with textarea support
- Template variables properly parsed with full default values
- Insertion codes ({{CUSTOMER_NAME}}, {{BUSINESS_NAME}}, etc.) documented
- Plugin logos displayed in marketplace and My Plugins
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
1. Changed "Install" button to "View" button with Eye icon
- Removed separate "Details" button
- Single "View" button now opens the details modal
2. Fixed author mapping to use author_name from API
3. Fixed rating field to use rating_average from API
4. Set isVerified based on visibility === 'PLATFORM'
The modal now correctly displays:
- Plugin name with verified badge for platform plugins
- Author name (e.g., "Smooth Schedule")
- Version number
- Full description with formatting
- Category, ratings, and install count
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Changes:
1. Added version field to PluginTemplate model (default: 1.0.0)
2. Updated platform plugins with detailed descriptions
3. Changed author_name from "SmoothSchedule Platform" to "Smooth Schedule"
4. Enhanced seed_platform_plugins command with comprehensive descriptions
Plugin descriptions now include:
- Detailed explanations of functionality
- Benefits and use cases
- Key features in bullet points
All 6 platform plugins now have:
- Version: 1.0.0
- Author: Smooth Schedule
- Rich, marketing-friendly descriptions
Migration: 0016_plugintemplate_version
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
1. Updated PluginTemplateViewSet.get_queryset() to include PLATFORM
visibility plugins in marketplace view alongside approved PUBLIC plugins
2. Fixed PluginTemplateListSerializer read_only_fields from string '__all__'
to proper list reference
Platform plugins are now visible in the marketplace API:
- 6 platform-created plugins seeded via seed_platform_plugins command
- Categories: EMAIL, REPORTS, CUSTOMER, BOOKING
- All marked as visibility=PLATFORM, is_approved=True
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Users can access the marketplace via the "Browse Marketplace" button
on the My Plugins page, so the redundant sidebar link has been removed.
The Plugins dropdown now contains:
- My Plugins
- Plugin Docs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit completes the plugin system UI by adding two key pages:
1. Plugin Marketplace (/plugins/marketplace):
- Browse and search platform-provided plugins
- Filter by category (EMAIL, REPORTS, CUSTOMER, BOOKING, etc.)
- View plugin details including ratings, install count, description
- Install plugins with one click
- Modal view for detailed plugin information
2. My Plugins (/plugins/my-plugins):
- View all installed plugins
- Manage plugin activation status
- Update plugins when new versions available
- Rate and review installed plugins
- Uninstall plugins with confirmation
- Links to create custom plugins and browse marketplace
Additional changes:
- Added plugin routes to App.tsx with owner/manager access control
- Updated HelpPluginDocs.tsx with navigation callout boxes
- Added TypeScript interfaces for PluginTemplate and PluginInstallation
- Both pages feature full dark mode support
- Professional UI with Tailwind CSS styling
- React Query integration for data fetching
The pages are accessible from the Plugins dropdown menu in the sidebar.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added Plugins collapsible menu with 3 items:
- Plugin Marketplace (/plugins/marketplace)
- My Plugins (/plugins/my-plugins)
- Plugin Docs (/help/plugins)
- Moved Plugin Docs from Help dropdown to Plugins dropdown
- Added Plug, ShoppingBag, Package icons from lucide-react
- Added translations for plugin navigation items
- Auto-opens dropdown when on /plugins/* routes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Backend Features:
- Created PluginTemplate and PluginInstallation models
- Built complete REST API with marketplace, my plugins, install/uninstall endpoints
- Platform plugins supported (PLATFORM visibility, no whitelisting required)
- Template variable extraction and compilation
- Plugin approval workflow for marketplace publishing
- Rating and review system
- Update detection and version management
- Install count tracking
API Endpoints:
- GET /api/plugin-templates/ - Browse marketplace (view=marketplace/my_plugins/platform)
- POST /api/plugin-templates/ - Create new plugin
- POST /api/plugin-templates/{id}/install/ - Install plugin as ScheduledTask
- POST /api/plugin-templates/{id}/publish/ - Publish to marketplace
- POST /api/plugin-templates/{id}/approve/ - Approve for marketplace (admins)
- POST /api/plugin-installations/{id}/rate/ - Rate and review
- POST /api/plugin-installations/{id}/update_to_latest/ - Update plugin
- DELETE /api/plugin-installations/{id}/ - Uninstall plugin
Platform Plugins:
- Created seed_platform_plugins management command
- 6 starter plugins ready: daily summary, no-show tracker, birthdays, revenue reports, reminders, re-engagement
- Platform plugins bypass whitelist validation
- Pre-approved and available to all businesses
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented static code analysis to detect and validate HTTP calls in plugins
before they are uploaded or approved for the marketplace.
**New Functions:**
1. **analyze_plugin_http_calls(script):**
- Parses plugin code using Python AST
- Detects all api.http_* method calls (GET, POST, PUT, PATCH, DELETE)
- Extracts URL from first argument if it's a string literal
- Handles dynamic URLs (f-strings, variables) with appropriate warnings
- Returns list of HTTP calls with method, URL, and line number
2. **validate_plugin_whitelist(script, scheduled_task):**
- Analyzes plugin code for HTTP calls
- Validates each detected URL against WhitelistedURL model
- Checks both platform-wide and plugin-specific whitelists
- Returns validation results with errors, warnings, and detected calls
- Provides clear error messages with line numbers
**Validation Logic:**
- **Static URLs** (string literals): Validated against whitelist, error if not found
- **Dynamic URLs** (f-strings, variables): Warning issued, runtime validation required
- **Syntax Errors**: Caught and reported as validation errors
- **Line Numbers**: All errors/warnings include line number for debugging
**Use Cases:**
1. Pre-upload validation: Check plugin before saving to database
2. Approval workflow: Platform staff can see which URLs need whitelisting
3. Marketplace submission: Reject plugins with non-whitelisted URLs
4. Security audit: Analyze existing plugins for HTTP call patterns
**Error Messages:**
- Clear, actionable messages with line numbers
- Direct users to pluginaccess@smoothschedule.com for whitelisting
- Warns about dynamic URLs that can't be statically validated
This enables proactive security enforcement before plugins are executed,
preventing runtime failures and improving user experience.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated all references to "Platform" in the licensing documentation to use
"SmoothSchedule" for better branding consistency:
- Changed "Platform Rights" to "SmoothSchedule Rights"
- Changed "Platform Service Rights" to "SmoothSchedule Service Rights"
- Changed "Platform Use" table header to "SmoothSchedule Use"
- Updated all inline references from "Platform" to "SmoothSchedule"
This makes the licensing terms more specific and branded while maintaining
the same legal structure and protections.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added new "Plugin Licensing" section to plugin documentation that covers:
**SmoothSchedule Community Plugin License (SCPL):**
- Custom license for marketplace plugins
- Grants platform rights to use, execute, host, and distribute code
- Grants users rights to install, use, and modify for their business
- Requires attribution to original author
- Allows users to adapt code but not republish without permission
- Permits authors to unpublish anytime (existing installs continue)
- Authors retain copyright and can license elsewhere
- Similar to MIT License + Platform Service Rights
**Private vs. Marketplace Plugins:**
- Private plugins: Full ownership, any license (or none), private to business
- Marketplace plugins: Must use SCPL, visible to all users, author credited
- Both types: Platform can execute code to provide automation service
**Key Features:**
- Comparison table showing differences between private and marketplace plugins
- Code verification and security requirements documented
- Decision guide for when to publish vs. keep private
- Important notices about warranties, compliance, and data privacy
- Platform service rights clearly explained
**Legal Protections:**
- Platform has rights to execute user code for service delivery
- No warranty disclaimer (plugins "as-is")
- User compliance responsibility for laws and regulations
- Data privacy obligations (GDPR, CCPA compliance)
The SCPL is designed to be marketplace-friendly while protecting both
the platform and plugin authors, similar to how npm/PyPI handle packages
but with added platform service rights for SaaS execution.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Backend Changes:
- Extended SafeScriptAPI to support all HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Created WhitelistedURL model for per-plugin and platform-wide URL whitelisting
- Added _validate_url() method with SSRF protection and private IP blocking
- Updated SafeScriptAPI to accept scheduled_task parameter for whitelist checking
- All HTTP methods now validate against whitelist before making requests
WhitelistedURL Model:
- Supports two scopes: PLATFORM (all plugins) and PLUGIN (specific plugin)
- Stores URL patterns with wildcard support (e.g., https://api.example.com/*)
- Tracks allowed HTTP methods per URL
- Includes approval workflow (approved_by, approved_at)
- Stores original plugin code for verification
- Domain-based indexing for fast lookup
- Database constraint ensures platform-wide entries have no plugin assigned
Security Features:
- SSRF prevention: blocks localhost, loopback, and private IP ranges
- Per-plugin whitelist: each ScheduledTask can only access its whitelisted URLs
- Platform-wide whitelist: approved URLs accessible by all plugins
- HTTP method validation: URLs must explicitly allow each method
- URL pattern matching with wildcard support
Related Models:
- WhitelistedURL.scheduled_task -> ScheduledTask (plugin that owns the whitelist)
- WhitelistedURL.approved_by -> User (platform user who approved the URL)
Migration: schedule/migrations/0014_whitelistedurl.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added complete plugin documentation with visual mockups and expanded template
variable system with CONTEXT, DATE helpers, and default values.
Backend Changes:
- Extended template_parser.py to support all new template types
- Added PROMPT with default values: {{PROMPT:var|desc|default}}
- Added CONTEXT variables: {{CONTEXT:business_name}}, {{CONTEXT:owner_email}}
- Added DATE helpers: {{DATE:today}}, {{DATE:+7d}}, {{DATE:monday}}
- Implemented date expression evaluation for relative dates
- Updated compile_template to handle all template types
- Added context parameter for business data auto-fill
Frontend Changes:
- Created comprehensive HelpPluginDocs.tsx with Stripe-style API docs
- Added visual mockup of plugin configuration form
- Documented all template types with examples and benefits
- Added Command Reference section with allowed/blocked Python commands
- Documented all HTTP methods (GET, POST, PUT, PATCH, DELETE)
- Added URL whitelisting requirements and approval process
- Created Platform Staff management page with edit modal
- Added can_approve_plugins and can_whitelist_urls permissions
Platform Staff Features:
- List all platform_manager and platform_support users
- Edit user details with role-based permissions
- Superusers can edit anyone
- Platform managers can only edit platform_support users
- Permission cascade: users can only grant permissions they have
- Real-time updates via React Query cache invalidation
Documentation Highlights:
- 4 template types: PROMPT, CONTEXT, DATE, and automatic validation
- Visual form mockup showing exactly what users see
- All allowed control flow (if/elif/else, for, while, try/except, etc.)
- All allowed built-in functions (len, range, min, max, etc.)
- All blocked operations (import, exec, eval, class/function defs)
- Complete HTTP API reference with examples
- URL whitelisting process: contact pluginaccess@smoothschedule.com🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
Assignee Dropdown:
- Fix useUsers hook to fetch from /api/staff/ endpoint
- Add useStaffForAssignment hook for formatted dropdown data
- Update TicketModal to use new hook for assignee selection
Staff Permissions UI:
- Add "Can access support tickets" permission to invite modal for both managers and staff
- Add permission to edit modal for both managers and staff
- Managers default to having ticket access enabled
- Staff default to having ticket access disabled (must be explicitly granted)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
WebSocket Updates:
- Create useTicketWebSocket hook for real-time ticket list updates
- Hook invalidates React Query cache when tickets are created/updated
- Shows toast notifications for new tickets and comments
- Auto-reconnect with exponential backoff
Staff Permissions:
- Add can_access_tickets() method to User model
- Owners and managers always have ticket access
- Staff members need explicit can_access_tickets permission
- Update Sidebar to conditionally show Tickets menu based on permission
- Add can_access_tickets to API user response
Backend Updates:
- Update ticket signals to broadcast updates to all relevant users
- Check ticket access permission in views
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>