-
Notifications
You must be signed in to change notification settings - Fork 1
Arquitetura do Projeto
Este documento tem como objetivo oferecer uma análise detalhada da arquitetura atual do projeto, com o intuito de identificar possíveis falhas de design e projeto, melhorar a facilidade de manutenção do sistema e otimizar os custos envolvidos. Por meio da avaliação da estrutura existente, iremos apresentar uma arquitetura recomendada, que contemplará representações abrangentes e elucidativas das diversas perspectivas relacionadas ao projeto.
O projeto adota uma arquitetura de camadas, seguindo um padrão comum na indústria. Cada camada desempenha um papel específico no funcionamento do sistema. As camadas principais são:
-
Front-end: Responsável pela interação com o usuário, apresentando a interface gráfica e permitindo a entrada de dados e a exibição de informações.
-
Back-end: Responsável pelas operações do sistema, incluindo a lógica de negócios, processamento de dados e comunicação com outras partes do sistema ou serviços externos.
-
Banco de Dados: Responsável pelo armazenamento e recuperação de informações utilizadas pelo sistema. É utilizado para persistir dados de forma estruturada, garantindo a integridade e a disponibilidade dos mesmos.
Além disso, é possível observar uma sub-arquitetura seguindo o padrão MVC (Model-View-Controller) na camada de front-end e back-end. Essa abordagem divide o sistema em três componentes:
-
Modelo (Model): Responsável pela representação e manipulação dos dados, bem como pela lógica de negócios relacionada a eles.
-
Visão (View): Responsável pela apresentação dos dados ao usuário, exibindo informações de forma adequada e interativa.
-
Controle (Controller): Responsável pela intermediação entre a visão e o modelo, gerenciando as interações do usuário e coordenando as ações correspondentes no sistema.
Essa estrutura no padrão MVC ajuda a promover a separação de responsabilidades, facilitando a manutenção e a evolução do projeto ao longo do tempo. Foi feito um Diagrama de Componentes a fim de observar claramente a estrutura MVC.
Link de Acesso à Imagem acima:Diagrama de Componentes
Módulo | Ação |
---|---|
Models | É onde será definido os schemas no mongoose que irão representar as entidades do projeto |
Controllers | É a Camada onde se encontra a lógica principal do backend |
Utils | São as Funções úteis que podem ser usadas em diferentes locais do projeto e, por isso, são abstraídas nessa camada. |
Middleware | São os Fluxos que serão executados de forma intermediária (antes de ser chamado a função do controller) |
Configs | É a Camada de configurações gerais do projeto |
Routes | Definição das rotas da API |
Services | Criação de serviços que serão usados pela aplicação |
Pages | É a Camada do frontend onde ficará o código de renderização das páginas que serão exibidas ao usuário |
Componentes | É a Camada responsável por permitir a reusabilidade de código, definindo os componentes que serão usados em diversos pontos do projeto |
Render | É utilizado para descrever o processo de transformação de dados em elementos visuais na interface do usuário |
Database | É o Banco de Dados propriamente dito |
-
Singleton: A biblioteca
recoil
é utilizada para armazenar o estado global da aplicação, sempre acessível por todas as páginas e componentes. A qualquer momento, só existe uma instância do gerenciador de estado, compartilhado por toda a aplicação. Esse padrão é utilizado em diversas partes da aplicação, e podem ser observados no diretóriofrontend/src/states/
. -
Observer: Esse padrão é utilizado para monitorar mudanças nos dados e atualizar os componentes do front-end para refletir as mudanças — a renderização condicional de componentes permite a alteração dos dados exibidos com base no estado armazenado internamente por cada componente. São exemplos desse padrão as funcionalidades de esvaziar carrinho; o bloqueio do botão de ‘Confirmar pedido’ quando o carrinho está vazio; além da atualização de status do pedido, emitida pelo restaurante, que é refletida na tela vista pelo usuário.
-
DAO: Os objetos da aplicação são armazenados em um modelo de dados padronizado para permitir a uniformização do acesso e escrita aos dados de uma forma unificada. Isso pode ser observado na pasta
backend/src/models
.
Link de Acesso à imagem acima: Modificação do Diagrama de Componentes
Foram sugeridas as seguintes modificações a fim de atender uma arquitetura ideal para o projeto.
Modificação | Justificativa |
---|---|
Remoção do Cabeçalho Admin de _frontend/src/componentes_
|
Criação de Apenas um cabeçalho que engloba tudo. Essa modificação serve para diminuir a quantidade de arquivos e trazer um padrão simples ao projeto. |
Criação de um service para cada controller em _backend/src/services_
|
Serve para criar uma camada de abstração suficiente evitando a manipulação direta do banco de dados e o service poderá cuidar de validações evitando conflitos e centralizando acesso aos dados. |
-
State: A lógica de status do pedido poderia utilizar melhor esse padrão para gerenciar a mudança da situação de um pedido. Assim, seria possível encapsular uma lógica diferente para cada estado possível, com funções de transição de um estado para outro (como gerar uma notificação para o usuário, ou permitir a operação “Confirmar entrega”, que só estaria disponível quando o status fosse “Saiu para entrega”), o que faciltaria a manutenção da lógica da aplicação.
-
Command: A fila de pedidos a ser apresentada na cozinha pode ser implementada utilizando o padrão Command. Cada solicitação de pedido gera um comando para que o pedido entre numa fila, onde o primeiro pedido a ser feito é o primeiro a ser atendido. Do lado da cozinha, deve haver também um comando que libere o pedido para entrega uma vez que estiver pronto, gerando uma atualização no status do pedido.
-
Strategy: As diferentes formas de pagamento podem utilizar o padrão Strategy, que consiste em criar subclasses intercambiáveis implementando diferentes lógicas para um mesmo processo. Assim, a lógica para pagamento via cartão poderia incluir uma lógica adicional para verificar se o cliente informou os dados do cartão ao criar a conta, e caso necessário, solicitar os dados do cartão; a lógica de pagamento por Pix incluiria a geração de um QR Code e a verificação automática de pagamento; e, por fim, o pagamento em dinheiro poderia solicitar a quantidade de troco a ser levada até o consumidor no ato da entrega.
-
Composite: Os combos podem ser implementados utilizando o padrão Composite, que permite o encapsulamento de objetos “simples” (objetos únicos) ou “compostos” (coleções) uns dentro dos outros, de maneira uniforme. A entidade
Combo
poderia conter outros objetos do tipoCombo
, ou objetosProduto
. Assim, poderia haver um combo contendo alguns itens (por exemplo, duas bebidas), e este poderia tanto ser adicionado ao carrinho por si só, como estar contido em um outro combo maior (por exemplo, um combo com dois hambúrgueres e duas bebidas). -
Adapter: Esse padrão pode ser utilizado para simplificar a interação com os objetos a partir da criação de serviços de manipulação para cada tipo de dado, evitando a interação direta com o banco de dados. Assim, cada service criado pode cuidar de etapas como consulta, atualização, validação e persistência, implementando para isso qualquer lógica – simples ou complexa. Assim, todas as partes da aplicação que precisassem manipular um recurso específico o fariam através da mesma interface. Obs.: No momento, um service já está sendo utilizado na aplicação para as funcionalidades de login e carrinho. Porém, outros também poderiam ser criado para a manipulação dos demais componentes (produto, pedido etc.)
-
DAO: Apesar de estar sendo usado no backend, também seria possível usufruir desse padrão no frontend, trazendo mais facilidade ao acesso de dados a cada objeto. Não existe, no momento, uma representação das estruturas
Delivery
,Item
,Order
eUser
no front-end — logo, caso alguma alteração seja feita no backend e novos campos sejam incluídos ou modificados, será dificíl atualizar o front-end para refletir essas mudanças.
Para o projeto criado, as seguintes estratégias serão aplicadas de acordo com objetivo:
- Sugestão: Utilizar-se do Armazenamento em cache
JustificativaÉ aconselhável, para o projeto, utilizar o armazenamento em cache, principalmente nos dados que são acessados frequentemente, como o Cardápio e o Carrinho. Isso reduz a carga no banco de dados e aumenta a velocidade de resposta de aplicação.
- Sugestão: Uso melhor do Design Responsivo:
Justificativa: Indica-se, para o Aplicativo, o uso de um design responsivo e adaptável à diversos dispositivos, como computador, celular e Tablets. Isso fará com que a experiência do cliente seja constante no dispositivo desejado pelo cliente. Além disso, o design responsivo auxilia no gerenciamento da aplicação pelos autores e também pelos usuários.
- Sugestão: Escalabilidade
Justificativa Para o projeto, o uso da Escalabilidade trará melhorias significativas em questão de desempenho. Para isso, a utilização de serviços em nuvem escaláveis e recursos de balanceamento de cargo são indicados à serem utilizados futuramente. É indicado também organizar o código em módulos, pois facilita a manutenção conforme o projeto vai avançando.
- Sugestão: Adicionar paginação no projeto em pontos críticos
Justificativa: Alguns pontos do projeto, conforme o projeto escala, podem retornar uma quantidade muito grande de dados para o frontend, caso não seja adicionado a paginação. Isso pode gerar grandes problemas de performance. Um exemplo de onde poderia ser adicionado a paginação, são nos endpoints de consulta relacionados a pedido.
- Sugestão: Salvar imagens na nuvem
Justificativa: Atualmente, existe um campo chamado file na model de Item. Não é uma boa prática salvar o buffer no banco de dados. Isso pode diminuir a performance do sistema. O ideal é salvar a imagem na nuvem, seja em um serviço separado para isso ou na própria máquina onde será hospedado o servidor. No banco de dados, será salvo apenas um string que irá ter a referencia dessa imagem.
- Sugestão: Implementar sistema de refresh token
Justificativa: O token atual está com a expiração de 48h. Esse tempo de expiração pode ser considerado relativamente alto. Para aumentar a segurança do sistema, pode ser implementado um sistema de refresh token, onde o refresh token terá um tempo de expiração maior, mas para acessar o sistema, será usado o access token que possui uma expiração curta.
- Sugestão: Usar o cors para limitar entre diferentes origens
Justificativa: Quando a aplicação estiver no ar, o cors pode ser usado para que seja possível a comunicação apenas entre as origens necessárias.
-
Sugestão: Retirar o
.env
do repositorio
Justificativa: Uma prática comum de segurança é colocar o caminho do arquivo de variáveis de ambiente, no arquivo
_gitignore_
. O arquivo_gitignore_
já existe no projeto, mas não está ignorando o.env
. Com isso, informações sensíveis ficam expostas, como por exemplo, a conexão com o banco de dados e o secret do token.
- Sugestão: Adicionar mais tratativas de erro no backend
Justificativa: Muitas endpoint possuem apenas um try catch e retornam um erro, geralmente com status 500, se qualquer erro ocorrer. Deveria ser adicionado mais tratativas, por exemplo, antes de tentar realizar a criação de um registro, verificar se já existe no banco, se já existir, retornar 400. Outro exemplo é verificar, ao tentar realizar um delete, se o id do registro que se está tentando deletar, realmente existe. Se não existir, retornar 404.
- Sugestão: Proteção contra ataques de força bruta
Justificativa: Atualmente, não existe nenhum mecanismo de segurança contra ataques de força bruta na autenticação. Desse forma, um algoritmo de força bruta pode ser utilizado para tentar diferentes combinações de senhas para invadir uma conta. Pode ser implementado um mecanismo para detectar e bloquear tentativas de acesso não autorizado à aplicação, como bloqueio de IP após várias tentativas falhas de login.
- Sugestão: Melhorias na criação de Senhas
Justificativa: A criação de senhas seguras é de extrema importância para garantir a proteção dos sistemas e dos dados dos usuários. Atualmente, é possível criar senhas fáceis, o que torna o sistema vulnerável a ataques de força bruta e violações de segurança. É indicado que os administradores do projeto melhorem a segurança do aplicativo, como o uso de: Complexidade da senha, Comprimento mínimo, Restrições de reutilização e Verificação de força da senha.
Trabalho Coletivo feito por PSW, APS e GPTI.
Trabalho Coletivo feito por PSW, APS e GPTI.