# Importação do histórico legado AutBank (PIX e SPB) para produção — mapa de→para

Data: 2026-07-08
Autor: sessão de engenharia Monetarie
Estado: proposta de design para revisão do dono

## 1. Objetivo e mandato

Existe obrigatoriedade regulatória junto ao Banco Central de manter o histórico das mensagens e operações PIX/SPB. O sistema legado (AutBank/AB) foi descontinuado em 30/06/2026 e a cabine própria da Monetarie entrou em produção em julho/2026. É preciso importar o histórico legado para os sistemas de produção da Monetarie, com um mapeamento de→para de tabelas e colunas que permita uma carga sequencial, idempotente e auditável.

Decisões já tomadas pelo dono (2026-07-08):

1. Forma do histórico: **fásico**. Fase 1 = arquivo bruto de mensagens BACEN (retenção legal). Fase 2 = entidades de negócio (ordens, créditos, devoluções, MED, extratos, chaves) para o histórico ficar consultável nas telas e relatórios.
2. Escopo: **PIX completo mais o pouco de SPB** que existe.
3. Destino: **tabelas vivas da cabine**, com marcador de origem legada, embutindo as travas de segurança que o ETL anterior já identificou.

## 2. Fatos empíricos das fontes (validados no restore local)

Backups SQL Server restaurados no container `monetarie-bak-mssql` (16 bancos). Bancos com histórico real:

| Banco legado | Domínio | Tabelas | Linhas | Observação |
|---|---|---|---|---|
| `AB_PAGAMENTO_INSTANTANEO` | PIX | 435 | 3.484.249 | O acervo real do PIX |
| `AB_MGI` | SPB | 77 | 1.413.551 | ~90% é catálogo de mensagens; histórico real pequeno |
| `AB_MGI_DDAMSG` | SPB/DDA | 72 | 590.002 | Idem, quase tudo catálogo |
| `AB_PAGAMENTO_INSTANTANEO_EXTRATO` | PIX extrato | 11 | 13.257 | Movimentos de extrato |
| `AB_PAGAMENTO_INSTANTANEO_METRICAS` | PIX métricas | 15 | 51.995 | Métricas/dashboards, descartável |
| demais (`AB_GX_*`, `AB_GI_*`, satélites) | — | — | ~0 a 300 | Agendamento/notificação/triagem vazios |

Janela temporal do histórico (min..max):

- PIX: `MSG_ENDERECAMENTO_ENVIADA` 2025-11-27 .. 2026-06-30; `ORDEM_PAGAMENTO` 2025-12-02 .. 2026-06-26; `ANOTACAO_CREDITO` 2025-12-02 .. 2026-06-30; `MENSAGEM_BACEN_PSP` 2025-12-02 .. 2026-06-30.
- SPB: `TRANS_INTERF_PASS.DTHRINC` 2025-12-02 .. 2026-06-24; `TRANS_SISTEMAS.DATAMOVTO` 2026-06-17 .. 2026-06-30.

Conclusão: histórico legado ~novembro/2025 a 30/06/2026, sem sobreposição com os dados nativos de julho/2026. Fronteira de corte limpa.

Chave privada e certificados: as chaves privadas NÃO estão nos backups (ver `docs/... / memória monetarie-autbank-backup-no-private-key`). Tabelas de segredo (`CERTIFICADOS` com chave, `PARAMETROS`, `PARAMETROS_MQ`, `PARAMETROS_SEGURANCA`, `THUMBPRINT_*`, `DOWNLOAD_CERTIFICADOS_SITE`, `TESTE_CONECTIVIDADE`) ficam FORA da importação por design.

## 3. Alvos de produção (destino)

### PIX (banco `mon_pix`, multi-schema)

