Aplicação Full Stack desenvolvida como teste técnico para simular um módulo simplificado de um ERP.
- Usuario
- Cliente
- Pedidos
- Itens
- Next.js
- React
- TypeScript
- Tailwind CSS
- Antd
- Zustand
- JWT (Autenticação)
- Node.js
- Express
- TypeScript
- Prisma ORM
- PostgreSQL
- Redis (Cache)
- JWT (Autenticação)
- bcryptjs (Hash seguro de senhas)
- Docker
- Docker Compose
- Git
- Chatgpt Free
- Windsurf (plung vscode)
Para rodar este projeto em sua máquina local, certifique-se de ter o Docker e o Docker Compose instalados.
- Docker Desktop (ou Docker Engine + Docker Compose).
- Git instalado.
Abra o seu terminal e execute os comandos abaixo:
# Clone o repositório
git clone git@github.com:davidsongsc/projeto-teste.git
# Entre na pasta do projeto
cd projeto-teste- Certifique-se de criar um arquivo (.env) em cada pasta api do .env.exemple, exemplo:
# Configurações do Banco de Dados
DB_USER=user
DB_PASSWORD=password
DB_NAME=logistic_order
DB_HOST=localhost
DB_PORT=5432
# URL de conexão do Prisma (utilizando as variáveis acima)
DATABASE_URL="postgresql://user:password@localhost:5432/logistic_order?schema=public"
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_URL=redis://redis:6379
PORT=3030
JWT_SECRET=OdyeqJAkdFq4WuXhCAK1B42SNxETSnqzavZQonmlTkc
projeto-teste/web/.env
-
- Certifique-se de criar um arquivo (.env) na pasta web .env.exemple, exemplo:
NEXT_PUBLIC_API_URL=http://localhost:3030/api
Com tudo pronto, suba os containers da aplicação (incluindo o banco de dados e o Redis):
# Subir os serviços em background
docker-compose build
docker-compose up -d
Após subir os containers, talvez seja necessario rodar o generate do prisma :
docker exec -u root -it logistic-order-api npx prisma generate
docker exec -u root -it logistic-order-api sh -c 'npx prisma migrate dev --name migracao_inicial --url "$DATABASE_URL"'
docker exec -u root -it logistic-order-api npx tsx prisma/seed.ts
admin@loja.com
senha123
colab6@empresa.com
senha123
Acesse para ver o projeto.
http://localhost:3000
Uttilizei o rediz na camada de cache para reduzir consulttas repetitas via (get).
O Plano era desenvolver uma solução simples para um middleware reutilizavel.
O TTL escolhido foi 60 segundos, permitindo um intervalo minimo entre consultas repetitivas. ex:
router.get(
'/:id',
cacheMiddleware('users', 60),
controller.show)
Quando o middleware é chamado ele espera o nome para o cache e o TTL
Acesse para ver a documentação da api. Lista de endpoints.
http://localhost:3030/docs/
Foi seguida a stack obrigatória do desafio, priorizando aderência aos requisitos e evitando overengineering.
Além disso, foram utilizadas algumas bibliotecas auxiliares para apoiar segurança, produtividade e integração da aplicação:
- Ant Design: utilizado para acelerar a construção da interface com componentes prontos e consistentes.
- bcryptjs: aplicado para hashing seguro de senhas, garantindo maior segurança no armazenamento de credenciais.
- JWT: utilizado para autenticação baseada em tokens.
- CORS: configurado de forma simples para permitir a comunicação entre frontend e backend durante o desenvolvimento.
A abordagem adotada buscou manter o projeto simples, alinhado ao escopo proposto, ao mesmo tempo em que aplicou boas práticas de segurança e organização.
+----------------+
| web |
| Next.js |
+-------+--------+
|
| HTTP
|
+-------v--------+
| api |
| Node/Express |
+---+---------+--+
| |
PostgreSQL | | Redis
| |
+---------v-+ +-v---------+
| db | | redis |
+-----------+ +-----------+
^
|
prisma migrate
|
+------v------+
| migrate |
+-------------+
| Method | Route | Description |
|---|---|---|
| POST | /auth/login |
Authenticate user and generate access token. |
| POST | /auth/refresh |
Refresh the access token. |
| POST | /auth/logout |
Invalidate the current session/token. |
| GET | /auth/me |
Return authenticated user information. |
| Method | Route | Description |
|---|---|---|
| GET | /users |
List users with pagination and filters. |
| GET | /users/:id |
Retrieve a specific user by ID. |
| POST | /users |
Create a new user. |
| PUT | /users/:id |
Update an existing user. |
| DELETE | /users/:id |
Remove a user. |
| Method | Route | Description |
|---|---|---|
| GET | /profiles |
List profiles. |
| GET | /profiles/:id |
Retrieve a profile by ID. |
| POST | /profiles |
Create a new profile. |
| PUT | /profiles/:id |
Update a profile. |
| DELETE | /profiles/:id |
Remove a profile. |
| Method | Route | Description |
|---|---|---|
| GET | /permissions |
List permissions. |
| GET | /permissions/:id |
Retrieve a permission by ID. |
| POST | /permissions |
Create a permission. |
| PUT | /permissions/:id |
Update a permission. |
| DELETE | /permissions/:id |
Remove a permission. |
| Method | Route | Description |
|---|---|---|
| GET | /collaborators |
List collaborators. |
| GET | /collaborators/:id |
Retrieve a collaborator by ID. |
| POST | /collaborators |
Create a collaborator. |
| PUT | /collaborators/:id |
Update collaborator information. |
| PATCH | /collaborators/:id/status |
Update collaborator status. |
| DELETE | /collaborators/:id |
Remove a collaborator. |
| Method | Route | Description |
|---|---|---|
| GET | /customers |
List customers. |
| GET | /customers/:id |
Retrieve a customer by ID. |
| POST | /customers |
Create a customer. |
| PUT | /customers/:id |
Update customer information. |
| DELETE | /customers/:id |
Remove a customer. |
| Method | Route | Description |
|---|---|---|
| GET | /products |
List products. |
| GET | /products/:id |
Retrieve a product by ID. |
| POST | /products |
Create a product. |
| PUT | /products/:id |
Update product information. |
| DELETE | /products/:id |
Remove a product. |
| Method | Route | Description |
|---|---|---|
| GET | /orders |
List orders with pagination and filters. |
| GET | /orders/:id |
Retrieve an order by ID. |
| POST | /orders |
Create a new order. |
| PUT | /orders/:id |
Update an existing order. |
| DELETE | /orders/:id |
Remove an order. |
| Method | Route | Description |
|---|---|---|
| GET | /items |
List order items. |
| GET | /items/:id |
Retrieve an item by ID. |
| POST | /items |
Create an item. |
| PUT | /items/:id |
Update an item. |
| DELETE | /items/:id |
Remove an item. |
| Method | Route | Description |
|---|---|---|
| GET | /permissions |
List permissions with pagination and filters. |
| GET | /permissions/:id |
Retrieve a permission by ID. |
| GET | /permissions/profile/:profileId |
Retrieve permissions by profile ID. |
| POST | /permissions |
Create a new permission. |
| PUT | /permissions/:id |
Update an existing permission. |
| DELETE | /permissions/:id |
Remove a permission. |
| Method | Route | Description |
|---|---|---|
| POST | /order-items |
Add an item to an order. |
| PUT | /order-items/:id |
Update an order item. |
| DELETE | /order-items/:id |
Remove an item from an order. |
Foram implementados testes unitários com foco na validação de regras de negócio do módulo de pedidos e controle de acesso baseado em perfil de usuário.
O objetivo é garantir que operações críticas não possam ser executadas em estados inválidos ou por usuários sem permissão adequada.
Valida o controle de acesso baseado em permissões (RBAC).
Cenários testados:
- Bloqueia o acesso quando o usuário não possui a permissão exigida, retornando HTTP 403 (Forbidden).
- Permite a execução da requisição quando o usuário possui a permissão necessária, chamando o próximo middleware (
next).
Valida o comportamento do middleware de cache para otimizar requisições de leitura.
Cenários testados:
- Ignora o cache em requisições diferentes de GET, permitindo que o fluxo continue normalmente.
- Permite a execução da requisição quando não existe conteúdo armazenado em cache.
- Retorna os dados armazenados em cache e interrompe o fluxo da requisição quando uma entrada válida é encontrada.
Valida o processo de autenticação e geração do token de acesso.
Cenários testados:
- Impede o login quando o usuário não existe.
- Impede o login quando o usuário não possui uma senha cadastrada.
- Impede o login quando a senha informada é inválida.
- Autentica o usuário com credenciais válidas, gerando um token JWT e retornando os dados do usuário juntamente com suas permissões.
Valida as principais regras de negócio para a criação de pedidos.
Cenários testados:
- Impede a criação de pedidos sem itens.
- Impede a criação de pedidos cujo valor total calculado seja igual ou inferior a zero.
- Impede a criação de pedidos quando um ou mais produtos informados não existem no sistema.
- Impede a criação de pedidos para clientes inativos ou inexistentes.
- Cria o pedido com sucesso quando todas as validações são atendidas, calculando o valor total e persistindo os dados da operação.
Valida as regras de negócio para o cadastro de clientes.
Cenários testados:
- Impede o cadastro quando o e-mail não é informado.
- Impede o cadastro quando o nome não é informado.
- Impede o cadastro quando o documento não é informado.
- Realiza o cadastro do cliente com sucesso quando todos os dados obrigatórios são válidos.
Valida as regras de negócio para o cadastro de itens.
Cenários testados:
- Impede o cadastro quando o nome do item não é informado.
- Impede o cadastro quando o preço não é informado.
- Realiza o cadastro do item com sucesso quando os dados obrigatórios são válidos.
- Permite o cadastro do item sem descrição, tratando esse campo como opcional.
Valida as principais regras de negócio para a criação de pedidos.
Cenários testados:
- Impede a criação de pedidos sem itens.
- Impede a criação de pedidos cujo valor total calculado seja igual ou inferior a zero.
- Impede a criação de pedidos quando um ou mais produtos informados não existem no sistema.
- Impede a criação de pedidos para clientes inativos ou inexistentes.
- Cria o pedido com sucesso quando todas as validações são atendidas, calculando o valor total e persistindo os dados da operação.
Valida as regras de negócio para o gerenciamento dos itens de um pedido.
Cenários testados:
- Adiciona um item a um pedido existente com sucesso.
- Impede a inclusão de itens em pedidos inexistentes.
- Atualiza a quantidade e/ou o valor total de um item existente.
- Impede a atualização de itens de pedido inexistentes.
- Remove um item de pedido existente.
- Impede a remoção de itens de pedido inexistentes.
Valida as regras de negócio para o cadastro de permissões.
Cenários testados:
- Impede o cadastro quando a chave da permissão (
key) não é informada. - Impede o cadastro quando o módulo (
module) não é informado. - Impede o cadastro quando a ação (
action) não é informada. - Realiza o cadastro da permissão com sucesso quando todos os dados obrigatórios são válidos.
- Permite o cadastro da permissão sem descrição, tratando esse campo como opcional.
Valida as regras de negócio para o cadastro de perfis de acesso.
Cenários testados:
- Impede o cadastro quando o nome do perfil não é informado.
- Impede o cadastro quando a função (
role) não é informada. - Realiza o cadastro do perfil com sucesso quando todos os dados obrigatórios são válidos.
- Permite o cadastro do perfil sem descrição, tratando esse campo como opcional.
Valida as regras de negócio para o cadastro de usuários.
Cenários testados:
- Impede o cadastro quando o nome não é informado.
- Impede o cadastro quando o e-mail não é informado.
- Impede o cadastro quando a senha não é informada.
- Realiza o cadastro do usuário com sucesso, gerando o hash da senha antes da persistência dos dados.
- Permite o cadastro de usuários sem um perfil associado, tratando o vínculo com o perfil como opcional.
- Usuários com perfil operador não podem ativar ou inativar clientes
- A execução de ações administrativas é restrita a perfis com permissão adequada
Esses testes garantem a integridade das regras de domínio e controle de acesso em nível de serviço, reduzindo dependência de validações na camada de interface e prevenindo execuções indevidas no sistema.
Com mais tempo, eu finalizaria algumas pendências do front e refinaria a experiência geral da aplicação.
No backend, melhoraria o uso de cache no Redis para evitar chamadas desnecessárias ao banco e deixar a API mais eficiente.
No frontend, aplicaria cache local e pequenas otimizações para reduzir requisições e melhorar a performance.
Também investiria um pouco mais em ajustes de performance e organização geral do fluxo entre front e backend.
Uso IA mais como apoio do que como algo que “faz o código por mim”.
Normalmente eu começo um módulo do zero e faço tudo manualmente (interface, form, create, edit e integração com a API). Depois que isso está funcionando bem no front e no back, uso IA para replicar a estrutura em módulos parecidos, mudando só as regras de negócio.
Funciona bem em casos como users e customers, onde a base é quase a mesma, mas muda a semântica e alguns campos.
Também uso IA para coisas mais repetitivas, como seeds e pequenos ajustes de código, além de sugestões do editor quando estou escrevendo algo parecido com o que já fiz antes.
No geral, ela entra mais como um acelerador de produtividade do que como substituição do desenvolvimento.
- Aproximadamente 20 horas.