📚 Módulo 02: Backend - Setup do Projeto, Prisma Migrate e Seeding

Neste módulo, realizaremos a inicialização física da API backend com o NestJS CLI, faremos a configuração do Prisma Client conectando-se a um banco de dados local ou na nuvem (Neon PostgreSQL) e criaremos um roteiro passo a passo para versionar o banco e semeá-lo com dados de testes via scripts automáticos em TypeScript.


🏛️ O Fluxo de Injeção de Dependências (DI)

No NestJS, a comunicação entre as camadas segue um fluxo arquitetural limpo através da Injeção de Dependências, isolando responsabilidades.

flowchart LR
    classDef nest fill:#ea2845,stroke:#3b0713,stroke-width:2px,color:#fff;
    classDef db fill:#003545,stroke:#001f29,stroke-width:2px,color:#fff;

    A[Rota /categorias] --> B(CategoriaController):::nest
    B -->|DI| C{CategoriaService}:::nest
    C -->|DI| D[PrismaService]:::nest
    D --> E[(PostgreSQL)]:::db

🛠️ 1. Inicializando o Projeto Backend com NestJS e Prisma

O primeiro passo é gerar a estrutura base do framework. Os comandos abaixo criam o projeto NestJS e instalam as dependências necessárias para a API REST e para a comunicação com o banco:

# 1. Instalar o NestJS CLI globalmente
npm install -g @nestjs/cli

# 2. Gerar o projeto base (Selecione npm como gerenciador de pacotes)
nest new tecloja-backend

# 3. Entrar na pasta do projeto
cd tecloja-backend

# 4. Instalar o Prisma CLI como dependência de desenvolvimento
npm install prisma --save-dev

# 5. Instalar o Prisma Client (produção) e Bcrypt para senhas seguras
npm install @prisma/client bcrypt
npm install @types/bcrypt --save-dev

# 6. Inicializar a estrutura do Prisma
npx prisma init

O comando npx prisma init gerará uma pasta chamada prisma/ com o arquivo schema.prisma e criará um arquivo .env na raiz do projeto.


🔑 2. Configurando Variáveis de Ambiente e Prisma Schema

Abra o arquivo .env gerado na raiz e configure sua string de conexão com o banco de dados do Neon PostgreSQL (ou Docker local):

# .env
DATABASE_URL="postgresql://tecloja_owner:senha_segura@ep-neon-pool.us-east-2.aws.neon.tech/tecloja_db?sslmode=require"
PORT=3000
JWT_SECRET="sua_chave_secreta_super_forte_para_gerar_tokens_jwt"

Copie as definições físicas do Módulo 01 no arquivo prisma/schema.prisma criado na sua máquina.


🚀 3. Executando as Migrações de Banco de Dados (Prisma Migrate)

Com as variáveis configuradas e o mapeamento concluído, criaremos e executaremos nossa primeira migração física para estruturar as tabelas do banco de dados na nuvem:

# Executa e versiona a migração gerando os códigos SQL físicos equivalentes no banco
npx prisma migrate dev --name inicializacao_banco

O Prisma Migrate irá:

  1. Comparar as definições do seu schema.prisma com o estado físico atual do banco.
  2. Gerar um arquivo SQL versionado e armazená-lo dentro da pasta prisma/migrations/.
  3. Executar o script SQL no banco na nuvem criando as tabelas fisicamente.
  4. Gerar dinamicamente os tipos TypeScript baseados no banco dentro do seu pacote node_modules/@prisma/client.

🌾 4. Programando o Script de Carga de Dados (Seeding)

Para carregar dados iniciais de catálogo e usuários administrativos para testes locais e deploys rápidos, criaremos um script de seeding em TypeScript.

Crie um arquivo chamado seed.ts dentro do diretório prisma/:

// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcrypt';

const prisma = new PrismaClient();

