Files
motovaultpro/docs/GAS-STATION-AGENTS.md
Eric Gullickson 2cc9cc5f9f Gas Station Prep
2025-11-03 14:18:25 -06:00

40 KiB

Gas Stations Feature - Parallel Agent Execution Plan

Overview

This document contains agent definition prompts for implementing the Gas Stations feature using parallel execution. The backend API is complete; this plan focuses on frontend implementation, backend improvements, and integration.

Key Context

  • Backend API: Fully implemented at backend/src/features/stations/
  • Frontend: Completely missing (needs full implementation)
  • Database: Schema ready, needs migration execution
  • Secrets: Google Maps API key exists in secrets/app/google-maps-api-key.txt
  • Pattern: Follow K8s-aligned runtime secrets (not build-time env vars)
  • Reference: Use frontend/src/features/vehicles/ as implementation pattern

Investigation Summary

  • Backend has 4 complete API endpoints (search, save, get saved, delete)
  • Database migration ready: 001_create_stations_tables.sql
  • External integration: Google Maps Places API client implemented
  • No frontend code exists yet (placeholder route only)
  • No tests exist (empty directories)
  • No circuit breaker or cache cleanup implemented

Execution Phases

Phase 1 (Parallel - Infrastructure):
├─ Agent 1: Frontend-Secrets-Agent
└─ Agent 2: Backend-Reliability-Agent

Phase 2 (Foundation):
└─ Agent 3: Frontend-Foundation-Agent (depends on Agent 1)

Phase 3 (Parallel - Components):
├─ Agent 4: Components-Agent (depends on Agent 3)
└─ Agent 5: Map-Visualization-Agent (depends on Agent 3)

Phase 4 (Parallel - Pages):
├─ Agent 6: Desktop-Mobile-Agent (depends on Agents 4, 5)
└─ Agent 7: Integration-Agent (depends on Agents 4, 5)

Phase 5 (Testing):
└─ Agent 8: Testing-Documentation-Agent (depends on all previous)

Agent 1: Frontend-Secrets-Agent

Scope

Implement K8s-aligned runtime secrets pattern for frontend to load Google Maps API key from /run/secrets/ at container startup.

Prerequisites

  • None (can start immediately)

Responsibilities

  1. Create Frontend Config Loader Script

    • File: frontend/scripts/load-config.sh
    • Reads /run/secrets/google-maps-api-key
    • Generates /usr/share/nginx/html/config.js with: window.CONFIG = { googleMapsApiKey: 'KEY_VALUE' }
    • Fallback to empty string if secret not found
    • Logs success/failure for debugging
  2. Update Frontend Dockerfile

    • File: frontend/Dockerfile
    • Copy scripts/load-config.sh into image
    • Make script executable
    • Add SECRETS_DIR environment variable (default: /run/secrets)
    • Update CMD to: ["sh", "-c", "/app/load-config.sh && nginx -g 'daemon off;'"]
  3. Update index.html

    • File: frontend/index.html
    • Add <script src="/config.js"></script> before app bundle script tag
    • Ensure config loads synchronously before React initializes
  4. Create Frontend Config Types

    • File: frontend/src/core/config/config.types.ts
    • Interface: RuntimeConfig { googleMapsApiKey: string }
    • Extend Window interface: declare global { interface Window { CONFIG: RuntimeConfig } }
    • Export typed accessor: export function getConfig(): RuntimeConfig
    • Runtime validation: throw if required values missing
  5. Update docker-compose.yml

    • File: docker-compose.yml
    • Add to mvp-frontend service volumes:
      - ./secrets/app/google-maps-api-key.txt:/run/secrets/google-maps-api-key:ro
      
    • Add environment variable: SECRETS_DIR: /run/secrets
  6. Create Documentation

    • File: frontend/docs/RUNTIME-CONFIG.md
    • Explain runtime config pattern vs build-time
    • How to add new runtime secrets
    • K8s deployment notes
    • Local development setup

Success Criteria

  • Frontend container starts successfully
  • /usr/share/nginx/html/config.js exists and contains API key
  • getConfig() returns typed RuntimeConfig object
  • No TypeScript errors
  • Linters pass

Handoff Notes

Provides getConfig().googleMapsApiKey for Agent 5 (Map-Visualization-Agent) to use when loading Google Maps JavaScript API.


Agent 2: Backend-Reliability-Agent

Scope

Enhance backend reliability with circuit breaker, comprehensive tests, and cache cleanup job.

Prerequisites

  • None (can start immediately)

