Add secret management guide, client-side performance monitoring, and search accessibility enhancements

- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols.
- Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage.
- Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
This commit is contained in:
pacnpal
2025-12-23 16:41:42 -05:00
parent ae31e889d7
commit edcd8f2076
155 changed files with 22046 additions and 4645 deletions

View File

@@ -11,6 +11,16 @@ This module implements a "full fat" set of endpoints:
Notes:
- These views try to use real Django models if available. If the domain models/services
are not present, they return a clear 501 response explaining what to wire up.
Caching Strategy:
- RideListCreateAPIView.get: 10 minutes (600s) - ride lists are frequently queried
- RideDetailAPIView.get: 30 minutes (1800s) - detail views are stable
- FilterOptionsAPIView.get: 30 minutes (1800s) - filter options change rarely
- HybridRideAPIView.get: 10 minutes (600s) - ride lists with filters
- RideFilterMetadataAPIView.get: 30 minutes (1800s) - metadata is stable
- CompanySearchAPIView.get: 10 minutes (600s) - company data is stable
- RideModelSearchAPIView.get: 10 minutes (600s) - ride model data is stable
- RideSearchSuggestionsAPIView.get: 5 minutes (300s) - suggestions should be fresh
"""
import logging
@@ -33,6 +43,7 @@ from apps.api.v1.serializers.rides import (
RideListOutputSerializer,
RideUpdateInputSerializer,
)
from apps.core.decorators.cache_decorators import cache_api_response
from apps.rides.services.hybrid_loader import SmartRideLoader
logger = logging.getLogger(__name__)
@@ -73,6 +84,13 @@ class StandardResultsSetPagination(PageNumberPagination):
# --- Ride list & create -----------------------------------------------------
class RideListCreateAPIView(APIView):
"""
API View for listing and creating rides.
Caching: GET requests are cached for 10 minutes (600s).
POST requests bypass cache and invalidate related cache entries.
"""
permission_classes = [permissions.AllowAny]
@extend_schema(
@@ -281,6 +299,7 @@ class RideListCreateAPIView(APIView):
responses={200: RideListOutputSerializer(many=True)},
tags=["Rides"],
)
@cache_api_response(timeout=600, key_prefix="ride_list")
def get(self, request: Request) -> Response:
"""List rides with comprehensive filtering and pagination."""
if not MODELS_AVAILABLE:
@@ -658,6 +677,13 @@ class RideListCreateAPIView(APIView):
tags=["Rides"],
)
class RideDetailAPIView(APIView):
"""
API View for retrieving, updating, or deleting a single ride.
Caching: GET requests are cached for 30 minutes (1800s).
PATCH/PUT/DELETE requests bypass cache and should trigger cache invalidation.
"""
permission_classes = [permissions.AllowAny]
def _get_ride_or_404(self, pk: int) -> Any:
@@ -671,6 +697,7 @@ class RideDetailAPIView(APIView):
except Ride.DoesNotExist: # type: ignore
raise NotFound("Ride not found")
@cache_api_response(timeout=1800, key_prefix="ride_detail")
def get(self, request: Request, pk: int) -> Response:
ride = self._get_ride_or_404(pk)
serializer = RideDetailOutputSerializer(ride, context={"request": request})
@@ -743,8 +770,16 @@ class RideDetailAPIView(APIView):
tags=["Rides"],
)
class FilterOptionsAPIView(APIView):
"""
API View for ride filter options.
Caching: 30-minute timeout (1800s) - filter options change rarely
and are expensive to compute.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=1800, key_prefix="ride_filter_options")
def get(self, request: Request) -> Response:
"""Return comprehensive filter options with Rich Choice Objects metadata."""
# Import Rich Choice registry
@@ -1733,8 +1768,13 @@ class FilterOptionsAPIView(APIView):
tags=["Rides"],
)
class CompanySearchAPIView(APIView):
"""
Caching: 10-minute timeout (600s) - company data is stable.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=600, key_prefix="company_search")
def get(self, request: Request) -> Response:
q = request.query_params.get("q", "")
if not q:
@@ -1767,8 +1807,13 @@ class CompanySearchAPIView(APIView):
tags=["Rides"],
)
class RideModelSearchAPIView(APIView):
"""
Caching: 10-minute timeout (600s) - ride model data is stable.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=600, key_prefix="ride_model_search")
def get(self, request: Request) -> Response:
q = request.query_params.get("q", "")
if not q:
@@ -1805,8 +1850,13 @@ class RideModelSearchAPIView(APIView):
tags=["Rides"],
)
class RideSearchSuggestionsAPIView(APIView):
"""
Caching: 5-minute timeout (300s) - suggestions should be relatively fresh.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=300, key_prefix="ride_suggestions")
def get(self, request: Request) -> Response:
q = request.query_params.get("q", "")
if not q:
@@ -2048,10 +2098,14 @@ class HybridRideAPIView(APIView):
Automatically chooses between client-side and server-side filtering
based on data size and complexity. Provides progressive loading
for large datasets and complete data for smaller sets.
Caching: 10-minute timeout (600s) - ride lists are frequently queried
but need to reflect new additions within reasonable time.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=600, key_prefix="hybrid_rides")
def get(self, request):
"""Get rides with hybrid filtering strategy."""
try:
@@ -2367,10 +2421,14 @@ class RideFilterMetadataAPIView(APIView):
Provides information about available filter options and ranges
to help build dynamic filter interfaces.
Caching: 30-minute timeout (1800s) - filter metadata is stable
and only changes when new entities are added.
"""
permission_classes = [permissions.AllowAny]
@cache_api_response(timeout=1800, key_prefix="ride_filter_metadata")
def get(self, request):
"""Get ride filter metadata."""
try: