# WhatsApp Mirror — Full-Stack Real-Time Bridge

A production-grade, highly-responsive WhatsApp Mirror application. This system allows you to remotely view and manage a WhatsApp account on a dark-themed Flutter mobile app (iOS + Android) by bridging commands and real-time events over a standalone WebSockets Node.js bridge server.

---

## 🏗️ Architecture

```
📱 Mobile Client (Flutter) ⚡ [WebSockets Protocol] ⚡ 🖥️ standalone Backend Server (Node.js) ⚙️ [Puppeteer] ⚙️ 🟩 WhatsApp Web (LocalAuth Session)
```

---

## 📂 Project Structure

```
whatsapp-app/
├── README.md               ← Full system configuration & documentation
├── whatsapp_bridge/        ← standalone Node.js server
│   ├── package.json        ← Package dependencies (whatsapp-web.js, ws, qrcode, express)
│   ├── server.js           ← Bridge server entrypoint (Port 3025)
│   └── .wwebjs_auth/       ← Session persistence auth cache (git-ignored)
└── whatsapp_app/           ← Dark-themed Flutter Client
    ├── pubspec.yaml        ← Flutter configuration and plugins
    └── lib/
        ├── main.dart       ← Flutter app entry point (GetX service initializer)
        ├── config/
        │   └── app_config.dart     ← Server host & port variables
        ├── theme/
        │   └── app_theme.dart      ← WhatsApp-style immersive Dark Theme
        ├── services/
        │   └── whatsapp_service.dart ← Websocket request/response manager
        ├── models/
        │   ├── conversation_model.dart
        │   └── message_model.dart
        ├── controllers/
        │   ├── conversations_controller.dart
        │   └── chat_controller.dart
        ├── screens/
        │   ├── conversations_screen.dart
        │   ├── chat_screen.dart
        │   └── qr_screen.dart
        └── widgets/
            ├── conversation_tile.dart
            └── message_bubble.dart
```

---

## ⚡ WebSockets Protocol Specification

To handle asynchronous requests and map them back to specific UI components or triggers, a strict **Request-Response ID matching mechanism** is implemented. 

### 1. Client-to-Server Requests
Every request from the Flutter client MUST contain a unique `requestId`. The server replies with the exact same `requestId`.

#### A. Ping Check (`ping`)
* **Request:**
  ```json
  { "type": "ping", "requestId": "1" }
  ```
* **Response:**
  ```json
  { "type": "pong", "ready": true, "requestId": "1" }
  ```

#### B. Get Conversation List (`get_conversations`)
* **Request:**
  ```json
  { "type": "get_conversations", "limit": 50, "offset": 0, "requestId": "2" }
  ```
* **Response:**
  ```json
  {
    "type": "conversations",
    "data": [
      {
        "id": "1234567890@c.us",
        "name": "Jane Doe",
        "isGroup": false,
        "unreadCount": 2,
        "avatar": "https://pps.whatsapp.net/v/...",
        "lastMessage": {
          "body": "Hello there!",
          "timestamp": 1716035000,
          "fromMe": false,
          "hasMedia": false
        },
        "timestamp": 1716035000,
        "pinned": false,
        "isMuted": false
      }
    ],
    "total": 1,
    "requestId": "2"
  }
  ```

#### C. Get Message History (`get_messages`)
* **Request:**
  ```json
  { "type": "get_messages", "chatId": "1234567890@c.us", "limit": 50, "requestId": "3" }
  ```
* **Response:**
  ```json
  {
    "type": "messages",
    "chatId": "1234567890@c.us",
    "data": [
      {
        "id": "true_1234567890@c.us_ABC123",
        "body": "Hello there!",
        "fromMe": false,
        "timestamp": 1716035000,
        "type": "chat",
        "hasMedia": false,
        "isForwarded": false,
        "author": null,
        "ack": 4
      }
    ],
    "requestId": "3"
  }
  ```

#### D. Send Message (`send_message`)
* **Request:**
  ```json
  { "type": "send_message", "chatId": "1234567890@c.us", "text": "Hello!", "requestId": "4" }
  ```
* **Response:**
  ```json
  {
    "type": "message_sent",
    "chatId": "1234567890@c.us",
    "data": {
      "id": "true_1234567890@c.us_XYZ987",
      "body": "Hello!",
      "fromMe": true,
      "timestamp": 1716035005,
      "type": "chat",
      "hasMedia": false,
      "isForwarded": false,
      "author": null,
      "ack": 1
    },
    "requestId": "4"
  }
  ```

#### E. Mark Chat as Read (`mark_read`)
* **Request:**
  ```json
  { "type": "mark_read", "chatId": "1234567890@c.us", "requestId": "5" }
  ```