Responsibilities

  1. Add Circuit Breaker Pattern

    • Install package: Add "opossum": "^8.1.4" to backend/package.json
    • File: backend/src/features/stations/external/google-maps/google-maps.circuit-breaker.ts
    • Create circuit breaker factory function
    • Configuration: 10s timeout, 50% error threshold, 30s reset timeout
    • Update: backend/src/features/stations/external/google-maps/google-maps.client.ts
    • Wrap searchNearby() method with circuit breaker
    • Follow pattern from backend/src/features/platform/ (reference implementation)
    • Add circuit breaker events logging (open, close, halfOpen)
  2. Backend Unit Tests

    • File: backend/src/features/stations/tests/unit/stations.service.test.ts
      • Test searchStations() with valid coordinates
      • Test saveStation() with user_id isolation
      • Test getSavedStations() returns only user's stations
      • Test deleteSavedStation() removes correct station
    • File: backend/src/features/stations/tests/unit/stations.repository.test.ts
      • Test database queries with mock connection
      • Test SQL injection protection
      • Test constraint violations (duplicate saves)
    • File: backend/src/features/stations/tests/unit/google-maps.client.test.ts
      • Mock Google Maps API responses
      • Test distance calculation (Haversine formula)
      • Test photo URL generation
      • Test error handling
  3. Backend Integration Tests

    • File: backend/src/features/stations/tests/integration/stations.api.test.ts
      • Test all 4 endpoints with real database
      • Test JWT authentication requirement
      • Test request validation (Zod schemas)
      • Test error responses (400, 401, 500)
    • File: backend/src/features/stations/tests/integration/saved-stations.flow.test.ts
      • Test complete workflow: search → save → retrieve → delete
      • Test duplicate save handling
      • Test user isolation (user A can't see user B's stations)
  4. Test Fixtures

    • File: backend/src/features/stations/tests/fixtures/mock-stations.ts
      • Export sample Station objects (5-10 examples)
      • Include various ratings, distances, prices
    • File: backend/src/features/stations/tests/fixtures/mock-google-response.ts
      • Mock Google Places API responses
      • Include success and error cases
    • File: backend/src/features/stations/tests/fixtures/test-coordinates.ts
      • Sample coordinates for major cities
      • Edge cases (equator, poles, date line)
  5. Cache Cleanup Job

    • File: backend/src/features/stations/jobs/cache-cleanup.job.ts
      • Scheduled job using cron (daily at 2 AM)
      • Delete station_cache entries older than 24 hours
      • Log metrics: rows deleted, execution time
      • Error handling and retry logic
    • Update: backend/src/app.ts
      • Import and register cache cleanup job
      • Add to scheduler (if exists) or create simple interval
  6. Run Tests

    • Execute: cd backend && npm test -- features/stations
    • Verify 100% pass rate
    • Check coverage (aim for >80%)

Success Criteria

  • Circuit breaker implemented and tested
  • All unit tests pass
  • All integration tests pass
  • Test coverage >80%
  • Cache cleanup job registered
  • Linters pass
  • No TypeScript errors

Handoff Notes

Backend is now production-ready with reliability patterns. Tests provide safety net for future changes.


Agent 3: Frontend-Foundation-Agent

Scope

Create frontend foundation: types, API client, and React Query hooks for stations feature.

Prerequisites

  • Depends on Agent 1 (needs getConfig() function)

Responsibilities

  1. Type Definitions

    • File: frontend/src/features/stations/types/stations.types.ts
    • Interface Station:
      • placeId: string
      • name: string
      • address: string
      • location: { latitude: number; longitude: number }
      • rating?: number
      • distance: number (meters)
      • photoUrl?: string
      • prices?: { fuel_type: string; price: number }[]
    • Interface SavedStation extends Station:
      • userId: string
      • nickname?: string
      • notes?: string
      • isFavorite: boolean
      • savedAt: string
    • Interface SearchRequest:
      • latitude: number
      • longitude: number
      • radius?: number (meters, default 5000)
      • fuelType?: string
    • Interface SearchResponse:
      • stations: Station[]
      • searchLocation: { latitude: number; longitude: number }
    • Interface SaveStationData:
      • placeId: string
      • nickname?: string
      • notes?: string
      • isFavorite?: boolean
  2. API Client

    • File: frontend/src/features/stations/api/stations.api.ts
    • Function searchStations(request: SearchRequest): Promise<Station[]>
      • POST /api/stations/search
      • Include JWT in Authorization header
      • Return stations array
    • Function saveStation(data: SaveStationData): Promise<SavedStation>
      • POST /api/stations/save
      • Include JWT in Authorization header
      • Return saved station with full details
    • Function getSavedStations(): Promise<SavedStation[]>
      • GET /api/stations/saved
      • Include JWT in Authorization header
      • Return array of user's saved stations
    • Function deleteSavedStation(placeId: string): Promise<void>
      • DELETE /api/stations/saved/:placeId
      • Include JWT in Authorization header
      • Return nothing (204 No Content)
    • Use axios instance from frontend/src/core/api/client.ts
    • Proper error handling with try-catch
    • Add request/response logging for debugging
  3. React Query Hooks

    • File: frontend/src/features/stations/hooks/useStationsSearch.ts
      • Export useStationsSearch() mutation hook
      • Accepts SearchRequest, returns Station[]
      • Don't cache by default (location-specific queries)
      • Loading/error states
    • File: frontend/src/features/stations/hooks/useSavedStations.ts
      • Export useSavedStations() query hook
      • Query key: ['stations', 'saved']
      • Auto-refetch on window focus
      • Stale time: 5 minutes
      • Loading/error states
    • File: frontend/src/features/stations/hooks/useSaveStation.ts
      • Export useSaveStation() mutation hook
      • Accepts SaveStationData
      • Optimistic update: add to saved list immediately
      • On success: invalidate ['stations', 'saved'] query
      • On error: rollback optimistic update
    • File: frontend/src/features/stations/hooks/useDeleteStation.ts
      • Export useDeleteStation() mutation hook
      • Accepts placeId string
      • Optimistic update: remove from saved list
      • On success: invalidate ['stations', 'saved'] query
      • On error: rollback optimistic update
    • File: frontend/src/features/stations/hooks/useGeolocation.ts
      • Export useGeolocation() hook
      • Uses browser Geolocation API
      • Returns: { position, loading, error, requestLocation }
      • Handle permission states: prompt, granted, denied
      • Error handling: timeout, unavailable, permission denied
      • Options: enableHighAccuracy, timeout, maximumAge
  4. Utilities

    • File: frontend/src/features/stations/utils/distance.ts
      • Export formatDistance(meters: number): string
      • Convert meters to miles with proper formatting
      • Examples: "0.3 mi", "1.2 mi", "5.7 mi"
    • File: frontend/src/features/stations/utils/location.ts
      • Export getCurrentPosition(): Promise<GeolocationPosition>
      • Wrapper around navigator.geolocation.getCurrentPosition
      • Promisified API
      • Error handling helpers

