Desafio Fullstack. O projeto foi desenvolvido com foco nos pilares solicitados: KISS (Simplicidade).
- IDE: IntelliJ
- ETL: Java 11+ (Processamento de Arquivos)
- Backend: Python 3.9+ (FastAPI + Pandas)
- Frontend: Vue.js 3 (CDN) + TailwindCSS
- Banco de Dados: PostgreSQL
O Java é responsável por baixar, limpar e consolidar os dados.
- Na raiz, execute a classe
TesteEstagio.java. - Saída: Serão gerados os arquivos
Resultado_Final.csv,despesas_agregadas.csve o zipTeste_Intuitive_Entrega.zip.
- Vá até a pasta
/sqle abra o scriptdados.sql. - Atualize o caminho do comando
COPYpara apontar para oResultado_Final.csvgerado acima. - Execute no seu banco PostgreSQL.
- Instale as dependências:
pip install fastapi "uvicorn[standard]" pandas - Rode a API:
python -m uvicorn main:app --reloadvia terminal dentro da pasta do projeto - Abra o arquivo
index.htmlno navegador.
Esta seção documenta as escolhas arquiteturais e o tratamento de inconsistências solicitados nas instruções do teste.
Durante a consolidação dos dados no Java, as seguintes anomalias foram tratadas:
-
A. CNPJs Duplicados com Razões Sociais Diferentes
- Cenário: Uma operadora mudou de nome entre o 1º e o 3º trimestre. O CNPJ é o mesmo, mas a Razão Social divergiu.
- Abordagem: Unificação via Fonte da Verdade (Cadastro).
- Justificativa: Utilizei o arquivo
Relatorio_cadop.csv(Cadastro de Operadoras Ativas) como mestre. Ao processar as despesas, ignorei a Razão Social que vinha no arquivo contábil antigo e forcei o uso do nome atualizado do cadastro. Isso garante unicidade e integridade dos dados cadastrais.
-
B. Valores Zerados ou Negativos
- Cenário: Lançamentos contábeis com valor
0.00ou negativos (ex:-1500.00). - Abordagem: Preservação Integral.
- Justificativa: Em contabilidade, valores negativos representam estornos, ajustes ou provisões revertidas. Excluí-los invalidaria o balanço final da operadora. Optei por manter os dados originais, aplicando apenas normalização de formatação (troca de vírgula por ponto).
- Cenário: Lançamentos contábeis com valor
-
C. Trimestres com Formatos de Data Inconsistentes
- Cenário: O conteúdo interno dos CSVs da ANS nem sempre possui colunas de data padronizadas.
- Abordagem: Inferência por Metadados (Nome do Arquivo).
- Justificativa: Como os arquivos são baixados de URLs padronizadas (
2024/3T), extraí o Ano e o Trimestre diretamente do nome do arquivo (ex:2025_3T.csv) via código Java. Isso é mais confiável do que tentar "adivinhar" qual coluna dentro do CSV representa a data.
-
Processamento de Arquivos (Memória vs. Stream):
- Decisão: Abordagem Híbrida.
- Justificativa: O arquivo de cadastro (~30MB) foi carregado em memória (
HashMap) para garantir acesso O(1) rápido durante o cruzamento. Já os arquivos de despesas (que podem crescer indefinidamente) foram lidos linha a linha (BufferedReader), evitando estouro de memória (Out of Memory) caso o volume de dados aumente no futuro.
-
Join de Dados (CNPJs sem Match):
- Decisão: Left Join (Prioridade para Despesas).
- Justificativa: Se uma operadora tem despesas mas não está no cadastro de "Ativas", ela ainda gerou custo histórico. Esses registros foram mantidos com a Razão Social marcada como "Operadora Desconhecida" ou "Cadastro Inativo", garantindo que a soma financeira total bata com os arquivos originais.
-
Normalização (Opção B):
- Separei em duas tabelas:
operadoras(Dados Cadastrais) edespesas(Dados Financeiros). - Justificativa: Evita redundância. Se tivéssemos uma tabela única, a string da "Razão Social" seria repetida milhões de vezes, desperdiçando armazenamento e dificultando updates de nome.
- Separei em duas tabelas:
-
Tipos de Dados:
- Dinheiro: Usei
NUMERIC(15,2)ouDECIMAL. JamaisFLOAT, pois cálculos flutuantes geram erros de arredondamento em sistemas financeiros. - Datas: Usei inteiros para
AnoeTrimestre, pois facilita a indexação e queries de agrupamento.
- Dinheiro: Usei
-
Framework (FastAPI):
- Escolhido pela performance superior ao Flask (Assíncrono) e pela geração automática de documentação (Swagger), agilizando o desenvolvimento.
-
Paginação e Busca:
- Implementei paginação no backend (
limitepage). - Justificativa: Trafegar todos os dados para o frontend travaria o navegador do usuário. A busca também é feita no backend para aproveitar a performance do Pandas/Banco de Dados.
- Implementei paginação no backend (
-
Frontend (Vue.js via CDN):
- Decisão KISS: Utilizei Vue via CDN em vez de configurar um ambiente complexo com Webpack/Vite.
- Justificativa: Para este escopo, reduz drasticamente a complexidade de configuração ("setup fatigue"), permitindo focar na lógica de visualização e consumo da API.
Autor: Leonardo A. Roeda