- Add userEmail field to AuditLogEntry type in backend and frontend
- Update audit-log repository to LEFT JOIN with user_profiles table
- Update AdminLogsPage to show email with fallback to truncated userId
- Update AdminLogsMobileScreen with same display logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend:
- Add login event logging to getUserStatus() controller method
- Create POST /auth/track-logout endpoint for logout tracking
Frontend:
- Create useLogout hook that wraps Auth0 logout with audit tracking
- Update all logout locations to use the new hook (SettingsPage,
Layout, MobileSettingsScreen, useDeletion)
Login events are logged when the frontend calls /auth/user-status after
Auth0 callback. Logout events are logged via fire-and-forget call to
/auth/track-logout before Auth0 logout.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The audit_logs table migration was not being executed because the
audit-log feature was missing from MIGRATION_ORDER in run-all.ts,
causing 500 errors when accessing the audit logs API.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The old /api/admin/audit-logs route in admin.routes.ts conflicted with the
new centralized audit-log feature. Removed the old route since we're now
using the unified audit logging system.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add audit_logs table with categories, severities, and indexes
- Create AuditLogService and AuditLogRepository
- Add REST API endpoints for viewing and exporting logs
- Wire audit logging into auth, vehicles, admin, and backup features
- Add desktop AdminLogsPage with filters and CSV export
- Add mobile AdminLogsMobileScreen with card layout
- Implement 90-day retention cleanup job
- Remove old AuditLogPanel from AdminCatalogPage
Security fixes:
- Escape LIKE special characters to prevent pattern injection
- Limit CSV export to 5000 records to prevent memory exhaustion
- Add truncation warning headers for large exports
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace per-schedule count-based retention with unified tiered classification.
Backups are now classified by timestamp into categories (hourly/daily/weekly/monthly)
and are only deleted when they exceed ALL applicable category quotas.
Changes:
- Add backup-classification.service.ts for timestamp-based classification
- Rewrite backup-retention.service.ts with tiered logic
- Add categories and expires_at columns to backup_history
- Add Expires column to desktop and mobile backup UI
- Add unit tests for classification logic (22 tests)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GET /api/admin/stats endpoint for Total Vehicles widget
- Add GET /api/admin/users/:auth0Sub/vehicles endpoint for user vehicle list
- Update AdminUsersPage with Total Vehicles stat and expandable vehicle rows
- Add My Vehicles section to SettingsPage (desktop) and MobileSettingsScreen
- Update AdminUsersMobileScreen with stats header and vehicle expansion
- Add defense-in-depth admin checks and error handling
- Update admin README documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add terms_agreements table for legal audit trail
- Create terms-agreement feature capsule with repository
- Modify signup to create terms agreement atomically
- Add checkbox with PDF link to SignupForm
- Capture IP, User-Agent, terms version, content hash
- Update CLAUDE.md documentation index
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new "Vehicles" column to the admin user management table showing
the count of active vehicles for each user.
Backend changes:
- Add vehicleCount to UserWithAdminStatus type
- Add SQL subquery to count active vehicles (is_active=true, not deleted)
- Add vehicleCount as sortable column option
Frontend changes:
- Add Vehicles column to desktop table (between Tier and Status)
- Add VehicleCountBadge component to mobile user cards
- Update ManagedUser type with vehicleCount field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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 <noreply@anthropic.com>