🛡️ SOS Motorista

Sistema de Emergência e Rastreamento para Motoristas

Produção Node.js 18+ PostgreSQL

📑 Índice Rápido

🏗️ Arquitetura do Sistema

🖥️
Servidor Principal
Porta 3002
📱
WhatsApp API
Porta 3003
🗄️
Banco de Dados
PostgreSQL 5432
📁
Uploads
/public/uploads

Componentes

Componente Descrição Tecnologia
sos-motorista Servidor principal da aplicação Node.js + Express
whatsapp-sos API de envio de mensagens WhatsApp whatsapp-web.js
PostgreSQL Banco de dados relacional PostgreSQL 14+
PM2 Gerenciador de processos PM2

📦 Instalação

Pré-requisitos

Verifique antes de instalar:
  • Node.js 18.0 ou superior
  • PostgreSQL 14.0 ou superior
  • PM2 instalado globalmente
  • Acesso root/sudo ao servidor

1. Instalar Dependências do Sistema

# Atualizar pacotes
apt update && apt upgrade -y

# Instalar Node.js (se não tiver)
curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
apt install -y nodejs

# Instalar PM2
npm install -g pm2

# Instalar dependências do projeto
cd /opt/sos-motorista
npm install express pg multer ejs qrcode whatsapp-web.js

2. Configurar Banco de Dados

# Acessar PostgreSQL
sudo -u postgres psql

# Criar usuário e banco (se necessário)
CREATE USER cesar_user WITH PASSWORD 'senha_forte_aqui';
CREATE DATABASE rastreament OWNER cesar_user;
\q

3. Iniciar Serviços com PM2

# Iniciar SOS Motorista
cd /opt/sos-motorista
pm2 start server.js --name sos-motorista

# Iniciar WhatsApp API
cd /opt/whatsapp-sos
pm2 start server.js --name whatsapp-sos

# Salvar configuração do PM2
pm2 save
pm2 startup

4. Verificar Status

# Listar todos os processos
pm2 list

# Ver logs em tempo real
pm2 logs --lines 20

# Monitorar recursos
pm2 monit

⚙️ Configuração

Server.js - SOS Motorista

Atenção: Altere as credenciais do banco de dados antes de produzir!
// Conexão PostgreSQL
const pool = new Pool({
  host: 'localhost',
  user: 'cesar_user',
  password: 'senha_forte_aqui',  // ← ALTERAR
  database: 'rastreament',
  port: 5432,
});

// URL da API WhatsApp
const WHATSAPP_API = 'http://204.157.124.220:3003/api/send';  // ← Verificar IP

// Porta do servidor
const PORT = 3002;

Server.js - WhatsApp SOS

// Porta da API WhatsApp
const PORT = 3003;

// Conexão PostgreSQL (mesma do SOS)
const pool = new Pool({
  host: 'localhost',
  user: 'cesar_user',
  password: 'senha_forte_aqui',
  database: 'rastreament',
  port: 5432,
});

// Configuração do Puppeteer (VPS)
puppeteer: {
  headless: 'new',
  args: [
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--disable-dev-shm-usage',
    '--disable-gpu'
  ]
}

🗄️ Estrutura do Banco de Dados

Tabela: dispositivos

Coluna Tipo Descrição
imei VARCHAR(50) Identificador único do dispositivo (PK)
nome_motorista VARCHAR(100) Nome completo do motorista
cidade VARCHAR(100) Cidade de atuação
foto_motorista_url TEXT URL da foto do motorista
foto_carro_url TEXT URL da foto do veículo
foto_placa_url TEXT URL da foto da placa
created_at TIMESTAMPTZ Data de cadastro
updated_at TIMESTAMPTZ Última atualização

Tabela: contatos_emergencia

Coluna Tipo Descrição
id SERIAL Identificador único (PK)
imei VARCHAR(50) Referência ao dispositivo (FK)
nome VARCHAR(100) Nome do contato de emergência
whatsapp VARCHAR(20) Número WhatsApp (formato: 55DD9XXXXXXXX)
created_at TIMESTAMPTZ Data de cadastro

Tabela: compartilhamentos

Coluna Tipo Descrição
token VARCHAR(50) Token único de emergência (PK)
imei VARCHAR(50) Referência ao dispositivo (FK)
expira_em TIMESTAMPTZ Data de expiração do link (24h)
created_at TIMESTAMPTZ Data de criação

Tabela: posicoes

Coluna Tipo Descrição
id SERIAL Identificador único (PK)
imei VARCHAR(50) Referência ao dispositivo (FK)
latitude DECIMAL(10,8) Latitude da posição
longitude DECIMAL(11,8) Longitude da posição
data_hora TIMESTAMPTZ Data e hora da posição

Tabela: mensagens_whatsapp

