Todos, absolutamente todos da área de desenvolvimento, nos dizem para desenvolver projetos com um objetivo em específico, preencher o nosso portfólio com possíveis ferramentas. A ideia por trás é preparar a pessoa para o mercado de trabalho, estando apta a exercer a profissão de acordo com os conceitos solicitados. O ponto é, "O que deveríamos desenvolver?", "Como pensar em uma ideia suficientemente boa?", "Como sair de um simples CRUD?", "Qual tema é interessante?".
Percebe?... é difícil responder essas perguntas, pois estamos procurando fazer coisas que possam agregar valor para nós como para a sociedade, e temas genéricos não entram aqui. Não fazem parte. É fácil dizer que você tem que fazer aquilo e isso, mas a parte difícil, é te dizerem informações únicas, que podem contribuir com a sua formação profissional e até mesmo pessoal. Provavelmente essa será uma série do meu blog, sendo este o primeiro artigo sobre o tema. Penso que ainda tenho muito a aprender, e sempre que aprendo algo novo, penso que sei menos ainda. É interessante. O presente artigo não é um tutorial, digo isto porque você, de forma autônoma, precisará pesquisar certos conceitos mencionados. No entanto, tentarei ser lúcido e explicar da melhor forma possível.
# 1. Uma boa ideia nasce de uma dor
Um projeto nasce a partir de uma ideia, e se for suficientemente boa o crescimento é viável. Mas as ideias, nem sempre, surgem a partir de uma necessidade. Por exemplo, no momento estou desenvolvendo uma aplicação voltada para gestão financeira utilizando IA. A ideia, por si só, é extremamente simples e popular no mundo acadêmico. Tenho certeza que já disseram para você: "faça um projeto de gestão acadêmica ou financeira, etc... ".
Ou seja, projetos com esse tema vão surgir a todo momento. No entanto, podemos transformar este projeto em algo único, adicionando uma funcionalidade que resolve uma dor. Essa dor em específico, foi ocasionada na minha vida.
Uma breve história... eu tenho o hábito de anotar todas as minhas despesas, estabelecendo o nome do produto, preço, local, cidade, data, etc. O cadastro é feito de forma manual na plataforma Notion, onde posso fiscalizar através de gráficos o resumo das minhas transações financeiras. O problema é, no caso, a minha dor foi ter que cadastrar individualmente cada comprovante. O que não necessariamente seria um problema, pois teria que apenas cadastrar posteriormente, porém em alguns dias não consegui cadastrar por estar focado em outras tarefas. Ficando de lado, por assim dizer, o que gerou um acúmulo de comprovantes em minha carteira e uma preguiça gigantesca de cadastrar tudo, um a um na minha base de dados. Na época, os modelos de IA (LLMs) já estavam a todo vapor, sendo adotados por várias empresas e projetos. Eu já usava de modo ocasional e breve para encontrar respostas para problemas de código ou arquitetura, e sabia da capacidade de leitura dos modelos em relação a imagens. Lembre-se que programadores são preguiçosos, mas isto não significa realizar um trabalho ruim.
Então, quando certa noite eu estava voltando da faculdade, já no ônibus e perto de chegar ao meu destino. Eu lembro de pensar: "como posso evitar ter de cadastrar toda vez a despesa?" Foi então que pensei em uma plataforma de análise de comprovantes utilizando IA. Fiquei bastante empolgado com a ideia, não por ser revolucionária (de fato, ela não é), mas por resolver de forma definitiva a minha dor, a minha necessidade. Qual é a sua dor?
# 2. O desenvolvimento do projeto
O projeto em questão, recebeu o nome: Cycle Finance. Talvez no futuro, o nome seja alterado. Como dito anteriormente, o projeto nasceu de uma dor: ter que cadastrar individualmente cada despesa. O processo deixa de ser manual e passa para algo automático, exigindo apenas que o usuário anexe uma foto do comprovante de pagamento. Então, a IA entra em ação, realizando a leitura das informações e exibindo para o usuário confirmar a autenticidade do escaneamento. Caso correto, o cadastro é feito e automaticamente exibido na tabela de listagem de despesas, assim como nos gráficos.
Uma funcionalidade extremamente simples e satisfatória. E, definindo estatísticas e números, o que levaria 1 minuto por comprovante, passou a sequer ter 1 segundo por upload. Ou seja, a economia de tempo e esforço é abundante, além dos benefícios. Uma visibilidade dos gastos a curto, médio e longo prazo.
No momento em que escrevo este artigo, o projeto ainda está em desenvolvimento com um prazo estimado de entrega até Novembro/2026, estando o backend finalizado. Venho trabalhando constantemente no backend, estando bem documentado com Swagger e 100% de cobertura dos testes unitários. O foco principal, foi isolar completamente a regra de negócio (use-cases) das camadas superiores, como dependências de banco de dados e HTTP. Ou seja, a regra de negócio não conhece PostgreSQL, Fastify ou qualquer outro detalhe de infraestrutura, não foi apenas uma escolha de padrão de arquitetura; foi uma tentativa de evitar que uma mudança de infraestrutura obrigasse a reescrever a lógica da aplicação. Ou seja, o domínio da aplicação está isolado e sem dependência com bibliotecas externas, sendo possível migrar para outra linguagem de programação, caso a necessidade ocorra, pois o código está profundamente puro e trabalhando apenas com as funções nativas da linguagem utilizada. Os conceitos aplicados utilizam da orientação a objetos com furor, como Domain Driven Design, SOLID e Clean Architecture. Dentre as ideias aplicadas, temos: SRP (single responsibility principle) e DIP (dependency inversion principle). A pergunta que fica: "Por que tanto trabalho?". É simples, a ideia é construir uma base que pode ser transferida facilmente para qualquer framework existente, ou simplesmente, para construir algo que vai crescer drasticamente, sendo de forma sustentável e manutenível.
Mas claro, esses padrões de projetos possuem muitos princípios a serem implementados e não necessariamente precisamos utilizar todos. No caso, se adotarmos a missão de aplicar os princípios com rigorosidade, apenas estaremos fazendo overengineering, adicionando complexidade para casos de uso que não necessitam.
"Existem duas maneiras de construir o design de um software: uma maneira é torná-lo tão simples que obviamente não existam deficiências, e a outra é torná-lo tão complicado que não existam deficiências óbvias.", — C.A.R. Hoare
# 3. As complexidades do projeto
Até então eu já havia feito aplicações fullstack, desenvolvendo tanto backend quanto frontend. Ambos tendo suas familiaridades e requisitos. O Cycle Finance foi o primeiro que implementei uma IA para auxiliar o usuário em seu uso, sendo mais preciso, na funcionalidade de escanear o comprovante. Isso me exigiu certo conhecimento que eu não possuía, tive que ler documentação do Gemini IA, entender como utilizaria o provider no backend, pesquisar no YouTube e afins. Me perguntava como poderia fazer de forma, que eventualmente, o modelo pudesse ser substituído por outro, e fui adaptando o código e modelando ele para uma solução escalável. Então utilizando orientação a objetos e SOLID, consegui utilizar o provider sem precisar instanciar, apenas implementando o contrato. A operação do caso de uso é receber os dados do comprovante, verificar e retornar. Em nenhum momento, ele saberá da camada mais externa. Sendo, no caso, o provider da IA. O provider, por sua vez, recebe uma imagem no formato file buffer com codificação 'base64', assim como o mimeType para definir o formato do arquivo: jpeg/png.
const response = await this.ai.models.generateContent({
model: "gemini-2.5-flash",
contents: [
imagePart,
"Extraia o título do estabelecimento ou nome do proprietário, valor total em decimal,
data no formato YYYY-MM-DD, CPF OU CNPJ, os quatro digitos do cartão, cidade e estado.
Entenda que alguns comprovantes são diferentes de outros. Ou seja, pode ter ou não as
informações acima.",
],
config: {
responseMimeType: "application/json",
responseSchema: {
type: "OBJECT",
properties: {
title: { type: "STRING" },
amount: { type: "NUMBER" },
date: { type: "STRING" },
cpfOrCNPJ: { type: "STRING" },
transactionId: { type: "STRING" },
city: { type: "STRING" },
state: { type: "STRING" },
},
required: ["title", "amount", "date", "transactionId"],
},
},
});
O código anterior, é de fato, a solicitação ao modelo free do Gemini IA. Sendo passadas configurações, como: modelo, conteúdo (imagem e orientação), como a resposta deve ser e em qual formato.
O projeto ainda está na versão v1, e em desenvolvimento. Ou seja, ainda há bastante tempo para mudanças decisivas e que possam contribuir com o crescimento a longo prazo. Este artigo provavelmente receberá atualizações com mais definições e explicações. No entanto, por hoje é só, crianças! Tchau.
Link do repositório (dá uma star, please): github
Gostou da leitura?
Acompanhe meus próximos laboratórios de código e anotações de arquitetura na aba de Artigos.