- Ledger canônico de pagamentos: `monetarie_spi.messages` (particionado por `operation_time`) + `monetarie_spi.payments` (`amount numeric(18,5)`, subcentavo). É o que as telas e relatórios leem. NÃO usar `monetarie_spi.transactions` como alvo primário (tabela de contexto quase vazia; o loader anterior mirava nela e deve ser retargetado).
- Arquivo bruto: `monetarie_spi.bacen_outbound` (enviadas), `monetarie_spi.bacen_inbound` (recebidas), `monetarie_spi_msg.xml_messages` (corpo XML por id), `monetarie_audit.xml_audit_logs` (auditoria XML com retenção).
- Histórico de status: `monetarie_spi.message_history`.
- DICT: `monetarie_dict.keys`, `.claims`, `.infractions`, `.med_requests`, `.refund_requests`, `.funds_recoveries`, `.cid_files`, `.cid_events`, `.operations`.
- Extrato/saldo: `monetarie_spi.statements` + `.statement_entries`; `monetarie_spi.balances` + `.balance_history` + `.balance_blocks`.
- Devolução: `monetarie_spi.returns` (canônica) e `monetarie_dict.refund_requests` (MED).

### SPB (banco `mon_spb`, schema `public`)

- Arquivo bruto e ledger de mensagem: `public.bacen_messages` (central).
- Operação pai: `public.spb_operations`; eventos: `public.operation_events`; histórico de estado: `public.message_state_history`.
- Certificados (opcional, histórico): `public.our_signing_certificates` / `public.institution_certificates`.

## 4. Arquitetura da importação

Reaproveitar o loader já existente e comprovado ao centavo: `etl/legacy_pix_spb/load_legacy_pix_spb.py` (2.406 linhas, versionado). Ele faz `setup / stage / project / fix-spb / verify` usando apenas `sqlcmd` (leitura) e `psql` (escrita), sem drivers. A lógica de→para e os mapas de status já estão nele e foram reconciliados no laboratório local. O que precisa mudar para produção está na seção 9.

Fluxo em três camadas:

1. Staging bruto: cada linha de origem vira JSONB em `legacy_ab_pix.source_rows` / `legacy_ab_spb.source_rows`, com idempotência por `{source_db, source_table, source_pk}`.
2. Projeção: SQL determinístico transforma staging nas tabelas vivas de destino, com `NOT EXISTS` / `ON CONFLICT DO NOTHING` sobre chaves naturais.
3. Rastro reverso: cada linha projetada é registrada em `legacy_ab_pix.final_links` / `legacy_ab_spb.final_links` (`source_pk -> target_schema/table/pk`), permitindo auditoria e reprocessamento.

Marcador de origem legada (obrigatório em tabelas vivas):

- Prefixo `LEGACY-` em toda chave natural/idempotente (message_id, resource_id, return_id, notification_id, control_number...) para nunca colidir com índices únicos vivos.
- Coluna de proveniência: usar as colunas `source` já existentes (`monetarie_spi.messages` não tem `source`; usar `resource_id`/`str_control` com marcador e/ou `json_input->>'source'='legacy_ab_pix'`; `bacen_inbound/outbound` guardam o marcador no `resource_id`; `bacen_messages.source='legacy_ab_spb'`; `statements.source='legacy_ab_pix'`; `spb_operations.created_by='legacy_ab_spb'`).
- KPIs, dashboards, saldos e conciliações devem filtrar proveniência legada (ver travas na seção 8).

## 5. Fase 1 — arquivo bruto de mensagens (de→para)

Objetivo: reter o XML enviado/recebido, indexado por tipo, E2E/ISPB e data. Cobre a obrigação regulatória sozinho.

### PIX — enviadas → `monetarie_spi.bacen_outbound`

