Files
tabungin/WHATSAPP_OTP_IMPLEMENTATION.md
dwindown 249f3a9d7d feat: remove OTP gate from transactions, fix categories auth, add implementation plan
- Remove OtpGateGuard from transactions controller (OTP verified at login)
- Fix categories controller to use authenticated user instead of TEMP_USER_ID
- Add comprehensive implementation plan document
- Update .env.example with WEB_APP_URL
- Prepare for admin dashboard development
2025-10-11 14:00:11 +07:00

346 lines
8.4 KiB
Markdown

# 📱 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<boolean>
// 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.** 🚀