Skip to content

Instantly share code, notes, and snippets.

@mbmaciel
Created June 29, 2026 13:03
Show Gist options
  • Select an option

  • Save mbmaciel/715f45d40eebe9d40ca96ad20d50ac30 to your computer and use it in GitHub Desktop.

Select an option

Save mbmaciel/715f45d40eebe9d40ca96ad20d50ac30 to your computer and use it in GitHub Desktop.
Integração Asaas BaaS
## Integração Asaas BaaS — Status: ✅ Completo
A integração com o Asaas BaaS (Banking as a Service) está **totalmente implementada** conforme o documento `docs/INTEGRACAO-FINANCEIRA-BAAS.md`. Todos os checklists do documento foram concluídos.
### Arquitetura
```
PlenoCRM (Master API Key)
└── POST /v3/accounts (cria subconta por sindicato)
└── Subconta Sindicato (apiKey + walletId próprios)
├── POST /v3/payments (PIX / Boleto)
├── POST /v3/customers (sync filiado)
├── POST /v3/transfers (transferência automática)
└── Webhook → PlenoCRM (PAYMENT_RECEIVED, PAYMENT_CONFIRMED, etc.)
```
### Arquivos principais
| Arquivo | Responsabilidade |
|---------|-----------------|
| `backend/src/modules/finance/payment.adapters.ts` | Adapter Asaas: `createCharge`, `getPixQrCode`, `getBoletoInfo`, `syncCustomer`, `createSubaccount`, `createTransfer`, `getBalance`, `validateWebhookSignature` |
| `backend/src/shared/crypto.ts` | AES-256-GCM: `encrypt()`, `decrypt()`, `isEncrypted()`, `safeDecryptApiKey()` |
| `backend/src/modules/financeiro/financeiro.routes.ts` | Webhook handler (`POST /financeiro/asaas/webhook`), split de comissão + transferência automática no evento `PAYMENT_CONFIRMED` |
| `backend/src/modules/tenants/tenants.routes.ts` | Criação automática de subconta Asaas ao criar tenant (`criar_subconta_asaas: true`) |
| `backend/src/modules/tenant-admin/tenant-admin.routes.ts` | Máscara da API key (`abcd...wxyz`), criptografia ao salvar nova chave |
| `backend/src/modules/commissions/commissions.routes.ts` | CRUD de regras de comissão, listagem de splits, resumo financeiro, reprocessamento de transferências |
| `database/migrations/043_asaas_financial_tables.sql` | Tabelas: `financial_accounts`, `payment_splits`, `transfers`, `webhook_logs`, `commission_rules` |
| `docs/INTEGRACAO-FINANCEIRA-BAAS.md` | Documento de arquitetura completo com checklist atualizado |
### Criptografia AES-256-GCM
Toda `apiKey` de subconta é armazenada criptografada no banco (`tenant_modules.settings.asaas_api_key`).
```typescript
import { encrypt, decrypt, safeDecryptApiKey, isEncrypted } from '../../shared/crypto.js';
// Ao SALVAR (nunca armazenar em texto puro):
settings.asaas_api_key = encrypt(novaApiKey);
// Ao LER (descriptografa automaticamente, compatível com chaves legadas):
const apiKey = safeDecryptApiKey(settings.asaas_api_key);
```
**Regras de segurança:**
- API key **nunca** é exibida na interface — apenas mascarada como `abcd...wxyz`
- API key **nunca** aparece em logs (`payment_logs`, `audit_log`)
- `getPaymentAdapterForTenant()` descriptografa automaticamente antes de usar
- `maskAsaasApiKey()` descriptografa apenas para exibir os 4 primeiros e 4 últimos caracteres
### Módulo de Comissão (`/commissions`)
Endpoints disponíveis apenas para perfil `MASTER`:
| Método | Rota | Descrição |
|--------|------|-----------|
| `GET` | `/commissions` | Listar todas as regras de comissão |
| `GET` | `/commissions/global` | Regra global (tenant_id = null) |
| `GET` | `/commissions/tenant/:tenantId` | Regra específica de um sindicato |
| `POST` | `/commissions` | Criar/atualizar regra (upsert por tenant_id) |
| `PUT` | `/commissions/:id` | Editar regra existente |
| `DELETE` | `/commissions/:id` | Remover regra (exceto global) |
| `GET` | `/commissions/splits` | Listar splits de comissão (filtros: tenant_id, status, período) |
| `GET` | `/commissions/splits/summary` | Resumo: total bruto, comissão, líquido, quantidade, % médio |
| `GET` | `/commissions/transfers` | Listar transferências (filtros: tenant_id, status) |
| `GET` | `/commissions/transfers/pending` | Transferências com falha aguardando retry |
| `POST` | `/commissions/transfers/:id/retry` | Reprocessar manualmente uma transferência com falha |
**Comportamento padrão:** regra global de 3% fixo é criada automaticamente pela migration 043.
### Fluxo de transferência automática
Quando o Asaas envia o webhook `PAYMENT_CONFIRMED`:
1. Calcula comissão (busca regra do tenant ou global)
2. Registra split em `payment_splits` (gross, commission, net)
3. Cria registro em `transfers` com `status = 'pending'`
4. Chama `POST /v3/transfers` no Asaas
5. Se sucesso: `status = 'processing'`
6. Se falha: `status = 'failed'` + agenda retry com exponential backoff (2, 4, 8, 16, 32, 60 min)
### Variáveis de ambiente necessárias
```env
# Gateway de pagamento (produção: 'asaas', dev: 'mock')
PAYMENT_PROVIDER=asaas
# Asaas — Subconta (usada se não houver tenant_modules configurado)
ASAAS_API_KEY=$ASAAS_SANDBOX_API_KEY
ASAAS_SANDBOX=true
ASAAS_ENVIRONMENT=sandbox
# Asaas — Conta Master (para criar subcontas Marketplace)
ASAAS_MASTER_API_KEY=
# Asaas — Webhook
ASAAS_WEBHOOK_TOKEN=token-configurado-no-painel-asaas
ASAAS_WEBHOOK_ENABLED=false
# Criptografia da API Key (se não definida, usa JWT_SECRET como fallback)
ASAAS_ENCRYPTION_KEY=
```
### Para testar localmente
```bash
# 1. Subir banco
docker compose up -d
# 2. Rodar migrations (inclui a 043 com tabelas financeiras)
cd backend && npm run migrate
# 3. Rodar backend com provider mock (não depende do Asaas real)
PAYMENT_PROVIDER=mock npm run dev
# 4. Rodar testes
cd backend && npx tsx --test src/shared/crypto.test.ts
cd backend && npx tsx --test src/modules/finance/payment.adapters.test.ts
cd backend && npx tsx --test src/app.test.ts
```
### Para usar em produção (sandbox Asaas)
```bash
# Criar tenant com subconta automática:
curl -X POST http://localhost:3333/tenants \
-H "Authorization: Bearer <master_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Sindicato Exemplo",
"slug": "sindicato-exemplo",
"cnpj": "12345678000199",
"email": "financeiro@sindicato.com",
"criar_subconta_asaas": true
}'
# O sistema automaticamente:
# 1. Cria subconta no Asaas via POST /v3/accounts
# 2. Criptografa e salva a apiKey no tenant_modules
# 3. Salva walletId e webhook token
# 4. Configura webhook no Asaas
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment