Backend: - Add HasQuota() permission factory for quota limits (resources, users, services, appointments, email templates, automated tasks) - Add HasFeaturePermission() factory for feature-based permissions (SMS, masked calling, custom domains, white label, plugins, webhooks, calendar sync, analytics) - Add has_feature() method to Tenant model for flexible permission checking - Add new tenant permission fields: can_create_plugins, can_use_webhooks, can_use_calendar_sync, can_export_data - Create Data Export API with CSV/JSON support for appointments, customers, resources, services - Create Analytics API with dashboard, appointments, revenue endpoints - Add calendar sync views and URL configuration Frontend: - Add usePlanFeatures hook for checking feature availability - Add UpgradePrompt components (inline, banner, overlay variants) - Add LockedSection wrapper and LockedButton for feature gating - Update settings pages with permission checks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Analytics API Documentation
Overview
The Analytics API provides detailed reporting and business insights for tenant businesses. All analytics endpoints are gated behind the advanced_analytics permission from the subscription plan.
Permission Gating
All analytics endpoints require:
- Authentication: User must be authenticated (
IsAuthenticated) - Feature Permission: Tenant must have
advanced_analyticspermission enabled in their subscription plan
If a tenant doesn't have the advanced_analytics permission, they will receive a 403 Forbidden response:
{
"detail": "Your current plan does not include Advanced Analytics. Please upgrade your subscription to access this feature."
}
Endpoints
Base URL
GET /api/analytics/
1. Dashboard Summary Statistics
Endpoint: GET /api/analytics/analytics/dashboard/
Returns high-level metrics for the tenant's dashboard including appointment counts, resource utilization, and peak times.
Response Example:
{
"total_appointments_this_month": 42,
"total_appointments_all_time": 1250,
"active_resources_count": 5,
"active_services_count": 3,
"upcoming_appointments_count": 8,
"average_appointment_duration_minutes": 45.5,
"peak_booking_day": "Friday",
"peak_booking_hour": 14,
"period": {
"start_date": "2024-12-01T00:00:00Z",
"end_date": "2024-12-31T23:59:59Z"
}
}
Metrics Explained:
total_appointments_this_month: Count of confirmed appointments in current calendar monthtotal_appointments_all_time: Total count of all confirmed appointments everactive_resources_count: Number of unique resources with future appointmentsactive_services_count: Number of unique services with future appointmentsupcoming_appointments_count: Appointments in the next 7 daysaverage_appointment_duration_minutes: Average duration of all appointments (in minutes)peak_booking_day: Day of week with most appointments (Sunday-Saturday)peak_booking_hour: Hour of day (0-23) with most appointments
2. Appointment Analytics
Endpoint: GET /api/analytics/analytics/appointments/
Detailed appointment breakdown with trends and metrics.
Query Parameters:
days(optional, default: 30): Number of days to analyzestatus(optional): Filter by status - 'confirmed', 'cancelled', 'no_show'service_id(optional): Filter by service IDresource_id(optional): Filter by resource ID
Response Example:
{
"total": 285,
"by_status": {
"confirmed": 250,
"cancelled": 25,
"no_show": 10
},
"by_service": [
{
"service_id": 1,
"service_name": "Haircut",
"count": 150
},
{
"service_id": 2,
"service_name": "Color Treatment",
"count": 135
}
],
"by_resource": [
{
"resource_id": 1,
"resource_name": "Chair 1",
"count": 145
},
{
"resource_id": 2,
"resource_name": "Chair 2",
"count": 140
}
],
"daily_breakdown": [
{
"date": "2024-11-01",
"count": 8,
"status_breakdown": {
"confirmed": 7,
"cancelled": 1,
"no_show": 0
}
},
{
"date": "2024-11-02",
"count": 9,
"status_breakdown": {
"confirmed": 8,
"cancelled": 1,
"no_show": 0
}
}
],
"booking_trend_percent": 12.5,
"cancellation_rate_percent": 8.77,
"no_show_rate_percent": 3.51,
"period_days": 30
}
Metrics Explained:
total: Total appointments in the periodby_status: Count breakdown by appointment statusby_service: Appointment count per serviceby_resource: Appointment count per resourcedaily_breakdown: Day-by-day breakdown with status detailsbooking_trend_percent: Percentage change vs previous period (positive = growth)cancellation_rate_percent: Percentage of appointments cancelledno_show_rate_percent: Percentage of appointments where customer didn't showperiod_days: Number of days analyzed
Usage Examples:
# Get appointment analytics for last 7 days
curl "http://lvh.me:8000/api/analytics/analytics/appointments/?days=7"
# Get analytics for specific service
curl "http://lvh.me:8000/api/analytics/analytics/appointments/?service_id=1"
# Get only cancelled appointments in last 30 days
curl "http://lvh.me:8000/api/analytics/analytics/appointments/?status=cancelled"
3. Revenue Analytics
Endpoint: GET /api/analytics/analytics/revenue/
Revenue breakdown and payment analytics. Requires both advanced_analytics AND can_accept_payments permissions.
Query Parameters:
days(optional, default: 30): Number of days to analyzeservice_id(optional): Filter by service ID
Response Example:
{
"total_revenue_cents": 125000,
"transaction_count": 50,
"average_transaction_value_cents": 2500,
"by_service": [
{
"service_id": 1,
"service_name": "Haircut",
"revenue_cents": 75000,
"count": 30
},
{
"service_id": 2,
"service_name": "Color Treatment",
"revenue_cents": 50000,
"count": 20
}
],
"daily_breakdown": [
{
"date": "2024-11-01",
"revenue_cents": 3500,
"transaction_count": 7
},
{
"date": "2024-11-02",
"revenue_cents": 4200,
"transaction_count": 8
}
],
"period_days": 30
}
Metrics Explained:
total_revenue_cents: Total revenue in cents (divide by 100 for dollars)transaction_count: Number of completed transactionsaverage_transaction_value_cents: Average transaction value in centsby_service: Revenue breakdown by servicedaily_breakdown: Day-by-day revenue metricsperiod_days: Number of days analyzed
Important Notes:
- Amounts are in cents (multiply by 0.01 for dollars)
- Only includes completed/confirmed payments
- Requires tenant to have payment processing enabled
- Returns 403 if
can_accept_paymentsis not enabled
Permission Implementation
How Feature Gating Works
The analytics endpoints use the HasFeaturePermission permission class:
class AnalyticsViewSet(viewsets.ViewSet):
permission_classes = [IsAuthenticated, HasFeaturePermission('advanced_analytics')]
This permission class:
- Checks Authentication: Ensures user is logged in
- Gets Tenant from Request: Uses
request.tenant(set by django-tenants middleware) - Calls
tenant.has_feature('advanced_analytics'): Checks both:- Direct boolean field on Tenant model (if exists)
- Subscription plan's
permissionsJSON field
- Raises 403 if Permission Not Found: Returns error with upgrade message
Adding Advanced Analytics to a Plan
To grant advanced_analytics permission to a subscription plan:
Option 1: Django Admin
1. Go to /admin/platform_admin/subscriptionplan/
2. Edit desired plan
3. In "Permissions" JSON field, add:
{
"advanced_analytics": true,
...other permissions...
}
4. Save
Option 2: Django Management Command
docker compose -f docker-compose.local.yml exec django python manage.py shell
# In the shell:
from platform_admin.models import SubscriptionPlan
plan = SubscriptionPlan.objects.get(name='Professional')
permissions = plan.permissions or {}
permissions['advanced_analytics'] = True
plan.permissions = permissions
plan.save()
Option 3: Direct Tenant Field
# If using direct field on Tenant:
from core.models import Tenant
tenant = Tenant.objects.get(schema_name='demo')
tenant.advanced_analytics = True # If field exists
tenant.save()
Architecture
File Structure
analytics/
├── __init__.py
├── apps.py # Django app configuration
├── views.py # AnalyticsViewSet with all endpoints
├── serializers.py # Read-only serializers for response validation
├── urls.py # URL routing
└── README.md # This file
Key Classes
AnalyticsViewSet (views.py)
- Inherits from
viewsets.ViewSet(read-only, no database models) - Three action methods:
dashboard()- Summary statisticsappointments()- Detailed appointment analyticsrevenue()- Payment analytics (conditional)
- All methods return
Responsewith calculated data
Permission Chain
Request → IsAuthenticated → HasFeaturePermission('advanced_analytics') → View
Error Responses
401 Unauthorized
{
"detail": "Authentication credentials were not provided."
}
403 Forbidden (Missing Permission)
{
"detail": "Your current plan does not include Advanced Analytics. Please upgrade your subscription to access this feature."
}
403 Forbidden (Revenue Endpoint, Missing Payments Permission)
{
"error": "Payment analytics not available",
"detail": "Your plan does not include payment processing."
}
Testing
Using cURL
# Get analytics with auth token
TOKEN="your_auth_token_here"
curl -H "Authorization: Token $TOKEN" \
"http://lvh.me:8000/api/analytics/analytics/dashboard/"
curl -H "Authorization: Token $TOKEN" \
"http://lvh.me:8000/api/analytics/analytics/appointments/?days=7"
curl -H "Authorization: Token $TOKEN" \
"http://lvh.me:8000/api/analytics/analytics/revenue/"
Using Python Requests
import requests
TOKEN = "your_auth_token_here"
headers = {"Authorization": f"Token {TOKEN}"}
# Dashboard
response = requests.get(
"http://lvh.me:8000/api/analytics/analytics/dashboard/",
headers=headers
)
print(response.json())
# Appointments with filter
response = requests.get(
"http://lvh.me:8000/api/analytics/analytics/appointments/",
headers=headers,
params={"days": 7, "service_id": 1}
)
print(response.json())
Performance Considerations
- Dashboard: Performs multiple aggregate queries, suitable for ~10k+ appointments
- Appointments: Filters and iterates over appointments, may be slow with 100k+ records
- Revenue: Depends on payment transaction volume, usually fast
- Caching: Consider implementing Redis caching for frequently accessed analytics
Future Enhancements
-
Performance Optimization
- Add database indexing on
start_time,status,created_at - Implement query result caching
- Use database aggregation instead of Python loops
- Add database indexing on
-
Additional Analytics
- Customer demographics (repeat rate, lifetime value)
- Staff performance metrics (revenue per staff member)
- Channel attribution (how customers found you)
- Resource utilization rate (occupancy percentage)
-
Export Features
- CSV/Excel export
- PDF report generation
- Email report scheduling
-
Advanced Filtering
- Date range selection
- Multi-service filtering
- Resource utilization trends
- Seasonal analysis