Use esta especificação como base para criar o projeto.
- 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
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
| 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 |
// 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": [] } }200OK (GET, PUT)201Created (POST)204No Content (DELETE)400Bad Request401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity500Internal Server Error
O Sequelize CLI não suporta ES Modules. Por isso:
-
Criar dois arquivos de config do banco:
src/config/database.js→ ES Module para a aplicaçãosrc/config/database.cjs→ CommonJS para o CLI
-
Migrations e Seeders sempre com extensão
.cjs -
Arquivo
.sequelizercna raiz apontando para os paths corretos
- 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.
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 })
- Criar classe
AppErrorcom: message, statusCode, code, details - Middleware
errorHandlercaptura todos os erros - Tratar erros específicos do Sequelize (ValidationError, UniqueConstraintError)
Usar express-validator nos middlewares, não nos controllers.
- Região via variável de ambiente
AWS_REGION - Credenciais via variáveis
AWS_ACCESS_KEY_IDeAWS_SECRET_ACCESS_KEY - Em produção, preferir IAM Roles em vez de credenciais hardcoded
Usar SDK v3: @aws-sdk/client-ses
SesService.js deve implementar:
sendEmail({ to, subject, html, text })- envio básicosendTemplatedEmail({ to, template, data })- envio com template SESsendBulkEmail(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
Usar SDK v3: @aws-sdk/client-s3 e @aws-sdk/s3-request-presigner
S3Service.js deve implementar:
upload(file, key, options)- upload de arquivodownload(key)- download de arquivodelete(key)- remoção de arquivogetSignedUrl(key, expiresIn)- URL assinada para acesso temporáriolistObjects(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
{
"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"
}
}- 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
- Base:
node:24-alpine - Instalar dependências antes de copiar código (cache)
- Criar usuário não-root
- Expor porta 3000
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
{
"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"
}