| Origem `AB_PAGAMENTO_INSTANTANEO` | Coluna origem | Destino `bacen_outbound` |
|---|---|---|
| `MSG_ENDERECAMENTO_ENVIADA` | `ID` | `resource_id` = `'LEGACY-ENDER-'||ID` |
| | `TIPO_MSG` | `message_type` |
| | `MSG` (varbinary gzip) | descompactar → `xml_content` |
| | `DATA` | `send_time`, `send_date` (::date) |
| | `CPF_CNPJ`, `ID_REIVINDICACAO`, `HEADERS` | preservar em `problem`/metadado |
| `MSG_SOLICITACAO_DEVOLUCAO_ENVIADA` | idem shape | `resource_id`=`'LEGACY-SDEVOL-'||ID` |
| `MSG_RELATO_DE_INFRACAO_ENVIADA` | `ID`,`TIPO`,`MENSAGEM`,`DATA_HORA`,`HEADERS` | `resource_id`=`'LEGACY-RINFR-'||ID` |
| `MENSAGEM_BACEN_PSP` (+ `_MENSAGEM`) | `ID`,`COD_MSG`,`ISPB_ORIGEM/DESTINO`,`MENSAGEM`,`DATA_HORA_REGISTRO` | `message_id`=`'LEGACY-ABPI-'||ID`, `message_type`=`COD_MSG`, `ispb`, `xml_content` |
| `MENSAGENS_LPI` | conteúdo LPI | `resource_id`=`'LEGACY-LPI-'||pk` |

### PIX — recebidas → `monetarie_spi.bacen_inbound`

| Origem | Coluna | Destino `bacen_inbound` |
|---|---|---|
| `MSG_ENDERECAMENTO_RECEBIDA` | `ID`,`TIPO_MSG`,`MSG`,`DATA` | `resource_id`=`'LEGACY-ENDER-R-'||ID`, `message_type`, `xml_content`, `receive_time`/`receive_date` |
| `MSG_SOLICITACAO_DEVOLUCAO_RECEBIDA` | idem | `resource_id`=`'LEGACY-SDEVOL-R-'||ID` |
| `MSG_RELATO_DE_INFRACAO_RECEBIDA` | idem | `resource_id`=`'LEGACY-RINFR-R-'||ID` |
| `MENSAGEM_RESPOSTA_BACEN_PSP` (+ `_MENSAGEM`) | `ID`,`MENSAGEM`,`DATA_HORA_REGISTRO`,`HEADERS` | `resource_id`=`'LEGACY-ABPI-RESP-'||ID` |
| `MENSAGENS_LPI_RETORNO` | conteúdo | `resource_id`=`'LEGACY-LPI-R-'||pk` |

O corpo XML de cada mensagem também alimenta `monetarie_spi_msg.xml_messages` (direção pela tabela de origem) e, quando exigido para auditoria com cabeçalhos, `monetarie_audit.xml_audit_logs` (com `pi_end_to_end_id`, `ispb_sender/receiver`, `retention_expires_at`).

Observação: `MSG` e `MENSAGEM` são gzip (`1F8B08`) na origem; a projeção precisa descompactar antes de gravar `xml_content text`.

### SPB — corpo de mensagem → `public.bacen_messages`

| Origem `AB_MGI` | Coluna | Destino `bacen_messages` |
|---|---|---|
| `CORPO_TRANS_INTERF_PASS` (+ `CORPO_TRANS_INTERF_USMSG_PASS`) | `XML` | `xml_content` |
| | regex `<CodMsg>` do XML | `message_type` |
| | `CODSISTEMA_O` (`SPB`=inbound; `EB/GI/SGR`=outbound) | `direction` |
| | `NUMCTRLSPB`/`NUMCTRLSTR` (inbound com prefixo `LEGACY-`) | `control_number_clearing` |
| | `DTHRINC` | `sent_at`/`received_at` |
| | fixo `legacy_ab_spb` | `source`, `message_id`=`'LEGACY-SPB-'||pk` |

## 6. Fase 2 — entidades de negócio (de→para)

### PIX — pagamento de saída: `ORDEM_PAGAMENTO` (+ `STATUS_ORDEM_PAGAMENTO`, `ORDEM_PAGAMENTO_MENSAGEM`, `BLOQUEIO_ORDEM_PAGAMENTO`) → `monetarie_spi.messages` + `monetarie_spi.payments`

Retarget do loader (que mirava `cecresa_spi.transactions`) para o par canônico `messages`+`payments`.