Success Criteria

  • All type interfaces defined with proper TypeScript types
  • API client functions work (test with curl against backend)
  • All React Query hooks created with proper caching
  • Geolocation hook handles all permission states
  • No TypeScript errors
  • Linters pass
  • Utilities properly format data

Handoff Notes

Foundation is complete. Agent 4 and Agent 5 can now build components and map visualization using these types, API client, and hooks.


Agent 4: Components-Agent

Scope

Build all React components for stations feature (cards, lists, forms).

Prerequisites

  • Depends on Agent 3 (needs types, hooks, API client)

Responsibilities

  1. StationCard Component

    • File: frontend/src/features/stations/components/StationCard.tsx
    • Props:
      • station: Station
      • isSaved?: boolean
      • onSave?: (placeId: string) => void
      • onDelete?: (placeId: string) => void
      • onSelect?: (station: Station) => void
    • UI Elements:
      • Material-UI Card component
      • Station name (Typography variant="h6")
      • Address (Typography variant="body2", color="text.secondary")
      • Distance chip (Chip with LocationOnIcon)
      • Rating stars (Rating component, if rating exists)
      • Price display (Typography, if prices available)
      • Photo thumbnail (CardMedia, if photoUrl exists)
      • Save/Unsave IconButton (BookmarkIcon / BookmarkBorderIcon)
      • Directions link (Button with OpenInNewIcon, opens Google Maps)
    • Styling:
      • Responsive: full width on mobile, fixed width on desktop
      • Min height 44px for touch targets
      • Hover effects on desktop
      • Loading state while saving/deleting
    • Follow pattern: frontend/src/features/vehicles/components/VehicleCard.tsx
  2. StationsList Component

    • File: frontend/src/features/stations/components/StationsList.tsx
    • Props:
      • stations: Station[]
      • loading?: boolean
      • error?: Error | null
      • onSaveStation?: (placeId: string) => void
      • savedStationIds?: Set
    • UI Elements:
      • Grid container (responsive)
      • Layout: 1 col mobile, 2 cols tablet, 3 cols desktop
      • Loading state: Skeleton components (3-6 skeletons)
      • Empty state: "No stations found. Try adjusting your search."
      • Error state: Alert with retry option
      • Map stations to StationCard components
    • Styling:
      • Gap between cards: 16px
      • Smooth loading transitions
    • Follow pattern: frontend/src/features/vehicles/components/VehiclesList.tsx
  3. SavedStationsList Component

    • File: frontend/src/features/stations/components/SavedStationsList.tsx
    • Props:
      • savedStations: SavedStation[]
      • loading?: boolean
      • error?: Error | null
      • onDelete: (placeId: string) => void
      • onSelect?: (station: SavedStation) => void
      • currentLocation?: { latitude: number; longitude: number }
    • UI Elements:
      • List container (vertical)
      • Each item shows: nickname || name, address, distance from current location
      • Notes preview (truncated to 50 chars)
      • Favorite icon if isFavorite
      • Delete IconButton with confirmation dialog
      • Loading state: Linear progress bar
      • Empty state: "No saved stations yet. Save stations from search results."
      • Error state: Alert with error message
    • Styling:
      • List item min height: 64px
      • Dividers between items
      • Delete button always visible (not just on hover for mobile)
    • Follow pattern: Material-UI List component examples
  4. StationsSearchForm Component

    • File: frontend/src/features/stations/components/StationsSearchForm.tsx
    • Props:
      • onSearch: (request: SearchRequest) => void
      • loading?: boolean
    • UI Elements:
      • Form container (Card or Paper)
      • "Use Current Location" Button (uses useGeolocation hook)
      • OR divider
      • Manual lat/lng inputs (TextField type="number")
      • Radius slider (Slider: 1-25 miles, default 5, step 1)
      • Fuel type select (optional, Select component)
      • Search LoadingButton (shows loading state during search)
      • Geolocation status indicator (permission state)
      • Error display for geolocation failures
    • Validation:
      • Require either current location OR manual lat/lng
      • Validate latitude: -90 to 90
      • Validate longitude: -180 to 180
    • Behavior:
      • Click "Use Current Location" → request permission → populate hidden lat/lng
      • Manual input disables current location
      • Convert miles to meters for API (1 mile = 1609.34 meters)
    • Styling:
      • Compact form layout
      • Responsive: stack vertically on mobile
      • Clear visual feedback for loading states
    • Follow pattern: frontend/src/features/fuel-logs/components/FuelLogForm.tsx
  5. Create Feature Index

    • File: frontend/src/features/stations/components/index.ts
    • Export all components for easy importing

