feat: navigation and UX improvements complete

This commit is contained in:
Eric Gullickson
2025-12-26 09:25:42 -06:00
parent 50baec390f
commit 8c13dc0a55
23 changed files with 327 additions and 126 deletions

View File

@@ -22,18 +22,15 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en
- Make no assumptions.
- Ask clarifying questions.
- Ultrathink
- You will be extending the "Documents" feature to include manuals.
- You will be auditing the Dark vs Light theme implementation
*** CONTEXT ***
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- You need to extend the Documents feature to include a third "Document Type"
- Right now the document has two types. Insurance and Registration
- The third type will be called "Manual"
- This document will just have the uploaded file and a notes field and Title field
- When implementing this we need to play for the future feature of scanning the document for maintenance schedules
- Add a toggle for this scanning. Label it "Scan for Maintenance Schedule"
- Do not implement this feature at this time but put the toggle in the interface and the backend changes to facility this workflow.
- You need to audit the Dark vs Light theme.
- The colors were not all changed so some of the dark theme
- The dark versus light theme does not save between logins.
- Think hard about the color choices and if any better colors are available form the MVP-COLOR-SCHEME.md
*** CHANGES TO IMPLEMENT ***
- Research this code base and ask iterative questions to compile a complete plan.
@@ -58,30 +55,7 @@ You are a senior software engineer specializsing in NodeJS, Typescript, front en
- Debug what could be causing this issue. No changes were made to the Gitlab server besides adding the RESEND variable so there shouldn't be anything on the server causing this issue.
$ chmod +x scripts/inject-secrets.sh
$ ./scripts/inject-secrets.sh
Injecting secrets...
Deploy path: /opt/gitlab-runner/builds/motovaultpro
Secrets dir: /opt/gitlab-runner/builds/motovaultpro/secrets/app
Cleaning up any corrupted secret paths...
ERROR: Variable POSTGRES_PASSWORD is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable AUTH0_CLIENT_SECRET is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable AUTH0_MANAGEMENT_CLIENT_ID is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable AUTH0_MANAGEMENT_CLIENT_SECRET is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable GOOGLE_MAPS_API_KEY is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable GOOGLE_MAPS_MAP_ID is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable CF_DNS_API_TOKEN is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: Variable RESEND_API_KEY is not set
Ensure it exists in GitLab CI/CD Variables
ERROR: One or more secrets failed to inject
Ensure all required CI/CD variables are configured as File type in GitLab
Running after_script
00:00
Running after script...
@@ -89,6 +63,35 @@ Running after script...
*** ROLE ***
- You are a senior DBA with expert knowledge in Postgres SQL.
*** ACTION ***
- Make no assumptions.
- Ask clarifying questions.
- Ultrathink
- You will be implementing an ETL process that takes a export of the NHTSA vPIC database in Postgres and transforming it for use in this application.
*** CONTEXT ***
- This is a modern web app for managing a vehicle fleet. It has both a desktop and mobile versions of the site that both need to maintain feature parity. It's currently deployed via docker compose but in the future will be deployed via k8s.
- Read README.md CLAUDE.md and AI-INDEX.md and follow relevant instructions to understand this code repository in the context of this change.
- There is an existing database import process in this directory. This process works and should not be changed.
- The source database from the NHTSA vPIC dataset is located in the @vpic-source directory
- Deep research needs to be conducted on how to execute this ETL process.
- The source database is designed for VIN decoding only.
- Example VIN: 2025 Honda Civic Hybrid - 2HGFE4F88SH315466
- Example VIN: 2023 GMC Sierra 1500 AT4x - 3GTUUFEL6PG140748
- Example VIN: 2017 Chevrolet Corvette Z06 - 1G1YU3D64H5602799
*** CHANGES TO IMPLEMENT ***
- Research this code base and ask iterative questions to compile a complete plan.
- generate a project plan
- break into bite-sized tasks and milestones
*** ROLE ***
- You are a senior DBA with expert knowledge in Postgres SQL.

View File

