Início Profile Projeto
Avatar de

Livio Lopes de Alvarenga

Projeto FULLSTACK DT Money Gestão Financeira com Nextjs 13 App Router, React, Typescript, Tailwindcss, Axios, Docker, Prisma, Vitest, API Rest SOLID Nextjs e PWA.

  • NodeJs
  • TypeScript
  • JavaScript
  • Typescript
  • Nextjs
  • React
  • React Hook Form
  • Tailwind
  • ZodJs
  • Axios
  • Docker
  • Prisma
  • MySql
  • Vitest
  • EsLint
  • prettier.

Projeto FULLSTACK DT Money Gestão Financeira com Nextjs 13 App Router, React, Typescript, Tailwindcss, Axios, Docker, Prisma, Vitest, API Rest SOLID Nextjs e PWA.

SobreVitrine DevTecnologiasInstalaçõesFuncionalidadesDeployGood habitsAutorLicença

 

DT Money Tablet

DT Money mobile

DT Money pwa

💻 Sobre o projeto

🚀 Olá a todos! Meu nome é Livio Alvarenga e gostaria de apresentar a vocês o projeto dt-money-finance, uma aplicação que criei para gerenciamento financeiro.

Objetivo:

O principal objetivo ao desenvolver este projeto foi explorar e integrar o Next.js 13 com o App Router, uma API integrada e funcionalidades de Progressive Web App (PWA). A combinação destes recursos permite não só uma integração mais suave entre o front-end e o back-end, mas também uma experiência offline otimizada, tornando a aplicação acessível mesmo quando o usuário não possui conexão com a internet.

Funcionalidades Principais:

  • Interface Responsiva: A aplicação foi projetada com uma abordagem "mobile first", garantindo que funcione perfeitamente em dispositivos de todos os tamanhos.

  • Gestão de Transações: Os usuários podem facilmente:

    • Adicionar novas transações.
    • Remover transações existentes.
    • Editar detalhes das transações.
  • Resumo Financeiro: A aplicação oferece um resumo claro das entradas, saídas e o saldo total.

  • Tabela Paginada de Transações: Para uma navegação eficiente e visualização das transações.

  • Filtro de Transações: Uma ferramenta poderosa que permite aos usuários pesquisar transações por descrição, preço ou categoria.

Especificações Técnicas:

  • API REST com SOLID: O princípios de design de software SOLID foram fundamentais para garantir que a API fosse escalável, manutenível e robusta. Isso garante que cada parte do sistema tenha uma responsabilidade única, tornando-o menos suscetível a erros e mais fácil de modificar ou expandir no futuro.

  • Testes: Utilizei o Vitest para realizar testes unitários e end-to-end (e2e). Isso assegura que cada funcionalidade da aplicação funcione como esperado e que quaisquer alterações ou adições ao código não quebrem funcionalidades existentes.

  • Práticas de Desenvolvimento Modernas: O projeto foi desenvolvido utilizando várias ferramentas e práticas recomendadas, como Zod para validação de dados, Eslint & Prettier para padronização do código, TailwindCSS para estilização, e Prisma como ORM.

Conclusão:

O dt-money-finance é mais do que apenas uma ferramenta de gerenciamento financeiro. É um testemunho do que é possível quando as melhores práticas de desenvolvimento são combinadas com tecnologias modernas. Com a integração do PWA, os usuários podem esperar uma experiência de usuário mais consistente e confiável, independentemente de sua conexão com a Internet. Foi um desafio, mas estou orgulhoso do resultado e espero que possa ser uma ferramenta útil para muitos. Agradeço pela oportunidade de compartilhar este projeto com vocês e estou aberto a quaisquer perguntas ou feedbacks!

 

issue site dt-money-finance total amount of programming languages used in the project most used language in the projects repository size

deploy badge Vercel

 


 

📺 Vitrine Dev

🪧 Vitrine.Dev
Nome Projeto FULLSTACK DT Money Gestão Financeira com Nextjs 13 App Router, React, Typescript, Tailwindcss, Axios, Docker, Prisma, Vitest, API Rest SOLID Nextjs e PWA.
🏷️ Tecnologias NodeJs, TypeScript, JavaScript, Typescript, Nextjs, React, React Hook Form, Tailwind, ZodJs, Axios, Docker, Prisma, MySql, Vitest, EsLint, prettier.

 

