feat: complete monorepo structure with frontend and shared resources

- Add complete backend/ directory with full Django application
- Add frontend/ directory with Vite + TypeScript setup ready for Next.js
- Add comprehensive shared/ directory with:
  - Complete documentation and memory-bank archives
  - Media files and avatars (letters, park/ride images)
  - Deployment scripts and automation tools
  - Shared types and utilities
- Add architecture/ directory with migration guides
- Configure pnpm workspace for monorepo development
- Update .gitignore to exclude .django_tailwind_cli/ build artifacts
- Preserve all historical documentation in shared/docs/memory-bank/
- Set up proper structure for full-stack development with shared resources
This commit is contained in:
pacnpal
2025-08-23 18:40:07 -04:00
parent b0e0678590
commit d504d41de2
762 changed files with 142636 additions and 0 deletions

View File

@@ -0,0 +1,301 @@
"""
Custom managers and QuerySets for Rides models.
Optimized queries following Django styleguide patterns.
"""
from typing import Optional, List, Union
from django.db.models import Q, F, Count, Prefetch
from apps.core.managers import (
BaseQuerySet,
BaseManager,
ReviewableQuerySet,
ReviewableManager,
StatusQuerySet,
StatusManager,
)
class RideQuerySet(StatusQuerySet, ReviewableQuerySet):
"""Optimized QuerySet for Ride model."""
def by_category(self, *, category: Union[str, List[str]]):
"""Filter rides by category."""
if isinstance(category, list):
return self.filter(category__in=category)
return self.filter(category=category)
def coasters(self):
"""Filter for roller coasters."""
return self.filter(category__in=["RC", "WC"])
def thrill_rides(self):
"""Filter for thrill rides."""
return self.filter(category__in=["RC", "WC", "FR"])
def family_friendly(self, *, max_height_requirement: int = 42):
"""Filter for family-friendly rides."""
return self.filter(
Q(min_height_in__lte=max_height_requirement) | Q(min_height_in__isnull=True)
)
def by_park(self, *, park_id: int):
"""Filter rides by park."""
return self.filter(park_id=park_id)
def by_manufacturer(self, *, manufacturer_id: int):
"""Filter rides by manufacturer."""
return self.filter(manufacturer_id=manufacturer_id)
def by_designer(self, *, designer_id: int):
"""Filter rides by designer."""
return self.filter(designer_id=designer_id)
def with_capacity_info(self):
"""Add capacity-related annotations."""
return self.annotate(
estimated_daily_capacity=F("capacity_per_hour")
* 10, # Assuming 10 operating hours
duration_minutes=F("ride_duration_seconds") / 60.0,
)
def high_capacity(self, *, min_capacity: int = 1000):
"""Filter for high-capacity rides."""
return self.filter(capacity_per_hour__gte=min_capacity)
def optimized_for_list(self):
"""Optimize for ride list display."""
return self.select_related(
"park", "park_area", "manufacturer", "designer", "ride_model"
).with_review_stats()
def optimized_for_detail(self):
"""Optimize for ride detail display."""
from .models import RideReview
return self.select_related(
"park",
"park_area",
"manufacturer",
"designer",
"ride_model__manufacturer",
).prefetch_related(
"location",
"rollercoaster_stats",
Prefetch(
"reviews",
queryset=RideReview.objects.select_related("user")
.filter(is_published=True)
.order_by("-created_at")[:10],
),
"photos",
)
def for_map_display(self):
"""Optimize for map display."""
return (
self.select_related("park", "park_area")
.prefetch_related("location")
.values(
"id",
"name",
"slug",
"category",
"status",
"park__name",
"park__slug",
"park_area__name",
"location__point",
)
)
def search_by_specs(
self,
*,
min_height: Optional[int] = None,
max_height: Optional[int] = None,
min_speed: Optional[float] = None,
inversions: Optional[bool] = None,
):
"""Search rides by physical specifications."""
queryset = self
if min_height:
queryset = queryset.filter(
Q(rollercoaster_stats__height_ft__gte=min_height)
| Q(min_height_in__gte=min_height)
)
if max_height:
queryset = queryset.filter(
Q(rollercoaster_stats__height_ft__lte=max_height)
| Q(max_height_in__lte=max_height)
)
if min_speed:
queryset = queryset.filter(rollercoaster_stats__speed_mph__gte=min_speed)
if inversions is not None:
if inversions:
queryset = queryset.filter(rollercoaster_stats__inversions__gt=0)
else:
queryset = queryset.filter(
Q(rollercoaster_stats__inversions=0)
| Q(rollercoaster_stats__isnull=True)
)
return queryset
class RideManager(StatusManager, ReviewableManager):
"""Custom manager for Ride model."""
def get_queryset(self):
return RideQuerySet(self.model, using=self._db)
def coasters(self):
return self.get_queryset().coasters()
def thrill_rides(self):
return self.get_queryset().thrill_rides()
def family_friendly(self, *, max_height_requirement: int = 42):
return self.get_queryset().family_friendly(
max_height_requirement=max_height_requirement
)
def by_park(self, *, park_id: int):
return self.get_queryset().by_park(park_id=park_id)
def high_capacity(self, *, min_capacity: int = 1000):
return self.get_queryset().high_capacity(min_capacity=min_capacity)
def optimized_for_list(self):
return self.get_queryset().optimized_for_list()
def optimized_for_detail(self):
return self.get_queryset().optimized_for_detail()
class RideModelQuerySet(BaseQuerySet):
"""QuerySet for RideModel model."""
def by_manufacturer(self, *, manufacturer_id: int):
"""Filter ride models by manufacturer."""
return self.filter(manufacturer_id=manufacturer_id)
def by_category(self, *, category: str):
"""Filter ride models by category."""
return self.filter(category=category)
def with_ride_counts(self):
"""Add count of rides using this model."""
return self.annotate(
ride_count=Count("rides", distinct=True),
operating_rides_count=Count(
"rides", filter=Q(rides__status="OPERATING"), distinct=True
),
)
def popular_models(self, *, min_installations: int = 5):
"""Filter for popular ride models."""
return self.with_ride_counts().filter(ride_count__gte=min_installations)
def optimized_for_list(self):
"""Optimize for model list display."""
return self.select_related("manufacturer").with_ride_counts()
class RideModelManager(BaseManager):
"""Manager for RideModel model."""
def get_queryset(self):
return RideModelQuerySet(self.model, using=self._db)
def by_manufacturer(self, *, manufacturer_id: int):
return self.get_queryset().by_manufacturer(manufacturer_id=manufacturer_id)
def popular_models(self, *, min_installations: int = 5):
return self.get_queryset().popular_models(min_installations=min_installations)
class RideReviewQuerySet(ReviewableQuerySet):
"""QuerySet for RideReview model."""
def for_ride(self, *, ride_id: int):
"""Filter reviews for a specific ride."""
return self.filter(ride_id=ride_id)
def by_user(self, *, user_id: int):
"""Filter reviews by user."""
return self.filter(user_id=user_id)
def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
"""Filter reviews by rating range."""
return self.filter(rating__gte=min_rating, rating__lte=max_rating)
def optimized_for_display(self):
"""Optimize for review display."""
return self.select_related("user", "ride", "moderated_by")
class RideReviewManager(BaseManager):
"""Manager for RideReview model."""
def get_queryset(self):
return RideReviewQuerySet(self.model, using=self._db)
def for_ride(self, *, ride_id: int):
return self.get_queryset().for_ride(ride_id=ride_id)
def by_rating_range(self, *, min_rating: int = 1, max_rating: int = 10):
return self.get_queryset().by_rating_range(
min_rating=min_rating, max_rating=max_rating
)
class RollerCoasterStatsQuerySet(BaseQuerySet):
"""QuerySet for RollerCoasterStats model."""
def tall_coasters(self, *, min_height_ft: float = 200):
"""Filter for tall roller coasters."""
return self.filter(height_ft__gte=min_height_ft)
def fast_coasters(self, *, min_speed_mph: float = 60):
"""Filter for fast roller coasters."""
return self.filter(speed_mph__gte=min_speed_mph)
def with_inversions(self):
"""Filter for coasters with inversions."""
return self.filter(inversions__gt=0)
def launched_coasters(self):
"""Filter for launched coasters."""
return self.exclude(launch_type="NONE")
def by_track_type(self, *, track_type: str):
"""Filter by track type."""
return self.filter(track_type=track_type)
def optimized_for_list(self):
"""Optimize for stats list display."""
return self.select_related("ride", "ride__park")
class RollerCoasterStatsManager(BaseManager):
"""Manager for RollerCoasterStats model."""
def get_queryset(self):
return RollerCoasterStatsQuerySet(self.model, using=self._db)
def tall_coasters(self, *, min_height_ft: float = 200):
return self.get_queryset().tall_coasters(min_height_ft=min_height_ft)
def fast_coasters(self, *, min_speed_mph: float = 60):
return self.get_queryset().fast_coasters(min_speed_mph=min_speed_mph)
def with_inversions(self):
return self.get_queryset().with_inversions()
def launched_coasters(self):
return self.get_queryset().launched_coasters()