Connection UX Flow
Purpose
The connection flow guides users from first signup through WhatsApp linking with real-time feedback at every stage. The UI adapts to show relevant information based on the current phase.
Phases
1. Setup (no slice, not connected)
User has an account but no WhatsApp connection. Shows:
- “Connect WhatsApp” button
- Instructions for what they’ll need (phone with WhatsApp)
- Step-by-step preview: open WhatsApp -> Settings -> Linked Devices -> Link a Device
2. Provisioning (after Connect click, 0-15s)
Slice container is being created. Shows:
- “Starting WhatsApp Web” heading
- “This usually takes up to a minute”
- Animated progress bar
- Elapsed timer
- Time-based status messages:
- 0-20s: “Setting up your connection…”
- 20-45s: “Launching WhatsApp Web. Almost there.”
- 45-90s: “Still loading – this is normal.”
- 90s+: “Taking longer than usual. Please wait.”
- “Start Over” button appears at 90s
3. QR Code Display
QR code is showing, waiting for scan. Shows:
- QR code image (refreshes every ~20s)
- Countdown bar for current QR code
- “Code X of 3” indicator
- Warning: if not scanned within 3 minutes, need to start over
- Step-by-step scan instructions
4. QR Timeout
All 3 QR codes expired without scan. Shows:
- “Connection Timed Out” message
- Explanation that QR wasn’t scanned in time
- “Try Again” button -> destroys slice, returns to setup
- Slice is auto-destroyed by gateway
5. Authenticated / Loading Contacts
QR was scanned, WhatsApp is syncing. Shows:
- “Linked!” confirmation with green checkmark
- “Reading your contacts – this takes 1-3 minutes”
- Live contact counter: “Found: {N} contacts”
- Phase descriptions:
- “Scrolling through your contact list…”
- “Checking archived contacts…”
- “Saving contacts…”
- Elapsed timer
6. Ready
Contacts loaded, redirects to ChatPage automatically.
SSE Event Flow
The frontend receives real-time events via Server-Sent Events (SSE) from the gateway:
| Event | Data | Used For |
|---|---|---|
| wa:qr | { qr } | Display QR code |
| wa:qr_health | { status, sinceLastQr, browserAlive } | QR countdown, stale detection |
| wa:authenticated | {} | Phase transition to contact loading |
| wa:ready | {} | Client fully ready |
| wa:contact_discovery | { found } | Live contact counter |
| wa:contact_phase | { phase, found } | Phase description text |
| wa:loading_failed | { reason, message } | Failure handling |
| wa:error | { code, message } | QR timeout, other errors |
| wa:disconnected | {} | Connection lost |
SSE Gating
SSE connection is conditional on having a slice:
useSSE(enabled)– only creates EventSource whenenabled=trueConnectionContextpasses!!slicefrom SaasAuthContext as the enabled flag- When user has no slice: no SSE connection, default state shown
- After provisioning:
refreshAuth()updates slice -> SSE activates -> events flow reconnect()function forces EventSource re-creation when needed
Error Recovery
| Scenario | Handling |
|---|---|
| QR timeout (3 codes expire) | Slice destroyed, user sees timeout screen, “Try Again” restarts |
| Chrome crashes during setup | wa:loading_failed broadcast, slice destroyed |
| WhatsApp forces logout during sync | wa:loading_failed with reason=whatsapp_logout, slice destroyed |
| Network interruption | SSE reconnects automatically, slice stays alive |
| User closes browser during QR | Slice stays for health check cycle, destroyed if no SSE clients |
Frontend Files
| File | Change |
|---|---|
| SaasApp.tsx | Removed ProvisioningWait, users without slice go to App -> LoginPage |
| SaasAuthContext.tsx | Fixed needsPayment logic (slice=null doesn’t mean needs payment) |
| ConnectionContext.tsx | SSE gated on slice existence, connect() calls POST /api/connect |
| useSSE.ts | Added enabled parameter and reconnect() function |
| LoginPage.tsx | Full UX: provisioning screen, timer, QR counter, timeout, contact progress |
Status
Complete and deployed. Users see real-time feedback through the entire connection process.