- Marcador logo após o prefixo s-/p-: "a" => Aéreo (sufixo " - Aéreo"), "r" => Rádio (sufixo " - Rádio"). Mantém "sub" => "(Subterrâneo) ...". - Ex.: "S-A-ABC" => "Sothis - Aéreo"; "P-R-Vivo" => "Vivo - Rádio". - Testes de classificarSigla e README atualizados. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
507 lines
18 KiB
Markdown
507 lines
18 KiB
Markdown
# Sothis Contratação API
|
|
|
|
## Visão Geral
|
|
|
|
A **Sothis Contratação API** é uma solução robusta para automatizar e facilitar o processo de novas contratações. A aplicação gerencia consultas de viabilidade técnica e a criação de prospectos de clientes no sistema integrado Hubsoft.
|
|
|
|
### Funcionalidades Principais
|
|
|
|
1. **Consulta de Viabilidade por CEP e Número**: Verifica a viabilidade técnica de um endereço e retorna informações sobre disponibilidade de serviços (dedicado e não-dedicado) com base na proximidade de pontos de presença.
|
|
2. **Consulta de Viabilidade por Coordenadas**: Consulta viabilidade usando latitude e longitude com reverse geocoding.
|
|
3. **Criação de Prospectos**: Registra novos clientes (Pessoa Física ou Jurídica) no sistema de gestão Hubsoft com suporte a diferentes planos de banda larga.
|
|
|
|
## Features Técnicas
|
|
|
|
- **Express.js 5.1**: Framework web moderno para construção de APIs RESTful.
|
|
- **Arquitetura Modular**: Estrutura baseada em MVC com separação clara entre Controller, Service, Repository e Model.
|
|
- **Integração com Múltiplas APIs**:
|
|
- **Google Maps Geocoding**: Para geocodificação e reverse geocoding de endereços.
|
|
- **GeoGrid API**: Consulta de pontos de presença e viabilidade técnica.
|
|
- **Hubsoft API**: Gestão de prospectos e clientes.
|
|
- **CEP Validation**: Integração com `cep-promise` para validação e busca de endereços brasileiros.
|
|
- **Logging Avançado**: Sistema de logging estruturado com `winston` e arquivo rotativo diário.
|
|
- **Configuração por Ambiente**: Suporte a múltiplos ambientes (desenvolvimento/produção) via `dotenv`.
|
|
- **CORS Configurado**: Habilitado para domínios específicos (`sothis.com.br` e `bandalarga.srv.br`).
|
|
- **PostgreSQL Ready**: Preparado para persistência de dados com `pg`.
|
|
- **Desenvolvimento Otimizado**: Hot-reload automático com `nodemon`.
|
|
|
|
## Pré-requisitos
|
|
|
|
- Node.js (versão 18.x ou superior recomendada)
|
|
- npm (geralmente instalado junto com o Node.js)
|
|
- PostgreSQL (opcional, para persistência de dados)
|
|
- Chaves de API: Google Maps, GeoGrid, Hubsoft
|
|
|
|
## 1. Instalação
|
|
|
|
Clone o repositório e instale as dependências:
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
## 2. Configuração
|
|
|
|
A aplicação utiliza arquivos `.env` para carregar suas configurações. Você precisará criar dois arquivos na raiz do projeto:
|
|
|
|
- `.env.development` (para ambiente de desenvolvimento)
|
|
- `.env.production` (para ambiente de produção)
|
|
|
|
### Variáveis de Ambiente Obrigatórias
|
|
|
|
```env
|
|
# Servidor
|
|
PORT=3000
|
|
NODE_ENV=development
|
|
|
|
# Google Maps Geocoding API (para geocodificação e reverse geocoding)
|
|
GOOGLE_API_KEY=sua_chave_google_maps_aqui
|
|
|
|
# GeoGrid API (para consulta de viabilidade técnica)
|
|
GEOGRID_API_URL=https://.../viabilidade/raio # URL COMPLETA da consulta por raio
|
|
GEOGRID_API_KEY=sua_chave_geogrid_aqui
|
|
GEOGRID_API_COOKIE=seu_cookie_geogrid_aqui
|
|
|
|
# Distância REAL de trajeto (opcionais — têm defaults seguros)
|
|
GEOGRID_API_BASE_URL=https://.../vale/api/v3 # base p/ o endpoint de trajeto; se ausente, derivada da URL de consulta
|
|
GEOGRID_TRAJETO_MODO=walking # modo do trajeto
|
|
GEOGRID_TRAJETO_TOP_N=3 # nº de caixas roteadas na consulta individual (precisão)
|
|
GEOGRID_TRAJETO_TOP_N_LOTE=2 # nº de caixas roteadas por item no lote (a planilha mostra 2 caixas)
|
|
GEOGRID_CONCURRENCY=5 # chamadas externas simultâneas no lote
|
|
|
|
# Hubsoft API (para gestão de prospectos)
|
|
HUBSOFT_URL=https://seu-dominio.hubsoft.com.br
|
|
HUBSOFT_CLIENT_ID=seu_client_id_hubsoft
|
|
HUBSOFT_CLIENT_SECRET=seu_client_secret_hubsoft
|
|
HUBSOFT_USERNAME=seu_usuario_hubsoft
|
|
HUBSOFT_PASSWORD=sua_senha_hubsoft
|
|
HUBSOFT_GRANT_TYPE=password
|
|
|
|
# Database PostgreSQL (opcional, para persistência de viabilidades)
|
|
DB_HOST=localhost
|
|
DB_PORT=5432
|
|
DB_USER=seu_usuario_postgres
|
|
DB_PASSWORD=sua_senha_postgres
|
|
DB_NAME=contratacao_db
|
|
```
|
|
|
|
### Classificação de Pastas (provedor)
|
|
|
|
O provedor é resolvido pelo **prefixo da sigla da pasta** no GeoGrid (não há configuração no `.env`):
|
|
|
|
- `s-...` → **Sothis** (rede própria).
|
|
- `p-<nome>...` → **parceiro**; o provedor é o nome que vem depois do `-` (ex.: `p-Vivo` → `Vivo`).
|
|
- **Meio de transmissão** (marcador logo após o prefixo):
|
|
- `sub` → rede **subterrânea**, prefixa `(Subterrâneo)` (ex.: `s-sub-Barueri` → `(Subterrâneo) Sothis`).
|
|
- `a` → **Aéreo**, sufixa ` - Aéreo` (ex.: `S-A-ABC` → `Sothis - Aéreo`).
|
|
- `r` → **Rádio**, sufixa ` - Rádio` (ex.: `P-R-Vivo` → `Vivo - Rádio`).
|
|
- Qualquer sigla fora dessa convenção é considerada **não elegível** (ignorada).
|
|
|
|
## 3. Rodando a Aplicação
|
|
|
|
### Modo de Desenvolvimento
|
|
|
|
Este comando inicia a API com `nodemon`, que reinicia o servidor automaticamente a cada alteração nos arquivos. As configurações serão carregadas do `.env.development`.
|
|
|
|
```bash
|
|
npm run dev:api
|
|
```
|
|
|
|
A API será iniciada na porta configurada (padrão `3000`) e exibirá:
|
|
```
|
|
🚀 Servidor API rodando na porta 3000 em modo development
|
|
```
|
|
|
|
### Modo de Produção
|
|
|
|
Este comando inicia a API de forma otimizada para produção usando `node`. As configurações serão carregadas do `.env.production`.
|
|
|
|
```bash
|
|
npm run start:api
|
|
```
|
|
|
|
---
|
|
|
|
## Logging e Monitoramento
|
|
|
|
A aplicação utiliza **Winston** para logging estruturado com as seguintes características:
|
|
|
|
- **Arquivos de Log**: Criados automaticamente no diretório `logs/`
|
|
- **Rotação Diária**: Novos arquivos criados a cada dia com formato `application-YYYY-MM-DD.log`
|
|
- **Níveis de Log**:
|
|
- `info`: Requisições recebidas, operações bem-sucedidas
|
|
- `warn`: Advertências e situações inesperadas
|
|
- `error`: Erros e exceções
|
|
|
|
### Exemplo de Logs
|
|
|
|
```
|
|
2026-05-20T10:30:45.123Z [info]: 🚀 Servidor API rodando na porta 3000 em modo development
|
|
2026-05-20T10:31:20.456Z [info]: Requisição recebida: POST /api/viabilidade - IP: 127.0.0.1
|
|
2026-05-20T10:31:21.789Z [info]: Endereço obtido com sucesso via cep-promise
|
|
2026-05-20T10:31:23.234Z [info]: Coordenadas obtidas com sucesso - lat: -23.5070, lon: -46.4036
|
|
2026-05-20T10:31:25.567Z [info]: Viabilidade salva com sucesso
|
|
```
|
|
|
|
---
|
|
|
|
## Tratamento de Erros
|
|
|
|
A API implementa tratamento robusto de erros:
|
|
|
|
1. **Validação de Entrada**: CEP e número são obrigatórios na consulta de viabilidade
|
|
2. **Erros de Integração**: Erros de terceiros são tratados e retornam respostas HTTP apropriadas
|
|
3. **Logging de Erros**: Todos os erros são registrados com stack trace completo
|
|
4. **Respostas Consistentes**: Erros retornam status HTTP apropriado e mensagem descritiva
|
|
|
|
---
|
|
|
|
## Integração com Serviços Externos
|
|
|
|
### Google Maps Geocoding
|
|
- **Uso**: Converter endereço em coordenadas e vice-versa (reverse geocoding)
|
|
- **Rate Limit**: Respeitar limites da Google API
|
|
|
|
### GeoGrid API
|
|
- **Uso**: Consultar pontos de presença e viabilidade de instalação
|
|
- **Autenticação**: Via API Key e Cookie
|
|
|
|
### Hubsoft API
|
|
- **Uso**: Criação e gestão de prospectos
|
|
- **Autenticação**: OAuth 2.0 com grant_type=password
|
|
|
|
---
|
|
|
|
## Configuração de CORS
|
|
|
|
A API está configurada para aceitar requisições apenas de domínios específicos:
|
|
|
|
```
|
|
✅ https://sothis.com.br
|
|
✅ https://bandalarga.srv.br
|
|
```
|
|
|
|
**Métodos HTTP Permitidos**:
|
|
- GET, POST, PUT, DELETE, OPTIONS
|
|
|
|
**Headers Permitidos**:
|
|
- Content-Type
|
|
- Authorization
|
|
|
|
Para adicionar novos domínios, edite o arquivo [app.js:18](src/app.js#L18).
|
|
|
|
---
|
|
|
|
## Documentação da API
|
|
|
|
O prefixo para todos os endpoints é `/api`.
|
|
|
|
### 1. Consulta de Viabilidade por CEP
|
|
|
|
Verifica a viabilidade técnica de um endereço usando CEP e número.
|
|
|
|
- **Endpoint**: `POST /viabilidade`
|
|
- **Descrição**: Realiza geocodificação do endereço e consulta viabilidade na GeoGrid baseado em pontos de presença.
|
|
- **Corpo da Requisição** (`application/json`):
|
|
|
|
```json
|
|
{
|
|
"nome": "João Silva",
|
|
"email": "joao@email.com",
|
|
"telefone": "11987654321",
|
|
"cep": "06419240",
|
|
"numero": "303",
|
|
"source": ""
|
|
}
|
|
```
|
|
|
|
- **Resposta de Sucesso** (`200 OK`):
|
|
|
|
```json
|
|
{
|
|
"nome": "João Silva",
|
|
"email": "joao@email.com",
|
|
"telefone": "11987654321",
|
|
"logradouro": "Rua Imirim",
|
|
"numero": "303",
|
|
"bairro": "Chácaras Marco",
|
|
"cidade": "Barueri",
|
|
"estado": "SP",
|
|
"cep": "06419240",
|
|
"naoDedicado": true,
|
|
"dedicado": true,
|
|
"distancia": 250,
|
|
"provedor": "Sothis"
|
|
}
|
|
```
|
|
|
|
**Campos da Resposta**:
|
|
- `naoDedicado`: Serviço disponível em banda compartilhada (distância real ≤ 500m)
|
|
- `dedicado`: Serviço disponível em banda dedicada (distância real ≤ 1000m)
|
|
- `distancia`: Distância **real de trajeto** em metros até a caixa mais próxima (ou "5KM+" se não houver caixa no raio). Se o trajeto falhar, cai para a distância em linha reta.
|
|
- `distanciaReta`: Distância em **linha reta** em metros (aditivo, para comparação).
|
|
- `provedor`: Identificação do provedor pela convenção de prefixo da sigla de pasta (ver "Classificação de Pastas")
|
|
|
|
> **Nota:** a regra de viabilidade e o campo `distancia` passaram a usar a **distância real de trajeto** (via GeoGrid `/integracao/trajeto/cordenada`). Como a real é sempre ≥ a linha reta, endereços de borda podem deixar de viabilizar em relação ao comportamento anterior.
|
|
|
|
- **Respostas de Erro**:
|
|
- `400 Bad Request`: Se `cep` ou `numero` não forem fornecidos.
|
|
- `422 Unprocessable Entity`: Se os dados de endereço estiverem incompletos ou inválidos.
|
|
- `502 Bad Gateway`: Se o CEP for inválido ou não encontrado na biblioteca `cep-promise`.
|
|
- `500 Internal Server Error`: Para outros erros no processo.
|
|
|
|
---
|
|
|
|
### 1.1. Consulta de Viabilidade em Lote
|
|
|
|
Consulta viabilidade para vários endereços/coordenadas de uma vez (usado pelo viabiliza). Reusa o mesmo core de viabilidade, com top-N de trajeto reduzido e concorrência limitada.
|
|
|
|
- **Endpoint**: `POST /viabilidade/lote`
|
|
- **Corpo da Requisição** (`application/json`):
|
|
|
|
```json
|
|
{
|
|
"itens": [
|
|
{ "cep": "06419240", "numero": "303" },
|
|
{ "latitude": "-23.5070", "longitude": "-46.4036" }
|
|
],
|
|
"modo": "walking"
|
|
}
|
|
```
|
|
|
|
- **Resposta de Sucesso** (`200 OK`): array alinhado por índice ao `itens` enviado.
|
|
|
|
```json
|
|
{
|
|
"resultados": [
|
|
{
|
|
"index": 0, "provedor": "Sothis",
|
|
"distancia": 630, "distanciaReta": 300, "distanciaReal": 630,
|
|
"dedicado": true, "naoDedicado": false,
|
|
"caixas": [
|
|
{ "provedor": "Sothis", "sigla": "A", "distancia": 420, "distanciaReta": 300, "distanciaReal": 420, "dedicado": true, "naoDedicado": true },
|
|
{ "provedor": "Parceiro - X", "sigla": "B", "distancia": 900, "distanciaReta": 700, "distanciaReal": 900, "dedicado": true, "naoDedicado": false }
|
|
]
|
|
},
|
|
{ "index": 1, "erro": "Item inválido: informe cep+numero ou latitude+longitude." }
|
|
]
|
|
}
|
|
```
|
|
|
|
- `caixas`: detalhe por caixa (as mais próximas em linha reta primeiro), cada uma com **seu próprio provedor**, distância de trajeto e classificação. No lote a seleção é **mista** (as N mais próximas de *qualquer* provedor — rede própria e parceiros), então caixas na mesma linha podem ter provedores diferentes. O viabiliza usa as **2 primeiras** para montar as colunas da planilha (Provedor/Não Dedicado/Dedicado/Distância por caixa). A consulta individual (`/viabilidade`) continua priorizando Sothis.
|
|
- Cada item é resolvido de forma independente: um erro em um item não derruba os demais (vem no campo `erro`).
|
|
- Coordenadas/CEPs repetidos são deduplicados (uma chamada externa por chave única).
|
|
|
|
---
|
|
|
|
### 2. Consulta de Viabilidade por Coordenadas
|
|
|
|
Verifica a viabilidade técnica usando latitude e longitude com reverse geocoding.
|
|
|
|
- **Endpoint**: `POST /viabilidade/lat-long`
|
|
- **Descrição**: Consulta viabilidade baseado em coordenadas geográficas e realiza reverse geocoding.
|
|
- **Corpo da Requisição** (`application/json`):
|
|
|
|
```json
|
|
{
|
|
"latitude": "-23.5070",
|
|
"longitude": "-46.4036"
|
|
}
|
|
```
|
|
|
|
- **Resposta de Sucesso** (`200 OK`):
|
|
|
|
```json
|
|
{
|
|
"endereco": "Avenida Paulista, 1000 - Bela Vista - São Paulo, SP",
|
|
"naoDedicado": false,
|
|
"dedicado": true,
|
|
"distancia": 750,
|
|
"provedor": "Sothis"
|
|
}
|
|
```
|
|
|
|
- **Respostas de Erro**:
|
|
- `500 Internal Server Error`: Se ocorrer erro na consulta ou reverse geocoding.
|
|
|
|
---
|
|
|
|
### 3. Criação de Prospecto
|
|
|
|
Cria um novo cliente (Pessoa Física ou Jurídica) no Hubsoft.
|
|
|
|
- **Endpoint**: `POST /prospecto`
|
|
- **Descrição**: Registra um novo prospecto no sistema Hubsoft com dados de contato e plano selecionado.
|
|
- **Corpo da Requisição** (`application/json`):
|
|
|
|
**Para Pessoa Física (CPF não vazio)**:
|
|
```json
|
|
{
|
|
"prospectData": {
|
|
"Nome completo": "João Silva Santos",
|
|
"CPF": "123.456.789-00",
|
|
"Nome da mãe": "Maria Silva",
|
|
"Data de nascimento": "15/05/1985",
|
|
"E-mail": "joao@email.com",
|
|
"Celular": "(11) 98765-4321",
|
|
"CEP": "06419240",
|
|
"Logradouro": "Rua Imirim",
|
|
"Número": "303",
|
|
"Complemento": "Apto 42",
|
|
"Bairro": "Chácaras Marco",
|
|
"Descrição": "100 Mega + Super WiFi",
|
|
"Valor (mensal)": "R$ 119,90"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Para Pessoa Jurídica (CPF vazio, CNPJ preenchido)**:
|
|
```json
|
|
{
|
|
"prospectData": {
|
|
"Razão Social": "Empresa LTDA",
|
|
"CNPJ": "12.345.678/0001-90",
|
|
"E-mail": "contato@empresa.com",
|
|
"Celular": "(11) 98765-4321",
|
|
"CEP": "06419240",
|
|
"Logradouro": "Rua Imirim",
|
|
"Número": "303",
|
|
"Complemento": "",
|
|
"Bairro": "Chácaras Marco",
|
|
"Descrição": "500 Mega + Super WiFi + IP Fixo",
|
|
"Valor (mensal)": "R$ 249,90",
|
|
"CPF:": ""
|
|
}
|
|
}
|
|
```
|
|
|
|
**Planos Disponíveis**:
|
|
- `100 Mega + Super WiFi` (ID: 22)
|
|
- `200 Mega + Super WiFi` (ID: 94)
|
|
- `500 Mega + Super WiFi` (ID: 96)
|
|
- `700 Mega + Super WiFi` (ID: 97)
|
|
- `1 Gb + Super WiFi` (ID: 32)
|
|
- Variações com `+ IP Fixo`
|
|
|
|
- **Resposta de Sucesso** (`200 OK`):
|
|
|
|
```json
|
|
{
|
|
"message": "Prospecto criado com sucesso",
|
|
"data": {
|
|
"tipo_pessoa": "pf",
|
|
"nome_razao_social": "João Silva Santos",
|
|
"cpf_cnpj": "123.456.789-00",
|
|
"email": "joao@email.com",
|
|
"telefone": "11987654321",
|
|
"endereco": "Rua Imirim",
|
|
"numero": "303",
|
|
"bairro": "Chácaras Marco",
|
|
"cep": "06419240",
|
|
"servico": {
|
|
"id_servico": 22,
|
|
"valor": 119.90
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
- **Respostas de Erro**:
|
|
- `400 Bad Request`: Se o plano informado for inválido ou não encontrado.
|
|
- `500 Internal Server Error`: Se ocorrer erro na comunicação com Hubsoft.
|
|
|
|
---
|
|
|
|
## Estrutura do Projeto
|
|
|
|
```
|
|
src/
|
|
├── app.js # Ponto de entrada da aplicação
|
|
├── routes/
|
|
│ └── routes.js # Definição de rotas
|
|
├── modules/
|
|
│ └── contratacao/
|
|
│ ├── contratacao.controller.js # Controladoras HTTP
|
|
│ ├── contratacao.service.js # Lógica de negócio
|
|
│ ├── contratacao.repository.js # Acesso a dados
|
|
│ └── contratacao.model.js # Modelos de dados
|
|
└── shared/
|
|
├── apis/
|
|
│ ├── googleService.js # Integração Google Maps
|
|
│ ├── geogridService.js # Integração GeoGrid
|
|
│ └── hubsoftService.js # Integração Hubsoft
|
|
├── config/
|
|
│ ├── environment.js # Carregamento de variáveis
|
|
│ ├── apiConfig.js # Configurações de API
|
|
│ └── dbConfig.js # Configurações de banco
|
|
└── utils/
|
|
└── logger.js # Sistema de logging
|
|
```
|
|
|
|
---
|
|
|
|
## Boas Práticas e Considerações
|
|
|
|
### Validação de CEP
|
|
- A biblioteca `cep-promise` realiza consulta em múltiplas bases de dados brasileiras
|
|
- Retorna erro 502 se o CEP for inválido ou não encontrado
|
|
|
|
### Distância de Viabilidade
|
|
- **≤ 500m**: Ambos serviços disponíveis (dedicado e não-dedicado)
|
|
- **500m - 1000m**: Apenas serviço dedicado disponível
|
|
- **> 1000m**: Nenhum serviço disponível (retorna "5KM+")
|
|
|
|
### Criação de Prospectos
|
|
- O tipo de pessoa é detectado automaticamente: CPF não vazio = Pessoa Física, CNPJ com CPF vazio = Pessoa Jurídica
|
|
- Números de telefone são sanitizados automaticamente (removem caracteres não-numéricos)
|
|
- Valores monetários aceitam diversos formatos (R$ 119,90 ou 119.90)
|
|
|
|
### Segurança
|
|
- CORS restrito a domínios específicos
|
|
- Todas as requisições são logadas com IP e método
|
|
- Erros não expõem informações sensíveis ao cliente
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Erro: "CEP não encontrado"
|
|
- Verifique se o CEP está correto e tem 8 dígitos
|
|
- Alguns CEPs novos podem não estar na base de dados
|
|
|
|
### Erro: "Sem caixas dentro de 5km"
|
|
- Significa que não há ponto de presença próximo ao endereço
|
|
- O serviço não é viável para esta localização
|
|
|
|
### Erro: "Plano inválido"
|
|
- Verifique se a descrição do plano corresponde exatamente a um dos planos mapeados
|
|
- Referência: [contratacao.service.js:159-170](src/modules/contratacao/contratacao.service.js#L159-L170)
|
|
|
|
### Logs não aparecem
|
|
- Verifique se a pasta `logs/` foi criada (criada automaticamente)
|
|
- Verifique permissões de escrita no diretório do projeto
|
|
|
|
---
|
|
|
|
## Histórico de Mudanças
|
|
|
|
### Recent Updates
|
|
- ✅ Adicionado tratamento de erro para casos sem caixa em 5km
|
|
- ✅ Implementada variável de sigla de pasta no .env com mapeamento de provedor
|
|
- ✅ Refatorada busca de CEP usando `cep-promise`
|
|
- ✅ Adicionada URL de banda larga na configuração de CORS
|
|
- ✅ Atualizado suporte de CORS para Express 5.x
|
|
|
|
---
|
|
|
|
## Suporte e Contribuições
|
|
|
|
Para reportar bugs ou sugerir melhorias, entre em contato com a equipe de desenvolvimento Sothis.
|
|
|
|
**Contato**: gabriel.amancio@sothis.com.br
|
|
|
|
---
|
|
|
|
## Licença
|
|
|
|
ISC |