| Origem | Destino `messages` / `payments` |
|---|---|
| `ORDEM_PAGAMENTO.END_TO_END` | `messages.end_to_end_id`, `payments` via FK |
| `BLOQUEIO_ORDEM_PAGAMENTO.VALOR` (ver unidade, seção 8) | `payments.amount` |
| literal `'46026562'` | `messages.debtor_ispb` |
| `BLOQUEIO.NOME/CPF_CNPJ/NRO_CONTA/TIPO_CONTA/COD_AGENCIA` | `payments.debtor_name/debtor_cpf_cnpj/debtor_account/...` |
| `BLOQUEIO.COD_ISPB_CONTRA_PARTE/NOME_CONTRA_PARTE/CPF_CNPJ_CONTRA_PARTE/NRO_CONTA_CONTRA_PARTE` | `messages.creditor_ispb`, `payments.creditor_name/creditor_cpf_cnpj/creditor_account` |
| `BLOQUEIO.CHAVE_ENDERECAMENTO` | `payments.creditor_proxy` |
| `ORDEM.DATA_HORA_REGISTRO` | `messages.operation_time`, `movement_date` (::date) |
| terminal liquidado (ts) | `messages.settlement_time`, `accounting_date` |
| `STATUS_ORDEM_PAGAMENTO` terminal (mapa seção 7) | `messages.status_id` |
| regex `\m(FRAD|[A-Z]{2}[0-9]{2})\M` em `INFORMACAO_ADICIONAL` | reason code (quando rejeitado) |
| fixo `outbound` | `messages.direction` |
| `'LEGACY-ABPI-OP-'||ID` | `messages.message_id` / `resource_id` (idempotência) |
| `STATUS_ORDEM_PAGAMENTO` (todas as transições) | `monetarie_spi.message_history` (history_time, status_id, return_data) |
| `BLOQUEIO_ORDEM_PAGAMENTO` (+ status) | `monetarie_spi.balance_blocks` (reference_id com marcador, status pelo mapa) |

Cuidado com a partição: `messages` é particionada por `operation_time`. Criar partições mensais 2025_11, 2025_12, 2026_01, 2026_02 antes da carga (as 2026_03..06 já existem). Sem isso as linhas caem em `messages_default`.

### PIX — crédito de entrada: `ANOTACAO_CREDITO` (+ `STATUS_ANOTACAO_CREDITO`) → `monetarie_spi.messages`+`payments` (direção inbound) e/ou `monetarie_spi.credit_notifications`

`ANOTACAO_CREDITO` é rica (E2E, ISPB, conta, contraparte, valor, status, devolução pacs.004, saque/troco, finalidade). Mapear:

| Origem `ANOTACAO_CREDITO` | Destino |
|---|---|
| `END_TO_END` | `messages.end_to_end_id` (inbound), `credit_notifications.end_to_end_id` |
| `VALOR` (ver unidade) | `payments.amount` / `credit_notifications.amount` |
| `COD_ISPB` (nós) / `COD_ISPB_CONTRA_PARTE` | `messages.creditor_ispb` / `debtor_ispb` |
| `CPF_CNPJ`,`NOME`,`NRO_CONTA`,`TIPO_CONTA`,`COD_AGENCIA` | dados do recebedor (nós) |
| `CPF_CNPJ_CONTRA_PARTE`,`NOME_CONTRA_PARTE`,`NRO_CONTA_CONTRA_PARTE` | dados do pagador |
| `DATA_HORA_REGISTRO` | `operation_time` / `booking_date` |
| `STATUS_ANOTACAO_CREDITO` (EFETIVADO/CANCELADO) | status / `credit_notifications.processed` |
| `COD_DEVOLUCAO_PACS004`,`INFO_DEVOLUCAO_PACS004`,`INFO_ERROS` | motivo de devolução/erro |
| `ID_ANOTACAO_CREDITO` | `notification_id`=`'LEGACY-AC-'||ID_ANOTACAO_CREDITO` |
| campos de saque (`VALOR_SAQUE/TROCO/COMPRA`, `MODALIDADE_AGENTE`, `PRESTADOR_SERVICO_SAQUE`) | preservar em `payments`/json |

