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>
This commit is contained in:
@@ -1,4 +1,27 @@
|
||||
{
|
||||
"sandbox": {
|
||||
"live": "Live",
|
||||
"test": "Test",
|
||||
"liveMode": "Live Mode - Production data",
|
||||
"testMode": "Test Mode - Sandbox data",
|
||||
"bannerTitle": "TEST MODE",
|
||||
"bannerDescription": "You are viewing test data. Changes here won't affect your live business.",
|
||||
"switchToLive": "Switch to Live",
|
||||
"switching": "Switching...",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"openNotifications": "Open notifications",
|
||||
"noNotifications": "No notifications yet",
|
||||
"markAllRead": "Mark all as read",
|
||||
"clearRead": "Clear read",
|
||||
"viewAll": "View all",
|
||||
"justNow": "Just now",
|
||||
"minutesAgo": "{{count}}m ago",
|
||||
"hoursAgo": "{{count}}h ago",
|
||||
"daysAgo": "{{count}}d ago"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Loading...",
|
||||
"error": "Error",
|
||||
@@ -65,7 +88,124 @@
|
||||
"users": "Users",
|
||||
"support": "Support",
|
||||
"platformSettings": "Platform Settings",
|
||||
"tickets": "Tickets"
|
||||
"tickets": "Tickets",
|
||||
"help": "Help",
|
||||
"platformGuide": "Platform Guide",
|
||||
"ticketingHelp": "Ticketing System",
|
||||
"apiDocs": "API Docs",
|
||||
"contactSupport": "Contact Support"
|
||||
},
|
||||
"help": {
|
||||
"guide": {
|
||||
"title": "Platform Guide",
|
||||
"subtitle": "Learn how to use SmoothSchedule effectively",
|
||||
"comingSoon": "Coming Soon",
|
||||
"comingSoonDesc": "We are working on comprehensive documentation to help you get the most out of SmoothSchedule. Check back soon!"
|
||||
},
|
||||
"api": {
|
||||
"title": "API Reference",
|
||||
"interactiveExplorer": "Interactive Explorer",
|
||||
"introduction": "Introduction",
|
||||
"introDescription": "The SmoothSchedule API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes.",
|
||||
"introTestMode": "You can use the SmoothSchedule API in test mode, which doesn't affect your live data. The API key you use determines whether the request is test mode or live mode.",
|
||||
"baseUrl": "Base URL",
|
||||
"baseUrlDescription": "All API requests should be made to:",
|
||||
"sandboxMode": "Sandbox Mode:",
|
||||
"sandboxModeDescription": "Use the sandbox URL for development and testing. All examples in this documentation use test API keys that work with the sandbox.",
|
||||
"authentication": "Authentication",
|
||||
"authDescription": "The SmoothSchedule API uses API keys to authenticate requests. You can view and manage your API keys in your Business Settings.",
|
||||
"authBearer": "Authentication to the API is performed via Bearer token. Include your API key in the Authorization header of all requests.",
|
||||
"authWarning": "Your API keys carry many privileges, so be sure to keep them secure. Don't share your secret API keys in publicly accessible areas such as GitHub, client-side code, etc.",
|
||||
"apiKeyFormat": "API Key Format",
|
||||
"testKey": "Test/sandbox mode key",
|
||||
"liveKey": "Live/production mode key",
|
||||
"authenticatedRequest": "Authenticated Request",
|
||||
"keepKeysSecret": "Keep your keys secret!",
|
||||
"keepKeysSecretDescription": "Never expose API keys in client-side code, version control, or public forums.",
|
||||
"errors": "Errors",
|
||||
"errorsDescription": "SmoothSchedule uses conventional HTTP response codes to indicate the success or failure of an API request.",
|
||||
"httpStatusCodes": "HTTP Status Codes",
|
||||
"errorResponse": "Error Response",
|
||||
"statusOk": "The request succeeded.",
|
||||
"statusCreated": "A new resource was created.",
|
||||
"statusBadRequest": "Invalid request parameters.",
|
||||
"statusUnauthorized": "Invalid or missing API key.",
|
||||
"statusForbidden": "The API key lacks required permissions.",
|
||||
"statusNotFound": "The requested resource doesn't exist.",
|
||||
"statusConflict": "Resource conflict (e.g., double booking).",
|
||||
"statusTooManyRequests": "Rate limit exceeded.",
|
||||
"statusServerError": "Something went wrong on our end.",
|
||||
"rateLimits": "Rate Limits",
|
||||
"rateLimitsDescription": "The API implements rate limiting to ensure fair usage and stability.",
|
||||
"limits": "Limits",
|
||||
"requestsPerHour": "requests per hour per API key",
|
||||
"requestsPerMinute": "requests per minute burst limit",
|
||||
"rateLimitHeaders": "Rate Limit Headers",
|
||||
"rateLimitHeadersDescription": "Every response includes headers with your current rate limit status.",
|
||||
"business": "Business",
|
||||
"businessObject": "The Business object",
|
||||
"businessObjectDescription": "The Business object represents your business configuration and settings.",
|
||||
"attributes": "Attributes",
|
||||
"retrieveBusiness": "Retrieve business",
|
||||
"retrieveBusinessDescription": "Retrieves the business associated with your API key.",
|
||||
"requiredScope": "Required scope",
|
||||
"services": "Services",
|
||||
"serviceObject": "The Service object",
|
||||
"serviceObjectDescription": "Services represent the offerings your business provides that customers can book.",
|
||||
"listServices": "List all services",
|
||||
"listServicesDescription": "Returns a list of all active services for your business.",
|
||||
"retrieveService": "Retrieve a service",
|
||||
"resources": "Resources",
|
||||
"resourceObject": "The Resource object",
|
||||
"resourceObjectDescription": "Resources are the bookable entities in your business (staff members, rooms, equipment).",
|
||||
"listResources": "List all resources",
|
||||
"retrieveResource": "Retrieve a resource",
|
||||
"availability": "Availability",
|
||||
"checkAvailability": "Check availability",
|
||||
"checkAvailabilityDescription": "Returns available time slots for a given service and date range.",
|
||||
"parameters": "Parameters",
|
||||
"appointments": "Appointments",
|
||||
"appointmentObject": "The Appointment object",
|
||||
"appointmentObjectDescription": "Appointments represent scheduled bookings between customers and resources.",
|
||||
"createAppointment": "Create an appointment",
|
||||
"createAppointmentDescription": "Creates a new appointment booking.",
|
||||
"retrieveAppointment": "Retrieve an appointment",
|
||||
"updateAppointment": "Update an appointment",
|
||||
"cancelAppointment": "Cancel an appointment",
|
||||
"listAppointments": "List all appointments",
|
||||
"customers": "Customers",
|
||||
"customerObject": "The Customer object",
|
||||
"customerObjectDescription": "Customers are the people who book appointments with your business.",
|
||||
"createCustomer": "Create a customer",
|
||||
"retrieveCustomer": "Retrieve a customer",
|
||||
"updateCustomer": "Update a customer",
|
||||
"listCustomers": "List all customers",
|
||||
"webhooks": "Webhooks",
|
||||
"webhookEvents": "Webhook events",
|
||||
"webhookEventsDescription": "Webhooks allow you to receive real-time notifications when events occur in your business.",
|
||||
"eventTypes": "Event types",
|
||||
"webhookPayload": "Webhook Payload",
|
||||
"createWebhook": "Create a webhook",
|
||||
"createWebhookDescription": "Creates a new webhook subscription. The response includes a secret that you'll use to verify webhook signatures.",
|
||||
"secretOnlyOnce": "The secret is only shown once",
|
||||
"secretOnlyOnceDescription": ", so save it securely.",
|
||||
"listWebhooks": "List webhooks",
|
||||
"deleteWebhook": "Delete a webhook",
|
||||
"verifySignatures": "Verify signatures",
|
||||
"verifySignaturesDescription": "Every webhook request includes a signature in the X-Webhook-Signature header. You should verify this signature to ensure the request came from SmoothSchedule.",
|
||||
"signatureFormat": "Signature format",
|
||||
"signatureFormatDescription": "The signature header contains two values separated by a dot: a timestamp and the HMAC-SHA256 signature.",
|
||||
"verificationSteps": "Verification steps",
|
||||
"verificationStep1": "Extract the timestamp and signature from the header",
|
||||
"verificationStep2": "Concatenate the timestamp, a dot, and the raw request body",
|
||||
"verificationStep3": "Compute HMAC-SHA256 using your webhook secret",
|
||||
"verificationStep4": "Compare the computed signature with the received signature",
|
||||
"saveYourSecret": "Save your secret!",
|
||||
"saveYourSecretDescription": "The webhook secret is only returned once when the webhook is created. Store it securely for signature verification.",
|
||||
"endpoint": "Endpoint",
|
||||
"request": "Request",
|
||||
"response": "Response"
|
||||
}
|
||||
},
|
||||
"staff": {
|
||||
"title": "Staff & Management",
|
||||
@@ -102,12 +242,16 @@
|
||||
"ticketDetails": "Ticket Details",
|
||||
"createTicket": "Create Ticket",
|
||||
"updateTicket": "Update Ticket",
|
||||
"comments": "Comments",
|
||||
"noComments": "No comments yet.",
|
||||
"internal": "Internal",
|
||||
"addCommentPlaceholder": "Add a comment...",
|
||||
"internalComment": "Internal Comment",
|
||||
"postComment": "Post Comment",
|
||||
"comments": "Replies",
|
||||
"noComments": "No replies yet.",
|
||||
"internal": "Internal Note",
|
||||
"addCommentPlaceholder": "Write a reply...",
|
||||
"postComment": "Send Reply",
|
||||
"replyLabel": "Reply to Customer",
|
||||
"internalNoteLabel": "Internal Note",
|
||||
"internalNoteHint": "(Not visible to customer)",
|
||||
"internalNotePlaceholder": "Add an internal note...",
|
||||
"addNote": "Add Note",
|
||||
"tabs": {
|
||||
"all": "All",
|
||||
"open": "Open",
|
||||
@@ -148,7 +292,73 @@
|
||||
"schedule_change": "Schedule Change",
|
||||
"equipment": "Equipment Issue",
|
||||
"other": "Other"
|
||||
}
|
||||
},
|
||||
"sandboxRestriction": "Platform Support Unavailable in Test Mode",
|
||||
"sandboxRestrictionMessage": "You can only contact SmoothSchedule support in live mode. Please switch to live mode to create a support ticket.",
|
||||
"status": {
|
||||
"open": "Open",
|
||||
"in_progress": "In Progress",
|
||||
"awaiting_response": "Awaiting Response",
|
||||
"resolved": "Resolved",
|
||||
"closed": "Closed"
|
||||
},
|
||||
"ticketNumber": "Ticket #{{number}}",
|
||||
"createdAt": "Created {{date}}"
|
||||
},
|
||||
"customerSupport": {
|
||||
"title": "Support",
|
||||
"subtitle": "Get help with your appointments and account",
|
||||
"newRequest": "New Request",
|
||||
"submitRequest": "Submit Request",
|
||||
"quickHelp": "Quick Help",
|
||||
"contactUs": "Contact Us",
|
||||
"contactUsDesc": "Submit a support request",
|
||||
"emailUs": "Email Us",
|
||||
"emailUsDesc": "Get help via email",
|
||||
"myRequests": "My Support Requests",
|
||||
"noRequests": "You haven't submitted any support requests yet.",
|
||||
"submitFirst": "Submit your first request",
|
||||
"subjectPlaceholder": "Brief summary of your issue",
|
||||
"descriptionPlaceholder": "Please describe your issue in detail...",
|
||||
"statusOpen": "Your request has been received. Our team will review it shortly.",
|
||||
"statusInProgress": "Our team is currently working on your request.",
|
||||
"statusAwaitingResponse": "We need additional information from you. Please reply below.",
|
||||
"statusResolved": "Your request has been resolved. Thank you for contacting us!",
|
||||
"statusClosed": "This ticket has been closed.",
|
||||
"conversation": "Conversation",
|
||||
"noRepliesYet": "No replies yet. Our team will respond soon.",
|
||||
"yourReply": "Your Reply",
|
||||
"replyPlaceholder": "Type your message here...",
|
||||
"sendReply": "Send Reply",
|
||||
"ticketClosedNoReply": "This ticket is closed. If you need further assistance, please open a new support request."
|
||||
},
|
||||
"platformSupport": {
|
||||
"title": "SmoothSchedule Support",
|
||||
"subtitle": "Get help from the SmoothSchedule team",
|
||||
"newRequest": "Contact Support",
|
||||
"quickHelp": "Quick Help",
|
||||
"platformGuide": "Platform Guide",
|
||||
"platformGuideDesc": "Learn the basics",
|
||||
"apiDocs": "API Docs",
|
||||
"apiDocsDesc": "Integration help",
|
||||
"contactUs": "Contact Support",
|
||||
"contactUsDesc": "Get personalized help",
|
||||
"myRequests": "My Support Requests",
|
||||
"noRequests": "You haven't submitted any support requests yet.",
|
||||
"submitFirst": "Submit your first request",
|
||||
"sandboxWarning": "You are in Test Mode",
|
||||
"sandboxWarningMessage": "Platform support is only available in Live Mode. Switch to Live Mode to contact SmoothSchedule support.",
|
||||
"statusOpen": "Your request has been received. Our support team will review it shortly.",
|
||||
"statusInProgress": "Our support team is currently working on your request.",
|
||||
"statusAwaitingResponse": "We need additional information from you. Please reply below.",
|
||||
"statusResolved": "Your request has been resolved. Thank you for contacting SmoothSchedule support!",
|
||||
"statusClosed": "This ticket has been closed.",
|
||||
"conversation": "Conversation",
|
||||
"noRepliesYet": "No replies yet. Our support team will respond soon.",
|
||||
"yourReply": "Your Reply",
|
||||
"replyPlaceholder": "Type your message here...",
|
||||
"sendReply": "Send Reply",
|
||||
"ticketClosedNoReply": "This ticket is closed. If you need further assistance, please open a new support request."
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
Reference in New Issue
Block a user