Feature: Onboarding Flow (iOS)
Version: 1.1.0 Last Reviewed: 2026-02-10 Status: Approved
User Story
As a first-time user, I am guided through the required setup steps so I can start using the app immediately. As a second caregiver, I can accept an invite and start tracking alongside the primary parent.
MVP Scope
- Sequential first-launch flow: Server URL → Auth → Add Baby → Dashboard
- Three auth paths: Create Account, I Have an Invite, Log In
- Each step reuses screens built for other features
- Invite path combines account creation with share link acceptance
NOT in MVP
- Feature walkthrough or tutorial overlays
- Skip/defer options (all steps required)
- Social auth (Google, Apple Sign In)
- Magic link auth (post-MVP #12)
Flow
Step 1: Server URL
┌──────────────────────────┐
│ Baby Basics │
│ │
│ Server URL │
│ ┌─────────────────────┐ │
│ │ https://baby.bretz… │ │ ← Pre-filled from build config
│ └─────────────────────┘ │
│ │
│ ┌─────────────────────┐ │
│ │ Continue │ │
│ └─────────────────────┘ │
│ │
│ Verifies server is │
│ reachable via /health │
└──────────────────────────┘
- Pre-filled with build config URL (default:
https://baby.bretzfam.com) - User can edit the URL (for self-hosted instances)
- "Continue" validates by hitting
/api/v1/health - If unreachable: show error with retry
- URL saved to UserDefaults on success
Step 2: Authentication
┌──────────────────────────┐
│ ← Back │
│ │
│ Welcome to Baby Basics │
│ │
│ ┌─────────────────────┐ │
│ │ Create Account │ │ ← Primary button
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │
│ │ I Have an Invite │ │ ← Near-equal button
│ └─────────────────────┘ │
│ │
│ Already have an │
│ account? Log in │ ← Text link
└──────────────────────────┘
Create Account path:
- Name, Email, and Password fields
- Name: required, 1-100 characters
- Password minimum: 8 characters
- Show/hide password toggle
- "Create Account" button → POST /auth/register (with name)
- On success: token saved to Keychain, proceed to Step 3
I Have an Invite path:
- Name, Email, and Password fields (same as Create Account)
- Invite code field (the share link token, can paste)
- "Join" button → POST /auth/register (with name), then POST /invites/accept
- On success: token saved, invite accepted, skip Step 3 (baby already exists), go to Dashboard
- Shows confirmation: "You're now tracking Baby Name" with subtext "Shared by Johnny" (from
child.nameandgranted_by.namein accept response) - If user already has account: show "Already registered? Log in with your invite" toggle
Log In path:
- Email + Password fields
- "Log In" button → POST /auth/login
- On success: token saved, check if user has children
- Has children → go to Dashboard
- No children → go to Step 3
Step 3: Add Baby
┌──────────────────────────┐
│ ← Back │
│ │
│ Add your baby │
│ │
│ Name │
│ ┌─────────────────────┐ │
│ │ │ │
│ └─────────────────────┘ │
│ Date of birth │
│ ┌─────────────────────┐ │
│ │ 📅 Pick date │ │ ← Native date picker
│ └─────────────────────┘ │
│ │
│ ┌─────────────────────┐ │
│ │ Let's Go! │ │
│ └─────────────────────┘ │
└──────────────────────────┘
- Name field: required, min 1 character
- Date of birth: native iOS date picker, defaults to today
- "Let's Go!" → POST /children
- On success: navigate to Dashboard
Step 4: Dashboard
- Onboarding complete, normal app flow begins
- Subsequent launches skip onboarding (token exists in Keychain)
State Management
- Onboarding progress tracked via AppState
- States:
.serverUrl,.auth,.addBaby,.ready - Back button available on Steps 2 and 3
- If app is killed mid-onboarding, restart from last incomplete step
- Server URL persists in UserDefaults even if auth isn't complete
Error Handling
- Server unreachable: "Can't connect to server. Check the URL and try again." + Retry button
- Registration failed (duplicate email): "An account with this email already exists. Try logging in."
- Login failed: "Invalid email or password." (generic, no email enumeration)
- Invalid invite code: "This invite link is invalid or has already been used."
- Network error: Generic error with retry button
Acceptance Criteria
- First launch shows server URL configuration screen
- Server URL is pre-filled from build config
- Server URL is validated via /health endpoint before proceeding
- Invalid server URL shows clear error with retry
- Create Account path: can register with name + email + password
- I Have an Invite path: can register + accept invite in one flow (shows who shared)
- Log In path: can log in with existing account
- After auth, shows "Add your baby" screen (if no children)
- After adding child, lands on Dashboard ready to use
- Subsequent launches go directly to Dashboard (skip onboarding)
- Can go back to previous steps during onboarding
- Token persists in Keychain across app restarts
- Invite path skips "Add baby" step (baby already shared)
Test Cases
- Full new user flow: Server URL → Register → Add Baby → Dashboard
- Invite flow: Server URL → I Have an Invite → Register + code → Dashboard (baby already visible)
- Returning user flow: Server URL → Log In → Dashboard (has children)
- Returning user, no children: Server URL → Log In → Add Baby → Dashboard
- Invalid server URL: Enter bad URL → error message → fix URL → proceed
- Duplicate email: Try to register with existing email → error → switch to login
- Wrong password: Try to log in with wrong password → error
- Invalid invite: Enter expired/used invite code → error
- Back navigation: Go to Step 2, go back to Step 1, URL is still filled
- Kill and restart: Complete Step 1, kill app, reopen → starts at Step 2 (URL saved)
- Subsequent launch: Complete onboarding, close app, reopen → goes to Dashboard
Boundaries
- No "skip" option - all steps are required
- No tutorial or feature walkthrough
- No account deletion during onboarding
- No deep link handling during onboarding (deferred until after auth)
- The invite code is the raw token from the share link URL (user can paste from Messages/email)