feat: navigation and UX improvements complete
This commit is contained in:
448
docs/changes/DARK-THEME-PLAN.md
Normal file
448
docs/changes/DARK-THEME-PLAN.md
Normal 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. Don’t 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)
|
||||
193
docs/changes/ONBOARDING-FIX.md
Normal file
193
docs/changes/ONBOARDING-FIX.md
Normal 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
|
||||
1218
docs/changes/admin-implementation-plan.md
Normal file
1218
docs/changes/admin-implementation-plan.md
Normal file
File diff suppressed because it is too large
Load Diff
134
docs/changes/admin-settings-frontend-plan.md
Normal file
134
docs/changes/admin-settings-frontend-plan.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Admin Settings Frontend Implementation Plan
|
||||
|
||||
## Audience & Scope
|
||||
- **Intended executor**: AI agent implementing MotoVaultPro admin settings UI across desktop and mobile.
|
||||
- **Scope**: Frontend-only tasks within `frontend/`, coordinating with existing backend admin APIs. Includes real-time audit log integration and bulk operations across admin users, catalog entities, and station management.
|
||||
|
||||
## Current State Summary
|
||||
- Routes exist (`frontend/src/pages/admin/*.tsx`, `frontend/src/features/admin/mobile/*.tsx`) but contain placeholder copy.
|
||||
- Hooks and API clients (`frontend/src/features/admin/hooks/*`, `frontend/src/features/admin/api/admin.api.ts`) already wrap CRUD endpoints but lack bulk helpers and streaming.
|
||||
- Settings pages link into admin routes; `useAdminAccess` gate is wired.
|
||||
- No shared admin layout, tables, or selection utilities; no real-time audit consumption; no bulk UI.
|
||||
|
||||
## Key Requirements
|
||||
1. **Real-time audit logging** for admin operations (desktop + mobile).
|
||||
2. **Bulk operations**: multi-select + batch mutate/delete/revoke across admin users, catalog hierarchy, stations.
|
||||
3. **Desktop / Mobile parity** while respecting CLAUDE.md mobile + desktop mandate and existing design system.
|
||||
|
||||
Assumptions:
|
||||
- Backend will expose streaming endpoint (`/api/admin/audit-logs/stream`) using SSE. (If absent, coordinate for addition.)
|
||||
- Backend will provide/extend batch mutation endpoints or accept arrays in current ones.
|
||||
- No additional design assets; follow existing Material UI / GlassCard patterns.
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 0 – Prep & Validation
|
||||
- Confirm backend endpoints:
|
||||
- `GET /api/admin/audit-logs/stream` (SSE) payload schema.
|
||||
- Batch endpoints for admins (`POST /admin/admins/bulk`, `PATCH /admin/admins/bulk-revoke`, etc.), catalog (`/admin/catalog/{entity}/bulk-delete`), stations (`/admin/stations/bulk-delete`).
|
||||
- Response format + error contracts.
|
||||
- Document agreements in `docs/ADMIN.md` and update API client typings before UI work.
|
||||
|
||||
### Phase 1 – Shared Infrastructure
|
||||
- Add shared admin components under `frontend/src/features/admin/components/`:
|
||||
- `AdminSectionHeader`
|
||||
- `AdminDataGrid` (wrapper around MUI DataGrid or Table) with checkbox selection and toolbar slot.
|
||||
- `SelectionToolbar` + `BulkActionDialog`.
|
||||
- `AuditLogPanel` (desktop) and `AuditLogDrawer` (mobile).
|
||||
- `EmptyState`, `ErrorState`, `Skeleton` variants.
|
||||
- Utility hooks/services:
|
||||
- `useBulkSelection` (manages item selection, select all, reset).
|
||||
- `useAuditLogStream` (SSE handling, merge into cache, pause/resume).
|
||||
- `useAdminRealtimeEffect` (common real-time logic for both platforms).
|
||||
- Error normalization helper for API responses.
|
||||
- Update `admin.api.ts` to include bulk endpoints and streaming subscription helper.
|
||||
- Ensure types in `admin.types.ts` cover new request/response payloads.
|
||||
|
||||
### Phase 2 – Admin Users Experience
|
||||
- **Desktop (`AdminUsersPage.tsx`)**:
|
||||
- Replace placeholder with layout:
|
||||
- Header (stats summary cards).
|
||||
- `AdminDataGrid` listing admins (columns: email, role, status, created/updated, last activity).
|
||||
- Toolbar actions: Invite, Revoke, Reinstate, Delete (single + bulk), export CSV placeholder.
|
||||
- Inline filters/search.
|
||||
- Audit log side panel fed by `useAuditLogStream`.
|
||||
- Modals/forms:
|
||||
- Invite admin (react-hook-form + Zod validation).
|
||||
- Confirm dialogs for revoke/reinstate/delete (bulk friendly).
|
||||
- State management:
|
||||
- Use React Query hooks (`useAdmins`, new `useBulkRevokeAdmins`, etc.).
|
||||
- Optimistic updates where safe; fallback to refetch on failure.
|
||||
- Surface backend constraints (last admin protection) in toasts/dialogs.
|
||||
- **Mobile (`AdminUsersMobileScreen.tsx`)**:
|
||||
- Card-based list with segmented controls.
|
||||
- Multi-select mode triggered by long-press or “Select” button; sticky bottom action bar for bulk operations.
|
||||
- Slide-in drawer for audit log stream; allow collapse to preserve screen space.
|
||||
- Ensure loading/error/empty states match mobile pattern.
|
||||
|
||||
### Phase 3 – Vehicle Catalog Management
|
||||
- Extend API hooks for per-entity bulk operations (`useDeleteMakesBulk`, etc.) and streaming updates.
|
||||
- **Desktop (`AdminCatalogPage.tsx`)**:
|
||||
- Two-column layout: left panel shows hierarchical tree (Makes → Models → Years → Trims → Engines). Right panel shows detail grid for selected level.
|
||||
- Support multi-select in each grid with bulk delete; confirm cascading impacts (warn when deleting parents).
|
||||
- Modals for create/edit per entity using shared form component (with validation & parent context).
|
||||
- Audit log panel filtered to catalog-related actions.
|
||||
- Show breadcrumbs + context metadata (created/updated timestamps).
|
||||
- **Mobile (`AdminCatalogMobileScreen.tsx`)**:
|
||||
- Drill-down navigation (list of makes → models → ...).
|
||||
- Selection mode toggles for bulk delete at current depth; use bottom sheet to display actions.
|
||||
- Provide “Recent Changes” sheet consuming audit stream (filtered).
|
||||
- Handle cache invalidation across hierarchies (e.g., deleting a make invalidates models/years/trims queries). Consider using queryClient `invalidateQueries` with partial keys.
|
||||
|
||||
### Phase 4 – Station Oversight
|
||||
- Hook updates: add `useBulkDeleteStations`, `useBulkRestoreStations` if available, with optional `force` flag.
|
||||
- **Desktop (`AdminStationsPage.tsx`)**:
|
||||
- Data grid with columns (name, address, status, last modified, createdBy). Add search bar and filter chips (active, soft-deleted).
|
||||
- Bulk selection with delete (soft/hard toggle), restore, export stub.
|
||||
- Station detail drawer with metadata and quick actions.
|
||||
- Audit log panel focusing on station events; highlight critical operations via toast (e.g., hard deletes).
|
||||
- **Mobile (`AdminStationsMobileScreen.tsx`)**:
|
||||
- Card list with quick actions (edit, delete, restore). Multi-select mode with sticky action bar.
|
||||
- Provide filter tabs (All / Active / Deleted).
|
||||
- Integrate audit log bottom sheet.
|
||||
|
||||
### Phase 5 – Integration & Routing Enhancements
|
||||
- Introduce route wrapper/components (e.g., `AdminUsersRoute`) that detect viewport using `useMediaQuery` and render desktop or mobile variant; ensures shared logic and prevents duplicate routing code.
|
||||
- Update navigation flows, ensuring mobile bottom navigation can reach admin sections gracefully.
|
||||
- Document keyboard shortcuts or focus management for accessibility (bulk selection, audit log toggles).
|
||||
|
||||
### Phase 6 – Testing & QA
|
||||
- Add unit tests for new hooks (`useAuditLogStream`, bulk hooks) using Jest + Testing Library. Mock EventSource for streaming tests.
|
||||
- Component tests:
|
||||
- Desktop grids: selection toggles, bulk action dialogs, form validation.
|
||||
- Mobile screens: selection mode toggling, action bar behaviors.
|
||||
- Audit log panels: streaming update rendering, pause/resume controls.
|
||||
- Visual regression smoke tests if tooling available; otherwise document manual screenshot checkpoints.
|
||||
- Manual QA matrix:
|
||||
- Desktop ≥1280px and mobile ≤480px.
|
||||
- Test flows: invite admin, revoke/reinstate, bulk revoke, catalog cascading delete, station soft/hard delete, audit log live updates.
|
||||
|
||||
## Deliverables Checklist
|
||||
- [ ] Updated API client + types for batch + streaming.
|
||||
- [ ] Shared admin UI components & utilities.
|
||||
- [ ] Desktop admin pages fully functional with bulk + real-time features.
|
||||
- [ ] Mobile admin screens matching functionality.
|
||||
- [ ] Comprehensive tests covering new flows.
|
||||
- [ ] Documentation updates (API usage, manual QA steps).
|
||||
|
||||
## Risks & Mitigations
|
||||
- **Streaming availability**: If backend stream not ready, fall back to polling with progressive enhancement; keep SSE integration behind feature flag.
|
||||
- **Bulk API inconsistencies**: Align payload format with backend; add defensive UI (disable actions until backend confirms support).
|
||||
- **State synchronization**: Ensure query invalidation covers dependent entities; consider structured query keys and `queryClient.setQueryData` for incremental updates.
|
||||
- **Mobile UX complexity**: Prototype selection mode early to validate ergonomics; leverage bottom sheets to avoid cramped toolbars.
|
||||
|
||||
## Follow-up Questions (Resolved)
|
||||
1. Real-time audit logs required — implement SSE-based stream handling.
|
||||
2. Bulk operations mandatory — support multi-select + batch actions across admin users, catalog entities, stations.
|
||||
3. No additional design constraints — rely on existing Material UI and GlassCard paradigms.
|
||||
|
||||
## Handoff Notes
|
||||
- Keep code comments concise per developer guidelines; avoid introducing new design systems.
|
||||
- Validate hooks for Auth0 dependency (ensure disabled when unauthenticated).
|
||||
- Coordinate with backend team if API gaps found; document interim shims.
|
||||
- Maintain responsiveness and accessibility; ensure touch targets ≥44px and keyboard operability on desktop grids.
|
||||
|
||||
Reference in New Issue
Block a user