🛠 Tecnologias

As seguintes ferramentas foram usadas na construção do projeto

 

Node.js badge TypeScript badge JavaScript badge Next.js badge React badge React Hook Form badge Radix UI badge Tailwind CSS badge ZOD badge Axios badge link projeto no figma Dotenv badge Prisma badge Docker badge MySQL badge Vitest Badge PWA Badge vscode download code formatter prettier code standardization eslint


 

⚙️ Instalações

 

Criando projeto NextJs Frontend / Backend

# Create project nodejs with npm and -y to accept all default options
npx create-next-app@latest

# What is your project named? project-Name
# Would you like to use TypeScript with this project? Yes
# Would you like to use ESLint with this project? Yes
# Would you like to use Tailwind CSS with this project? Yes
# Would you like to use `src/` directory with this project? Yes
# Use App Router (recommended)? Yes
# Would you like to customize the default import alias? No
// Create scripts in package.json
"scripts": {
  "dev": "next dev", // Start development server
  "build": "next build", // Create production build
  "start": "next start", // Start production server
  "lint": "next lint" // Run ESLint
},

Create .gitignore file

Create .npmrc file with save-exact=true to save exact version of dependencies

 

.env architecture

npm install dotenv # Install dotenv to use environment variables in NodeJs

Create .env file with all environment variables and gitignore this file

Create .env.example file with all environment variables and not gitignore this file

 

Configurando ESlint and Prettier

npm install -D @rocketseat/eslint-config # Install Rocketseat ESLint config
npm install -D prettier-plugin-tailwindcss # Install prettier plugin to use TailwindCSS

Edit .eslintrc.json file with extends Rocketseat ESLint config

{
  "extends": ["next/core-web-vitals", "@rocketseat/eslint-config/react"],
  "overrides": [
    {
      "files": ["**/*.tsx"],
      "excludedFiles": ["page.tsx", "layout.tsx", "**/api/**/*"],
      "plugins": ["import"],
      "rules": {
        "import/no-default-export": "error"
      }
    }
  ]
}

Create .eslintignore file with all ESLint ignore files

Create prettier.config.js file with plugin prettier-plugin-tailwindcss to use Prettier to format classnames of TailwindCSS

module.exports = {
  plugins: [require("prettier-plugin-tailwindcss")],
};

 

Json-Server architecture

npm install -D json-server # Install json-server to simulate API

Create db.json file with data to simulate API / database Create src/lib/json-server.js file with json-server configuration

// src/lib/json-server.js
const jsonServer = require("json-server");
const { randomUUID } = require("crypto");
const path = require("path");
const server = jsonServer.create();
const router = jsonServer.router(path.join(__dirname, "../../db.json"));
const middlewares = jsonServer.defaults({
  delay: 500,
  watch: true,
});

server.use(middlewares);
server.use(jsonServer.bodyParser);

server.use((req, res, next) => {
  // middleware to transform the price to cents
  if (req.method === "GET") {
    const originalSend = res.jsonp;
    res.jsonp = function (data) {
      // transform the transactions, if it is an array
      if (Array.isArray(data)) {
        data.forEach((transaction) => {
          transaction.price = transaction.price / 100; // transform to cents
        });
      }
      // transform the transaction, if it is an object
      else if (typeof data === "object" && data.price) {
        data.price = data.price / 100; // transform to cents
      }
      originalSend.call(this, data);
    };
  }

  // middleware to add createdAt, updatedAt and id
  if (req.method === "POST") {
    req.body.id = randomUUID();
    req.body.createdAt = new Date().toISOString();
    req.body.updatedAt = new Date().toISOString();
    req.body.price = req.body.price * 100; // transform to cents
  }

  // middleware to add updatedAt
  if (req.method === "PUT" || req.method === "PATCH") {
    req.body.updatedAt = new Date().toISOString();
    req.body.price = req.body.price * 100; // transform to cents
  }
  // Continue to JSON Server router
  next();
});

