Skip to content

Instantly share code, notes, and snippets.

@pedropuppim
Last active February 2, 2026 11:41
Show Gist options
  • Select an option

  • Save pedropuppim/1c75fe21630fe48842f0d03cce0693eb to your computer and use it in GitHub Desktop.

Select an option

Save pedropuppim/1c75fe21630fe48842f0d03cce0693eb to your computer and use it in GitHub Desktop.
specs_backend.md

Especificação Backend Node.js

Use esta especificação como base para criar o projeto.

Stack

  • Runtime: Node.js 24+ com ES Modules ("type": "module" no package.json)
  • Framework: Express.js
  • ORM: Sequelize
  • Banco de Dados: MariaDB
  • Autenticação: JWT
  • Cloud: AWS (SES para emails, S3 para storage)
  • Infraestrutura: Docker + Docker Compose

Estrutura de Diretórios

project-root/
├── src/
│   ├── config/
│   │   ├── database.js          # Config Sequelize (ES Module)
│   │   ├── database.cjs         # Config para Sequelize CLI (CommonJS)
│   │   ├── jwt.js
│   │   ├── aws.js               # Config AWS (região, credentials)
│   │   └── index.js
│   │
│   ├── controllers/
│   │   └── [Entity]Controller.js
│   │
│   ├── database/
│   │   ├── migrations/          # Arquivos .cjs (CommonJS)
│   │   ├── seeders/             # Arquivos .cjs (CommonJS)
│   │   └── index.js             # Instância Sequelize
│   │
│   ├── middlewares/
│   │   ├── authMiddleware.js    # Validação JWT
│   │   ├── errorHandler.js      # Handler global de erros
│   │   ├── validator.js         # Validação de requests (express-validator)
│   │   └── index.js
│   │
│   ├── models/
│   │   ├── [Entity].js
│   │   └── index.js             # Registra models e associações
│   │
│   ├── repositories/
│   │   ├── BaseRepository.js    # CRUD genérico com paginação
│   │   ├── [Entity]Repository.js
│   │   └── index.js
│   │
│   ├── routes/
│   │   ├── [entity].routes.js
│   │   └── index.js             # Agrupa todas rotas
│   │
│   ├── services/
│   │   ├── SesService.js        # AWS SES - envio de emails
│   │   ├── S3Service.js         # AWS S3 - upload/download de arquivos
│   │   └── index.js
│   │
│   └── utils/
│       ├── hash.js              # bcrypt helpers
│       ├── response.js          # Padronização responses
│       ├── errors.js            # Classe AppError
│       ├── logger.js            # Winston
│       └── index.js
│
├── logs/                        # Diretório de logs (gitignore)
├── server.js                    # Entry point
├── package.json
├── .env.example
├── .sequelizerc
├── .gitignore
├── Dockerfile
├── docker-compose.yml
└── README.md

Convenções

Nomenclatura

Tipo Padrão Exemplo
Arquivos camelCase userController.js
Classes PascalCase UserController
Funções/Métodos camelCase findById
Constantes UPPER_SNAKE_CASE JWT_SECRET
Tabelas DB snake_case plural users, order_items
Colunas DB snake_case created_at, user_id

Padrão de Response

// Sucesso
{ "success": true, "data": { ... }, "message": "opcional" }

// Sucesso com paginação
{ "success": true, "data": [...], "pagination": { "page": 1, "limit": 20, "total": 100, "totalPages": 5 } }

// Erro
{ "success": false, "error": { "code": "ERROR_CODE", "message": "Descrição", "details": [] } }

HTTP Status Codes

  • 200 OK (GET, PUT)
  • 201 Created (POST)
  • 204 No Content (DELETE)
  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 409 Conflict
  • 422 Unprocessable Entity
  • 500 Internal Server Error

Regras Importantes

ES Modules + Sequelize CLI

O Sequelize CLI não suporta ES Modules. Por isso:

  1. Criar dois arquivos de config do banco:

    • src/config/database.js → ES Module para a aplicação
    • src/config/database.cjs → CommonJS para o CLI
  2. Migrations e Seeders sempre com extensão .cjs

  3. Arquivo .sequelizerc na raiz apontando para os paths corretos

