Gas Station Prep
This commit is contained in:
1118
docs/GAS-STATION-AGENTS.md
Normal file
1118
docs/GAS-STATION-AGENTS.md
Normal file
File diff suppressed because it is too large
Load Diff
648
docs/GAS-STATIONS.md
Normal file
648
docs/GAS-STATIONS.md
Normal file
@@ -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 <script src="/config.js"></script> 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<Station[]>
|
||||||
|
- saveStation(placeId: string, data: SaveStationData): Promise<SavedStation>
|
||||||
|
- getSavedStations(): Promise<SavedStation[]>
|
||||||
|
- deleteSavedStation(placeId: string): Promise<void>
|
||||||
|
- 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<GeolocationPosition>
|
||||||
|
- requestLocationPermission(): Promise<boolean>
|
||||||
|
- 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: <Route path="/stations" element={<div>Stations (TODO)</div>} />
|
||||||
|
- Add: <Route path="/stations" element={<StationsPage />} />
|
||||||
|
- 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: <Route path="/m/stations" element={<StationsMobileScreen />} />
|
||||||
|
- 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
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user