@@ -0,0 +1,448 @@
from pathlib import Path
md = """# MotoVaultPro Homepage Dark Theme Update (Logo-Compatible)
## Goal
Update the **public marketing homepage** to a **dark theme** so the **new logo (with a black background)** feels native and intentional.
## Constraints (DO NOT VIOLATE)
- **Do not modify the logo image files** (no transparency edits, no recolors).
- The logo background **must remain dark/black**.
- Keep the existing page structure (nav → hero → welcome → about → features grid → CTA strip → footer).
- Only adjust styling/theme + minor hero layout to place the logo cleanly.
## Source of Truth (what this doc is based on)
The current homepage markup is Tailwind-based and includes these notable class patterns:
- Root container: `min-h-screen bg-white`
- Nav: `bg-white shadow-md sticky top-0`
- Section backgrounds: `bg-white`, `bg-gray-100`, `bg-gray-50`
- Feature cards: `bg-white p-6` + `text-gray-900` + `text-gray-600`
- Footer: `bg-gray-900`
- Primary color already matches **Rosso Mugello** (primary-500 = `#7A212A`)
This doc provides **exact class changes and snippets** to implement in the **React/Tailwind** source (not the built HTML).
---
## Assets
### Logo files (must remain unchanged)
Place these in the frontend **public** folder so they can be used without bundler imports:
- `frontend/public/branding/motovaultpro-title.png`
- `frontend/public/branding/motovaultpro-logo-only.png`
(If your repo structure differs, keep the same `/branding/...` URL path equivalent.)
Usage:
- Hero: `/branding/motovaultpro-title.png`
- Nav: `/branding/motovaultpro-logo-only.png`
---
## Design Tokens (from MVP color scheme)
Use these colors (hex values) directly in Tailwind arbitrary values or via Tailwind config.
- **Nero Daytona**: `#231F1C` (page base)
- **Bianco Avus**: `#F2F3F6` (primary text on dark)
- **Grigio Titanio**: `#A8B8C0` (secondary text on dark)
- **Canna Di Fucile**: `#7E8792` (muted borders/icons)
- **Rosso Mugello (Primary)**: `#7A212A` (primary CTA; already `primary-500`)
### Quick token aliases (recommended)
If you can edit `tailwind.config.*`, add:
- `nero: "#231F1C"`
- `avus: "#F2F3F6"`
- `titanio: "#A8B8C0"`
- `canna: "#7E8792"`
If you prefer no config changes, use arbitrary values like `bg-[#231F1C]`.
---
## Implementation Plan (Step-by-step)
### 0) Locate the homepage components
In the repo, find the marketing homepage by searching for one of these:
- `hero-carousel`
- `slick-dots`
- `MOTOVAULTPRO`
- `Thank you for your interest in MotoVaultPro`
- `What We Offer`
- `min-h-screen bg-white`
- `bg-gray-50` + `Our Features`
Common file names in React projects:
- `LandingPage.tsx`, `HomePage.tsx`, `MarketingHome.tsx`, `PublicHome.tsx`
- Components: `HeroCarousel.tsx`, `Navbar.tsx`, `FeaturesSection.tsx`
---
## 1) Root container: switch to dark base
**Before**
```tsx
<div className="min-h-screen bg-white">
After
Always show details
<div className="min-h-screen bg-[#231F1C] text-[#F2F3F6]">
Notes:
This makes all default text inherit Bianco Avus.
Any sections that used gray text must be updated (see below).
2) Nav: dark surface + logo-only
Nav container
Before
Always show details
<nav className="bg-white shadow-md sticky top-0 z-50">
After
Always show details
<nav className="sticky top-0 z-50 bg-[#231F1C]/90 backdrop-blur border-b border-white/10">
Brand area
Replace the text-only brand with logo-only + text.
Before
Always show details
<h1 className="text-2xl font-bold text-primary-500">MotoVaultPro</h1>
After
Always show details
<a href="#home" className="flex items-center gap-3">
<img
src="/branding/motovaultpro-logo-only.png"
alt="MotoVaultPro"
className="h-8 w-auto"
/>
<span className="text-lg md:text-xl font-bold tracking-wide text-[#F2F3F6]">
MotoVaultPro
</span>
</a>
Nav links (desktop)
Before
Always show details
<a className="text-gray-700 hover:text-primary-500 transition-colors">Home</a>
After
Always show details
<a className="text-white/75 hover:text-white transition-colors">Home</a>
Apply same to Features/About links.
Mobile menu button
Before
Always show details
<button className="text-gray-700 hover:text-primary-500 ...">
After
Always show details
<button className="text-white/80 hover:text-white focus:outline-none">
Nav CTA buttons
Remove light hover backgrounds (e.g., hover:bg-primary-50) since that becomes bright on dark.
Sign Up (outline)
Before
Always show details
<button className="border-2 border-primary-500 text-primary-500 hover:bg-primary-50 ...">
After
Always show details
<button className="border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 hover:border-primary-500 transition-colors duration-300 font-semibold py-2 px-6 rounded-lg">
Sign Up
</button>
Login (filled)
Keep as primary, optionally add shadow.
Always show details
<button className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30">
Login
</button>
3) Hero: place the full logo on a dark “brand plate”
Goal: the logo has a black rectangle background; we want it to feel embedded, not pasted.
We do that by placing it on a slightly-transparent dark plate with a subtle border and blur.
Replace hero overlay content
Find the hero overlay container (currently shows “Welcome to” + big text + Learn More button).
Before (conceptually)
Always show details
<p className="text-white ...">Welcome to</p>
<h1 className="text-white ...">MOTOVAULTPRO</h1>
<button className="bg-primary-500 ...">Learn More</button>
After
Always show details
<div className="absolute inset-0 flex flex-col items-center justify-center text-center px-4">
<div className="rounded-2xl border border-white/10 bg-black/40 backdrop-blur-sm p-5 md:p-8 shadow-[0_20px_60px_rgba(0,0,0,0.65)]">
<img
src="/branding/motovaultpro-title.png"
alt="MotoVaultPro — Precision Vehicle Management"
className="w-[280px] md:w-[520px] lg:w-[620px] h-auto"
loading="eager"
/>
</div>
<p className="mt-6 max-w-2xl text-white/85 text-base md:text-lg leading-relaxed">
Maintenance, fuel/energy, documents, and reminders — organized per vehicle.
</p>
<div className="mt-6 flex flex-col sm:flex-row gap-3">
<button className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30">
Get Started
</button>
<a href="#features" className="inline-flex items-center justify-center rounded-lg border border-white/15 bg-white/5 hover:bg-white/10 text-white font-semibold py-3 px-8 transition-colors duration-300">
View Features
</a>
</div>
</div>
Keep existing hero gradient overlay
Your hero images already have:
bg-gradient-to-b from-black/60 via-black/40 to-black/60
Keep it; it improves readability.
Optional: reduce slick arrow intensity
If the slick arrows feel too “bright” on dark:
Reduce opacity and add hover.
Example CSS:
Always show details
.hero-carousel .slick-prev:before,
.hero-carousel .slick-next:before { opacity: 0.45; }
.hero-carousel .slick-prev:hover:before,
.hero-carousel .slick-next:hover:before { opacity: 0.8; }
4) Welcome section: dark panel
Before
Always show details
<section className="py-16 px-4 md:px-8 bg-white">
After
Always show details
<section className="py-16 px-4 md:px-8 bg-[#1D1A18] border-t border-white/5">
Text updates (do as class swaps; keep content if you want):
text-gray-900 → text-[#F2F3F6]
text-gray-600 → text-[#A8B8C0]
Example:
Always show details
<h2 className="text-3xl md:text-4xl font-bold text-[#F2F3F6] mb-6">...</h2>
<p className="text-lg text-[#A8B8C0] leading-relaxed mb-8">...</p>
5) About section: dark base + keep the maroon feature block
Before
Always show details
<section id="about" className="py-16 px-4 md:px-8 bg-gray-100">
After
Always show details
<section id="about" className="py-16 px-4 md:px-8 bg-[#231F1C] border-t border-white/5">
Text swaps:
text-gray-900 → text-[#F2F3F6]
text-gray-600 → text-[#A8B8C0]
Trusted Platform block:
Keep bg-primary-500
Add subtle border to sharpen against dark background:
Always show details
<div className="w-64 h-64 bg-primary-500 rounded-lg border border-white/10 ...">
6) Features section: dark background + convert white cards to “dark cards”
Section background
Before
Always show details
<section className="py-16 px-4 md:px-8 bg-gray-50">
After
Always show details
<section className="py-16 px-4 md:px-8 bg-[#1D1A18] border-t border-white/5">
Card container (most important change)
Find the card body container:
Before
Always show details
<div className="bg-white p-6">
<h3 className="text-xl font-bold text-gray-900 mb-2">...</h3>
<p className="text-gray-600 leading-relaxed">...</p>
</div>
After
Always show details
<div className="bg-white/5 border border-white/10 p-6">
<h3 className="text-xl font-bold text-[#F2F3F6] mb-2">...</h3>
<p className="text-[#A8B8C0] leading-relaxed">...</p>
</div>
Card outer wrapper (shadow + hover)
Before
Always show details
<div className="overflow-hidden rounded-lg shadow-lg hover:shadow-xl transition-shadow duration-300">
After
Always show details
<div className="overflow-hidden rounded-lg border border-white/10 bg-white/5 shadow-lg shadow-black/30 hover:border-white/20 hover:shadow-xl hover:shadow-black/40 transition-all duration-300">
Note: With the new card body background already set, you may remove redundant bg-white/5 either on wrapper or body.
Prefer wrapper bg-white/5 + body bg-transparent, OR wrapper bg-transparent + body bg-white/5. Dont double-darken unless it looks better.
7) CTA strip: keep Rosso Mugello but make it richer on dark pages
Current
Always show details
<section className="py-16 px-4 md:px-8 bg-primary-500 text-white">
Recommended
Always show details
<section className="py-16 px-4 md:px-8 text-white bg-[linear-gradient(90deg,#6A1C24_0%,#7A212A_50%,#6A1C24_100%)] border-t border-white/10">
Button:
Before
Always show details
<button className="bg-white text-primary-500 hover:bg-gray-100 ...">Get Started</button>
After
Always show details
<button className="bg-white/95 text-primary-500 hover:bg-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300 shadow-lg shadow-black/30">
Get Started
</button>
8) Footer: align to the new dark base
Before
Always show details
<footer className="bg-gray-900 text-white py-8 px-4 md:px-8">
<p className="text-gray-400">...</p>
</footer>
After
Always show details
<footer className="bg-black text-white py-8 px-4 md:px-8 border-t border-white/10">
<p className="text-white/50">© 2025 MotoVaultPro. All rights reserved.</p>
</footer>
9) Remove or replace light-only Tailwind classes on homepage
On the homepage only, avoid these patterns because they create “light UI” artifacts on dark pages:
bg-white, bg-gray-50, bg-gray-100
text-gray-900, text-gray-700, text-gray-600
hover:bg-primary-50 (currently a very light blue in your built CSS)
Use instead:
dark surfaces: bg-[#231F1C], bg-[#1D1A18], bg-white/5
text: text-[#F2F3F6], text-[#A8B8C0], text-white/80
hover: hover:bg-white/10 or hover:bg-primary-500/10
Acceptance Criteria (QA checklist)
Homepage background is dark everywhere (no white sections).
Full logo in hero feels native (sits on a dark “brand plate” with border/blur).
Nav uses logo-only and remains readable on scroll.
Feature cards are dark, readable, and keep hover affordances.
No bright hover states (no primary-50 / light blue flashes).
Mobile: spacing remains consistent; CTAs are reachable; text contrast is good.
Suggested PR structure
feat(ui): dark theme for marketing homepage to match logo background
Include before/after screenshots at desktop + mobile widths.
"""
path = Path("/mnt/data/MVP-HOMEPAGE-DARK-THEME-SPEC.md")
path.write_text(md, encoding="utf-8")
str(path)

