# WhatsApp Server Integration Plan

## Current State Analysis

### Existing Components

1. **WhatsApp Server** (Port 6101)
   - Location: `/home/ashraffarid2010/halavoice.store/whatsapp-server/`
   - Uses: Baileys library for WhatsApp Web API
   - Endpoints:
     - `POST /sessions/add` - Create session
     - `GET /sessions/:id/qr` - Get QR code
     - `GET /sessions/:id/status` - Get session status
     - `DELETE /sessions/:id` - Delete session
     - `GET /sessions/list` - List all sessions
   - Session Management: In-memory Map storage
   - Authentication: QR code based

2. **Database Schema** (Already Exists)
   - `whatsapp_sessions` - Session data with user mapping
   - `whatsapp_settings` - User preferences (AI model, auto-reply, etc.)
   - `whatsapp_chats` - Chat conversations
   - `whatsapp_messages` - Individual messages
   - `whatsapp_contacts` - Contact information
   - `whatsapp_audit_logs` - Activity logging
   - `whatsapp_agents` - AI agent assignments

3. **Current Issue**
   - Main server has mock WhatsApp routes
   - No integration with actual WhatsApp server
   - No database operations for WhatsApp data
   - No authentication/authorization for WhatsApp operations

## Integration Architecture

### Proposed Flow

```
┌─────────────────┐
│  Client (React)  │
│  /app/settings   │
└────────┬────────┘
         │ HTTP requests (with JWT auth)
         ▼
┌─────────────────────────────────┐
│   Main Server (agentlabs)        │
│   Port: 4000 (or configured)     │
│                                  │
│  ┌──────────────────────────┐   │
│  │  WhatsApp Routes Layer    │   │
│  │  - Authentication        │   │
│  │  - Authorization (user) │   │
│  │  - Validation            │   │
│  │  - Database operations   │   │
│  └───────────┬──────────────┘   │
└──────────────┼──────────────────┘
               │ HTTP proxy calls
               ▼
┌─────────────────────────────────┐
│   WhatsApp Server                │
│   Port: 6101                     │
│                                  │
│  ┌──────────────────────────┐   │
│  │  Baileys WhatsApp API     │   │
│  │  - Session Management    │   │
│  │  - QR Generation          │   │
│  │  - Message Handling      │   │
│  │  - Connection Status     │   │
│  └──────────────────────────┘   │
│                                  │
│  Sessions stored in:             │
│  /sessions/{sessionId}/         │
└─────────────────────────────────┘
```

## Implementation Plan

### Phase 1: Database Integration (Priority: HIGH)

#### 1.1 Add Drizzle Schema Definitions

File: `shared/schema.ts`