* **Response:**
  ```json
  { "type": "marked_read", "chatId": "1234567890@c.us", "requestId": "5" }
  ```

#### F. Search Conversations (`search_conversations`)
* **Request:**
  ```json
  { "type": "search_conversations", "query": "Jane", "requestId": "6" }
  ```
* **Response:**
  ```json
  {
    "type": "conversations",
    "data": [...],
    "search": true,
    "requestId": "6"
  }
  ```

---

### 2. Server-to-Client Push Events
The server broadcasts live events to all connected clients immediately.

* **QR Code Broadcast:**
  ```json
  { "type": "qr", "qr": "data:image/png;base64,iVBORw0KGgo..." }
  ```
* **Authenticated:**
  ```json
  { "type": "authenticated" }
  ```
* **Client Ready:**
  ```json
  { "type": "ready" }
  ```
* **Status Updates:**
  ```json
  { "type": "status", "ready": true }
  ```
* **Client Disconnected:**
  ```json
  { "type": "disconnected", "reason": "Session expired or logged out" }
  ```
* **New Incoming Message:**
  ```json
  {
    "type": "new_message",
    "chatId": "1234567890@c.us",
    "data": {
      "id": "false_1234567890@c.us_DEF456",
      "body": "Live incoming text!",
      "fromMe": false,
      "timestamp": 1716035100,
      "type": "chat",
      "hasMedia": false,
      "isForwarded": false,
      "author": null,
      "ack": 2
    }
  }
  ```
* **Message Delivery / Read Receipt (`message_ack`):**
  ```json
  {
    "type": "message_ack",
    "messageId": "true_1234567890@c.us_XYZ987",
    "chatId": "1234567890@c.us",
    "ack": 4
  }
  ```
  *(Ack codes: 0 = Error/None, 1 = Pending, 2 = Sent, 3 = Delivered, 4 = Read)*

---

## 🚀 Quick Setup & Installation

### 1. Server Setup (`whatsapp_bridge/`)
Navigate into the backend project, install dependencies, and start the standalone service:

```bash
cd whatsapp_bridge
npm install
node server.js
```
The server will boot up and bind to **Port 3025**. It will automatically print:
`[SERVER] Standalone WhatsApp Bridge running on port 3025`

### 2. Flutter App Setup (`whatsapp_app/`)

First, ensure that you have created the Flutter project structure using standard platform templates:
```bash
# Run this inside the workspace directory
flutter create whatsapp_app
```
Then, copy all files in `whatsapp_app/` into the newly created project folder. Open the folder and install Dart packages:

```bash
cd whatsapp_app
flutter pub get
```

#### Run on Simulator / Device
```bash
flutter run
```

---

## 🌐 Production Deployment (CloudPanel Server)

Since this backend server acts as a standalone daemon and does not conflict with existing apps, it operates exclusively on **Port 3025**.

### 1. Create Node.js Site in CloudPanel
1. Navigate to **CloudPanel Admin Portal** -> **Sites** -> **Add Site** -> **Create a Node.js Application**.
2. Set Domain Name: `mywhatsappapp.interlap.com` (or your subdomain).
3. Set Port: `3025`.
4. Set Entry Point: `server.js`.
5. Select Node.js Version: `18+ LTS` (or Node 20 LTS).

### 2. Bypass Nginx Reverse Proxy
By default, CloudPanel routes external traffic from Port 80/443 through an Nginx reverse proxy. For our standalone WebSockets configuration, we want direct access.
Make sure to open **Port 3025** on your firewall (e.g. AWS Security Group or UFW):
```bash
sudo ufw allow 3025/tcp
```
This isolates Node.js directly on port 3025.

### 3. Keep Server Alive with PM2
We highly recommend running your Node.js application inside PM2 to ensure it auto-reconnects, logs diagnostic crashes, and recovers seamlessly:

```bash
# Install PM2 globally
npm install -g pm2

# Start the bridge server
pm2 start server.js --name "whatsapp-bridge"

# Persist server launch on reboot
pm2 save
pm2 startup
```

---

## 🔒 Security & Performance Features
* **Session Persistence:** Configured using `whatsapp-web.js`'s built-in `LocalAuth` session strategies, meaning that once you scan the QR code once, you will not have to scan it again unless explicitly logged out.
* **Resilience & Crash Prevention:** The server wraps critical events in structured `try/catch` clauses and binds events to `process.on('uncaughtException')`, protecting the server from unexpected Puppeteer execution crashes.
* **Auto-Reconnection:** If WhatsApp Web loses connection or the user logs out, the server attempts re-initialization automatically after a 5-second backoff delay.
* **Dark Mode Design:** Beautiful custom-tailored dark theme matching official WhatsApp guidelines (`#111B21`, `#1F2C34`, `#00A884`) with full custom ripple alerts, status badges, and tick indicators.
