Shared flow for sign up, sign in, role selection, and first-time experience across both user types.
Step 1 — First Impression
WelcomeScreen — Entry point. Logo uses wordmark asset.
useAuth().isSignedIn → skip to tabs
OnboardingCarousel — 3 swipeable slides, horizontal pager.
PagerView with dot indicators
OnboardingCarousel — Slide 2. Handshake icon.
OnboardingCarousel — Slide 3. Final slide swaps "Next" for "Get Started".
onComplete() → navigate to Role Selection
Step 2 — Role Selection
RoleSelectionScreen — Sets userRole in Clerk metadata.
useMutation(api.users.setRole) → route to role-specific signup
RoleSelectionScreen — Alternate state with contractor selected.
CTA text & color change on selection
Step 3 — Account Creation
SignUpScreen — Clerk signUp.create() with email strategy.
useSignUp() from @clerk/clerk-expo
PhoneVerificationScreen — Clerk phone_code strategy.
signUp.prepareVerification({ strategy: "phone_code" })
Step 4 — Sign In & Recovery
SignInScreen — Clerk signIn.create() with email or phone.
useSignIn() → setActive({ session })
ForgotPasswordScreen — Clerk password_reset flow.
signIn.create({ strategy: "reset_password_email_code" })
ForgotPasswordScreen — Success state after email sent.
Linking.openURL("mailto:") for "Open Email App"
Step 5 — Email Verification
EmailVerificationScreen — Shown after email signup.
signUp.prepareVerification({ strategy: "email_code" })
EmailVerificationScreen — Deep link callback confirms email.
signUp.attemptVerification() → setActive() → profile setup
Step 6 — Poster Profile Setup
PosterProfileSetup — Google Places autocomplete for address.
useMutation(api.users.posters.updateProfile) + api.users.posterProperties.create
Step 7 — Contractor Profile Setup
ContractorProfileSetup — Multi-select chips for service categories.
useMutation(api.users.contractors.updateProfile) + serviceArea array
Step 8 — Enhanced Auth & Acquisition
SignInScreen — Google OAuth via Clerk. Falls back to email/password. Deep-linked from magic link invitations.
useSignIn() → oauth_google strategy → setActive({ session })
AcquisitionSourcePicker — Tracks acquisition source for growth analytics. 11 options mapped to marketing channels.
useMutation(api.users.updateAcquisitionSource) → acquisitionSource field
SignUpScreen — Role-aware tab selector replaces separate sign-up flows. Tab choice sets intendedSetupRole for post-auth routing.
useSignUp() → unsafeMetadata.intendedSetupRole = “poster” | “contractor”
useSignUp() — Handles email/phone registration with ClerkuseSignIn() — Email or phone login, social OAuth (Google, Apple)useAuth() — Session state, isSignedIn, userIduseUser() — Current user profile from Clerkemail_code, phone_code, oauth_google, oauth_apple, reset_password_email_codeexp:// scheme for email verification callbackspublicMetadata.role in Clerk via users.setRole mutationposterUsers + posterProfile + posterProperties recordscontractorUsers + contractorProfile recordstransactionalEmail.ts (SendGrid)#growth_feed on every new signuponboardingProgress schema: { userId, role, step, completedSteps[], createdAt }useOnboarding() hook returns current step + navigation helpersposterUsers — Core poster identity (clerkId, email, name, phone)posterProfile — Extended poster data (avatar, preferences, referralSource)posterProperties — Address, propertyType, lat/lng, zipCodecontractorUsers — Core contractor identity (clerkId, email, name, phone)contractorProfile — Business info (businessName, licenseNumber, serviceCategories, serviceArea, yearsExperience, avatar)useAuth() — Clerk session state, isSignedIn, isLoadeduseOnboarding() — Steps completed, current step, next() / back()useWarmup() — Preloads user data after auth for instant navigationuseDeepLinking() — Handles email verification callback URLs(auth)/welcome → (auth)/onboarding → (auth)/role-select(auth)/sign-up → (auth)/verify-email → (auth)/profile-setup(auth)/sign-in → (auth)/forgot-password(poster)/ or (contractor)/ tab navigatorisSignedIn ? tabs : auth via Expo Router layout