API REST para um sistema de Help Desk, desenvolvida com Node.js, Express, MySQL, Sequelize, JWT e Zod.
O projeto tem como objetivo gerenciar chamados de suporte, usuários, categorias, comentários, histórico de status, dashboard administrativo e regras de acesso baseadas em perfil.
- Node.js
- Express
- MySQL
- Sequelize
- Sequelize CLI
- Zod
- JWT
- bcryptjs
- Docker / Docker Compose
- CORS
- Helmet
- dotenv
O projeto segue uma arquitetura em camadas:
Controller → Service → Repository → ModelController
→ recebe a requisição
→ chama o service
→ define status HTTP
→ retorna JSON
Service
→ aplica regras de negócio
→ valida dados com Zod
→ define formato das respostas
→ lança erros de domínio
Repository
→ acessa o banco de dados
→ executa queries com Sequelize
Model
→ representa as tabelas do banco
→ define campos e associações- Cadastro de usuário
- Login
- Consulta do usuário autenticado
- Senhas criptografadas com bcrypt
- Autenticação via JWT
- Middleware de autenticação
Perfis disponíveis:
ADMIN
TECHNICIAN
USERRegras gerais:
ADMIN
→ acesso administrativo completo
TECHNICIAN
→ acessa apenas tickets atribuídos a ele
USER
→ acessa apenas os próprios tickets- Listar usuários
- Buscar usuário por ID
- Alterar role de um usuário
- Rotas protegidas para ADMIN
- Bloqueio para impedir que um admin altere a própria role
- Criar categoria
- Listar categorias
- Buscar categoria por ID
- Atualizar categoria
- Deletar categoria
- Validação contra categorias duplicadas
- Criar ticket
- Listar tickets conforme perfil do usuário
- Buscar ticket por ID
- Atualizar ticket
- Deletar ticket
- Autoatribuição para o técnico com menor número de tickets ativos
- Controle de acesso por perfil
- Registro automático de histórico quando o status muda
- Transaction no update de ticket + histórico de status
- Adicionar comentários em tickets
- Listar comentários de um ticket
- Controle de acesso baseado no ticket
- Registro automático de mudanças de status
- Consulta do histórico de status de um ticket
- Registro de:
- ticket alterado
- usuário que alterou
- status anterior
- novo status
- data da alteração
- Resumo de tickets
- Contagem total
- Contagem por status
- Contagem por prioridade
- Escopo baseado no perfil do usuário
ADMIN
→ lista todos os tickets
→ visualiza qualquer ticket
→ atualiza qualquer ticket
→ deleta tickets
TECHNICIAN
→ lista apenas tickets atribuídos a ele
→ visualiza apenas tickets atribuídos a ele
→ atualiza apenas tickets atribuídos a ele
→ não deleta tickets
USER
→ lista apenas os próprios tickets
→ visualiza apenas os próprios tickets
→ não atualiza tickets
→ não deleta ticketsADMIN
→ acessa comentários de qualquer ticket
TECHNICIAN
→ acessa comentários de tickets atribuídos a ele
USER
→ acessa comentários dos próprios ticketsADMIN
→ acessa histórico de qualquer ticket
TECHNICIAN
→ acessa histórico de tickets atribuídos a ele
USER
→ acessa histórico dos próprios ticketsOPEN
IN_PROGRESS
WAITING_USER
RESOLVED
CLOSEDLOW
MEDIUM
HIGH
CRITICALsrc/
├── config/
│ └── database.js
├── controllers/
├── database/
│ ├── migrations/
│ └── seeders/
├── middlewares/
├── models/
├── repositories/
├── routes/
├── services/
├── utils/
├── validators/
└── app.jsCrie um arquivo .env na raiz do projeto com base no .env.example.
Exemplo:
PORT=3000
DB_HOST=localhost
DB_PORT=3307
DB_USER=root
DB_PASSWORD=root
DB_NAME=helpify_db
JWT_SECRET=your_jwt_secret
JWT_EXPIRES_IN=1dnpm installdocker compose up -dnpx sequelize-cli db:migratenpx sequelize-cli db:seed:allnpm run devA API ficará disponível em:
http://localhost:3000GET /healthResposta esperada:
{
"status": "ok",
"message": "App is running"
}POST /auth/signup
POST /auth/signin
GET /auth/meRotas protegidas para ADMIN.
GET /users
GET /users/:id
PATCH /users/:id/rolePayload para alterar role:
{
"role": "TECHNICIAN"
}Roles aceitas:
ADMIN
TECHNICIAN
USERPOST /categories
GET /categories
GET /categories/:id
PATCH /categories/:id
DELETE /categories/:idPayload de criação:
{
"name": "Hardware"
}POST /tickets
GET /tickets
GET /tickets/:id
PATCH /tickets/:id
DELETE /tickets/:idPayload de criação:
{
"title": "Computador travando",
"description": "Computador está travando ao abrir o navegador.",
"categoryId": 1,
"priority": "HIGH"
}Payload de atualização:
{
"status": "IN_PROGRESS",
"priority": "CRITICAL",
"categoryId": 2
}POST /tickets/:ticketId/comments
GET /tickets/:ticketId/commentsPayload:
{
"content": "Chamado analisado. Será necessário verificar o hardware."
}GET /tickets/:ticketId/status-historiesExemplo de resposta:
{
"statusHistories": [
{
"id": 1,
"ticketId": 8,
"changedById": 1,
"oldStatus": "OPEN",
"newStatus": "IN_PROGRESS",
"createdAt": "2026-06-27T18:30:00.000Z",
"changedBy": {
"id": 1,
"name": "Admin Helpify",
"email": "admin@helpify.com"
}
}
]
}GET /dashboard/summaryExemplo de resposta:
{
"totalTickets": 10,
"ticketsByStatus": {
"open": 2,
"inProgress": 3,
"waitingUser": 1,
"resolved": 2,
"closed": 2
},
"ticketsByPriority": {
"low": 1,
"medium": 4,
"high": 3,
"critical": 2
}
}{
"user": {}
}{
"users": []
}{
"ticket": {}
}{
"tickets": []
}{
"category": {}
}{
"categories": []
}{
"comments": []
}{
"message": "Ticket has been deleted."
}A API utiliza um middleware global de erros.
Exemplos:
{
"error": "Unauthorized."
}{
"error": "Forbidden."
}{
"error": "Ticket not found."
}{
"error": "Campos inválidos."
}{
"error": "An error occurred with your request. Please try again later."
}Principais tabelas:
roles
users
categories
tickets
comments
ticket_status_historiesRole 1:N User
User 1:N Ticket
Category 1:N Ticket
User 1:N assignedTickets
Ticket N:1 assignedTechnician
Ticket 1:N Comment
User 1:N Comment
Ticket 1:N TicketStatusHistory
User 1:N TicketStatusHistoryAo criar um ticket, a API busca todos os técnicos disponíveis e atribui o chamado ao técnico com menos tickets ativos.
Tickets ativos:
OPEN
IN_PROGRESS
WAITING_USERSe não houver técnicos cadastrados, o ticket é criado com:
assignedToId = nullO histórico só é criado quando o status realmente muda.
Exemplo:
OPEN → IN_PROGRESSCria histórico.
IN_PROGRESS → IN_PROGRESSNão cria histórico duplicado.
A atualização do ticket e a criação do histórico de status ocorrem dentro de uma transaction.
Se a criação do histórico falhar, a atualização do ticket é revertida.
Rodar migrations:
npx sequelize-cli db:migrateDesfazer última migration:
npx sequelize-cli db:migrate:undoRodar seeders:
npx sequelize-cli db:seed:allDesfazer seeders:
npx sequelize-cli db:seed:undo:allVer status das migrations:
npx sequelize-cli db:migrate:statusSubir banco:
docker compose up -dParar banco:
docker compose downAPI finalizada como MVP.
Funcionalidades principais concluídas:
✅ autenticação
✅ autorização por role
✅ gerenciamento de usuários
✅ categorias
✅ tickets
✅ autoatribuição
✅ comentários
✅ histórico de status
✅ dashboard summary
✅ controle de acesso por perfil
✅ transaction no update de ticketPossíveis evoluções:
- paginação
- filtros avançados de tickets
- Swagger/OpenAPI
- testes automatizados
- upload de anexos
- refresh token
- recuperação de senha
- notificações
- otimização do dashboard com GROUP BY
- front-end completo