🛡️ 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:
- 📱 Motorista aciona SOS (botão físico, app ou API)
- 🔐 Server gera token único válido por 24 horas
- 🗄️ Token salvo na tabela
compartilhamentos - 📞 Busca contatos na tabela
contatos_emergencia - 📱 Formata números para padrão internacional (55DD9XXXXXXXX)
- 📨 Envia WhatsApp para cada contato via API (porta 3003)
- 🔗 Retorna link de emergência para acompanhamento
- 📍 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