diff --git a/docs/GAS-STATION-AGENTS.md b/docs/GAS-STATION-AGENTS.md new file mode 100644 index 0000000..45a1b56 --- /dev/null +++ b/docs/GAS-STATION-AGENTS.md @@ -0,0 +1,1118 @@ +# 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)** diff --git a/docs/GAS-STATIONS.md b/docs/GAS-STATIONS.md new file mode 100644 index 0000000..869c2c5 --- /dev/null +++ b/docs/GAS-STATIONS.md @@ -0,0 +1,648 @@ +Gas Stations Feature - Complete Implementation Plan (K8s-Aligned Secrets) + + Overview + + Implement complete Gas Stations feature with full integration, map visualization, backend improvements, and comprehensive testing. Uses K8s-aligned runtime + secrets pattern for frontend Google Maps API key. + + Phase 1: Frontend Secrets Infrastructure (K8s-Aligned) + + 1.1 Create Frontend Config Loader + + Create frontend/scripts/load-config.sh: + - Bash script that runs as container entrypoint + - Reads /run/secrets/google-maps-api-key + - Generates /usr/share/nginx/html/config.js with: window.CONFIG = { googleMapsApiKey: '...' } + - Falls back to empty string if secret not found + - Logs success/failure for debugging + + 1.2 Update Frontend Dockerfile + + Modify frontend/Dockerfile: + - Copy load-config.sh into image + - Make script executable + - Add SECRETS_DIR environment variable (default: /run/secrets) + - Update CMD to run script before nginx: ["sh", "-c", "/app/load-config.sh && nginx -g 'daemon off;'"] + + 1.3 Update Frontend index.html + + Modify frontend/index.html: + - Add before app bundle + - Config loads before React app initializes + - Add TypeScript types for window.CONFIG + + 1.4 Create Frontend Config Types + + Create frontend/src/core/config/config.types.ts: + - Interface for window.CONFIG + - Export typed accessor: getConfig() + - Runtime validation (throw if required values missing) + + 1.5 Update docker-compose.yml + + Add to mvp-frontend service: + volumes: + - ./secrets/app/google-maps-api-key.txt:/run/secrets/google-maps-api-key:ro + environment: + SECRETS_DIR: /run/secrets + + 1.6 Document Pattern + + Create frontend/docs/RUNTIME-CONFIG.md: + - Explain runtime config pattern + - How to add new runtime secrets + - K8s deployment notes + - Local development setup + + Phase 2: Backend Improvements + + 2.1 Add Circuit Breaker Pattern + + - Install opossum package: backend/package.json + - Create backend/src/features/stations/external/google-maps/google-maps.circuit-breaker.ts + - Update google-maps.client.ts to wrap API calls + - Follow platform feature pattern (reference: backend/src/features/platform/) + - Config: 10s timeout, 50% threshold, 30s reset + + 2.2 Backend Unit Tests + + Create backend/src/features/stations/tests/unit/: + - stations.service.test.ts - Business logic, user isolation + - stations.repository.test.ts - Database operations, SQL queries + - google-maps.client.test.ts - API mocking, distance calculation + - Use test fixtures for sample data + + 2.3 Backend Integration Tests + + Create backend/src/features/stations/tests/integration/: + - stations.api.test.ts - Full endpoint testing with real database + - saved-stations.flow.test.ts - Save, retrieve, delete workflow + - Use test database (configured in test setup) + + 2.4 Test Fixtures + + Create backend/src/features/stations/tests/fixtures/: + - mock-stations.ts - Sample station objects + - mock-google-response.ts - Mock Google Places API responses + - test-coordinates.ts - Test location data + + 2.5 Cache Cleanup Job + + Create backend/src/features/stations/jobs/cache-cleanup.job.ts: + - Scheduled job (daily at 2 AM) + - Delete station_cache entries older than 24 hours + - Log cleanup metrics (rows deleted) + - Register in main app scheduler + + Phase 3: Frontend Foundation + + 3.1 Type Definitions + + Create frontend/src/features/stations/types/stations.types.ts: + - Station interface (id, name, address, location, rating, distance, photoUrl, prices) + - SavedStation interface (extends Station, adds nickname, notes, isFavorite) + - SearchRequest interface (latitude, longitude, radius?, fuelType?) + - SearchResponse interface + - MapMarker interface for map pins + + 3.2 API Client + + Create frontend/src/features/stations/api/stations.api.ts: + - searchStations(request: SearchRequest): Promise + - saveStation(placeId: string, data: SaveStationData): Promise + - getSavedStations(): Promise + - deleteSavedStation(placeId: string): Promise + - Use axios with proper error handling + - Add request/response logging + + 3.3 React Query Hooks + + Create frontend/src/features/stations/hooks/: + + useStationsSearch.ts: + - Mutation hook for search (not cached by default) + - Accepts SearchRequest + - Returns Station array + - Integrates with useGeolocation + + useSavedStations.ts: + - Query hook with React Query caching + - Auto-refetch on window focus + - Invalidate on save/delete mutations + + useSaveStation.ts: + - Mutation hook + - Optimistic updates to saved list + - Invalidates saved stations cache on success + + useDeleteStation.ts: + - Mutation hook + - Optimistic removal from list + - Invalidates cache on success + + useGeolocation.ts: + - Browser Geolocation API wrapper + - Permission handling + - Error states (permission denied, unavailable, timeout) + - Returns current position + + 3.4 Google Maps Integration + + Create frontend/src/features/stations/utils/maps-loader.ts: + - Load Google Maps JavaScript API dynamically + - Use runtime config: getConfig().googleMapsApiKey + - Promise-based API + - Singleton pattern (load once) + - TypeScript types for Google Maps objects + + Phase 4: Frontend Components + + 4.1 Core Components + + Create frontend/src/features/stations/components/: + + StationCard.tsx: + - Material-UI Card component + - Props: station, onSave, onDelete, isSaved + - Display: name (Typography h6), address (Typography body2), distance (Chip) + - Rating stars (Rating component) + - Price display (if available) + - Photo thumbnail (if available) + - Save/Unsave IconButton (BookmarkIcon / BookmarkBorderIcon) + - Directions link (opens Google Maps) + - Mobile: 44px min height, touch targets + - Desktop: hover effects + + StationsList.tsx: + - Container for search results + - Props: stations[], loading, error, onSaveStation + - Grid layout (responsive: 1 col mobile, 2 cols tablet, 3 cols desktop) + - Loading skeleton (Skeleton components) + - Empty state: "No stations found. Try adjusting your search." + - Error state with retry button + + SavedStationsList.tsx: + - User's favorites display + - Props: savedStations[], onDelete, onSelect + - List layout (vertical) + - Show nickname if set, otherwise station name + - Notes preview (truncated) + - Distance from current location (optional) + - Delete IconButton + - Empty state: "No saved stations yet. Save stations from search results." + + StationsSearchForm.tsx: + - Form with search parameters + - Current Location button (uses useGeolocation) + - Manual lat/lng inputs (number fields) + - Radius slider (FormControl, Slider: 1-25 miles, default 5) + - Fuel type select (optional filter) + - Search button (LoadingButton) + - Loading states on button + - Validation: require location (current OR manual) + - Error display for geolocation failures + + StationMap.tsx: + - Google Maps embed component + - Props: stations[], center, zoom, onMarkerClick + - Load map using maps-loader utility + - Station markers (color-coded: blue=normal, gold=saved) + - Current location marker (red pin) + - Info windows on marker click (station details + save button) + - Directions button in info window + - Zoom controls, pan controls + - Responsive height (300px mobile, 500px desktop) + + 4.2 UI Utilities + + Create frontend/src/features/stations/utils/: + + distance.ts: + - formatDistance(meters: number): string - "1.2 mi" or "0.3 mi" + - calculateDistance(lat1, lng1, lat2, lng2): number - Haversine formula + + location.ts: + - getCurrentPosition(): Promise + - requestLocationPermission(): Promise + - Error handling helpers + + map-utils.ts: + - createStationMarker(station, map, isSaved): google.maps.Marker + - createInfoWindow(station): google.maps.InfoWindow + - fitBoundsToMarkers(map, markers): void + + Phase 5: Desktop Implementation + + 5.1 Desktop Page + + Create frontend/src/features/stations/pages/StationsPage.tsx: + - Layout: Grid container + - Left column (60%): StationMap (full height) + - Right column (40%): + - StationsSearchForm at top + - Tabs: "Search Results" | "Saved Stations" + - Tab 1: StationsList + - Tab 2: SavedStationsList + - State management: + - searchResults (from search mutation) + - savedStations (from query) + - selectedStation (for map focus) + - Effects: + - Load saved stations on mount + - Update map when search results change + - Mobile breakpoint: Stack vertically (map on top) + + 5.2 Desktop Routing + + Update frontend/src/App.tsx (line 556): + - Remove: Stations (TODO)} /> + - Add: } /> + - Import: import { StationsPage } from './features/stations/pages/StationsPage' + - Ensure route is inside ProtectedRoute wrapper + + Phase 6: Mobile Implementation + + 6.1 Mobile Screen + + Create frontend/src/features/stations/pages/StationsMobileScreen.tsx: + - BottomNavigation with 3 tabs: Search, Saved, Map + - Tab 0 (Search): + - StationsSearchForm (compact mode) + - StationsList (vertical scroll) + - Pull-to-refresh support + - Tab 1 (Saved): + - SavedStationsList (full screen) + - Swipe to delete gestures + - Tab 2 (Map): + - StationMap (full screen, 100vh) + - Floating search button (FAB) to go back to search tab + - Bottom sheet for station details (SwipeableDrawer) + - Touch targets: 44px minimum + - Safe area insets for notched devices + + 6.2 Mobile Routing + + Update frontend/src/App.tsx: + - Add mobile route: } /> + - Update mobile navigation items (add stations) + - Ensure icon is interactive (onClick navigation) + + Phase 7: Fuel Logs Integration + + 7.1 Station Picker Component + + Create frontend/src/features/fuel-logs/components/StationPicker.tsx: + - Autocomplete component (Material-UI) + - Props: value, onChange, userLocation? + - Options: + - Saved stations (shown first, grouped) + - Nearby stations (if location available) + - Manual text input (freeSolo mode) + - Option rendering: + - Station name (primary) + - Distance + address (secondary) + - Bookmark icon if saved + - Debounced search (300ms) + - Loading indicator while searching + - Fallback to text input if API fails + + 7.2 Update Fuel Log Form + + Modify frontend/src/features/fuel-logs/components/FuelLogForm.tsx: + - Replace LocationInput with StationPicker + - Props: pass user location from geolocation + - Value binding to stationName field + - Maintain backward compatibility (accepts text string) + - Show nearby stations on field focus + - Optional: "Save this station" checkbox when new station entered + + 7.3 Integration Features + + Optional enhancements: + - In FuelLogCard, link station name to station details + - In StationsPage, show "Recent fuel logs at this station" + - Suggest saving station after logging fuel at new location + + Phase 8: Testing + + 8.1 Backend Tests Execution + + cd backend + npm test -- features/stations + - Verify all unit tests pass + - Verify all integration tests pass + - Check coverage report (aim for >80%) + - Fix any failing tests + + 8.2 Frontend Component Tests + + Create frontend/src/features/stations/__tests__/components/: + - StationCard.test.tsx - Rendering, save/delete actions + - StationsList.test.tsx - List rendering, empty/error states + - SavedStationsList.test.tsx - Saved list, delete action + - StationsSearchForm.test.tsx - Form validation, submission + - StationMap.test.tsx - Map initialization (with mocks) + - Use React Testing Library + - Mock API calls with MSW (Mock Service Worker) + + 8.3 Frontend Page Tests + + Create frontend/src/features/stations/__tests__/pages/: + - StationsPage.test.tsx - Desktop page integration + - StationsMobileScreen.test.tsx - Mobile navigation, tabs + - Test user workflows: search, save, delete + - Test error handling and loading states + + 8.4 API Client Tests + + Create frontend/src/features/stations/api/__tests__/: + - stations.api.test.ts - Test all API methods + - Mock axios responses + - Test error handling (network, 401, 500) + - Verify request payloads + + 8.5 React Query Hook Tests + + Create frontend/src/features/stations/hooks/__tests__/: + - Test each hook in isolation + - Mock React Query + - Test loading, success, error states + - Test cache invalidation logic + - Test optimistic updates + + 8.6 E2E Tests + + Create frontend/cypress/e2e/stations.cy.ts (or similar E2E framework): + - Test: Search for nearby stations + - Test: Save a station to favorites + - Test: View saved stations list + - Test: Delete a saved station + - Test: Use station in fuel log entry + - Test: Mobile navigation flow + - Test: Map marker click and info window + - Use real backend API in test environment + + Phase 9: Documentation + + 9.1 Backend Feature Docs + + Create backend/src/features/stations/docs/: + + ARCHITECTURE.md: + - System design overview + - Data flow diagrams + - External dependencies (Google Maps API) + - Caching strategy + - Database schema + - Circuit breaker pattern + + API.md: + - All endpoint documentation + - Request/response examples (curl commands) + - Authentication requirements + - Rate limits and quotas + - Error responses + + TESTING.md: + - How to run tests + - Test database setup + - Writing new tests + - Coverage goals + + GOOGLE-MAPS-SETUP.md: + - API key creation in Google Cloud Console + - Required APIs to enable + - Quota management + - Cost estimation + - Security best practices + + 9.2 Frontend Feature Docs + + Create frontend/src/features/stations/README.md: + - Feature overview + - Component hierarchy + - Hook usage examples + - Adding new functionality + - Runtime config pattern + - Testing guide + + 9.3 Runtime Config Documentation + + Already created in Phase 1.6: frontend/docs/RUNTIME-CONFIG.md + + 9.4 Update Main Documentation + + Update docs/README.md: + - Add "Gas Stations" to features list + - Link to backend and frontend docs + - Mention Google Maps integration + + Update backend/src/features/stations/README.md: + - Complete feature overview + - Configuration requirements + - API endpoints summary + - Testing instructions + - Deployment notes + + Phase 10: Validation & Polish + + 10.1 Docker Build & Test + + make rebuild # Rebuild all containers + make logs # Watch for errors + make migrate # Run database migrations + make test # Run all tests + + Verify: + - Frontend config.js is generated at startup + - Backend loads Google Maps API key from secret + - All containers start without errors + - Database migrations create tables + - Tests pass in container environment + + 10.2 Linting & Formatting + + # Backend + cd backend && npm run lint && npm run type-check + + # Frontend + cd frontend && npm run lint && npm run type-check + + Fix all issues (MUST be 100% green per CLAUDE.md): + - Zero TypeScript errors + - Zero ESLint warnings + - Zero Prettier formatting issues + + 10.3 Manual Testing - Desktop + + - Open https://motovaultpro.com/stations in browser + - Test geolocation permission flow + - Search for stations near current location + - Verify map loads with markers + - Click marker, verify info window + - Save a station + - View saved stations list + - Delete a saved station + - Test manual lat/lng search + - Test with no results (remote location) + - Test error handling (API failure) + + 10.4 Manual Testing - Mobile + + - Open mobile nav, navigate to Stations + - Test all 3 tabs (Search, Saved, Map) + - Verify 44px touch targets + - Test swipe gestures + - Test bottom sheet interactions + - Verify responsive layout + - Test on actual mobile device (if possible) + + 10.5 Fuel Logs Integration Testing + + - Navigate to Fuel Logs + - Create new fuel log entry + - Test StationPicker autocomplete + - Select a saved station + - Enter new station name + - Submit fuel log + - Verify station name is saved + + 10.6 Cross-Browser Testing + + Test on: + - Chrome (latest) + - Safari (latest) + - Firefox (latest) + - Mobile Safari (iOS) + - Mobile Chrome (Android) + + 10.7 Performance Validation + + - Check map load time (<2s) + - Verify API response times (<500ms) + - Check Redis cache hits (backend logs) + - Monitor Google Maps API quota usage + - Verify no memory leaks (React DevTools Profiler) + + Phase 11: Deployment Preparation + + 11.1 Configuration Checklist + + Backend: + - Secret file exists: ./secrets/app/google-maps-api-key.txt + - Docker compose mounts secret to /run/secrets/google-maps-api-key + - Backend config loader reads from SECRETS_DIR + + Frontend: + - Secret file mounted: /run/secrets/google-maps-api-key + - Entrypoint script generates /usr/share/nginx/html/config.js + - index.html loads config.js before app + - App accesses via getConfig().googleMapsApiKey + + 11.2 Database Migration + + make migrate + Verify: + - Migration 001_create_stations_tables.sql runs successfully + - Tables created: station_cache, saved_stations + - Indexes created on both tables + - Test queries work + + 11.3 Secrets Verification + + # Verify backend can read secret + docker compose exec mvp-backend cat /run/secrets/google-maps-api-key + + # Verify frontend generates config + docker compose exec mvp-frontend cat /usr/share/nginx/html/config.js + # Should show: window.CONFIG = { googleMapsApiKey: "..." } + + 11.4 Health Checks + + - Verify /health endpoint includes stations feature + - Test stations API endpoints with curl: + # Get JWT token first + TOKEN="your-jwt-token" + + # Search stations + curl -X POST http://localhost:3001/api/stations/search \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"latitude": 37.7749, "longitude": -122.4194}' + + # Get saved stations + curl http://localhost:3001/api/stations/saved \ + -H "Authorization: Bearer $TOKEN" + + 11.5 Production Readiness + + Update config/app/production.yml.example: + - Document Google Maps API key requirement + - Add example configuration + + Create deployment checklist: + - Google Maps API key in secrets + - Frontend container mounts secret + - Backend container mounts secret + - Database migrations run + - All tests pass + - Linters pass + - Manual testing complete + - Performance acceptable + - Documentation complete + + Success Criteria (per CLAUDE.md) + + - All linters pass with zero issues + - All tests pass (backend + frontend) + - Feature works end-to-end on desktop + - Feature works end-to-end on mobile + - Fuel logs integration functional + - Map visualization working + - Google Maps API integration live via runtime secrets + - K8s-aligned secrets pattern implemented + - Documentation complete + - Old code deleted (no orphaned files) + + K8s Secrets Pattern Summary + + Backend (already implemented): + - Secret mounted: /run/secrets/google-maps-api-key + - Read at runtime by config-loader.ts + - Never in environment variables or code + + Frontend (new implementation): + - Secret mounted: /run/secrets/google-maps-api-key + - Read at container startup by entrypoint script + - Injected into config.js served with static files + - App loads config at runtime via window.CONFIG + - Can be updated by restarting container (no rebuild) + + This mirrors K8s deployment where: + - Secrets are mounted as volumes + - Applications read them at runtime + - Secrets can be rotated without rebuilding images + + Estimated Timeline + + - Phase 1 (Frontend Secrets): 1 day + - Phase 2 (Backend): 1 day + - Phase 3 (Foundation): 0.5 day + - Phase 4 (Components): 1 day + - Phase 5 (Desktop): 0.5 day + - Phase 6 (Mobile): 0.5 day + - Phase 7 (Integration): 0.5 day + - Phase 8 (Testing): 1.5 days + - Phase 9 (Docs): 0.5 day + - Phase 10 (Validation): 0.5 day + - Phase 11 (Deployment): 0.5 day + + Total: 8 days (full implementation with K8s-aligned secrets) + + Reference Implementations + + - Secrets pattern: Backend config-loader.ts and docker-compose.yml + - Feature structure: frontend/src/features/vehicles/ + - Component patterns: Vehicles components + - Testing: Vehicles test suite + - Mobile + Desktop: Vehicles pages \ No newline at end of file diff --git a/docs/PLATFORM-INTEGRATION-AGENTS.md b/docs/PLATFORM-INTEGRATION-AGENTS.md deleted file mode 100644 index e4e0c11..0000000 --- a/docs/PLATFORM-INTEGRATION-AGENTS.md +++ /dev/null @@ -1,1189 +0,0 @@ -# Platform Service Integration - Agent Execution Manifest - -## Overview - -Integration of mvp-platform vehicles service into backend as a feature module. This document defines specialized agents for parallel execution. - -**Goal**: Convert 6-container architecture to 5-container by absorbing platform service into backend. - -**Strategy**: Single-phase cutover with parallel agent execution. - -**Estimated Duration**: 6-8 hours with 7 agents running in parallel. - ---- - -## Execution Waves - -### Wave 1: Parallel Foundation (4 agents) -Can execute simultaneously, no dependencies. - -- **Agent 1**: Backend Feature Creator -- **Agent 2**: VIN Removal - Backend -- **Agent 3**: VIN Removal - Frontend -- **Agent 4**: Configuration Cleanup - -### Wave 2: Integration & Testing (2 agents) -Depends on Wave 1 completion. - -- **Agent 5**: Integration & Testing -- **Agent 6**: Documentation Updates - -### Wave 3: Final Cleanup (1 agent) -Depends on Wave 2 completion. - -- **Agent 7**: Container Removal & Deployment - ---- - -## Agent Definitions - -## AGENT 1: Backend Feature Creator - -**Role**: Create new vehicle-data feature module in TypeScript - -**Subagent Type**: `feature-agent` - -**Dependencies**: None (can start immediately) - -**Deliverables**: -- Complete feature structure in `backend/src/features/vehicle-data/` -- TypeScript repository with all SQL queries converted from Python -- Caching service using Redis -- API routes and controllers -- Request/response DTOs -- Feature README - -**Prompt**: -``` -Create a new feature module at backend/src/features/vehicle-data/ that replaces the Python FastAPI platform service. - -CONTEXT: -- Source: /Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/vehicles/ -- Python FastAPI service with vehicle hierarchical data (makes/models/trims/engines) -- Uses vehicles schema in PostgreSQL (vehicles.make, vehicles.model, etc.) -- Redis caching with 6-hour TTL -- Authentication via JWT (extract user_id) - -REQUIREMENTS: - -1. CREATE FEATURE STRUCTURE: -backend/src/features/vehicle-data/ -├── api/ -│ ├── vehicle-data.routes.ts # Fastify routes -│ └── vehicle-data.controller.ts # Controllers -├── domain/ -│ ├── vehicle-data.service.ts # Business logic -│ └── vehicle-data.cache.ts # Redis caching -├── data/ -│ └── vehicle-data.repository.ts # PostgreSQL queries -├── models/ -│ ├── requests.ts # DTOs -│ └── responses.ts # DTOs -├── tests/ -│ ├── unit/ -│ └── integration/ -└── README.md - -2. CONVERT PYTHON TO TYPESCRIPT: - -Source files: -- Python repo: mvp-platform-services/vehicles/api/repositories/vehicles_repository.py -- Python service: mvp-platform-services/vehicles/api/services/vehicles_service.py -- Python cache: mvp-platform-services/vehicles/api/services/cache_service.py - -Convert these methods: -- get_years() → SELECT DISTINCT year FROM vehicles.model_year ORDER BY year DESC -- get_makes(year) → Join vehicles.make through model_year -- get_models(year, make_id) → Join vehicles.model through model_year -- get_trims(year, model_id) → Get trims for model/year -- get_engines(year, model_id, trim_id) → Get engines via trim_engine - -3. IMPLEMENT CACHING: -- Use Redis from backend core (already connected) -- Cache keys: vehicle-data:makes:{year}, vehicle-data:models:{year}:{makeId}, etc. -- TTL: 6 hours (21600 seconds) -- Graceful fallback if Redis unavailable - -4. CREATE API ROUTES: -All routes require JWT authentication: -- GET /api/vehicle-data/years -- GET /api/vehicle-data/makes?year={year} -- GET /api/vehicle-data/models?year={year}&make_id={id} -- GET /api/vehicle-data/trims?year={year}&model_id={id} -- GET /api/vehicle-data/engines?year={year}&trim_id={id} - -5. RESPONSE FORMATS (match Python service): -{ - "years": [2024, 2023, 2022, ...], - "makes": [{ id: 1, name: "Honda" }, ...], - "models": [{ id: 1, name: "Civic" }, ...], - "trims": [{ id: 1, name: "LX" }, ...], - "engines": [{ id: 1, name: "2.0L I4" }, ...] -} - -6. ERROR HANDLING: -- Validate query parameters (year 1950-2100, IDs positive integers) -- Return 400 for invalid input -- Return 404 if no data found -- Log errors but don't expose internal details - -7. REGISTER ROUTES: -Update backend/src/app.ts to register feature: -import { vehicleDataRoutes } from './features/vehicle-data/api/vehicle-data.routes'; -app.register(vehicleDataRoutes, { prefix: '/api/vehicle-data' }); - -CONSTRAINTS: -- Use existing PostgreSQL pool from core -- Use existing Redis client from core -- Follow feature capsule pattern (see backend/src/features/vehicles/ as example) -- NO VIN decoding (that's being removed) -- Production-ready code (error handling, logging, validation) - -VERIFICATION: -- All TypeScript compiles without errors -- Routes registered in app.ts -- Repository queries match Python SQL logic -- Caching implementation complete -- Feature README documents all endpoints - -Return confirmation when complete with file paths created. -``` - -**Success Criteria**: -- ✅ Feature structure created -- ✅ All Python logic converted to TypeScript -- ✅ Caching implemented -- ✅ Routes registered -- ✅ TypeScript compiles -- ✅ README complete - -**Estimated Time**: 3-4 hours - ---- - -## AGENT 2: VIN Removal - Backend - -**Role**: Remove all VIN decoding logic from backend - -**Subagent Type**: `general-purpose` - -**Dependencies**: None (can start immediately) - -**Deliverables**: -- Removed VIN decode methods from platform client -- Removed vPIC fallback client -- Updated vehicles service (no auto-populate from VIN) -- Updated vehicle creation to require make/model/year -- Removed VIN cache methods -- Removed circuit breaker for VIN decode - -**Prompt**: -``` -Remove all VIN decoding functionality from the backend codebase. - -CONTEXT: -VIN decoding is being removed as a feature. Users will manually select make/model/year instead of auto-populating from VIN. - -TASKS: - -1. DELETE ENTIRE DIRECTORY: -backend/src/features/vehicles/external/platform-vehicles/ -- This contains the platform client with VIN decode -- The entire external integration is being replaced - -2. DELETE FILE: -backend/src/features/vehicles/domain/platform-integration.service.ts -- This service wraps platform calls and vPIC fallback -- No longer needed - -3. UPDATE VEHICLES SERVICE: -File: backend/src/features/vehicles/domain/vehicles.service.ts - -Remove: -- Import of PlatformIntegrationService -- Constructor dependency on platformIntegration -- Any calls to platformIntegration.decodeVIN() -- Auto-population of make/model/year from VIN - -Keep VIN as optional string field (for user reference only). - -4. UPDATE VEHICLES REPOSITORY: -File: backend/src/features/vehicles/data/vehicles.repository.ts - -Remove: -- cacheVINDecode() method -- Any VIN cache queries -- VIN decode cache table references - -5. UPDATE VEHICLE CREATION: -File: backend/src/features/vehicles/api/vehicles.controller.ts - -Update createVehicle endpoint: -- Remove VIN decode step -- Require make, model, year in request body (not optional) -- VIN field optional (string for reference only) - -6. UPDATE VALIDATION: -File: backend/src/features/vehicles/models/requests.ts - -Update CreateVehicleRequest: -- make: REQUIRED string -- model: REQUIRED string -- year: REQUIRED number (1950-2100) -- vin: OPTIONAL string (17 chars if provided) - -7. REMOVE CIRCUIT BREAKER: -Check package.json for opossum dependency: -- If ONLY used for platform service, remove from package.json -- If used elsewhere, keep but remove platform-specific circuit breaker config - -8. REMOVE VPIC CLIENT: -Search for vPIC/NHTSA API client: -- Remove any vPIC fallback client files -- Remove VPIC_API_URL environment variable references - -9. UPDATE TESTS: -backend/src/features/vehicles/tests/ -- Delete: unit/platform-vehicles.client.test.ts -- Update: integration/vehicles.integration.test.ts - - Remove VIN decode test scenarios - - Update create vehicle tests (now requires make/model/year) - -VERIFICATION: -- No references to "platform-vehicles" in backend code -- No references to "vindecode" or "decodeVIN" -- No references to "vPIC" or "NHTSA" -- Vehicle creation requires make/model/year -- All tests updated and passing -- TypeScript compiles without errors - -Return list of files deleted and modified with confirmation. -``` - -**Success Criteria**: -- ✅ Platform integration deleted -- ✅ VIN decode logic removed -- ✅ Vehicle creation updated -- ✅ Tests updated -- ✅ No VIN references remain - -**Estimated Time**: 2-3 hours - ---- - -## AGENT 3: VIN Removal - Frontend - -**Role**: Remove VIN decoding from frontend UI - -**Subagent Type**: `first-frontend-agent` - -**Dependencies**: None (can start immediately) - -**Deliverables**: -- Removed VIN decode button/functionality -- Updated vehicle form to require make/model/year dropdowns -- Updated form validation -- Updated user experience (manual selection) - -**Prompt**: -``` -Remove VIN decoding functionality from the frontend and update vehicle creation form to require manual make/model/year selection. - -CONTEXT: -VIN decoding is being removed. Users will now manually select vehicle details from dropdowns instead of auto-populating from VIN. - -TASKS: - -1. FIND VEHICLE CREATION FORM: -Search for vehicle creation/edit components: -- Likely in: frontend/src/features/vehicles/ or frontend/src/components/vehicles/ -- Look for: CreateVehicle, VehicleForm, AddVehicle components - -2. REMOVE VIN DECODE UI: -Remove: -- "Decode VIN" button -- VIN input auto-complete/lookup functionality -- Any loading states for VIN decode -- Success/error messages for VIN decode - -3. UPDATE FORM FIELDS: -Make these fields REQUIRED with dropdowns: -- Make: Dropdown populated from /api/vehicle-data/makes?year={year} -- Model: Dropdown populated from /api/vehicle-data/models?year={year}&make_id={makeId} -- Year: Dropdown populated from /api/vehicle-data/years -- Trim: Optional dropdown from /api/vehicle-data/trims -- Engine: Optional dropdown from /api/vehicle-data/engines - -Make VIN field OPTIONAL (text input for reference only). - -4. IMPLEMENT CASCADING DROPDOWNS: -- Year selection → loads Makes -- Make selection → loads Models -- Model selection → loads Trims -- Trim selection → loads Engines - -5. UPDATE API CALLS: -Change from: -- /api/vehicles/dropdown/* (old platform proxy) - -To: -- /api/vehicle-data/years -- /api/vehicle-data/makes?year={year} -- /api/vehicle-data/models?year={year}&make_id={id} - -6. UPDATE FORM VALIDATION: -- Require year, make, model -- VIN optional (17 chars if provided) -- Show clear error messages for required fields - -7. UPDATE USER EXPERIENCE: -- Add help text: "Select your vehicle from the dropdowns below" -- Clear dependent dropdowns when parent changes (e.g., clear Models when Make changes) -- Show loading states while fetching dropdown data - -8. TEST ON MOBILE + DESKTOP: -- Dropdowns work on mobile -- Touch-friendly dropdown selection -- Responsive layout -- No horizontal scrolling - -9. REMOVE VIN DECODE UTILITIES: -Search for and remove: -- VIN validation functions (if only used for decode) -- VIN formatting utilities -- API client methods for VIN decode - -VERIFICATION: -- No "Decode VIN" button in UI -- Vehicle form has year/make/model dropdowns (required) -- Cascading dropdowns work correctly -- VIN field is optional -- Form validation updated -- Works on mobile and desktop -- API calls updated to /api/vehicle-data/* -- npm run build succeeds -- npm run lint passes - -Return confirmation with screenshots of updated form (mobile + desktop). -``` - -**Success Criteria**: -- ✅ VIN decode UI removed -- ✅ Dropdowns implemented -- ✅ Cascading logic works -- ✅ Mobile + desktop tested -- ✅ Validation updated - -**Estimated Time**: 2-3 hours - ---- - -## AGENT 4: Configuration Cleanup - -**Role**: Remove platform service from docker-compose and configuration - -**Subagent Type**: `general-purpose` - -**Dependencies**: None (can start immediately) - -**Deliverables**: -- Updated docker-compose.yml (remove mvp-platform) -- Removed environment variables -- Removed secrets -- Updated Traefik configuration - -**Prompt**: -``` -Remove the mvp-platform service from docker-compose and clean up all related configuration. - -CONTEXT: -The platform service is being absorbed into the backend. The mvp-platform container will be removed, reducing from 6 to 5 containers. - -TASKS: - -1. UPDATE DOCKER-COMPOSE.YML: -File: /Users/egullickson/Documents/Technology/coding/motovaultpro/docker-compose.yml - -Remove lines 184-227 (entire mvp-platform service definition). - -This includes: -- Service: mvp-platform -- Build context: ./mvp-platform-services/vehicles -- Container name: mvp-platform -- All environment variables -- All volume mounts -- Network connections -- Health check -- Traefik labels - -2. UPDATE BACKEND ENVIRONMENT: -File: docker-compose.yml (mvp-backend service) - -Remove environment variable: -- PLATFORM_VEHICLES_API_URL: http://mvp-platform:8000 - -3. REMOVE FROM ENV FILES: -File: .env.development - -Remove: -- PLATFORM_VEHICLES_API_URL=http://mvp-platform:8000 - -4. UPDATE BACKEND CONFIG: -File: config/app/production.yml - -Remove any platform service references: -- platform_vehicles_api_url -- platform_api_key - -5. DELETE SECRETS: -File: secrets/app/platform-vehicles-api-key.txt - -Delete this file (no longer needed). - -Update docker-compose.yml backend volumes: -Remove secret mount: -- ./secrets/app/platform-vehicles-api-key.txt:/run/secrets/platform-vehicles-api-key:ro - -6. UPDATE TRAEFIK CONFIG: -File: config/traefik/middleware.yml or traefik.yml - -Remove: -- Any router rules for /platform prefix -- Any platform service backends -- Platform health checks - -7. UPDATE MAKEFILE: -File: Makefile - -Remove or update: -- Any platform-specific commands -- Update logs command if it references mvp-platform -- Update rebuild if it specifically references platform - -8. VERIFY NETWORK CONFIGURATION: -Check docker-compose.yml networks section: -- Ensure frontend, backend, database networks still defined -- Remove platform-specific networks if any - -9. VERIFY VOLUME CONFIGURATION: -Check docker-compose.yml volumes section: -- Ensure mvp_postgres_data, mvp_redis_data still defined -- Remove platform-specific volumes if any - -VERIFICATION: -- docker-compose.yml valid YAML (use yamllint or docker compose config) -- Only 5 services defined: mvp-traefik, mvp-frontend, mvp-backend, mvp-postgres, mvp-redis -- No references to "mvp-platform" in config files -- No references to "platform-vehicles-api" -- Secrets file removed -- docker compose config runs without errors - -Return confirmation with list of modified files and line numbers. -``` - -**Success Criteria**: -- ✅ docker-compose.yml updated (5 services) -- ✅ Environment variables removed -- ✅ Secrets deleted -- ✅ Traefik config updated -- ✅ Valid YAML - -**Estimated Time**: 1 hour - ---- - -## AGENT 5: Integration & Testing - -**Role**: Integrate new vehicle-data feature with vehicles feature and create comprehensive tests - -**Subagent Type**: `general-purpose` - -**Dependencies**: Agents 1, 2 complete - -**Deliverables**: -- Vehicles feature updated to use vehicle-data feature -- Unit tests for vehicle-data feature -- Integration tests for full workflow -- All tests passing - -**Prompt**: -``` -Integrate the new vehicle-data feature with the vehicles feature and create comprehensive tests. - -CONTEXT: -- Agent 1 created: backend/src/features/vehicle-data/ -- Agent 2 removed: VIN decode and platform integration -- Now need to connect vehicles feature to vehicle-data feature - -TASKS: - -1. UPDATE VEHICLES SERVICE: -File: backend/src/features/vehicles/domain/vehicles.service.ts - -Add dependency: -import { VehicleDataService } from '../../vehicle-data/domain/vehicle-data.service'; - -Constructor: -constructor( - private repository: VehiclesRepository, - private vehicleData: VehicleDataService // NEW -) {} - -Update dropdown methods to use vehicleData: -- Replace platformIntegration.getMakes() → vehicleData.getMakes() -- Replace platformIntegration.getModels() → vehicleData.getModels() -- etc. - -2. UPDATE VEHICLES CONTROLLER: -File: backend/src/features/vehicles/api/vehicles.controller.ts - -Update dropdown route handlers to call vehicleData service. - -3. UPDATE VEHICLES ROUTES: -File: backend/src/features/vehicles/api/vehicles.routes.ts - -Ensure dropdown routes call updated controller methods. - -4. CREATE UNIT TESTS - VEHICLE DATA: -File: backend/src/features/vehicle-data/tests/unit/vehicle-data.service.test.ts - -Test: -- getYears() returns descending array -- getMakes(year) returns makes for year -- getModels(year, makeId) returns models -- Cache hits work correctly -- Cache misses query database -- Invalid parameters throw errors - -Mock: -- Repository calls -- Redis calls - -5. CREATE UNIT TESTS - REPOSITORY: -File: backend/src/features/vehicle-data/tests/unit/vehicle-data.repository.test.ts - -Test: -- Each SQL query method -- Parameter binding -- Error handling -- Empty result sets - -Mock: -- PostgreSQL pool - -6. CREATE INTEGRATION TESTS: -File: backend/src/features/vehicle-data/tests/integration/vehicle-data.integration.test.ts - -Test full workflow: -1. GET /api/vehicle-data/years → [2024, 2023, ...] -2. GET /api/vehicle-data/makes?year=2024 → [{id: 1, name: "Honda"}, ...] -3. GET /api/vehicle-data/models?year=2024&make_id=1 → [{id: 1, name: "Civic"}, ...] -4. GET /api/vehicle-data/trims?year=2024&model_id=1 → [{id: 1, name: "LX"}, ...] -5. GET /api/vehicle-data/engines?year=2024&trim_id=1 → [{id: 1, name: "2.0L I4"}, ...] - -Test: -- Authentication required (401 without JWT) -- Invalid parameters return 400 -- Caching works (second call faster) -- CORS headers present - -7. UPDATE VEHICLES INTEGRATION TESTS: -File: backend/src/features/vehicles/tests/integration/vehicles.integration.test.ts - -Update: -- Remove VIN decode scenarios -- Update create vehicle to include make/model/year -- Verify validation requires make/model/year -- Test dropdown endpoints still work - -8. RUN ALL TESTS: -Execute: -- npm run test (all unit tests) -- npm run test:integration (all integration tests) - -Fix any failures. - -9. VERIFY TYPE SAFETY: -Execute: -- npm run type-check or npx tsc --noEmit - -Fix any TypeScript errors. - -10. RUN LINTER: -Execute: -- npm run lint - -Fix any linting issues. - -VERIFICATION: -- All unit tests passing -- All integration tests passing -- TypeScript compiles without errors -- Linter passes -- Vehicles feature successfully uses vehicle-data feature -- Dropdown APIs work end-to-end -- Test coverage >80% for new feature - -Return test results summary and any issues found. -``` - -**Success Criteria**: -- ✅ Features integrated -- ✅ Unit tests complete -- ✅ Integration tests complete -- ✅ All tests passing -- ✅ Type-check passes -- ✅ Linter passes - -**Estimated Time**: 2-3 hours - ---- - -## AGENT 6: Documentation Updates - -**Role**: Update all documentation to reflect 5-container architecture - -**Subagent Type**: `general-purpose` - -**Dependencies**: Agents 1, 2, 3, 4 complete - -**Deliverables**: -- Updated architecture documentation -- Updated API documentation -- Updated feature documentation -- Migration notes created - -**Prompt**: -``` -Update all documentation to reflect the new 5-container architecture and removal of platform service. - -CONTEXT: -- Platform service absorbed into backend as vehicle-data feature -- VIN decoding removed -- Architecture now 5 containers (was 6) - -TASKS: - -1. UPDATE ARCHITECTURE OVERVIEW: -File: docs/ARCHITECTURE-OVERVIEW.md - -Changes: -- Update container count: 6 → 5 -- Remove mvp-platform container from list -- Add vehicle-data as backend feature module -- Update architecture diagram (remove platform container) -- Add note: "VIN decoding removed - users manually select vehicle details" - -2. UPDATE VEHICLES API DOCS: -File: docs/VEHICLES-API.md - -Changes: -- Remove all platform service references -- Update API endpoints from /platform/* to /api/vehicle-data/* -- Remove VIN decode endpoint documentation -- Update dropdown endpoint documentation -- Remove platform reset instructions -- Update troubleshooting section - -3. UPDATE DATABASE SCHEMA DOCS: -File: docs/DATABASE-SCHEMA.md - -Changes: -- Clarify vehicles schema accessed by vehicle-data feature (backend module) -- Remove VIN decode function references (f_decode_vin) -- Add note: "vehicles schema managed by vehicle-data feature" - -4. UPDATE ROOT README: -File: README.md - -Changes: -- Line 1-3: Change "6 containers" to "5 containers" -- Remove mvp-platform from container list -- Update quick start section (5 containers expected) - -5. UPDATE CLAUDE.MD: -File: CLAUDE.md - -Changes: -- Line 94-95: Update architecture description to "5 containers: Traefik, Frontend, Backend, PostgreSQL, Redis" -- Update "Integrated Platform service" to "vehicle-data feature module" -- Remove references to separate platform service - -6. UPDATE AI-INDEX.MD: -File: AI-INDEX.md - -Changes: -- Update container count to 5 -- Update service list -- Update any platform service references - -7. CREATE VEHICLE-DATA FEATURE README: -File: backend/src/features/vehicle-data/README.md - -Content: -```markdown -# Vehicle Data Feature - -Provides hierarchical vehicle data (makes, models, trims, engines) for the vehicles feature. - -## Purpose -Replaced the separate mvp-platform Python service. Now integrated as a backend feature module. - -## Architecture -- Database: vehicles schema (separate from public schema) -- Caching: Redis with 6-hour TTL -- Authentication: JWT required on all endpoints - -## API Endpoints -- GET /api/vehicle-data/years -- GET /api/vehicle-data/makes?year={year} -- GET /api/vehicle-data/models?year={year}&make_id={id} -- GET /api/vehicle-data/trims?year={year}&model_id={id} -- GET /api/vehicle-data/engines?year={year}&trim_id={id} - -## Database Tables -vehicles.make, vehicles.model, vehicles.model_year, vehicles.trim, vehicles.engine, vehicles.trim_engine - -## Caching Strategy -Redis keys: vehicle-data:makes:{year}, etc. -TTL: 6 hours -Graceful fallback if Redis unavailable - -## Notes -- VIN decoding was removed (not part of this feature) -- Users manually select vehicle details from dropdowns -``` - -8. UPDATE VEHICLES FEATURE README: -File: backend/src/features/vehicles/README.md - -Changes: -- Remove VIN decode documentation -- Remove platform integration references -- Update vehicle creation workflow: "Users manually select make/model/year from dropdowns provided by vehicle-data feature" -- Update dependencies: Add vehicle-data feature - -9. CREATE MIGRATION NOTES: -File: docs/PLATFORM-INTEGRATION-MIGRATION.md - -Content: -```markdown -# Platform Service Integration - Migration Notes - -## Date -[Insert completion date] - -## Summary -Integrated the separate mvp-platform Python service into the backend as a TypeScript feature module. - -## Changes - -### Architecture -- Before: 6 containers (Traefik, Frontend, Backend, PostgreSQL, Redis, Platform) -- After: 5 containers (Traefik, Frontend, Backend, PostgreSQL, Redis) - -### Features Removed -- VIN decoding via NHTSA API -- VIN auto-population of vehicle details -- Separate platform container - -### Features Added -- vehicle-data feature module in backend -- Manual vehicle selection workflow (dropdowns) - -### Breaking Changes -- VIN decode API endpoint removed -- Vehicle creation now requires make/model/year in request -- Frontend updated to use dropdowns instead of VIN decode - -### Technical Details -- Python FastAPI code converted to TypeScript/Fastify -- vehicles schema remains unchanged -- Redis caching maintained (6-hour TTL) -- API endpoints moved from /platform/* to /api/vehicle-data/* - -## Rationale -Simplify architecture by reducing container count and unifying on Node.js/TypeScript stack. - -## Migration Path -Single-phase cutover completed [date]. -``` - -10. UPDATE DOCS README: -File: docs/README.md - -Changes: -- Update feature list to include vehicle-data -- Update architecture summary (5 containers) - -VERIFICATION: -- All references to "6 containers" changed to "5 containers" -- No references to mvp-platform container -- No references to VIN decode API -- vehicle-data feature documented -- Migration notes complete -- All markdown files valid (no broken links) - -Return list of files updated with line numbers changed. -``` - -**Success Criteria**: -- ✅ All architecture docs updated -- ✅ API docs updated -- ✅ Feature READMEs updated -- ✅ Migration notes created -- ✅ No references to 6 containers - -**Estimated Time**: 1-2 hours - ---- - -## AGENT 7: Container Removal & Deployment - -**Role**: Final cleanup, container removal, and deployment verification - -**Subagent Type**: `general-purpose` - -**Dependencies**: All other agents complete - -**Deliverables**: -- Platform service directory archived -- Docker images cleaned -- Deployment verified -- 5 containers running - -**Prompt**: -``` -Perform final cleanup, remove platform service, and verify deployment. - -CONTEXT: -All code changes complete. Ready for final cleanup and deployment. - -TASKS: - -1. ARCHIVE PLATFORM SERVICE: -Move platform service to archive (don't delete from git history): -mkdir -p /Users/egullickson/Documents/Technology/coding/motovaultpro/archive/platform-services/ -mv /Users/egullickson/Documents/Technology/coding/motovaultpro/mvp-platform-services/vehicles/ /Users/egullickson/Documents/Technology/coding/motovaultpro/archive/platform-services/ - -Create archive README: -File: archive/platform-services/README.md -Content: -```markdown -# Archived Platform Services - -## vehicles/ -**Archived**: [date] -**Reason**: Integrated into backend as vehicle-data feature module - -This Python FastAPI service was replaced by the TypeScript vehicle-data feature in backend/src/features/vehicle-data/. - -For migration details, see: docs/PLATFORM-INTEGRATION-MIGRATION.md -``` - -2. VERIFY DOCKER COMPOSE: -Execute: -docker compose config - -Verify: -- Valid YAML (no errors) -- Exactly 5 services defined -- No references to mvp-platform - -3. STOP ALL CONTAINERS: -Execute: -docker compose down - -Verify all containers stopped: -docker ps -a - -4. CLEAN UP DOCKER IMAGES: -Remove old platform image: -docker image rm motovaultpro-mvp-platform 2>/dev/null || true - -5. REBUILD BACKEND: -Execute: -docker compose build mvp-backend - -Verify build succeeds without errors. - -6. START ALL CONTAINERS: -Execute: -docker compose up -d - -Verify 5 containers start: -docker ps - -Expected: -- mvp-traefik -- mvp-frontend -- mvp-backend -- mvp-postgres -- mvp-redis - -7. VERIFY HEALTH CHECKS: -Wait 60 seconds for startup. - -Check health: -docker compose ps - -All containers should show "healthy" or "running". - -8. VERIFY DATABASE MIGRATIONS: -Check vehicles schema exists: -docker compose exec mvp-postgres psql -U postgres -d motovaultpro -c "\dn" - -Should see "vehicles" schema. - -Check tables exist: -docker compose exec mvp-postgres psql -U postgres -d motovaultpro -c "\dt vehicles.*" - -Should see: make, model, model_year, trim, engine, trim_engine - -9. TEST VEHICLE-DATA ENDPOINTS: -Execute (requires JWT token): -curl http://localhost/api/vehicle-data/years - -Expected: [2024, 2023, ...] - -Execute: -curl http://localhost/api/vehicle-data/makes?year=2024 - -Expected: {"makes": [{id: 1, name: "Honda"}, ...]} - -10. TEST FRONTEND: -Open: http://localhost - -Navigate to vehicles page. -Verify: -- Dropdowns load (years, makes, models) -- Can create vehicle by selecting from dropdowns -- No VIN decode button visible -- Vehicle creation works - -11. MONITOR LOGS: -Execute: -docker compose logs -f mvp-backend - -Watch for: -- No errors on startup -- Vehicle-data endpoints responding -- No calls to mvp-platform (should be gone) - -12. VERIFY REDIS CACHING: -Execute: -docker compose exec mvp-redis redis-cli - -Run: -KEYS vehicle-data:* - -After making API calls, should see cached keys. - -Run: -GET vehicle-data:makes:2024 - -Should see JSON data. - -13. PERFORMANCE CHECK: -Test response times: -time curl http://localhost/api/vehicle-data/years - -Should be <500ms after cache warm-up. - -14. FINAL VERIFICATION CHECKLIST: -- [ ] 5 containers running (not 6) -- [ ] All health checks passing -- [ ] Vehicle-data API endpoints responding -- [ ] Redis caching working -- [ ] Frontend loads without errors -- [ ] Vehicle creation works -- [ ] No platform service references in logs -- [ ] No errors in docker logs - -VERIFICATION: -Return: -- Output of: docker ps (should show 5 containers) -- Output of: curl http://localhost/api/vehicle-data/years -- Confirmation that frontend works -- Any errors encountered -- Performance metrics (response times) - -If any issues found, provide rollback instructions. -``` - -**Success Criteria**: -- ✅ Platform service archived -- ✅ 5 containers running -- ✅ Health checks passing -- ✅ APIs responding -- ✅ Frontend working -- ✅ No errors in logs - -**Estimated Time**: 1-2 hours - ---- - -## Dependency Graph - -``` -Wave 1 (Parallel): -┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ -│ Agent 1 │ │ Agent 2 │ │ Agent 3 │ │ Agent 4 │ -│ Backend │ │ VIN Rem │ │ VIN Rem │ │Configuration │ -│ Feature │ │ Backend │ │ Frontend │ │ Cleanup │ -└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ - │ │ │ │ - └─────────┬───────┴─────────────────┴─────────────────┘ - │ -Wave 2 (Parallel): │ - ┌────────▼────────┐ ┌─────────────────┐ - │ Agent 5 │ │ Agent 6 │ - │ Integration │ │ Documentation │ - │ & Testing │ │ Updates │ - └────────┬────────┘ └────────┬────────┘ - │ │ -Wave 3: └──────────┬─────────┘ - │ - ┌──────────▼────────┐ - │ Agent 7 │ - │ Container │ - │ Removal & │ - │ Deployment │ - └───────────────────┘ -``` - ---- - -## Execution Instructions - -### Start Wave 1 (4 agents in parallel): -```bash -# Spawn all 4 agents simultaneously -/task agent1_prompt -/task agent2_prompt -/task agent3_prompt -/task agent4_prompt -``` - -### Wait for Wave 1 Completion -Monitor all 4 agents. When all report completion: -- Review deliverables -- Verify no conflicts -- Commit changes from Wave 1 - -### Start Wave 2 (2 agents in parallel): -```bash -# Spawn 2 agents simultaneously -/task agent5_prompt -/task agent6_prompt -``` - -### Wait for Wave 2 Completion -When both agents complete: -- Run all tests -- Review documentation -- Commit changes from Wave 2 - -### Start Wave 3 (1 agent): -```bash -# Spawn final agent -/task agent7_prompt -``` - -### Final Verification -When Agent 7 completes: -- Verify 5 containers running -- Test all functionality -- Create git tag: `v1.0-platform-integrated` - ---- - -## Rollback Plan - -If critical issues during deployment: - -1. **Restore docker-compose.yml**: - ```bash - git restore docker-compose.yml - ``` - -2. **Restore platform service**: - ```bash - mv archive/platform-services/vehicles/ mvp-platform-services/ - ``` - -3. **Rebuild containers**: - ```bash - docker compose down - docker compose up -d - ``` - -4. **Revert backend changes**: - ```bash - git revert HEAD~[n] # Revert last n commits - ``` - -5. **Rebuild backend**: - ```bash - docker compose build mvp-backend - docker compose restart mvp-backend - ``` - ---- - -## Success Metrics - -- ✅ 5 containers running (down from 6) -- ✅ All automated tests passing -- ✅ Vehicle dropdown APIs <500ms response time -- ✅ Redis cache hit rate >80% after warm-up -- ✅ Zero errors in logs after 1 hour -- ✅ Frontend vehicle creation works on mobile + desktop -- ✅ All documentation updated -- ✅ TypeScript compiles without warnings -- ✅ Linter passes - ---- - -## Estimated Timeline - -**Total**: 6-8 hours with parallel execution - -| Wave | Duration | Agents | -|------|----------|--------| -| Wave 1 | 3-4 hours | 4 parallel | -| Wave 2 | 2-3 hours | 2 parallel | -| Wave 3 | 1-2 hours | 1 sequential | - -**Sequential Execution**: 12-16 hours -**Parallel Execution**: 6-8 hours -**Time Saved**: 50% - ---- - -## Notes - -- Each agent is independent in Wave 1 (no conflicts expected) -- Wave 2 depends on Wave 1 code changes -- Wave 3 is deployment only (must be last) -- Use feature branches for each wave if needed -- Test after each wave before proceeding -- Commit after each wave for easy rollback - ---- - -## Agent Communication Protocol - -Agents should report: -1. **Start**: "Agent [N] starting [task]" -2. **Progress**: Regular updates every 30 minutes -3. **Blockers**: Immediate report if stuck -4. **Completion**: "Agent [N] complete - [deliverables]" -5. **Handoff**: Files created/modified for next wave - -Coordinator (you) should: -- Monitor all agents in parallel -- Resolve conflicts between agents -- Gate Wave 2 until Wave 1 100% complete -- Gate Wave 3 until Wave 2 100% complete -- Make final deployment decision \ No newline at end of file diff --git a/docs/PLATFORM-INTEGRATION-MIGRATION.md b/docs/PLATFORM-INTEGRATION-MIGRATION.md deleted file mode 100644 index 6bd681a..0000000 --- a/docs/PLATFORM-INTEGRATION-MIGRATION.md +++ /dev/null @@ -1,252 +0,0 @@ -# Platform Service Integration - Migration Notes - -## Date -2025-11-03 - -## Summary -Integrated the separate mvp-platform Python service into the backend as a TypeScript feature module. - -## Changes - -### Architecture -- **Before**: 6 containers (Traefik, Frontend, Backend, PostgreSQL, Redis, Platform) -- **After**: 5 containers (Traefik, Frontend, Backend, PostgreSQL, Redis) - -### Features MIGRATED (Not Removed) -- VIN decoding via vPIC API (migrated to platform feature) -- Vehicle hierarchical data lookups (makes/models/trims/engines) -- PostgreSQL VIN decode function integration -- Redis caching with 6-hour TTL (vehicle data) and 7-day TTL (VIN decode) - -### Features Removed -- Separate mvp-platform container (Python FastAPI service) -- External HTTP calls to platform service (http://mvp-platform:8000) -- Platform service API key and secrets - -### Features Added -- Platform feature module in backend (`backend/src/features/platform/`) -- Unified API endpoints under `/api/platform/*` -- Circuit breaker for vPIC API resilience (opossum library) -- Dual user workflow (VIN decode OR manual dropdown selection) -- PostgreSQL-first VIN decode strategy with vPIC fallback - -### Breaking Changes -- API endpoints moved from old locations to `/api/platform/*` -- VIN decode endpoint changed from POST to GET request -- Frontend updated to use new unified endpoints -- External platform service URL removed from environment variables - -### Technical Details -- **Python FastAPI → TypeScript/Fastify**: Complete code conversion -- **vehicles schema**: Remains unchanged, accessed by platform feature -- **Redis caching**: Maintained with same TTL strategy -- **VIN decode strategy**: PostgreSQL function → vPIC API (circuit breaker protected) -- **Authentication**: JWT required on all platform endpoints - -## Rationale -Simplify architecture by: -- Reducing container count (6 → 5) -- Unifying on Node.js/TypeScript stack -- Eliminating inter-service HTTP calls -- Improving development experience -- Reducing deployment complexity - -## Migration Path -Single-phase cutover completed 2025-11-03 with parallel agent execution: - -### Wave 1 (Parallel - 4 agents): -1. **Platform Feature Creator**: Created `backend/src/features/platform/` -2. **VIN Migration - Backend**: Migrated VIN logic from vehicles to platform -3. **VIN Migration - Frontend**: Updated to `/api/platform/*` endpoints -4. **Configuration Cleanup**: Removed platform container from docker-compose - -### Wave 2 (Parallel - 2 agents): -5. **Integration & Testing**: Verified integration and tests -6. **Documentation Updates**: Updated all documentation - -### Wave 3 (Sequential - 1 agent): -7. **Container Removal & Deployment**: Archive and final verification - -## Agents Used - -### Agent 1: Platform Feature Creator -- Created complete feature structure -- Converted Python to TypeScript -- Implemented VIN decode with circuit breaker -- Created unit and integration tests - -### Agent 2: VIN Migration - Backend -- Migrated VIN decode from vehicles feature -- Updated vehicles service to use platform -- Removed external platform client - -### Agent 3: VIN Migration - Frontend -- Updated API calls to `/api/platform/*` -- Kept VIN decode functionality -- Enhanced mobile responsiveness - -### Agent 4: Configuration Cleanup -- Removed mvp-platform from docker-compose -- Cleaned environment variables -- Updated Makefile - -## Verification - -### Integration Points -- Vehicles service calls `getVINDecodeService()` from platform feature (vehicles.service.ts:46, 229) -- Platform routes registered in app.ts (app.ts:22, 110) -- Frontend uses `/api/platform/vehicle?vin=X` for VIN decode -- Frontend uses `/api/platform/years`, `/api/platform/makes`, etc. for dropdowns - -### Testing -- Platform feature: Unit tests for VIN decode and vehicle data services -- Platform feature: Integration tests for all API endpoints -- Vehicles feature: Updated tests to mock platform service - -### Performance -- VIN decode: < 500ms with cache -- Dropdown APIs: < 100ms with cache -- Redis cache hit rate: Target >80% after warm-up - -## API Endpoint Changes - -### Old Endpoints (Deprecated) -``` -POST /api/vehicles/decode-vin -GET /api/vehicles/dropdown/years -GET /api/vehicles/dropdown/makes?year={year} -GET /api/vehicles/dropdown/models?year={year}&make_id={id} -``` - -### New Endpoints (Active) -``` -GET /api/platform/vehicle?vin={vin} -GET /api/platform/years -GET /api/platform/makes?year={year} -GET /api/platform/models?year={year}&make_id={id} -GET /api/platform/trims?year={year}&model_id={id} -GET /api/platform/engines?year={year}&trim_id={id} -``` - -## User Experience Changes - -### Before Migration -- VIN decode: Required separate platform service -- Manual selection: Dropdowns via vehicles API -- Limited mobile optimization - -### After Migration -- VIN decode: Integrated platform feature with circuit breaker resilience -- Manual selection: Unified `/api/platform/*` endpoints -- Dual workflow: Users can VIN decode OR manually select -- Enhanced mobile: 44px touch targets, 16px fonts (no iOS zoom) - -## Rollback Plan - -If critical issues discovered: - -1. Restore docker-compose.yml: -```bash -git restore docker-compose.yml -``` - -2. Restore platform service directory: -```bash -git restore mvp-platform-services/ -``` - -3. Rebuild containers: -```bash -docker compose down -docker compose up -d -``` - -4. Revert code changes: -```bash -git revert HEAD~[n] -``` - -## Success Metrics - -- Container count: 5 (down from 6) -- All automated tests: Passing -- VIN decode response time: <500ms -- Redis cache hit rate: >80% (after warm-up) -- Zero errors in logs: After 1 hour runtime -- Mobile + desktop: Both workflows functional -- TypeScript compilation: Zero errors -- Linter: Zero issues - -## Files Created - -### Backend -- `backend/src/features/platform/` (14 files total) - - API layer: routes, controller - - Domain layer: VIN decode, vehicle data, cache services - - Data layer: repository, vPIC client - - Models: requests, responses - - Tests: unit and integration - - Documentation: README.md - -### Documentation -- `docs/PLATFORM-INTEGRATION-MIGRATION.md` (this file) - -## Files Modified - -### Configuration -- `docker-compose.yml` - Removed mvp-platform service -- `.env` - Removed platform URL -- `config/app/production.yml` - Removed platform config -- `Makefile` - Updated to 5-container architecture - -### Backend -- `backend/src/app.ts` - Registered platform routes -- `backend/src/features/vehicles/domain/vehicles.service.ts` - Uses platform VIN decode -- `backend/src/features/vehicles/tests/unit/vehicles.service.test.ts` - Updated mocks - -### Frontend -- `frontend/src/features/vehicles/api/vehicles.api.ts` - Updated endpoints -- `frontend/src/features/vehicles/components/VehicleForm.tsx` - Mobile enhancements - -### Documentation -- `README.md` - Updated to 5 containers -- `CLAUDE.md` - Updated architecture description -- `docs/README.md` - Updated container count and feature list - -## Files Deleted - -### Backend -- `backend/src/features/vehicles/external/platform-vehicles/` (entire directory) -- `backend/src/features/vehicles/domain/platform-integration.service.ts` -- `backend/src/features/vehicles/external/vpic/` (moved to platform) -- `backend/src/features/vehicles/tests/unit/vpic.client.test.ts` - -## Future Considerations - -### Potential Enhancements -- Batch VIN decode endpoint -- Alternative VIN decode APIs (CarMD, Edmunds) -- Part number lookups -- Service bulletin integration -- Recall information integration -- Admin cache invalidation endpoints - -### Monitoring -- Track cache hit rates -- Monitor circuit breaker state transitions -- Log slow queries (>200ms) -- Alert on high error rates -- Dashboard for vPIC API health - -## Related Documentation - -- Platform Feature README: `backend/src/features/platform/README.md` -- Architecture Overview: `docs/PLATFORM-SERVICES.md` -- Vehicles Feature: `backend/src/features/vehicles/README.md` -- API Documentation: Platform README contains complete API reference - ---- - -**Migration Status**: COMPLETE - -The platform service has been successfully integrated into the backend as a feature module. The architecture now runs with 5 containers instead of 6, with all platform logic accessible via `/api/platform/*` endpoints. diff --git a/docs/PLATFORM-INTEGRATION-TESTING.md b/docs/PLATFORM-INTEGRATION-TESTING.md deleted file mode 100644 index ae58df9..0000000 --- a/docs/PLATFORM-INTEGRATION-TESTING.md +++ /dev/null @@ -1,335 +0,0 @@ -# Platform Integration Testing Guide - -## Prerequisites - -Docker must be running: -```bash -# Check Docker status -docker compose ps - -# If not running, start containers -make rebuild # Rebuilds with all changes -make start # Starts all services -``` - -## Testing Sequence - -### 1. TypeScript Compilation Verification - -```bash -# In backend container -docker compose exec mvp-backend npm run type-check - -# Expected: No TypeScript errors -``` - -### 2. Linter Verification - -```bash -# In backend container -docker compose exec mvp-backend npm run lint - -# Expected: Zero linting issues -``` - -### 3. Platform Feature Unit Tests - -```bash -# Run all platform unit tests -docker compose exec mvp-backend npm test -- features/platform/tests/unit - -# Expected tests: -# - vin-decode.service.test.ts (VIN validation, circuit breaker, caching) -# - vehicle-data.service.test.ts (dropdown data, caching) -``` - -### 4. Platform Feature Integration Tests - -```bash -# Run platform integration tests -docker compose exec mvp-backend npm test -- features/platform/tests/integration - -# Expected tests: -# - GET /api/platform/years -# - GET /api/platform/makes?year=2024 -# - GET /api/platform/models?year=2024&make_id=1 -# - GET /api/platform/trims?year=2024&model_id=1 -# - GET /api/platform/engines?year=2024&trim_id=1 -# - GET /api/platform/vehicle?vin=1HGCM82633A123456 -# - Authentication (401 without JWT) -# - Validation (400 for invalid params) -``` - -### 5. Vehicles Feature Integration Tests - -```bash -# Run vehicles integration tests -docker compose exec mvp-backend npm test -- features/vehicles/tests/integration - -# Expected: VIN decode now uses platform feature -``` - -### 6. End-to-End Workflow Tests - -#### VIN Decode Workflow -```bash -# 1. Start containers -make start - -# 2. Get auth token (via frontend or Auth0 test token) - -# 3. Test VIN decode endpoint -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/vehicle?vin=1HGCM82633A123456 - -# Expected: -# { -# "vin": "1HGCM82633A123456", -# "success": true, -# "result": { -# "make": "Honda", -# "model": "Accord", -# "year": 2003, -# ... -# } -# } -``` - -#### Dropdown Cascade Workflow -```bash -# 1. Get years -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/years - -# Expected: [2024, 2023, 2022, ...] - -# 2. Get makes for 2024 -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/makes?year=2024 - -# Expected: {"makes": [{"id": 1, "name": "Honda"}, ...]} - -# 3. Get models for Honda 2024 -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/models?year=2024&make_id=1 - -# Expected: {"models": [{"id": 101, "name": "Civic"}, ...]} -``` - -### 7. Frontend Testing - -#### Desktop Testing -```bash -# 1. Open browser -open https://motovaultpro.com - -# 2. Navigate to Vehicles → Add Vehicle - -# 3. Test VIN decode: -# - Enter VIN: 1HGCM82633A123456 -# - Click "Decode VIN" -# - Verify auto-population of make/model/year - -# 4. Test manual selection: -# - Select Year: 2024 -# - Select Make: Honda -# - Select Model: Civic -# - Verify cascading dropdowns work -``` - -#### Mobile Testing -```bash -# Use Chrome DevTools responsive mode - -# Test at widths: -# - 320px (iPhone SE) -# - 375px (iPhone 12) -# - 768px (iPad) -# - 1920px (Desktop) - -# Verify: -# - 44px minimum touch targets -# - No iOS zoom on input focus (16px font) -# - Dropdowns work on touch devices -# - VIN decode button accessible -# - Both workflows functional -``` - -### 8. Performance Testing - -```bash -# Monitor response times -time curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/years - -# Expected: < 500ms (first call, cache miss) -# Expected: < 100ms (second call, cache hit) -``` - -### 9. Cache Verification - -```bash -# Connect to Redis -docker compose exec mvp-redis redis-cli - -# Check cache keys -KEYS mvp:platform:* - -# Expected keys: -# - mvp:platform:years -# - mvp:platform:vehicle-data:makes:2024 -# - mvp:platform:vin-decode:1HGCM82633A123456 - -# Check TTL -TTL mvp:platform:vehicle-data:makes:2024 -# Expected: ~21600 seconds (6 hours) - -TTL mvp:platform:vin-decode:1HGCM82633A123456 -# Expected: ~604800 seconds (7 days) - -# Get cached value -GET mvp:platform:years -# Expected: JSON array of years -``` - -### 10. Error Handling Tests - -```bash -# Test invalid VIN (wrong length) -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/vehicle?vin=INVALID - -# Expected: 400 Bad Request - -# Test missing auth -curl http://localhost:3001/api/platform/years - -# Expected: 401 Unauthorized - -# Test invalid year -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/makes?year=3000 - -# Expected: 400 Bad Request or empty array -``` - -### 11. Circuit Breaker Testing - -```bash -# Monitor backend logs -make logs-backend | grep "circuit breaker" - -# Should see: -# - State transitions (open/half-open/close) -# - Timeout events -# - Fallback executions - -# Test with invalid VIN that requires vPIC API -curl -H "Authorization: Bearer YOUR_TOKEN" \ - http://localhost:3001/api/platform/vehicle?vin=UNKNOWNVIN1234567 - -# Check logs for circuit breaker activity -``` - -### 12. Container Health Check - -```bash -# Verify 5 containers running -docker compose ps - -# Expected output: -# mvp-traefik - running -# mvp-frontend - running -# mvp-backend - running -# mvp-postgres - running -# mvp-redis - running - -# No mvp-platform container should exist - -# Check backend health -curl http://localhost:3001/health - -# Expected: -# { -# "status": "healthy", -# "features": ["vehicles", "documents", "fuel-logs", "stations", "maintenance", "platform"] -# } -``` - -## Success Criteria - -- TypeScript compilation: Zero errors -- Linter: Zero issues -- Unit tests: All passing -- Integration tests: All passing -- VIN decode workflow: Functional -- Dropdown cascade workflow: Functional -- Mobile + desktop: Both responsive and functional -- Cache hit rate: >80% after warm-up -- Response times: <500ms VIN decode, <100ms dropdowns -- 5 containers: Running healthy -- Zero errors: In logs after 1 hour - -## Troubleshooting - -### TypeScript Errors -```bash -# Check compilation -docker compose exec mvp-backend npm run type-check - -# If errors, review files modified by agents -``` - -### Test Failures -```bash -# Run specific test -docker compose exec mvp-backend npm test -- path/to/test.ts - -# Check test logs for details -``` - -### VIN Decode Not Working -```bash -# Check backend logs -make logs-backend | grep -E "vin|platform" - -# Verify vPIC API accessible -curl https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVin/1HGCM82633A123456?format=json - -# Check circuit breaker state in logs -``` - -### Dropdowns Empty -```bash -# Check PostgreSQL vehicles schema -docker compose exec mvp-postgres psql -U postgres -d motovaultpro -c "\\dt vehicles.*" - -# Query makes table -docker compose exec mvp-postgres psql -U postgres -d motovaultpro -c "SELECT COUNT(*) FROM vehicles.make;" - -# Should have data -``` - -### Frontend Not Loading -```bash -# Check frontend logs -make logs-frontend - -# Rebuild frontend -docker compose build mvp-frontend -docker compose restart mvp-frontend -``` - -## Next Steps After Testing - -If all tests pass: -1. Create git tag: `v1.0-platform-integrated` -2. Document any issues in GitHub -3. Monitor production logs for 24 hours -4. Archive Python platform service directory - -If tests fail: -1. Review failure logs -2. Fix issues -3. Re-run tests -4. Consider rollback if critical failures