Camadas

  • Controllers: Recebem request, chamam repository/service, retornam response. Não contêm lógica de negócio complexa.
  • Repositories: Única camada que acessa o banco. Contém queries e operações CRUD.
  • Services: Apenas integrações externas (email, S3, APIs terceiras). Não acessam banco diretamente.
  • Models: Definição das entidades, validações Sequelize, hooks e associações.
  • Middlewares: Autenticação, validação de input, tratamento de erros.

BaseRepository

Implementar um repositório base com métodos genéricos:

  • findAll(options)
  • findById(id)
  • findOne(where)
  • create(data)
  • update(id, data)
  • delete(id)
  • paginate({ page, limit, where, ...options })

Error Handling

  • Criar classe AppError com: message, statusCode, code, details
  • Middleware errorHandler captura todos os erros
  • Tratar erros específicos do Sequelize (ValidationError, UniqueConstraintError)

Validação

Usar express-validator nos middlewares, não nos controllers.

AWS Services

Configuração (config/aws.js)

  • Região via variável de ambiente AWS_REGION
  • Credenciais via variáveis AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY
  • Em produção, preferir IAM Roles em vez de credenciais hardcoded

SES (Simple Email Service)

Usar SDK v3: @aws-sdk/client-ses

SesService.js deve implementar:

  • sendEmail({ to, subject, html, text }) - envio básico
  • sendTemplatedEmail({ to, template, data }) - envio com template SES
  • sendBulkEmail(recipients, subject, html) - envio em massa

Boas práticas:

  • Configurar email verificado como remetente (FROM)
  • Tratar bounces e complaints
  • Usar templates do SES para emails transacionais
  • Respeitar limites de envio da conta

S3 (Simple Storage Service)

Usar SDK v3: @aws-sdk/client-s3 e @aws-sdk/s3-request-presigner

S3Service.js deve implementar:

  • upload(file, key, options) - upload de arquivo
  • download(key) - download de arquivo
  • delete(key) - remoção de arquivo
  • getSignedUrl(key, expiresIn) - URL assinada para acesso temporário
  • listObjects(prefix) - listar objetos por prefixo

Boas práticas:

  • Bucket separado por ambiente (dev, staging, prod)
  • Organizar objetos com prefixos: uploads/users/, uploads/documents/
  • Usar URLs assinadas para arquivos privados
  • Definir ContentType correto no upload
  • Configurar lifecycle rules para limpeza automática se necessário

Dependências Base

{
  "dependencies": {
    "express": "^4.18.x",
    "sequelize": "^6.x",
    "mariadb": "^3.x",
    "jsonwebtoken": "^9.x",
    "bcryptjs": "^2.x",
    "dotenv": "^16.x",
    "cors": "^2.x",
    "helmet": "^7.x",
    "express-validator": "^7.x",
    "winston": "^3.x",
    "@aws-sdk/client-ses": "^3.x",
    "@aws-sdk/client-s3": "^3.x",
    "@aws-sdk/s3-request-presigner": "^3.x"
  },
  "devDependencies": {
    "sequelize-cli": "^6.x"
  }
}

Docker

docker-compose.yml

  • Serviço app: build do Dockerfile, depende do db com healthcheck
  • Serviço db: MariaDB 10.11+, volume persistente, healthcheck configurado
  • Network compartilhada entre serviços
  • Variáveis de ambiente via .env

Dockerfile

  • Base: node:24-alpine
  • Instalar dependências antes de copiar código (cache)
  • Criar usuário não-root
  • Expor porta 3000

Variáveis de Ambiente (.env.example)

NODE_ENV=development
PORT=3000
APP_NAME=myapp

DB_HOST=localhost
DB_PORT=3306
DB_NAME=app_db
DB_USER=app_user
DB_PASS=app_pass

JWT_SECRET=change-me
JWT_EXPIRES_IN=7d

# AWS
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key

# AWS S3
AWS_S3_BUCKET=your-bucket-name

# AWS SES
AWS_SES_FROM_EMAIL=noreply@yourdomain.com

LOG_LEVEL=info

Scripts package.json

{
  "start": "node server.js",
  "dev": "node --watch server.js",
  "db:migrate": "sequelize-cli db:migrate",
  "db:migrate:undo": "sequelize-cli db:migrate:undo",
  "db:seed": "sequelize-cli db:seed:all",
  "db:seed:undo": "sequelize-cli db:seed:undo:all"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment