1.10.0 • Published 2 years ago

ms_communication v1.10.0

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Provi Tech Team

Quality Gate Status Coverage

Objetivo

Projeto responsável por toda a comunicação entre a Provi e os alunos e parceiros. O microsserviço é encarregado da chamada de eventos, como disparo de e-mails, SMS, Webhooks e integrações CRM. Além disso, o projeto roda eventos em background de outros microsserviços.

Conteúdo

  1. Rodando o projeto
  2. Documentação da API
  3. Estrutura do projeto
  4. SQS Events
  5. Criando E-mails
  6. Postman Enterprise
  7. Testes
  8. Tech stack
  9. Próximos passos

🐍️ Rodando o projeto

docker-compose up -d

Para visualizar os logs do projeto

$> docker logs ms_communication

📎 Documentação da API

Utilizamos jsDocs para criar a documentação da API e também para criar uma simples tipagem em funções, a fim de facilitar o processo de desenvolvimento. Para acessar rapidamente a documentação da api, execute o comando

$> npm run doc

🧬 Estrutura do Projeto

A estrutura do projeto é baseada principalmente em filas SQS. De forma simplificada, o projeto roda diversos consumers, sendo que cada um possui uma fila. Cada consumer recebe uma mensagem da fila, que funciona de modo F.I.F.O (First In First Out) ou standard. A mensagem recebida possui os eventos que devem ser executados e as variáveis necessárias para a execução. Para saber mais sobre filas tradicionais e FIFO, procure ler esse Medium, e para um entendimento mais profundo sobre o funcionamento de filas SQS é interessante ler a documentação da AWS. A imagem abaixo mostra de forma simplificada esse processo.

Consumers

Na pasta src > app > controllers > consumers se encontram todos os consumers criados e a função createConsumer. Dessa forma, para criar um novo consumer, basta executar essa função passando um objeto como parâmetro, contendo a url da fila, o nome do consumer e os eventos que serão executados, como no exemplo abaixo.

{
  newConsumer: createConsumer({ queueUrl: awsQueueUrl, consumerName: 'Some new interesting consumer', consumerEvents: emailEvents }),
}

Mensagens

As mensagens disparadas são objetos contendo um array de strings com o nome do evento que será executado, além das variáveis necessárias para a execução. Como o event runner não é case sensitive, o nome do evento não precisa seguir a risca as letras maiúsculas e minúsculas.

  {
	 "events": ["creditRequestUpdate"],
	 "data": {
	 	  "CreditRequestId": 32355
	 }
  }

Event Runner

A função eventRunner tem a responsabilidade de executar de forma ascendente os eventos que as mensagens possuem. Ela se encontra na pasta src > app > controllers > eventRunner. Dessa forma, cada consumer vai chamar essa função quando precisar rodar os eventos.

💼 SQS Events

Esse projeto funciona de uma forma diferente dos outros microsserviços. Diferente dos outros, ele não trabalha por meio de múltiplos endpoints, no qual cada um realiza um serviço, mas sim por meio de eventos. Todos os eventos criados estão na pasta src > app > services > sqsEvents, sendo desde envios de E-mails, SMS, integrações CRM, até eventos mais complexos envolvendo a régua de crédito. No arquivo Index de cada pasta do sqsEvents, encontra-se o evento relacionado a cada bloco. A estrutura básica de cada evento deve seguir os seguintes passos:

  1. Receber e validar os parâmetros
  2. Realizar uma validação se o evento deve ser executado mesmo com os parâmetros envolvidos.
  3. Executar o evento usando métodos statics ou prototypes

O exemplo abaixo mostra como o evento creditRequestUpdate é estruturado:

const creditRequestUpdate = async ({ CreditRequestId }) => {
  try {
    if (!CreditRequestId) throw new MissingProperty({ event: 'creditRequestUpdate', message: `Missing CreditRequestId` })

    /** @type {CreditRequest} */
    const creditRequest = await db.CreditRequest.getCreditRequest(CreditRequestId)

    if (!creditRequest)
      throw new MissingProperty({
        event: 'creditRequestUpdate',
        message: `Missing CreditRequest for CRID ${CreditRequestId}`
      })

    await creditRequest.updateOrCreateHubspotDeal()
    await creditRequest.notifyPartner()
  } catch (error) {
    errorHandler({ error, event: 'creditRequestUpdate' })
    return
  }
}

Criando um novo evento

Para criar um novo evento, basta encontrar a pasta que melhor adeque ao seu propósito. Se não existe uma que encaixe nessa finalidade, fique a vontade para criar uma, só não se esqueça que cada pasta será executada por um tipo de fila e alguns eventos, como os que demoram mais de 30 segundos para serem executados, podendo demandar uma fila com uma configuração diferenciada para evitar erros de execução. Os eventos gerados até agora são do tipo:

  • CRM: Integrações CRM com ferramentas como Hubspot, beMoby e Webhooks.
  • Data Exports: Exportações de dados para parceiros via CSV.
  • CreditRule: Requisições feita para terceiros que fornecem dados, ajudando na tomada de decisão de crédito.
  • CreditRequestServices: Requisições que afetam a creditRequest. Por exemplo: Cancelar todos os CRIDs de um parceiro
  • Email Services: Relacionados a e-mails do tipo transaction
  • Sign In Services: Relacionados a e-mails do tipo sign in
  • SMS Services: Relacionados a verificação de telefone ou qualquer tipo de comunicação por SMS.
  • Pre Approved Services: Serviços que rodam a lógica de aprovação instantânea.

