Initial commit: SmoothSchedule multi-tenant scheduling platform

This commit includes:
- Django backend with multi-tenancy (django-tenants)
- React + TypeScript frontend with Vite
- Platform administration API with role-based access control
- Authentication system with token-based auth
- Quick login dev tools for testing different user roles
- CORS and CSRF configuration for local development
- Docker development environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
poduck
2025-11-27 01:43:20 -05:00
commit 2e111364a2
567 changed files with 96410 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
"""
Schedule App - DRF ViewSets
API endpoints for Resources and Events with quota enforcement.
"""
from rest_framework import viewsets, status
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response
from .models import Resource, Event, Participant
from .serializers import ResourceSerializer, EventSerializer, ParticipantSerializer
from core.permissions import HasQuota
class ResourceViewSet(viewsets.ModelViewSet):
"""
API endpoint for managing Resources.
Permissions:
- Must be authenticated
- Subject to MAX_RESOURCES quota (hard block on creation)
The HasQuota permission prevents creating resources when tenant
has reached their subscription tier limit.
"""
queryset = Resource.objects.all()
serializer_class = ResourceSerializer
# TODO: Re-enable authentication for production
permission_classes = [AllowAny] # Temporarily allow unauthenticated access for development
filterset_fields = ['is_active', 'max_concurrent_events']
search_fields = ['name', 'description']
ordering_fields = ['name', 'created_at', 'max_concurrent_events']
ordering = ['name']
def perform_create(self, serializer):
"""Create resource (quota-checked by HasQuota permission)"""
serializer.save()
def perform_update(self, serializer):
"""Update resource"""
serializer.save()
class EventViewSet(viewsets.ModelViewSet):
"""
API endpoint for managing Events.
Permissions:
- Must be authenticated
Validation:
- EventSerializer.validate() automatically checks resource availability
- If resource capacity exceeded, returns 400 Bad Request
- See schedule/services.py AvailabilityService for logic
"""
queryset = Event.objects.all()
serializer_class = EventSerializer
# TODO: Re-enable authentication for production
permission_classes = [AllowAny] # Temporarily allow unauthenticated access for development
filterset_fields = ['status', 'start_time', 'end_time']
search_fields = ['title', 'notes']
ordering_fields = ['start_time', 'end_time', 'created_at']
ordering = ['start_time']
def perform_create(self, serializer):
"""
Create event with automatic availability validation.
The EventSerializer.validate() method calls AvailabilityService
to check if resources have capacity. If not, DRF automatically
returns 400 Bad Request with error details.
"""
# TODO: Re-enable authentication - this is temporary for development
if self.request.user.is_authenticated:
serializer.save(created_by=self.request.user)
else:
serializer.save(created_by=None)
def perform_update(self, serializer):
"""
Update event with availability re-validation.
Uses exclude_event_id in AvailabilityService to allow
rescheduling of the event itself.
"""
serializer.save()
class ParticipantViewSet(viewsets.ModelViewSet):
"""
API endpoint for managing Event Participants.
Allows adding/removing participants (Resources, Staff, Customers)
to/from events via the GenericForeignKey pattern.
"""
queryset = Participant.objects.all()
serializer_class = ParticipantSerializer
permission_classes = [IsAuthenticated]
filterset_fields = ['event', 'role', 'content_type']
ordering_fields = ['created_at']
ordering = ['-created_at']