```typescript
// WhatsApp Sessions Table
export const whatsappSessions = pgTable("whatsapp_sessions", {
  id: varchar("id", { length: 255 }).primaryKey(),
  userId: varchar("user_id", { length: 255 }).notNull().references(() => users.id),
  tenantId: varchar("tenant_id", { length: 255 }),
  sessionId: varchar("session_id", { length: 255 }).notNull().unique(),
  sessionName: varchar("session_name", { length: 255 }).notNull(),
  phoneNumber: varchar("phone_number", { length: 50 }),
  status: varchar("status", { length: 50 }).notNull().default("connecting"),
  qrCode: text("qr_code"),
  authState: jsonb("auth_state"),
  lastActivity: timestamp("last_activity"),
  lastPing: timestamp("last_ping"),
  reconnectAttempts: integer("reconnect_attempts").default(0),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow(),
  updatedAt: timestamp("updated_at").defaultNow(),
});

// WhatsApp Settings Table
export const whatsappSettings = pgTable("whatsapp_settings", {
  id: varchar("id", { length: 255 }).primaryKey(),
  userId: varchar("user_id", { length: 255 }).notNull().references(() => users.id),
  tenantId: varchar("tenant_id", { length: 255 }),
  defaultAiModel: varchar("default_ai_model", { length: 100 }),
  defaultAiMode: varchar("default_ai_mode", { length: 50 }),
  autoReplyEnabled: boolean("auto_reply_enabled").default(false),
  autoReplyKeywords: text("auto_reply_keywords").array(),
  messageRetentionDays: integer("message_retention_days").default(30),
  enableNotifications: boolean("enable_notifications").default(true),
  notifyOnNewMessage: boolean("notify_on_new_message").default(true),
  notifyOnAiResponse: boolean("notify_on_ai_response").default(false),
  businessHoursEnabled: boolean("business_hours_enabled").default(false),
  businessHoursStart: time("business_hours_start"),
  businessHoursEnd: time("business_hours_end"),
  businessHoursTimezone: varchar("business_hours_timezone", { length: 100 }),
  businessDays: text("business_days").array(),
  maxReconnectAttempts: integer("max_reconnect_attempts").default(3),
  reconnectIntervalSeconds: integer("reconnect_interval_seconds").default(5),
  enableAiSuggestions: boolean("enable_ai_suggestions").default(false),
  suggestionConfidenceThreshold: numeric("suggestion_confidence_threshold"),
  enableHumanHandoff: boolean("enable_human_handoff").default(false),
  handoffKeywords: text("handoff_keywords").array(),
  defaultAgentId: varchar("default_agent_id", { length: 255 }),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow(),
  updatedAt: timestamp("updated_at").defaultNow(),
});

// WhatsApp Chats Table
export const whatsappChats = pgTable("whatsapp_chats", {
  id: varchar("id", { length: 255 }).primaryKey(),
  sessionId: varchar("session_id", { length: 255 }).notNull().references(() => whatsappSessions.sessionId),
  phoneNumber: varchar("phone_number", { length: 50 }).notNull(),
  contactName: varchar("contact_name", { length: 255 }),
  profilePicture: text("profile_picture"),
  unreadCount: integer("unread_count").default(0),
  lastMessageContent: text("last_message_content"),
  lastMessageTimestamp: timestamp("last_message_timestamp"),
  metadata: jsonb("metadata"),
  createdAt: timestamp("created_at").defaultNow(),
  updatedAt: timestamp("updated_at").defaultNow(),
});

// Type exports
export type WhatsAppSession = typeof whatsappSessions.$inferSelect;
export type WhatsAppSettings = typeof whatsappSettings.$inferSelect;
export type WhatsAppChat = typeof whatsappChats.$inferSelect;
```

### Phase 2: WhatsApp Service Layer (Priority: HIGH)

#### 2.1 Create WhatsApp Integration Service

File: `server/services/whatsapp-integration-service.ts`