// Custom routes - to get summary
server.get("/transactions/summary", (req, res) => {
  const transactions = router.db.get("transactions").value();

  const summary = transactions.reduce(
    (acc, transaction) => {
      const priceInCents = transaction.price / 100; // transform to cents

      if (transaction.type === "income") {
        acc.income += priceInCents;
        acc.total += priceInCents;
      } else {
        acc.outcome += priceInCents;
        acc.total -= priceInCents;
      }

      return acc;
    },
    {
      income: 0,
      outcome: 0,
      total: 0,
    }
  );

  res.jsonp(summary);
});

server.get("/transactions/count", (req, res) => {
  const transactions = router.db.get("transactions").value();

  const count = transactions.length;
  res.jsonp({ count });
});

server.use(router);

server.listen(3333, () => {
  console.log("⚡ JSON Server is running at http://localhost:3333 ⚡");
});

Agora o json server irá salvar datas createdAt e updatedAt automaticamente com o valor Date.now() quando for feito um POST, PUT or PATCH.

Adicionei também um GET na rota /transactions/summary para passar o total income, outcome e total de todas as transações. Desta forma não preciso fazer um reduce no front-end para calcular o total de income, outcome e total. Fazer isso no front-end é uma má prática, pois o front-end não deve ter essa responsabilidade.

Adicionei também um GET na rota /transactions/count para passar o total de transações.

NEXT_PUBLIC_URL_API="http://localhost:3333/transactions"
// Create scripts in package.json
"scripts": {
  "dev:server": "node src/lib/json-server.js",
},

Além de modificar a variável de ambiente NEXT_PUBLIC_API_URL deve rodar o script dev:server para simular a API na porta 3333.

 

API Nextjs com json de database architecture

Iniciei o projeto com json-server para simular uma API. E assim foi possível finalizar o front-end.

Porem o objetivo era criar uma API Rest no NextJs 13 com App router e utilizar o Prisma para conectar com o banco de dados MariaDB (MySQL). Assim para testar a funcionalidade da API com Next mantive o database em json e criei uma API transactions-json com os mesmos endpoints do json-server. Assim foi possível testar a funcionalidade da API com Next e manter o front-end funcionando para posteriormente conectar com o banco de dados MariaDB (MySQL).

Para testar esta funcionalidade, deve se modificar a variável de ambiente NEXT_PUBLIC_API_URL, assim não terá que rodar o script dev:server para simular a API na porta 3333.

NEXT_PUBLIC_URL_API="http://localhost:3000/api/transactions-json"

A API esta localizada em src/app/api/transactions-json.

Mesmo apos desenvolver a API Rest com NextJs e SOLID, manterei tanto o json-server quanto o transactions-json para demostrar a evolução do projeto.

 

Docker architecture

Instalando Docker https://docs.docker.com/get-docker/

# Command to run postgres image database without docker-compose. This image is from bitnami (https://hub.docker.com/r/bitnami/postgresql)
docker run --name api-solid-pg -e POSTGRESQL_USERNAME=docker -e POSTGRESQL_PASSWORD=docker -e POSTGRESQL_DATABASE=apisolid -p 5432:5432 bitnami/postgresql
# We don't use this command because we use docker-compose to run all images, this command is just to show how to run a single image
// Create scripts in package.json
"scripts": {
  "start-docker": "docker-compose up -d", // Create script to run docker-compose in background
  "stop-docker": "docker-compose stop" // Create script to stop docker-compose
},

Create docker-compose.yml file with all docker-compose config

Create .dockerignore file with all docker-compose ignore files

# Commands to use docker
docker ps # List all running containers
docker ps -a # List all containers
docker images # List all images
docker pull mysql # Pull mysql image database (if you want to use mysql)
docker pull postgres # Pull postgres image database (if you want to use postgres)
docker pull mariadb # Pull mariadb image database (if you want to use mariadb)
docker start <container_id or container_name> # <container_id> Start container with id | <container_name> Start container with name
docker stop <container_id or container_name> # <container_id> Stop container with id | <container_name> Stop container with name
docker pause <container_id or container_name> # <container_id> Pause container with id | <container_name> Pause container with name
docker unpause <container_id or container_name> # <container_id> Unpause container with id | <container_name> Unpause container with name
docker rm <container_id or container_name> # <container_id> Remove container with id | <container_name> Remove container with name
docker logs <container_id or container_name> # <container_id> Show logs of container with id | <container_name> Show logs of container with name
docker inspect <container_id or container_name> # <container_id> Show all information of container with id | <container_name> Show all information of container with name
docker-compose --version # Show docker-compose version
docker-compose up # Run docker-compose, show logs in terminal
docker-compose up -d # Run docker-compose in background, not show logs in terminal
docker-compose start # Start o docker-compose
docker-compose stop # Stop o docker-compose, not remove all data in database
docker-compose down # Stop and remove o docker-compose, obs remove all data in database

 