Success Criteria

  • All 4 components render without errors
  • Components follow Material-UI design patterns
  • Mobile responsive (test at 375px width)
  • Touch targets minimum 44px
  • Loading and error states work
  • TypeScript types are correct
  • Linters pass
  • Components match vehicles feature pattern

Handoff Notes

Core components are ready. Agent 6 can now build pages using these components. Agent 7 can integrate with map visualization.


Agent 5: Map-Visualization-Agent

Scope

Implement Google Maps integration and StationMap component for visualizing stations on a map.

Prerequisites

  • Depends on Agent 1 (needs getConfig().googleMapsApiKey)
  • Depends on Agent 3 (needs Station types)

Responsibilities

  1. Google Maps API Loader

    • File: frontend/src/features/stations/utils/maps-loader.ts
    • Function: loadGoogleMapsAPI(): Promise<typeof google>
    • Load Google Maps JavaScript API dynamically
    • Use runtime config: getConfig().googleMapsApiKey
    • Include libraries: libraries=places,geometry
    • Singleton pattern: only load once, return cached promise
    • Error handling: throw if API key missing or script fails
    • TypeScript: Use @types/google.maps for types
  2. Map Utilities

    • File: frontend/src/features/stations/utils/map-utils.ts
    • Function: createStationMarker(station: Station, map: google.maps.Map, isSaved: boolean): google.maps.Marker
      • Create marker at station location
      • Icon: blue pin for normal, gold star for saved
      • Title: station name
      • Clickable: true
    • Function: createInfoWindow(station: Station, isSaved: boolean, onSave: () => void, onDirections: () => void): google.maps.InfoWindow
      • Create info window with station details
      • Content: name, address, rating, distance
      • Action buttons: Save/Saved, Directions
      • HTML string with proper escaping
    • Function: fitBoundsToMarkers(map: google.maps.Map, markers: google.maps.Marker[]): void
      • Calculate bounds containing all markers
      • Fit map to bounds with padding
      • Handle single marker case (zoom to 14)
    • Function: calculateCenter(stations: Station[]): google.maps.LatLng
      • Calculate geometric center of stations
      • Return LatLng object
  3. StationMap Component

    • File: frontend/src/features/stations/components/StationMap.tsx
    • Props:
      • stations: Station[]
      • savedStationIds?: Set
      • center?: { latitude: number; longitude: number }
      • zoom?: number
      • currentLocation?: { latitude: number; longitude: number }
      • onStationClick?: (station: Station) => void
      • onSaveStation?: (placeId: string) => void
    • State:
      • map: google.maps.Map | null
      • markers: google.maps.Marker[]
      • infoWindow: google.maps.InfoWindow | null
    • Behavior:
      • Load Google Maps API on mount (useEffect)
      • Initialize map in div container
      • Create markers for all stations
      • Current location marker (red pin, if provided)
      • Click marker → open info window
      • Click save button → call onSaveStation
      • Click directions → open Google Maps in new tab
      • Auto-fit bounds to show all markers
      • Clean up markers on unmount
    • Styling:
      • Container: width 100%, height configurable (default 500px)
      • Responsive: 300px height on mobile, 500px on desktop
      • Map controls: zoom, pan, fullscreen
      • Custom map styles (optional: subtle styling)
    • Map Options:
      • mapTypeControl: false
      • streetViewControl: false
      • fullscreenControl: true
      • zoomControl: true
    • Error Handling:
      • Show error message if API fails to load
      • Fallback: display stations in list if map unavailable
  4. TypeScript Types

    • Ensure @types/google.maps is in frontend/package.json
    • Add if missing: "@types/google.maps": "^3.54.0"
  5. Testing

    • Test map loads with valid API key
    • Test markers render for each station
    • Test info windows open on marker click
    • Test current location marker (red pin)
    • Test directions link opens correct URL
    • Test error handling (invalid API key)

