Migrate admin controller, routes, validation, and users controller
from auth0Sub identifiers to UUID. Admin CRUD now uses admin UUID id,
user management routes use user_profiles UUID. Clean up debug logging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated user-profile.repository.ts to use UUID instead of auth0_sub:
- Added getById(id) method for UUID-based lookups
- Changed all methods (except getByAuth0Sub, getOrCreate) to accept userId (UUID) instead of auth0Sub
- Updated SQL WHERE clauses from auth0_sub to id for UUID-based queries
- Fixed cross-table joins in listAllUsers and getUserWithAdminStatus to use user_profile_id
- Updated hardDeleteUser to use UUID for all DELETE statements
- Updated auth.plugin.ts to call updateEmail and updateEmailVerified with userId (UUID)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auth plugin now uses profile.id (UUID) as userContext.userId instead
of raw JWT sub. Admin guard queries admin_users by user_profile_id.
Auth0 Management API calls continue using auth0Sub from JWT.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Multi-phase SQL migration converting all user_id columns from
VARCHAR(255) auth0_sub to UUID referencing user_profiles.id.
Restructures admin_users with UUID PK and user_profile_id FK.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /guide SPA route conflicts with the static /guide/ screenshot directory.
Nginx's try_files $uri/ matches the directory and issues a 301 redirect to
/guide/ with trailing slash, bypassing SPA routing. Removing $uri/ ensures
all non-file paths fall through to index.html for client-side routing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create CLAUDE.md for GuidePage directory with architecture docs
- Create CLAUDE.md index for pages/ directory
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Guide link to public nav bar (desktop + mobile) in HomePage
- Add Guide link to authenticated sidebar in Layout.tsx
- Add Guide link to HamburgerDrawer with window.location guard
- Add GuidePage integration tests (6 test scenarios)
- Remove old PDF user guide at public/docs/v2026-01-03.pdf
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All 10 guide sections converted from USER-GUIDE.md to styled React
components using GuideTable and GuideScreenshot shared components.
Sections 1-5: Getting Started, Dashboard, Vehicles, Fuel Logs, Maintenance.
Sections 6-10: Gas Stations, Documents, Settings, Subscription Tiers, Mobile Experience.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create GuidePage with responsive layout (sticky TOC sidebar desktop, collapsible accordion mobile)
- Add GuideTableOfContents with scroll-based active section tracking
- Create GuideScreenshot and GuideTable shared components
- Add guideTypes.ts with section metadata for all 10 sections
- Add lazy-loaded /guide route in App.tsx with public access
- Placeholder section components for all 10 guide sections
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename "Schedule Maintenance" to "Add Maintenance", match contained
button style to "Add Fuel Log", and open inline MaintenanceRecordForm
dialog on click. Applied to both desktop and mobile views.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: React fires child effects before parent effects. App's URL
sync effect called history.replaceState() on /callback, stripping the
?code= and &state= query params before Auth0Provider's useEffect could
read them via hasAuthParams(). The SDK fell through to checkSession()
instead of handleRedirectCallback(), silently failing with no error.
Guard both URL sync effects to skip on /callback, /signup, /verify-email.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add allKeys() to IndexedDBStorage to eliminate Auth0 CacheKeyManifest
fallback, revert set()/remove() to non-blocking persist, add auth error
display on callback route, remove leaky force-auth-check interceptor,
and migrate debug console calls to centralized logger.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
loadCacheFromDB used store.getAll() which returns raw values, not
key-value pairs. The item.key check always failed, so memoryCache
was empty after every page reload. Auth0 SDK state stored before
redirect was lost on mobile Safari (no bfcache).
Also fixed set()/remove() to await IDB persistence so Auth0 state
is fully written before loginWithRedirect() navigates away.
Added 10s timeout on callback loading state as safety net.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
URL.createObjectURL on a PDF creates a blob URL that cannot render in
an img tag, showing broken image alt text. Skip preview creation for
PDF files so the review modal displays without a thumbnail.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The 5s cloud timeout was too tight for the initial WIF authentication
which requires 3 HTTP round-trips (STS, IAM credentials, resource
manager). First call took 5.5s and was discarded, falling back to slow
CPU-based PaddleOCR. Increased to 10s to accommodate cold-start auth.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pdf2image requires poppler-utils which is not installed in the OCR
container. PyMuPDF is already in requirements.txt and can render PDF
pages to PNG at 300 DPI natively without extra system dependencies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The backend SUPPORTED_IMAGE_TYPES set excluded application/pdf, returning
415 before the request ever reached the OCR microservice. Added PDF to
the allowed types in both controller and service validation layers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The receipt extractor only accepted image MIME types, rejecting PDFs at
the OCR layer. Added application/pdf to supported types and PDF-to-image
conversion (first page at 300 DPI) before OCR preprocessing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace ReceiptCameraButton with "Add Receipt" button that opens
AddReceiptDialog. Upload path feeds handleCaptureImage, camera path
calls startCapture. Tier gating preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>