PrismaJs database architecture

npm install prisma # Install Prisma
npm i prisma-erd-generator @mermaid-js/mermaid-cli # Install Prisma ERD generator
npm i @prisma/client # Install Prisma client

npx prisma init # Create prisma folder with prisma.schema and prisma folder
npx prisma migrate dev # Enter a name for the new migration: » created tab Habits
npx prisma studio # Open Prisma Studio in browser
npx prisma studio -b chrome -p 5173 # Open Prisma Studio in browser with specific port and browser
npx prisma generate # Generate diagram in prisma folder
npx prisma db seed # Seed database with data in prisma/seed.ts - Populate database with data for development
// Add generator in prisma.schema
generator erd {
  provider = "prisma-erd-generator"
}
// Create scripts in package.json
"scripts": {
  "studio": "npx prisma studio -b chrome -p 5173", // Create script to open Prisma Studio in browser with specific port and browser
  "generate": "npx prisma generate", // Create script to generate diagram in prisma folder
  "migrate": "npx prisma migrate dev", // Create script to migrate database
  "seed": "npx prisma db seed" // Create script to seed database
},
"prisma": {
    "seed": "tsx prisma/seed.ts" // Create script to seed database
},

Em /prisma existe um arquivo seedDb.json e o seed.ts. Ambos são utilizados para popular o banco de dados com dados para desenvolvimento.

Environment variables to databases mysql

 

Create NEXT_PUBLIC_DATABASE_URL in .env and .env.example file with MySql

NEXT_PUBLIC_DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE_NAME"

NEXT_PUBLIC_SHADOW_DATABASE_URL="mysql://OTHER_USER:PASSWORD@HOST:PORT/OTHER_DATABASE_NAME"

I used mysql, but you can use postgresql, mariadb, sqlite, sqlserver, mongodb, etc.

// Add datasource in prisma.schema to mysql database
datasource db {
  provider          = "mysql"
  url               = env("NEXT_PUBLIC_DATABASE_URL")
  shadowDatabaseUrl = env("NEXT_PUBLIC_SHADOW_DATABASE_URL")
}
// https://www.prisma.io/docs/concepts/components/prisma-migrate/shadow-database
// Exist provider that user cannot have access to create a database, to resolve this problem, you can use shadow database

 

Vitest architecture

npm install -D vitest # Install Vitest
npm install -D @vitest/coverage-v8 # Install coverage vitest
npm install -D @vitest/ui # Install vitest ui
npm install -D supertest # Install supertest to test http requests
npm install -D @types/supertest # Install types supertest

Create vitest.config.ts file with all vitest config

import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default defineConfig({
  plugins: [tsconfigPaths()],
});
// now vitest can understand tsconfig paths
// Create scripts in package.json
"scripts": {
  "test": "vitest run --dir src/use-cases", // Create script to run vitest
  "test:watch": "vitest --dir src/use-cases", // Create script to run vitest in watch mode
  "test:ui": "vitest --ui --no-threads", // Create script to run vitest with ui in browser with no-threads
  "test:coverage": "vitest run --coverage --no-threads", // Create script to run vitest with coverage in browser with no-threads
  "test:e2e": "vitest run --dir src/http/controllers --no-threads", // Create script to run vitest with e2e with no-threads
  "test:safety": "vitest run --dir src/http/middlewares" // Create script to run vitest with safety
},

Foram criados 79 testes: sendo 55 e2e em 7 arquivos, 1 de segurança tentativa de Ataques DoS e DDoS e 23 testes unitários em 7 arquivos. Todas as rotas foram testadas, e todos os casos de uso foram testados.

deploy badge Vercel

Observe que testes e2e, ui e coverage não utilizam threads, pois não foi possível criar um vitest-environment-prisma para rodar os teste e2e isolados, sendo assim utilizamos o mesmo banco de dados para todos os testes, e isso pode gerar problemas de concorrência. Por isso não utilizamos threads.