Success Criteria

  • Google Maps API loads successfully from runtime config
  • StationMap component renders map
  • Markers appear for all stations
  • Color coding works (blue vs gold for saved)
  • Info windows display correct station details
  • Directions links work
  • Current location marker shows if provided
  • Responsive sizing works
  • No TypeScript errors
  • Linters pass

Handoff Notes

Map visualization is complete. Agent 6 can integrate StationMap into desktop and mobile pages.


Agent 6: Desktop-Mobile-Agent

Scope

Build desktop StationsPage and mobile StationsMobileScreen, update routing.

Prerequisites

  • Depends on Agent 4 (needs all components)
  • Depends on Agent 5 (needs StationMap)

Responsibilities

  1. Desktop StationsPage

    • File: frontend/src/features/stations/pages/StationsPage.tsx
    • Layout:
      • Container: Full width, Grid layout
      • Left column (60%): StationMap (full height 600px)
      • Right column (40%):
        • StationsSearchForm at top
        • Tabs component: "Search Results" | "Saved Stations"
        • Tab 1 content: StationsList (scrollable)
        • Tab 2 content: SavedStationsList (scrollable)
    • State:
      • searchResults: Station[] (from useStationsSearch)
      • selectedStation: Station | null (for map focus)
      • currentLocation: Position | null (from useGeolocation)
      • activeTab: 0 | 1
    • Hooks:
      • useStationsSearch() for searching
      • useSavedStations() for saved list
      • useSaveStation() for saving
      • useDeleteStation() for deleting
      • useGeolocation() for current location
    • Behavior:
      • On search submit → call searchStations mutation
      • On search success → update map with results
      • On save station → add to saved list (optimistic)
      • On delete station → remove from saved list (optimistic)
      • Click station card → highlight on map (zoom to marker)
      • Map marker click → highlight card and scroll into view
    • Responsive:
      • Breakpoint <960px: Stack vertically (map on top)
      • Mobile view: Map 300px height, full width
    • Loading States:
      • Show loading spinner during search
      • Skeleton loaders for saved stations
    • Error Handling:
      • Display error alerts for API failures
      • Retry buttons where appropriate
    • Follow pattern: frontend/src/features/vehicles/pages/VehiclesPage.tsx
  2. Mobile StationsScreen

    • File: frontend/src/features/stations/pages/StationsMobileScreen.tsx
    • Layout:
      • BottomNavigation with 3 tabs: "Search", "Saved", "Map"
      • Tab content area (full screen minus bottom nav)
    • Tab 0 (Search):
      • StationsSearchForm (compact mode, vertical layout)
      • StationsList (vertical scroll, full width)
      • Pull-to-refresh support (optional)
    • Tab 1 (Saved):
      • SavedStationsList (full screen)
      • Swipe-to-delete gestures (optional enhancement)
      • Empty state with illustration
    • Tab 2 (Map):
      • StationMap (full screen, 100vh minus nav)
      • Floating action button (FAB) to return to search tab
      • Current location button (FAB)
    • State:
      • activeTab: 0 | 1 | 2
      • Same data state as desktop page
    • Hooks:
      • Same as desktop page
    • Behavior:
      • Tab switching persists scroll position
      • Search → auto-switch to results view
      • Save station → show snackbar confirmation
      • Map marker click → open bottom sheet with station details
    • Bottom Sheet:
      • SwipeableDrawer component
      • Shows station details
      • Save/Delete buttons
      • Directions link
    • Touch Targets:
      • All buttons minimum 44px
      • Adequate spacing between interactive elements
    • Safe Areas:
      • Handle notched devices (safe-area-inset)
      • Bottom navigation respects safe area
    • Follow pattern: frontend/src/features/vehicles/pages/VehiclesMobileScreen.tsx
  3. Update Desktop Routing

    • File: frontend/src/App.tsx (around line 556)
    • Remove: <Route path="/stations" element={<div>Stations (TODO)</div>} />
    • Add: <Route path="/stations" element={<StationsPage />} />
    • Import: import { StationsPage } from './features/stations/pages/StationsPage'
    • Verify route is inside ProtectedRoute wrapper (requires auth)
  4. Update Mobile Routing

    • File: frontend/src/App.tsx (mobile routes section)
    • Add: <Route path="/m/stations" element={<StationsMobileScreen />} />
    • Import: import { StationsMobileScreen } from './features/stations/pages/StationsMobileScreen'
    • Update mobile navigation items:
      • Add stations icon and route to bottom nav
      • Icon: PlaceRoundedIcon (already used in Layout.tsx)
      • Ensure onClick navigates to /m/stations
  5. Feature Index

    • File: frontend/src/features/stations/index.ts
    • Export StationsPage and StationsMobileScreen
    • Export all components for external use
  6. Manual Testing

    • Desktop: Navigate to /stations, test all functionality
    • Mobile: Navigate to /m/stations, test all tabs
    • Test on real mobile device or Chrome DevTools mobile emulation
    • Verify responsive breakpoints work
    • Verify touch targets are adequate (44px minimum)

