feat: Add comprehensive plugin documentation and advanced template system

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 is contained in:
poduck
2025-11-28 20:54:07 -05:00
parent a9719a5fd2
commit 3fef0d5749
46 changed files with 8883 additions and 555 deletions

View File

@@ -0,0 +1,551 @@
# Resource-Free Scheduler & Plugin System
## Overview
The Resource-Free Scheduler is a comprehensive system for running automated tasks on schedules without requiring resource allocation. It's separate from the customer-facing Event/Appointment system and designed for internal automation tasks.
## Key Features
- **Plugin-Based Architecture**: Extensible system for creating custom automated tasks
- **Multiple Schedule Types**: Cron expressions, fixed intervals, and one-time executions
- **Celery Integration**: Asynchronous task execution with retry logic
- **Execution Logging**: Complete audit trail of all task executions
- **Multi-Tenant Aware**: Works seamlessly with django-tenants
- **Built-in Plugins**: Common tasks ready to use out of the box
## Architecture
```
┌─────────────────┐
│ ScheduledTask │ (Model: Configuration for recurring tasks)
│ - plugin_name │
│ - schedule_type │
│ - config │
└────────┬────────┘
├─> Plugin Registry ──> BasePlugin ──> Custom Plugins
│ │
│ ├─> SendEmailPlugin
│ ├─> DailyReportPlugin
│ ├─> CleanupPlugin
│ └─> WebhookPlugin
└─> Celery Tasks ──> execute_scheduled_task()
└─> TaskExecutionLog (Model: Execution history)
```
## Core Components
### 1. Models (`schedule/models.py`)
#### ScheduledTask
Stores configuration for scheduled tasks.
**Fields:**
- `name` - Human-readable task name
- `description` - What the task does
- `plugin_name` - Which plugin to execute
- `plugin_config` - JSON configuration for the plugin
- `schedule_type` - CRON, INTERVAL, or ONE_TIME
- `cron_expression` - Cron syntax (e.g., "0 0 * * *")
- `interval_minutes` - Run every N minutes
- `run_at` - Specific datetime for one-time tasks
- `status` - ACTIVE, PAUSED, or DISABLED
- `next_run_at` - Calculated next execution time
- `last_run_at` - When last executed
- `last_run_status` - success/failed
- `last_run_result` - JSON result from last execution
#### TaskExecutionLog
Audit log of all task executions.
**Fields:**
- `scheduled_task` - Reference to the task
- `started_at` - Execution start time
- `completed_at` - Execution end time
- `status` - SUCCESS, FAILED, or SKIPPED
- `result` - JSON result from plugin
- `error_message` - Error details if failed
- `execution_time_ms` - Duration in milliseconds
### 2. Plugin System (`schedule/plugins.py`)
#### BasePlugin
Abstract base class for all plugins.
**Required Attributes:**
- `name` - Unique identifier (snake_case)
- `display_name` - Human-readable name
- `description` - What the plugin does
- `category` - For organization (e.g., "communication", "reporting")
**Required Methods:**
- `execute(context)` - Main task logic
**Optional Methods:**
- `validate_config()` - Validate plugin configuration
- `can_execute(context)` - Pre-execution checks
- `on_success(result)` - Post-success callback
- `on_failure(error)` - Error handling callback
#### Plugin Registry
Global registry for managing plugins.
**Methods:**
- `register(plugin_class)` - Register a plugin
- `get(plugin_name)` - Get plugin class by name
- `get_instance(plugin_name, config)` - Create plugin instance
- `list_all()` - List all plugins with metadata
- `list_by_category()` - Group plugins by category
### 3. Celery Tasks (`schedule/tasks.py`)
#### execute_scheduled_task(scheduled_task_id)
Main task executor. Runs the plugin, logs results, updates next run time.
**Features:**
- Automatic retry with exponential backoff
- Multi-tenant context preservation
- Pre-execution validation
- Comprehensive error handling
- Automatic next-run calculation
#### check_and_schedule_tasks()
Background task that finds due tasks and queues them for execution.
## Built-in Plugins
### 1. SendEmailPlugin
Send custom emails to recipients.
**Config:**
```json
{
"recipients": ["user@example.com"],
"subject": "Subject line",
"message": "Email body",
"from_email": "sender@example.com" // optional
}
```
### 2. CleanupOldEventsPlugin
Delete old completed/canceled events.
**Config:**
```json
{
"days_old": 90,
"statuses": ["COMPLETED", "CANCELED"],
"dry_run": false
}
```
### 3. DailyReportPlugin
Send daily business summary reports.
**Config:**
```json
{
"recipients": ["manager@example.com"],
"include_upcoming": true,
"include_completed": true
}
```
### 4. AppointmentReminderPlugin
Send appointment reminders to customers.
**Config:**
```json
{
"hours_before": 24,
"method": "email", // or "sms", "both"
"message_template": "Optional custom template"
}
```
### 5. BackupDatabasePlugin
Create database backups.
**Config:**
```json
{
"backup_location": "/path/to/backups",
"compress": true
}
```
### 6. WebhookPlugin
Call external webhook URLs.
**Config:**
```json
{
"url": "https://example.com/webhook",
"method": "POST",
"headers": {"Authorization": "Bearer token"},
"payload": {"key": "value"}
}
```
## API Endpoints
### Scheduled Tasks
**List tasks:**
```
GET /api/scheduled-tasks/
```
**Create task:**
```
POST /api/scheduled-tasks/
{
"name": "Daily Cleanup",
"description": "Clean up old events",
"plugin_name": "cleanup_old_events",
"plugin_config": {"days_old": 90},
"schedule_type": "CRON",
"cron_expression": "0 0 * * *",
"status": "ACTIVE"
}
```
**Update task:**
```
PATCH /api/scheduled-tasks/{id}/
```
**Pause task:**
```
POST /api/scheduled-tasks/{id}/pause/
```
**Resume task:**
```
POST /api/scheduled-tasks/{id}/resume/
```
**Manually execute:**
```
POST /api/scheduled-tasks/{id}/execute/
```
**Get execution logs:**
```
GET /api/scheduled-tasks/{id}/logs/?limit=20&offset=0
```
### Plugins
**List all plugins:**
```
GET /api/plugins/
```
**List by category:**
```
GET /api/plugins/by_category/
```
**Get plugin details:**
```
GET /api/plugins/{plugin_name}/
```
### Execution Logs
**List all logs:**
```
GET /api/task-logs/
```
**Filter by task:**
```
GET /api/task-logs/?task_id=1
```
**Filter by status:**
```
GET /api/task-logs/?status=FAILED
```
## Creating Custom Plugins
### Step 1: Create Plugin Class
```python
# myapp/plugins.py
from schedule.plugins import BasePlugin, register_plugin
@register_plugin
class MyCustomPlugin(BasePlugin):
name = "my_custom_plugin"
display_name = "My Custom Plugin"
description = "Does something awesome"
category = "automation"
config_schema = {
'api_key': {
'type': 'string',
'required': True,
'description': 'API key for external service',
},
'threshold': {
'type': 'integer',
'required': False,
'default': 100,
'description': 'Processing threshold',
},
}
def execute(self, context):
"""
context contains:
- business: Current tenant
- scheduled_task: ScheduledTask instance
- execution_time: When execution started
- user: User who created the task
"""
api_key = self.config.get('api_key')
threshold = self.config.get('threshold', 100)
# Do your task logic here
result = perform_some_operation(api_key, threshold)
return {
'success': True,
'message': 'Operation completed',
'data': {
'items_processed': result.count,
}
}
def can_execute(self, context):
"""Optional: Add pre-execution checks"""
if context['business'].is_suspended:
return False, "Business is suspended"
return True, None
def on_failure(self, error):
"""Optional: Handle failures"""
# Send alert, log to external service, etc.
pass
```
### Step 2: Import Plugin on Startup
Add to your app's `apps.py`:
```python
class MyAppConfig(AppConfig):
def ready(self):
from . import plugins # Import to register
```
### Step 3: Use via API
```bash
curl -X POST http://lvh.me:8000/api/scheduled-tasks/ \
-H "Content-Type: application/json" \
-d '{
"name": "Custom Automation",
"plugin_name": "my_custom_plugin",
"plugin_config": {
"api_key": "secret123",
"threshold": 500
},
"schedule_type": "INTERVAL",
"interval_minutes": 60,
"status": "ACTIVE"
}'
```
## Schedule Types
### Cron Expression
```python
{
"schedule_type": "CRON",
"cron_expression": "0 0 * * *" # Daily at midnight
}
# Examples:
# "*/5 * * * *" - Every 5 minutes
# "0 */2 * * *" - Every 2 hours
# "0 9 * * 1-5" - Weekdays at 9am
# "0 0 1 * *" - First day of month
```
### Fixed Interval
```python
{
"schedule_type": "INTERVAL",
"interval_minutes": 30 # Every 30 minutes
}
```
### One-Time
```python
{
"schedule_type": "ONE_TIME",
"run_at": "2025-12-01T10:00:00Z"
}
```
## Execution Context
Every plugin receives a context dictionary:
```python
{
'business': <Business instance>, # Current tenant
'scheduled_task': <ScheduledTask instance>,
'execution_time': <datetime>, # Execution timestamp
'user': <User instance or None>, # Task creator
}
```
## Error Handling
Tasks automatically retry on failure with exponential backoff:
1. First retry: 60 seconds
2. Second retry: 120 seconds
3. Third retry: 240 seconds
After 3 failures, the task is marked as failed and won't retry until next scheduled run.
## Multi-Tenant Behavior
The scheduler respects django-tenants:
- Tasks execute in the context of their tenant's schema
- Each tenant has separate scheduled tasks
- Execution logs are tenant-isolated
- Plugins can access `context['business']` for tenant info
## Monitoring & Debugging
### View Recent Logs
```bash
curl http://lvh.me:8000/api/task-logs/?limit=10
```
### Check Failed Tasks
```bash
curl http://lvh.me:8000/api/task-logs/?status=FAILED
```
### View Task Details
```bash
curl http://lvh.me:8000/api/scheduled-tasks/1/
```
### Manual Test Execution
```bash
curl -X POST http://lvh.me:8000/api/scheduled-tasks/1/execute/
```
## Best Practices
### 1. Plugin Design
- Keep plugins focused on one task
- Make config schema explicit
- Return structured results
- Handle errors gracefully
- Add logging for debugging
### 2. Configuration
- Use environment variables for secrets (not plugin_config)
- Validate config in `validate_config()`
- Provide sensible defaults
- Document config schema
### 3. Scheduling
- Use cron for predictable times (e.g., daily reports)
- Use intervals for continuous processing
- Avoid very short intervals (< 5 minutes)
- Consider business hours for customer-facing tasks
### 4. Error Handling
- Use `can_execute()` for pre-flight checks
- Return detailed error messages
- Implement `on_failure()` for alerts
- Don't silence exceptions in `execute()`
### 5. Performance
- Keep executions fast (< 30 seconds ideal)
- Use pagination for large datasets
- Offload heavy work to dedicated queues
- Monitor execution times in logs
## Testing
### Test Plugin Directly
```python
from schedule.plugins import registry
plugin = registry.get_instance('my_plugin', config={'key': 'value'})
result = plugin.execute({
'business': business,
'scheduled_task': None,
'execution_time': timezone.now(),
'user': None,
})
assert result['success'] == True
```
### Test via API
```python
import requests
# Create task
response = requests.post('http://lvh.me:8000/api/scheduled-tasks/', json={
'name': 'Test Task',
'plugin_name': 'send_email',
'plugin_config': {'recipients': ['test@example.com']},
'schedule_type': 'ONE_TIME',
'run_at': '2025-12-01T10:00:00Z',
})
task_id = response.json()['id']
# Execute immediately
requests.post(f'http://lvh.me:8000/api/scheduled-tasks/{task_id}/execute/')
# Check logs
logs = requests.get(f'http://lvh.me:8000/api/scheduled-tasks/{task_id}/logs/')
```
## Troubleshooting
### Plugins Not Registered
Check that `apps.py` imports the plugin module in `ready()`.
### Tasks Not Executing
1. Check task status is ACTIVE
2. Verify next_run_at is in the future
3. Check Celery worker is running
4. Look for errors in Django logs
### Execution Logs Empty
Check that `execute_scheduled_task` Celery task is configured and workers are running.
### Cron Expression Not Working
Use a cron validator. Common issues:
- Syntax errors
- Timezone mismatches (server runs in UTC)
## Future Enhancements
Potential additions:
- Web UI for managing tasks
- Plugin marketplace
- Task dependencies/chaining
- Rate limiting
- Notifications on failure
- Dashboard with metrics
- Plugin versioning
- A/B testing for plugins