- 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
346 lines
8.4 KiB
Markdown
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.** 🚀
|