Success Criteria

  • Desktop page renders and functions completely
  • Mobile screen renders with all 3 tabs
  • Routing works for both desktop and mobile
  • All components integrate properly
  • Search, save, delete operations work
  • Map updates when data changes
  • Mobile touch targets meet 44px requirement
  • Responsive design works at all breakpoints
  • No TypeScript errors
  • Linters pass

Handoff Notes

Desktop and mobile UIs are complete and fully functional. Users can now search, save, and view stations on both platforms.


Agent 7: Integration-Agent

Scope

Integrate stations feature with fuel logs using a station picker component.

Prerequisites

  • Depends on Agent 4 (needs StationCard and search functionality)
  • Depends on Agent 5 (needs map utilities)

Responsibilities

  1. StationPicker Component

    • File: frontend/src/features/fuel-logs/components/StationPicker.tsx
    • Props:
      • value: string (station name)
      • onChange: (stationName: string) => void
      • userLocation?: { latitude: number; longitude: number }
      • label?: string
      • error?: boolean
      • helperText?: string
    • UI Elements:
      • Autocomplete component (Material-UI)
      • TextField with LocationOnIcon adornment
      • Dropdown shows: saved stations (group 1) + nearby stations (group 2)
      • Option rendering:
        • Primary text: station name
        • Secondary text: distance + address
        • Bookmark icon if saved
      • FreeSolo mode: allow manual text entry
      • Loading indicator while fetching stations
    • Behavior:
      • On focus → fetch saved stations immediately
      • If userLocation provided → fetch nearby stations (5 mile radius)
      • Show saved stations first (grouped, labeled "Saved Stations")
      • Show nearby stations second (grouped, labeled "Nearby Stations")
      • On select → call onChange with station name
      • On manual input → call onChange with entered text
      • Debounce: 300ms delay for search queries
    • Data:
      • Use useSavedStations() hook
      • Use useStationsSearch() hook with userLocation
      • Combine results: saved + nearby
      • De-duplicate by placeId
    • Error Handling:
      • If geolocation fails → only show saved stations
      • If API fails → fallback to manual text input
      • Display error message in helper text
    • Follow pattern: Material-UI Autocomplete with grouping
  2. Update FuelLogForm

    • File: frontend/src/features/fuel-logs/components/FuelLogForm.tsx
    • Find: Current location input field (likely TextField or LocationInput component)
    • Replace with: StationPicker component
    • Props to pass:
      • value: formData.stationName (or equivalent)
      • onChange: (name) => setFormData({ ...formData, stationName: name })
      • userLocation: from useGeolocation hook
      • label: "Gas Station"
      • error: Boolean(errors.stationName)
      • helperText: errors.stationName
    • Integration:
      • Add useGeolocation hook to FuelLogForm
      • Pass current position to StationPicker
      • Maintain existing form validation
      • Ensure backward compatibility (text input still works)
  3. Enhance Fuel Log Display (Optional)

    • File: frontend/src/features/fuel-logs/components/FuelLogCard.tsx
    • If stationName is present → make it clickable
    • On click → navigate to /stations with search for that name
    • OR: Show station details in dialog
    • Add LocationOnIcon next to station name
    • Follow existing card styling
  4. Add Geolocation to Fuel Logs

    • Update FuelLogForm to request location permission on mount
    • Store current location in component state
    • Pass to StationPicker for nearby stations
    • Show permission request UI if needed
    • Handle permission denied gracefully (picker still works with saved stations)
  5. Testing

    • Test StationPicker in isolation (render component)
    • Test selecting saved station
    • Test selecting nearby station
    • Test manual text entry (freeSolo)
    • Test integration in FuelLogForm
    • Test submitting fuel log with station
    • Test geolocation permission flow

Success Criteria

  • StationPicker component renders and functions
  • Saved stations appear in dropdown
  • Nearby stations appear in dropdown (if location available)
  • Manual text entry works (fallback)
  • FuelLogForm integrates StationPicker successfully
  • Submitting fuel log with station works
  • Backward compatible (existing fuel logs still display)
  • Geolocation permission handled gracefully
  • No TypeScript errors
  • Linters pass

Handoff Notes

Fuel logs now integrate with stations feature. Users can select stations from saved or nearby lists when logging fuel, improving data consistency and user experience.


Agent 8: Testing-Documentation-Agent

Scope

Create comprehensive tests for all new code and complete documentation.

Prerequisites

  • Depends on all previous agents (needs complete implementation)

