User Flows Documentation¶
Documentation of the main user flows in ECall iOS.
Overview¶
This document describes the main user flows of the ECall iOS application, including unified authentication, calling, and contact management.
Unified Authentication Flow (Sign-in and Registration combined)¶
Flow Diagram¶
User opens app
↓
Show AuthFlowMainView (select method: Email, Phone, Google, Apple)
↓
Enter identifier (email/phone) and display name (if first-time)
↓
Submit (single action for both sign-in/register)
↓
Receive OTP code (email/SMS) if required
↓
Enter OTP → Verify
↓
Generate/Import RSA keys (if first-time on this device)
↓
Complete authentication (new user → register; existing user → sign in)
↓
Navigate to main app
Detailed Steps¶
Step 1: Select Method and Input¶
Screen: AuthFlowMainView
Actions: 1. User selects verification method (Email / Phone / Google / Apple) 2. User enters email or phone number (for Email/Phone methods) 3. User enters display name if this is the first time (new account) 4. User taps "Continue" + method login
Validation: - Email format validation (for Email method) - Phone number format validation (for Phone method) - Display name length validation (max 50 characters) - Apple Sign-in uses native iOS authentication (no manual input required)
Step 2: OTP Verification (if required)¶
Screen: OTPVerificationView
Actions: 1. User receives OTP code (via email/SMS) 2. User enters OTP code 3. User taps "Verify"
Validation: - OTP code format (6 digits) - OTP expiration check
Step 3: Key Generation/Import (per device)¶
Screen: KeyGenerationView
Options:
Option A: Generate New Keys 1. User taps "Generate Keys" 2. System generates RSA-2048 key pair 3. Keys displayed for user review 4. User saves recovery key (optional) 5. User taps "Continue"
Option B: Import Existing Keys 1. User enters public key 2. User enters private key 3. System validates key format 4. User taps "Continue"
Special Case: Apple Sign-in - For Apple Sign-in, the user authenticates using Face ID, Touch ID, or Apple ID password - System receives authorization code and identity token from Apple - Display name is extracted from Apple credential or uses email as fallback - System calls Apple login API with code, token, and display name - Backend verifies tokens with Apple and creates/logs in user - User proceeds to key generation/import step (same as other methods)
Step 4: Complete Authentication¶
Screen: CompleteRegistrationView (for first-time) or direct transition
Actions: 1. System sends public key + device info to server (on first device registration) 2. System stores access token and user info 3. User navigates to main app
Call Flow¶
Outgoing Call Flow¶
Flow Diagram¶
User selects contact
↓
User taps call button
↓
User selects video/audio
↓
System initiates call
↓
Fetch callee public keys
↓
Generate AES key
↓
Encrypt AES key for each callee
↓
Setup Janus room
↓
Call backend API
↓
Join Janus room
↓
Create WebRTC offer
↓
Exchange SDP/ICE candidates
↓
Establish WebRTC connection
↓
Start E2EE media encryption
↓
Call active
Detailed Steps¶
Step 1: Initiate Call Screen: ContactsView or CallHistoryView
Actions: 1. User selects contact from address book 2. User taps call button 3. User selects call type (video/audio) 4. System shows calling screen
Step 2: Call Setup System: GroupCallManager.startCall()
Actions: 1. Initialize CallKit transaction 2. Fetch callee public keys from server 3. Generate random AES-256 key 4. Encrypt AES key with RSA public key for each callee 5. Setup Janus room (create session, attach plugin, create room) 6. Call backend API (POST /api/call/start) 7. Join Janus room
Step 3: WebRTC Connection System: WebRTCManager
Actions: 1. Create WebRTC offer 2. Send offer to Janus Gateway 3. Receive answer from callee 4. Exchange ICE candidates 5. Establish peer connection 6. Start media encryption
Step 4: Call Active Screen: CallView
Actions: 1. User sees video/audio streams 2. User can mute/unmute audio 3. User can enable/disable video 4. User can toggle speaker 5. User can end call
Incoming Call Flow¶
Flow Diagram¶
Receive call invitation (WebSocket)
↓
Decrypt AES key
↓
Report to CallKit
↓
Show incoming call UI
↓
User answers? → Yes → Join Janus room
↓
Create WebRTC answer
↓
Exchange SDP/ICE candidates
↓
Establish WebRTC connection
↓
Start E2EE media encryption
↓
Call active
↓
User rejects? → Reject call
↓
Timeout? → Auto-reject (60 seconds)
Detailed Steps¶
Step 1: Receive Invitation System: StompSignalingManager receives call_invitation message
Actions: 1. Parse invitation message 2. Decrypt AES key with RSA private key 3. Report incoming call to CallKit 4. Start timeout timer (60 seconds)
Step 2: User Response Screen: CallKit native UI
Actions: - Answer: User swipes up or taps "Answer" - Reject: User swipes down or taps "Decline" - Timeout: Auto-reject after 60 seconds
Step 3: Join Call (if answered) System: GroupCallManager.handleCallAnswer()
Actions: 1. Join Janus room 2. Create WebRTC answer 3. Exchange SDP/ICE candidates 4. Establish peer connection 5. Start media encryption 6. Show call UI
Group Call Flow¶
Flow Diagram¶
User starts call with multiple contacts
↓
For each contact:
- Fetch public key
- Encrypt AES key
↓
Setup Janus room
↓
Call backend API
↓
Join Janus room
↓
Create WebRTC offer
↓
For each participant:
- Exchange SDP/ICE candidates
- Establish peer connection
↓
Call active with multiple participants
Detailed Steps¶
Step 1: Initiate Group Call Screen: ContactsView
Actions: 1. User selects multiple contacts 2. User taps call button 3. User selects call type (video/audio) 4. System initiates call for all contacts
Step 2: Encrypt Keys System: Encrypt AES key for each participant
Actions: 1. Fetch public keys for all participants 2. Encrypt AES key with RSA public key for each participant 3. Send encrypted keys to backend
Step 3: Join Call System: Each participant joins call
Actions: 1. Each participant receives invitation 2. Each participant decrypts AES key 3. Each participant joins Janus room 4. Each participant establishes WebRTC connection
Step 4: Call Active Screen: CallView with participant list
Actions: 1. User sees all participants' video/audio 2. User can mute/unmute individual participants 3. User can invite additional participants 4. User can end call
Invite Participants Flow¶
Flow Diagram¶
During active call
↓
User clicks invite button
↓
User selects contacts
↓
Fetch public keys
↓
Encrypt AES key
↓
Call backend API
↓
Send invitations
↓
Participants receive invitations
↓
Participants join call
Detailed Steps¶
Step 1: Invite Participants Screen: CallView
Actions: 1. User clicks invite button 2. User selects contacts from address book 3. System fetches public keys 4. System encrypts AES key for each participant 5. System calls backend API (POST /api/call/{callId}/invite)
Step 2: Participants Join System: Each participant receives invitation
Actions: 1. Participant receives call_invitation message 2. Participant decrypts AES key 3. Participant joins Janus room 4. Participant establishes WebRTC connection 5. Participant appears in call UI
Rejoin Call Flow¶
Flow Diagram¶
User views call history
↓
User sees active call
↓
User taps rejoin button
↓
Request rejoin via backend API
↓
Backend sends request to active participants
↓
Active participant encrypts AES key for rejoining user
↓
Send encrypted AES key via STOMP (participant_accept_rejoin)
↓
Rejoining user receives encrypted AES key
↓
Decrypt AES key with RSA private key
↓
Join Janus room
↓
Establish WebRTC connection
↓
Rejoin successful - call active
Detailed Steps¶
Step 1: Initiate Rejoin Screen: CallHistoryView or CallHistoryDetailView
Actions: 1. User views call history 2. User identifies an active call (status: "active") 3. User taps "Rejoin" button 4. System calls backend API (POST /api/call/{callId}/request-rejoin)
Step 2: Request Processing System: Backend and active participants
Actions: 1. Backend receives rejoin request 2. Backend sends participant_request_rejoin message to active participants via STOMP 3. Active participant receives request with requester's userId and deviceId 4. Active participant fetches requester's public key 5. Active participant encrypts current AES key with requester's RSA public key 6. Active participant sends participant_accept_rejoin message with encrypted AES key
Step 3: Rejoin Call System: GroupCallSessionManager.rejoinActiveCall()
Actions: 1. Rejoining user receives participant_accept_rejoin message via STOMP 2. System decrypts encrypted AES key using RSA private key 3. System calls backend API (POST /api/call/{callId}/rejoin) 4. Backend returns call record with Janus room ID 5. System initializes call session with rejoin flag 6. System joins Janus room 7. System establishes WebRTC publisher/subscriber connections 8. System updates participant list 9. User successfully rejoins call with E2EE encryption
Step 4: Call Active Screen: CallView
Actions: 1. User sees all participants' video/audio streams 2. User can use all call controls (mute, video toggle, speaker) 3. User appears in participant list for other users 4. Call continues with full E2EE encryption
Contact Management Flow¶
Add Contact Flow¶
Flow Diagram¶
User opens Contacts
↓
User clicks add button
↓
User selects add method:
- Search by email/phone
- Scan QR code
↓
Send friend request
↓
Contact receives request
↓
Contact accepts
↓
Contact added to list
Detailed Steps¶
Step 1: Add Contact Screen: AddFriendView
Options:
Option A: Search 1. User enters email/phone or public key hash 2. System searches for contact 3. User clicks "Send Friend Request" 4. System sends friend request (POST /api/friend-request)
Option B: QR Code 1. User clicks "Scan QR Code" 2. System opens camera 3. User scans QR code 4. System parses contact info 5. User clicks "Send Friend Request" 6. System sends friend request
Step 2: Accept Request Screen: FriendRequestView
Actions: 1. Contact receives friend request notification 2. Contact opens friend requests screen 3. Contact clicks "Accept" 4. System accepts friend request (POST /api/friend-request/accept) 5. Contact added to contacts list
Remove Friend Flow¶
Flow Diagram¶
User opens contact details
↓
User clicks remove friend button
↓
User confirms removal
↓
Friendship removed
↓
Contact removed from list
Detailed Steps¶
Step 1: Remove Friend Screen: ContactDetailView
Actions: 1. User opens contact details 2. User clicks "Remove Friend" button 3. System shows confirmation dialog 4. User confirms removal 5. System removes friendship (DELETE /api/friend/{id}) 6. Contact removed from contacts list
Settings Flow¶
Profile Update Flow¶
Flow Diagram¶
User opens Settings
↓
User clicks Profile
↓
User edits profile info
↓
User saves changes
↓
System updates profile
↓
Profile updated
Detailed Steps¶
Step 1: Edit Profile Screen: MyProfileView
Actions: 1. User opens profile settings 2. User edits display name/email/phone 3. User clicks "Save" 4. System updates profile (PUT /api/user) 5. Profile updated
Login Method Management Flow¶
Flow Diagram¶
User opens Settings
↓
User clicks Login Methods
↓
User sees linked methods (Email / Phone / Google)
↓
User can:
- Add new login method (email/phone)
- Change primary login method
- Remove a linked method (if multiple remain)
Detailed Steps¶
Step 1: Manage Login Methods Screen: LoginMethodsView
Actions: 1. User opens login methods settings 2. System fetches current linked methods (GET /api/user/login-methods) 3. User can add another email/phone (multiple bindings supported) (POST /api/user/login-methods) 4. User can change primary method (PUT /api/user/login-methods/primary) 5. User can remove a method if at least one remains (DELETE /api/user/login-methods/{id})
Device Management Flow¶
Flow Diagram¶
User opens Settings
↓
User clicks Devices
↓
User sees device list
↓
User can:
- View device details
- Remove device
Detailed Steps¶
Step 1: View Devices Screen: DevicesView
Actions: 1. User opens devices settings 2. System fetches device list (GET /api/devices) 3. User sees all registered devices 4. User can view device details 5. User can remove device
Language Change Flow¶
Flow Diagram¶
User opens Settings
↓
User clicks Language
↓
User selects language
↓
Language changed
↓
App restarts with new language
Detailed Steps¶
Step 1: Change Language Screen: LanguageSwitcherView
Actions: 1. User opens language settings 2. User selects language from list 3. System saves language preference 4. System updates UI with new language 5. App restarts or reloads UI
Error Flows¶
Network Error Flow¶
User action
↓
Network request fails
↓
System shows error message
↓
User can retry
↓
Retry successful? → Continue
↓
Retry failed? → Show error
Call Error Flow¶
Call initiation
↓
Error occurs:
- Network error
- Encryption error
- Janus error
↓
System shows error message
↓
User can retry or cancel
Authentication Error Flow¶
API request
↓
401 Unauthorized
↓
System auto-logout
↓
User redirected to login
↓
User re-login
Success Criteria¶
Authentication Flow¶
- ✅ User completes first-time authentication in < 5 minutes
- ✅ OTP verification works correctly
- ✅ Keys generated/imported successfully
- ✅ User navigates to main app
Call Flow¶
- ✅ Call connects in < 5 seconds
- ✅ Audio/video quality is good
- ✅ E2EE encryption works correctly
- ✅ Call ends gracefully
Contact Management Flow¶
- ✅ Friend requests sent/received correctly
- ✅ QR code scanning works
- ✅ Contacts added successfully
- ✅ Remove friend works correctly