# 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 `` 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: ```yaml - ./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` - POST /api/stations/search - Include JWT in Authorization header - Return stations array - Function `saveStation(data: SaveStationData): Promise` - POST /api/stations/save - Include JWT in Authorization header - Return saved station with full details - Function `getSavedStations(): Promise` - GET /api/stations/saved - Include JWT in Authorization header - Return array of user's saved stations - Function `deleteSavedStation(placeId: string): Promise` - 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` - 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` - 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: `Stations (TODO)} />` - Add: `} />` - 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: `} />` - 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 ```bash make rebuild # Rebuild all containers make logs # Watch for errors make migrate # Run database migrations make test # Run all tests ``` ### Linting ```bash 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) ```bash # 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 ```bash # Wait for Phase 1 to complete claude-code "Execute Agent 3: Frontend-Foundation-Agent as defined in GAS-STATION-AGENTS.md" ``` ### Phase 3 (Parallel) ```bash # 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) ```bash # 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 ```bash # 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)**