# 🔔 Configuração: Sistema Híbrido de Notificações (Socket.io + FCM)

## 📋 Resumo

Sistema híbrido implementado que usa **Socket.io** (tempo real) + **FCM** (push notification) para garantir que notificações sejam entregues mesmo quando o app está fechado.

---

## ✅ Implementação Completa

### **1. Sistema Híbrido:**
- ✅ **Socket.io** quando app está **aberto** (tempo real)
- ✅ **FCM** quando app está **fechado** (push notification)
- ✅ **Fallback automático** (tenta Socket.io primeiro, se falhar usa FCM)

### **2. Componentes Criados:**
- ✅ `models/FCMTokensModel.js` - Gerenciar tokens FCM
- ✅ `utils/fcmService.js` - Serviço FCM
- ✅ `controllers/fcmController.js` - Controller para gerenciar tokens
- ✅ `routes/fcmRoutes.js` - Rotas da API
- ✅ `create-fcm-tokens-table.js` - Script para criar tabela
- ✅ Tabela `fcm_tokens` no banco de dados

### **3. Modificações:**
- ✅ `utils/notificationUtils.js` - Atualizado para sistema híbrido
- ✅ `controllers/purchaseController.js` - Atualizado para usar sistema híbrido
- ✅ `app.js` - Rotas FCM adicionadas, inicialização FCM

---

## 🔧 Configuração do Firebase (FCM)

### **1. Criar Projeto Firebase:**

1. Acesse [Firebase Console](https://console.firebase.google.com/)
2. Crie um novo projeto ou use um existente
3. Vá em **Project Settings** > **Service Accounts**
4. Clique em **Generate New Private Key**
5. Baixe o arquivo JSON (service account key)

### **2. Configurar Backend:**

**Opção A: Usar arquivo JSON (Recomendado)**

1. Coloque o arquivo JSON em um local seguro (ex: `config/firebase-service-account.json`)
2. Adicione ao `.env`:
   ```env
   FCM_SERVICE_ACCOUNT_PATH=./config/firebase-service-account.json
   ```

**Opção B: Usar JSON como string (Variável de ambiente)**

1. Converte o JSON para string (remover quebras de linha)
2. Adicione ao `.env`:
   ```env
   FCM_SERVICE_ACCOUNT_JSON={"type":"service_account","project_id":"...","private_key_id":"...","private_key":"...","client_email":"...","client_id":"...","auth_uri":"...","token_uri":"...","auth_provider_x509_cert_url":"...","client_x509_cert_url":"..."}
   ```

### **3. Adicionar ao .gitignore:**

```gitignore
# Firebase
config/firebase-service-account.json
*.json
!package.json
!package-lock.json
```

⚠️ **IMPORTANTE:** Nunca commite o arquivo JSON do Firebase!

---

## 📱 Configuração do Frontend

### **1. Instalar Firebase SDK:**

```bash
npm install firebase
# ou
yarn add firebase
```

### **2. Inicializar Firebase no Frontend:**

```javascript
// firebase.js
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_PROJECT_ID.appspot.com",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID"
};

const app = initializeApp(firebaseConfig);
export const messaging = getMessaging(app);

// Solicitar permissão e obter token
export async function requestNotificationPermission() {
  try {
    const token = await getToken(messaging, {
      vapidKey: 'YOUR_VAPID_KEY' // VAPID key do Firebase
    });
    
    if (token) {
      console.log('Token FCM:', token);
      // Enviar token para o backend
      await registerFCMToken(token);
      return token;
    } else {
      console.log('Sem permissão para notificações');
      return null;
    }
  } catch (error) {
    console.error('Erro ao obter token FCM:', error);
    return null;
  }
}

// Escutar mensagens quando app está aberto
export function onMessageListener() {
  return new Promise((resolve) => {
    onMessage(messaging, (payload) => {
      resolve(payload);
    });
  });
}

// Registrar token no backend
async function registerFCMToken(token) {
  try {
    const response = await fetch('/api/fcm/register', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${userToken}`
      },
      body: JSON.stringify({
        fcmToken: token,
        deviceId: getDeviceId(), // ID único do dispositivo
        platform: getPlatform(), // 'web', 'android', 'ios'
        appVersion: getAppVersion() // Versão do app
      })
    });
    
    const data = await response.json();
    console.log('Token FCM registrado:', data);
  } catch (error) {
    console.error('Erro ao registrar token FCM:', error);
  }
}
```

### **3. Usar no App:**

```javascript
// App.js ou index.js
import { requestNotificationPermission, onMessageListener } from './firebase';