View File

@@ -0,0 +1,193 @@
# Fix New User Signup Wizard Flow
## Problem Summary
The new user signup wizard is broken:
1. After Auth0 callback, users go to `/garage` instead of `/verify-email`
2. Users can access `/garage/*` without verified email
3. Onboarding flow is bypassed entirely
4. **New Requirement**: Block login completely at Auth0 for unverified users
## Root Causes
1. **Auth0Provider.tsx:29** - `onRedirectCallback` defaults to `/garage` without checking verification
2. **App.tsx:472-481** - Callback route just shows "Processing login..." with no routing logic
3. **App.tsx:549+** - Protected routes have no email verification check
4. **Auth0** - No rule/action blocking unverified users from logging in
---
## Implementation Plan
### Phase 1: Auth0 Configuration (Manual Step)
**Auth0 Dashboard -> Actions -> Flows -> Login**
Create a Post Login Action to block unverified users:
```javascript
exports.onExecutePostLogin = async (event, api) => {
if (!event.user.email_verified) {
api.access.deny('Please verify your email address before logging in. Check your inbox for a verification link.');
}
};
```
This ensures:
- Unverified users cannot get a JWT
- They see a clear error on the Auth0 login screen
- They must click the verification link before logging in
### Phase 2: Update Signup Flow
**After signup, redirect to a "Check Your Email" page (not /verify-email)**
The new flow:
1. User submits signup form
2. Backend creates Auth0 user (unverified)
3. Auth0 automatically sends verification email
4. Frontend shows "Check Your Email" page with:
- Message: "We've sent a verification link to your email"
- Resend button (calls public resend endpoint)
- "Back to Login" button
5. User clicks email link -> Auth0 marks as verified
6. User can now login -> goes to /onboarding
### Phase 3: Backend Changes
**File: `backend/src/features/auth/api/auth.routes.ts`**
- Add `POST /api/auth/resend-verification-public` (no JWT required)
- Takes email address, looks up user, resends verification
**File: `backend/src/features/auth/api/auth.controller.ts`**
- Add `resendVerificationPublic` handler
**File: `backend/src/features/auth/domain/auth.service.ts`**
- Add `resendVerificationByEmail` method
**File: `backend/src/features/auth/api/auth.routes.ts`**
- Add `GET /api/auth/user-status` (JWT required)
- Returns: `{ emailVerified, onboardingCompleted, email }`
**File: `backend/src/core/plugins/auth.plugin.ts`**
- Add `/api/auth/user-status` to `VERIFICATION_EXEMPT_ROUTES`
### Phase 4: Create Callback Handler
**File: `frontend/src/features/auth/pages/CallbackPage.tsx`** (NEW)
- Fetches user status after Auth0 callback
- Routes based on status:
- Not onboarded -> `/onboarding`
- Onboarded -> `/garage` (or returnTo)
- Note: Unverified users never reach this (blocked by Auth0)
**File: `frontend/src/features/auth/mobile/CallbackMobileScreen.tsx`** (NEW)
- Mobile version
### Phase 5: Update Auth0Provider
**File: `frontend/src/core/auth/Auth0Provider.tsx`**
Update `onRedirectCallback` (line 27-31):
```typescript
const onRedirectCallback = (appState?: { returnTo?: string }) => {
navigate('/callback', {
replace: true,
state: { returnTo: appState?.returnTo || '/garage' }
});
};
```
### Phase 6: Rename/Update Verify Email Page
**File: `frontend/src/features/auth/pages/VerifyEmailPage.tsx`**
- Rename concept to "Check Your Email" page
- Remove polling (user can't be authenticated)
- Show static message + resend button (calls public endpoint)
- Add "Back to Login" button
**File: `frontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx`**
- Same changes for mobile
### Phase 7: Update App.tsx Routing
**File: `frontend/src/App.tsx`**
1. Replace callback handling (lines 472-481) with CallbackPage
2. Add onboarding guard after authentication check
3. Remove email verification check from frontend (Auth0 handles it)
```typescript
// After isAuthenticated check:
// Fetch onboarding status
// If not onboarded -> /onboarding
// Otherwise -> proceed to /garage
```
### Phase 8: Create Supporting Files
**File: `frontend/src/core/auth/useUserStatus.ts`** (NEW)
- Hook for fetching user status
**File: `frontend/src/features/auth/api/auth.api.ts`**
- Add `getUserStatus()`
- Add `resendVerificationPublic(email)` (no auth)
---
## Files to Modify
### Auth0 (Manual Configuration)
- Create Post Login Action to block unverified users
### Backend
- `backend/src/features/auth/api/auth.routes.ts` - Add endpoints
- `backend/src/features/auth/api/auth.controller.ts` - Add handlers
- `backend/src/features/auth/domain/auth.service.ts` - Add methods
- `backend/src/core/plugins/auth.plugin.ts` - Update exempt routes
### Frontend
- `frontend/src/core/auth/Auth0Provider.tsx` - Fix onRedirectCallback
- `frontend/src/App.tsx` - Add route guards and callback handler
- `frontend/src/features/auth/pages/CallbackPage.tsx` - NEW
- `frontend/src/features/auth/mobile/CallbackMobileScreen.tsx` - NEW
- `frontend/src/features/auth/pages/VerifyEmailPage.tsx` - Update to static page
- `frontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx` - Update
- `frontend/src/core/auth/useUserStatus.ts` - NEW
- `frontend/src/features/auth/api/auth.api.ts` - Add functions
---
## New User Flow (After Fix)
```
1. Signup form submission
2. -> POST /api/auth/signup (creates unverified Auth0 user)
3. -> Navigate to /verify-email (static "Check Your Email" page)
4. User clicks verification link in email
5. -> Auth0 marks user as verified
6. User clicks "Login" on /verify-email page
7. -> Auth0 login succeeds (user is now verified)
8. -> /callback page fetches status
9. -> Not onboarded? -> /onboarding
10. -> Complete onboarding -> /garage
```
## Returning User Flow
```
1. Login attempt (unverified) -> Auth0 blocks with error message
2. Login attempt (verified, not onboarded) -> /callback -> /onboarding
3. Login attempt (verified, onboarded) -> /callback -> /garage
```
---
## Testing Checklist
- [ ] Auth0 Action blocks unverified login with clear error
- [ ] Signup -> check-email page -> verify via email -> login works
- [ ] Resend verification from check-email page works
- [ ] Verified user (no onboarding) -> onboarding wizard
- [ ] Verified + onboarded user -> direct to garage
- [ ] Direct URL access to /garage -> requires login
- [ ] All flows work on mobile
- [ ] All flows work on desktop