- Software para gerenciamento financeiro que permite registrar despesas manualmente ou através da captura de comprovantes utilizando a câmera do dispositivo. O sistema oferece visualizações e análises dos gastos por dia, mês e ano.
🚧 Status v1: Em desenvolvimento
- API: Armazena o código backend da aplicação;
- WEB: Armazena a interface web do cliente;
- MOBILE: Armazena a interface mobile do cliente.
- Backend: Node.js, Fastify, PrismaORM v7, PostgreSQL, Redis, Docker, Zod, Swagger, FastifyMultipart, GeminiIA Client API.
- Frontend: React.js, React-Hook-Form, React-Router, Tanstack-Query, Shadcn, RadixUI, PhosphorIcons, Axios, Date-fns, Zod, Sonner, ReCharts, React-Helmet, Tailwindcss.
- Mobile: React Native.
- Tooling: TypeScript, ESLint, Prettier, tsup, tsx.
- API REST utilizando Fastify
- Autenticação baseada em JWT
- Autenticação automática via Refresh Token (JWT)
- Controle de acesso baseado em papéis (RBAC)
- Persistência com PostgreSQL
- Cache e Rate Limiting com Redis
- Validação de entrada com Zod
- ORM Prisma
- O usuário deve poder se cadastrar;
- O usuário deve poder se logar;
- O usuário deve poder resetar a senha;
- O usuário deve poder registrar uma categoria;
- O usuário deve poder registrar um comprovante;
- O usuário deve poder visualizar suas informações de perfil;
- O usuário deve poder visualizar o histórico de todas as suas despesas;
- O usuário deve poder visualizar o histórico de todas as suas categorias;
- O usuário deve poder visualizar a quantidade de despesas registradas;
- O usuário deve poder visualizar a quantidade de despesas registradas no dia;
- O usuário deve poder visualizar o valor gasto do mês;
- O usuário deve poder visualizar o valor gasto do dia;
- O usuário deve poder deletar depesas;
- O usuário deve poder deletar categorias;
- O usuário deve poder deletar a própria conta;
- O usuário deve poder atualizar as informações de seu perfil;
- O usuário deve poder atualizar uma despesa;
- O usuário deve poder atualizar uma categoria;
- O usuário deve poder visualizar despesas agrupadas por data e valor;
- O usuário deve poder visualizar a quantidade de despesas por categoria;
- O usuário deve poder filtrar seu histórico de despesas por período e por categoria;
- O usuário deve poder enviar o comprovante e o sistema deve extrair as informações;
- O sistema deve sugerir valores e datas com base no comprovante;
- O administrador deve poder visualizar todos os usuários.
- A senha do usuário precisa estar em formato hash;
- Os dados da aplicação precisam estar persistidos em um banco PostgreSQL;
- Todas as listas de dados precisam estar paginadas com 15 itens por página;
- O banco de dados deve utilizar UUID v7 para performance e identificação;
- O usuário deve ser identificado por um JWT (JSON Web Token) entre as requisições;
- Todos os usuários devem ser identificados pela permissão de "membro" ou "admin";
- O Redis deve ser utilizado para cache e rate limiting;
- O sistema deve possuir tratamento centralizado de erros;
- O administrador não pode visualizar senhas dos usuários.
- A API deve registrar logs de erros e auditoria;
- Todas as rotas precisam estar documentadas utilizando o swagger;
- Os testes unitários devem ter cobertura de 100% (coverage);
- Deve ser possível realizar o upload nos seguintes formatos: JPEG, PNG;
- O sistema deve implementar refresh token para renovação de autenticação;
- Invalidar o JWT ao deletar a conta do usuário.
- O usuário não deve poder se cadastrar com e-mail duplicado;
- O usuário não deve poder cadastrar categorias com o mesmo título;
- O usuário não deve poder deletar despesas de outro usuário;
- O usuário não deve poder deletar categorias de outro usuário;
- O usuário não deve poder deletar uma categoria com gastos vinculados;
- O usuário não deve poder cadastrar mais que 15 categorias;
- O usuário só pode atualizar despesas e categorias criadas por ele mesmo.
- O token de reset de senha deve expirar em 15 minutos e só pode ser usado uma vez;
- O usuário que solicitou renovação de senha não pode cadastrar a mesma senha novamente;
- Deve ter um limite de tamanho para o upload da foto (máximo 5MB);
- O usuário não deve pode atualizar uma despesa informando a categoria de outro usuário;
- O usuário só pode atualizar a própria despesa;
- O usuário não deve poder atualizar a despesa com a mesma categoria já em uso por ela;
- Os usuários, por padrão, recebem o cargo (permissão) de "membro";
- O usuário não deve poder visualizar despesas de outros usuários;
- O usuário não deve poder atualizar despesas de outros usuários;
- O administrador pode visualizar todos os usuários;
- Ao deletar uma conta, todas as despesas e categorias vinculadas devem ser deletadas em cascata;
- O usuário deve ter acesso aos termos de serviços/política de privacidade;
- O usuário deve ter acesso a documentação da API;
- Autenticação: dados sensível em memória - CONTEXT API;
- Redefinição de senha;
- Cadastro de despesas;
- Validação de campos com erros;
- Tratamento de campo price;
- Adicionar sidebar com botão de categoria;
- Exibição dos dados no gráfico de categorias populares;
- Limitar a quantidade de caracteres na exibição do nome do usuário;
- Exibir detalhes da despesa selecionada;
- Editar uma despesa;
- Confirmação de remoção de despesa;
- Filtro de pesquisa por id na tabela;
- Filtro de pesquisa por name na tabela;
- Filtro de pesquisa por category na tabela;
- Botão de remover filtros (limpar campos / realizar requisição novamente);
- Adicionar paginação na tabela de despesas;
- Preview do comprovante enviado;
- Acesso aos termos de serviços/privacidade;
- Exibição dos dados no gráfico de gasto no período;
- Validação de campo vazio no cadastro de categorias;
- Loading para o gráfico de gasto no período;
- Loading para o gráfico de categorias populares;
- Exibir mensagem de erro ao tentar recadastrar categoria;
- Permitir cadastrar data manualmente na despesa;
- Personalizar alerta do checkbox (browser);
- Upload de comprovante (imagem - arquivo) via form;
- O usuário deve poder importar uma planilha contendo gastos para cadastramento em lote;
- A API deve tratar as datas considerando o fuso horário do usuário/padronizar tudo em UTC no banco e fazer a conversão na camada de aplicação;
- As imagens dos comprovantes devem ser armazenadas em um serviço de Object Storage (S3/R2);
- Realizar integração com ferramenta externa de log: DataDog, NewRelic, Sentry;
- Se a planilha contiver um gasto com uma categoria que ultrapasse o limite de 15 categorias, ou se a linha estiver corrompida, o sistema deve rejeitar o lote inteiro e retornar um relatório de erros;
- Users
- PasswordResetTokens
- Expenses
- Categories
- Um usuário possui várias despesas
- Um usuário possui até 15 categorias
- Uma categoria pode possuir várias despesas
- Uma despesa pertence a uma categoria
pnpm install— instala dependências da APIdocker compose up -d— lança o serviço de banco de dados e redis como containernpx prisma migrate deploypnpm start:dev— inicia o servidor em modo watch (ambiente de desenvolvimento)pnpm build— compila o projetopnpm start— inicia o servidor compilado
pnpm test— executa os testes uma vezpnpm test:watch— executa os testes em modo watchpnpm test:coverage— executa os testes com coberturapnpm test:ui— abre a interface visual dos testes
pnpm db:studio— abre o Prisma Studiopnpm seed— popula o banco com dados iniciais (usuário administrador)
pnpm lint— verifica problemas de lintpnpm lint:fix— corrige problemas de lint automaticamentepnpm format— formata o código com Prettier
-
pnpm init -y [criar package json para construir o backend em nodejs]
-
pnpm install -D typescript @types/node tsx tsup [instalação do typescript e seus pacotes. O "tsx" é uma biblioteca pra executar o código em tempo de desenvolvimento por causa do typescript, nativamente o nodejs não compreende. Ou seja, irá converter o código para javascript rodando automaticamente. O "tsup" é uma biblioteca para gerar a build do projeto para o ambiente de produção]
-
npx tsc --init [criar arquivo "tsconfig.json" para abrigar as configurações de uso do typescript]
-
pnpm install dotenv [responsável pelo parseamento dos dados inseridos no ".env" para uso na aplicação]
-
pnpm install zod [responsável pela validação dos dados do ".env"]
-
pnpm create @eslint/config@latest [instalação do ESLint para correções de problemas no código, exibe uma série de perguntas sobre]
-
renomear "eslint.config.mts" para "eslint.config.mjs" [o ESLint 10 tem bug com arquivos ".mts", renomear para ".mjs" resolve sem precisar de dependências extras]
-
pnpm install -D prettier eslint-config-prettier [o "prettier" formata o código automaticamente. O "eslint-config-prettier" desativa regras do ESLint que conflitam com o Prettier]
-
criar ".prettierrc.js" na raiz do projeto [arquivo de configuração do Prettier com as preferências de formatação do código. Usar ".js" ao invés de ".prettierrc" para suportar comentários explicativos nas opções]
-
criar ".prettierignore" na raiz do projeto [arquivo para o Prettier ignorar pastas como "node_modules" e "build" durante a formatação]
-
adicionar "ignores" no "eslint.config.mjs" [configura o ESLint para ignorar as pastas "node_modules" e "build" durante a análise]
-
adicionar "baseUrl" e "paths" no "tsconfig.json" [configura o alias "@" para importações absolutas a partir da pasta "src", evitando caminhos relativos longos como "../../"]
-
pnpm install prisma -D [instala o Prisma CLI como dependência de desenvolvimento]
-
npx prisma -h [exibe todos os comandos disponíveis do Prisma CLI]
-
npx prisma init [inicializa o Prisma no projeto, criando a pasta "prisma/" com o "schema.prisma", o ".env" com a variável "DATABASE_URL" e o "prisma.config.ts"]
-
pnpm install @prisma/client [instala o Prisma Client para acesso ao banco de dados com tipagem]
-
npx prisma generate [gera o Prisma Client a partir do schema. No Prisma 7, gera na pasta "generated/prisma" ao invés da "node_modules"]
-
npx prisma --version [exibe a versão atual do Prisma instalada no projeto]
-
pnpm install @prisma/adapter-pg [instala o adaptador do PostgreSQL para o Prisma 7. A partir da v7, o Prisma separou o core do driver de banco, exigindo um adaptador explícito na instanciação do PrismaClient]
-
docker -v [verifica se o Docker está instalado e exibe a versão]
-
docker ps [lista os containers em execução]
-
docker ps -a [lista todos os containers, incluindo os parados]
-
docker run [cria e inicia um container]
-
docker rm [remove um container parado]
-
docker run --name api-cycle-finance-pg -e POSTGRESQL_USERNAME=docker -e POSTGRESQL_PASSWORD=docker -e POSTGRESQL_DATABASE=apicyclefinance -p 5432:5432 bitnami/postgresql [cria e inicia o container do PostgreSQL com usuário "docker", senha "docker" e banco "apicyclefinance" na porta 5432. A imagem utilizada é a "bitnami/postgresql"]
-
configurar DATABASE_URL no ".env" [após criar o container, atualizar a variável no ".env" com a string de conexão: postgresql://docker:docker@localhost:5432/apicyclefinance]
-
criar "docker-compose.yml" na raiz do projeto [arquivo para orquestrar os containers do projeto. Define o serviço do PostgreSQL com a imagem "bitnami/postgresql", usuário "docker", senha "docker", banco "apicyclefinance" e porta 5432]
-
docker compose up -d [sobe os containers definidos no "docker-compose.yml" em segundo plano]
-
pnpm add bcryptjs [responsável pelo hash da senha do usuário que está se cadastrando]
-
pnpm install vitest vite-tsconfig-paths -D [biblioteca para escrever testes unitários, integração e end to end]
-
pnpm install @vitest/coverage-v8 [biblioteca para exibir cobertura de testes nos casos de uso, validar se algum item não foi testado, deve utilizar no package: "test:coverage": "vitest run --coverage"]
-
pnpm install -D @vitest/ui [uma inteface visual que destaca o relacionamento dos testes com os módulos da aplicação, deve utilizar no package: "test:ui": "vitest --ui"]
-
set "DATABASE_URL=" && npx prisma migrate deploy [subir tabelas na hospedagem do banco de dados]
-
Depreciações no tsconfig.json (TypeScript 5+)
- Avisos de funções descontinuadas que deixarão de funcionar no TypeScript 7.0 (como baseUrl e moduleResolution: "node"):
- Solução: Removar a propriedade "baseUrl", ajustar os mapeamentos de caminhos (paths) para o formato relativo "./" e atualize a estratégia de resolução de módulos:
JSON { "compilerOptions": { "module": "NodeNext", moduleResolution": "NodeNext", "paths": { ["./src/*"] } } }
- Avisos de funções descontinuadas que deixarão de funcionar no TypeScript 7.0 (como baseUrl e moduleResolution: "node"):
(Nota: Utilizar "moduleResolution": "Bundler", pois o build do projeto seja gerenciado pelo empacotador tsup).
-
pnpm install @fastify/swagger @fastify/swagger-ui [biblioteca swagger pare realizar o mapeamento de entrada e saída de dados, realizando uma documentação dos endpoints da API]
-
pnpm install fastify-type-provider-zod [biblioteca para realizar a integração do zod validation com a ferramenta de documentação swagger]
-
pnpm add tailwindcss @tailwindcss/vite [instalação do tailwindcss no projeto, sendo necessário realizar modificações em vite.config.ts para aceitar "@" como raiz]
-
pnpm i @types/node -D [para que o vite consiga trabalhar com aliases de importação no momento de build]
-
pnpm dlx shadcn-ui@latest init
-
npx shadcn@latest init [instalação da biblioteca de componentes shadcn-ui e uso do cli para iniciar arquivo de configurações]
-
pnpm install localforage match-sorter sort-by [instalação do react router dom mais dependencias de desenvolvimento]
-
pnpm create @eslint/config@latest [gera a base do arquivo de configuração e instala as dependências iniciais do ESLint e TypeScript]
-
pnpm install -D prettier eslint-config-prettier prettier-plugin-tailwindcss eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh [instala apenas o que o CLI do ESLint não instala: Prettier, suporte para Tailwind e plugins específicos de React Hooks/Refresh]
-
configurar "eslint.config.ts" com plugins de React e Prettier [é necessário configurar o arquivo (que pode ser mantido em .ts nas versões atuais) para injetar os plugins "react-hooks", "react-refresh" e o "eslint-config-prettier". Isso garante a aplicação das regras do React 19 e evita que o ESLint brigue com a formatação do Prettier]
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import pluginReact from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import prettierConfig from "eslint-config-prettier";
export default tseslint.config(
{ ignores: ["dist", "build", "node_modules"] },
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
react: pluginReact,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...pluginReact.configs.flat.recommended.rules,
...reactHooks.configs.recommended.rules,
"react/react-in-jsx-scope": "off",
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
},
prettierConfig,
);- criar ".prettierrc.mjs" na raiz do projeto [arquivo de configuração do Prettier usando padrão ESM. Inclui o "prettier-plugin-tailwindcss" para habilitar a ordenação automática das classes do Tailwind no atributo className ao salvar o arquivo]
/** @type {import("prettier").Config} */
export default {
semi: true,
singleQuote: true,
trailingComma: 'all',
printWidth: 80,
tabWidth: 2,
plugins: ['prettier-plugin-tailwindcss'],
};- criar ".prettierignore" na raiz do projeto [arquivo para o Prettier ignorar diretórios como "node_modules", "dist" e "build", evitando processamento desnecessário e lentidão durante a formatação automática]
node_modules
dist
build
- configurar "resolve.alias" no "vite.config.ts" [utiliza o módulo "path" do Node.js para mapear o caractere "@" diretamente para a pasta "src", permitindo resolver importações absolutas de forma manual sem dependências extras]
export default defineConfig({
plugins: [
tailwindcss(),
react(),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
});- adicionar "baseUrl" e "paths" no "tsconfig.json" [configuração obrigatória para que o TypeScript e o VS Code reconheçam o alias "@", habilitando o preenchimento automático (autocomplete) e a navegação entre arquivos]
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
}- configurar ".vscode/settings.json" na pasta do projeto [configuração de workspace que define o Prettier como formatador padrão e ativa o "source.fixAll.eslint". Isso faz com que o VS Code corrija erros de lint e organize as classes do Tailwind automaticamente ao salvar (Ctrl + S)]
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
}- pnpm i -D eslint-plugin-simple-import-sort [organiza importações dos arquivos no projeto]
plugins: {
react: pluginReact,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
"simple-import-sort": simpleImportSort,
},
rules: {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
},-
pnpm i react-hook-form zod @hookform/resolvers [lidar com formulário no react utilizando validação com o zod e habilitando integração entre as ferramentas com resolvers]
-
pnpm install sonner [biblioteca de componente toast já estilizado e pronto para uso]
-
pnpm i recharts [biblioteca para construção de gráficos do dashboard]
-
pnpm install axios []
-
pnpm install zod []
-
pnpm install @tanstack/react-query []