```typescript
/**
 * WhatsApp Integration Service
 * 
 * Bridges the main server with the WhatsApp server on port 6101
 * Handles database operations and API proxying
 */

import axios from 'axios';
import { db } from '../db';
import { whatsappSessions, whatsappSettings, whatsappChats } from '@shared/schema';
import { eq, and, desc } from 'drizzle-orm';

const WHATSAPP_SERVER_URL = process.env.WHATSAPP_SERVER_URL || 'http://127.0.0.1:6101';

class WhatsAppIntegrationService {
  
  /**
   * Get user WhatsApp settings from database
   */
  async getUserSettings(userId: string) {
    const [settings] = await db
      .select()
      .from(whatsappSettings)
      .where(eq(whatsappSettings.userId, userId))
      .limit(1);
    
    if (!settings) {
      // Create default settings for user
      const newSettings = {
        id: `wa_settings_${userId}`,
        userId,
        autoReplyEnabled: false,
        defaultAiModel: 'gpt-4o',
        messageRetentionDays: 30,
        enableNotifications: true,
      };
      
      await db.insert(whatsappSettings).values(newSettings);
      return newSettings;
    }
    
    return settings;
  }

  /**
   * Update user WhatsApp settings
   */
  async updateUserSettings(userId: string, updates: Partial<typeof whatsappSettings.$inferInsert>) {
    await db
      .update(whatsappSettings)
      .set({ ...updates, updatedAt: new Date() })
      .where(eq(whatsappSettings.userId, userId));
    
    return this.getUserSettings(userId);
  }

  /**
   * Get user's WhatsApp sessions from database
   */
  async getUserSessions(userId: string) {
    const sessions = await db
      .select({
        id: whatsappSessions.id,
        sessionId: whatsappSessions.sessionId,
        sessionName: whatsappSessions.sessionName,
        phoneNumber: whatsappSessions.phoneNumber,
        status: whatsappSessions.status,
        lastActivity: whatsappSessions.lastActivity,
        createdAt: whatsappSessions.createdAt,
      })
      .from(whatsappSessions)
      .where(eq(whatsappSessions.userId, userId))
      .orderBy(desc(whatsappSessions.createdAt));
    
    return sessions;
  }

  /**
   * Create new WhatsApp session
   * 1. Generate unique session ID
   * 2. Store in database
   * 3. Call WhatsApp server to create session
   * 4. Return session info
   */
  async createSession(userId: string, sessionName: string) {
    const sessionId = `wa_${Date.now()}_${userId.slice(0, 8)}`;
    const id = `session_${sessionId}`;
    
    // Store in database first
    await db.insert(whatsappSessions).values({
      id,
      userId,
      sessionId,
      sessionName,
      status: 'connecting',
      reconnectAttempts: 0,
    });

    // Call WhatsApp server to create actual session
    try {
      const response = await axios.post(`${WHATSAPP_SERVER_URL}/sessions/add`, {
        id: sessionId,
        typeAuth: 'qr',
      });

      // Update database with WhatsApp server response
      await db
        .update(whatsappSessions)
        .set({ 
          status: response.data.data?.status || 'connecting',
          updatedAt: new Date(),
        })
        .where(eq(whatsappSessions.id, id));

      return {
        success: true,
        data: {
          session: {
            id,
            sessionId,
            sessionName,
            status: response.data.data?.status || 'connecting',
          },
        },
      };
    } catch (error) {
      // Update database status to failed
      await db
        .update(whatsappSessions)
        .set({ status: 'failed', updatedAt: new Date() })
        .where(eq(whatsappSessions.id, id));
      
      throw error;
    }
  }

  /**
   * Get QR code for session
   * Proxies request to WhatsApp server
   */
  async getSessionQR(sessionId: string, userId: string) {
    // Verify user owns this session
    const [session] = await db
      .select()
      .from(whatsappSessions)
      .where(
        and(
          eq(whatsappSessions.sessionId, sessionId),
          eq(whatsappSessions.userId, userId)
        )
      )
      .limit(1);

    if (!session) {
      throw new Error('Session not found or unauthorized');
    }

    // Call WhatsApp server
    const response = await axios.get(`${WHATSAPP_SERVER_URL}/sessions/${sessionId}/qr`);
    
    // Update database if QR received
    if (response.data.data?.qr) {
      await db
        .update(whatsappSessions)
        .set({ 
          qrCode: response.data.data.qr,
          status: response.data.data.status || 'connecting',
          updatedAt: new Date(),
        })
        .where(eq(whatsappSessions.sessionId, sessionId));
    }

    return response.data;
  }

  /**
   * Get session status
   * Proxies request to WhatsApp server
   */
  async getSessionStatus(sessionId: string, userId: string) {
    // Verify user owns this session
    const [session] = await db
      .select()
      .from(whatsappSessions)
      .where(
        and(
          eq(whatsappSessions.sessionId, sessionId),
          eq(whatsappSessions.userId, userId)
        )
      )
      .limit(1);

    if (!session) {
      throw new Error('Session not found or unauthorized');
    }

    // Call WhatsApp server
    try {
      const response = await axios.get(`${WHATSAPP_SERVER_URL}/sessions/${sessionId}/status`);
      
      // Update database with latest status
      await db
        .update(whatsappSessions)
        .set({ 
          status: response.data.data?.status || session.status,
          lastActivity: new Date(),
          updatedAt: new Date(),
        })
        .where(eq(whatsappSessions.sessionId, sessionId));

      return response.data;
    } catch (error) {
      // If WhatsApp server is down, return database status
      return {
        success: true,
        data: {
          id: sessionId,
          status: session.status,
          lastActivity: session.lastActivity,
        },
      };
    }
  }

  /**
   * Delete WhatsApp session
   * 1. Verify ownership
   * 2. Call WhatsApp server to delete
   * 3. Update database
   */
  async deleteSession(sessionId: string, userId: string) {
    // Verify user owns this session
    const [session] = await db
      .select()
      .from(whatsappSessions)
      .where(
        and(
          eq(whatsappSessions.sessionId, sessionId),
          eq(whatsappSessions.userId, userId)
        )
      )
      .limit(1);

    if (!session) {
      throw new Error('Session not found or unauthorized');
    }

    // Call WhatsApp server to delete
    try {
      await axios.delete(`${WHATSAPP_SERVER_URL}/sessions/${sessionId}`);
    } catch (error) {
      console.error('[WhatsApp Service] Failed to delete from WhatsApp server:', error);
    }

    // Update database status
    await db
      .update(whatsappSessions)
      .set({ 
        status: 'deleted',
        updatedAt: new Date(),
      })
      .where(eq(whatsappSessions.sessionId, sessionId));

    return {
      success: true,
      message: 'Session deleted successfully',
    };
  }

  /**
   * Get user's chats
   */
  async getUserChats(userId: string) {
    const userSessions = await this.getUserSessions(userId);
    
    if (userSessions.length === 0) {
      return [];
    }

    const sessionIds = userSessions.map(s => s.sessionId);
    
    const chats = await db
      .select()
      .from(whatsappChats)
      .where(
        // @ts-ignore - Array comparison
        eq(whatsappChats.sessionId, sessionIds[0]) // Simplified for now
      )
      .orderBy(desc(whatsappChats.lastMessageTimestamp));

    return chats;
  }
}

export const whatsappIntegrationService = new WhatsAppIntegrationService();
```

