Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tech challenge #6

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
./data
./postgres-data
.data
.env
131 changes: 67 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,97 @@
# PT-BR 🇧🇷

# Tech Challenge
Para facilitar os testes é realizado de maneira automatica um seed com um merchant.

O desafio consiste em implementar novas **API's** para trabalhar com as transações de nossos merchants (vendedores).

## Nós precisamos que você implemente:
```
id: 8e33fb74-8bdb-4f38-9f64-ca56c3051fa5
name: Jhon Smith
documentId: 1112223334455
```

## Tecnologias

- Typescript
- NestJS
- RabbitMQ
- Postgres
- TypeORM
- Jest
- Docker

1. Um endpoint para processar transações e pagamentos de um determinado merchant (vendedor)
## Patterns

- Uma transação possui as informações a seguir:
Para melhor abstração da aplicação e consequencimento legibilidade para a condicional do modo de pagamento na entidade payable foi utilizado o abstract factory.
Para (não só) confiabilidade do pipeline durante o processo de pagamento entre os microserviços e pelo ganho em escalabilidade foi utilizado o pattern SAGA (não-completo).
Os services assim como events handler e commands (no caso do saga) são utilizados como camada de dominio.
Os endpoints estão respeitando o padrão restful.

- O valor total da transação
- Descrição da transação, por exemplo "T-Shirt Black M"
- Método de pagamento: **debit_card** ou **credit_card**
- O número do cartão (devemos armazenar e retornar somente os últimos 4 dígitos do cartão, por ser uma informação sensível)
- O nome do dono do cartão
- Data de Expiração
- CVV do cartão
- O id do merchant (vendedor)

Exemplo de transação:
## API docs

| Campo | Valor |
| -------------------- | --------------- |
| Merchant Id | 2441 |
| Description | T-Shirt Black/M |
| Payment Method | Credit_Card |
| Card Number | 4338 |
| Card Holder | John Smith |
| Card Expiration Date | 12/2028 |
| Card CVV | 123 |
```
POST /merchants/:id/transactions
GET /merchants/:id/payables?page=1&limit=10&start_date=yyyy-MM-dd&end_date=yyyy-MM-dd
```

- Ao criar uma transação, também deve ser criado um recebível do merchant (payables), com as seguintes regras de negócio:
ou swagger disponível em
```
http://localhost:3000/docs#
```

- Transação **Debit card**:
## Infraestrutura

- O payable deve ser criado com **status = paid**, indicando que o merchant irá receber o valor
- O payable deve ser criado com a data igual a data de criação (D + 0).
Para solução do desafio proposto segui a arquitetura de microserviços com a utilização do pattern SAGA.

- Transação **Credit card**:
Os principais beneficios da arquitetura de microserviços para este problema é o ganho na escalabilidade, monitoramento e manunteção a longo prazo. Os microserviços só poderão ser utilizados na rede interna, usando como paralelismo uma infraestrutura AWS os microserviços só poderiam ser consultados dentro da VPC.

- O payable deve ser criado com **status = waiting_funds**, indicando que o merchant irá receber esse valor no futuro
- O Payable deve ser criado com a data igual a data de criação da transação + 30 dias (D + 30)
A utilização do pattern SAGA traz o beneficio não só de confiabilidade durante o pipeline do processamento de pagamento como também escalabilidade por todos processamentos serem executados por eventos.
Há um ganho significado na complexidade da aplicação quando utilizado SAGA por conta da interface rxjs implementada pelo framework nestjs, que é o caso do desafio. Para comunicação entre os microserviços foi utilizado o message broker RabbitMQ. O ganho de velocidade do protocolo AMQP ao invés do http traz ganhos significativos em performance da aplicação conforme escala.

- Ao criar payables, devemos descontar uma taxa de processamento (chamada de `fee`). Considere **2%** para transações **debit_card**
e **4%** para transações **credit_card**. Exemplo: Quando um payable é criado no valor de R$ 100,00 a partir de uma transação **credit_card** ele receberá R$ 96,00.
Foi adicionado um serviço de api-gateway no qual expoe dois endpoints http para ser consumido pelo usuario final.
Cada serviço possui o seu proprio banco de dados. A confiabilidade de pesistencia de dados é dada ao uso do SAGA.

Exemplo de payable:
Sugestão de solução na cloud:

