Este projeto é uma API RESTful desenvolvida em Node.js com NestJS para processar faturas de energia elétrica em PDF (padrão Cemig). O grande diferencial desta aplicação é a utilização de modelos avançados de IA (Large Language Models - LLMs) com suporte multimodal para extrair dados estruturados diretamente da imagem do documento, dispensando o uso de ferramentas clássicas de OCR (Optical Character Recognition) que costumam falhar diante de variações de layout.
A API já está hospedada na nuvem utilizando Serverless Functions e um banco online (Neon/PostgreSQL). Acesse a documentação interativa (Swagger UI) e teste as faturas ao vivo: 👉 Teste a API Online Aqui (Swagger): https://billlens-coral.vercel.app/api/docs
- Além disso, foi construído um painel de teste para vizualização frontend das informações e upload das faturas, a partir de 👉 BillLens-Front
- Como Iniciar o Projeto (Quick Start)
- Rotas da API (Endpoints)
- CI/CD Pipeline
- Estratégia do LLM e Fallbacks
- Motor Analítico de Agregações
- Otimizações do Prisma ORM
- Arquitetura de DB e Consultas
A forma mais espetacular de levantar a base inteira em Segundos:
- Instale o Docker Desktop.
- Na raiz onde fica o
docker-compose.yml, rode o comando aglutinador com sua Key:
GEMINI_API_KEY=sua_API_key docker-compose up --build -dO Docker fará o download do Node.js, empacotará a API (
Dockerfile), baixará o PostgreSQL nativo livre, isolará as redes, aplicará os Migrations sozinhos e soltará o back-end emhttp://localhost:3000.
- Node.js (v18+)
- PostgreSQL (pode rodar via Docker
docker run --name billlens-db -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=billlens_db -p 5432:5432 -d postgres) - Chave de API da Google Gen AI (Gemini)
# Clone o repositório
git clone https://github.com/JoaoIto/BillLens.git
# Entre na pasta do projeto
cd billlens-api
# Instale as dependências
npm install
# Crie e configure o arquivo .env
cp .env.example .env
# Rode as migrations do banco de dados relacional
npx prisma migrate dev
# Inicie o servidor
npm run start:devA aplicação usa o Jest. Pode validar tudo com:
npm run testA aplicação expõe as seguintes rotas principais para interação e consumo dos dados:
POST /faturas/upload: Recebe um arquivo.pdf(fatura real da CEMIG) via form-data (file), executa o serviço de extração de dados através da API LLM, processa todas as regras de negócio para encontrar a economia de energia gerada e consumo total, e persiste o registro no banco de dados.GET /faturas: Retorna uma biblioteca com todas as faturas já salvas. É possível iterar e navegar nas faturas inserindo filtros na query string do navegador ou API:?clientNumber=123e/ou?referenceMonth=JAN/2024.GET /faturas/dashboard: Rota focada em servir frontends de Inteligência de Negócio e desenhar gráficos. Ela não devolve JSONs extensos, ela retorna apenas as Somatórias Consolidadas (Data Aggregation via SUM no Prisma) de meses de consumo e injetadas de GD unificadas, separadas em métricas financeiras (financialMetrics) e consumo (energyMetrics). Para puxar os gráficos exclusivos de um cliente, use?clientNumber=X.
O objetivo central é:
- Upload: Receber um arquivo PDF da fatura via endpoint
POST /faturas/upload. - Processamento (LLM): Enviar o PDF para uma API de IA capaz de retornar os dados lidos em um formato JSON restrito e previsível (Structured Output).
- Regra de Negócio: Calcular novas variáveis a partir dos dados extraídos (ex.: consumo total, economia com energia injetada GD).
- Persistência e Consulta: Armazenar os resultados em um banco PostgreSQL usando Prisma e disponibilizá-los em endpoints de listagem e de agregações para o frontend (Dashboard).
Para que a leitura da fatura se transforme em dados estruturados no banco, a API orquestra o seguinte pipeline no momento em que a rota POST /faturas/upload é acionada:
- Recepção em Memória: O NodeJS intercepta o
.pdfusandoMultere aloca o Buffer diretamente na memória (sem salvar arquivos temporários no disco). - Conversão Base64: O conteúdo do PDF é convertido em uma string codificada em
Base64. - Engenharia de Prompt (LLM): O
LlmServicecria um payload passando o documento viainlineDatajunto com um Prompt rigoroso. Este prompt ensina a IA a se comportar como um auditor e a devolver os valores obrigatoriamente num Formato JSON Estrito predefinido. Há inclusive um sistema de fallback (cascata) que tenta diferentes versões de modelo (ex:gemini-1.5-flash,gemini-1.5-pro) caso haja falha ou recusa de API. - Parsing e Sanitização: O texto retornado pela IA é limpo de artefatos (como marcações Markdown) e convertido via
JSON.parse(). - Cálculos de Regra de Negócio: Na camada
InvoicesService, a API pega os valores capturados da Cemig e efetua a lógica matemática do sistema:totalConsumptionKwh: Soma Energia Elétrica + Energia SCEE.totalValueWithoutGd: Remocão dos descontos da Geração Distribuída.gdEconomyValue: Valor da Isenção/Economia na fatura injetada.
- Persistência (Prisma ORM): Após os cálculos numéricos forçados (para evitar erros de tipagem), os dados são finalmente gravados na tabela
Invoicedo PostgreSQL.
Depois que a fatura PDF sofre todo o pipeline acima (upload -> IA -> Parse -> Cálculos), o banco de dados armazena e retorna no GET /faturas o seguinte objeto documentado:
[
{
"id": "67dd773f-3ff2-4660-ad88-fc02e8cd06d0",
"clientNumber": "7204076116",
"referenceMonth": "JAN/2024",
"electricalEnergyKwh": 50,
"electricalEnergyValue": 47.75,
"sceeEnergyKwh": 456,
"sceeEnergyValue": 232.42,
"compensatedEnergyKwh": 456,
"compensatedEnergyValue": 222.22,
"municipalLightingValue": 49.43,
"totalConsumptionKwh": 506,
"totalCompensatedKwh": 456,
"totalValueWithoutGd": 329.6,
"gdEconomyValue": 222.22,
"createdAt": "2026-02-24T21:17:24.376Z"
}
]A escolha da stack foi voltada para garantir um código limpo, tipado, testável e escalável, refletindo um ambiente de produção moderno.
- Framework:
NestJS(Node.js)- Por que? Ao contrário do Express (que é não-opinativo), o NestJS impõe uma arquitetura baseada em Clean Architecture e Angular. A separação nativa em Módulos, Controllers, Services e a Injeção de Dependência nativa facilitam imensamente a criação de testes unitários isolando dependências externas (mockando a API do LLM e o Banco de Dados).
- Banco de Dados & ORM:
PostgreSQL+Prisma- Por que? O PostgreSQL é o padrão de mercado para banco relacional. O Prisma ORM é adotado pela sua tipagem fenomenal (type-safety) que se integra perfeitamente ao TypeScript. Ele permite consultar agregações de forma performática para o dashboard sem escrever SQL cru.
- Testes & CI/CD:
JesteGitHub Actions- Por que? A Suíte 100% Mockada com Jest está entrelaçada a um Worker contínuo do Github. Todos os Commits devem passar pelo gargalo virtual do Teste antes de virarem versão de produção.
- Infra-as-Code & Nuvem:
Docker ComposeeRender (PaaS)- Por que? Empacotamento Multi-Stage gerando contêiners minúsculos (Alpine Node). Facilitam o Deploy Cloud de 1-Clique na provedora Render (
render.yamlgerencia o Cloud PostgreSQL e a Web API automaticamente).
- Por que? Empacotamento Multi-Stage gerando contêiners minúsculos (Alpine Node). Facilitam o Deploy Cloud de 1-Clique na provedora Render (
- Integração IA: SDK do
@google/genaipara o Gemini
O ecossistema é dividido em módulos para isolamento de contexto dinâmico:
AppModule: Inicialização do roteamento.LlmModule: Um wrapper de infraestrutura em torno da API de IA para isolar os SDKs terceiros e centralizar validação do Output da IA (com schema estrito via Zod/etc) e lógicas de "retry on failure".InvoicesModule: Coração das regras de contabilidade e endpoints de upload e leitura.
Para guias extremamente aprofundados dos motores e regras de arquitetura desta API, acesse a pasta oficial de documentação /docs:
- 🤖 Técnica de Engenharia de Prompt: Uma dissecação da estrutura psicológica do prompt escrito para forçar restrições (Output Constraint e Role Prompting) no Gemini, neutralizando alucinações de saída da IA.
- 🧪 A Estratégia de Testes (Jest Isolado e Mocks LLM): Como cobrimos 100% da lógica matemática, regras de negócio e bloqueios da API (UnprocessableEntity e Conflict) sem gastar 1 único token do pacote pago da inteligência artificial através das funções Injetáveis do NestJS.
- ⚙️ Automação de CI/CD (GitHub Actions): Explicação da pipeline que garante a integridade de commits com as matrizes LTS do Node.js.
- 🧠 A Estratégia do LLM e Fallbacks: Como a Visão Computacional extrai os dados do PDF de fatura superando o OCR antigo, Engenharia de Prompt restrita e mecanismo de Cascata de Modelos Gemini.
- 📊 O Motor do Dashboard de Faturas: Uma aula técnica demonstrando como a nossa API lida matematicamente com agregações sem travar a memória do Node.js, com trechos de código mostrando a delegação de somas (
SUM()) ao PostgreSQL via Prisma, e explicação do escopo dos resultados financeiros. - 💎 Otimizações Extremas com Prisma ORM: Aprofundamento no combate a Memory Leaks com paralelismo I/O na Engine transacional do banco (
$transaction), aniquilação de Full-Table Scans em listagens usando estrita de metadados exatos para indexaçãoB-Tree(saltos assintóticos de$O(N)$ para $O(1)$) e implementações do Repository Pattern contra Hard-Coding na Controller. - ⚡ Arquitetura de DB e Otimizações de Consultas: Um registro profundo de Engenharia de Software demonstrando as refatorações do back-end, destravando a V8 de arrays imensos.