Decisão de modelagem: como o dono quer o histórico nas tabelas vivas e consultável como transação, o alvo primário do crédito é `messages`+`payments` (inbound), com `credit_notifications` como espelho quando aplicável. Confirmar na revisão.

### PIX — devolução: `SOLICITACAO_DEVOLUCAO`, `ANOTACAO_DEVOLUCAO`, `PROCESSA_PACS004`, `DEVOLUCAO_ESPECIAL` → `monetarie_spi.returns` e `monetarie_dict.refund_requests`

| Origem | Destino |
|---|---|
| `SOLICITACAO_DEVOLUCAO` (MED) | `monetarie_dict.refund_requests` (`refund_id`=`'LEGACY-...'`, `bacen_creation_time`, `status` pelo mapa) |
| `ANOTACAO_DEVOLUCAO` / pacs.004 | `monetarie_spi.returns` (`return_id`=`'LEGACY-RETAD-'||ID`, `original_end_to_end_id`) |

### PIX — infração/MED: `RELATO_DE_INFRACAO` (+ `_OPERACAO_RELATOR`, `_CONTESTADO`), `PROCESSA_MED` → `monetarie_dict.infractions` (+ `med_requests`, `funds_recoveries`)

Mapear enum DICT como está (CLOSED/CANCELLED preservados). Usar as colunas `bacen_creation_time`/`bacen_last_modified` de `monetarie_dict.infractions` para carregar as datas ORIGINAIS do BACEN.

### PIX — extrato: `AB_PAGAMENTO_INSTANTANEO_EXTRATO` + `CAMT053/052/054` → `monetarie_spi.statements` + `statement_entries`

| Origem | Destino |
|---|---|
| cabeçalho de extrato | `statements` (`source='legacy_ab_pix'`, `statement_id`=`'LEGACY-...'`) |
| linhas de movimento (`SEQUENCIAL`, `NATUREZA C/D`, `VALOR`, `END_TO_END_ORIGINAL`, `STATUS`) | `statement_entries` (credit_debit, booking_date, amount, end_to_end_id) |
| `CAMT053` (834) | conciliar como extrato importado ou arquivo bruto (bacen_inbound) |

### PIX — chaves e claims: `CLAIM_PORTABILITY`, `CONSULTA_DICT_RESPOSTA`, `PARTICIPANTE_PIX`, `ENDERECAMENTO`

| Origem | Destino |
|---|---|
| `CLAIM_PORTABILITY` (12) | `monetarie_dict.claims` (portabilidade) |
| `ENDERECAMENTO` (303) | `monetarie_dict.keys` (chaves de endereçamento do legado) ou view read-only |
| `PARTICIPANTE_PIX` (809) | referência (diretório de participantes) — ver seção 8, provavelmente já semeado em prod |

### PIX — movimentos contábeis: `MOVIMENTOS_CONTABEIS_*`, `MOVIMENTOS_CONTA_PI`, `SALDO_CONTA_PI` → contabilidade (GATED)

Projetar só após o `chart_of_accounts` da cabine PIX estar semeado. Alvo: `monetarie_settlement.journal_entries`/`accounting_events`. Enquanto a COA estiver vazia, manter como view/staging (não projetar). `SALDO_CONTA_PI`/`BALANCO_SALDO_SPI` só via gate explícito (não sobrescrever saldo vivo).

### SPB — operações: `TRANS_INTERF_PASS` + `TRANS_SISTEMAS` → `public.spb_operations` (+ `operation_events`, `bacen_messages.operation_id`)