Estamos usando uma API interna do NextJs e não consegui que o vitest reconhecesse o vitest-environment-prisma. Por isso o desafio foi criar testes e2e que apos cada teste ele limpasse os dados criados pelos testes.

Como a API inicia junto com a aplicação Nextjs, sendo assim mesmo trocando a variável de ambiente NEXT_PUBLIC_DATABASE_URL apos cada teste, a API não reconhece a troca da variável de ambiente. Por mais este motivo optei por realizar os testes e2e no mesmo banco de dados de desenvolvimento.

O preço a ser pago é não rodar os testes e2e em paralelo, pois não podemos utilizar threads. Com isso perdemos um pouco de performance, mas ganhamos em confiabilidade. Neste trade-off optei por confiabilidade.

Poderia criar uma API SOLID REST isolada, mas o objetivo era criar uma API REST com NextJs 13 e App Router. Assim optei por utilizar a API interna do NextJs.

 

Proteções Implementadas:

  • Rate Limiting: Meu aplicativo possui um sistema de limitação de taxa para evitar ataques de inundação e prevenir sobrecarga do servidor. Isso é essencial para combater ataques DoS (Denial-of-Service) e DDoS (Distributed Denial-of-Service).

  • Validações de Parâmetros de Entrada: Meus testes asseguram que os parâmetros de entrada estão sendo corretamente validados. Isso é crucial para prevenir vulnerabilidades como SQL injection, garantindo que entradas mal-intencionadas sejam rejeitadas.

  • Proteção contra SQL Injection: Implementei testes específicos para detectar tentativas de injeção SQL em vários parâmetros. Isso é vital para impedir que atacantes executem comandos SQL não autorizados no banco de dados do meu aplicativo.

  • Erros de Validação Amigáveis: Utilizando o ZodError, faço questão de retornar mensagens de erro claras e amigáveis. Isso ajuda a ocultar detalhes internos do sistema, mantendo uma boa prática de segurança.

  • Tratamento de Erros: Graças ao middleware de tratamento de erros, posso ter certeza de que erros não tratados não causarão instabilidades no aplicativo nem revelarão informações sensíveis.

 

Sem mais delongas, let's code! 🚀🚀🚀

 

Acessibilidade architecture

A acessibilidade é um dos pilares do desenvolvimento web. Por isso, é importante que o projeto seja acessível para todos os usuários. Para isso, utilizei o Radix UI para criar componentes acessíveis, como o Modal e o RadioGroup. Também me preocupei com uma paleta de cores que atendesse aos padrões de acessibilidade.

Utilizei tags semânticas para melhorar a acessibilidade do projeto. Além de boas praticas de uso dos atributos alt, title e aria-label...

npm install @radix-ui/react-radio-group # Install Radix UI to RadioGroup

npm install @radix-ui/react-dialog # Install Radix UI to Modal

 

Others libraries

npm install zod # Install zod to use types in NodeJs and validate data

npm install clsx # Install clsx to generate dynamic classnames

npm install react-hot-toast # Install react-hot-toast to use toast notifications

npm install -D tsx # Install tsx to use typescript in NodeJs (run seed on prisma)

 

⚙️ Funcionalidades

RF - Requisitos Funcionais

  • Deve utilizar mobile first e ser responsivo;

deploy badge Vercel

  • Deve ser possível adicionar uma nova transação através de um modal ao clicar no botão Nova Transação;

deploy badge Vercel

  • Deve ser possível remover uma transação através de um ícone de lixeira;

deploy badge Vercel

  • Deve ser possível alterar dados de uma transação através de um modal ao clicar na linha da tabela;

deploy badge Vercel

  • Deve ser possível ter total de entradas, saídas e total;

deploy badge Vercel

  • Deve ser possível exibir as transações em uma tabela paginada;
  • Deve ser possível passar as paginas da tabela com botões de navegação;

deploy badge Vercel

  • Deve ser possível em mobile ver um titulo com total de transações;

deploy badge Vercel

  • Deve ser possível atualizar os valores de entrada, saída e total ao adicionar, remover e alterar uma transação;
  • Deve ser possível fazer uma pesquisa full de transações através de descrição, preço ou categoria. O sistema deverá funcionar a paginação somente com este filtro;
  • Deve ser possível remover o filtro após pesquisa;

