44 lines
2.5 KiB
Markdown
44 lines
2.5 KiB
Markdown
# Etapa 04 — Normalizador e padronização de dados
|
|
|
|
## Objetivo
|
|
Implementar o módulo `normalizer/` que transforma os `LeadBrutoDTO` extraídos na etapa 03 em dados padronizados prontos para persistência, conforme as regras definidas em `ARQUITETURA-SCHEMA.md` seção 5.
|
|
|
|
## Contexto
|
|
Esta etapa não persiste nada ainda — produz um `LeadNormalizadoDTO` a partir do `LeadBrutoDTO`. A persistência com deduplicação é a etapa 06 (junto com a API).
|
|
|
|
## Tarefas
|
|
|
|
1. Criar `normalizer/NomeNormalizer`:
|
|
- Trim + colapsar espaços múltiplos
|
|
- Title Case, preservando em maiúsculo as siglas societárias: `LTDA`, `ME`, `EIRELI`, `S/A`, `S.A.`
|
|
- Remover caracteres de controle/emoji
|
|
2. Criar `normalizer/TelefoneNormalizer`:
|
|
- Extrair apenas dígitos do texto bruto
|
|
- Assumir DDI `+55` se ausente
|
|
- Validar tamanho (DDD de 2 dígitos + número de 8 ou 9 dígitos); se inválido, retornar `null` no campo normalizado mas manter o bruto
|
|
- Formatar em E.164 (`+5543999999999`)
|
|
3. Criar `normalizer/CnpjValidator`:
|
|
- Extrair apenas dígitos (14 posições)
|
|
- Implementar validação de dígito verificador (algoritmo módulo 11)
|
|
- Se inválido, descartar o CNPJ (gravar `null`) em vez de persistir um valor incorreto
|
|
4. Criar `normalizer/RamoMapper`:
|
|
- Buscar na tabela `ramos.aliases` (JSONB) se a categoria bruta já tem mapeamento conhecido
|
|
- Se encontrar, retornar o `ramo_id` correspondente
|
|
- Se não encontrar, retornar `ramo_id = null` e manter a categoria bruta em `categoria_bruta` para curadoria manual posterior
|
|
5. Criar `normalizer/DedupHashCalculator`:
|
|
- Calcular `hash_dedup = SHA-256(nomeNormalizado + "|" + telefoneE164)`
|
|
6. Criar `normalizer/LeadNormalizerService` que orquestra os passos acima e produz o `LeadNormalizadoDTO` completo a partir de um `LeadBrutoDTO`
|
|
7. Escrever testes unitários para cada normalizador, cobrindo casos-limite:
|
|
- Telefone sem DDD, com formatação variada (parênteses, traços, espaços)
|
|
- CNPJ com dígito verificador inválido
|
|
- Nome com sigla societária em posições diferentes
|
|
- Categoria bruta sem mapeamento conhecido em `ramos`
|
|
|
|
## Critérios de aceite
|
|
|
|
- [ ] Todos os normalizadores implementados e cobertos por testes unitários com casos-limite
|
|
- [ ] CNPJ inválido nunca é persistido como válido
|
|
- [ ] Telefone sempre sai em E.164 quando válido, ou `null` quando não for possível normalizar
|
|
- [ ] Ramo sem mapeamento conhecido não quebra o fluxo — apenas fica pendente de curadoria
|
|
- [ ] `hash_dedup` calculado de forma determinística e reproduzível para o mesmo par nome+telefone
|