# BACEN

Configuracao da integracao com o Banco Central do Brasil (BACEN) via RSFN para operacao no ecossistema PIX.

## Pre-requisitos

- Certificados ICP-Brasil instalados (ver [Certificados](./certificates))
- Adesao ao arranjo PIX formalizada junto ao BACEN
- Acesso a RSFN (Rede do Sistema Financeiro Nacional)
- Codigo ISPB (8 digitos) da instituicao
- Variaveis `BACEN_ENABLED=true` e `BACEN_ENV` configuradas

## Arquitetura de Conectividade

```mermaid
flowchart LR
    subgraph PIX["Monetarie PIX"]
        BC["Bacen.Client<br/>(Finch HTTP/2)"]
        CR["ChannelRouter<br/>(GenServer)"]
        EL["ErrorLookup<br/>(ETS Cache)"]
        XV["XSD Validator"]
        AL["AuditLogger<br/>(10yr retention)"]
    end

    subgraph RSFN["RSFN — Rede do Sistema Financeiro Nacional"]
        subgraph CPM["CPM — Canal Primario"]
            DICT_CPM["DICT API<br/>:16422/:16522"]
            SPI_CPM["ICOM/SPI Primario<br/>:16422/:16522"]
        end
        subgraph CSM["CSM — Canal Secundario"]
            SPI_CSM["ICOM/SPI Secundario<br/>:17422/:17522"]
        end
    end

    BC -->|mTLS| DICT_CPM
    BC -->|mTLS + pacs.*| SPI_CPM
    BC -->|mTLS + camt.*| SPI_CSM
    CR --> BC
    EL --> BC
    BC --> XV
    BC --> AL
```

## URLs do BACEN

### Homologacao

| Servico | URL | Porta |
|---------|-----|-------|
| DICT API v2 | `https://dict-h.pi.rsfn.net.br:16522/api/v2` | 16522 |
| ICOM/SPI Primario | `https://icom-h.pi.rsfn.net.br:16522` | 16522 |
| ICOM/SPI Secundario | `https://icom-sec-h.pi.rsfn.net.br:17522` | 17522 |

### Producao

| Servico | URL | Porta |
|---------|-----|-------|
| DICT API v2 | `https://dict.pi.rsfn.net.br:16422/api/v2` | 16422 |
| ICOM/SPI Primario | `https://icom.pi.rsfn.net.br:16422` | 16422 |
| ICOM/SPI Secundario | `https://icom-sec.pi.rsfn.net.br:17422` | 17422 |

### Configuracao

A selecao de ambiente e feita pela variavel `BACEN_ENV`:

```bash
# Homologacao (padrao)
export BACEN_ENV="homolog"

# Producao
export BACEN_ENV="production"
```

## Roteamento de Canais (CPM/CSM)

O BACEN define dois canais de mensageria obrigatorios desde 2023:

### CPM — Canal Primario de Mensageria

Para mensagens **financeiras** (movimentacao de valores):

| Tipo de Mensagem | Descricao | Canal |
|------------------|-----------|-------|
| `pacs.008` | Transferencia de Credito | CPM |
| `pacs.002` | Relatorio de Status | CPM |
| `pacs.004` | Devolucao | CPM |
| `pain.001` | Solicitacao de Pagamento | CPM |

### CSM — Canal Secundario de Mensageria

Para mensagens **nao-financeiras** (consultas e operacionais):

| Tipo de Mensagem | Descricao | Canal |
|------------------|-----------|-------|
| `camt.060` | Consulta de Saldo | CSM |
| `pibr.001` | Echo Request | CSM |
| `pibr.002` | Echo Response | CSM |
| `admi.*` | Administrativas | CSM |
| `pain.002+` | Informativas | CSM |

### ChannelRouter (GenServer)

O `Shared.Bacen.ChannelRouter` gerencia o roteamento e monitoramento de saude dos canais:

```mermaid
stateDiagram-v2
    [*] --> Healthy
    Healthy --> Degraded: 2 falhas consecutivas
    Degraded --> Down: 3 falhas consecutivas
    Down --> Healthy: Health check OK (a cada 2min)
    Degraded --> Healthy: Requisicao bem-sucedida
    Healthy --> Healthy: Requisicao bem-sucedida
```

