Pular para o conteúdo
Geral

Construa do zero um projeto full‑stack com Node.js e React

Admin4 min de leitura
Construa do zero um projeto full‑stack com Node.js e React

Construa do zero um projeto full‑stack com Node.js e React

Objetivo: Demonstrar, de forma hands‑on, como iniciar, desenvolver e publicar um aplicativo completo que combina um backend em Node.js, um banco PostgreSQL, um frontend React e automação de entrega contínua usando Docker e GitHub Actions.

Tecnologia e Inovação

Introdução

A criação de um produto digital costuma envolver várias camadas: servidor, banco de dados, interface de usuário e processos de publicação. Embora existam inúmeras ferramentas, montar tudo “na unha” ainda é a melhor maneira de entender as interdependências e garantir que cada parte esteja configurada de forma otimizada.

Neste tutorial, você vai:

  • Definir a estrutura de diretórios de um projeto full‑stack.
  • Implementar um backend leve com Express e Sequelize.
  • Conectar o servidor ao PostgreSQL.
  • Construir um frontend React usando Vite.
  • Containerizar a aplicação com Docker Compose.
  • Automatizar o deploy com GitHub Actions.
  • Ao final, você terá um repositório pronto para ser clonado, executado localmente e enviado para produção com apenas um clique.


    1. Preparando o ambiente

    Antes de escrever código, certifique‑se de que as seguintes ferramentas estejam instaladas:

    FerramentaVersão mínimaComo instalar
    Node.js18.x
    Docker Desktop24.x
    Git2.30+
    VS Code (ou outro editor)

    Dica: Use o nvm (Node Version Manager) para alternar entre versões do Node sem conflitos.

    # Verificando versões
    

    node -v docker --version git --version


    2. Estrutura de pastas e configuração do backend

    Crie a pasta raiz do projeto e inicie o repositório Git:

    mkdir fullstack-node-react
    

    cd fullstack-node-react git init

    2.1. Backend

    mkdir backend
    

    cd backend npm init -y npm install express sequelize pg pg-hstore dotenv cors npm install --save-dev nodemon

    2.1.1. Arquivo de configuração .env

    # backend/.env
    

    DB_HOST=postgres DB_PORT=5432 DB_NAME=fullstack_db DB_USER=admin DB_PASSWORD=secret PORT=4000

    2.1.2. Estrutura de diretórios

    backend/
    

    │ app.js │ server.js │ .env │ package.json │ ├─ config/ │ database.js │ ├─ models/ │ User.js │ └─ routes/ users.js

    2.1.3. Conexão com o banco (config/database.js)

    // backend/config/database.js
    

    const { Sequelize } = require('sequelize'); require('dotenv').config();

    const sequelize = new Sequelize( process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, { host: process.env.DB_HOST, port: process.env.DB_PORT, dialect: 'postgres', logging: false, } );

    module.exports = sequelize;

    2.1.4. Modelo de usuário (models/User.js)

    // backend/models/User.js
    

    const { DataTypes } = require('sequelize'); const sequelize = require('../config/database');

    const User = sequelize.define('User', { // id será criado automaticamente name: { type: DataTypes.STRING, allowNull: false, }, email: { type: DataTypes.STRING, allowNull: false, unique: true, validate: { isEmail: true }, }, });

    module.exports = User;

    2.1.5. Rotas (routes/users.js)

    // backend/routes/users.js
    

    const express = require('express'); const router = express.Router(); const User = require('../models/User');

    // CREATE – cadastrar novo usuário router.post('/', async (req, res) => { try { const user = await User.create(req.body); res.status(201).json(user); } catch (err) { res.status(400).json({ error: err.message }); } });

    // READ – listar todos router.get('/', async (req, res) => { const users = await User.findAll(); res.json(users); });

    // READ – buscar por id router.get('/:id', async (req, res) => { const user = await User.findByPk(req.params.id); if (!user) return res.status(404).json({ error: 'Não encontrado' }); res.json(user); });

    // UPDATE – alterar dados router.put('/:id', async (req, res) => { const user = await User.findByPk(req.params.id); if (!user) return res.status(404).json({ error: 'Não encontrado' }); await user.update(req.body); res.json(user); });

    // DELETE – remover registro router.delete('/:id', async (req, res) => { const rows = await User.destroy({ where: { id: req.params.id } }); if (!rows) return res.status(404).json({ error: 'Não encontrado' }); res.status(204).send(); });

    module.exports = router;

    2.1.6. Aplicação principal (app.js)

    // backend/app.js
    

    const express = require('express'); const cors = require('cors'); const sequelize = require('./config/database'); const userRoutes = require('./routes/users'); require('dotenv').config();

    const app = express();

    app.use(cors()); app.use(express.json());

    // Rotas app.use('/api/users', userRoutes);

    // Sincronizar modelo e iniciar servidor (async () => { try { await sequelize.authenticate(); await sequelize.sync({ alter: true }); // cria/atualiza tabelas console.log('Conexão com o banco estabelecida.'); } catch (err) { console.error('Falha ao conectar ao banco:', err); process.exit(1); } })();

    module.exports = app;

    2.1.7. Servidor (server.js)

    // backend/server.js
    

    const http = require('http'); const app = require('./app'); require('dotenv').config();

    const PORT = process.env.PORT || 4000; const server = http.createServer(app);

    server.listen(PORT, () => { console.log(🚀 Servidor rodando em http://localhost:${PORT}); });

    2.1.8. Scripts de desenvolvimento (package.json)

    // backend/package.json (trecho)
    

    { "scripts": { "dev": "nodemon server.js", "start": "node server.js" } }

    Com npm run dev o backend será recarregado automaticamente a cada alteração.


    3. Frontend com React e Vite

    Volte à raiz do projeto e crie a camada de cliente:

    cd ..
    

    npm create vite@latest frontend -- --template react cd frontend npm install npm install axios

    3.1. Estr

    Artigos relacionados