async function main() {
  console.log('🌱 Iniciando seeding do banco de dados...');

  // 1. Limpar banco para evitar duplicidade de registros em novos testes
  await prisma.itemPedido.deleteMany();
  await prisma.pedido.deleteMany();
  await prisma.produto.deleteMany();
  await prisma.categoria.deleteMany();
  await prisma.usuario.deleteMany();
  await prisma.papel.deleteMany();
  await prisma.cliente.deleteMany();

  // 2. Semear Papéis (Roles)
  const papelAdmin = await prisma.papel.create({ data: { nome: 'ADMIN' } });
  const papelUser = await prisma.papel.create({ data: { nome: 'USER' } });
  console.log('✅ Papéis criados.');

  // 3. Semear Usuários Administrativos
  const senhaCriptografadaAdmin = await bcrypt.hash('admin123', 10);
  const senhaCriptografadaUser = await bcrypt.hash('user123', 10);

  await prisma.usuario.create({
    data: {
      username: 'admin@tecloja.com',
      password: senhaCriptografadaAdmin,
      papelId: papelAdmin.id,
    },
  });

  await prisma.usuario.create({
    data: {
      username: 'cliente@tecloja.com',
      password: senhaCriptografadaUser,
      papelId: papelUser.id,
    },
  });
  console.log('✅ Usuários de teste semeados (senhas: admin123 e user123).');

  // 4. Semear Categorias
  const catSmartphones = await prisma.categoria.create({ data: { nome: 'Smartphones' } });
  const catNotebooks = await prisma.categoria.create({ data: { nome: 'Notebooks' } });
  console.log('✅ Categorias de catálogo semeadas.');

  // 5. Semear Produtos
  await prisma.produto.createMany({
    data: [
      {
        nome: 'iPhone 15 Pro Max',
        descricao: 'Smartphone Apple com tela Super Retina XDR e câmera de 48MP.',
        preco: 8999.00,
        estoque: 15,
        categoriaId: catSmartphones.id,
      },
      {
        nome: 'Galaxy S24 Ultra',
        descricao: 'Smartphone Samsung com recursos avançados de IA e câmera de 200MP.',
        preco: 7999.00,
        estoque: 20,
        categoriaId: catSmartphones.id,
      },
      {
        nome: 'MacBook Air M3',
        descricao: 'Notebook Apple ultrafino com processador M3 de 8 núcleos.',
        preco: 11499.00,
        estoque: 8,
        categoriaId: catNotebooks.id,
      },
      {
        nome: 'Dell XPS 13 Plus',
        descricao: 'Notebook Dell Premium com tela InfinityEdge 4K e Intel Core i7.',
        preco: 9499.00,
        estoque: 5,
        categoriaId: catNotebooks.id,
      },
    ],
  });
  console.log('✅ Catálogo de eletrônicos cadastrado com sucesso.');

  // 6. Semear Cliente Padrão para compras
  await prisma.cliente.create({
    data: {
      nome: 'José da Silva',
      email: 'jose@gmail.com',
      cpf: '123.456.789-00',
    },
  });
  console.log('✅ Cliente de testes criado.');
  console.log('🚀 Seeding finalizado com sucesso!');
}

main()
  .catch((e) => {
    console.error('❌ Erro no seeding:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

⚙️ Habilitando o Seeding no NestJS

Para ensinar o Prisma CLI a interpretar seu script em TypeScript nativamente, abra o arquivo package.json na raiz do projeto e insira a propriedade "prisma" no final das configurações do arquivo JSON:

  // package.json (no final do arquivo)
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  }

Agora, execute o semeador de forma automatizada no terminal:

# Comando nativo do Prisma CLI para carregar o seed.ts
npx prisma db seed


✅ Pré-Requisitos deste Módulo

Antes de passar para a validação de DTOs e controle de transações, certifique-se de que:


🤔 Por que fizemos assim?


🔍 Checkpoint

  1. Versionamento do Banco: Confirme se a pasta prisma/migrations foi criada contendo uma subpasta versionada com o arquivo SQL de criação de tabelas.
  2. Massa de Dados Semeda: Execute o comando npx prisma db seed no terminal. Certifique-se de que a mensagem 🚀 Seeding finalizado com sucesso! é impressa sem nenhuma falha de restrição ou chave.
  3. Acesso ao Banco: Abra o gerenciador de banco de dados (ex: DBeaver ou painel do Neon) e confirme se as tabelas foram devidamente populadas com os produtos e categorias informados.

⚠️ Erros Comuns

Erro Causa Solução
O comando prisma migrate dev falha ao tentar conectar no banco A variável DATABASE_URL no arquivo .env está incorreta, com credenciais inválidas ou o banco de dados está offline. Revise detalhadamente a string de conexão no .env. Se estiver usando o Neon, certifique-se de incluir a diretiva sslmode=require no final da URL.
Erro Cannot find module 'ts-node' ao rodar o comando de seeding O executável ts-node não está instalado no projeto local como dependência ou não está disponível globalmente. Instale o executável nas dependências de desenvolvimento do projeto executando o comando npm install ts-node --save-dev.
Erro de restrição de chave estrangeira (Foreign key constraint failed) ao executar o script de seed A ordem de deleção (deleteMany()) no início do seed está violando a integridade referencial. Certifique-se de apagar primeiro as tabelas filhas (que dependem de IDs de terceiros, como ItemPedido e Pedido) antes de apagar as tabelas pai (Produto, Categoria, Cliente).

🏁 Conclusão

Com o banco de dados carregado e as migrações criadas com sucesso, nosso próximo passo é proteger a integridade lógica da nossa aplicação NestJS.

No Módulo 03, aprenderemos a realizar a validação de entrada de dados de forma automática em tempo de execução utilizando DTOs e Pipes do class-validator, e trataremos as exceções do banco de dados interceptando falhas HTTP e convertendo-as em JSONs elegantes através dos Filtros de Exceção globais do NestJS.


Voltar para o Sumário