| Estado | Comportamento |
|--------|--------------|
| **Healthy** | Usa canal preferencial |
| **Degraded** | Usa canal preferencial, mas monitora de perto |
| **Down** | Failover para canal alternativo. Health check a cada 2 minutos |

### Configuracao do ChannelRouter

| Variavel | Padrao | Descricao |
|----------|--------|-----------|
| `BACEN_FAILOVER_ENABLED` | `true` | Habilitar failover automatico |
| `BACEN_FAILURE_THRESHOLD` | `3` | Falhas consecutivas para marcar como Down |
| `BACEN_HEALTH_CHECK_INTERVAL` | `30` | Intervalo de verificacao (segundos) |

## Tratamento de Erros (RFC 7807)

Todas as respostas de erro seguem o padrao RFC 7807 (Problem Details for HTTP APIs):

### ProblemDetails

O modulo `Shared.Bacen.ProblemDetails` gera respostas no formato:

```json
{
  "type": "https://dict.pi.rsfn.net.br/api/v2/error/EntryNotFound",
  "title": "Entry Not Found",
  "status": 404,
  "detail": "A chave PIX informada nao foi encontrada no DICT.",
  "violation": {
    "reason": "EntryNotFound",
    "property": "key"
  }
}
```

Content-Type: `application/problem+json`

### ErrorLookup (ETS Cache)

O `Shared.Bacen.ErrorLookup` mantem um cache ETS de codigos de erro BACEN com refresh a cada 10 minutos:

| Parametro | Valor |
|-----------|-------|
| Storage | ETS table (in-memory) |
| Refresh | 10 minutos |
| Codigos | 161 codigos de erro BACEN |
| Lookup | `{:error, :bacen_code, "AB03"}` |
| Fonte | `monetarie_spi_ref.error_codes` |

### Mapeamentos de Erro

O sistema mapeia mais de 40 razoes de erro para codigos HTTP:

| Razao | HTTP Status | Descricao |
|-------|-------------|-----------|
| `EntryNotFound` | 404 | Chave PIX nao encontrada |
| `EntryAlreadyExists` | 409 | Chave PIX ja cadastrada |
| `InvalidEntry` | 400 | Dados da chave invalidos |
| `AccountLockedByOwner` | 403 | Conta bloqueada pelo titular |
| `InternalError` | 500 | Erro interno do BACEN |
| `ServiceUnavailable` | 503 | Servico BACEN indisponivel |
| `RateLimitExceeded` | 429 | Limite de requisicoes excedido |

## Validacao XSD

O FluxiQ PIX implementa validacao dupla de mensagens ISO 20022:

### Estrategia Dual

```mermaid
flowchart LR
    MSG["Mensagem XML"] --> V1["Validacao Estrutural<br/>(:xmerl + regras Elixir)"]
    MSG --> V2["Validacao XSD<br/>(xmllint)"]
    V1 --> R["Resultado<br/>armazenado em<br/>bacen_api_validations"]
    V2 --> R
```

| Estrategia | Ferramenta | Descricao |
|------------|------------|-----------|
| Estrutural | `:xmerl` + Elixir | Verifica campos obrigatorios e formatos via regras |
| XSD | `xmllint` | Valida contra schema XSD oficial do BACEN |

### Schemas XSD

27 tipos de mensagem com schemas definidos:

| Tipo | Schema | Campos Obrigatorios |
|------|--------|---------------------|
| `pacs.008` | `pacs.008.001.08` | BizMsgIdr, MsgId, EndToEndId, TxId, amount, debtor, creditor |
| `pacs.002` | `pacs.002.001.10` | BizMsgIdr, MsgId, OrgnlEndToEndId, TxSts |
| `pacs.004` | `pacs.004.001.09` | BizMsgIdr, MsgId, OrgnlEndToEndId, amount |
| `pacs.028` | `pacs.028.001.03` | BizMsgIdr, OrgnlEndToEndId |
| `camt.060` | `camt.060.001.05` | BizMsgIdr, BalType |
| `pibr.001` | `pibr.001.001.01` | BizMsgIdr, EchoData |
| `pibr.002` | `pibr.002.001.01` | BizMsgIdr, EchoData |

### Validacao Assincrona

A validacao e executada via `Task.start` (nao bloqueante):

```elixir
# Validacao assincrona em mensagens inbound e outbound
Task.start(fn ->
  result = Shared.Validation.XsdValidator.validate(xml, message_type)
  Shared.Repo.insert!(%BacenApiValidation{
    message_id: msg_id,
    validation_type: "xsd",
    result: result,
    validated_at: DateTime.utc_now()
  })
end)
```

