# 📱 WhatsApp OTP & Phone Number Implementation ## ✅ **Completed Features:** ### **1. Google Avatar Fix** ✅ - **Problem**: Avatar not loading for Google OAuth users - **Fix**: Always update avatar from Google profile (not just when null) - **File**: `apps/api/src/auth/auth.service.ts` ### **2. Phone Number Field** ✅ - Added `phone` field to User model - Unique constraint on phone number - Migration created and applied ### **3. WhatsApp OTP System** ✅ - Full WhatsApp OTP implementation with mode support - Check number validity - Send OTP (test/live modes) - Verify OTP - Enable/disable WhatsApp OTP --- ## 📊 **Database Changes:** ### **Schema Updates** (`schema.prisma`): ```prisma model User { // ... existing fields phone String? @unique otpEmailEnabled Boolean @default(false) otpWhatsappEnabled Boolean @default(false) otpTotpEnabled Boolean @default(false) otpTotpSecret String? } ``` ### **Migration**: - ✅ Migration created: `20251010132022_add_phone_and_whatsapp_otp` - ✅ Applied successfully - ✅ Prisma Client regenerated --- ## 🔧 **Backend Implementation:** ### **1. OTP Service** (`otp.service.ts`): #### **New Methods**: ```typescript // Send WhatsApp OTP async sendWhatsappOtp(userId: string, mode: 'test' | 'live' = 'test') // Verify WhatsApp OTP (for setup) async verifyWhatsappOtp(userId: string, code: string) // Verify WhatsApp OTP (for login) async verifyWhatsappOtpForLogin(userId: string, code: string): Promise // Disable WhatsApp OTP async disableWhatsappOtp(userId: string) // Check if number is registered on WhatsApp async checkWhatsappNumber(phone: string) ``` #### **Webhook Payload Structure**: **Email OTP**: ```json { "method": "email", "mode": "test", // or "live" "to": "user@example.com", "subject": "Tabungin - Your OTP Code", "message": "Your OTP code is: 123456...", "code": "123456" } ``` **WhatsApp OTP**: ```json { "method": "whatsapp", "mode": "test", // or "live" "phone": "+1234567890", "message": "Your Tabungin OTP code is: 123456...", "code": "123456" } ``` **Check WhatsApp Number**: ```json { "method": "whatsapp", "mode": "checknumber", "phone": "+1234567890" } ``` **Expected Response**: ```json { "isRegistered": true, "message": "Number is valid" } ``` --- ### **2. OTP Controller** (`otp.controller.ts`): #### **New Endpoints**: ```typescript // Send WhatsApp OTP (for setup in profile) POST /api/otp/whatsapp/send Body: { mode?: 'test' | 'live' } Auth: Required // Verify WhatsApp OTP (enable feature) POST /api/otp/whatsapp/verify Body: { code: string } Auth: Required // Disable WhatsApp OTP POST /api/otp/whatsapp/disable Auth: Required // Check if phone number is registered on WhatsApp POST /api/otp/whatsapp/check Body: { phone: string } Auth: Required ``` #### **Updated Endpoints**: ```typescript // Get OTP status (now includes phone and whatsappEnabled) GET /api/otp/status Response: { phone: string | null, emailEnabled: boolean, whatsappEnabled: boolean, totpEnabled: boolean, totpSecret?: string } ``` --- ### **3. Users Service** (`users.service.ts`): #### **New Methods**: ```typescript async updateProfile(userId: string, data: { name?: string; phone?: string }) ``` #### **Features**: - Update name - Update phone number - Unique phone validation - Error handling for duplicate phone --- ### **4. Users Controller** (`users.controller.ts`): #### **New Endpoints**: ```typescript // Update user profile PUT /api/users/profile Body: { name?: string, phone?: string } Auth: Required ``` --- ### **5. Auth Service** (`auth.service.ts`): #### **Updated Methods**: **Login Flow**: ```typescript async login(email: string, password: string) { // ... authentication // Check if OTP required const requiresOtp = user.otpEmailEnabled || user.otpWhatsappEnabled || user.otpTotpEnabled; if (requiresOtp) { // Send email OTP if enabled if (user.otpEmailEnabled) { await this.otpService.sendEmailOtp(user.id); } // Send WhatsApp OTP if enabled (LIVE mode) if (user.otpWhatsappEnabled) { await this.otpService.sendWhatsappOtp(user.id, 'live'); } return { requiresOtp: true, availableMethods: { email: user.otpEmailEnabled, whatsapp: user.otpWhatsappEnabled, totp: user.otpTotpEnabled, }, tempToken: this.generateTempToken(user.id, user.email), }; } } ``` **Google OAuth Flow**: - Same logic as login - Always updates avatar from Google - Sends WhatsApp OTP if enabled **OTP Verification**: ```typescript async verifyOtpAndLogin( tempToken: string, otpCode: string, method: 'email' | 'whatsapp' | 'totp' ) { // ... verify temp token if (method === 'whatsapp') { const isValid = await this.otpService.verifyWhatsappOtpForLogin( userId, otpCode ); if (!isValid) { throw new UnauthorizedException('Invalid WhatsApp OTP'); } } // ... generate full JWT } ``` --- ## 📝 **Mode Parameter Usage:** ### **Email OTP**: - **`mode: "test"`** - For setup in Profile page (logs to console) - **`mode: "live"`** - For login page (sends actual email) ### **WhatsApp OTP**: - **`mode: "checknumber"`** - Check if number is registered on WhatsApp - **`mode: "test"`** - For setup in Profile page (logs to console) - **`mode: "live"`** - For login page (sends actual WhatsApp message) --- ## 🔄 **Complete Flow:** ### **Setup WhatsApp OTP (Profile Page)**: 1. User enters phone number 2. Frontend calls `POST /api/users/profile` with `{ phone: "+1234567890" }` 3. Frontend calls `POST /api/otp/whatsapp/check` with `{ phone: "+1234567890" }` 4. If valid, frontend calls `POST /api/otp/whatsapp/send` with `{ mode: "test" }` 5. Backend sends OTP via webhook with `mode: "test"` 6. User enters OTP code 7. Frontend calls `POST /api/otp/whatsapp/verify` with `{ code: "123456" }` 8. WhatsApp OTP enabled! ### **Login with WhatsApp OTP**: 1. User logs in with email/password or Google 2. Backend detects `otpWhatsappEnabled: true` 3. Backend calls `sendWhatsappOtp(userId, 'live')` 4. Webhook receives request with `mode: "live"` 5. User receives WhatsApp message 6. User enters code on OTP page 7. Frontend calls `POST /api/auth/verify-otp` with `{ method: "whatsapp", code: "123456" }` 8. Login successful! --- ## 🎯 **Next Steps:** ### **Frontend Implementation** (TODO): 1. ✅ Update Profile page to include phone number field 2. ✅ Add WhatsApp OTP setup UI 3. ✅ Add phone number validation 4. ✅ Add "Check Number" button 5. ✅ Update OTP verification page to support WhatsApp 6. ✅ Restore original auth UI design from Git ### **n8n Webhook Configuration** (TODO): 1. Update webhook to handle `method: "whatsapp"` 2. Handle `mode: "checknumber"` - check if number is registered 3. Handle `mode: "test"` - log to console or test endpoint 4. Handle `mode: "live"` - send actual WhatsApp message 5. Return proper response format --- ## 📊 **API Summary:** | Endpoint | Method | Auth | Body | Purpose | |----------|--------|------|------|---------| | `/api/users/profile` | PUT | ✅ | `{ phone }` | Update phone | | `/api/otp/whatsapp/check` | POST | ✅ | `{ phone }` | Check number | | `/api/otp/whatsapp/send` | POST | ✅ | `{ mode }` | Send OTP | | `/api/otp/whatsapp/verify` | POST | ✅ | `{ code }` | Verify & enable | | `/api/otp/whatsapp/disable` | POST | ✅ | - | Disable | | `/api/otp/status` | GET | ✅ | - | Get status | | `/api/auth/verify-otp` | POST | - | `{ tempToken, code, method }` | Login verify | --- ## ✅ **Files Modified:** ### **Backend**: 1. `prisma/schema.prisma` - Added phone and otpWhatsappEnabled 2. `src/otp/otp.service.ts` - Added WhatsApp methods 3. `src/otp/otp.controller.ts` - Added WhatsApp endpoints 4. `src/users/users.service.ts` - Added updateProfile 5. `src/users/users.controller.ts` - Added PUT /profile 6. `src/auth/auth.service.ts` - Updated login/OAuth flows ### **Database**: 1. Migration: `20251010132022_add_phone_and_whatsapp_otp` --- ## 🎉 **Status:** ✅ **Backend Complete** - All WhatsApp OTP endpoints implemented ✅ **Database Updated** - Phone field and WhatsApp OTP flag added ✅ **Google Avatar Fixed** - Always updates from Google profile ⏳ **Frontend Pending** - Need to add UI components ⏳ **Auth UI Pending** - Need to restore original design from Git --- **Backend is ready for WhatsApp OTP! Frontend implementation next.** 🚀