Skip to content

Repositório contendo as atividades da disciplina Arquitetura de Aplicações com Node.Js - professor Samuel Martins da Silva - PUC Minas 2025

License

Notifications You must be signed in to change notification settings

disouzam/atividades-arq-aplicacoes-nodejs-puc-minas-2025

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sobre esse repositório

Repositório contendo as atividades da disciplina Arquitetura de Aplicações com Node.Js - professor Samuel Martins da Silva, parte integrante do curso de Especialização em Arquitetura de Software Distribuído, oferta 9, turma 1, PUC Minas 2025.

Setup do ambiente de desenvolvimento

Configuração do arquivo .gitattributes

CRLF vs. LF: Normalizing Line Endings in Git

echo > .gitattributes

Verificação da versão do Node.JS

Checar a versão ativa do Node.JS

node --version
# v24.5.0 (latest version)

Checar as versões instaladas usando o nvm:

nwm ls
#        v22.18.0
# ->      v24.5.0
# default -> node (-> v24.5.0)
# iojs -> N/A (default)
# unstable -> N/A (default)
# node -> stable (-> v24.5.0) (default)
# stable -> 24.5 (-> v24.5.0) (default)
# lts/* -> lts/jod (-> v22.18.0)
# lts/argon -> v4.9.1 (-> N/A)
# lts/boron -> v6.17.1 (-> N/A)
# lts/carbon -> v8.17.0 (-> N/A)
# lts/dubnium -> v10.24.1 (-> N/A)
# lts/erbium -> v12.22.12 (-> N/A)
# lts/fermium -> v14.21.3 (-> N/A)
# lts/gallium -> v16.20.2 (-> N/A)
# lts/hydrogen -> v18.20.8 (-> N/A)
# lts/iron -> v20.19.4 (-> N/A)
# lts/jod -> v22.18.0

Configurar o alias default para apontar para a versão LTS:

nvm alias default 22.18.0

Mudar para a última versão LTS instalada (LTS = suporte de longa duração) usando o nvm

nvm use default

Comandos adicionados ao arquivo .bashrc para evitar digitá-los a cada nova instância do bash criada:

nvm alias default 22.18.0
nvm use default
node -v

Instalação do nest cli globalmente

npm i -g @nestjs/cli

Criação do projeto

nest new project-manager-api
# selected npm as package manager

Pós-criação

Após a criação do projeto, os arquivos da pasta project-manager-api foram movidos para a raiz do repositório e a pasta project-manager-api foi removida. Com isso, o script para executar o projeto recém-criado foi alterado, removendo a necessidade de alterar o diretório do shell.