Responsibilities

  1. Backend Tests Verification

    • Run: cd backend && npm test -- features/stations
    • Verify all tests pass (from Agent 2)
    • If failures: debug and fix
    • Check coverage: npm test -- --coverage features/stations
    • Ensure coverage >80%
  2. Frontend Component Tests

    • File: frontend/src/features/stations/__tests__/components/StationCard.test.tsx
      • Test rendering with all props
      • Test save button click
      • Test delete button click
      • Test directions link
    • File: frontend/src/features/stations/__tests__/components/StationsList.test.tsx
      • Test rendering with stations array
      • Test loading state (skeletons)
      • Test empty state
      • Test error state
    • File: frontend/src/features/stations/__tests__/components/SavedStationsList.test.tsx
      • Test rendering saved stations
      • Test delete action
      • Test empty state
    • File: frontend/src/features/stations/__tests__/components/StationsSearchForm.test.tsx
      • Test form submission
      • Test validation (lat/lng ranges)
      • Test current location button
      • Test manual input
    • File: frontend/src/features/stations/__tests__/components/StationMap.test.tsx
      • Mock Google Maps API
      • Test map initialization
      • Test marker rendering
      • Test info window
    • Use React Testing Library
    • Mock hooks with jest.mock()
  3. Frontend API Tests

    • File: frontend/src/features/stations/api/__tests__/stations.api.test.ts
      • Test searchStations() - mock axios
      • Test saveStation() - mock axios
      • Test getSavedStations() - mock axios
      • Test deleteSavedStation() - mock axios
      • Test error handling (network errors, 401, 500)
      • Verify request payloads
      • Verify response parsing
  4. Frontend Hook Tests

    • File: frontend/src/features/stations/hooks/__tests__/useStationsSearch.test.ts
      • Test mutation flow
      • Test loading state
      • Test success state
      • Test error state
    • File: frontend/src/features/stations/hooks/__tests__/useSavedStations.test.ts
      • Test query flow
      • Test cache behavior
      • Test refetch logic
    • File: frontend/src/features/stations/hooks/__tests__/useSaveStation.test.ts
      • Test mutation with optimistic update
      • Test cache invalidation
      • Test rollback on error
    • File: frontend/src/features/stations/hooks/__tests__/useDeleteStation.test.ts
      • Test mutation with optimistic update
      • Test cache invalidation
      • Test rollback on error
    • Use @testing-library/react-hooks
    • Mock React Query client
  5. Frontend Page Tests

    • File: frontend/src/features/stations/__tests__/pages/StationsPage.test.tsx
      • Test page renders
      • Test search workflow
      • Test save station workflow
      • Test tab switching
      • Test map interaction
    • File: frontend/src/features/stations/__tests__/pages/StationsMobileScreen.test.tsx
      • Test all 3 tabs render
      • Test tab navigation
      • Test search on mobile
      • Test saved list on mobile
  6. Integration Component Tests

    • File: frontend/src/features/fuel-logs/__tests__/components/StationPicker.test.tsx
      • Test rendering
      • Test saved stations load
      • Test nearby stations load (with geolocation)
      • Test manual text entry
      • Test selection callback
      • Mock useStationsSearch and useSavedStations
  7. E2E Tests (Optional but Recommended)

    • File: frontend/cypress/e2e/stations.cy.ts (or similar framework)
    • Test flows:
      • Login → Navigate to Stations
      • Search for nearby stations
      • Save a station
      • View saved stations
      • Delete a station
      • Navigate to Fuel Logs
      • Select station from picker
      • Submit fuel log
      • Verify station name appears in log
    • Use real backend in test environment
    • Seed test data if needed
  8. Run All Tests

    • Backend: cd backend && npm test
    • Frontend: cd frontend && npm test
    • Verify 100% pass rate
    • Fix any failures
  9. Backend Documentation

    • File: backend/src/features/stations/docs/ARCHITECTURE.md
      • System design overview
      • Data flow diagrams (text-based)
      • External dependencies (Google Maps Places API)
      • Caching strategy (Redis + PostgreSQL)
      • Database schema with relationships
      • Circuit breaker pattern explanation
    • File: backend/src/features/stations/docs/API.md
      • All endpoint documentation
      • Request/response examples with curl commands
      • Authentication requirements (JWT)
      • Rate limits and quotas
      • Error response formats
    • File: backend/src/features/stations/docs/TESTING.md
      • How to run tests
      • Test database setup
      • Writing new tests
      • Coverage goals (>80%)
      • CI/CD integration
    • File: backend/src/features/stations/docs/GOOGLE-MAPS-SETUP.md
      • Google Cloud Console setup
      • Create project and enable Places API
      • API key creation and restrictions
      • Quota management and monitoring
      • Cost estimation ($10-50/month typical)
      • Security best practices (restrict by IP, referrer)
  10. Frontend Documentation

    • File: frontend/src/features/stations/README.md
      • Feature overview
      • Component hierarchy diagram (text-based)
      • Hook usage examples
      • Adding new functionality guide
      • Runtime config pattern explanation
      • Testing guide
      • Integration with other features
    • Update: frontend/docs/RUNTIME-CONFIG.md (created by Agent 1)
      • Ensure complete and accurate
  11. Update Main Documentation

    • File: docs/README.md
      • Add "Gas Stations" to features list
      • Brief description: "Search and save gas stations using Google Maps"
      • Link to backend docs: backend/src/features/stations/docs/
      • Link to frontend docs: frontend/src/features/stations/README.md
    • File: backend/src/features/stations/README.md
      • Update with complete feature overview
      • Configuration requirements
      • API endpoints summary
      • Testing instructions
      • Deployment notes
  12. Create User Guide (Optional)

    • File: docs/USER-GUIDE-STATIONS.md
      • How to search for stations
      • How to save favorites
      • How to use in fuel logs
      • Screenshots (if possible)
      • Troubleshooting common issues