deploy badge Vercel

RN - Regras de Negócio

  • O usuário não pode criar/editar transação com campos vazios e inválidos;
  • O usuário não pode criar transação com preço negativo;
  • O usuário não pode paginar a tabela com paginas negativas e nem maiores que o total de paginas;
  • Os botões de navegação/input deverão ser desativados enquanto estiver carregando os dados da API;

RNF - Requisitos Não Funcionais

  • O preço deve ser armazenado em centavos para evitar erros de precisão, recebendo o valor em reais e convertendo para centavos e vice-versa;
  • Uso de Zod para validação de dados de entrada;
  • Uso de Eslint para padronização de código;
  • Uso de Prettier para padronização de código;
  • Uso de TailwindCSS para estilização;
  • Uso de Json Server para simular uma API;
  • Uso de API Nextjs com App Router para criar uma API Rest;
  • Uso de Radix UI para Modal e RadioGroup (componentes com acessibilidade);
  • Uso de NextJs para SSR;
  • Uso de TypeScript para tipagem estática;
  • Uso de NextJs com App Router para rotas;
  • Uso Context API para compartilhar dados entre componentes;
  • Uso de CLSX para gerar classnames dinâmicos;
  • Uso de lucide-react para ícones;
  • Uso de react-hook-form para formulários;
  • Uso de @hookform/resolvers para validação de formulários;
  • Uso de axios para requisições HTTP;
  • Uso de toast para notificações;
  • Uso de Prisma para conectar com o banco de dados MariaDB (MySQL);
  • Uso de Docker para criar um container com o banco de dados MariaDB (MySQL);
  • Uso de Vitest para testes unitários e e2e;

 

🧭 Rodando a aplicação (Modo desenvolvimento) com json-server

git clone https://github.com/LivioAlvarenga/t-money-finance # Clone este repositório
cd dt-money-finance # Acesse a pasta do projeto no seu terminal/cmd
npm install # Instale as dependências

# Modificar variável de ambiente NEXT_PUBLIC_URL_API no arquivo .env para:
NEXT_PUBLIC_URL_API="http://localhost:3333/transactions"

npm run dev:server # Execute o json-server para simular uma API. A API será executada na porta:3333 - acesse http://localhost:3333
npm run dev # Execute a aplicação em modo de desenvolvimento, a aplicação será aberta na porta:3000 - acesse http://localhost:3000

🧭 Rodando a aplicação (Modo desenvolvimento) com API Nextjs com json de database

git clone https://github.com/LivioAlvarenga/t-money-finance # Clone este repositório
cd dt-money-finance # Acesse a pasta do projeto no seu terminal/cmd
npm install # Instale as dependências

# Modificar variável de ambiente NEXT_PUBLIC_URL_API no arquivo .env para:
NEXT_PUBLIC_URL_API="http://localhost:3000/api/transactions-json"

npm run dev # Execute a aplicação em modo de desenvolvimento, a aplicação será aberta na porta:3000 - acesse http://localhost:3000

🧭 Rodando a aplicação (Modo desenvolvimento) com API Nextjs com Prisma e docker com database MariaDB (MySQL)

git clone https://github.com/LivioAlvarenga/t-money-finance # Clone este repositório
cd dt-money-finance # Acesse a pasta do projeto no seu terminal/cmd
npm install # Instale as dependências

# Modificar variável de ambiente NEXT_PUBLIC_URL_API no arquivo .env para:
NEXT_PUBLIC_URL_API="http://localhost:3000/api/transactions"

npm run start-docker # Execute o docker-compose para criar um container com o banco de dados MariaDB (MySQL). O container será executado na porta:3306 - acesse http://localhost:3306

npm run dev # Execute a aplicação em modo de desenvolvimento, a aplicação será aberta na porta:3000 - acesse http://localhost:3000

🧭 Rodando a aplicação (Modo produção)

npm run build # Compilar o TypeScript em modo de produção
npm run start # Iniciar o servidor em modo de produção

🧭 Prisma

npm run studio # Iniciar o Prisma Studio para visualizar o banco de dados
npm run migrate # Criar migrations do banco de dados
npm run seed # Popular o banco de dados com dados de desenvolvimento
npm run generate # Gerar diagrama do banco de dados

🧭 Testes