| Campo | Valor |
| ----------- | ---------- |
| Merchant Id | 2343 |
| Status | paid |
| Create Date | 08/12/2023 |
| Subtotal | 200 |
| Discount | 4 |
| Total | 196 |
![Microservices architecture](docs/images/architecture-diagram.png#center)

2. Um endpoint que calcule o total de Recebíveis (payables) do merchant num período de datas informado, a resposta deve conter:

- Valor total de recebíveis pagos
- Total cobrado de taxa nos recebíveis pagos
- Valor a receber para o futuro
## Entity relationship diagram

## Pré-requisitos
Utilizado o banco de dados relacional postgres.

Você pode utilizar qualquer linguagem de programação (recomendamos que utilize a que você possui maior familiaridade), frameworks e biblioteca
*Apenas é salvo os ultimos 4 digitos do cartão do usuario no banco de dados. Os dados necessários para o processamento do pagamento é trafegado pelo massage broker.

Para a execução do projeto, é necessário configurar um banco de dados, de preferência relacional, para armazenar os dados(transactions e payables). Recomenda-se utilizar Docker para facilitar o gerenciamento do ambiente de desenvolvimento.
![ERD](docs/images/erd.png#center)

### Configuração do Banco de Dados

O banco de dados deve ser iniciado utilizando o seguinte comando:
## Como executar

```bash
docker compose up
```
docker compose up -d
```
*É necessário possuir docker compose version > v2.24 e docker > 24.0.0 ou execute o serviço postgres antes dos outros*
```
docker compose up -d postgres
docker compose up -d --build
```


## Executar os testes

## Critérios de avaliação
```
npm run test
```

- Assertividade: A aplicação está fazendo o que é esperado? Se algo estiver faltando, o README explica o motivo?
- Legibilidade do código (incluindo comentários)
- Segurança: Existem vulnerabilidades claras?
- Cobertura de testes (Não esperamos cobertura completa)
- Histórico de commits (estrutura e qualidade)
- Escolhas técnicas: A escolha de bibliotecas, banco de dados, arquitetura, etc., é a melhor escolha para a aplicação?
- Escalabilidade: A aplicação é capaz de lidar com um aumento significativo do tráfego?
- Manutenibilidade: O código é fácil de manter e modificar?
- Resiliência: A aplicação é resiliente a falhas e erros inesperados?
ou para executar os testes com coverage

## Como entregar
```
npm run test:cov
```

- Fork esse desafio no seu repositório pessoal. Crie uma branch para desenvolver sua implementação e, assim que finalizar, submeta um pull request na branch main desse repo, marcando @ewma18, @AndreAffonso e @rafaelito91 como reviewers
## TO DO
- Aumentar a cobertura de Testes unitários (principalmente nos metodos saga)
- Funcionalidade de rollback em caso de falhas no pipeline pelo saga
- Monitoramento/Observabilidade
- Melhor abstração das camadas de comunicação com message broker
- Adição de cache
5 changes: 5 additions & 0 deletions api-gateway/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/node_modules
/.data
/dist
/files
.env
40 changes: 40 additions & 0 deletions api-gateway/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
{
singleQuote: true,
parser: 'flow',
},
],
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/no-floating-promises': 'error',
},
};
56 changes: 56 additions & 0 deletions api-gateway/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# compiled output
/dist
/node_modules
/build

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# temp directory
.temp
.tmp

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
5 changes: 5 additions & 0 deletions api-gateway/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf"
}
35 changes: 35 additions & 0 deletions api-gateway/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Nest Framework",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start:debug", "--", "--inspect-brk"],
"autoAttachChildProcesses": true,
"restart": true,
"sourceMaps": true,
"stopOnEntry": false,
"console": "integratedTerminal"
},
{
"type": "node",
"request": "launch",
"name": "Debug Worker Nest Framework",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start:debug",
"--",
"--inspect-brk",
"--config tyr.nest-cli.json "
],
"autoAttachChildProcesses": true,
"restart": true,
"sourceMaps": true,
"stopOnEntry": false,
"console": "integratedTerminal"
}
]
}
8 changes: 8 additions & 0 deletions api-gateway/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:18.16.0-alpine

# RUN npm install -g [email protected]
RUN mkdir -p /var/www/gateway
WORKDIR /var/www/gateway
ADD . /var/www/gateway
RUN npm install
CMD npm run build && npm run start:prod
73 changes: 73 additions & 0 deletions api-gateway/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
</p>

[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest

<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->

## Description

[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.

## Installation

```bash
$ npm install
```

## Running the app

```bash
# development
$ npm run start

# watch mode
$ npm run start:dev

# production mode
$ npm run start:prod
```

## Test

```bash
# unit tests
$ npm run test

# e2e tests
$ npm run test:e2e

# test coverage
$ npm run test:cov
```

## Support

Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).

## Stay in touch

- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)

## License

Nest is [MIT licensed](LICENSE).
Loading