## Auditoria

### Requisitos de Retencao

| Tipo de Mensagem | Retencao | Requisito |
|------------------|----------|-----------|
| Mensagens ICOM (SPI) | **10 anos** | Resolucao BCB |
| Consultas DICT (leitura) | **2 anos** | Resolucao BCB |
| Eventos administrativos | **5 anos** | Politica interna |

### Fluxo de Auditoria

```mermaid
flowchart LR
    MSG["Mensagem BACEN"] --> LOG["BacenLogger<br/>(async via Task.start)"]
    LOG --> XML["XmlArchiver<br/>(arquivo XML)"]
    XML --> HASH["SHA-256 hash<br/>(integridade)"]
    HASH --> DB["monetarie_audit<br/>(PostgreSQL)"]
    DB --> EXP["Export JSONL.gz<br/>(cold storage)"]
    EXP --> GCS["GCS Bucket<br/>(futuro)"]
```

| Componente | Modulo | Descricao |
|------------|--------|-----------|
| Logger | `Shared.Audit.BacenLogger` | Log assincrono (nao-bloqueante) com `Logger.warning` |
| Archiver | `Shared.Audit.XmlArchiver` | Arquivo XML com hash SHA-256 de integridade |
| Purge | `Shared.PartitionManager` | Purga diaria de registros expirados |
| Export | JSONL gzipped | Exportacao para armazenamento frio |

## Simulador BACEN

Para desenvolvimento e testes sem conexao real com o BACEN:

```bash
# Habilitar simulador
export SIMULATOR_ENABLED="true"
export BACEN_ENABLED="false"
```

O simulador substitui as chamadas reais ao BACEN com respostas simuladas. Veja [Simulador](../administration/simulator) para detalhes completos.

### Teste de Conectividade

```bash
# Verificar conectividade com BACEN (homologacao)
curl -v --cert cpic.pem --key cpic-key.pem \
  --cacert bacen-ca.pem \
  https://dict-h.pi.rsfn.net.br:16522/api/v2/health

# Via aplicacao (Kubernetes)
kubectl exec -n pix deployment/pix-backend -- \
  bin/monetarie_pix rpc "Shared.Bacen.Client.health_check()"
```

## Modulos BACEN

| Modulo | Localizacao | Funcao |
|--------|-------------|--------|
| `Shared.Bacen.Client` | `apps/shared/lib/shared/bacen/client.ex` | Cliente HTTP para BACEN |
| `Shared.Bacen.ChannelRouter` | `apps/shared/lib/shared/bacen/channel_router.ex` | Roteamento CPM/CSM |
| `Shared.Bacen.ErrorLookup` | `apps/shared/lib/shared/bacen/error_lookup.ex` | Cache de codigos de erro |
| `Shared.Bacen.ProblemDetails` | `apps/shared/lib/shared/bacen/problem_details.ex` | Respostas RFC 7807 |
| `Shared.Validation.XsdValidator` | `apps/shared/lib/shared/validation/xsd_validator.ex` | Validacao XSD |
| `Shared.Validation.MessageSchemas` | `apps/shared/lib/shared/validation/message_schemas.ex` | Schemas de mensagem |
| `Shared.Audit.BacenLogger` | `apps/shared/lib/shared/audit/bacen_logger.ex` | Log de auditoria |
| `Shared.Audit.XmlArchiver` | `apps/shared/lib/shared/audit/xml_archiver.ex` | Arquivo XML |

## Resultado Esperado

Apos a configuracao da integracao BACEN:

- O `ChannelRouter` inicia e monitora a saude dos canais CPM e CSM
- O `ErrorLookup` carrega 161 codigos de erro na ETS com refresh a cada 10 minutos
- Mensagens financeiras (`pacs.*`) sao roteadas para o CPM (porta 16422/16522)
- Mensagens nao-financeiras (`camt.*`, `pibr.*`) sao roteadas para o CSM (porta 17422/17522)
- Failover automatico redireciona trafico quando um canal fica inativo
- Todas as mensagens sao auditadas com hash SHA-256 de integridade
- Validacao XSD assincrona verifica mensagens inbound e outbound
- Respostas de erro seguem o formato RFC 7807 (`application/problem+json`)