// Ao iniciar o app
useEffect(() => {
  // Solicitar permissão e registrar token
  requestNotificationPermission();
  
  // Escutar mensagens quando app está aberto
  onMessageListener()
    .then((payload) => {
      console.log('Notificação recebida:', payload);
      // Exibir notificação
      showNotification(payload);
    })
    .catch((error) => {
      console.error('Erro ao escutar mensagens:', error);
    });
}, []);
```

---

## 🔄 Como Funciona o Sistema Híbrido

### **Fluxo de Notificação:**

```
1. Admin aprova compra
   POST /api/purchases/:id/confirm
   ↓
2. Sistema tenta Socket.io primeiro (tempo real)
   ✅ Se cliente está conectado → Envia via Socket.io → FIM
   ❌ Se cliente não está conectado → Continua
   ↓
3. Sistema tenta FCM (push notification)
   ✅ Se cliente tem token FCM → Envia push → FIM
   ❌ Se cliente não tem token → Falha
   ↓
4. Logs registram resultado
```

### **Resultado:**

```javascript
{
  socketIO: {
    sent: true/false,
    error: null/'mensagem de erro'
  },
  fcm: {
    sent: true/false,
    error: null/'mensagem de erro',
    successCount: 2, // Número de dispositivos que receberam
    failureCount: 0
  }
}
```

---

## 📊 Endpoints da API

### **1. Registrar Token FCM:**
```
POST /api/fcm/register
Authorization: Bearer TOKEN
Content-Type: application/json

{
  "fcmToken": "token_fcm_do_dispositivo",
  "deviceId": "device_unique_id",
  "platform": "web|android|ios",
  "appVersion": "1.0.0"
}
```

### **2. Listar Tokens do Usuário:**
```
GET /api/fcm/tokens
Authorization: Bearer TOKEN
```

### **3. Remover Token:**
```
DELETE /api/fcm/tokens/:token
Authorization: Bearer TOKEN
```

### **4. Desativar Token:**
```
POST /api/fcm/tokens/:token/deactivate
Authorization: Bearer TOKEN
```

### **5. Testar Notificação (Apenas Desenvolvimento):**
```
POST /api/fcm/test
Authorization: Bearer TOKEN
```

---

## ✅ Benefícios do Sistema Híbrido

### **1. Cobertura Completa:**
- ✅ **App Aberto:** Socket.io (tempo real, baixa latência)
- ✅ **App Fechado:** FCM (push notification)

### **2. Fallback Automático:**
- ✅ Se Socket.io falhar, usa FCM automaticamente
- ✅ Se FCM não estiver configurado, ainda funciona com Socket.io

### **3. Múltiplos Dispositivos:**
- ✅ Um usuário pode ter múltiplos tokens (celular, tablet, web)
- ✅ Notificação é enviada para todos os dispositivos registrados

### **4. Flexibilidade:**
- ✅ FCM é opcional (sistema funciona só com Socket.io)
- ✅ Pode configurar FCM depois sem quebrar nada

---

## 🔍 Testando

### **1. Sem FCM Configurado:**
```bash
# Sistema funciona apenas com Socket.io
✅ Notificações via Socket.io (quando app aberto)
⚠️ Notificações perdidas (quando app fechado)
```

### **2. Com FCM Configurado:**
```bash
# Sistema funciona com Socket.io + FCM
✅ Notificações via Socket.io (quando app aberto)
✅ Notificações via FCM (quando app fechado)
```

### **3. Testar Notificação:**
```bash
POST /api/fcm/test
Authorization: Bearer USER_TOKEN
```

---

## ⚠️ IMPORTANTE: FCM é OBRIGATÓRIO!

### **1. FCM OBRIGATÓRIO:**
- ⚠️ **FCM é OBRIGATÓRIO** para notificações push funcionarem corretamente
- A maioria das notificações será quando app está **fechado/offline**
- Sem FCM configurado, notificações serão **perdidas** quando app estiver fechado
- Socket.io só funciona quando app está **aberto e conectado**

### **2. Tokens FCM:**
- Cliente precisa registrar token FCM no backend
- Token precisa ser atualizado se app for reinstalado

### **3. Permissões:**
- Cliente precisa dar permissão para notificações push
- iOS precisa de permissão explícita

---

## 📝 Resumo

1. ✅ **Sistema Híbrido** implementado (Socket.io + FCM)
2. ✅ **Fallback automático** (tenta Socket.io primeiro, depois FCM)
3. ⚠️ **FCM OBRIGATÓRIO** - Configure FCM para notificações push funcionarem
4. ✅ **Endpoints** para gerenciar tokens FCM
5. ✅ **Múltiplos dispositivos** suportados

⚠️ **IMPORTANTE:** Configure Firebase (FCM) para garantir que notificações sejam entregues quando app estiver fechado! 🚀

---

## 🔗 Referências

- [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging)
- [Firebase Admin SDK](https://firebase.google.com/docs/admin/setup)
- [Socket.io](https://socket.io/docs/v4/)