Success Criteria

  • All backend tests pass (100%)
  • All frontend tests pass (100%)
  • Test coverage >80% for new code
  • All documentation files created
  • Documentation is clear and accurate
  • Code examples in docs work
  • Main README updated
  • No TypeScript errors
  • Linters pass

Handoff Notes

Testing and documentation complete. Feature is production-ready. All code is tested, documented, and follows project standards.


Final Validation Checklist

After all agents complete, run final validation:

Build & Deploy

make rebuild   # Rebuild all containers
make logs      # Watch for errors
make migrate   # Run database migrations
make test      # Run all tests

Linting

cd backend && npm run lint && npm run type-check
cd frontend && npm run lint && npm run type-check

Manual Testing

  • Desktop: Search stations at https://motovaultpro.com/stations
  • Desktop: Save a station
  • Desktop: View saved stations
  • Desktop: Delete a station
  • Desktop: Map visualization works
  • Mobile: Navigate to stations (/m/stations)
  • Mobile: All 3 tabs work
  • Mobile: Touch targets are 44px minimum
  • Fuel Logs: Station picker works
  • Fuel Logs: Submit log with station
  • Cross-browser: Chrome, Safari, Firefox

Performance

  • Map loads in <2 seconds
  • API responses <500ms
  • Redis caching works (check logs)
  • No memory leaks (React DevTools)

Security

  • All endpoints require JWT auth
  • User data isolation works (can't see other users' saved stations)
  • SQL injection protected (prepared statements)
  • API key not exposed to client (runtime config)

Documentation

  • All docs created and accurate
  • Code examples work
  • Main README updated
  • Google Maps setup guide complete

Standards (per CLAUDE.md)

  • All linters pass with zero issues
  • All tests pass
  • Feature works end-to-end on desktop
  • Feature works end-to-end on mobile
  • Old code deleted (no placeholder routes)
  • No emojis in code or docs
  • Meaningful variable names used

Execution Commands

To execute agents in parallel using Claude Code:

Phase 1 (Parallel)

# Terminal 1
claude-code "Execute Agent 1: Frontend-Secrets-Agent as defined in GAS-STATION-AGENTS.md"

# Terminal 2
claude-code "Execute Agent 2: Backend-Reliability-Agent as defined in GAS-STATION-AGENTS.md"

Phase 2

# Wait for Phase 1 to complete
claude-code "Execute Agent 3: Frontend-Foundation-Agent as defined in GAS-STATION-AGENTS.md"

Phase 3 (Parallel)

# Terminal 1
claude-code "Execute Agent 4: Components-Agent as defined in GAS-STATION-AGENTS.md"

# Terminal 2
claude-code "Execute Agent 5: Map-Visualization-Agent as defined in GAS-STATION-AGENTS.md"

Phase 4 (Parallel)

# Terminal 1
claude-code "Execute Agent 6: Desktop-Mobile-Agent as defined in GAS-STATION-AGENTS.md"

# Terminal 2
claude-code "Execute Agent 7: Integration-Agent as defined in GAS-STATION-AGENTS.md"

Phase 5

# Wait for Phase 4 to complete
claude-code "Execute Agent 8: Testing-Documentation-Agent as defined in GAS-STATION-AGENTS.md"

Notes

  • Each agent is designed to be autonomous and complete its scope independently
  • Agents include clear prerequisites and dependencies
  • Follow CLAUDE.md standards: no emojis, meaningful names, delete old code
  • All implementations follow K8s-aligned patterns (runtime secrets, not build-time)
  • Reference implementation: vehicles feature
  • Testing is mandatory (per CLAUDE.md: must be 100% green)
  • Mobile + Desktop requirement: all features work on both platforms

Estimated Total Time

  • Phase 1: 8 hours (parallel: 8 hours)
  • Phase 2: 4 hours
  • Phase 3: 8 hours (parallel: 8 hours)
  • Phase 4: 8 hours (parallel: 8 hours)
  • Phase 5: 12 hours

Total: 40 hours elapsed (with parallelization) Total: 48 hours of work (across all agents)

Savings from parallelization: 8 hours (17% faster)