# Unified "Get Started" Flow ## Overview The unified get-started flow provides a single entry point for customer account creation and eligibility checking. It replaces separate `/signup` and `/migrate` pages with a streamlined flow at `/auth/get-started`. ## User Flows ### 1. Direct Account Creation (`/auth/get-started`) ``` /auth/get-started │ ├─→ Step 1: Enter email │ ├─→ Step 2: Verify email (6-digit OTP) │ └─→ Step 3: System checks accounts & routes: │ ├─→ Portal exists → "Go to login" ├─→ WHMCS exists (unmapped) → "Link account" (enter WHMCS password) ├─→ SF exists (unmapped) → "Complete account" (pre-filled form) └─→ Nothing exists → "Create account" (full form) ``` ### 2. Eligibility Check First (`/services/internet/check-availability`) For customers who want to check internet availability before creating an account: ``` /services/internet (public) │ └─→ Click "Check Availability" │ └─→ /services/internet/check-availability (dedicated page) │ ├─→ Step 1: Enter name, email, address (with Japan ZIP lookup) │ └─→ Step 2: Choose action: │ ├─→ "Just Submit Request" (secondary action) │ └─→ SF Account + Opportunity (find/create) + Case created │ └─→ Case description notes if Opportunity was created or matched │ └─→ Success page shows "View Internet Plans" → /services/internet │ └─→ User can return later via SF email to create account │ └─→ "Create Account & Submit" (primary action) ├─→ Step 2a: OTP sent to email (inline on same page) ├─→ Step 2b: User verifies OTP ├─→ Step 2c: Complete account form (phone, DOB, password) ├─→ Creates SF Account + Opportunity + Case + WHMCS + Portal ├─→ Case description notes if Opportunity was created or matched └─→ Success page → Auto-redirect to /dashboard (5s countdown) ``` **Key design:** The entire eligibility check flow is self-contained on `/services/internet/check-availability`. There is no redirect to `/auth/get-started` - all steps (form, OTP, account creation, success) happen on the same page using internal step state. ## Account Status Detection The system checks accounts **in order** and returns the first match: ### Step 1: Portal User with ID Mapping Check if Portal user exists (by email) AND has an ID mapping. - **Found**: `PORTAL_EXISTS` → Redirect to login - **Not found**: Continue to step 2 ### Step 2: WHMCS Client (Billing Account) Check if WHMCS client exists (by email). - **Found**: `WHMCS_UNMAPPED` → "Link account" flow (enter WHMCS password to migrate) - **Not found**: Continue to step 3 _WHMCS clients are existing billing customers who haven't created a Portal account yet._ ### Step 3: Salesforce Account Only Check if SF Account exists (by email). - **Found**: `SF_UNMAPPED` → "Complete account" flow (pre-filled form, create WHMCS + Portal) - **Not found**: Continue to step 4 _SF-only accounts are customers who:_ - _Checked internet eligibility without creating an account_ - _Contacted us via email/phone and we created an SF record_ - _Were created through other CRM workflows_ ### Step 4: No Account Found - `NEW_CUSTOMER` → Full signup form ### Summary Table | Check Order | System Found | Status | User Flow | | ----------- | ----------------- | ---------------- | ----------------------------- | | 1 | Portal + Mapping | `portal_exists` | Go to login | | 2 | WHMCS (no portal) | `whmcs_unmapped` | Enter WHMCS password to link | | 3 | SF only | `sf_unmapped` | Complete account (pre-filled) | | 4 | Nothing | `new_customer` | Full signup form | ## Frontend Structure ``` apps/portal/src/features/get-started/ ├── api/get-started.api.ts # API client functions ├── stores/get-started.store.ts # Zustand state management ├── components/ │ ├── GetStartedForm/ │ │ ├── GetStartedForm.tsx # Main form container │ │ └── steps/ │ │ ├── EmailStep.tsx # Email input │ │ ├── VerificationStep.tsx # OTP verification │ │ ├── AccountStatusStep.tsx# Route based on status │ │ ├── CompleteAccountStep.tsx # Full signup form │ │ └── SuccessStep.tsx # Success confirmation │ └── OtpInput/OtpInput.tsx # 6-digit code input ├── views/GetStartedView.tsx # Page view └── index.ts # Public exports ``` ## Eligibility Check Page **Location:** `apps/portal/src/features/services/views/PublicEligibilityCheck.tsx` **Route:** `/services/internet/check-availability` **Store:** `apps/portal/src/features/services/stores/eligibility-check.store.ts` A dedicated page for guests to check internet availability. This approach provides: - Better mobile experience with proper form spacing - Clear user journey with bookmarkable URLs - Natural browser navigation (back button works) - Self-contained multi-step experience (no redirects to other pages) **Steps:** `form` → `otp` → `complete-account` → `success` **Path 1: "Just Submit Request"** (guest, no account): 1. Collects name, email, and address (with Japan ZIP code lookup) 2. Creates SF Account + Opportunity (find/create) + Eligibility Case 3. Shows success with "View Internet Plans" button **Path 2: "Create Account & Submit"** (full account creation): 1. Collects name, email, and address (with Japan ZIP code lookup) 2. Sends OTP, user verifies on same page 3. Collects account details (phone, DOB, password) 4. Creates SF Account + Opportunity + Case + WHMCS client + Portal user 5. Shows success with auto-redirect to dashboard (5s countdown) ## Backend Endpoints | Endpoint | Rate Limit | Purpose | | ------------------------------------------------ | ---------- | ------------------------------------------------------------------- | | `POST /auth/get-started/send-code` | 5/5min | Send OTP to email | | `POST /auth/get-started/verify-code` | 10/5min | Verify OTP, return account status | | `POST /auth/get-started/guest-eligibility` | 3/15min | Guest eligibility (no OTP, creates SF Account + Opportunity + Case) | | `POST /auth/get-started/complete-account` | 5/15min | Complete SF-only account | | `POST /auth/get-started/signup-with-eligibility` | 5/15min | Full signup with eligibility (OTP verified) | ## Domain Schemas Location: `packages/domain/get-started/` Key schemas: - `sendVerificationCodeRequestSchema` - email only - `verifyCodeRequestSchema` - email + 6-digit code - `guestEligibilityRequestSchema` - email, name, address (no OTP required) - `completeAccountRequestSchema` - sessionToken + password + profile fields - `signupWithEligibilityRequestSchema` - sessionToken + full account data - `accountStatusSchema` - `portal_exists | whmcs_unmapped | sf_unmapped | new_customer` ## OTP Security - **Storage**: Redis with key format `otp:{email}` - **TTL**: 10 minutes - **Max Attempts**: 3 per code - **Rate Limits**: 5 codes per 5 minutes ## Eligibility Check Flow Details ### Path 1: "Just Submit Request" (Guest Flow) When a user clicks "Just Submit Request": 1. Calls `guestEligibilityCheck` API with `continueToAccount: false` 2. Backend creates SF Account + Opportunity (find/create) + Eligibility Case 3. Frontend navigates to success step with `hasAccount: false` 4. Success page shows only "View Internet Plans" button 5. User can return later via SF email to create an account at `/auth/get-started` ### Path 2: "Create Account & Submit" (Full Account Creation) When a user clicks "Create Account & Submit": 1. **OTP Step**: Calls `sendVerificationCode` API → navigates to OTP step (same page) 2. **Verify OTP**: User enters code, calls `verifyCode` API → receives session token 3. **Complete Account**: Navigates to complete-account step (same page) 4. **Submit**: Calls `signupWithEligibility` API which creates: - SF Account (find or create) - Opportunity (find or create) - Eligibility Case - WHMCS client - Portal user 5. **Success**: Shows success with "Go to Dashboard" button + auto-redirect (5s) ### Guest Return Flow via SF Email SF can send "finish your account" emails with this link format: ``` https://portal.example.com/auth/get-started?email={Account.PersonEmail} ``` - User goes to `/auth/get-started` (not the eligibility check page) - Standard flow: Email (pre-filled) → OTP → Account Status → Complete - Backend detects `sf_unmapped` status and returns prefill data from existing SF Account ## Testing Checklist ### Manual Testing - Get Started Page (`/auth/get-started`) 1. **New customer flow**: Enter new email → Verify OTP → Full signup form 2. **SF-only flow**: Enter email with SF account → Verify → Pre-filled form (name, address pre-filled, add phone, DOB, password) 3. **WHMCS migration**: Enter email with WHMCS → Verify → Enter WHMCS password 4. **Return flow**: Customer with existing SF account returns, enters same email → Auto-links to SF account ### Manual Testing - Eligibility Check Page (`/services/internet/check-availability`) 5. **Eligibility check - Just Submit Request**: - Click "Check Availability" → Fill form → Click "Just Submit Request" - Verify success page shows only "View Internet Plans" button - Verify SF Account + Opportunity + Case are created 6. **Eligibility check - Create Account & Submit**: - Click "Check Availability" → Fill form → Click "Create Account & Submit" - Verify OTP step appears (same page, no redirect) - Complete OTP → Verify complete-account step appears (same page) - Fill account details → Submit - Verify success page with auto-redirect countdown to dashboard - Verify SF Account + Opportunity + Case + WHMCS + Portal user created 7. **Mobile experience**: Test eligibility check page on mobile viewport 8. **Browser back button**: After OTP success, press back → Verify graceful handling 9. **Existing account handling**: During OTP verification, if `portal_exists` or `whmcs_unmapped` status returned, verify appropriate error message ### Security Testing - Verify OTP expires after 10 minutes - Verify max 3 attempts per code - Verify rate limits on all endpoints - Verify email enumeration is prevented (same response until OTP verified) ## Routes | Route | Action | | --------------------------------------- | -------------------------------- | | `/auth/get-started` | Unified account creation page | | `/auth/signup` | Redirects to `/auth/get-started` | | `/auth/migrate` | Redirects to `/auth/get-started` | | `/services/internet/check-availability` | Guest eligibility check (public) | ## Environment Variables ```bash # OTP Configuration OTP_TTL_SECONDS=600 # 10 minutes OTP_MAX_ATTEMPTS=3 GET_STARTED_SESSION_TTL=3600 # 1 hour ```