Coluna Tipo Descrição
id SERIAL Identificador único (PK)
remetente VARCHAR(50) Número de origem
destinatario VARCHAR(50) Número de destino
corpo TEXT Conteúdo da mensagem
tipo VARCHAR(20) 'enviada' ou 'recebida'
lida BOOLEAN Status de leitura
data_hora TIMESTAMPTZ Data e hora da mensagem

Script SQL de Criação

-- Tabela dispositivos
CREATE TABLE IF NOT EXISTS dispositivos (
  imei VARCHAR(50) PRIMARY KEY,
  nome_motorista VARCHAR(100),
  cidade VARCHAR(100),
  foto_motorista_url TEXT,
  foto_carro_url TEXT,
  foto_placa_url TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Tabela contatos_emergencia
CREATE TABLE IF NOT EXISTS contatos_emergencia (
  id SERIAL PRIMARY KEY,
  imei VARCHAR(50) NOT NULL REFERENCES dispositivos(imei) ON DELETE CASCADE,
  nome VARCHAR(100),
  whatsapp VARCHAR(20),
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Tabela compartilhamentos
CREATE TABLE IF NOT EXISTS compartilhamentos (
  token VARCHAR(50) PRIMARY KEY,
  imei VARCHAR(50) NOT NULL REFERENCES dispositivos(imei) ON DELETE CASCADE,
  expira_em TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Tabela posicoes
CREATE TABLE IF NOT EXISTS posicoes (
  id SERIAL PRIMARY KEY,
  imei VARCHAR(50) NOT NULL REFERENCES dispositivos(imei) ON DELETE CASCADE,
  latitude DECIMAL(10,8),
  longitude DECIMAL(11,8),
  data_hora TIMESTAMPTZ DEFAULT NOW()
);

-- Tabela mensagens_whatsapp
CREATE TABLE IF NOT EXISTS mensagens_whatsapp (
  id SERIAL PRIMARY KEY,
  remetente VARCHAR(50),
  destinatario VARCHAR(50),
  corpo TEXT,
  tipo VARCHAR(20),
  lida BOOLEAN DEFAULT false,
  data_hora TIMESTAMPTZ DEFAULT NOW()
);

-- Índices para performance
CREATE INDEX IF NOT EXISTS idx_contatos_imei ON contatos_emergencia(imei);
CREATE INDEX IF NOT EXISTS idx_posicoes_imei ON posicoes(imei);
CREATE INDEX IF NOT EXISTS idx_posicoes_data ON posicoes(data_hora DESC);
CREATE INDEX IF NOT EXISTS idx_compartilhamentos_token ON compartilhamentos(token);

🚨 API SOS Motorista

Base URL: http://204.157.124.220:3002

Ativar Emergência

POST /api/sos/:imei

Aciona o alerta de emergência e envia WhatsApp para todos os contatos cadastrados.

Parâmetros

Nome Tipo Local Descrição
imei String URL Path IMEI do dispositivo

Resposta de Sucesso

{
  "success": true,
  "link": "http://204.157.124.220:3002/emergencia/w3jbqqfn1",
  "token": "w3jbqqfn1"
}

Exemplo de Uso (cURL)

curl -X POST http://204.157.124.220:3002/api/sos/356938035643809

Última Posição

GET /api/ultima-posicao/:imei
// Resposta
{
  "latitude": -25.4284,
  "longitude": -49.2733,
  "data_hora": "15/01/2025 14:30:00"
}

Página de Emergência

GET /emergencia/:token

Página pública com localização do veículo em emergência. Válida por 24 horas.

📝 API Cadastro

Formulário de Cadastro

GET /cadastro/:imei

Exibe o formulário de cadastro/atualização de dados do motorista.

Salvar Cadastro

POST /api/cadastro/:imei

Salva dados do motorista, fotos e contatos de emergência.

Campos do Formulário

Campo Tipo Obrigatório Descrição
nome_motorista Text Sim Nome completo
cidade Text Sim Cidade de atuação
foto_motorista File Não Foto do rosto (image/*)
foto_carro File Não Foto do veículo
foto_placa File Não Foto da placa
contato1_nome Text Não Nome do contato 1
contato1_whatsapp Text Não* WhatsApp (55DD9XXXXXXXX)
contato2_* - Não Segundo contato
contato3_* - Não Terceiro contato

* Pelo menos 1 contato com WhatsApp é recomendado para funcionamento do SOS.

Formato do WhatsApp

✅ Correto: 554399496205 (55 + DDD + Número)
❌ Errado: 43999496205 (sem 55)
❌ Errado: 5543999496205 (com 9 extra indevido)
❌ Errado: +55 (43) 99949-6205 (com formatação)

📱 API WhatsApp

Base URL: http://204.157.124.220:3003

Status da Conexão

GET /api/status
// Resposta
{
  "connected": true,
  "qr": null
}

Enviar Mensagem

POST /api/send

Body da Requisição

{
  "to": "554399496205",
  "message": "🚨 EMERGÊNCIA! Veículo ativou SOS."
}

Resposta de Sucesso

{
  "success": true,
  "message": "Mensagem enviada"
}

Exemplo de Uso (cURL)

curl -X POST http://localhost:3003/api/send \
  -H "Content-Type: application/json" \
  -d '{
    "to": "554399496205",
    "message": "Teste de envio"
  }'

Health Check

GET /health
{
  "status": "ok",
  "service": "whatsapp-sos",
  "uptime": "3600.00s",
  "whatsapp": "connected",
  "timestamp": "2025-01-15T14:30:00.000Z"
}

Interface Web

GET /

Interface gráfica para escanear QR Code e monitorar status da conexão.

URL: http://204.157.124.220:3003/

🔄 Fluxo de Emergência

Sequência completa do acionamento SOS:
  1. 📱 Motorista aciona SOS (botão físico, app ou API)
  2. 🔐 Server gera token único válido por 24 horas
  3. 🗄️ Token salvo na tabela compartilhamentos
  4. 📞 Busca contatos na tabela contatos_emergencia
  5. 📱 Formata números para padrão internacional (55DD9XXXXXXXX)
  6. 📨 Envia WhatsApp para cada contato via API (porta 3003)
  7. 🔗 Retorna link de emergência para acompanhamento
  8. 📍 Contatos acessam link e veem localização em tempo real

Diagrama de Sequência

┌─────────────┐     ┌──────────────┐     ┌─────────────┐     ┌──────────────┐
│  Motorista  │     │  SOS Server  │     │  PostgreSQL │     │ WhatsApp API │
└──────┬──────┘     └──────┬───────┘     └──────┬──────┘     └──────┬───────┘
       │                   │                    │                   │
       │  1. Aciona SOS    │                    │                   │
       │──────────────────>│                    │                   │
       │                   │                    │                   │
       │                   │  2. Gera Token     │                   │
       │                   │───────────────────>│                   │
       │                   │                    │                   │
       │                   │  3. Busca Contatos │                   │
       │                   │───────────────────>│                   │
       │                   │<───────────────────│                   │
       │                   │                    │                   │
       │                   │  4. Envia Msg      │                   │
       │                   │───────────────────────────────────────>│
       │                   │                    │                   │
       │                   │  5. Retorna Link   │                   │
       │<──────────────────│                    │                   │
       │                   │                    │                   │
       │  6. Recebe WhatsApp                       7. Notificação   │
       │<──────────────────────────────────────────────────────────│
       │                   │                    │                   │

🔧 Solução de Problemas

WhatsApp não envia mensagens

Sintoma Causa Provável Solução
fetch failed API WhatsApp fora do ar pm2 restart whatsapp-sos
WhatsApp não está conectado QR Code não escaneado Acesse :3003 e escaneie
ECONNREFUSED Porta 3003 bloqueada Verifique firewall e lsof -i :3003
Mensagem não chega Número formatado errado Use formato: 55DD9XXXXXXXX

Servidor não inicia

# Ver logs de erro
pm2 logs sos-motorista --lines 50

# Verificar porta em uso
lsof -i :3002

# Matar processo travado
kill -9 $(lsof -t -i:3002)

# Reiniciar
pm2 restart sos-motorista

Erro de Banco de Dados

# Testar conexão
psql -U cesar_user -d rastreament -h localhost

# Ver tabelas
\dt

# Ver erros no log do PostgreSQL
tail -f /var/log/postgresql/postgresql-*.log

Comandos Úteis de Debug

# Status de todos os serviços
pm2 list

# Logs em tempo real
pm2 logs --lines 20

# Reiniciar tudo
pm2 restart all

# Limpar logs antigos
pm2 flush

# Monitorar recursos
pm2 monit

# Ver processo na porta
lsof -i :3002
lsof -i :3003

# Testar conexão WhatsApp
curl http://localhost:3003/health

# Testar envio manual
curl -X POST http://localhost:3003/api/send \
  -H "Content-Type: application/json" \
  -d '{"to":"554399496205","message":"Teste"}'

🔐 Segurança

Recomendações

  • ✅ Altere a senha do banco de dados em produção
  • ✅ Use HTTPS com certificado SSL (Let's Encrypt)
  • ✅ Configure firewall (UFW) para liberar apenas portas necessárias
  • ✅ Faça backup diário do banco de dados
  • ✅ Mantenha Node.js e dependências atualizadas
  • ✅ Use PM2 para reinício automático em caso de falha

Configurar Firewall (UFW)

# Habilitar UFW
ufw enable

# Liberar portas necessárias
ufw allow 22/tcp    # SSH
ufw allow 3002/tcp  # SOS Motorista
ufw allow 3003/tcp  # WhatsApp API

# Ver status
ufw status

Backup Automático

# Adicionar ao crontab (crontab -e)
0 3 * * * pg_dump -U cesar_user rastreament > /opt/backups/rastreament_$(date +\%Y\%m\%d).sql

# Restaurar backup
psql -U cesar_user -d rastreament < /opt/backups/rastreament_20250115.sql