# 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***.