Files
motovaultpro/backend/src/features/onboarding
2025-12-22 18:20:25 -06:00
..
2025-12-22 18:20:25 -06:00
2025-12-22 18:20:25 -06:00
2025-12-22 18:20:25 -06:00
2025-12-22 18:20:25 -06:00

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:

  1. Set their preferences (unit system, currency, timezone)
  2. Optionally add their first vehicle (handled by vehicles feature)
  3. 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 found
  • 500 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 found
  • 500 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 found
  • 500 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 updating onboarding_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 - Stores onboarding_completed_at timestamp
  • user_preferences - Stores unit_system, currency_code, time_zone

Business Logic

Save Preferences Flow

  1. Extract Auth0 user ID from JWT
  2. Fetch user profile to get internal user ID
  3. Check if user_preferences record exists
  4. If exists, update preferences; otherwise create new record
  5. Return saved preferences

Complete Onboarding Flow

  1. Extract Auth0 user ID from JWT
  2. Call UserProfileRepository.markOnboardingComplete(auth0Sub)
  3. Updates onboarding_completed_at to NOW() if not already set
  4. Return completion timestamp

Get Status Flow

  1. Extract Auth0 user ID from JWT
  2. Fetch user profile
  3. Check if user_preferences record exists
  4. 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 record
  • completeOnboarding - 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 - Success
  • 404 Not Found - User profile not found
  • 500 Internal Server Error - Unexpected errors

Testing

Tests to be added:

  • Unit tests for OnboardingService with 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)