Pre-web changes

This commit is contained in:
Eric Gullickson
2025-11-05 11:04:48 -06:00
parent 45fea0f307
commit 0c3ed01f4b
25 changed files with 257 additions and 3538 deletions

View File

@@ -137,7 +137,7 @@ MotoVaultPro is a single-tenant vehicle management application built with a **6-
- **Port**: 3000 (internal)
- **Networks**: frontend
- **Dependencies**: Backend (API calls)
- **Health Check**: `curl http://localhost:3000` (30s interval)
- **Health Check**: `curl https://motovaultpro.com` (30s interval)
- **Environment Variables**:
- `VITE_AUTH0_DOMAIN` - Auth0 tenant
- `VITE_AUTH0_CLIENT_ID` - Auth0 application ID
@@ -151,7 +151,7 @@ MotoVaultPro is a single-tenant vehicle management application built with a **6-
- **Port**: 3001 (internal)
- **Networks**: backend, database
- **Dependencies**: PostgreSQL, Redis, Platform
- **Health Check**: `http://localhost:3001/health` (30s interval)
- **Health Check**: `https://motovaultpro.com/api/health` (30s interval)
- **Configuration**:
- `/app/config/production.yml` - Main config
- `/app/config/shared.yml` - Shared config
@@ -402,7 +402,7 @@ docker logs mvp-postgres -f
curl https://motovaultpro.com/api/health # Backend (includes platform module)
# Or from within backend container
docker compose exec mvp-backend curl http://localhost:3001/health
docker compose exec mvp-backend curl https://motovaultpro.com/api/health
```
### Database Access

File diff suppressed because it is too large Load Diff

View File

@@ -1,295 +0,0 @@
# Gas Stations Feature - Testing Implementation Report
## Overview
Comprehensive test suite implemented for Phase 8 of the Gas Stations feature. All critical paths covered with unit, integration, and end-to-end tests.
## Test Files Created
### Backend Tests
#### Unit Tests (3 files)
1. **`backend/src/features/stations/tests/unit/stations.service.test.ts`**
- Test Coverage: StationsService business logic
- Tests:
- searchNearbyStations (happy path, sorting, metadata, default radius)
- saveStation (success, not found, with metadata)
- getUserSavedStations (returns all, empty array)
- removeSavedStation (success, error handling, user isolation)
- Total: 10 test cases
2. **`backend/src/features/stations/tests/unit/google-maps.client.test.ts`**
- Test Coverage: Google Maps API client
- Tests:
- searchNearbyStations (success, API errors, zero results, network errors)
- Distance calculation accuracy
- Result formatting
- Custom radius parameter
- Caching behavior (multiple calls, different coordinates)
- Total: 10 test cases
3. **`backend/src/features/stations/tests/fixtures/mock-stations.ts`** (existing, updated)
- Mock data for all tests
- Properly typed Station and SavedStation objects
- Test coordinates for major cities
#### Integration Tests (1 file)
4. **`backend/src/features/stations/tests/integration/stations.api.test.ts`**
- Test Coverage: Complete API endpoint testing
- Tests:
- POST /api/stations/search (valid search, missing coordinates, auth required, coordinate validation)
- POST /api/stations/save (save success, invalid placeId, station not in cache, user isolation)
- GET /api/stations/saved (returns user stations, empty array, includes metadata)
- DELETE /api/stations/saved/:placeId (delete success, 404 not found, ownership verification)
- Error handling (Google Maps API errors, schema validation, authentication)
- Total: 15 test cases
### Frontend Tests
#### Component Tests (1 file)
5. **`frontend/src/features/stations/__tests__/components/StationCard.test.tsx`**
- Test Coverage: StationCard component
- Tests:
- Rendering (name, address, photo, rating, distance)
- Save/delete actions
- Directions link (Google Maps integration)
- Touch targets (44px minimum)
- Card selection
- Total: 10 test cases
#### Hook Tests (1 file)
6. **`frontend/src/features/stations/__tests__/hooks/useStationsSearch.test.ts`**
- Test Coverage: useStationsSearch React Query hook
- Tests:
- Search execution (basic, custom radius)
- Loading states (pending, clearing after success)
- Error handling (API errors, onError callback)
- Success callback
- Total: 6 test cases
#### API Client Tests (1 file)
7. **`frontend/src/features/stations/__tests__/api/stations.api.test.ts`**
- Test Coverage: Stations API client
- Tests:
- searchStations (valid request, without radius, error handling, 401/500 errors)
- saveStation (with metadata, without optional fields, error handling)
- getSavedStations (fetch all, empty array, error handling)
- deleteSavedStation (delete success, 404 handling, error handling)
- URL construction validation
- Request payload validation
- Response parsing
- Total: 18 test cases
#### E2E Tests (1 file - Template)
8. **`frontend/cypress/e2e/stations.cy.ts`**
- Test Coverage: Complete user workflows
- Tests:
- Search for nearby stations (current location, manual coordinates, error handling, loading states)
- View stations on map (markers, info windows, auto-fit)
- Save station to favorites (save action, nickname/notes, prevent duplicates)
- View saved stations list (display all, empty state, custom nicknames)
- Delete saved station (delete action, optimistic removal, error handling)
- Mobile navigation flow (tab switching, touch targets)
- Error recovery (network errors, authentication errors)
- Integration with fuel logs
- Total: 20+ test scenarios
## Test Statistics
### Backend Tests
- **Total Test Files**: 4 (3 unit + 1 integration)
- **Total Test Cases**: ~35
- **Coverage Target**: >80%
- **Framework**: Jest with ts-jest
- **Mocking**: jest.mock() for external dependencies
### Frontend Tests
- **Total Test Files**: 3 (1 component + 1 hook + 1 API)
- **Total Test Cases**: ~34
- **E2E Template**: 1 file with 20+ scenarios
- **Framework**: React Testing Library, Jest
- **E2E Framework**: Cypress
### Combined
- **Total Test Files**: 8
- **Total Test Cases**: ~69 (excluding E2E)
- **E2E Scenarios**: 20+
- **Total Lines of Test Code**: ~2,500+
## Test Standards Applied
### Code Quality
- Zero TypeScript errors
- Zero lint warnings
- Proper type safety with strict null checks
- Clear test descriptions
- Proper setup/teardown
### Testing Best Practices
- Arrange-Act-Assert pattern
- Mocking external dependencies (Google Maps API, database)
- Test isolation (beforeEach cleanup)
- Meaningful test names
- Edge case coverage
### Coverage Areas
1. **Happy Paths**: All successful user flows
2. **Error Handling**: API failures, network errors, validation errors
3. **Edge Cases**: Empty results, missing data, null values
4. **User Isolation**: Data segregation by user_id
5. **Authentication**: JWT requirements
6. **Performance**: Response times, caching behavior
7. **Mobile**: Touch targets, responsive design
## Key Fixes Applied
### TypeScript Strict Mode Compliance
1. Fixed array access with optional chaining (`array[0]?.prop`)
2. Fixed SavedStation type (uses `stationId` not `placeId`)
3. Fixed Station optional properties (only set if defined)
4. Fixed import paths (`buildApp` from `app.ts`)
5. Removed unused imports
### Test Implementation Corrections
1. Aligned test mocks with actual repository methods
2. Corrected method names (`getUserSavedStations` vs `getSavedStations`)
3. Fixed return type expectations
4. Added proper error assertions
## Running Tests
### Backend Tests
```bash
cd backend
# Run all stations tests
npm test -- stations
# Run with coverage
npm test -- stations --coverage
# Run specific test file
npm test -- stations.service.test.ts
```
### Frontend Tests
```bash
cd frontend
# Run all stations tests
npm test -- stations
# Run with coverage
npm test -- stations --coverage
# Run E2E tests
npm run e2e
# or
npx cypress run --spec "cypress/e2e/stations.cy.ts"
```
### Docker Container Tests
```bash
# Backend tests in container
make shell-backend
npm test -- stations
# Run from host
docker compose exec mvp-backend npm test -- stations
```
## Test Results (Expected)
### Unit Tests
- All 10 service tests: PASS
- All 10 Google Maps client tests: PASS
- Mock data: Valid and type-safe
### Integration Tests
- All 15 API endpoint tests: PASS (requires database)
- User isolation verified
- Error handling confirmed
### Frontend Tests
- Component tests: PASS
- Hook tests: PASS
- API client tests: PASS
### E2E Tests
- Template created for manual execution
- Requires Google Maps API key
- Requires Auth0 test user
## Coverage Report
Expected coverage after full test run:
```
Feature: stations
-------------------------------|---------|----------|---------|---------|
File | % Stmts | % Branch | % Funcs | % Lines |
-------------------------------|---------|----------|---------|---------|
stations.service.ts | 85.7 | 80.0 | 100.0 | 85.7 |
stations.repository.ts | 75.0 | 66.7 | 90.0 | 75.0 |
google-maps.client.ts | 90.0 | 85.7 | 100.0 | 90.0 |
stations.controller.ts | 80.0 | 75.0 | 100.0 | 80.0 |
-------------------------------|---------|----------|---------|---------|
All files | 82.5 | 77.2 | 97.5 | 82.5 |
-------------------------------|---------|----------|---------|---------|
```
## Next Steps
### Phase 9: Documentation
- API documentation with examples
- Setup instructions
- Troubleshooting guide
### Phase 10: Validation & Polish
- Run all tests in Docker
- Fix any remaining linting issues
- Manual testing (desktop + mobile)
- Performance validation
### Phase 11: Deployment
- Verify secrets configuration
- Run migrations
- Final smoke tests
- Production checklist
## Notes
### Test Dependencies
- Backend: Jest, Supertest, ts-jest, @types/jest
- Frontend: @testing-library/react, @testing-library/jest-dom, @testing-library/user-event
- E2E: Cypress (installed separately)
### Known Limitations
1. Integration tests require database connection
2. Google Maps API tests use mocks (not real API)
3. E2E tests require manual execution (not in CI yet)
4. Some tests may need Auth0 test credentials
### Future Improvements
1. Add CI/CD pipeline integration
2. Add snapshot testing for components
3. Add performance benchmarks
4. Add accessibility testing
5. Add visual regression testing
## Conclusion
Comprehensive testing suite implemented covering:
- 100% of backend service methods
- 100% of API endpoints
- All critical frontend components
- All React Query hooks
- All API client methods
- Complete E2E user workflows
All tests follow MotoVaultPro testing standards and are ready for integration into the continuous integration pipeline.
---
**Testing Complete**: Phase 8 ✅
**Report Generated**: 2025-11-04
**Author**: Feature Capsule Agent

View File

@@ -1,648 +0,0 @@
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

View File

@@ -1,260 +1 @@
*** CRITICAL ***: Never read this file. Stop and move on.
*** STARTING PROMPT ***
## Agent Team (Specialized Development)
MotoVaultPro uses a 4-agent team for optimal development velocity and quality enforcement.
### When to Use Agents
**Feature Capsule Agent** - Backend feature development
- Implementing new features in `backend/src/features/{feature}/`
- Creating API endpoints, business logic, database access
- Platform service integration
- Backend tests and migrations
**Platform Feature Agent** - Integrated platform module
- Enhancing `backend/src/features/platform/`
- Vehicle lookup + VIN decoding logic
- Redis/SQL performance tuning for platform endpoints
- Platform module tests and documentation
**Mobile-First Frontend Agent** - Responsive UI/UX
- React components in `frontend/src/features/{feature}/`
- Mobile + desktop responsive design (NON-NEGOTIABLE)
- Forms, validation, and React Query integration
- Frontend tests and accessibility
**Quality Enforcer Agent** - Quality assurance
- Running complete test suites
- Validating linting and type checking
- Enforcing "all green" policy (ZERO TOLERANCE)
- Mobile + desktop validation
### Agent Spawning Examples
```
# Backend feature development
Task: "Implement {feature} backend following feature capsule pattern.
Read backend/src/features/{feature}/README.md and implement API, domain, data layers with tests."
Agent: Feature Capsule Agent
# Frontend development
Task: "Build responsive UI for {feature}. Read backend API docs and implement mobile-first.
Test on 320px and 1920px viewports."
Agent: Mobile-First Frontend Agent
# Platform module work
Task: "Enhance platform feature capsule (backend/src/features/platform).
Implement API/domain/data changes with accompanying tests."
Agent: Platform Feature Agent
# Quality validation
Task: "Validate {feature} quality gates. Run all tests, check linting, verify mobile + desktop.
Report pass/fail with details."
Agent: Quality Enforcer Agent
```
### Agent Coordination Workflow
1. Feature Capsule Agent → Implements backend
2. Mobile-First Frontend Agent → Implements UI (parallel)
3. Quality Enforcer Agent → Validates everything
4. Expert Software Architect → Reviews and approves
### When Coordinator Handles Directly
- Quick bug fixes (single file)
- Documentation updates
- Configuration changes
- Simple code reviews
- Answering questions
## Key Commands
- Start: `make start`
- Rebuild: `make rebuild`
- Logs: `make logs`
- Test: `make test`
- Migrate: `make migrate`
- Shell (backend): `make shell-backend`
- Shell (frontend): `make shell-frontend`
## Development Rules
1. NEVER use emojis in code or documentation
2. Every feature MUST be responsive (mobile + desktop) - NON-NEGOTIABLE
3. Testing and debugging can be done locally
4. All testing and debugging needs to be verified in containers
5. Each backend feature is self-contained in `backend/src/features/{name}/`
6. Delete old code when replacing (no commented code)
7. Use meaningful variable names (`userID` not `id`)
8. ALL quality gates must pass (all green policy)
9. Feature capsules are self-contained modules
## Making Changes
### Frontend Changes (React)
**Agent**: Mobile-First Frontend Agent
- Components: `frontend/src/features/{feature}/components/`
- Types: `frontend/src/features/{feature}/types/`
- After changes: `make rebuild` then test at https://admin.motovaultpro.com
- MUST test on mobile (320px) AND desktop (1920px)
### Backend Changes (Node.js)
**Agent**: Feature Capsule Agent
- API: `backend/src/features/{feature}/api/`
- Business logic: `backend/src/features/{feature}/domain/`
- Database: `backend/src/features/{feature}/data/`
- After changes: `make rebuild` then check logs
### Platform Module Changes (TypeScript)
**Agent**: Platform Feature Agent
- Feature capsule: `backend/src/features/platform/`
- API routes: `backend/src/features/platform/api/`
- Domain/data: `backend/src/features/platform/domain/` and `data/`
- After changes: `make rebuild` then verify platform endpoints via backend logs/tests
### Database Changes
- Add migration: `backend/src/features/{feature}/migrations/00X_description.sql`
- Run: `make migrate`
- Validate: Check logs and test affected features
### Adding NPM Packages
- Edit `package.json` (frontend or backend)
- Run `make rebuild` (no local npm install)
- Containers handle dependency installation
## Common Tasks
### Add a New Feature (Full Stack)
1. Spawn Feature Capsule Agent for backend
2. Spawn Mobile-First Frontend Agent for UI (parallel)
3. Feature Capsule Agent: API + domain + data + tests
4. Mobile-First Agent: Components + forms + tests
5. Spawn Quality Enforcer Agent for validation
6. Review and approve
### Add a Form Field
1. Update types in frontend/backend
2. Add to database migration if needed
3. Update React form component (Mobile-First Agent)
4. Update backend validation (Feature Capsule Agent)
5. Test with `make rebuild`
6. Validate with Quality Enforcer Agent
### Add New API Endpoint
**Agent**: Feature Capsule Agent
1. Create route in `backend/src/features/{feature}/api/`
2. Add service method in `domain/`
3. Add repository method in `data/`
4. Write unit and integration tests
5. Test with `make rebuild`
### Fix UI Responsiveness
**Agent**: Mobile-First Frontend Agent
1. Use Tailwind classes: `sm:`, `md:`, `lg:`
2. Test on mobile viewport (320px, 375px, 768px)
3. Test on desktop viewport (1024px, 1920px)
4. Ensure touch targets are 44px minimum
5. Validate keyboard navigation on desktop
### Add Platform Integration
**Agents**: Platform Feature Agent + Feature Capsule Agent
1. Platform Feature Agent: Implement/update platform endpoint logic
2. Feature Capsule Agent: Update consuming feature client (e.g. `external/platform-vehicles/`)
3. Feature Capsule Agent: Adjust caching/circuit breaker strategies as needed
4. Joint testing: run targeted unit/integration suites
5. Quality Enforcer Agent: Validate end-to-end
### Run Quality Checks
**Agent**: Quality Enforcer Agent
1. Run all tests: `make test`
2. Check linting: `npm run lint` (backend container)
3. Check types: `npm run type-check` (backend container)
4. Validate mobile + desktop
5. Report pass/fail with details
## Quality Gates (MANDATORY)
Code is complete when:
- All linters pass with zero issues
- All tests pass (100% green)
- Feature works end-to-end
- Mobile + desktop validated (for frontend)
- Old code is deleted
- Documentation updated
- Test coverage >= 80% for new code
## Architecture Quick Reference
### Application Stack
- **Backend Feature Capsules**: Modular monolith in `backend/src/features/`
- **Platform Module**: Vehicle data + VIN decoding in `backend/src/features/platform/`
- **Frontend**: React SPA in `frontend/src/`
### Feature Capsule Pattern
Each feature is self-contained:
```
backend/src/features/{feature}/
├── README.md # Complete feature documentation
├── api/ # HTTP layer
├── domain/ # Business logic
├── data/ # Database access
├── migrations/ # Schema changes
├── external/ # Platform service clients
└── tests/ # Unit + integration tests
```
## Important Context
- **Auth**: Frontend uses Auth0, backend validates JWTs
- **Database**: PostgreSQL with user-isolated data (user_id scoping)
- **Platform APIs**: Exposed via `/api/platform/*`, secured with Auth0 JWTs
- **Caching**: Redis with feature-specific TTL strategies
- **Testing**: Jest (backend + frontend)
- **Docker-First**: All development in containers (production-only)
## Agent Coordination Rules
### Clear Ownership
- Feature Capsule Agent: Backend application features
- Platform Feature Agent: Platform capsule inside backend
- Mobile-First Frontend Agent: All UI/UX code
- Quality Enforcer Agent: Testing and validation only
### Handoff Protocol
1. Development agent completes work
2. Development agent hands off to Quality Enforcer
3. Quality Enforcer validates all quality gates
4. Quality Enforcer reports pass/fail
5. If fail: Development agent fixes issues
6. If pass: Expert Software Architect approves
### Parallel Development
- Feature Capsule + Mobile-First work simultaneously
- Both agents have clear boundaries
- Both hand off to Quality Enforcer when ready
- Quality Enforcer validates complete feature
## Current Task
[Describe your specific task here - e.g., "Add notes field to vehicle form", "Create maintenance reminders feature", "Integrate new platform service"]
**Recommended Agent**: [Which agent should handle this task]
**Steps**:
1. [Step 1]
2. [Step 2]
3. [Step 3]
## References
- Agent Definitions: `.claude/agents/`
- Architecture: `docs/PLATFORM-SERVICES.md`
- Testing: `docs/TESTING.md`
- Context Loading: `.ai/context.json`
- Development Guidelines: `CLAUDE.md`
- Feature Documentation: `backend/src/features/{feature}/README.md`
*** CRITICAL ***: Never read this file. Stop and move on.

View File

@@ -136,7 +136,7 @@ npm test -- vehicles.service.test.ts
npm test -- --testNamePattern="VIN validation"
# Frontend tests (Jest)
make test-frontend
docker compose exec mvp-frontend npm test
```
### Coverage Reports
@@ -271,7 +271,7 @@ docker compose exec mvp-frontend npm test
### Feature Development Workflow
1. **Write tests first**: TDD approach preferred
2. **Run tests continuously**: Use `npm run test:watch`
3. **Test in containers**: Always verify with `make test`
3. **Test in containers**: Always verify with `docker compose exec mvp-backend npm test`
4. **Check coverage**: Ensure new code is covered
5. **Integration last**: Run full test suite before PR

View File

@@ -19,27 +19,30 @@ This document explains the endtoend Vehicles API architecture after the pl
Idempotent constraints/indexes added where applicable (e.g., unique lower(name), unique(model_id, year), guarded `CREATE INDEX IF NOT EXISTS`, guarded trigger).
### API Endpoints (Bearer auth required)
Prefix: `/api/platform`
- `GET /api/platform/years``[number]` distinct years (desc)
- `GET /api/platform/makes?year={year}``{ makes: { id, name }[] }`
- `GET /api/platform/models?year={year}&make_id={make_id}``{ models: { id, name }[] }`
- `GET /api/platform/trims?year={year}&make_id={make_id}&model_id={model_id}``{ trims: { id, name }[] }`
- `GET /api/platform/engines?year={year}&make_id={make_id}&model_id={model_id}&trim_id={trim_id}``{ engines: { id, name }[] }`
### Dropdown API (Bearer auth required)
Prefix: `/api/vehicles/dropdown`
- `GET /years``[number]` (latest to oldest model years)
- `GET /makes?year={year}``{ id, name }[]` (makes available in that year)
- `GET /models?year={year}&make_id={make}``{ id, name }[]` (models filtered by year + make)
- `GET /trims?year={year}&make_id={make}&model_id={model}``{ id, name }[]` (trims for the selection)
- `GET /engines?year={year}&make_id={make}&model_id={model}&trim_id={trim}``{ id, name }[]` (engines for the trim)
- `GET /transmissions?year={year}&make_id={make}&model_id={model}``{ id, name }[]` (`Automatic`, `Manual`)
Notes:
- `make_id` is maintained for a consistent query chain, but engines are enforced by `(year, model_id, trim_id)`.
- Trims/engines include `id` to enable the next hop in the UI.
Selection order is enforced: each endpoint requires the IDs returned by the previous stage, so users never see invalid combinations (e.g., 2023 Chevrolet excludes the S-10, 1999 GMC trims exclude AT4X, etc.).
### Platform module (internal bridge)
Prefix: `/api/platform`
- Same hierarchical endpoints as above, but responses are wrapped (`{ makes: [...] }`, `{ models: [...] }`) for service-to-service integrations.
- VIN decode endpoint: `GET /api/platform/vehicle?vin={vin}`
### Authentication
- Auth0 JWT via `Authorization: Bearer ${JWT_TOKEN}` (required for all platform endpoints)
- Auth0 JWT via `Authorization: Bearer ${JWT_TOKEN}` (required for both `/api/vehicles/*` and `/api/platform/*`)
- Configured in backend: `src/core/plugins/auth.plugin.ts` with JWKS validation
### Caching (Redis)
- Keys: `dropdown:years`, `dropdown:makes:{year}`, `dropdown:models:{year}:{make}`, `dropdown:trims:{year}:{model}`, `dropdown:engines:{year}:{model}:{trim}`
- Dropdown data TTL: 6 hours (21600 seconds)
- VIN decode cache TTL: 7 days (604800 seconds)
- Cache key format for VIN decodes: `vin:decode:{vin}`
- Keys: `platform:years`, `platform:vehicle-data:makes:{year}`, `platform:vehicle-data:models:{year}:{make}`, `platform:vehicle-data:trims:{year}:{model}`, `platform:vehicle-data:engines:{year}:{model}:{trim}`
- Dropdown TTL: 6 hours (`21600s`)
- VIN decode TTL: 7 days (`604800s`) via `platform:vin-decode:{vin}`
- Implementation: `backend/src/features/platform/domain/platform-cache.service.ts`
### Seeds & Specific Examples
@@ -56,22 +59,12 @@ Clear platform cache:
## MotoVaultPro Backend (Application Service)
### Proxy Dropdown Endpoints
Prefix: `/api/vehicles/dropdown`
- `GET /years``[number]` (calls platform `/years`)
- `GET /makes?year=YYYY``{ id, name }[]`
- `GET /models?year=YYYY&make_id=ID``{ id, name }[]`
- `GET /trims?year=YYYY&make_id=ID&model_id=ID``{ id, name }[]`
- `GET /engines?year=YYYY&make_id=ID&model_id=ID&trim_id=ID``{ id, name }[]`
Vehicles service simply re-emits the data returned by `Platform VehicleDataService`, normalizing it to `{ id, name }[]` arrays for frontend consumption. Redis caching and Postgres lookups all remain centralized in the platform module.
Changes:
- Engines route now requires `trim_id`.
- New `/years` route for UI bootstrap.
### Platform Client & Integration
- `PlatformVehiclesClient`:
- Added `getYears()`
- `getEngines(year, makeId, modelId, trimId)` to pass trim id
- `PlatformIntegrationService` consumed by `VehiclesService` updated accordingly.
### Platform Integration
- `VehiclesService` lazily instantiates `VehicleDataService` via `getVehicleDataService()`, guaranteeing a shared cache.
- Each dropdown call passes the shared Postgres pool (`getPool()`) and propagates selection context (year/make/model/trim).
- Transmission dropdown is intentionally static (`Automatic`, `Manual`) until richer metadata is available.
### Authentication (App)
- Auth0 JWT enforced via Fastify + JWKS. No mock users.
@@ -94,6 +87,7 @@ Changes:
- APIs used:
- `/api/vehicles/dropdown/years`
- `/api/vehicles/dropdown/makes|models|trims|engines`
- `/api/vehicles/dropdown/transmissions`
## Add Vehicle Form Change/Add/Modify/Delete Fields (Fast Track)
@@ -135,7 +129,7 @@ VIN/License rule
- Backend (includes platform module): `docker compose up -d --build backend`
### Logs & Health
- Backend: `/health` shows status/feature list, including platform readiness
- Backend: `https://motovaultpro.com/api/health` shows status/feature list, including platform readiness
- Logs: `make logs-backend`, `make logs-frontend`
### Common Reset Sequences