# taxes-whatsapp-service

Servicio Node.js que envuelve `whatsapp-web.js` y expone una API REST consumida por Laravel (Taxes Software). Una sesión wwebjs por `ws_telefono`.

## Arquitectura

```
Laravel (PHP)                Node (este servicio)             WhatsApp Web
─────────────                ────────────────────             ─────────────
WhatsappWwebjsSender ──HTTP─→  POST /sessions/:id/send  ─→  client.sendMessage()
                                                                      │
InternalWhatsApp     ←─HTTP──  POST /internal/whatsapp/  ←─  client.on('message')
WwebjsController              wwebjs/event
```

- `:id` = `ws_telefonos_global.id` (id único cross-tenant). El Node no sabe de tenants, Laravel resuelve el tenant desde ese ID.
- Auth en ambos sentidos: header `X-Wwebjs-Token` con un secreto compartido en ambos `.env`.

## Endpoints

| Método | Path                         | Descripción |
|--------|------------------------------|-------------|
| GET    | `/health`                    | Ping (sin auth). |
| POST   | `/sessions/:id/start`        | Iniciar/retomar sesión. Devuelve `{status, qr}` |
| GET    | `/sessions/:id/status`       | `not_started | starting | qr_ready | ready | disconnected | auth_failed` |
| GET    | `/sessions/:id/qr`           | QR actual (base64 PNG) si `status=qr_ready` |
| POST   | `/sessions/:id/send`         | `{phone, message, attach_url?, attach_name?}` → `{message_id}` |
| POST   | `/sessions/:id/logout`       | Cierra sesión y borra LocalAuth. Requiere QR nuevo. |

## Setup local (Windows)

```powershell
cd whatsapp-service
copy .env.example .env
# editar .env: WWEBJS_TOKEN (random largo), CHROME_PATH apuntando al chrome.exe

# Instalar deps SIN bajar Chromium (~280MB que no necesitamos):
$env:PUPPETEER_SKIP_DOWNLOAD="true"
npm install --strict-ssl=false

# Levantar
npm start
```

Si tu proxy MITM corporativo rompe el handshake SSL: `npm install --strict-ssl=false` y considerar `NODE_TLS_REJECT_UNAUTHORIZED=0` solo en dev (NUNCA en prod).

## Setup producción (Linux)

```bash
cd /var/www/whatsapp-service
cp .env.example .env
vim .env   # WWEBJS_TOKEN, CHROME_PATH=/usr/bin/google-chrome, LARAVEL_WEBHOOK_URL=https://taxes.com.ar/...

PUPPETEER_SKIP_DOWNLOAD=true npm install --production
pm2 start ecosystem.config.js
pm2 save
pm2 startup
```

Sin Chrome en el sistema:
```bash
sudo apt install -y google-chrome-stable
```

## Persistencia

Las sesiones viven en `storage/.wwebjs_auth/session-{id}/`. **Sensibles**: contienen cookies de WhatsApp Web del cliente. NO commitear (`.gitignore` lo bloquea).

Si el server se reformatea, los clientes tienen que reescanear QR. Considerar backups encriptados de `storage/` si hace falta.

## Gotchas conocidos

Documentados en `.claude/memory/feedback_wwebjs_windows_gotchas.md` del repo Laravel. Resumen:

1. **Detached frame** en `sendMessage` → pin de versión WhatsApp Web + flags Chrome anti-isolation. **Aplicado en `sessionManager.js`.**
2. **Webhook IPv6 en Windows** → axios `family: 4`. **Aplicado en `webhook.js`.**
3. **LocalAuth corrupto al kill brusco** → graceful shutdown SIGTERM. **Aplicado en `index.js`.**
4. **Burst de históricos al ready** → filtros `fromMe`, grupos, pre-ready. **Aplicado en `sessionManager.js`.**

## Cómo se levanta una sesión nueva (flujo)

```
1. Usuario en Taxes → /whatsapp/configuracion → "Conectar wwebjs"
2. Laravel:   POST {NODE}/sessions/42/start         → {status:'starting', qr:null}
3. Node arranca sesión wwebjs id=42 (LocalAuth nuevo, espera QR)
4. wwebjs.on('qr', ...) → Node POSTea webhook {type:'session', status:'qr_ready', qr}
5. Frontend Vue hace polling a GET /sessions/42/status hasta status='qr_ready'
6. Frontend muestra el QR. Usuario escanea con celular.
7. wwebjs.on('ready', ...) → Node POSTea webhook {type:'session', status:'ready'}
8. Frontend cierra modal. Provider wwebjs operativo.
```

## Troubleshooting

```bash
# Ver logs
pm2 logs taxes-whatsapp

# Estado de sesiones (cuando esté ready)
curl -H "X-Wwebjs-Token: ..." http://localhost:3010/sessions/42/status

# Forzar logout (útil cuando se corrompió LocalAuth)
curl -X POST -H "X-Wwebjs-Token: ..." http://localhost:3010/sessions/42/logout
# Borra LocalAuth y obliga al usuario a reescanear QR.
```
