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,303 @@
"""
Selectors for ride-related data retrieval.
Following Django styleguide pattern for separating data access from business logic.
"""
from typing import Optional, Dict, Any
from django.db.models import QuerySet, Q, Count, Avg, Prefetch
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import Distance
from .models import Ride, RideModel, RideReview
def ride_list_for_display(
*, filters: Optional[Dict[str, Any]] = None
) -> QuerySet[Ride]:
"""
Get rides optimized for list display with related data.
Args:
filters: Optional dictionary of filter parameters
Returns:
QuerySet of rides with optimized queries
"""
queryset = (
Ride.objects.select_related(
"park",
"park__operator",
"manufacturer",
"designer",
"ride_model",
"park_area",
)
.prefetch_related("park__location", "location")
.annotate(average_rating_calculated=Avg("reviews__rating"))
)
if filters:
if "status" in filters:
queryset = queryset.filter(status=filters["status"])
if "category" in filters:
queryset = queryset.filter(category=filters["category"])
if "manufacturer" in filters:
queryset = queryset.filter(manufacturer=filters["manufacturer"])
if "park" in filters:
queryset = queryset.filter(park=filters["park"])
if "search" in filters:
search_term = filters["search"]
queryset = queryset.filter(
Q(name__icontains=search_term)
| Q(description__icontains=search_term)
| Q(park__name__icontains=search_term)
)
return queryset.order_by("park__name", "name")
def ride_detail_optimized(*, slug: str, park_slug: str) -> Ride:
"""
Get a single ride with all related data optimized for detail view.
Args:
slug: Ride slug identifier
park_slug: Park slug for the ride
Returns:
Ride instance with optimized prefetches
Raises:
Ride.DoesNotExist: If ride doesn't exist
"""
return (
Ride.objects.select_related(
"park",
"park__operator",
"manufacturer",
"designer",
"ride_model",
"park_area",
)
.prefetch_related(
"park__location",
"location",
Prefetch(
"reviews",
queryset=RideReview.objects.select_related("user").filter(
is_published=True
),
),
"photos",
)
.get(slug=slug, park__slug=park_slug)
)
def rides_by_category(*, category: str) -> QuerySet[Ride]:
"""
Get all rides in a specific category.
Args:
category: Ride category code
Returns:
QuerySet of rides in the category
"""
return (
Ride.objects.filter(category=category)
.select_related("park", "manufacturer", "designer")
.prefetch_related("park__location")
.annotate(average_rating_calculated=Avg("reviews__rating"))
.order_by("park__name", "name")
)
def rides_by_manufacturer(*, manufacturer_id: int) -> QuerySet[Ride]:
"""
Get all rides manufactured by a specific company.
Args:
manufacturer_id: Company ID of the manufacturer
Returns:
QuerySet of rides by the manufacturer
"""
return (
Ride.objects.filter(manufacturer_id=manufacturer_id)
.select_related("park", "manufacturer", "ride_model")
.prefetch_related("park__location")
.annotate(average_rating_calculated=Avg("reviews__rating"))
.order_by("park__name", "name")
)
def rides_by_designer(*, designer_id: int) -> QuerySet[Ride]:
"""
Get all rides designed by a specific company.
Args:
designer_id: Company ID of the designer
Returns:
QuerySet of rides by the designer
"""
return (
Ride.objects.filter(designer_id=designer_id)
.select_related("park", "designer", "ride_model")
.prefetch_related("park__location")
.annotate(average_rating_calculated=Avg("reviews__rating"))
.order_by("park__name", "name")
)
def rides_in_park(*, park_slug: str) -> QuerySet[Ride]:
"""
Get all rides in a specific park.
Args:
park_slug: Slug of the park
Returns:
QuerySet of rides in the park
"""
return (
Ride.objects.filter(park__slug=park_slug)
.select_related("manufacturer", "designer", "ride_model", "park_area")
.prefetch_related("location")
.annotate(average_rating_calculated=Avg("reviews__rating"))
.order_by("park_area__name", "name")
)
def rides_near_location(
*, point: Point, distance_km: float = 50, limit: int = 10
) -> QuerySet[Ride]:
"""
Get rides near a specific geographic location.
Args:
point: Geographic point (longitude, latitude)
distance_km: Maximum distance in kilometers
limit: Maximum number of results
Returns:
QuerySet of nearby rides ordered by distance
"""
return (
Ride.objects.filter(
park__location__coordinates__distance_lte=(
point,
Distance(km=distance_km),
)
)
.select_related("park", "manufacturer")
.prefetch_related("park__location")
.distance(point)
.order_by("distance")[:limit]
)
def ride_models_with_installations() -> QuerySet[RideModel]:
"""
Get ride models that have installations with counts.
Returns:
QuerySet of ride models with installation counts
"""
return (
RideModel.objects.annotate(installation_count=Count("rides"))
.filter(installation_count__gt=0)
.select_related("manufacturer")
.order_by("-installation_count", "name")
)
def ride_search_autocomplete(*, query: str, limit: int = 10) -> QuerySet[Ride]:
"""
Get rides matching a search query for autocomplete functionality.
Args:
query: Search string
limit: Maximum number of results
Returns:
QuerySet of matching rides for autocomplete
"""
return (
Ride.objects.filter(
Q(name__icontains=query)
| Q(park__name__icontains=query)
| Q(manufacturer__name__icontains=query)
)
.select_related("park", "manufacturer")
.prefetch_related("park__location")
.order_by("park__name", "name")[:limit]
)
def rides_with_recent_reviews(*, days: int = 30) -> QuerySet[Ride]:
"""
Get rides that have received reviews in the last N days.
Args:
days: Number of days to look back for reviews
Returns:
QuerySet of rides with recent reviews
"""
from django.utils import timezone
from datetime import timedelta
cutoff_date = timezone.now() - timedelta(days=days)
return (
Ride.objects.filter(
reviews__created_at__gte=cutoff_date, reviews__is_published=True
)
.select_related("park", "manufacturer")
.prefetch_related("park__location")
.annotate(
recent_review_count=Count(
"reviews", filter=Q(reviews__created_at__gte=cutoff_date)
)
)
.order_by("-recent_review_count")
.distinct()
)
def ride_statistics_by_category() -> Dict[str, Any]:
"""
Get ride statistics grouped by category.
Returns:
Dictionary containing ride statistics by category
"""
from .models import CATEGORY_CHOICES
stats = {}
for category_code, category_name in CATEGORY_CHOICES:
if category_code: # Skip empty choice
count = Ride.objects.filter(category=category_code).count()
stats[category_code] = {"name": category_name, "count": count}
return stats
def rides_by_opening_year(*, year: int) -> QuerySet[Ride]:
"""
Get rides that opened in a specific year.
Args:
year: The opening year
Returns:
QuerySet of rides that opened in the specified year
"""
return (
Ride.objects.filter(opening_date__year=year)
.select_related("park", "manufacturer")
.prefetch_related("park__location")
.order_by("opening_date", "park__name", "name")
)