# Distribuição de payins/payouts
## Contexto
### Motivação
Sempre que uma instituição falha temos que manualmente checar qual instituição está ativa e trocar automaticamente.
Precisamos automatizar esse processo para que todos possam **dormir em paz**.
### Objetivo
- Detecção instânanea de erros nas instituições bancárias
- Chaveamento de instituições de acordo com ordem de prioridade escolhida
## Proposta
### Novas aplicações:
`transferocaas-banking-service`
`transferocaas-adapters-monitor-service`
`transferocaas-pix-bucket`
### Funcionalidades:
> - API para comunição síncrona com os adapters
- Geração de QRCode
- Consulta de saldo
- Comprovantes
>- Background Services / Azure Functions
- PixPaymentBucket
- AdaptersHealthMonitor
### Discussões/Decisões Técnicas
### 1. Como compartilhar status dos adapters para todas as aplicações interessadas?
> **Opções:**
> - **Usar cache compartilhado *(Azure Cache for Redis)***
> **Solução**:
A cada mudança de status, será guardado o status na cache. Assim qualquer nó de qualquer aplicação interessada nesse status imediatamente terá a informação do status atual do adapter.
> **PROS**
- Todos os serviços sempre terão a mesma informação, de forma sincronizada.
- Apenas um acesso Read-Only será necessário nos serviços.
> **CONS**
- Custo Adicional (R$ 200/mês aprox.)
-
> - **Publicar toda mudança de status em um tópico *(Topic/Azure ServiceBus)***
> **Solução**:
A cada mudança de status, será publicado uma nova mensagem no tópico. Cada aplicação interessada terá uma subscription e deverá consumir e cachear esse status da melhor maneira.
> **PROS**
- Integração assíncrona entre os serviços/informação.
- Sem custo adicional.
> **CONS**
- Para aplicação com multiplos nós, apenas um consumirá o tópico. Logo causará dessincronia de informação entre os nós de um mesmo serviço.
- Implementação customizada para cada serviço interessado.
-
> - **HTTP Request para pegar o status atual de cada adapter**
> **Solução**:
Sempre que uma aplicação se interessar no status atual do adapter, ela fará um request para o serviço de monitoramento e conseguirá essa informação de forma síncrona. E, a fim de dimuinuir o consumo, a aplicação cacheará o retorno do status do adapter.
> **PROS**
- Implementação simples (apenas um novo request)
- Sem custo adicional.
> **CONS**
- Dessincronização de informação. Um adapter pode mudar de status e o serviço só ficar sabendo após sua cache interna expirar.
- Alto consumo de recursos se não tiver cache.
> **Decisão:** Usar cache compartilhado *(Azure Cache for Redis)*
### Dependências
> - CosmosDB
- openbanking (somente Account)
- caas-adapters-health **(new)**
- pix-payment-bucket **(new)**
> - Azure Service Bus
- payment-bucket-queue **(new)**
- caas-adapters-monitor-queue **(new)**
- ~~caas-adapters-health **(new) (topic)**~~
> - Azure Redis for cache ([see](https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/cache-dotnet-core-quickstart))
- caas-adapters-status **(new)**
> - Banking Adapters (Genial, Stone, BS2, BIND, Frick)
### Aplicações impactadas
> - openbanking-api
> - payment-processor
# Fluxos
## 1. Banking Service API
### O que é?
> Nova API onde ficará centralizada toda a lógica realicionada a Banking, comum a todos os adapters de moedas FIAT.
> A idéia é tirar toda lógica relacionada à esses adapters de dentro da *openbanking-api* e centralizar nesse serviço
### Fluxo proposto
Todo o fluxo no openbanking-api que chama os adapters síncronamente (via HTTP Request) deverão passar por essa nova API.
Os fluxos são:
- Criação de QR Code Dinâmico
- Consulta de Saldo
- Geração de comprovante
- Cadastro de novas contas para monitoramento
## 2. Adapters Health Monitoring
### O que é?
>Sistema de monitoramento que acompanha a *saúde* dos adapters bancários.
>A idéia é implementarmos um serviço que consuma os mensagens de todos os adapters, trate e repasse essa informação a todos os serviços afetados.
### Definições
A disponibilidade do adapter será avaliada em dois fluxos:
- **Deposit**: fluxo de pay-in (geração de QR Code)
- **Payment**: fluxo de pay-out (envio de pagamentos)
Que poderão ter os seguintes estados:
- <span style="color:gray">**Out**</span>: Adapter fora de operação *(configurado manualmente)*.
- <span style="color:red">**Suspended**</span>: Adapter com operação suspensa devido a falha.
- <span style="color:chocolate">**PartiallySuspended**</span>: Adapter funcionando porém pode apresentar falhas.
- <span style="color:green">**Healthy**</span>: Adapter funcionando.
onde:
- Os estados <span style="color:red">**Suspended**</span> e <span style="color:chocolate">**PartiallySuspended**</span> DEVEM POSSUIR um tempo de expiração.
- Ao expirar, será aplicado a seguintes lógica de *recovery*:
- <span style="color:red">**Suspended**</span> **-->** <span style="color:chocolate">**PartiallySuspended**</span>, com o mesmo tempo expiração.
- <span style="color:chocolate">**PartiallySuspended**</span> **-->** <span style="color:green">**Healthy**</span>, sem tempo de expiração
### Fluxo proposto
1. Todas as chamadas à API externas possuirão alertas configurados **(App Insights)**.
2. Para cada adapter, serão definidas as regras para que um alerta seja triggado e dispare um webhook para ***transferocaas-adapters-monitor-service***.
Esse alerta poderá ser dos seguintes tipos:
- Critical
- High
- Medium
3. Cada webhook recebido é mapeado para um modelo definido e publicado na fila ***caas-adapters-monitor-queue***.
4. O serviço ***transferocaas-adapters-monitor-service*** consumirá todas as mensagens dessa fila e salvará no Cosmos DB (nova collection).
5. Cada nova entrada no banco disparará uma função para mudar o status do adapter, com as seguintes regras:
- Para mensagens **Critical** -> mudar para status **Suspended** por 30 min.
- Para mensagens **High** -> mudar para status **Suspended** por 10 min.
- Para mensagens **Medium** -> mudar para status **PartiallySuspended** por 10 min.
6. Persisitir o novo AdapterStatus no CosmosDB.
7. Persisitir o novo AdapterStatus no Redis Cache.
```
key: Stone
value: {
"Deposit": "Suspended",
"Payment": "Suspended"
}
expires_in: 12h
```
8. **A cada 5 minutos**, disparar um serviço será disparado para executar a lógica de *recovery*.
## 3. QR Code distributed creation
### O que é?
> No fluxo de criação de QR Code dinâmicos para pay-in, a aplicação poderá distribuir o payout nas seguintes condições:
> - Account configurada para distribuir pay-in em mais de uma instituição
> - Adapter configurado para receber pay-in não está ativo.
### Fluxo proposto
1. O documento de Account terá uma nova propriedade
```
{
//propriedade atual
"AccountTypesPayIn": {
"{Blockchain}": {paymentGroupType}
},
//nova propriedade
"PayInConfiguration": {
"{Blockchain}": [
{
"Adapter": "{paymentGroupType}", //adapter configurado
"Priority": 1, //prioridade de uso
"Probability": 0.7 //prob. para distribuição ativa
},
{
"Adapter": "{paymentGroupType}",
"Priority": 2,//prioridade de uso
"Probability": 0.3 //prob. para distribuição ativa
},
{
"Adapter": "{paymentGroupType}",
"Priority": 3, //prioridade de uso - usada somente se os outros falharem
"Probability": 0.0 //prob. para distribuição ativa
}
]
},
}
```
2. Quando a API solicitar a criação de um novo QR Code, será escolhido aleatóriamente o adapter para ser criado (levando em conta a probabilidade configurada.)
3. Caso o adapter escolhido esteja indisponível ([ref](#2-Adapters-Health-Monitoring)) ou falhe na criação, o adapter de maior prioridade será usado para gerar.
4. Caso todos os adapters configurados estejam indisponíveis ou falhem, será retornado erro.
## 4. Payment Distribution
### O que é?
> No fluxo de criação de enviar pagamentos para os adapters, o payment-processor poderá distribuir o payout nas seguintes condições:
> - Account configurada para distribuir pagamentos em mais de uma instituição
> - Adapter configurado para receber pagamentos não está ativo.
### Fluxo proposto
1. O documento de Account terá uma nova propriedade
```
{
//propriedade atual
"AccountTypesPayOut": {
"{Blockchain}": {paymentGroupType}
},
//nova propriedade
"PayOutConfiguration": {
"{Blockchain}": [
{
"Adapter": "{paymentGroupType}", //adapter configurado
"Priority": 1, //prioridade de uso
"Probability": 1.0 //prob. para distribuição ativa
},
{
"Adapter": "{paymentGroupType}",
"Priority": 2,//prioridade de uso
"Probability": 0.0 //prob. para distribuição ativa
},
{
"Adapter": "{paymentGroupType}",
"Priority": 3, //prioridade de uso - usada somente se os outros falharem
"Probability": 0.0 //prob. para distribuição ativa
}
]
},
}
```
2. Quando um pagamento for aprovado, será escolhido aleatóriamente o adapter para ele ser enviado (levando em conta a probabilidade configurada.)
3. Caso o adapter escolhido esteja indisponível ([ref](#2-Adapters-Health-Monitoring)) o pagamento será enviado para o próximo adapter de maior prioridade.
4. Caso todos os adapters configurados estejam indisponíveis, o payment não será processado e entrará num fluxo de espera até algum adapter esteja disponível.
## 5. Pix Payment Bucket (PPB)
#### O que é?
>O sistema PIX conta com uma política de proteção usando o conhecido algoritmo de [token bucket](https://en.wikipedia.org/wiki/Token_bucket).
>A idéia é implementarmos o mesmo algoritmo do nosso lado para que seja possível prever e atuar nos erros antes mesmo que ele aconteça.
#### Fluxo de pagamentos FIAT (já implementado)
>Todo pagamento Pix segue o seguinte fluxo dentro dos adapters:
>1. Payment recebido do CaaS via fila e cadastrado no DB com status **pending**.
>2. A API do banco é chamada para consultar a chave PIX informada no payment. Após isso temos três cenários possíveis:
2.1. **Chave PIX não existe:**
2.2. **Conta de destino não pertence ao taxId informado:**
2.3. **Conta de destina válida**
>:::info
>:pushpin: Nos cenários 2.1 e 2.2, mudamos o status do payment diretamente para **processedWithError**.
>:::
>3. A API do banco é chamada novamente para iniciar o pagamento.
>4. Esperamos via webhook/polling a confirmação do pagamento.
>5. Depois de confirmado (erro ou sucesso), noticamos o CaaS.
#### Fluxo Proposto do PPB
>1. Toda instituição terá um balde com capacidade máxima (e inicial) de 2.000 fichas.
>
>No cenário de hoje teremos:
> | Instituição | Capacidade (Max)|
> | ----------------- |:---------- |
> | Stone JUST | 2000 |
> | Stone 3RZ | 2000 |
> | BS2 JUST | 2000 |
> | BS2 3RZ | 2000 |
> | Genial | 2000 |
>2. Todo resultado de **consulta de chave pix** *(item 2 acima)* é notificado à fila ***payment-bucket-queue***.
>3. Todo pagamento **confirmado** *(item 5 acima)* é notificado à fila ***payment-bucket-queue***.
>4. O BackgroundService do PPB consome ativamente a fila ***payment-bucket-queue*** e cada mensagem afeta o número de fichas na seguinte forma:
- **Consulta de chave Pix válida:** <span style="color:red">**-2 fichas**</span>
- **Consulta de chave Pix inválida:** <span style="color:red">**-10 fichas**</span>
- **Pagamento confirmado:** <span style="color:blue">**+2 fichas**</span>
>5. O balde também possuirá um incrementador recorrente de fichas com <span style="color:blue">**2 fichas/minuto**</span>.
>6. Cada balde terá os seguintes limites de operação configuráveis:
- **Limite de atenção (Lo)** -> Ativa status de ***Atenção*** / Inativa status de ***Suspensão de operação***.
- **Limite crítico (LoLo)** -> Ativa status de ***Suspensão de operação***.
E, toda vez que a quantidade de fichas no balde ultrapassar esses limites uma mensagem de status será disparado na fila ***caas-adapters-monitor-queue***.