| Origem `AB_MGI` | Destino `spb_operations` |
|---|---|
| `NUMCTRLIF`/`NUMCTRLSPB`/`NUMCTRLSTR` (inbound com `LEGACY-`) | `control_number`/`control_number_clearing` |
| `CODINST`/`CODINSTLIQ` | `sender_ispb`/`receiver_ispb` |
| `VALORMOVTO` | `amount` (verificar unidade subcentavo) |
| `NATUREZA` (C/D) | direção contábil |
| `DATAMOVTO`/`DATARESERVA`/`DTHRINC`/`DTHRR1` | timestamps de ciclo |
| `CODEVENTO`/`TIPO_M` | `message_type`/`message_category` |
| composto `STATUSSGR/STATUSSTR/SITUACAO` (mapa seção 7) | `state` |
| `CODREJEICAO`/`CODERRO`/`MOTIVOREJEI` | `error_code`/`error_description`/`reason_code` |
| fixo `legacy_ab_spb` | `created_by`; `nuop`=`'LEGACY-SPB-'||pk` |
| 1 evento sintético por operação | `operation_events` (`event_type='legacy_import'`) |

### SPB — certificados (opcional): `CERTIFICADOS` (colunas `NUMSERIE`,`ISPB`,`DTINI`,`DTFIM`,`CN`,`CA`,`STATUS_CER`,`CONTAINER`) → `public.institution_certificates` / `our_signing_certificates`

Somente metadado público (série, validade, CN, AC). Sem chave privada (não existe nos backups). Útil como histórico de certificados ativados. `PBKEY1/PBKEY2` são chave pública, não privada.

## 7. Mapa oficial de status legado (reaproveitado, provado ao centavo)

PIX ordem `STATUS_ORDEM_PAGAMENTO` → status canônico: `EFETIVADA→settled(9)`, `RECUSADA→rejected`, `ERRO→cancelled`, `ICOM→accepted`, `AGENDADA→pending`, senão `pending`.

PIX crédito `STATUS_ANOTACAO_CREDITO`: `EFETIVADO→processed=true`, `CANCELADO→processed=false`.

PIX bloqueio `STATUS_BLOQUEIO_ORDEM_PAGAMENTO`: `APROVADO→confirmed`, `RECUSADO→released`, `ERRO→cancelled`.

PIX extrato `STATUS`: `SUCESSO→booked`, `ERRO→legacy_erro` (auditoria, nunca afeta saldo). `INDDEVOLUCAO=1`→perna de devolução.

SPB composto (avaliar de cima para baixo):
1. `SITUACAO='C'`→cancelled; 2. `STATUSSGR='9'`→r1_rejected; 3. `SGR='5' AND STR='02' AND CODSISTEMA_O='SPB'`→confirmed; 4. `SGR='5' AND STR='02'`→r1_confirmed; 5. `SGR='5' AND STR IN ('04','05')`→r1_rejected; 6. `SGR='5' AND STR='06'`→processing; 7. `SGR='3' AND STR=''`→created; 8. `SGR IN ('1','2') AND STR=''`→created; 9. `SGR='' AND STR=''`→confirmed (inbound de rede); 10. senão→processing.

Códigos SPB ainda não mapeados (mapear para `processing` e reportar se aparecerem): `STATUSSTR 03/07`, `TIPO_M R3`, domínio completo de `STATUSSPB`, `TIPO_E 'N'`.

## 8. Travas, gates e riscos

