Descrição do Projeto
Desenvolvendo um marketplace. Como único desenvolvedor, fiquei responsável por desenvolver tanto o frontend quanto o backend, além de gerenciar a infraestrutura em uma VPS para colocar o sistema em produção. Estamos utilizando o padrão REST para a comunicação entre o frontend e o backend, bem como entre os serviços internos. Nosso objetivo é que esta primeira versão tenha funcionalidades essenciais, como registro e autenticação de usuários, listagem e gerenciamento de produtos, carrinho de compras, checkout e integração com um gateway de pagamento.
O intuito deste post é mostrar como o projeto foi pensado e desenvolvido, apontar as dificuldades enfrentadas e, por fim, sugerir melhorias para as próximas versões. Caso você esteja pensando em construir um marketplace ou e-commerce, leve em consideração as informações contidas neste post, mas use o bom senso, pois nem tudo o que está aqui pode se aplicar ao seu caso.
Observação: Esse post não irá detalhar como foi desenvolvido o frontend.
Requisitos
Definição: Definem o que um sistema deve fazer e sob quais restrições. Requisitos relacionados com a primeira parte dessa definição - "o que um sistema deve fazer", ou seja, suas funcionalidades - são chamados de Requisitos Funcionais. Já os requisitos relacionados a segunda parte - "sob que restrições" - são chamados de Requisitos Não Funcionais.[1]
Requisitos Funcionais(RF)
Lojista
[RF01]: O sistema deve permitir que os lojistas se registrem sendo do tipo pessoa física ou jurídica.
[RF02]: O sistema deve permitir que o administrador possa autorizar ou desautorizar o lojistas caso não esteja em conformidades com as informações verdadeiras informadas no cadastro.
[RF03]: O sistema deve permitir que o lojista vincule o seu perfil a uma comunidade
[RF04]: O sistema deve permitir que o lojista possa cria sua loja com foto da loja, descrição e contato.
[RF05]: O sistema deve permitir que o lojista cadastre produtos
[RF06]: O sistema deve permitir que o lojista possa alterar o preço do produto, quantidade e excluir produto.
[RF08]: O sistema deve permitir que o lojista possa
Cliente
[RF01]: O sistema deve permitir que o cliente se registrem sendo do tipo pessoa física ou jurídica.
[RF02]: O sistema deve permitir que o cliente cadastre endereços, cartões para pagamentos e informações básicas de contato como email e telefone.
[RF03]: O sistema deve permitir que o cliente adicione ao carrinho o item desejado
[RF04]: O sistema deve permitir o pagamento de cartão de crédito ou pix
[RF05]: O sistema deve permitir que o cliente escolha se prefere retirar na loja ou entrega(via transportadora).
[RF06]: O sistema deve permitir que o cliente acompanhe o status do pedido, como: pedido feito, pedido autorizado, pedido em transporte e pedido entregue
[RF07]: O sistema deve permitir que o cliente receba um email informando os itens comprados
Comunidades
[RF01]: O sistema deve permitir que o um líder de comunidade se registre com informações do tipo quem são os líderes da comunidade CPF, CNPJ, informações de contato e endereço.
[RF02]: O sistema deve permitir que o líder da comunidade liste todos os lojistas vinculada a essa comunidade.
Administrador
[RF01]: O sistema deve permitir o administrador listar todos os clientes cadastrados.
[RF02]: O sistema deve permitir que o administrador liste todos os lojistas e consiga desautorizar o lojista que não esteja em conformidades com a regras da plataforma.
[RF03]: O sistema deve permitir que o administrador liste todas as comunidades, tenha informações sobre os responsáveis delas e possa autorizar ou desautorizar as comunidades.
Requisitos não funcionais(RNF)
Segurança
[RNF01]: O armazenamento dos tokens de acesso e de renovação deve ser seguro, preferencialmente em armazenamento seguro do navegador (por exemplo, localStorage ou cookies com flags Secure e HttpOnly).
[RNF02]: O sistema deve implementar a renovação de tokens (refresh tokens) de forma segura para permitir sessões prolongadas sem comprometer a segurança.
Stack
- NextJS/ReactJS
- NodeJS
- PostgreSQL
- Nginx
- minIO
- Docker
- RabbitMQ
System Design
Explicando o Fluxo
- public-gateway
Tecnologia: NodeJS, Typescript
Descrição: Atua como ponto de entrada para gerenciar e rotear. Redireciona o tráfego de entrada e saída entre a rede interna e externa.
- auth
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de Autenticação recebe as requisições de autenticação do public-gateway, valida essas requisições, e faz chamadas apropriadas para o serviço de identity para verificar as credenciais e gerenciar o registro dos usuários.
- identity
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de Identity gerencia as operações relacionadas aos usuários e contas, incluindo autenticação, registro, atualização de perfis.
- community
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de Community gerencia a criação, atualização e manutenção de dados de comunidades e seus respectivos responsáveis, incluindo endereços, e-mails e telefones.
- customer
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de Customer gerencia a criação, atualização e manutenção de dados de comunidades e seus respectivos responsáveis, incluindo endereços, e-mails e telefones.
- marketplace
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de marketplace é responsável por gerenciar as operações essenciais de um marketplace, incluindo carrinho de compras, categorias de produtos, inventário e pedidos. Ele utiliza diversos modelos, como Cart, que representa um carrinho de compras; CartSessionCartItem, que gerencia a associação entre uma sessão de carrinho e itens; Category, que classifica os itens em categorias; e Department, que organiza os produtos por departamentos. Além disso, inclui Item, que representa os produtos disponíveis; ItemMedia, para gerenciar as fotos dos itens; ItemNumbering, que lida com a numeração dos itens; e ItemSize, que define os tamanhos dos itens (P, M, G, etc.). O serviço também abrange OrderItem, que representa itens dentro de um pedido; OrderStatus, que gerencia o status dos pedidos; OrderShipping, que lida com as informações de envio dos pedidos; e OrderItemShipping, que gerencia o envio de itens específicos dentro de um pedido. Outros modelos incluem ShippingToken, que representa tokens de envio para rastreamento; ShippingService, que gerencia os serviços de envio disponíveis; e StoreStoreAddress, que representa o endereço das lojas. O serviço permite a adição e remoção de itens do carrinho, a categorização e organização dos produtos, e o processamento completo dos pedidos, desde a criação até o envio.
- media
Tecnologia: NodeJS, Typescript, minIO
Descrição: O Serviço de media é responsável pelo gerenciamento e armazenamento de arquivos de mídia, incluindo fotos das lojas, fotos de perfil e fotos dos itens (produtos). Organiza por buckets do MinIO para armazenar essas mídias.
- supplier
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de supplier gerencia a criação, atualização e manutenção de dados do lojista incluindo endereços, e-mails e telefones.
- marketplace-cart-session-cron
Tecnologia: NodeJS, Typescript
Descrição: O Serviço de marketplace-cart-session-cron é responsável por gerenciar e limpar carrinhos de compras abandonados. Este serviço executa uma tarefa programada que verifica e remove carrinhos inativos no banco de dados. Para carrinhos de usuários não autenticados, ou seja, aqueles que não fizeram login, o serviço mantém o carrinho ativo por um período de 24 horas antes de removê-lo. Para carrinhos de usuários autenticados, o carrinho permanece ativo por 7 dias.
- marketplace-order-cron
Tecnologia: NodeJS, Typescript
Descrição: A crontab marketplace-order-cron é responsável pela automação do processo de verificação e atualização dos pedidos com status de pagamento pendente. O serviço opera em intervalos regulares para consultar todos os pedidos que estão com o status "pendente de pagamento". Para cada pedido identificado, o serviço realiza uma solicitação à API de pagamento para processar o pagamento. Se o pagamento for bem-sucedido, o serviço atualiza o status do pedido no banco de dados para refletir a nova condição.
- shipping-cron
Tecnologia: NodeJS, Typescript
Descrição: O Serviço shipping-cron é responsável por manter a validade dos tokens da API da transportadora. Este serviço é executado periodicamente para atualizar o token de autenticação, que é necessário para realizar chamadas à API da transportadora. Como os tokens fornecidos pela transportadora têm um período de expiração, o shipping-cron garante que um novo token seja obtido e registrado antes que o token atual expire, assegurando que as operações de envio e rastreamento continuem a funcionar sem interrupções.
- customer-external-consumer
Tecnologia: NodeJS, Typescript
Descrição:
O customer-external-consumer é um serviço que consome mensagens de uma fila no RabbitMQ. Sua principal função é cadastrar clientes na API de pagamento e obter o identificador exclusivo do cliente fornecido pela API de pagamento. Esse identificador é então armazenado no banco de dados. Isso permite que, ao fazer pedidos de itens, o serviço envie à API de pagamento o identificador do cliente, facilitando a associação dos pagamentos com os clientes corretos.
- supplier-external-consumer
Tecnologia: NodeJS, Typescript
Descrição: O supplier-external-consumer é um serviço que consome mensagens de uma fila no RabbitMQ. Sua principal função é cadastrar (lojistas) fornecedores na API de pagamento e obter o identificador exclusivo do fornecedor fornecido pela API de pagamento. Esse identificador é então armazenado no banco de dados local. Isso permite que, ao processar transações relacionadas aos fornecedores, o serviço envie à API de pagamento o identificador do fornecedor, garantindo a correta associação dos pagamentos com os fornecedores registrados.
- email-consumer
Tecnologia: NodeJS, Typescript
Descrição: O email-consumer é um serviço que consome mensagens de email de uma fila no RabbitMQ. Ao receber uma mensagem, o serviço monta o template de email utilizando os atributos fornecidos no payload da mensagem. Após a montagem do email, o serviço envia o email formatado para o servidor SMTP para ser entregue ao destinatário.
Dificuldades enfrentadas
Inicialmente, eu não quis trabalhar com nenhum ORM, o que foi um grande erro, porque no início, quando eu desenvolvia uma feature e o cliente pedia para adicionar ou remover uma nova informação, a manutenção das queries ficava bastante custosa. Então, tive que refatorar e adotei o ORM, facilitando a manutenção do sistema.
Inicialmente, não tínhamos um(a) designer para o projeto, então precisei dedicar muito tempo à construção dos layouts das telas, e o cliente acabou achando-os muito simples. No final do projeto, uma UX/UI foi integrada à equipe e conseguiu criar, no Figma, os layouts da maneira que o cliente desejava. Minha observação: ter um(a) UX/UI facilitará e agregará valor ao seu projeto.
Como as especificações não estavam definidas desde o primeiro dia, a primeira versão foi desenvolvida de forma iterativa e contínua. Decidi aplicar os conceitos de Domain-Driven Design (DDD), mas, ao precisar refatorar, era necessário modificar muitos arquivos, como interfaces de repositório e validações. Então, para a versão 1 e considerando que o cliente ainda não tinha clareza sobre o que precisava ser implementado, eu optaria por uma arquitetura mais simples para facilitar o desenvolvimento. Acredito que isso tenha sido um exemplo de overengineering no projeto, o que custou tempo de desenvolvimento.
Melhorias futuras
Adicionar um BFF (Backend For Frontend) com GraphQL, isso vai agregar bastante ao front-end ao consumir os dados da API.
Adicionar testes, já que temos vários serviços e, ao alterar um, é necessário que todos estejam consistentes.
Adicionar CI/CD para automatizar a integração e deploy conforme as equipes forem contratadas para gerenciar o projeto.
Adicionar observabilidade dos serviços. [OpenTelemetry, Grafana]
Adicionar CDN para imagens dos produtos.
Top comments (0)