### Phase 3: Update Routes (Priority: HIGH)

#### 3.1 Rewrite WhatsApp Routes

File: `server/routes/whatsapp-routes.ts`

```typescript
'use strict';

import { Router } from "express";
import { authenticateToken, type AuthRequest } from "../middleware/auth";
import { whatsappIntegrationService } from "../services/whatsapp-integration-service";

export function whatsappRoutes(): Router {
  const router = Router();

  /**
   * GET /api/whatsapp/settings
   * Get WhatsApp settings for the current user
   */
  router.get("/settings", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const settings = await whatsappIntegrationService.getUserSettings(req.userId!);
      res.json(settings);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error fetching settings:", error);
      res.status(500).json({ error: "Failed to fetch settings" });
    }
  });

  /**
   * PATCH /api/whatsapp/settings
   * Update WhatsApp settings for the current user
   */
  router.patch("/settings", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const settings = await whatsappIntegrationService.updateUserSettings(req.userId!, req.body);
      res.json({
        success: true,
        message: "Settings updated successfully",
        data: settings,
      });
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error updating settings:", error);
      res.status(500).json({ error: "Failed to update settings" });
    }
  });

  /**
   * GET /api/whatsapp/sessions
   * Get all WhatsApp sessions for the current user
   */
  router.get("/sessions", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const sessions = await whatsappIntegrationService.getUserSessions(req.userId!);
      res.json(sessions);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error fetching sessions:", error);
      res.status(500).json({ error: "Failed to fetch sessions" });
    }
  });

  /**
   * POST /api/whatsapp/sessions
   * Create a new WhatsApp session
   */
  router.post("/sessions", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const { sessionName } = req.body;
      
      if (!sessionName) {
        return res.status(400).json({ error: "Session name is required" });
      }

      const result = await whatsappIntegrationService.createSession(req.userId!, sessionName);
      res.json(result);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error creating session:", error);
      res.status(500).json({ error: "Failed to create session" });
    }
  });

  /**
   * GET /api/whatsapp/sessions/:id/qr
   * Get QR code for a WhatsApp session
   */
  router.get("/sessions/:id/qr", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const { id } = req.params;
      const result = await whatsappIntegrationService.getSessionQR(id, req.userId!);
      res.json(result);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error fetching QR:", error);
      if (error.message === 'Session not found or unauthorized') {
        res.status(404).json({ error: "Session not found" });
      } else {
        res.status(500).json({ error: "Failed to fetch QR code" });
      }
    }
  });

  /**
   * DELETE /api/whatsapp/sessions/:id
   * Delete a WhatsApp session
   */
  router.delete("/sessions/:id", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const { id } = req.params;
      const result = await whatsappIntegrationService.deleteSession(id, req.userId!);
      res.json(result);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error deleting session:", error);
      if (error.message === 'Session not found or unauthorized') {
        res.status(404).json({ error: "Session not found" });
      } else {
        res.status(500).json({ error: "Failed to delete session" });
      }
    }
  });

  /**
   * GET /api/whatsapp/chats
   * Get all WhatsApp chats for the current user
   */
  router.get("/chats", authenticateToken as any, async (req: AuthRequest, res: any) => {
    try {
      const chats = await whatsappIntegrationService.getUserChats(req.userId!);
      res.json(chats);
    } catch (error: any) {
      console.error("[WhatsApp Routes] Error fetching chats:", error);
      res.status(500).json({ error: "Failed to fetch chats" });
    }
  });

  return router;
}
```

