- Node.js
- Express
- Prisma ORM
- SQLite
- Postman
O projeto utiliza SQLite como SGBD relacional e Prisma como ferramenta de mapeamento objeto-relacional (ORM). Essa escolha facilita a execução local e atende ao critério de persistência com ORM exigido pela disciplina.
-
Instalar as dependências: npm install
-
Criar o arquivo de ambiente: copiar
.env.examplepara.env -
Gerar o client do Prisma: npx prisma generate
-
Executar a migration inicial: y
-
Popular o banco de dados: npm run seed
-
Iniciar o servidor: npm run dev
O projeto utiliza, por padrão, a porta 3000.
- POST /servicos
- GET /servicos
- GET /servicos/:id
- PUT /servicos/:id
- DELETE /servicos/:id
No arquivo ZIP foi incluída a coleção:
eduarda_silva_santos_Desenvolvimento_de_Sistemas_Backend_Fase-1.postman_collection.json
Para testar:
- abrir o Postman;
- importar a coleção;
- definir
baseUrlcomohttp://localhost:3000; - executar primeiro o endpoint de criação;
- usar o
idretornado para testar busca, atualização e remoção.
A entrega contém:
- pasta
servico-gestaocom os arquivos-fonte; - relatório arquitetural em PDF;
- orientações de execução em PDF;
- coleção Postman.
O sistema foi modelado com base nos princípios da Arquitetura Limpa (Clean Architecture), proposta por Robert C. Martin, com o objetivo de garantir baixo acoplamento, alta coesão, facilidade de manutenção, testabilidade e evolução incremental do código-fonte. Nessa abordagem, a solução é organizada em camadas bem definidas, nas quais as dependências sempre apontam para o núcleo de negócio, preservando as regras do domínio e reduzindo o impacto de mudanças em frameworks, banco de dados ou detalhes de interface.
Nesta fase, o foco da implementação está no serviço principal denominado ServicoGestao, responsável por concentrar as operações centrais do domínio. A arquitetura foi estruturada em quatro grandes grupos: Domínio, Aplicação, Interface e Infraestrutura. A camada de domínio contém as entidades e regras essenciais do sistema. A camada de aplicação contém os casos de uso, responsáveis por orquestrar as operações do sistema de acordo com as regras de negócio. A camada de interface adapta as entradas e saídas da aplicação, normalmente por meio de controllers e DTOs. Por fim, a camada de infraestrutura concentra os detalhes técnicos, como persistência de dados, configuração do servidor e implementação concreta dos repositórios.
Essa organização permite que a regra de negócio permaneça protegida de dependências externas. Em termos práticos, isso significa que o sistema pode trocar o mecanismo de persistência, alterar framework web, modificar a forma de exposição da API ou até mesmo incluir novas interfaces sem comprometer a lógica central do serviço.
+-------------------------------------------------------------+
| CAMADA DE INTERFACE |
|---|
| Controllers |
| - ServicoGestaoController |
| DTOs |
| - CriarServicoDTO |
| - AtualizarServicoDTO |
| - ServicoResponseDTO |
| +------------------------------+------------------------------+ |
|
v
+-------------------------------------------------------------+
| CAMADA DE APLICAÇÃO |
|---|
| Use Cases |
| - CriarServicoUseCase |
| - ListarServicosUseCase |
| - BuscarServicoPorIdUseCase |
| - AtualizarServicoUseCase |
| - RemoverServicoUseCase |
| Contratos |
| - IServicoRepository |
| +------------------------------+------------------------------+ |
|
v
+-------------------------------------------------------------+
| CAMADA DE DOMÍNIO |
|---|
| Entidades |
| - ServicoGestao |
| Regras de negócio |
| - ValidadorDeServico |
| +------------------------------+------------------------------+ |
|
v
+-------------------------------------------------------------+
| CAMADA DE INFRAESTRUTURA |
|---|
| Banco de dados / ORM |
| - PrismaClient / TypeORM / Sequelize |
| Repositórios concretos |
| - ServicoRepositoryImpl |
| Configurações |
| - databaseConfig |
| - serverConfig |
| +-------------------------------------------------------------+ |
+------------------------------------------------------+ | ServicoGestaoController | +------------------------------------------------------+ | + criar(dto: CriarServicoDTO) | | + listar() | | + buscarPorId(id: string) | | + atualizar(id: string, dto: AtualizarServicoDTO) | | + remover(id: string) | +------------------------------------------------------+ | | usa v +------------------------------------------------------+ | CriarServicoUseCase | +------------------------------------------------------+ | - servicoRepository: IServicoRepository | +------------------------------------------------------+ | + execute(dto: CriarServicoDTO): ServicoGestao | +------------------------------------------------------+
+------------------------------------------------------+ | ListarServicosUseCase | +------------------------------------------------------+ | - servicoRepository: IServicoRepository | +------------------------------------------------------+ | + execute(): ServicoGestao[] | +------------------------------------------------------+
+------------------------------------------------------+ | BuscarServicoPorIdUseCase | +------------------------------------------------------+ | - servicoRepository: IServicoRepository | +------------------------------------------------------+ | + execute(id: string): ServicoGestao | null | +------------------------------------------------------+
+------------------------------------------------------+ | AtualizarServicoUseCase | +------------------------------------------------------+ | - servicoRepository: IServicoRepository | +------------------------------------------------------+ | + execute(id: string, dto: AtualizarServicoDTO) | +------------------------------------------------------+
+------------------------------------------------------+ | RemoverServicoUseCase | +------------------------------------------------------+ | - servicoRepository: IServicoRepository | +------------------------------------------------------+ | + execute(id: string): void | +------------------------------------------------------+
+------------------------------------------------------+ | <> IServicoRepository | +------------------------------------------------------+ | + create(data: ServicoGestao): ServicoGestao | | + findAll(): ServicoGestao[] | | + findById(id: string): ServicoGestao | null | | + update(id: string, data: ServicoGestao) | | + delete(id: string): void | +------------------------------------------------------+ ^ | | implementa +------------------------------------------------------+ | ServicoRepositoryImpl | +------------------------------------------------------+ | - ormClient: PrismaClient | +------------------------------------------------------+ | + create(data: ServicoGestao): ServicoGestao | | + findAll(): ServicoGestao[] | | + findById(id: string): ServicoGestao | null | | + update(id: string, data: ServicoGestao) | | + delete(id: string): void | +------------------------------------------------------+
+------------------------------------------------------+ | ServicoGestao | +------------------------------------------------------+ | - id: string | | - nome: string | | - descricao: string | | - categoria: string | | - preco: number | | - ativo: boolean | | - createdAt: Date | | - updatedAt: Date | +------------------------------------------------------+ | + validar(): void | | + ativar(): void | | + desativar(): void | | + atualizarDados(...): void | +------------------------------------------------------+
ServicoGestaoController --> CriarServicoUseCase ServicoGestaoController --> ListarServicosUseCase ServicoGestaoController --> BuscarServicoPorIdUseCase ServicoGestaoController --> AtualizarServicoUseCase ServicoGestaoController --> RemoverServicoUseCase
CriarServicoUseCase --> IServicoRepository ListarServicosUseCase --> IServicoRepository BuscarServicoPorIdUseCase --> IServicoRepository AtualizarServicoUseCase --> IServicoRepository RemoverServicoUseCase --> IServicoRepository
ServicoRepositoryImpl ..|> IServicoRepository ServicoRepositoryImpl --> ORM Client
CriarServicoUseCase --> ServicoGestao AtualizarServicoUseCase --> ServicoGestao
A modelagem proposta foi construída para refletir, de maneira objetiva, os princípios SOLID, que orientam a construção de softwares mais modulares, legíveis e sustentáveis ao longo do tempo.
O princípio da responsabilidade única estabelece que cada classe deve possuir apenas um motivo para mudar. No sistema desenvolvido, essa separação foi respeitada da seguinte forma:
- a classe ServicoGestaoController é responsável apenas por receber a requisição, extrair dados de entrada, acionar os casos de uso e devolver a resposta HTTP;
- os Use Cases são responsáveis exclusivamente pela execução das regras de aplicação e orquestração do fluxo de negócio;
- a entidade ServicoGestao representa o núcleo do domínio, encapsulando comportamentos e validações essenciais da regra de negócio;
- a interface IServicoRepository define apenas o contrato de persistência;
- a classe ServicoRepositoryImpl concentra exclusivamente os detalhes de acesso a dados.
Essa divisão reduz acoplamento entre camadas e facilita a manutenção do sistema, pois alterações em uma responsabilidade específica tendem a não impactar as demais.
O princípio aberto/fechado determina que os componentes devem estar abertos para extensão, mas fechados para modificação. No projeto, isso ocorre principalmente pelo uso de abstrações. Os casos de uso dependem do contrato IServicoRepository, e não de uma implementação concreta. Com isso, novas estratégias de persistência podem ser adicionadas sem modificar a lógica de negócio.
Por exemplo, caso o sistema precise trocar o ORM, utilizar outro banco de dados ou incluir uma fonte externa de dados, a alteração principal ocorrerá na infraestrutura, preservando os casos de uso já implementados.
O princípio da substituição de Liskov determina que uma implementação concreta deve poder substituir sua abstração sem comprometer o comportamento esperado do sistema. A classe ServicoRepositoryImpl, ao implementar IServicoRepository, deve respeitar integralmente o contrato definido, retornando tipos e comportamentos compatíveis com aquilo que os casos de uso esperam.
Isso garante previsibilidade e evita que a camada de aplicação dependa de detalhes específicos da infraestrutura.
O princípio da segregação de interfaces orienta que clientes não devem ser forçados a depender de métodos que não utilizam. A interface IServicoRepository foi desenhada para representar apenas as operações necessárias ao contexto do serviço principal, evitando contratos excessivamente genéricos ou inflados.
Essa abordagem favorece clareza, simplicidade e aderência ao domínio implementado nesta fase.
O princípio da inversão de dependência é um dos pontos centrais da Arquitetura Limpa. No sistema proposto, a camada de aplicação depende de abstrações, e não de implementações concretas. Os casos de uso conhecem apenas a interface IServicoRepository, enquanto a implementação concreta fica isolada na infraestrutura.
Com isso, a regra de negócio não depende diretamente de frameworks, bibliotecas de banco de dados ou detalhes de persistência. Essa inversão melhora testabilidade, desacoplamento e portabilidade do sistema.
O projeto também demonstra o uso de padrões de projeto e de organização coerentes com a proposta da disciplina.
O padrão Repository foi utilizado para abstrair o acesso aos dados. Em vez de permitir que os casos de uso manipulem diretamente o ORM ou comandos SQL, toda a persistência é mediada pelo contrato IServicoRepository e sua implementação concreta ServicoRepositoryImpl.
Esse padrão melhora a separação de responsabilidades, facilita testes e reduz o acoplamento entre aplicação e banco de dados.
Cada operação principal do sistema foi encapsulada em um caso de uso específico, como CriarServicoUseCase, ListarServicosUseCase e AtualizarServicoUseCase. Essa decisão torna o fluxo de negócio explícito, melhora a legibilidade do projeto e evita a concentração excessiva de lógica em controllers ou serviços genéricos.
Os DTOs foram utilizados para padronizar a troca de dados entre a camada de interface e a camada de aplicação. Isso ajuda a controlar o formato de entrada e saída, reduz o risco de acoplamento indevido com a entidade de domínio e melhora a organização da API.
Ainda que a implementação possa ser simples nesta fase, a estrutura proposta favorece o uso de injeção de dependência, permitindo que os casos de uso recebam suas dependências no momento da construção. Essa abordagem melhora testabilidade e aderência ao princípio da inversão de dependência.
A Arquitetura Limpa está representada no projeto a partir da separação entre regras centrais de negócio e detalhes externos de implementação. A camada de Domínio representa a parte mais estável do sistema, pois contém os conceitos centrais do negócio. A camada de Aplicação coordena os fluxos e casos de uso, mas ainda sem conhecer detalhes de banco de dados ou protocolo HTTP. A camada de Interface trata a adaptação da entrada e saída da aplicação. Por fim, a camada de Infraestrutura implementa os detalhes técnicos necessários para a execução do sistema.
A principal evidência de aderência à Arquitetura Limpa é a direção das dependências:
- controllers dependem de use cases;
- use cases dependem de abstrações;
- implementações concretas dependem das abstrações;
- o domínio permanece isolado de detalhes externos.
Essa estrutura reduz a propagação de mudanças, facilita testes unitários e torna o projeto mais preparado para crescimento futuro.
servico-gestao/ ├── src/ │ ├── domain/ │ │ ├── entities/ │ │ │ └── ServicoGestao.js │ │ └── rules/ │ │ └── ValidadorDeServico.js │ │ │ ├── application/ │ │ ├── interfaces/ │ │ │ └── IServicoRepository.js │ │ └── usecases/ │ │ ├── CriarServicoUseCase.js │ │ ├── ListarServicosUseCase.js │ │ ├── BuscarServicoPorIdUseCase.js │ │ ├── AtualizarServicoUseCase.js │ │ └── RemoverServicoUseCase.js │ │ │ ├── infrastructure/ │ │ ├── database/ │ │ │ └── prismaClient.js │ │ └── repositories/ │ │ └── ServicoRepositoryImpl.js │ │ │ ├── interfaces/ │ │ ├── controllers/ │ │ │ └── ServicoGestaoController.js │ │ └── dtos/ │ │ ├── CriarServicoDTO.js │ │ ├── AtualizarServicoDTO.js │ │ └── ServicoResponseDTO.js │ │ │ ├── routes/ │ │ └── servicoRoutes.js │ └── server.js │ ├── prisma/ │ └── schema.prisma ├── package.json ├── .env.example └── README.md
Essa estrutura de diretórios reforça a divisão por responsabilidades e favorece a legibilidade do projeto. Além disso, ela está alinhada com o que se espera de um sistema orientado a casos de uso, com separação clara entre regra de negócio, orquestração, adaptação de interface e detalhes de infraestrutura.
O desenvolvimento desta fase exigiu principalmente a organização da solução sob uma perspectiva arquitetural consistente, priorizando desacoplamento e clareza estrutural. Um dos principais desafios desse tipo de modelagem está em evitar que controllers, repositórios e regras de negócio se misturem de forma inadequada, o que é comum em projetos iniciantes. Para resolver esse problema, foi adotada uma separação explícita de responsabilidades entre camadas, com uso de contratos, casos de uso e abstrações de persistência.
Outro desafio relevante é traduzir corretamente os conceitos da Arquitetura Limpa e dos princípios SOLID para uma implementação funcional, sem transformar a estrutura em algo apenas teórico. Por isso, o modelo proposto busca equilibrar organização acadêmica e aplicabilidade prática, permitindo que o sistema seja executável, evolutivo e coerente com os critérios de avaliação da disciplina.
Por fim, a modelagem apresentada fornece base adequada para evolução nas próximas fases, permitindo ampliação do sistema com novas entidades, novos casos de uso e novas integrações sem comprometer a integridade da arquitetura.
Este texto está pronto para compor a seção arquitetural do PDF, porém ainda existe um ponto que precisa ser tratado com rigor: os nomes das entidades, atributos e operações precisam refletir exatamente o domínio definido no documento complementar da disciplina. Em outras palavras, a estrutura arquitetural está correta, mas o conteúdo semântico do UML precisa ser ajustado ao enunciado real do ServicoGestao.
Isso é importante porque, para avaliação com nota máxima, não basta apresentar uma arquitetura limpa e bem explicada. O diagrama e a implementação precisam estar semanticamente coerentes com o problema proposto pela disciplina. Portanto, antes de fechar a entrega, recomenda-se revisar:
- nome e finalidade da entidade principal;
- atributos obrigatórios da entidade;
- operações realmente exigidas pelo serviço principal;
- possíveis entidades auxiliares do domínio;
- endpoints efetivamente implementados no projeto e no Postman.
Quando esses elementos forem alinhados ao enunciado complementar, este material passa a ficar muito mais próximo de uma versão final realmente forte para avaliação máxima.