Onboarding Feature Module
Overview
The onboarding feature manages the user signup workflow after email verification. It handles user preference setup (unit system, currency, timezone) and tracks onboarding completion status.
Purpose
After a user verifies their email with Auth0, they go through an onboarding flow to:
- Set their preferences (unit system, currency, timezone)
- Optionally add their first vehicle (handled by vehicles feature)
- Mark onboarding as complete
API Endpoints
All endpoints require JWT authentication via fastify.authenticate preHandler.
POST /api/onboarding/preferences
Save user preferences during onboarding.
Request Body:
{
"unitSystem": "imperial",
"currencyCode": "USD",
"timeZone": "America/New_York"
}
Validation:
unitSystem: Must be either "imperial" or "metric"currencyCode: Must be exactly 3 uppercase letters (ISO 4217)timeZone: 1-100 characters (IANA timezone identifier)
Response (200):
{
"success": true,
"preferences": {
"unitSystem": "imperial",
"currencyCode": "USD",
"timeZone": "America/New_York"
}
}
Error Responses:
404 Not Found- User profile not found500 Internal Server Error- Failed to save preferences
POST /api/onboarding/complete
Mark onboarding as complete for the authenticated user.
Request Body: None
Response (200):
{
"success": true,
"completedAt": "2025-12-22T15:30:00.000Z"
}
Error Responses:
404 Not Found- User profile not found500 Internal Server Error- Failed to complete onboarding
GET /api/onboarding/status
Get current onboarding status for the authenticated user.
Response (200):
{
"preferencesSet": true,
"onboardingCompleted": true,
"onboardingCompletedAt": "2025-12-22T15:30:00.000Z"
}
Response (200) - Incomplete:
{
"preferencesSet": false,
"onboardingCompleted": false,
"onboardingCompletedAt": null
}
Error Responses:
404 Not Found- User profile not found500 Internal Server Error- Failed to get status
Architecture
Directory Structure
backend/src/features/onboarding/
├── README.md # This file
├── index.ts # Public API exports
├── api/ # HTTP layer
│ ├── onboarding.controller.ts # Request handlers
│ ├── onboarding.routes.ts # Route definitions
│ └── onboarding.validation.ts # Zod schemas
├── domain/ # Business logic
│ ├── onboarding.service.ts # Core logic
│ └── onboarding.types.ts # Type definitions
└── tests/ # Tests (to be added)
├── unit/
└── integration/
Integration Points
Dependencies
- UserProfileRepository (
features/user-profile) - For updatingonboarding_completed_at - UserPreferencesRepository (
core/user-preferences) - For saving unit system, currency, timezone - Database Pool (
core/config/database) - PostgreSQL connection - Logger (
core/logging/logger) - Structured logging
Database Tables
user_profiles- Storesonboarding_completed_attimestampuser_preferences- Storesunit_system,currency_code,time_zone
Business Logic
Save Preferences Flow
- Extract Auth0 user ID from JWT
- Fetch user profile to get internal user ID
- Check if user_preferences record exists
- If exists, update preferences; otherwise create new record
- Return saved preferences
Complete Onboarding Flow
- Extract Auth0 user ID from JWT
- Call
UserProfileRepository.markOnboardingComplete(auth0Sub) - Updates
onboarding_completed_atto NOW() if not already set - Return completion timestamp
Get Status Flow
- Extract Auth0 user ID from JWT
- Fetch user profile
- Check if user_preferences record exists
- Return status object with:
preferencesSet: boolean (preferences exist)onboardingCompleted: boolean (onboarding_completed_at is set)onboardingCompletedAt: timestamp or null
Key Behaviors
User Ownership
All operations are scoped to the authenticated user via JWT. No cross-user access is possible.
Idempotency
savePreferences- Can be called multiple times; updates existing recordcompleteOnboarding- Can be called multiple times; returns existing completion timestamp if already completed
Email Verification
These routes are in VERIFICATION_EXEMPT_ROUTES in auth.plugin.ts because users complete onboarding immediately after email verification.
Error Handling
All errors are logged with structured logging:
logger.error('Error saving onboarding preferences', {
error,
userId: auth0Sub.substring(0, 8) + '...',
});
Controller methods return appropriate HTTP status codes:
200 OK- Success404 Not Found- User profile not found500 Internal Server Error- Unexpected errors
Testing
Tests to be added:
- Unit tests for
OnboardingServicewith mocked repositories - Integration tests for API endpoints with test database
Future Enhancements
Potential improvements:
- Add validation for IANA timezone identifiers
- Add validation for ISO 4217 currency codes against known list
- Track onboarding step completion for analytics
- Add onboarding progress percentage
- Support for skipping onboarding (mark as complete without preferences)