mv ./project-manager-api/* ./
rm -r ./project-manager-api

Execução do projeto novo

npm run start
# npm run start:dev - to watch files

Criação de estrutura de pastas para a arquitetura limpa usando domain driven design

# Create folders
mkdir src/domain
mkdir src/domain/entities
mkdir src/domain/interfaces
mkdir src/domain/use-cases
mkdir src/domain/use-cases/projects
mkdir src/domain/use-cases/tasks
mkdir src/domain/use-cases/users
mkdir src/gateways
mkdir src/gateways/controllers
mkdir src/gateways/controllers/projects
mkdir src/gateways/controllers/tasks
mkdir src/gateways/controllers/users
mkdir src/gateways/guards
mkdir src/infrastructure
mkdir src/infrastructure/auth
mkdir src/infrastructure/database
mkdir src/infrastructure/database/entities
mkdir src/infrastructure/database/repositories

# Add empty .gitignore in each one to preserve folder structure while no file is added
echo > src/domain/.gitignore
echo > src/domain/entities/.gitignore
echo > src/domain/interfaces/.gitignore
echo > src/domain/use-cases/.gitignore
echo > src/domain/use-cases/projects/.gitignore
echo > src/domain/use-cases/tasks/.gitignore
echo > src/domain/use-cases/users/.gitignore
echo > src/gateways/.gitignore
echo > src/gateways/controllers/.gitignore
echo > src/gateways/controllers/projects/.gitignore
echo > src/gateways/controllers/tasks/.gitignore
echo > src/gateways/controllers/users/.gitignore
echo > src/gateways/guards/.gitignore
echo > src/infrastructure/.gitignore
echo > src/infrastructure/auth/.gitignore
echo > src/infrastructure/database/.gitignore
echo > src/infrastructure/database/entities/.gitignore
echo > src/infrastructure/database/repositories/.gitignore

Criação dos primeiros arquivos de código

# Controllers
echo > src/gateways/controllers/controller.module.ts
# [Controllers](https://docs.nestjs.com/controllers)
nest g controller gateways/controllers/projects
nest g controller gateways/controllers/tasks
nest g controller gateways/controllers/users

# Interfaces
echo > src/domain/interfaces/user.interface.ts
echo > src/domain/interfaces/task.interface.ts
echo > src/domain/interfaces/project.interface.ts

# Entities
echo > src/domain/entities/project.ts
echo > src/domain/entities/task.ts
echo > src/domain/entities/user.ts

Atividade 2 - Arquitetura Clean

Instalação das dependências adicionais

# [TypeORM module for Nest](https://www.npmjs.com/package/@nestjs/typeorm)
# [TypeORM repository](https://github.com/nestjs/typeorm)

# [TypeORM is an ORM that can run in Node.js, Browser, Cordova, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript (ES2021)](https://www.npmjs.com/package/typeorm)
# [ORM for TypeScript and JavaScript](https://github.com/typeorm/typeorm)

# [Asynchronous, non-blocking SQLite3 bindings for Node.js](https://www.npmjs.com/package/sqlite3)
# [SQLite3 bindings for Node.js repository](https://github.com/TryGhost/node-sqlite3)

# [Allows use of decorator and non-decorator based validation. Internally uses validator.js to perform validation. Class-validator works on both browser and node.js platforms.](https://www.npmjs.com/package/class-validator)
# [Decorator-based property validation for classes.](https://github.com/typestack/class-validator)

# [Class-transformer allows you to transform plain object to some instance of class and versa](https://www.npmjs.com/package/class-transformer)
# [Decorator-based transformation, serialization, and deserialization between objects and classes.](https://github.com/typestack/class-transformer)

npm install --save @nestjs/typeorm typeorm sqlite3 class-validator class-transformer

# [Mapped Types module for Nest used by the @nestjs/graphql and @nestjs/swagger packages.](https://www.npmjs.com/package/@nestjs/mapped-types)
# [Configuration module for Nest framework (node.js) 🐺](https://github.com/nestjs/mapped-types)
npm install --save @nestjs/mapped-types

Estrutura dos módulos

nest g module domain
nest g module domain/use-cases
nest g module domain/use-cases/projects
nest g module domain/use-cases/tasks
nest g module domain/use-cases/users
nest g module infrastructure
nest g module infrastructure/database
nest g module infrastructure/auth
nest g module gateways

Casos de uso

nest g service domain/use-cases/projects/get-all-projects --flat
nest g service domain/use-cases/projects/get-project-by-id --flat
nest g service domain/use-cases/projects/create-project --flat

nest g service domain/use-cases/tasks/get-all-tasks --flat
nest g service domain/use-cases/tasks/get-task-by-id --flat
nest g service domain/use-cases/tasks/create-task --flat
nest g service domain/use-cases/tasks/update-task --flat

nest g service domain/use-cases/users/create-user --flat
nest g service domain/use-cases/users/get-user-by-id --flat
nest g service domain/use-cases/users/get-all-users --flat

Repositórios

nest g service infrastructure/database/repositories/projects.repository --flat --no-spec
nest g service infrastructure/database/repositories/tasks.repository --flat --no-spec
nest g service infrastructure/database/repositories/users.repository --flat --no-spec

Entidades

echo > src/infrastructure/database/entities/project.entity.ts
echo > src/infrastructure/database/entities/task.entity.ts
echo > src/infrastructure/database/entities/user.entity.ts

Implementação dos repositórios

mkdir src/domain/repositories

# Interfaces
echo "import { DeepPartial } from 'typeorm';" > src/domain/repositories/projects-repository.interface.ts
echo "import { DeepPartial } from 'typeorm';" > src/domain/repositories/tasks-repository.interface.ts
echo "import { DeepPartial } from 'typeorm';" > src/domain/repositories/users-repository.interface.ts

# Implementations
echo "import { Injectable } from '@nestjs/common';" > src/infrastructure/database/repositories/projects.repository.service.ts
echo "import { DataSource, DeepPartial, Repository } from 'typeorm';" >> src/infrastructure/database/repositories/projects.repository.service.ts
echo >> src/infrastructure/database/repositories/projects.repository.service.ts
echo "@Injectable()" >> src/infrastructure/database/repositories/projects.repository.service.ts
echo "export class" >> src/infrastructure/database/repositories/projects.repository.service.ts

echo "import { Injectable } from '@nestjs/common';" > src/infrastructure/database/repositories/tasks.repository.service.ts
echo "import { DataSource, DeepPartial, Repository } from 'typeorm';" >> src/infrastructure/database/repositories/tasks.repository.service.ts
echo >> src/infrastructure/database/repositories/tasks.repository.service.ts
echo "@Injectable()" >> src/infrastructure/database/repositories/tasks.repository.service.ts
echo "export class" >> src/infrastructure/database/repositories/tasks.repository.service.ts


echo "import { Injectable } from '@nestjs/common';" > src/infrastructure/database/repositories/users.repository.service.ts
echo "import { DataSource, DeepPartial, Repository } from 'typeorm';" >> src/infrastructure/database/repositories/users.repository.service.ts
echo >> src/infrastructure/database/repositories/users.repository.service.ts
echo "@Injectable()" >> src/infrastructure/database/repositories/users.repository.service.ts
echo "export class" >> src/infrastructure/database/repositories/users.repository.service.ts

Implementação dos casos de uso

mkdir src/gateways/controllers/projects/dtos
echo > src/gateways/controllers/projects/dtos/create-project.dto.ts
echo > src/gateways/controllers/projects/dtos/update-project.dto.ts

mkdir src/gateways/controllers/tasks/dtos
echo > src/gateways/controllers/tasks/dtos/create-task.dto.ts
echo > src/gateways/controllers/tasks/dtos/update-task.dto.ts

mkdir src/gateways/controllers/users/dtos
echo > src/gateways/controllers/users/dtos/create-user.dto.ts
echo > src/gateways/controllers/users/dtos/update-user.dto.ts

Interface para implementação dos casos de uso

echo > src/domain/use-cases/base-use-case.ts

Testes da API implementada até a atividade 2 usando Postman e Newman

Instalação do newman usando a linha de comando

# https://learning.postman.com/docs/collections/using-newman-cli/installing-running-newman/
npm install -g newman

Instruções básicas de uso do newman

Usage: newman [options] [command]

Options:
  -v, --version               output the version number
  -h, --help                  display help for command

Commands:
  run [options] <collection>  Initiate a Postman Collection run from a given URL or path

To get available options for a command:
  newman <command> -h

Os arquivos do Postman foram organizados em Collections e Environments e um script global do PowerShell, chamado Global.CollectionRunner.ps1 foi criado para executar todas as requisições de uma dada coleção de forma automatizada, permitindo salvar logs em arquivo para posterior avaliação.

Uma das possíveis formas de chamar esse script global é

.\Global.CollectionRunner.ps1 -WriteLog yes -LocalEnvironment yes -Verbosity yes

Internamente ao script, chama-se um ou mais scripts do PowerShell para rodar cada coleção individual. No presente momento, há apenas um script Assignment2.CollectionRunner.ps1 que executa toda a coleção Assignment em um comando similar ao apresentado abaixo:

newman run "$($collectionFileName)" --insecure -e "../Environments/$($envFile)" --verbose | Out-File -FilePath "$($collectionName).log" -Encoding oem

e o sumário de uma execução bem sucedida é apresentado no arquivo Collections\Assignment2.log conforme mostrado abaixo:

┌─────────────────────────┬─────────────────────┬────────────────────┐
│                         │            executed │             failed │
├─────────────────────────┼─────────────────────┼────────────────────┤
│              iterations │                   1 │                  0 │
├─────────────────────────┼─────────────────────┼────────────────────┤
│                requests │                   9 │                  0 │
├─────────────────────────┼─────────────────────┼────────────────────┤
│            test-scripts │                   9 │                  0 │
├─────────────────────────┼─────────────────────┼────────────────────┤
│      prerequest-scripts │                   0 │                  0 │
├─────────────────────────┼─────────────────────┼────────────────────┤
│              assertions │                  18 │                  0 │
├─────────────────────────┴─────────────────────┴────────────────────┤
│ total run duration: 1201ms                                         │
├────────────────────────────────────────────────────────────────────┤
│ total data received: 831B (approx)                                 │
├────────────────────────────────────────────────────────────────────┤
│ average response time: 39ms [min: 8ms, max: 132ms, s.d.: 38ms]     │
├────────────────────────────────────────────────────────────────────┤
│ average DNS lookup time: 903µs [min: 903µs, max: 903µs, s.d.: 0µs] │
├────────────────────────────────────────────────────────────────────┤
│ average first byte time: 36ms [min: 6ms, max: 129ms, s.d.: 39ms]   │
└────────────────────────────────────────────────────────────────────┘

Capturas de tela dos testes usando o Postman e registro do banco de dados

Após a inicialização da aplicação, sem arquivo prévio de banco de dados, foram realizadas requisições para a API usando o Postman e os resultados e testes embutidos no Postman serão apresentados a seguir. A Figura 1 mostra o estado da aplicação logo após o startup usando o comando npm run start:

Figura 1: Estado da aplicação após a inicialização Startup da aplicação

As primeiras três requisições ao banco visavam registrar o estado inicial do banco de dados - sem usuários, projetos e tarefas. As Figuras 2, 3, 4, 5, 6 e 7 mostram as requisições e os respectivos testes escritos em Javascript na interface do Postman - que podem ser conferidos diretamente na coleção Assignment2.postman_collection.json

Figura 2: Requisição para retornar todos os usuários do banco - Banco de dados vazio GET All Users - Lista vazia

Figura 3: Requisição para retornar todos os usuários do banco - Testes GET All Users - Testes

Figura 4: Requisição para retornar todos os projetos do banco - Banco de dados vazio GET All Projects - Lista vazia

Figura 5: Requisição para retornar todos os projetos do banco - Testes GET All Projects - Testes

Figura 6: Requisição para retornar todas as tarefas do banco - Banco de dados vazio GET All Tasks - Lista vazia

Figura 7: Requisição para retornar todas as tarefas do banco - Testes GET All Tasks - Testes

As próximas operações consistem da criação de um usuário (Figuras 8 e 9), um projeto para esse usuário (Figuras 12 e 13) e de uma tarefa (Figuras 16 e 17) para esse projeto e testes na própria requisição e requisição de GET por ID para checar a operação anterior de POST (Figuras 10 e 11 - Usuário; Figuras 14 e 15 - Projeto; Figuras 18 e 19 - Tarefas).

Figura 8: Criação de um usuário - Requisição Criação de novo usuário

Figura 9: Criação de um usuário - Testes Criação de novo usuário - Testes

Figura 10: Consulta de usuário pelo ID - Requisição Consulta de usuário por ID

Figura 11: Consulta de usuário pelo ID - Testes Consulta de usuário por ID

Figura 12: Criação de um projeto - Requisição Criação de novo projeto

Figura 13: Criação de um projeto - Testes Criação de novo projeto - Testes

Figura 14: Consulta de projeto pelo ID - Requisição Consulta de projeto por ID

Figura 15: Consulta de projeto pelo ID - Testes Consulta de projeto por ID

Figura 16: Criação de uma tarefa - Requisição Criação de nova tarefa

Figura 17: Criação de uma tarefa - Testes Criação de nova tarefa - Testes

Figura 18: Consulta de tarefa pelo ID - Requisição Consulta de tarefa por ID

Figura 19: Consulta de tarefa pelo ID - Testes Consulta de tarefa por ID

Por fim, requisições que devem retornar coleções - Usuários, Projetos e Tarefas - foram inseridas no final da coleção para uma verificação final da sua implementação. As Figuras 20 a 25 mostram os resultados dessas requisições

Figura 20: Requisição para retornar todos os usuários do banco - Banco de dados com 1 usuário inserido GET All Users - 1 usuário inserido

Figura 21: Requisição para retornar todos os usuários do banco - Testes GET All Users - Testes

Figura 22: Requisição para retornar todos os projetos do banco - Banco de dados com 1 projeto inserido GET All Projects - 1 projeto inserido

Figura 23: Requisição para retornar todos os projetos do banco - Testes GET All Projects - Testes

Figura 24: Requisição para retornar todas as tarefas do banco - Banco de dados com 1 tarefa inserida GET All Tasks - 1 tarefa inserida

Figura 25: Requisição para retornar todas as tarefas do banco - Testes GET All Tasks - Testes

Atividade 3 - Autenticação e Cache

Estrutura da aplicação

Pacotes adicionais - bcrypt, jwt, cache-manager e redis

Alguns pacotes adicionais serão instalados para essa parte da atividade 3. O comando original é apresentado abaixo, junto com os resultados que apontam conflitos com os pacotes instalados anteriormente.

# Original command

# [bcrypt](https://www.npmjs.com/package/bcrypt)
# [bcrypt repository](https://github.com/kelektiv/node.bcrypt.js)

# [Type definitions for bcrypt](https://www.npmjs.com/package/@types/bcrypt)
# [Repository with types for bcrypt](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bcrypt)

# [JWT utilities module for Nest based on the jsonwebtoken package](https://www.npmjs.com/package/@nestjs/jwt)
# [jwt repositories](https://github.com/nestjs/jwt)

# [cache-manager module for Nest originally published as part of the @nestjs/common package. This package is a drop-in replacement for the deprecated CacheModule](https://www.npmjs.com/package/@nestjs/cache-manager/v/2.3.0)
# [cache-manager module repository](https://github.com/nestjs/cache-manager#readme)

# [A cache module for nodejs that allows easy wrapping of functions in cache, tiered caches, and a consistent interface. This module is now part of the Cacheable project](https://www.npmjs.com/package/cache-manager/v/5.7.6)
# [Caching for Nodejs based on Keyv](https://github.com/jaredwray/cacheable#readme)

# [Redis cache store for node-cache-manager](https://www.npmjs.com/package/cache-manager-redis-store/v/2.0.0)
# [Redis cache store repository](https://github.com/dabroek/node-cache-manager-redis-store#readme)

# [Redis](https://www.npmjs.com/package/redis)
# [node-redis repository](https://github.com/redis/node-redis)

npm install --save bcrypt @types/bcrypt @nestjs/jwt @nestjs/cache-manager@2 cache-manager@5 cache-manager-redis-store@2 redis
# Results of original command - Redacted
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: [email protected]
npm error Found: @nestjs/[email protected]
npm error node_modules/@nestjs/common
npm error   @nestjs/common@"^11.0.1" from the root project
npm error
npm error Could not resolve dependency:
npm error peer @nestjs/common@"^9.0.0 || ^10.0.0" from @nestjs/[email protected]
npm error node_modules/@nestjs/cache-manager
npm error   @nestjs/cache-manager@"2" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error {REDACTED}\npm-cache\_logs\2025-09-14T19_54_12_471Z-eresolve-report.txt
npm error A complete log of this run can be found in: {REDACTED}\npm-cache\_logs\2025-09-14T19_54_12_471Z-debug-0.log

Com o objetivo de resolver o conflito, tentar-se-á forçar a resolução de dependências.

# Modified command
npm install --save bcrypt @types/bcrypt @nestjs/jwt @nestjs/cache-manager@2 cache-manager@5 cache-manager-redis-store@2 redis --legacy-peer-deps

Novos módulos de infraestrutura

Novos módulos serão criados conforme os comandos listados abaixo:

nest g module infrastructure/redis
nest g module infrastructure/auth # (it didn't have any impact due to commands executed before)

Um novo serviço será criado dentro da pasta auth:

nest g service infrastructure/auth/auth --flat

Criação de arquivo com constante para uso com o jwt:

echo > src/infrastructure/auth/constants.ts

Caso de uso - Recuperar usuários por e-mail

O comando a ser executado é:

nest g service domain/use-cases/users/get-user-by-email --flat

Criação de um guarda para controle da autenticação

O comando para criação do guard é:

nest g service gateways/guards/auth-guard --flat

Criação de um controller para o login

O comando para criação do controller é:

nest g controller gateways/controllers/auth/auth --flat

Criação de dtos para o login

O comando para criação dos dtos de login via linha de comando é:

echo > src/gateways/controllers/auth/dtos/login.dto.ts

Capturas de tela dos testes usando o Postman

Para ilustrar o funcionamento das configurações de autenticação e autorização, uma pequena coleção (Assignment #3 - Postman collection) foi criada com 3 requisições HTTP usando o Postman. A coleção criada para a atividade 2 foi usada como base.

O tempo de expiração do token foi ajustado em 5 minutos por dois fatores: longo o suficiente para fazer duas ou mais requisições sequenciais sem necessitar obter um novo token e curto o suficiente para expirar durante os testes e permitir checar sua expiração.

A primeira requisição consistiu na criação do usuário com uma senha. Nessa atividade, a senha passou a ser encriptada para ser salva no banco de dados, conforme implementação disponível no Commit 4f4f640: Added encryption of password in creation of users.

A Figura 26 apresenta a requisição para a criação de usuários. Nota-se que essa requisição não carece de autorização nessa implementação presente. Num cenário real, a criação de usuários também é protegida para evitar abusos na criação e acessos ao sistema. Nota-se também que a senha é devolvida na resposta devidamente encriptada. Num cenário real, essa senha não seria devolvida dessa forma, pois não importa ao usuário saber o resultado da encriptação de sua senha, além de expor esse retorno a abusos.

Figura 26: Criação de usuário Criação de usuário - Atividade 3

Na Figura 27, uma requisição para a rota de login (/auth/login) é feita para a obtenção do token de acesso. Essa também é uma requisição que dispensa autorização - sendo a senha e usuário corretos, o token de acesso será usado posteriormente para a autorização de outras rotas.

Figura 27: Obtenção do token de acesso Obtenção do token de acesso - Atividade 3

Para facilitar o uso dessa coleção da forma mais autônoma possível - mesmo que nesse cenário didático a coleção seja pequena e apenas uma requisição vá usar efetivamente o token de acesso - criação de projetos a partir de um usuário autenticado, foi implementado um script que é executado no retorno da requisição para coletar o token de acesso no corpo da resposta e salvar automaticamente na variável de ambiente access_token - dessa maneira, nenhuma intervenção manual é necessária para uso do token.

O script para esse salvamento está reproduzido abaixo e na Figura 28 e está presente também no arquivo da coleção.

const response = pm.response.json();
const access_token_value = response['access_token'];

pm.environment.set('access_token', access_token_value);

console.info('New access token written to environment variable access_token');

Figura 28: Salvamento do token de acesso automaticamente Salvamento do token de acesso na variável de ambiente - Atividade 3

E, por fim, temos a criação do projeto. Foram feitos dois testes para simular o uso ativo do token de acesso.

Na Figura 29, mostra-se o resultado da requisição sem a presença do Bearer Token. Já a Figura 30 mostra o exmeplo de uma requisição bem sucedida. Note que o token é obtido automaticamente das variáveis de ambiente.

Figura 29: Criação de projeto não autorizada pela falta de token de acesso Criação de projeto não autorizada - Atividade 3

Figura 30: Criação de projeto autorizada pela falta de token de acesso Criação de projeto autorizada - Atividade 3

Voltando ao aspecto da encriptação da senha no banco de dados, as Figuras 31 e 32 mostram o salvamento da senha não encriptada como parte da atividade #2 e a senha encriptada como parte da atividade #3

Figura 31: Senha não encriptada Senha não encriptada - Atividade 2

Figura 32: Senha encriptada Senha encriptada - Atividade 3

Atividade 4

Para a atividade 4, será utilizado o Redis para implementação da comunicação entre microserviços. As rotas / serviços de tarefas serão extraídos do projeto principal e será implementado como um microserviço.

Configurações

Criação de arquivo docker-compose.yml:

echo > docker-compose.yml
code docker-compose.yml

Conversão do projeto para sistema de monorepos:

nest generated app tasks

Ajustes na resolução de referências por meio da modificação do caminho no tsconfig.json

"paths": {
  "@project-manager-api/*": [
    "apps/project-manager-api/src/*"
  ]
}

Usando o recurso de busca do VS Code, a string src/ foi substituída por @project-manager-api/ em todos os arquivos na pasta ./apps/project-manager-api

Instalação de pacotes do redis e dos microserviços do nestjs: o parâmetro --legacy-peer-deps foi adicionado para forçar a resolução de dependências e obter sucesso na instalação dos pacotes necessários.

# [microservices package from nestjs](https://www.npmjs.com/package/@nestjs/microservices)
# [NestJS repository](https://github.com/nestjs/nest)

# [A robust, performance-focused and full-featured Redis client for Node.js](https://www.npmjs.com/package/ioredis)
# [ioredis repository](https://github.com/redis/ioredis#readme)

# [node-redis is a modern, high performance Redis client for Node.js.](https://www.npmjs.com/package/redis)
# [node-redis repository](https://github.com/redis/node-redis)

npm i --save @nestjs/microservices@10 ioredis redis@4 --legacy-peer-deps

Criação de uma biblioteca compartilhada entre as aplicações para compartilhar arquivos e interfaces

nest generate lib common

Replicação da arquitetura clean dentro do pacote Tasks:

mkdir apps/tasks/src/gateways
echo > apps/tasks/src/gateways/.gitignore
mkdir apps/tasks/src/gateways/controllers
echo > apps/tasks/src/gateways/controllers/.gitignore
mkdir apps/tasks/src/gateways/controllers/dtos
echo > apps/tasks/src/gateways/controllers/dtos/.gitignore
mkdir apps/tasks/src/infrastructure
echo > apps/tasks/src/infrastructure/.gitignore
mkdir apps/tasks/src/infrastructure/entities
echo > apps/tasks/src/infrastructure/entities/.gitignore
mkdir apps/tasks/src/infrastructure/database
echo > apps/tasks/src/infrastructure/database/.gitignore
mkdir apps/tasks/src/infrastructure/repositories
echo > apps/tasks/src/infrastructure/repositories/.gitignore
mkdir apps/tasks/src/domain
echo > apps/tasks/src/domain/.gitignore
mkdir apps/tasks/src/domain/entities
echo > apps/tasks/src/domain/entities/.gitignore
mkdir apps/tasks/src/domain/interfaces
echo > apps/tasks/src/domain/interfaces/.gitignore
mkdir apps/tasks/src/domain/repositories
echo > apps/tasks/src/domain/repositories/.gitignore
mkdir apps/tasks/src/domain/use-cases
echo > apps/tasks/src/domain/use-cases/.gitignore

Todos os arquivos relacionados às Tasks dentro do projecto project-manager-api serão movidos ou terão seu conteúdo migrado para o pacote tasks

mv ./apps/project-manager-api/src/domain/entities/task.ts ./apps/tasks/src/domain/entities
mv ./apps/project-manager-api/src/domain/interfaces/task.interface.ts ./apps/tasks/src/domain
mv ./apps/project-manager-api/src/domain/repositories/tasks-repository.interface.ts ./apps/tasks/src/domain/repositories
mv -t ./apps/tasks/src/domain/use-cases ./apps/project-manager-api/src/domain/use-cases/tasks/*
mv ./apps/project-manager-api/src/infrastructure/database/entities/task.entity.ts ./apps/tasks/src/infrastructure/entities
mv ./apps/project-manager-api/src/infrastructure/database/repositories/tasks.repository.service.ts ./apps/tasks/src/infrastructure/repositories
cp ./apps/project-manager-api/src/gateways/controllers/tasks/tasks.controller.ts ./apps/tasks/src/gateways/controllers/tasks.controller.ts
mv -t ./apps/tasks/src/gateways/controllers/dtos ./apps/project-manager-api/src/gateways/controllers/tasks/dtos/*

Criar módulos no pacote tasks:

echo > apps/tasks/src/domain/domain.module.ts
echo > apps/tasks/src/gateways/gateways.module.ts
echo > apps/tasks/src/infrastructure/infrastructure.module.ts

Capturas de tela dos testes usando o Postman

Uma nova coleção foi criada para a atividade 4. As primeiras requisições fazem a carga inicial do banco de dados para em seguida permitir o teste das rotas que são manipuladas pelo microserviço de Tasks, que foi extraído - em relação à atividade 3 - do projeto project-manager-api.

Nessa tarefa, três diferentes componentes arquiteturais são necessários:

  1. API de gestão de projetos - criada nas atividades 1 a 3 - project-manager-api, inicializada via npm run start:dev
  2. Instância do Redis para manipular os eventos de tarefas enviados pelo project-manager-api e processado pelo microserviço de Tasks, inicializada via docker-compose up --build
  3. E, por fim, o microserviço de tarefas Tasks que foi extraído da API de gestão de projetos e inicalizada via nest start tasks --watch

As Figuras 33 a 44 mostram os resultados dessa implementação e as legendas proveem explicação adicional sobre cada uma delas. Nas Figuras que exibem o console bipartido horizontalmente, o painel superior é a API project-manager-api e o painel inferior é o microserviço Tasks. Apenas as operações que envolvem as tarefas produzirão logs no painel inferior mas todas as imagens mostrarão ambos os painéis incondicionalmente.

Figura 33: Criação de usuário para popular o banco de dados e permitir as próximas operações Criação de usuário para popular o banco de dados e permitir as próximas operações - Atividade 4

Figura 34: Log de criação do usuário. Note que nesse e em outras imagens nesse repositório as senhas enviadas no corpo da requisição são exibidas em texto plano nos logs a título de exemplo educativo. Essa não é uma prática segura nem recomendada para o uso em sistemas em produção. Log do project-manager-api - Atividade 4

Figura 35: Operação de login para obtenção de token de acesso Operação de login para obtenção de token de acesso - Atividade 4

Figura 36: Detalhes da operação de login: Log exibindo os dados do corpo da requisição, data e horário de expiração do token de acesso e token propriamente dito Log exibindo os dados do corpo da requisição, data e horário de expiração do token de acesso e token propriamente dito - Atividade 4

Figura 37: Criação de um novo projeto Criação de um novo projeto - Atividade 4

Figura 38: Log da criação de novo projeto. Esse e outros logs fazem replicação da resposta enviada ao cliente da API Log da criação de novo projeto. Esse e outros logs fazem replicação da resposta enviada ao cliente da API - Atividade 4

Figura 39: Criação de nova tarefa Criação de nova tarefa - Atividade 4

Figura 40: Log da criação da nova tarefa mostrando o envio de um evento do project-manager-api para o microserviço Tasks. Apesar desses logs não apresentarem timestamps, a sequência de exibição é sempre no painel superior seguida pelo painel inferior, visto que o microserviço Tasks apenas reage aos comandos solicitados. Log da criação da nova tarefa mostrando o envio de um evento do project-manager-api para o microserviço Tasks - Atividade 4

Figura 41: Obtenção de uma tarefa por meio de seu identificador único Obtenção de uma tarefa por meio de seu identificador único - Atividade 4

Figura 42: Log da consulta de tarefa pelo seu identificador Log da consulta de tarefa pelo seu identificador - Atividade 4

Figura 43: Obtenção de todas as tarefas cadastradas Obtenção de todas as tarefas cadastradas - Atividade 4

Figura 44: Log da obtenção de todas as tarefas cadastradas Log da obtenção de todas as tarefas cadastradas - Atividade 4