# Gas Stations Feature Complete gas station discovery and management feature with Google Maps integration, caching, and user favorites. ## Quick Summary Search nearby gas stations via Google Maps API. Users can view stations on a map, save favorites with custom notes, and integrate station data into fuel logging. Search results cached for 1 hour. JWT required for all endpoints. User data isolation via `user_id`. ## Implementation Phases Status | Phase | Feature | Status | |-------|---------|--------| | 1 | Frontend K8s-aligned secrets pattern | ✅ Complete | | 2 | Backend improvements (circuit breaker, tests) | ✅ Complete | | 3 | Frontend foundation (types, API, hooks) | ✅ Complete | | 4 | Frontend components (card, list, form, map) | ✅ Complete | | 5 | Desktop page with map/search layout | ✅ Complete | | 6 | Mobile screen with tab navigation | 🔄 In Progress | | 7 | Fuel logs integration (StationPicker) | ⏳ Pending | | 8 | Testing (unit, integration, E2E) | ⏳ Pending | | 9 | Documentation (API, setup, troubleshooting) | ⏳ Pending | | 10 | Validation & Polish (lint, tests, manual) | ⏳ Pending | | 11 | Deployment preparation & checklist | ⏳ Pending | ## Architecture ### Backend Structure ``` features/stations/ ├── api/ # HTTP handlers and routes │ ├── stations.controller.ts │ └── stations.routes.ts ├── domain/ # Business logic │ ├── stations.service.ts │ └── stations.types.ts ├── data/ # Database access │ └── stations.repository.ts ├── external/google-maps/ # External API │ ├── google-maps.client.ts │ ├── google-maps.circuit-breaker.ts │ └── google-maps.types.ts ├── jobs/ # Scheduled tasks │ └── cache-cleanup.job.ts ├── migrations/ # Database schema │ ├── 001_create_stations_tables.sql │ └── 002_add_indexes.sql ├── tests/ # Test suite │ ├── fixtures/ │ ├── unit/ │ └── integration/ └── index.ts # Feature exports ``` ### Frontend Structure ``` features/stations/ ├── types/ # TypeScript definitions │ └── stations.types.ts ├── api/ # API client │ └── stations.api.ts ├── hooks/ # React Query hooks │ ├── useStationsSearch.ts │ ├── useSavedStations.ts │ ├── useSaveStation.ts │ ├── useDeleteStation.ts │ └── useGeolocation.ts ├── utils/ # Utilities │ ├── distance.ts │ ├── maps-loader.ts │ └── map-utils.ts ├── components/ # React components │ ├── StationCard.tsx │ ├── StationsList.tsx │ ├── SavedStationsList.tsx │ ├── StationsSearchForm.tsx │ └── StationMap.tsx ├── pages/ # Page layouts │ └── StationsPage.tsx # Desktop ├── mobile/ # Mobile layouts (Phase 6) │ └── StationsMobileScreen.tsx └── __tests__/ # Tests (Phase 8) ``` ## API Endpoints (All require JWT) ``` POST /api/stations/search Body: { latitude, longitude, radius?, fuelType? } Response: { stations[], searchLocation, searchRadius, timestamp } POST /api/stations/save Body: { placeId, nickname?, notes?, isFavorite? } Response: SavedStation GET /api/stations/saved Response: SavedStation[] GET /api/stations/saved/:placeId Response: SavedStation | 404 PATCH /api/stations/saved/:placeId Body: { nickname?, notes?, isFavorite? } Response: SavedStation DELETE /api/stations/saved/:placeId Response: 204 ``` ## Database Schema ### station_cache Temporary Google Places results (auto-cleanup after 24h) ```sql - id: UUID PRIMARY KEY - place_id: VARCHAR UNIQUE - name: VARCHAR - address: VARCHAR - latitude: DECIMAL - longitude: DECIMAL - rating: DECIMAL - photo_url: VARCHAR - created_at: TIMESTAMP ``` ### saved_stations User's favorite stations with metadata ```sql - id: UUID PRIMARY KEY - user_id: VARCHAR (indexed) - place_id: VARCHAR (indexed) - nickname: VARCHAR - notes: TEXT - is_favorite: BOOLEAN - created_at: TIMESTAMP - updated_at: TIMESTAMP - deleted_at: TIMESTAMP (soft delete) - UNIQUE(user_id, place_id) ``` ## Key Features Implemented ✅ **Security** - User-scoped data isolation via `user_id` filtering - Parameterized queries (no SQL injection) - JWT authentication required on all endpoints - K8s-aligned secrets pattern (never in environment variables) ✅ **Performance** - Redis caching with 1-hour TTL - Circuit breaker for resilience (10s timeout, 50% threshold) - Database indexes on user_id and place_id - Scheduled cache cleanup (24h auto-expiry) - Lazy-loaded Google Maps API in browser ✅ **User Experience** - Real-time browser geolocation with permission handling - Touch-friendly 44px minimum button heights - Responsive map with auto-fit bounds - Saved stations with custom nicknames and notes - One-click directions to Google Maps ## Testing ### Run Tests ```bash # Backend feature tests cd backend npm test -- features/stations # Frontend component tests (Phase 8) cd frontend npm test -- stations # E2E tests (Phase 8) npm run e2e ``` ### Coverage Goals - Backend: >80% coverage - Frontend components: >80% coverage - All critical paths tested ## Deployment ### Prerequisites 1. Google Maps API key with Places API enabled 2. PostgreSQL database with migrations applied 3. Redis cache service running 4. Docker for containerization ### Setup ```bash # Create secrets directory mkdir -p ./secrets/app # Add Google Maps API key echo "YOUR_API_KEY_HERE" > ./secrets/app/google-maps-api-key.txt # Build and start make setup make logs # Verify curl http://localhost:3001/health ``` ### Verification ```bash # Check secrets mounted docker compose exec mvp-frontend cat /run/secrets/google-maps-api-key # Check config generated docker compose exec mvp-frontend cat /usr/share/nginx/html/config.js # Test API endpoint curl -H "Authorization: Bearer $TOKEN" http://localhost:3001/api/stations/saved ``` ## Next Steps (Phases 6-11) ### Phase 6: Mobile Implementation Create mobile bottom-tab navigation screen with Search, Saved, Map tabs. ### Phase 7: Fuel Logs Integration Add StationPicker component with autocomplete to FuelLogForm. ### Phases 8-11: Testing, Docs, Validation, Deployment Follow the detailed plan in `/docs/GAS-STATIONS.md`. ## References - Full implementation plan: `/docs/GAS-STATIONS.md` - Runtime config pattern: `/frontend/docs/RUNTIME-CONFIG.md` - Design patterns: See Platform feature (`backend/src/features/platform/`) - Component patterns: See Vehicles feature (`frontend/src/features/vehicles/`)