### Phase 4: WhatsApp Server Enhancements (Priority: MEDIUM)

#### 4.1 Add User Association to WhatsApp Server

Update WhatsApp server to store user ID with session and support user filtering.

### Phase 5: Error Handling & Monitoring (Priority: MEDIUM)

#### 5.1 Add Health Check Endpoint

```typescript
router.get("/health", async (req, res) => {
  try {
    // Check WhatsApp server availability
    const wsHealth = await axios.get(`${WHATSAPP_SERVER_URL}/`, { timeout: 5000 });
    
    res.json({
      status: 'healthy',
      whatsappServer: 'connected',
      timestamp: new Date().toISOString(),
    });
  } catch (error) {
    res.status(503).json({
      status: 'degraded',
      whatsappServer: 'disconnected',
      timestamp: new Date().toISOString(),
    });
  }
});
```

## Implementation Order

1. **Step 1**: Add Drizzle schema definitions (30 min)
2. **Step 2**: Create WhatsApp integration service (1 hour)
3. **Step 3**: Update WhatsApp routes (30 min)
4. **Step 4**: Test basic operations (create session, get QR, delete)
5. **Step 5**: Add error handling and health checks (30 min)
6. **Step 6**: Test with real WhatsApp connection (30 min)

**Total Estimated Time**: 3-4 hours

## Testing Checklist

- [ ] User can view WhatsApp settings
- [ ] User can update WhatsApp settings
- [ ] User can create new WhatsApp session
- [ ] QR code generation works
- [ ] Session status updates correctly
- [ ] Session deletion works
- [ ] User can only access their own sessions
- [ ] WhatsApp server communication works
- [ ] Error handling for WhatsApp server downtime
- [ ] Health check endpoint works

## Future Enhancements

1. **Real-time Updates**: WebSocket for live QR status updates
2. **Message History**: Store and display message history
3. **Auto-Reply**: Configure AI auto-responses
4. **Business Hours**: Set availability hours
5. **Multiple Sessions**: Support for multiple WhatsApp accounts per user
6. **Analytics**: Usage statistics and reporting