Testando eventos

Para testar a execução de algum evento, rode o projeto localmente e faça o consumer apontar para uma fila teste. Dessa forma, realizando um POST no endpoint v1/admin/send-message a mensagem será disparada para a fila. O exemplo abaixo mostra como deve ser o body da request no endpoint:

{
  "queue": "https://sqs.sa-east-1.amazonaws.com/999685507619/luciano-dev.fifo",
  "events": ["creditRequestUpdate"],
  "data": {
    "CreditRequestId": 32355
  }
}

✉️ Criando E-mails

Esse projeto além de ter uma estrutura para o disparo de e-mails, ele também consegue criar, deletar e atualizar templates de e-mails para disparo. Na pasta src > templates estão disponíveis os templates gerados.

Criando um template

Para criar um novo template, ache a melhor pasta que encaixe o propósito do e-mail e crie uma nova pasta. Assim, crie um arquivo index.js, um .html e um .txt. Só não se esqueça que os arquivos .txt e .html devem ter o mesmo nome. Dessa forma, o arquivo index.js deve seguir a seguinte estrutura:

module.exports = {
  sendEmailParams: {
    toAddresses: toAddresses,
    templateName: 'WELCOME_EMAIL',
    templateData: JSON.stringify({
      footer: footer,
      header: header,
      regards: regards,
      subject: '[Provi] Seu link de acesso!',
      webSdkUrl: 'https://www.google.com',
      emailTitle: 'emailTitle',
      isISA: false
    })
  },
  updateTemplateParams: {
    templateName: 'WELCOME_EMAIL',
    subject: '{{subject}}',
    htmlFilePath: 'SignInTemplates/welcome/WELCOME_EMAIL.html',
    textFilePath: 'SignInTemplates/welcome/WELCOME_EMAIL.txt'
  }
}

Sendo o primeiro objeto sendEmailParams o grupo de informações que serão usadas para o disparo de um e-mail teste. Já o segundo objeto updateTemplateParams são as informações para criar e atualizar o template.

Observações sobre o objeto updateTemplateParams:

  • templateName: Adicione o nome do template com todas as letras maiúsculas seguindo o padrão snake case.
  • subject: Adicione o assunto de forma dinâmica usando {{}}.
  • htmlFilePath: Adicione o caminho do arquivo .html considerando a pasta templates como a pasta raíz.
  • textFilePath: Adicione o caminho do arquivo .txt considerando a pasta templates como a pasta raíz.

Após isso, no arquivo awsService da pasta templates, mude o caminho onde ocorre a desestruturação dos objetos anteriores. Por exemplo:

const { sendEmailParams, updateTemplateParams } = require('./SignInTemplates/welcome')

Após isso, descomente a função do evento que você deseja executar. Por exemplo:

// CREATE TEMPLATE -----------------

emailTemplateService.createTemplate(updateTemplateParams)

Lembre de não executar mais de uma função por vez. Após isso basta executar o comando

node src/templates/awsService.js

Finalmente na pasta src > templates > emailTemplateService é possível fazer alterações no ambiente da criação do e-mail, sendo:

// USE region 'us-east-1' for create emails in Production
const PRODUCTION_EMAIL_REGION = 'us-east-1'

// USE region 'us-east-2' to create Emails in Staging
const STAGING_EMAIL_REGION = 'us-east-2'

🛀 Postman Enterprise

Todos os endpoints disponíveis no ms_communication estão dentro do Postman Enterprise, na pasta MSCommunication

🧚 Testes

A aplicação foi desenhada para rodar os testes em jest considerando três cenários diferentes. A lógica está splitada entre testes unitários, teste de integração e o setup que roda todos os testes disponiveis na aplicação

Executando testes

npm run test:unit

Vai executar os testes unitários presentes na pasta __tests__/unit/, nesse formato os testes unitários foram desenhados para serem executados utilizando mocks para todas as chamadas ao banco ou externas.

npm run test:integration

Vai executar os testes de integração presentes na pasta __tests__/integration, nesse cenário o framework vai subir um container de docker permitindo que os testes usem chamadas ao banco. Como uma cópia das tables é feita, mas não uma cópia dos dados, o ideal é utilizar factories para criar dados de acordo com cada teste.

npm run test:ci

Vai executar todos os testes da aplicação e fazer as considerações do coverageThreshold presentes no arquivo jest.config.js

🪄 Tech stack

⏭️ Próximos passos

  • Retirar as funções desnecessárias de outros microsserviços
  • Refatorar os eventos SQS para serem mais orientados a validações
  • Refatorar a estrutura de disparo de SMS e e-mails
  • Iniciar processo de alteração das regions das queues utilizadas
  • Alterar a logica dos pipelines de hubspot

License

The use of this project is intended solely for Provi purposes. Unauthorized use will be legally impaired.