npm run test # Rodar testes unitários
npm run test:watch # Rodar testes unitários em watch mode
npm run test:ui # Rodar testes unitários com vitest ui
npm run test:coverage # Rodar testes unitários com vitest coverage
npm run test:e2e # Rodar testes e2e
npm run test:safety # Rodar testes de segurança

 


 

🚀 Deploy

O deploy foi realizado na plataforma Vercel.com.

Clique aqui para ver o DT Money em ambiente de produção

As variáveis de ambiente configuradas incluem:

  • NEXT_PUBLIC_NODE_ENV
  • NEXT_PUBLIC_URL_API
  • NEXT_PUBLIC_RATE_LIMIT_MAX
  • NEXT_PUBLIC_DATABASE_URL
  • NEXT_PUBLIC_SHADOW_DATABASE_URL

Foi comentado a linha generator erd no arquivo prisma/schema.prisma, pois a lib prisma-erd-generator não funciona no ambiente de produção e esta dando conflito com o prisma no deploy na Vercel.

Foi modificado o scrip build para rodar antes o prisma generate e depois o next build.

"build": "prisma generate && next build",

O banco de dados utilizado foi o MySQL MariaDB. Foi necessário criar um banco de dados sombra (Shadow), pois o serviço utilizado para criar o banco de dados não permite a criação de um banco de dados para testes. O Prisma utiliza um banco de dados sombra para realizar seus processos de migrações (migrations) e testes.


 

✅ Good Habits

 

❗ 1 - O hook useCallBack

 

  • O que é useCallback?

useCallback é um hook do React que retorna uma versão memorizada de uma função callback que só muda se uma das dependências mudar. Ele é útil quando você tem um componente filho otimizado que depende de uma função callback do componente pai. Se você não usar o useCallback, o componente filho será re-renderizado toda vez que a função pai for re-renderizada, mesmo que a função callback não tenha mudado.

  • Qual problema o useCallback resolve?

O useCallback resolve o problema de performance de re-renderização de componentes filhos que dependem de funções callback do componente pai. Sem o useCallback, o componente filho será re-renderizado toda vez que a função pai for re-renderizada, mesmo que a função callback não tenha mudado.

Imagine que você tem um componente pai que passa uma função callback para um componente filho. Sem useCallback, uma nova função callback é criada toda vez que o componente pai é renderizado. Isso significa que o componente filho também é renderizado toda vez que o componente pai é renderizado porque a função callback passada para ele é considerada uma nova prop.

Agora, isso pode não ser um problema se a renderização do componente filho for barata. No entanto, se a renderização do componente filho for cara ou se o componente filho estiver otimizado (por exemplo, com React.memo ou shouldComponentUpdate), você terá renderizações desnecessárias.

useCallback resolve esse problema, criando uma versão memorizada da função callback que só muda se uma das dependências mudar. Isso significa que, se as dependências não mudarem, a mesma função callback será passada ao componente filho, evitando renderizações desnecessárias.

 

Tudo certo, mas show me the code!

 

import React, { useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    console.log("Criando uma nova função increment.");
    setCount(count + 1);
  };

  return (
    <div>
      Count: {count}
      <Button onClick={increment} />
    </div>
  );
}

const Button = React.memo(({ onClick }) => {
  console.log("Renderizando o componente Button.");
  return (
    <button type="button" onClick={onClick}>
      Increment count
    </button>
  );
});

export default App;

No exemplo acima, o componente Button é otimizado com React.memo, o que significa que ele só será renderizado se suas props mudarem. No entanto, como a função increment é recriada toda vez que o App é renderizado, Button também será renderizado toda vez que App for renderizado.

 


 

🦸 Autor

Olá, eu sou Livio Alvarenga, Engenheiro de Produção | Dev Back-end e Front-end. Sou aficcionado por tecnologia, programação, processos e planejamento. Uni todas essas paixões em uma só profissão. Dúvidas, sugestões e críticas são super bem vindas. Seguem meus contatos.

 

portfólio livio alvarenga perfil LinkedIn livio alvarenga perfil twitter livio alvarenga perfil Instagram livio alvarenga perfil Facebook livio alvarenga perfil YouTube livio alvarenga

perfil vitrinedev livio alvarenga


 

📝 Licença

Este projeto é MIT licensed.

#CompartilheConhecimento