1. Unidade monetária (crítico, money-safe). Legado guarda VALOR em reais (numeric). Alvos divergem: `payments.amount` é `numeric(18,5)` (subcentavo); `transactions.amount`/`med_claims.amount_cents` são bigint em centavos; `credit_notifications.amount`/`statement_entries.amount` são `numeric(18,2)`. Fixar e testar a conversão por tabela antes de qualquer carga (lembrar do bug histórico 100x). Nenhuma carga em produção sem prova de reconciliação ao centavo por tabela.
2. Partições de `messages`. Criar 2025_11..2026_02 antes da Fase 2 do PIX.
3. Colisão de chave natural. Prefixar tudo com `LEGACY-` para não bater nos índices únicos vivos (message_id, control_number_clearing, end_to_end, return_id, notification_id).
4. Proveniência em KPIs/saldos. Dashboards, saldos, conciliação diária e APIX001 devem filtrar `source/created_by/resource_id` legado, para o histórico não contaminar posição viva e métricas correntes.
5. Saldos. `balances`/`SALDO_CONTA_PI`/`BALANCO_SALDO_SPI` só via gate explícito com snapshot de rollback. Nunca sobrescrever saldo vivo por upsert.
6. Contabilidade. `journal_entries`/movimentos contábeis bloqueados até a COA da cabine estar semeada.
7. Segredos. NÃO importar `CERTIFICADOS` com chave, `PARAMETROS*`, `THUMBPRINT_*`, `TESTE_CONECTIVIDADE`, `DOWNLOAD_CERTIFICADOS_SITE`, `RESULTADO_GRAFICO*`, `*_METRICAS`. Segredos vivem em Secrets Manager/HSM.
8. Core. NÃO carregar nada disto no Core (é histórico de cabine PIX/SPB, não do Core).
9. Idempotência e reversão. `final_links` + `ON CONFLICT DO NOTHING`; toda carga precisa provar delta-zero na segunda execução.
10. Backup pré-carga. Snapshot do Aurora de produção antes de qualquer projeção (padrão já usado: `monetarie-core-homolog-45-pre-*`).

## 9. Reuso do loader e o que precisa mudar para produção

Reaproveitar `etl/legacy_pix_spb/load_legacy_pix_spb.py` (de→para e mapas de status já provados). Mudanças necessárias:

1. Retarget de schema: `cecresa_*` (laboratório) → schemas reais de produção (`monetarie_spi`, `monetarie_dict`, `monetarie_settlement`, `monetarie_spi_msg`, `monetarie_audit`; SPB `public`). O loader hoje só alcança o Postgres local via `docker exec` (trava proposital). Precisa de um caminho de conexão ao Aurora de produção, revisado.
2. Alvo PIX: trocar `transactions` por `messages`+`payments` (+ `message_history`), com a lógica de partição.
3. Honrar o gate de saldo (`--allow-balance-overwrite` off por padrão) e exigir snapshot.
4. Prefixos `LEGACY-` e colunas de proveniência conforme seção 4.
5. Descompactar gzip das mensagens antes de gravar `xml_content`.

## 10. Ordem sequencial de importação

Fase 0 (preparação): snapshot Aurora prod; criar partições `messages_2025_11..2026_02`; validar/semear COA se for importar contábil; confirmar unidades monetárias por tabela.

Fase 1 (arquivo, por sistema): PIX `bacen_outbound`/`bacen_inbound`/`xml_messages`/`xml_audit_logs`; SPB `bacen_messages`. Reconciliar contagem vs origem.

Fase 2 (entidades, respeitando dependências):
1. Referências/diretórios (participantes, chaves) — se necessário.
2. PIX `messages`+`payments` (ordem de saída + crédito de entrada) → `message_history` → `balance_blocks`.
3. PIX devoluções (`returns`/`refund_requests`) → infrações/MED (`infractions`/`med_requests`/`funds_recoveries`).
4. PIX extratos (`statements`/`statement_entries`).
5. PIX contábil (gated pela COA).
6. SPB `spb_operations` → `operation_events` → ligar `bacen_messages.operation_id`.
7. SPB certificados (opcional).

Após cada fase: `verify` (contagem + reconciliação financeira) e prova de idempotência (segunda execução = delta zero).

## 11. Itens em aberto para a revisão do dono

1. Confirmar alvo primário do crédito de entrada: `messages`+`payments` (inbound) versus `credit_notifications`. Recomendação: `messages`+`payments`.
2. Confirmar se o extrato legado entra como `statements`/`statement_entries` (consultável) ou apenas como arquivo bruto.
3. Definir se `legacy_erro` (826 linhas de extrato só-auditoria) e status legados aparecem nas telas ou ficam só em auditoria.
4. Autorizar (ou não) a importação contábil, o que exige semear a COA da cabine PIX.
5. Confirmar o caminho de conexão ao Aurora de produção para o loader (com trava de escrita revisada) e a janela de carga.
