Use docker exec curl instead of node http.get from host.
Port 3001 is not exposed to host, so health checks must run inside the container.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Change CF_DNS_API_TOKEN_FILE to CLOUDFLARE_DNS_API_TOKEN_FILE (correct env var for Traefik/lego)
- Fix inject-secrets.sh to clean up Docker-created directories before injecting secrets
- Add detection for GitLab variables set as Variable type instead of File type
- Improve error messages to help diagnose configuration issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Move config.js script to head section so it loads synchronously before
any module scripts execute. This fixes a race condition on mobile where
the app could initialize before window.CONFIG was set.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Config files were previously gitignored, causing CI/CD pipeline to fail
because Docker would create directories instead of mounting the expected files.
- Remove config/** from .gitignore
- Track all config files (secrets still ignored)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <[email protected]>
Completed HIGH severity security fix (CVSS 6.5) to prevent Google Maps
API key exposure to frontend clients.
Issue: API key was embedded in photo URLs sent to frontend, allowing
potential abuse and quota exhaustion.
Solution: Implemented backend proxy endpoint for photos.
Backend Changes:
- google-maps.client.ts: Changed photoUrl to photoReference, added fetchPhoto()
- stations.types.ts: Updated type definition (photoUrl → photoReference)
- stations.controller.ts: Added getStationPhoto() proxy method
- stations.routes.ts: Added GET /api/stations/photo/:reference route
- stations.service.ts: Updated to use photoReference
- stations.repository.ts: Updated database queries and mappings
- admin controllers/services: Updated for consistency
- Created migration 003 to rename photo_url column
Frontend Changes:
- stations.types.ts: Updated type definition (photoUrl → photoReference)
- photo-utils.ts: NEW - Helper to generate proxy URLs
- StationCard.tsx: Use photoReference with helper function
Tests & Docs:
- Updated mock data to use photoReference
- Updated test expectations for proxy URLs
- Updated API.md and TESTING.md documentation
Database Migration:
- 003_rename_photo_url_to_photo_reference.sql: Renames column in station_cache
Security Benefits:
- API key never sent to frontend
- All photo requests proxied through authenticated endpoint
- Photos cached for 24 hours (Cache-Control header)
- No client-side API key exposure
Files modified: 16 files
New files: 2 (photo-utils.ts, migration 003)
Status: All 3 P0 security fixes now complete
- Fix 1: crypto.randomBytes() ✓
- Fix 2: Magic byte validation ✓
- Fix 3: API key proxy ✓
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Generated formal audit report identifying security, code quality,
architecture, data integrity, performance, and compliance issues.
Key findings:
- CRITICAL: Insecure random number generation in document storage
- HIGH: Inadequate file upload validation (no magic bytes)
- HIGH: Google Maps API key exposure to frontend
Overall verdict: CONDITIONALLY READY for production pending
remediation of 3 critical/high security issues.
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Google Maps and React both manipulate the DOM, causing race conditions where
Google Maps removes nodes that React still has references to. This manifests
as a NotFoundError during removeChild operations, which is harmless and doesn't
affect functionality.
Add a global error event listener in StationMap that suppresses these specific
errors. Also revert to using script.async=true with callback parameter for
proper asynchronous Google Maps loading.
The map continues to work normally despite the suppressed errors.
🤖 Generated with Claude Code
Co-Authored-By: Claude <[email protected]>
The Google Maps API and React both manipulate the DOM, which can cause
conflicts where Google Maps removes nodes that React still has references
to. Add graceful error handling:
1. Remove async flag from Google Maps script - use defer only
2. Add try-catch in marker update useEffect to ignore removeChild errors
3. Add cleanup function to properly tear down markers on unmount
4. Log warnings instead of crashing when DOM conflicts occur
This allows the app to continue functioning even when there are minor
DOM reconciliation issues between Google Maps and React.
🤖 Generated with Claude Code
Co-Authored-By: Claude <[email protected]>