# Mapa de integração do ecossistema Monetarie

Data: 2026-07-10. Escopo: monorepo `/Users/luizpenha/monetarie` inteiro (Core, cabine PIX, cabine SPB, satélites NPC/STA/CLST, UIs, mobile, Partner API). Método: varredura estática read-only com evidência `arquivo:linha` para cada afirmação. Caminhos relativos à raiz do monorepo. Este documento é o insumo para o desacoplamento do monorepo (seção 9).

Resumo executivo:

- O barramento é NATS JetStream (3 nós). Foram mapeados cerca de 190 subjects (famílias expandidas) em 16 streams: 11 criados pelo Core, 4 internos do SPB (`BACEN_*`) e 1 referenciado sem dono (`MONETARIE_PIX_TBFIRST`). Três sistemas criam o MESMO stream `MONETARIE_CORE` com configs próprias (risco de drift, ver seção 9.3).
- Todo money-path publica via outbox (Oban `nats_publish` no Core/PIX/NPC/STA/CLST; tabela `pending_publish_events` no SPB) e consome via consumer durável com dedup e DLQ.
- Só o Core conecta ao TigerBeetle. Cabines PIX e SPB nunca escrevem no ledger: roteiam eventos ao Core, que credita/debita em subcentavos (1 unidade = R$ 0,0001).
- Externos: BACEN DICT/SPI-ICOM por mTLS direto ou pelo sidecar Go `bacen_ln` (cabine PIX); BACEN STR por IBM MQ via sidecar Java (SPB); HSM RTM para assinatura nas duas cabines e KMS no Core; STA BACEN (satélite STA); Nuclea PCR (NPC); Nextcode KYC (Core); webhooks HTTP assinados para parceiros (Partner API).

---

## 1. Visão geral do ecossistema

```mermaid
flowchart LR
  subgraph CANAIS["Canais e parceiros"]
    IB["IB Banking<br/>core/apps/banking"]
    ADM["Core Admin<br/>core/apps/admin"]
    MER["Merchant<br/>core/apps/merchant"]
    MOB["Mobile Flutter<br/>mobile/"]
    PARC["Parceiros (Vulci)<br/>Partner API"]
    UIPIX["PIX Admin<br/>pix/frontend/admin"]
    UISPB["SPB Admin<br/>spb/frontend-vue"]
    BOF["Backoffice<br/>backoffice/"]
  end

  subgraph CORE["Core Banking (core/backend)"]
    COREAPI["core-api Phoenix<br/>+ Partner API + webhooks"]
  end

  subgraph PIXC["Cabine PIX (pix/backend, umbrella)"]
    SPISVC["spi_service"]
    DICTSVC["dict_service"]
    SETTSVC["settlement_service<br/>(gateway :4003)"]
    LN["sidecar mTLS bacen_ln (Go)<br/>pix/services/bacen_mtls_sidecar"]
  end

  subgraph SPBC["Cabine SPB (spb/services)"]
    BG["bacen_gateway (spb-api)"]
    MQJ["sidecar IBM MQ (Java :9080)<br/>bacen_gateway_mq_sidecar"]
  end

  subgraph SATS["Satélites"]
    NPC["NPC boletos Nuclea<br/>npc/backend"]
    STA["STA connector<br/>sta/backend"]
    CLST["CLST clearing/liquidez<br/>clst/"]
  end

  NATS[("NATS JetStream x3<br/>16 streams")]
  TB[("TigerBeetle 0.17.3 x3<br/>ledger subcentavo")]
  PG[("Aurora PostgreSQL<br/>DBs por sistema")]
  RED[("Redis")]

  subgraph EXT["Externos"]
    DICTB["BACEN DICT<br/>dict.pi.rsfn.net.br"]
    ICOM["BACEN SPI/ICOM<br/>icom(.sec).pi.rsfn.net.br"]
    STR["BACEN STR<br/>IBM MQ RTM 172.31.2.50"]
    STAB["BACEN STA<br/>sta.bcb.gov.br"]
    HSM["HSM RTM<br/>monetarie-hsm-*.rtmcloud"]
    NUC["Nuclea PCR"]
    NXC["Nextcode KYC"]
  end

  IB --> COREAPI
  ADM --> COREAPI
  MER --> COREAPI
  MOB --> COREAPI
  PARC --> COREAPI
  UIPIX --> SETTSVC
  UISPB --> BG
  BOF --> COREAPI

  COREAPI <--> NATS
  SPISVC <--> NATS
  DICTSVC <--> NATS
  SETTSVC <--> NATS
  BG <--> NATS
  NPC <--> NATS
  STA <--> NATS
  CLST <--> NATS

  COREAPI --> TB
  COREAPI --> PG
  SPISVC --> PG
  BG --> PG
  NPC --> PG
  STA --> PG
  CLST --> PG
  COREAPI --> RED
  SPISVC --> RED

  COREAPI -. "HTTP pontual por E2E" .-> SETTSVC
  COREAPI -. "HTTP reconciliação" .-> BG
  COREAPI -. "HTTP arquivos" .-> STA
  COREAPI -- "webhooks HMAC" --> PARC

  SPISVC --> LN
  DICTSVC --> LN
  LN --> DICTB
  LN --> ICOM
  SPISVC -. "mTLS Finch direto (default)" .-> ICOM
  DICTSVC -. "mTLS Finch direto (default)" .-> DICTB
  BG --> MQJ
  MQJ <--> STR
  MQJ -- "webhook HMAC inbound" --> BG
  SPISVC --> HSM
  BG --> HSM
  COREAPI -. "KMS" .-> HSM
  STA --> STAB
  NPC --> NUC
  COREAPI --> NXC
```

Bancos de dados: cluster Aurora único por ambiente, com bancos/schemas separados por sistema. Core exige `DATABASE_URL` (`core/backend/config/runtime.exs:321`); cabine PIX usa `DB_NAME` default `monetarie` com schemas `monetarie_auth/dict/spi/spi_ref/spi_msg/audit/settlement` (`pix/backend/config/runtime.exs:194`, `pix/CLAUDE.md`); SPB (`spb/services/bacen_gateway/config/runtime.exs:24`), NPC (`npc/backend/config/runtime.exs:75`), STA (`sta/backend/config/runtime.exs:43`) e CLST (`clst/config/runtime.exs:5`) têm `DATABASE_URL` próprios. O `api_gateway` do SPB trata o banco como opcional (`spb/services/api_gateway/config/runtime.exs:4`).

---

## 2. Streams JetStream: quem cria o quê

| Stream | Subjects | Retenção | Criado por | Evidência |
|---|---|---|---|---|
| `MONETARIE_SPI` | `monetarie.spi.>` | 7d | Core e PIX | `core/backend/lib/monetarie/infra/nats/stream_setup.ex:25`; `pix/backend/apps/shared/lib/shared/nats/jetstream.ex:26` |
| `MONETARIE_SETTLEMENT` | `monetarie.settlement.>` | 7d | Core e PIX | `stream_setup.ex:37`; `jetstream.ex:50` |
| `MONETARIE_DICT` | `monetarie.dict.>` | 7d | Core e PIX | `stream_setup.ex:47`; `jetstream.ex:38` |
| `MONETARIE_SPB` | `monetarie.spb.>` | 7d | Core (somente) | `stream_setup.ex:58`; o SPB apenas publica (comentário em `spb/services/bacen_gateway/lib/bacen_gateway/lifecycle_engine.ex:1624`) |
| `MONETARIE_NPC` | `monetarie.npc.>` | 7d | Core (somente; satélite não cria streams) | `stream_setup.ex:69` |
| `MONETARIE_STA` | `monetarie.sta.>` | 7d | Core | `stream_setup.ex:80` |
| `MONETARIE_CLST` | `monetarie.clst.>` | 7d | Core | `stream_setup.ex:90` |
| `MONETARIE_CORE` | `monetarie.core.>` | 7d | Core, PIX e SPB (3 donos, configs próprias) | `stream_setup.ex:102`; `jetstream.ex:86`; `spb/services/bacen_gateway/lib/bacen_gateway/nats/stream_manager.ex:77` |
| `MONETARIE_AUDIT` | `monetarie.audit.>` | 90d | Core e PIX | `stream_setup.ex:113`; `jetstream.ex:62` |
| `MONETARIE_DLQ` | `monetarie.dlq.>` | 30d (Core) / 90d (PIX) | Core e PIX (retenções divergentes) | `stream_setup.ex:124`; `jetstream.ex:74` |
| `MONETARIE_SCR` | `monetarie.scr.>` | 7d | Core | `stream_setup.ex:136` |
| `BACEN_OUTBOUND` | `bacen.outbound.>` | 7d/5GB | SPB | `stream_manager.ex:20` |
| `BACEN_INBOUND` | `bacen.inbound.>` | 7d/5GB | SPB | `stream_manager.ex:36` |
| `BACEN_DLQ` | `bacen.dlq.>` | 30d | SPB | `stream_manager.ex:49` |
| `BACEN_EVENTS` | `bacen.events.>` | 3d | SPB | `stream_manager.ex:63` |
| `MONETARIE_PIX_TBFIRST` | `monetarie.pix.tbfirst.settled` | não criado por ninguém | referenciado pelo publisher (`core/backend/lib/monetarie/use_cases/pix/tb_first/settled_publisher.ex:24`) e pelo consumer `pg-writer` (`.../tb_first/pg_writer_worker.ex:30`) | pendência registrada no próprio código |

O Core deleta streams deprecados no boot, hoje restrito a `MONETARIE_PIX` (`stream_setup.ex:21`, `stream_setup.ex:236`). Réplicas via `NATS_STREAM_REPLICAS` (default 3) nos dois lados.

Subjects SEM stream (core NATS puro, sem persistência): todos os request/reply da seção 4, os subjects `messages.new`/`transactions.new` do api_gateway SPB (`spb/services/api_gateway/lib/api_gateway/nats/publisher.ex:55`, `:70`, publicados em `spb/services/api_gateway/lib/api_gateway_web/controllers/messages_controller.ex:121`, sem consumidor conhecido) e o DLQ do CLST `planner.dlq.clst.failed` (`clst/lib/monetarie_clst/nats/dead_letter_queue.ex:24`, `:60`, fora do namespace `monetarie.*`).

---

## 3. Matriz NATS completa: produtor, subject, consumidor

Convenções de payload: eventos enriquecidos com `published_at` (ISO 8601) e `source` (`"core"`, `"pix-umbrella"`/`"pix"`, `"spb"`, `"npc"`, `"sta"`, `"clst"`). Publicações money-path via outbox; JS = JetStream durável (nome do durable indicado); RR = request/reply (core NATS, sem stream).

### 3.1 Core -> cabine PIX (comandos, stream `MONETARIE_CORE`)

| Subject | Produtor (arquivo:linha) | Consumidor (durable) | Payload resumido |
|---|---|---|---|
| `monetarie.core.pix.payment_request` | `core/backend/lib/monetarie_web/controllers/pix_controller.ex:103` (pix_in), `:184` e `:189` (pix_out), `core/backend/lib/monetarie_web/controllers/v2/transfer_controller.ex:358`, `core/backend/lib/monetarie_web/controllers/partner_v1/transfers_controller.ex:559` | PIX `CoreEventProcessor`, durable `core-event-processor`, filtro `monetarie.core.pix.>` (`pix/backend/apps/settlement_service/lib/settlement_service/workers/core_event_processor.ex:41`) | `event` (routing key), `transaction_id`, `end_to_end_id`, `amount`, `account_id`, `recipient_key/_type/_name/_document/_ispb`, `hold_id` |
| `monetarie.core.pix.return_request`, `key_create`, `key_delete`, `dict_lookup`, `balance_inquiry`, `claim_*`, `recovery_*`, `infraction_*` | Core (adapter in-house e controllers; catálogo em `core_event_processor.ex:13-37`) | idem (`core-event-processor`) | comandos DICT/MED/devolução; campo `event` decide a rota (`core_event_processor.ex:68`) |
| `monetarie.spi.recurrence.execute` | `core/backend/lib/monetarie/use_cases/pix_automatico.ex:298` | PIX `recurrence-executor` (JS, `MONETARIE_SPI`; `pix/backend/apps/spi_service/lib/spi_service/recurrences/execution_worker.ex:27`) | execução de Pix Automático |

### 3.2 Cabine PIX -> Core (eventos, streams `MONETARIE_SPI`/`MONETARIE_SETTLEMENT`/`MONETARIE_DICT`)

| Subject | Produtor (arquivo:linha) | Consumidor (durable) | Payload resumido |
|---|---|---|---|
| `monetarie.spi.transaction.created` (direction `INBOUND`, evento que credita o PIX-in) | `pix/backend/apps/spi_service/lib/spi_service/workers/inbound_processor.ex:2874` (helper; chamado em `:931`), reconciliação de órfãs em `pix/backend/apps/spi_service/lib/spi_service/workers/pix_in_orphan_reconciliation.ex:381` | Core `PixConsumer`, durable `core-pix-consumer`, stream `MONETARIE_SPI` (`core/backend/lib/monetarie/infra/nats/consumers/pix_consumer.ex:30-39`) | `transaction_id`, `message_id`, `end_to_end_id`, `direction:"INBOUND"`, `amount`, `account_id`, `debtor_ispb`, `creditor_ispb`, `type:"pix_transaction"` |
| `monetarie.spi.transaction.created` (direction `OUTBOUND`) | `pix/backend/apps/settlement_service/lib/settlement_service/workers/core_event_processor.ex:425` | Core `core-pix-consumer` (audit/tracking) e PIX `status-updater` | idem + `hold_id`, `block_id`, `event_type:"TRANSACTION_CREATED"` |
| `monetarie.spi.transaction.settled` | `pix/backend/apps/spi_service/lib/spi_service/workers/status_updater.ex:224` (payload em `:257`) | Core `core-pix-consumer` (liquida a saída, post do pending); PIX `settlement-obligation-worker` (`.../settlement_obligation_worker.ex:45`); CLST (`clst/lib/monetarie_clst/nats/consumer.ex:67`) | `message_id`, `end_to_end_id`, `amount` (centavos), `direction`, `status:"settled"`, `settled_at`, `transaction_id` |
| `monetarie.spi.transaction.rejected` | `status_updater.ex:406`; inbound inválida em `inbound_processor.ex:1078` | Core `core-pix-consumer` (release de fundos, NUNCA credita) | `transaction_id`, `end_to_end_id`, `reason_code`, `reason_description`, `block_id` |
| `monetarie.spi.transaction.status_update` | `inbound_processor.ex:3042` | PIX `status-updater`, durable `status-updater`, filtro `monetarie.spi.transaction.>` (`status_updater.ex:14`) | `old_status`, `new_status`, `reason_code`, `response_message_type` (pacs.002/admi.002) |
| `monetarie.spi.transaction.returned` | `core_event_processor.ex:693` (pacs.004 out), `inbound_processor.ex:1203` (pacs.004 in) | Core `core-pix-consumer` (`handle_return`) | `original_transaction_id`, `amount`, `reason_code`, `direction` |
| `monetarie.spi.transaction.ab03_rejection` | `status_updater.ex:1057` | PIX `outbound-sender` | `xml_content` pacs.002 AB03 |
| `monetarie.spi.return.created` | MED: `pix/backend/apps/dict_service/lib/dict_service/nats/infraction_response_consumer.ex:162`; legado `.../spi_service/nats/event_publisher.ex:183` | PIX `return-processor`, durable `return-processor`, filtro `monetarie.spi.return.>` (`return_processor.ex:14`); Core `core-pix-consumer` | devolução (pacs.004) a criar |
| `monetarie.spi.return.rejected` | `status_updater.ex:398` | Core `core-pix-consumer` clause dedicada (estorno, `pix_consumer.ex:88`) | `RtrId`, motivo da rejeição da nossa pacs.004 |
| `monetarie.spi.outbound.send` / `.pacs002` / `.return` / `.med` | `core_event_processor.ex:544`; `inbound_processor.ex:2617`; `return_processor.ex:208`; `pix/backend/apps/spi_service/lib/spi_service/med.ex:531` | PIX `outbound-sender`, durable `outbound-sender`, filtro `monetarie.spi.outbound.>` (`outbound_sender.ex:32`) | `message_type`, `message_id`, `xml_content` assinável, `end_to_end_id` |
| `monetarie.spi.inbound.<msg_type>` | `pix/backend/apps/spi_service/lib/spi_service/icom/nats_bridge.ex:61` (long-poll ICOM, `Gnat.pub` fire-and-forget com `republish_pending`) | PIX `inbound-processor`, durable `inbound-processor`, filtro `monetarie.spi.inbound.>` (`inbound_processor.ex:79`) | `message_type`, `message_id`, `xml_content` cru do BACEN |
| `monetarie.spi.med.resolution_received` / `.cancellation_requested` | `inbound_processor.ex:1919` / `:2272` | PIX `med-resolution-consumer` (`.../med/resolution_consumer.ex:19`) | camt.029/camt.055 |
| `monetarie.spi.recurrence.{created,updated,paused,resumed,cancelled,execute}` | `pix/backend/apps/spi_service/lib/spi_service/recurrences.ex:76,200,267,309,363,654` | PIX `recurrence-executor` (só `.execute`); demais audit | dados da recorrência |
| `monetarie.spi.balance.updated.<ispb>`, `.block.created/.released.<ispb>`, `.participant.*` | `pix/backend/apps/spi_service/lib/spi_service/nats/event_publisher.ex:217,234,250,268,283` (legado, `Gnat.pub` direto) | CLST (`clst/lib/monetarie_clst/nats/consumer.ex:69`, monitor de liquidez) | saldo/bloqueio da Conta PI |
| `monetarie.settlement.transaction.credited` | `pix/backend/apps/settlement_service/lib/settlement_service/workers/settlement_obligation_worker.ex:374` | Core `core-pix-settlement-consumer` (stream `MONETARIE_SETTLEMENT`, `pix_consumer.ex:40-44`) | `end_to_end_id`, `amount`, `obligation_id`, `cycle_id`, `money_path: true` |
| `monetarie.settlement.session.{created,opened,closed,finalized}` | `pix/backend/apps/settlement_service/lib/settlement_service/sessions.ex:52,95,147,269` | Core `core-pix-settlement-consumer` (`session.credit` deposita via `SettlementHandler`, `pix_consumer.ex:98`); CLST `monetarie.settlement.*` (`clst/.../consumer.ex:71`) | `session_id`, tipo, janela |
| `monetarie.settlement.schedule.<ação>` / `.file.>` / `fees.calculated` / `reconciliation.completed` etc. | `.../workers/cycle_scheduler.ex:157`; `.../fees.ex:64,195`; `.../reconciliation.ex:105,260`; `.../qr_codes.ex:81,438` | PIX `settlement-scheduler` e `file-importer` (`scheduler.ex:15`, `file_importer.ex:15`) | agenda de janelas de netting |
| `monetarie.dict.keys.{created,deleted,blocked,unblocked}` | `pix/backend/apps/dict_service/lib/dict_service/keys.ex:781,865,384,453` (+ reconciliador `dict_external_reconciler.ex:1009,1021`) | Core (auditoria; consumer `core-dict-consumer` filtra só infrações/recovery) | chave, dono, motivo |
| `monetarie.dict.claims.*` (initiated, acknowledged, confirmed, completed, cancelled, auto_*) | `pix/backend/apps/dict_service/lib/dict_service/claims.ex:646,811,911,955,1052,1123,1185,1249,1342` | Core (auditoria/telas MED) | claim de portabilidade/posse |
| `monetarie.dict.infractions.*` e `monetarie.dict.recovery.*` | `pix/backend/apps/dict_service/lib/dict_service/infractions.ex:148,312,998,1010,1022`; `.../funds_recovery.ex:133,288,364,493,1089,1362,1459` | Core `DictConsumer`, durable `core-dict-consumer`, stream `MONETARIE_DICT`, filtros `monetarie.dict.infractions.*`/`monetarie.dict.recovery.*` (`core/backend/lib/monetarie/infra/nats/consumers/dict_consumer.ex:19-23`); MED com dinheiro via `Med.Processor` (`dict_consumer.ex:143`) | infração/MED 2.0, ids e status |
| `monetarie.dict.infractions.response` | Core (resposta do operador) | PIX `med-infraction-response` (`infraction_response_consumer.ex:28`), AGREED gera `spi.return.created` | decisão da infração |
| `monetarie.dict.med.infraction_received` | cabine (fluxo MED inbound) | PIX `med-infraction-responder` (`.../med/infraction_responder.ex:16`) | abre claim de fraude |
| `monetarie.dict.deadlines.<tipo>` | `pix/backend/apps/dict_service/lib/dict_service/events/nats_publisher.ex:246` (timer durável via header `Nats-Msg-Deliver-After`, `:264`) | PIX `claim-deadline-consumer` (`.../nats/claim_deadline_consumer.ex:24`) | auto-resolução de claim D+14 |

### 3.3 Core -> cabine SPB e SPB -> Core

| Subject | Produtor (arquivo:linha) | Consumidor | Payload resumido |
|---|---|---|---|
| `monetarie.core.spb.transfer_request` | `core/backend/lib/monetarie/use_cases/payments/outbound/ted.ex:100` (payload flat em `:194`), `core/backend/lib/monetarie_web/controllers/ted_controller.ex:78`, `.../v2/transfer_controller.ex:85,479`, Partner API `.../partner_v1/transfers_controller.ex:559` | SPB `CoreEventConsumer`, `Gnat.sub` plano em `monetarie.core.spb.>` (`spb/services/bacen_gateway/lib/bacen_gateway/consumers/core_event_consumer.ex:23,41`); há durable `bacen-core-event-processor` declarado mas NÃO usado em runtime (`stream_manager.ex:127`) | FLAT com `event:"transfer_request"` no topo (a cabine descarta envelope aninhado, contrato em `core/backend/lib/monetarie/infra/nats/publisher.ex:216-238`): `transaction_id`, `message_type:"STR0008"`, `amount`, `account_id`, `hold_id`, `recipient_name/_document/_ispb/_agency/_account` |
| `monetarie.core.spb.devolution_request` | Core (devolução W2) | SPB `CoreEventConsumer.handle_event("devolution_request")` (`core_event_consumer.ex:116`), monta STR0010 (`spb/services/bacen_gateway/lib/bacen_gateway/devolution/devolution_engine.ex:386`) | `num_ctrl_str` da STR original |
| `monetarie.core.spb.inter_entity_credit` | SPB Liquidante (flag OFF) `spb/services/bacen_gateway/lib/bacen_gateway/liquidante/processor.ex:541` | Core | crédito interentidade |
| `monetarie.spb.transactions.{accepted,confirmed,rejected,settled}` | SPB: aceite do TED-out em `core_event_consumer.ex:336-359`; transições de ciclo (R1/R2/R3) em `spb/services/bacen_gateway/lib/bacen_gateway/nats/core_notifier.ex:22-57`; crédito inbound legado em `core_notifier.ex:69-107` | Core `SpbConsumer`, durable `core-spb-consumer`, stream `MONETARIE_SPB` (`core/backend/lib/monetarie/infra/nats/consumers/spb_consumer.ex:34`); settled inbound vai a TB (`spb_consumer.ex:93` -> `SpbHandler`) | `type:"spb_transaction"`, `transaction_id`, `status`, `message_type` (STR0008/PAG0108), `account_id`, `hold_id`, `amount`, `direction`, `error_reason` |
| `monetarie.spb.credits.inbound` (canônico Fase 4 do crédito TED-in) | `spb/services/bacen_gateway/lib/bacen_gateway/lifecycle_engine.ex:1664-1743` (outbox na mesma transação do INSERT da operação) | Core `SpbInboundCreditHandler` (`spb_consumer.ex:66` -> `core/backend/lib/monetarie/infra/nats/handlers/spb_inbound_credit_handler.ex:60`) | `event:"credit_received"`, `num_ctrl_str` (idempotência), `amount_brl` (STRING em reais, crua), `credit_kind` (client/institutional), `creditor_account/agency/cpf_cnpj/name`, `debtor_ispb`, `dt_movto` |
| `monetarie.spb.credits.return_status` | `spb/services/bacen_gateway/lib/bacen_gateway/devolution/devolution_engine.ex:368` | Core (`spb_consumer.ex:74`) | desfecho de devolução STR0010 |
| `monetarie.spb.cosif.entry` | `core_notifier.ex:126-158` | Core `SpbCosifMirrorHandler` (`spb_consumer.ex:83`), espelho em PG, NÃO vai a TB (`core/backend/lib/monetarie/infra/nats/handlers/spb_cosif_mirror_handler.ex:8`) | `operation_id`, `cd_evento`, `debito_conta`, `credito_conta`, `valor` (reais) |
| `bacen.outbound.<dominio>.<cod>` / `bacen.inbound.<dominio>.<cod>` / `bacen.events.*` / `bacen.dlq.*` (INTERNOS do SPB) | `spb/services/bacen_gateway/lib/bacen_gateway/nats/publisher.ex:92-126`; inbound publicado por `message_processor.ex:722` | SPB pull consumers: `bacen-gateway-sender` (`message_consumer.ex:24-28`), `bacen-gateway-receiver` (`inbound_consumer.ex:35-39`), `bacen-events-processor` audit-only (`events_consumer.ex:30-34`), `bacen-dlq-processor` (`stream_manager.ex:116`) | XML BACEN parseado, `nuop`, `correlation_id` |

### 3.4 Satélites (NPC, STA, CLST) e SCR

| Subject | Produtor (arquivo:linha) | Consumidor (durable) | Payload |
|---|---|---|---|
| `monetarie.npc.boleto.{created,registered,paid,cancelled,modified,expired}` | `npc/backend/lib/monetarie_npc/nats/publisher.ex:98-118` (outbox Oban `publish_job.ex:24`) | Core `core-npc-consumer` (`core/backend/lib/monetarie/infra/nats/consumers/npc_consumer.ex:33,35`); CLST (`clst/lib/monetarie_clst/nats/consumer.ex:60`) | `%{type, data: boleto}` |
| `monetarie.npc.cycle.{started,completed}` / `protocol.processed` / `settlement.*` | `publisher.ex:123-132`; MQ Nuclea em `npc/backend/lib/monetarie_npc/mq/ldl_handler.ex:53,122,182,238` e `gen_handler.ex:39` | Core `core-npc-consumer` (`npc_consumer.ex:174-189`); CLST (`consumer.ex:61-62`) | ciclos LDL/GEN da Nuclea |
| `monetarie.npc.titulo.{liquidado,rejeitado,protestado,baixado,movimento}` (produzidos pelo CORE, retorno CNAB) | `core/backend/lib/monetarie/use_cases/receivables/cnab/retorno_processor.ex:310-447` | Core `core-npc-consumer` (`npc_consumer.ex:197`, `.liquidado` credita via COSIF journaling) | título CNAB |
| `monetarie.core.npc.boleto_request` / `settlement_request` | Core `core/backend/lib/monetarie/infra/nats/publisher.ex:242`, controllers `boleto_controller.ex:81,145` | NPC consumer (`npc/backend/lib/monetarie_npc/nats/consumer.ex:8,107,113`) | pedido de registro/settlement |
| `monetarie.sta.file.{received,processed,sent,error,uploaded,failed}` / `protocol.processed` | `sta/backend/lib/sta_connector/nats/publisher.ex:92-120` (helpers síncronos, sem outbox) | Core `core-sta-consumer` (`core/backend/lib/monetarie/infra/nats/consumers/sta_consumer.ex:24-27`); CLST (`consumer.ex:64-65`) | `%{type, data: file_info}` |
| `monetarie.sta.regulatory.upload` / `sisbajud.{order,response}` / `file.upload` (produzidos pelo CORE) | `core/backend/lib/monetarie/use_cases/cadoc/sta_dispatcher.ex:15,43`, `.../regulatory/sta_delivery.ex:19,86`, `.../judicial/nats_handler.ex:43` | STA consumer (`sta/backend/lib/sta_connector/nats/consumer.ex:20-25,132,152,172`) | `system_id`, `file_name`, `content_base64`, `metadata` |
| `monetarie.sta.accs.generated` | `core/backend/lib/monetarie/infra/nats/publisher.ex:271` | STA/auditoria | arquivo ACCS |
| `monetarie.clst.settlement.*` / `clearing.{batch_created,batch_completed,netting_result}` / `reconciliation.*` / `liquidity.{warning,critical,snapshot}` | `clst/lib/monetarie_clst/nats/publisher.ex:160-325` (outbox Oban) | Core `core-clst-consumer` (`core/backend/lib/monetarie/infra/nats/consumers/clst_consumer.ex:26-38`) | janela de settlement, posições líquidas por participante, alertas de liquidez |
| CLST consome de todos | | `clst/lib/monetarie_clst/nats/consumer.ex:58-72` assina `monetarie.npc.*`, `monetarie.sta.*`, `monetarie.spi.transaction/return/balance.*`, `monetarie.settlement.*` | agregador de clearing |
| `monetarie.scr.event.*` | `core/backend/lib/monetarie/use_cases/scr_engine/nats/publisher.ex:93` (callers em `credit/loans.ex:815,1667`) | Core `core-scr-consumer`, stream `MONETARIE_SCR` (`core/backend/lib/monetarie/use_cases/scr_engine/nats/consumer.ex:20-24`) | eventos de crédito SCR (loan_created etc.) |
| `monetarie.core.fees.{charged,reversed,batch_completed}` | `core/backend/lib/monetarie/use_cases/fees/fee_events.ex:25,49,66` | auditoria | tarifas |
| `ledger.account.<tipo>` / `ledger.balance.updated` | `core/backend/lib/monetarie/infra/nats/publisher.ex:250,262` | fire-and-forget (UIs/monitoração) | saldo atualizado |
| `monetarie.pix.tbfirst.settled` | `core/backend/lib/monetarie/use_cases/pix/tb_first/settled_publisher.ex:57` (usa `Publisher.request` para puback at-least-once) | Core `pg-writer` (`.../tb_first/pg_writer_worker.ex:30-33`) | espelho PG do crédito TB-first |
| DLQs | Core `monetarie.dlq.<origem>.failed`; PIX `monetarie.dlq.<subject>` (`base_worker.ex:635`) e `monetarie.dlq.poison.<consumer>` (`pix/backend/apps/shared/lib/shared/workers/poison_policy.ex:129`); NPC `monetarie.npc.dlq.*` (`npc/backend/lib/monetarie_npc/nats/dead_letter_queue.ex:14`); STA `monetarie.sta.dlq.*`; CLST `planner.dlq.clst.failed` (fora de stream) | operação/replay manual | mensagem original + erro + retry_count |

### 3.5 Request/reply (core NATS, sem stream, sem outbox)

| Subject | Solicitante (arquivo:linha) | Respondedor (arquivo:linha) | Uso |
|---|---|---|---|
| `dict.lookup.request` | Core `core/backend/lib/monetarie/services/pix_providers/in_house/adapter.ex:151` e `core/backend/lib/monetarie/use_cases/pix/gateway.ex:258` | PIX `DictLookupResponder` (`pix/backend/apps/dict_service/lib/dict_service/nats/dict_lookup_responder.ex:15,33,82`) | lookup de chave PIX (caminho quente do PIX-out) |
| `dict.list_keys.request` | `adapter.ex:184` | idem (`dict_lookup_responder.ex:16,34`) | listar chaves da conta |
| `dict.api.request` | `adapter.ex:146-451` (dezenas de ações: claims, MED, políticas, fraude, estatísticas) | PIX `DictApiResponder` (`.../dict_api_responder.ex:16,33,75`) | proxy genérico da DICT API |
| `monetarie.core.pix.validate_account` | PIX `inbound_processor.ex:988` (`Gnat.request`, valida conta do recebedor ANTES de aceitar pacs.008) | Core `PixAccountValidator` (`core/backend/lib/monetarie/infra/nats/responders/pix_account_validator.ex:33,86`) | fail-closed: sem resposta = RJCT |
| `monetarie.pix.{limits.check,limits.get,idempotency.check,e2e.generate,e2e.parse,med.check,qrcode.image,qrcode.cobv}` | Core (gateway PIX) | PIX `CoreGatewayHandler` (`pix/backend/apps/spi_service/lib/spi_service/nats/core_gateway_handler.ex:39,74,392`) | utilidades síncronas (limites, E2E, QR) |
| `pix.health.check` / `spb.health.check` / `npc.health.check` / `sta.health.check` | monitoração | PIX `health_responder.ex:31,47`; SPB `core_event_consumer.ex:24`; NPC `consumer.ex:9,60`; STA `consumer.ex:24,85` | health via barramento |

### 3.6 Mecanismos transversais

- Outbox: Core `Publisher.publish_async` -> Oban `nats_publish` (`core/backend/lib/monetarie/infra/nats/publisher.ex:172`, `core/backend/lib/monetarie/workers/nats/publish_job.ex:1`); PIX idem (`pix/backend/apps/shared/lib/shared/nats/publisher.ex:70`, `.../workers/nats/publish_job.ex:35`); SPB via tabela `pending_publish_events` + `Outbox.Worker` (`spb/services/bacen_gateway/lib/bacen_gateway/outbox/repository.ex:30`, `.../outbox/worker.ex:55,138-185`); NPC/STA/CLST via Oban próprios. Guardas de atomicidade I-1 em runtime e Credo check `OutboxAtomicity` em cada sistema.
- Consumo durável do Core: macro `Monetarie.Infra.Nats.DurableConsumer` (push com `deliver_subject` + `deliver_group`, NAK com backoff, dedup por `MsgIdentity`/`MessageDedup`, DLQ NATS + PG `nats_dead_letters`; `core/backend/lib/monetarie/infra/nats/durable_consumer.ex:1`, `jet_stream_flow.ex:129-151`). Consumo durável do PIX: macro `Shared.Workers.BaseWorker` (push durável, `deliver_group`, poison policy; `pix/backend/apps/shared/lib/shared/workers/base_worker.ex:43,298,120`). SPB usa pull (`$JS.API.CONSUMER.MSG.NEXT`).
- Fronteira monetária: `MoneyBoundary.convert_inbound/outbound` traduz centavos da cabine para subcentavos do Core e vice-versa em TODOS os consumers/publishers do Core (`core/backend/lib/monetarie/infra/nats/money_boundary.ex:111,124`; lista de campos monetários em `:70`). Exceções deliberadas: `amount_brl` e `valor` do SPB passam crus (string em reais) e são parseados pelo handler (`spb_inbound_credit_handler.ex:146`).

---

## 4. Integrações HTTP

### 4.1 Internas (sistema a sistema)

| Origem -> destino | Endpoint | Propósito | Evidência |
|---|---|---|---|
| Core -> cabine PIX | `POST /api/v1/auth/login`; `GET /api/v1/transactions?end_to_end_id=<e2e>&per_page=1` | status verdade BACEN por E2E, pontual, fail-closed (sem fallback SQL) | `core/backend/lib/monetarie/services/pix_providers/in_house/cabin_status_lookup.ex:147,176` (envs `PIX_CABIN_API_BASE_URL`, `PIX_CABIN_ADMIN_LOGIN/_PASSWORD`, `:94-117`) |
| Core -> cabine PIX | `POST /api/v1/operations/query` | comprovante/reprocesso (camt.054 + raw_message_id) | `.../in_house/cabin_operation_query.ex:86` |
| Core -> cabine PIX | `GET /api/v1/balance`; `GET /api/v1/transactions` | tesouraria: saldo Conta PI e janela de liquidadas para conciliação | `.../in_house/cabin_treasury.ex:76,169` |
| Core -> cabine SPB | `POST /api/auth/login`; `GET /api/messages?search=<transaction_id>&limit=20` | reconciliação de status de TED (Bearer cacheado 5 min) | `core/backend/lib/monetarie/services/spb_integration/cabin_status_lookup.ex:180,230` (envs `SPB_CABIN_API_BASE_URL`, `SPB_CABIN_ADMIN_LOGIN/_PASSWORD`, `:107-116`) |
| Core -> STA connector | `POST {sta_base_url}/api/v1/files`; `GET /api/v1/files/{id}` | envio de arquivos regulatórios via cabine STA (modo `CCS_STA_MODE=http`) | `core/backend/lib/monetarie/sta/client/http.ex:6-7,74,109`; callback inbound `POST /api/internal/{cadoc,ccs}/sta-callback` (`core/backend/lib/monetarie_web/router.ex:229-234`) |
| SPB -> sidecar MQ (Java) | `POST {sidecar}/ibmmq/rest/v2/messaging/qmgr/{qm}/queue/{fila}/message`; `GET /statusz`; `DELETE .../message` (poll) | enfileirar/desenfileirar mensagens BACEN no IBM MQ | `spb/services/bacen_gateway/lib/bacen_gateway/mq/domain_manager.ex:662,704,762`; `.../mq/mq_response_poller.ex:111`; env `IBM_MQ_SIDECAR_URL` default `http://localhost:9080` (`spb/services/bacen_gateway/config/runtime.exs:127`) |
| sidecar MQ -> SPB | `POST {WEBHOOK_BASE_URL}/api/mq/webhook/{domain}` (+ `/report`, `/quarantine`), HMAC `X-Webhook-Signature` | entrega de mensagem recebida do MQ | `spb/services/bacen_gateway_mq_sidecar/src/main/java/com/monetarie/bacen/Sidecar.java:84-89,536,571`; rotas `spb/services/bacen_gateway/lib/bacen_gateway_web/router.ex:52-55` |
| Parceiro -> Core (Partner API) | `POST /api/partner/v1/oauth/token` e catálogo `/api/partner/v1/*` (customers, accounts, pix, transfers, webhooks) | API de parceiros (Vulci), Bearer JWT sobre api_keys, rate limit por chave | `core/backend/lib/monetarie_web/router.ex:120-123,133-207` |
| Core -> parceiro (webhooks) | `POST {webhook.url}` com HMAC-SHA256 (`X-Monetarie-Signature/-Timestamp/-Event-Id/-Event-Type`), anti-SSRF, dedup por `(webhook_id, event_id)`, retry Oban | eventos `pix.payout.confirmed` (`core/backend/lib/monetarie/infra/nats/handlers/pix_handler.ex:264`), `pix.payout.failed` (`:283`), `pix.received` (`:296`), `pix.charge.paid`, `pix.return.received` | dispatcher `core/backend/lib/monetarie/use_cases/webhooks.ex:157,129-163`; POST real `core/backend/lib/monetarie/workers/services/webhooks/delivery_job.ex:86,107-114,176,186` |

### 4.2 Externas (BACEN e provedores)

| Origem -> destino | Endpoint | Propósito | Evidência |
|---|---|---|---|
| Cabine PIX -> BACEN DICT | `GET/POST/PUT /entries/*`, `/claims/*`, CIDs; mTLS ICP-Brasil | diretório de chaves, claims, MED | `pix/backend/apps/shared/lib/shared/bacen/dict_client.ex:91,139,165,205,379-502`; hosts `dict(-h).pi.rsfn.net.br:16422/16522`, DICT-NP `:16432/16532` (`pix/backend/config/runtime.exs:523-541`) |
| Cabine PIX -> BACEN SPI/ICOM | `POST /api/v1/in/{ispb}/msgs` (pacs.008/002/004, camt.060, pibr.001); long-poll `POST /api/v1/out/{ispb}/stream/start` + pull + `DELETE .../stream/{token}` | envio e RECEBIMENTO de mensagens SPI | `pix/backend/apps/shared/lib/shared/bacen/spi_client.ex:108,206`; `.../bacen/client.ex:309,348,356`; workers CPM/CSM `pix/backend/apps/spi_service/lib/spi_service/icom/cpm/worker.ex:8-32` |
| Transporte mTLS PIX | (a) direto: pools Finch com cert em disco (`pix/backend/apps/shared/lib/shared/application.ex:67-107`); (b) produção: sidecar Go `bacen_ln`, mTLS lastreado no HSM, upstreams locais `dict=9101, dict_np=9102, icom=9103, icom_sec=9104, arq=9105` | a escolha é por env: `DICT_BASE_URL`/`ICOM_PRIMARY_URL`/`ICOM_SECONDARY_URL` apontando para `http://localhost:<porta>` roteiam pelo sidecar | sidecar `pix/services/bacen_mtls_sidecar/main.go:540-543` (`SIDECAR_UPSTREAMS`); roteamento `pix/backend/config/runtime.exs:520-523,551-557` |
| SPB -> BACEN STR | IBM MQ RTM `172.31.2.50` (SPB01 `QM.46026562.01:1514`; MES01 `:12522`), filas `QR.REQ.{ispb}.{bacen}.{seq}` | mensageria SPB (STR0008, GEN, LDL) | filas e QMs `spb/services/bacen_gateway/lib/bacen_gateway/mq/domain_manager.ex:1012-1013,1122-1170`; filas de resposta `mq_bridge.ex:26-32` |
| PIX/SPB/Core -> HSM RTM | `POST {base}/v1/kmip/{vhsm}/{op}` (get-session-credential, sign-rsa, decrypt) | assinatura XMLDSig (PIX CPIA), C15/C14 do SPB, KMS do Core | PIX `pix/backend/apps/shared/lib/shared/crypto/rtm_hsm/client.ex`; SPB `spb/services/bacen_gateway/lib/bacen_gateway/crypto/rtm_hsm.ex:49-84` + uso em `message_packer.ex:224-231,401-407`; Core `core/backend/lib/monetarie/infra/rtm_hsm/client.ex:117-131`; env `RTM_HSM_BASE_URL` (`spb/services/bacen_gateway/config/runtime.exs:104-113`) |
| STA -> BACEN STA | `https://sta(-h).bcb.gov.br/staws` (`GET/PUT /staws/arquivos/{protocolo}/conteudo`) | transferência de arquivos BACEN | `sta/backend/lib/sta_connector/sta/client.ex:64-65,546,626,717` |
| NPC -> Nuclea PCR | `PCR_API_URL` (default `https://api-hom.pcr.nuclea.com.br/v1`), Bearer + mTLS | registro/consulta/baixa de boletos | `npc/backend/lib/monetarie_npc/integrations/pcr_client.ex:18-77,182-233` (+ FTP `nuclea_ftp.ex`, MQ `mq_client.ex:20-24`) |
| Core -> Nextcode | `NEXTCODE_API_URL` (default `https://api.nxcd.app`), header `ApiKey` | KYC (bureau, OCR, face match, liveness); webhook inbound `POST /api/webhooks/nextcode/:external_id/finish` | `core/backend/lib/monetarie/services/nextcode/client.ex:74-80`; `router.ex:224-226` |

### 4.3 UIs e mobile -> APIs

| Frontend | Base de API | Evidência |
|---|---|---|
| core/apps/banking (IB) | `VITE_API_URL` default `/api` (core-api) | `core/apps/banking/.env.production:1` |
| core/apps/admin | `VITE_API_URL \|\| '/api'` | `core/apps/admin/src/lib/api.ts:9` |
| core/apps/merchant | `VITE_API_URL \|\| '/api'` | `core/apps/merchant/src/http/api.ts:4` |
| pix/frontend/admin | `VITE_API_BASE_URL \|\| ''` (pix-api :4003) | `pix/frontend/admin/src/services/api.ts:7` |
| spb/frontend-vue | `VITE_API_URL \|\| '/api'` (spb-api) | `spb/frontend-vue/src/services/api.ts:5,9` |
| backoffice | `VITE_API_URL \|\| '/api'` | `backoffice/src/shared/services/api.ts:1` |
| mobile (Flutter) | `BASE_URL=https://coreapi-monetarie.vulci.com.br` (referência legada de infra; runtime atual é AWS) | `mobile/flavors/monetarie.env:1` |
| docs-portal | estático, sem proxy de API | `docs-portal/nginx.conf:3,23,30` |
| nginx local (dev) | pix-admin -> `pix-api:4003`; spb-admin -> `spb-api:4000`; sta-admin -> `sta-backend:4000` | `nginx/local/pix-admin.conf:18`, `spb-admin.conf:23`, `sta-admin.conf:20` |

---

## 5. TigerBeetle (ledger central)

Fato central: SOMENTE o Core conecta ao TigerBeetle. PIX, SPB, NPC, STA e CLST não abrem cliente TB (grep zero); guardam no máximo `settlement_account_id`/`tb_transfer_id` para conciliação (`pix/backend/apps/shared/lib/shared/participants/participant.ex:19`, `clst/lib/monetarie_clst/schemas/reconciliation_record.ex:6`). Não existe código Go `tb-gateway` no repo (apenas o relatório AVIV `docs/reports/2026-07-09-mapeamento-aviv/06-tigerbeetle-tb-gateway.md`).

- Conexão: `core/backend/lib/monetarie/infra/tigerbeetle.ex:1` (client vendorizado `core/backend/vendor/tigerbeetlex/`), endereços por env `TIGERBEETLE_ADDRESSES` com resolução para IP (`core/backend/config/runtime.exs:419-449`), pool round-robin `:tb_0..N` (`.../tigerbeetle/pool.ex:1`, `TB_POOL_SIZE`), cliente separado de leitura `:tb_bulk` (`tigerbeetle.ex:42`), circuit breaker (`.../tigerbeetle/circuit_breaker.ex:1`).
- Unidade: SUBCENTAVO, 1 unidade = R$ 0,0001 (`core/backend/lib/monetarie/util/money_unit.ex:1-6,74`; `from_cents = centavos*100` em `:83`). Conversão só na borda: NATS via `MoneyBoundary` (`money_boundary.ex:89-97`); crédito SPB converte explicitamente (`core/backend/lib/monetarie/use_cases/spb/inbound_credits.ex:301`, com o comentário do incidente 100x: R$ 50.000 virando R$ 500 quando se depositou centavos crus).
- Ledgers (`core/backend/lib/monetarie/use_cases/ledgers.ex`): money-path real roda no ledger 1 (`:41`); catálogo 1_000+ para operacionais, com escrow em `operational_escrow = 1_004` (`:60`, uso em `core/backend/lib/monetarie/use_cases/escrow/provisioning.ex:26-70`); `pix_reserve` 6e9+ é código morto com overflow u32 documentado (`:249-264`).
- Códigos de conta (`core/backend/lib/monetarie/util/codes/account_code.ex`): 10 cash_asset, 11 Conta SPI/PI, 20 settlement_pool, 30 client_liability (carteira do cliente), 35 espelho passivo MED, 321/322 trânsito PIX out/in, 331/332 trânsito TED, 411-414 tarifas (`:53-91`); mapa TB->COSIF em `:261-292`.
- Códigos de transferência (`core/backend/lib/monetarie/util/codes/transfer_code.ex:31-39`): 1 deposit, 2 withdrawal, 3 internal_transfer (book-transfer), 4 settlement_credit, 5 fee, 6 pix, 7 boleto, 8 ted, 9 inter_entity; 1006 escrow_hold two-phase (`:44`); sharp codes PIX-in 1001/1018/5050/1016 (`:170-191`) e cadeia MED 1022-1026 (`:139-156`).
- Escritores principais: `Wallet.deposit/withdraw/hold/internal_transfer` (`core/backend/lib/monetarie/use_cases/wallet.ex:180-196,231-247,277-297,329-350`); PIX-in TB-first em batch linked de 3-4 pernas (`core/backend/lib/monetarie/use_cases/pix/tb_first/deposit.ex:65-197`); two-phase do PIX-out via `PendingTransfers.build_pending/post/void` (`core/backend/lib/monetarie/use_cases/payments/pending_transfers.ex:22-160`) executado por `AtomicPaymentHandler` (`.../payments/atomic_payment_handler.ex:100-260`); crédito TED-in `InboundCredits.post_member_credit` com id determinístico por `num_ctrl_str` (`inbound_credits.ex:288-315,1145`); coalescer e batchers com flags OFF (`.../tigerbeetle/deposit_coalescer.ex:1`, `batch_transfer.ex:1`, `batch_accumulator.ex:1`).
- Leitores: saldo `Wallet.get_balance` (credits_posted - debits_posted - debits_pending, `wallet.ex:138-146`); reconciliação TB<->PG (`core/backend/lib/monetarie/workers/reconciliation/tb_pg_reconciliation_job.ex:118`); `transfer_timestamp` como âncora temporal (`tigerbeetle.ex:587-604`). O saldo da Conta PI na cabine é lido por HTTP (`cabin_treasury.ex:76`), não por TB.
- Seeds: contas fundacionais id 1 (cash, code 10), 2 (fee, 40), 3 (settlement, 20), 5 (capital, 50) em `core/backend/priv/repo/seeds/tigerbeetle.exs:83-154`; plano COSIF com 21 contas TB-backed em `core/backend/priv/repo/seeds/cosif_accounts_owem.exs:41-101`.

---

## 6. Fluxos de dinheiro ponta a ponta

### 6.1 PIX-out (IB -> Core -> cabine -> BACEN -> pacs.002)

```mermaid
sequenceDiagram
  autonumber
  participant IB as IB (banking)
  participant Core as core-api
  participant TB as TigerBeetle
  participant N as NATS
  participant CEP as PIX CoreEventProcessor
  participant OS as PIX OutboundSender
  participant HSM as HSM RTM
  participant BC as BACEN SPI/ICOM
  participant IP as PIX InboundProcessor
  participant SU as PIX StatusUpdater
  participant PC as Core PixConsumer
  participant P as Parceiro (webhook)

  IB->>Core: POST /api/v2/pix (chave, valor)
  Core->>N: Gnat.request dict.lookup.request (resolve chave)
  Note over Core: InternalTransfer.route = :external<br/>(ISPB do credor difere do nosso)
  Core->>TB: hold two-phase (PendingTransfers.build_pending)
  Core->>N: publish_async monetarie.core.pix.payment_request (outbox Oban, Repo.transaction)
  N->>CEP: durable core-event-processor (MONETARIE_CORE)
  CEP->>CEP: valida E2E da consulta DICT, bloqueia saldo,<br/>cria messages PDNG (Repo.transaction)
  CEP->>N: monetarie.spi.transaction.created OUTBOUND
  CEP->>N: monetarie.spi.outbound.send (xml pacs.008)
  N->>OS: durable outbound-sender
  OS->>HSM: assina XMLDSig (CPIA)
  OS->>BC: POST /api/v1/in/{ispb}/msgs (mTLS, direto ou sidecar bacen_ln)
  BC-->>OS: 201 (ACK de transporte, NAO liquida)
  BC-->>IP: pacs.002 via long-poll ICOM (NatsBridge -> monetarie.spi.inbound.pacs.002)
  IP->>N: monetarie.spi.transaction.status_update
  N->>SU: durable status-updater
  SU->>N: monetarie.spi.transaction.settled (ou .rejected)
  N->>PC: durable core-pix-consumer (MONETARIE_SPI)
  PC->>TB: post_pending_transfer (AtomicPaymentHandler) ou void no rejeitado
  PC->>P: webhook pix.payout.confirmed / pix.payout.failed
```

Evidências dos elos: hold e publish no Core (`pix_controller.ex:184`, `transfer_controller.ex:358`); cabine (`core_event_processor.ex:190,408,425,484,544`); envio (`outbound_sender.ex:56-117`); retorno de status (`inbound_processor.ex:3042`, `status_updater.ex:224,406`); liquidação no Core (`pix_consumer.ex:67`, `atomic_payment_handler.ex:100-260`); webhook (`pix_handler.ex:264,283`).

### 6.2 PIX-in (BACEN -> cabine -> NATS created INBOUND -> Core credita)

Canônico (2026-07-09): o BACEN liquida ANTES de entregar a pacs.008 e o recebedor não recebe pacs.002 na prática. O caminho de crédito é o `created` INBOUND untracked; `TWO_PHASE_PIX_IN` permanece proibida e OFF.

```mermaid
sequenceDiagram
  autonumber
  participant BC as BACEN SPI/ICOM
  participant CPM as PIX CPM/CSM worker
  participant NB as PIX NatsBridge
  participant N as NATS
  participant IP as PIX InboundProcessor
  participant Core as Core (PixAccountValidator)
  participant OS as PIX OutboundSender
  participant PC as Core PixConsumer
  participant TB as TigerBeetle
  participant P as Parceiro (webhook)

  BC-->>CPM: pacs.008 JA LIQUIDADA (long-poll stream/start + pull)
  CPM->>NB: partes do long-poll
  NB->>N: Gnat.pub monetarie.spi.inbound.pacs.008 (xml cru)
  N->>IP: durable inbound-processor (MONETARIE_SPI)
  IP->>N: Gnat.request monetarie.core.pix.validate_account
  N->>Core: responder valida conta do recebedor
  Core-->>IP: ok (sem resposta = RJCT fail-closed)
  IP->>IP: grava messages + credita Conta PI (update_pi_balance)
  IP->>N: publish_async monetarie.spi.transaction.created (direction INBOUND)
  IP->>N: monetarie.spi.outbound.pacs002 (ACSP)
  N->>OS: envia pacs.002 ACSP ao BACEN
  N->>PC: durable core-pix-consumer
  PC->>PC: MoneyBoundary.convert_inbound; guardas:<br/>two-phase OFF, inbound_direction?, tx nao rastreada
  PC->>PC: PixInWal.track_received (WAL antes do TB)
  PC->>TB: Wallet.deposit (id deterministico SHA-256)
  PC->>PC: transactions PIXIN + extrato + WAL completed
  PC->>P: webhook pix.received
```

Evidências: entrada (`icom/nats_bridge.ex:61`, `cpm/worker.ex:8-32`); processamento e crédito da PI (`inbound_processor.ex:918,931,2874,2617`); validação de conta (`inbound_processor.ex:988`, `pix_account_validator.ex:33`); crédito no Core (`pix_consumer.ex:67`, `pix_handler.ex:61-78,420-524`, `pix_in_wal.ex:34-86`); recovery da perna PG (`pix_in_credit_recovery_worker.ex`, replay em `pix_handler.ex:859`); reconciliação de órfãs alert-only (`pix_in_orphan_reconciliation.ex:381`).

### 6.3 TED-out (Core/IB -> SPB -> MQ -> BACEN STR0008 -> R1)

```mermaid
sequenceDiagram
  autonumber
  participant IB as IB / Partner API
  participant Core as core-api
  participant TB as TigerBeetle
  participant N as NATS
  participant CEC as SPB CoreEventConsumer
  participant HSM as HSM RTM
  participant MQS as sidecar MQ (Java :9080)
  participant MQ as IBM MQ RTM
  participant BC as BACEN STR
  participant IC as SPB InboundConsumer
  participant SC as Core SpbConsumer

  IB->>Core: POST TED (v2/transfer ou partner)
  Core->>TB: hold do valor
  Core->>N: publish_async monetarie.core.spb.transfer_request (payload FLAT, event=transfer_request)
  N->>CEC: Gnat.sub monetarie.core.spb.>
  CEC->>CEC: STR0008Builder.build (fail-closed, 9 campos)<br/>Messages.create_message + LifecycleEngine.process_outgoing
  CEC->>HSM: MessagePacker.pack assina C15 (sign-rsa)
  CEC->>MQS: RealDispatcher -> DomainManager (POST .../queue/QR.REQ...)
  MQS->>MQ: JMS put
  MQ->>BC: STR0008
  CEC->>N: monetarie.spb.transactions.accepted (outbox)
  N->>SC: durable core-spb-consumer (status tracked)
  MQ-->>MQS: R0 (ACK transporte, report COA)
  MQS->>CEC: POST /mq/webhook/report -> LifecycleEngine.handle_r0
  BC-->>MQ: STR0008R1 (confirmacao BACEN)
  MQ-->>MQS: mensagem R1
  MQS->>IC: webhook -> InboundAudit -> MQConsumer -> bacen.inbound.* (BACEN_INBOUND)
  IC->>IC: LifecycleEngine.handle_r1
  IC->>N: CoreNotifier monetarie.spb.transactions.confirmed/settled
  N->>SC: durable core-spb-consumer
  SC->>TB: SpbHandler.handle_tracked_status (liquida, libera/consome hold)
```

Evidências: publish do Core (`ted.ex:100,194`); recepção e montagem (`core_event_consumer.ex:102-109,196-225`; `str0008_builder.ex:35-53`); assinatura e MQ (`real_dispatcher.ex:21-39`, `message_packer.ex:224-231`, `domain_manager.ex:658-735`); R0/R1 (`mq_bridge.ex:404-407`, `inbound_consumer.ex:458-473`, `lifecycle_engine.ex:420,2092`); Core (`spb_consumer.ex:93`, `spb_handler.ex:58-159,381`).

### 6.4 TED-in (STR0008R2 -> SPB -> NATS -> Core credita)

```mermaid
sequenceDiagram
  autonumber
  participant BC as BACEN STR
  participant MQ as IBM MQ RTM
  participant MQS as sidecar MQ (Java)
  participant BG as SPB bacen_gateway
  participant HSM as HSM RTM
  participant N as NATS
  participant IC as SPB InboundConsumer
  participant OW as SPB Outbox.Worker
  participant SC as Core SpbConsumer
  participant TB as TigerBeetle

  BC->>MQ: STR0008R2 (TED recebida)
  MQ-->>MQS: mensagem
  MQS->>BG: POST /mq/webhook/{domain} (HMAC)
  BG->>BG: InboundAudit.record_raw (1o passo duravel)
  BG->>HSM: decifra C14 + verifica assinatura C15 (fail-closed)
  BG->>N: publish_async bacen.inbound.<dominio>.str0008r2 (BACEN_INBOUND)
  BG->>N: hook legado CoreNotifier monetarie.spb.transactions.settled (inbound)
  N->>IC: pull durable bacen-gateway-receiver
  IC->>IC: LifecycleEngine.process_incoming -> INSERT spb_operations r2_confirmed<br/>(dedup ON CONFLICT num_ctrl_str)
  IC->>IC: enqueue outbox monetarie.spb.credits.inbound (MESMA transacao)
  OW->>N: publica monetarie.spb.credits.inbound (stream MONETARIE_SPB)
  N->>SC: durable core-spb-consumer
  SC->>SC: SpbInboundCreditHandler: parse amount_brl (reais),<br/>INSERT spb_inbound_credits ON CONFLICT num_ctrl_str
  SC->>TB: InboundCredits.post_member_credit (MoneyUnit.from_cents, subcentavo)
  SC->>SC: extrato + transactions TEDIN + espelho COSIF
```

Evidências: webhook e auditoria (`mq_webhook_controller.ex:11`, `mq_bridge.ex:178-241`, `inbound_audit.ex:27,142-244`); decifra (`mq_consumer.ex:27-94`, `message_packer.ex:401-407`); publicação (`message_processor.ex:711-739`); materialização e outbox (`lifecycle_engine.ex:931,1103-1140,1390-1526,1664-1743`; `outbox/worker.ex:171-173`); crédito no Core (`spb_consumer.ex:66`, `spb_inbound_credit_handler.ex:60-229`, `inbound_credits.ex:288-315`).

Nota: há DOIS emissores de crédito TED-in no SPB, o canônico `monetarie.spb.credits.inbound` (Fase 4) e o legado `monetarie.spb.transactions.settled` com `direction=inbound` (`core_notifier.ex:69-107`); o Core tem handler para cada um (`spb_consumer.ex:66` e `:93`). ATENÇÃO: o árbitro de idempotência por `num_ctrl_str` (`spb_inbound_credits` UNIQUE) só protege o caminho da ponte; o caminho legado (`SpbHandler.handle_transaction_ledger`, `spb_handler.ex:159`) credita com referência NumCtrlIF/NUOp e transfer TB derivado dessa referência (`spb_handler.ex:357-366`), sem consultar o árbitro. Não foi encontrado dedup cruzado entre os dois caminhos: risco provável de crédito duplo, verificação P0 em `docs/reports/2026-07-10-ted-in-duplo-credito-verificacao.md`.

### 6.5 Book-transfer interno (mesmo ISPB, não vai ao BACEN)

```mermaid
sequenceDiagram
  autonumber
  participant IB as IB (banking)
  participant Core as core-api
  participant N as NATS
  participant PIXR as PIX DictLookupResponder
  participant TB as TigerBeetle

  IB->>Core: POST /api/v2/pix (chave do recebedor)
  Core->>N: Gnat.request dict.lookup.request
  N->>PIXR: lookup DICT (cache/BACEN)
  PIXR-->>Core: creditor_ispb = 46026562 (nosso)
  Note over Core: InternalTransfer.route: ISPB nosso E conta interna viva<br/>=> {:book_transfer, receiver_account_id}<br/>fail-safe: sem conta interna => caminho externo
  Core->>TB: Wallet.internal_transfer (1 transfer code 3,<br/>id deterministico do transaction_id)
  Core->>Core: registra transacao com internal_transfer=true
  Core->>N: publish_balance_update (ledger.balance.updated)
  Note over Core,TB: NAO passa pela cabine PIX, NAO gera pacs.008,<br/>NAO consome ficha E2E no BACEN
```

Evidências: decisão de rota (`core/backend/lib/monetarie/use_cases/pix/internal_transfer.ex:60-101`, chamada em `core/backend/lib/monetarie_web/controllers/v2/pix_controller.ex:299-300`); liquidação (`internal_transfer.ex:147-186`, `Wallet.internal_transfer` em `:160`, marca `"internal_transfer" => true` em `:259`, balance update em `:295`); transfer TB code 3 (`wallet.ex:329-350`, `transfer_code.ex:33`).

---

## 7. Contratos de eventos (payloads principais)

Unidades: eventos da cabine PIX carregam `amount` em CENTAVOS; o Core converte para subcentavos na entrada (`MoneyBoundary.convert_inbound`) e converte de volta na saída. Eventos do SPB carregam `amount_brl`/`valor` como STRING em REAIS, propositalmente fora da lista do MoneyBoundary (parse no handler).

1. `monetarie.core.pix.payment_request` (Core -> PIX; `pix_controller.ex:184`):
   `{"type": "pix_out", "data": {"event": "payment_request", "transaction_id", "end_to_end_id", "direction": "outbound", "amount", "account_id", "recipient_key", "recipient_key_type", "recipient_name", "recipient_document", "recipient_ispb", "hold_id", "status"}}`. O campo `event` é a routing key no `CoreEventProcessor` (gotcha: ausente ou errado = ack silencioso sem processamento).

2. `monetarie.core.spb.transfer_request` (Core -> SPB; `ted.ex:194`, contrato em `publisher.ex:216-238`):
   payload FLAT no topo (a cabine SPB descarta envelope `{type,data}` aninhado): `{"event": "transfer_request", "type": "spb_transaction", "transaction_id", "transaction_type": "TED", "message_type": "STR0008", "amount", "account_id", "hold_id", "recipient_name", "recipient_document", "recipient_ispb", "recipient_agency", "recipient_account", "description", "initiated_at"}` + campos do debtor.

3. `monetarie.spi.transaction.created` direction INBOUND (PIX -> Core, crédito do PIX-in; `inbound_processor.ex:2874`):
   `{"transaction_id", "message_id", "message_type": "pacs.008", "event_type": "CREATED", "debtor_ispb", "creditor_ispb", "end_to_end_id", "direction": "INBOUND", "amount", "account_id", "type": "pix_transaction", "source": "pix", "published_at", "trace_id"}`. Sufixo `received` só existiria com two-phase (proibido em produção).

4. `monetarie.spi.transaction.settled` (PIX -> Core; `status_updater.ex:257`):
   `{"message_id", "end_to_end_id", "amount", "debtor_ispb", "creditor_ispb", "direction", "status_id": 4, "status": "settled", "settled_at", "transaction_id", "pix_transaction_id", "type": "pix_transaction"}`.

5. `monetarie.spb.credits.inbound` (SPB -> Core, crédito TED-in; `lifecycle_engine.ex:1712-1743`):
   `{"event": "credit_received", "source": "spb", "message_type": "STR0008", "num_ctrl_str", "nuop", "operation_id", "debtor_ispb", "creditor_ispb", "amount_brl", "dt_movto", "credit_kind": "client"|"institutional", "creditor_account", "creditor_agency", "creditor_cpf_cnpj", "creditor_name", "debtor_*", "finldd_cli", "hist"}`. Idempotência core-side por `num_ctrl_str` (`spb_inbound_credit_handler.ex:229`).

6. `monetarie.spb.transactions.<status>` (SPB -> Core; `core_notifier.ex:22-57`):
   `{"type": "spb_transaction", "transaction_id", "message_id", "status", "message_type", "account_id", "hold_id", "merchant_id", "amount", "direction", "lifecycle_state", "error_reason"}`.

7. `monetarie.settlement.transaction.credited` (PIX -> Core; `settlement_obligation_worker.ex:374`):
   `{"message_id", "end_to_end_id", "amount", "debtor_ispb", "creditor_ispb", "direction", "status_id", "settled_at", "obligation_id", "cycle_id"}` com `money_path: true`.

8. Webhooks de parceiro (Core -> parceiro; `delivery_job.ex:107-114`): eventos `pix.payout.confirmed`, `pix.payout.failed`, `pix.received`, `pix.charge.paid`, `pix.return.received`; headers `X-Monetarie-Signature` (HMAC-SHA256), `X-Monetarie-Timestamp`, `X-Monetarie-Event-Id`, `X-Monetarie-Event-Type`; dedup por `(webhook_id, event_id)`; guarda fail-closed que recusa eventos terminais de dinheiro sem confirmação de settlement (`webhooks.ex:140-163`).

9. Satélites (envelope comum): `{"type": "<dominio>.<evento>", "data": {...}, "published_at", "source": "npc"|"sta"|"clst", "trace_id"}` (NPC `publisher.ex:98`, STA `publisher.ex:92`, CLST `publisher.ex:160`).

---

## 8. Garantias por elo (durabilidade, dedup, retry)

| Elo | Garantia |
|---|---|
| Publicação money-path (todos) | outbox transacional (Oban/`pending_publish_events`), `Nats-Msg-Id` para dedup de stream (janela 2 min), retry com backoff, guarda I-1 em runtime + Credo `OutboxAtomicity` |
| Consumo Core | push durável com NAK + backoff, `max_ack_pending`, dedup determinístico (`MsgIdentity`/`MessageDedup`), DLQ NATS + PG após esgotar tentativas (`durable_consumer.ex`) |
| Consumo PIX | push durável (BaseWorker), `max_deliver = retries+1`, poison policy -> `monetarie.dlq.poison.*` |
| Consumo SPB | pull durável (`MSG.NEXT`), ACK/NAK com backoff 5s a 300s, `max_deliver` 3-5 |
| PIX-in crédito | WAL `pix_in_credit_wal` com estados received -> tb_done -> pg_done -> completed; recovery reexecuta só a perna PG (sem risco de duplo crédito); reconciliação de órfãs por camt.054 alert-only |
| TED-in crédito | dedup em três camadas: ON CONFLICT em `spb_operations`, outbox na mesma transação, ON CONFLICT `num_ctrl_str` em `spb_inbound_credits` no Core |
| Request/reply | sem persistência; fail-closed nos pontos de dinheiro (validação de conta PIX-in vira RJCT em timeout) |

---

## 9. Pontos de acoplamento (insumo para o desacoplamento do monorepo)

### 9.1 Código compartilhado

| Acoplamento | Onde | Observação |
|---|---|---|
| App umbrella `shared` da cabine PIX | `pix/backend/apps/shared` (schemas, BACEN client, crypto, NATS, auth) usado por `dict_service`, `spi_service`, `settlement_service` | fronteira interna da cabine; ao quebrar o umbrella, `Shared.*` vira biblioteca |
| Pacote frontend compartilhado do Core | `core/packages/shared` (workspace pnpm) usado por banking/admin/merchant | |
| Pacote mobile | `packages/mobile-ui` na raiz | consumido pelo app Flutter/web mobile |
| Cliente TB vendorizado | `core/backend/vendor/tigerbeetlex` | só o Core; bom candidato a permanecer interno |
| Credo check `OutboxAtomicity` COPIADO em 6 sistemas | `core/backend/lib/monetarie/credo_checks/outbox_atomicity.ex`, `pix/backend/apps/shared/lib/shared/credo_checks/outbox_atomicity.ex`, `spb/services/bacen_gateway/lib/bacen_gateway/credo_checks/outbox_atomicity.ex`, `npc/backend/lib/monetarie_npc/credo_checks/outbox_atomicity.ex`, `sta/backend/lib/sta_connector/credo_checks/outbox_atomicity.ex`, `clst/lib/monetarie_clst/credo_checks/outbox_atomicity.ex` | 6 cópias do mesmo AST check (ADR-008/009/010); extrair para lib hex interna |
| Padrão Publisher/outbox/RuntimeGuard duplicado por sistema | `publisher.ex` + `publish_job.ex` + `runtime_guard.ex` em Core, PIX, SPB, NPC, STA, CLST | mesma semântica, 6 implementações; candidata a lib `monetarie_nats` |
| Contrato de unidade monetária implícito | Core subcentavo (`money_unit.ex`), cabine PIX centavos, SPB reais string (`amount_brl`); tradução concentrada em `money_boundary.ex:70` (lista de campos) | acoplamento semântico frágil: campo novo fora da lista passa sem conversão; explicitar unidade no payload ao desacoplar |
| JWT cross-service | cadeia `JWT_SECRET` -> `GUARDIAN_SECRET_KEY` -> `SECRET_KEY_BASE` compartilhada Core/cabines (`pix/CLAUDE.md`, seção Cross-Service Auth) | segredo compartilhado entre repositórios futuros |

### 9.2 Banco de dados

- Cluster Aurora único por ambiente hospedando os bancos de todos os sistemas (HML `monetarie-core-homolog-45`; ver seção 1). Cada sistema tem `DATABASE_URL` próprio, sem FK cruzada conhecida entre bancos: o desacople físico é viável por banco.
- O Core NÃO lê o banco da cabine PIX: o fallback SQL direto foi removido (commit `e96e1d09`); o acesso pontual é HTTP admin (`cabin_status_lookup.ex`). Manter essa disciplina é pré-requisito do split.
- ETL/staging legado compartilha o banco do SPB (`stg.*` em prod, ver relatório de reconciliação AutBank).

### 9.3 Barramento NATS (acoplamentos de infraestrutura)

- `MONETARIE_CORE` tem TRÊS criadores com configs próprias (Core `stream_setup.ex:102`, PIX `jetstream.ex:86`, SPB `stream_manager.ex:77`) e `MONETARIE_SPI/DICT/SETTLEMENT/AUDIT/DLQ` têm dois (Core e PIX), com retenções divergentes no DLQ (30d vs 90d). Boot de um sistema pode dar UPDATE no stream do outro. Recomendação: um único dono por stream (idealmente IaC/StreamSetup central) antes do split.
- Satélites NPC/STA/CLST NÃO criam streams: dependem do Core criar `MONETARIE_NPC/STA/CLST` no boot (acoplamento de ordem de subida; houve incidente em que o Core deletava e recriava esses streams a cada boot, corrigido em `stream_setup.ex:13-21`).
- `MONETARIE_PIX_TBFIRST` é consumido (`pg_writer_worker.ex:30`) mas nenhum StreamSetup o cria.
- Discrepância SPB: durable `bacen-core-event-processor` declarado (`stream_manager.ex:127`) mas o `CoreEventConsumer` usa `Gnat.sub` plano (`core_event_consumer.ex:41`): o pedido de TED do Core NÃO tem redelivery de servidor nesse elo (mitigado pelo outbox do Core e pela reconciliação HTTP).
- Subjects órfãos: `messages.new`/`transactions.new` do api_gateway SPB sem stream nem consumidor; DLQ do CLST `planner.dlq.clst.failed` fora do namespace `monetarie.*` (não capturado por `MONETARIE_DLQ`).
- Roteamento por convenção de payload: `event` como routing key (PIX `core_event_processor.ex:68`, SPB `core_event_consumer.ex:102`) e contrato flat vs envelope `{type,data}` divergente entre PIX e SPB (`publisher.ex:216-238`). Formalizar schema por subject (JSON Schema versionado) é pré-condição de desacoplamento seguro.

### 9.4 Ledger e dinheiro

- TigerBeetle é exclusivo do Core: as cabines não têm caminho de escrita no ledger, o que já isola o domínio contábil. O acoplamento restante é semântico (unidades, códigos de transfer/conta) e temporal (crédito do cliente depende do consumo do evento pelo Core).
- Dois emissores de crédito TED-in coexistem (seção 6.4); consolidar em `monetarie.spb.credits.inbound` e aposentar o hook legado do `CoreNotifier` reduz a superfície de contrato.
- Publishers legados da cabine PIX fora do outbox (`EventPublisher`, `SettlementService.NATS.Publisher`, deprecados; `event_publisher.ex:321`) devem morrer antes do split.

### 9.5 Sidecars e credenciais

- Cabine PIX: sidecar Go `bacen_ln` (mTLS HSM-backed) é infraestrutura de deploy da cabine; contrato via envs `DICT_BASE_URL`/`ICOM_*_URL` (seção 4.2).
- SPB: sidecar Java IBM MQ acoplado por task-def do ECS (mesma task do spb-api) com webhook HMAC local.
- HSM RTM: três clientes distintos (PIX, SPB, Core/KMS) contra o mesmo endpoint; UIDs de chave por sistema em Secrets Manager.

---

## 10. Anexo: inventário de consumers duráveis

| Sistema | Durable | Stream | Filtro | Evidência |
|---|---|---|---|---|
| Core | `core-pix-consumer` | MONETARIE_SPI | `monetarie.spi.transaction.*`, `.payment.*`, `.return.*` | `pix_consumer.ex:30-39` |
| Core | `core-pix-settlement-consumer` | MONETARIE_SETTLEMENT | `monetarie.settlement.session.*` | `pix_consumer.ex:40-44` |
| Core | `core-spb-consumer` | MONETARIE_SPB | `monetarie.spb.messages.*`, `.transactions.*`, `.credits.inbound`, `.credits.return_status`, `.cosif.entry` | `spb_consumer.ex:34` |
| Core | `core-npc-consumer` | MONETARIE_NPC | `monetarie.npc.boleto.*`, `.cycle.*`, `.protocol.processed`, `.titulo.*` | `npc_consumer.ex:33-35` |
| Core | `core-sta-consumer` | MONETARIE_STA | `monetarie.sta.file.*`, `.protocol.processed` | `sta_consumer.ex:24-27` |
| Core | `core-clst-consumer` | MONETARIE_CLST | `monetarie.clst.settlement.>`, `.clearing.*`, `.reconciliation.*`, `.liquidity.*` | `clst_consumer.ex:26-29` |
| Core | `core-dict-consumer` | MONETARIE_DICT | `monetarie.dict.infractions.*`, `.recovery.*` | `dict_consumer.ex:19-23` |
| Core | `core-scr-consumer` | MONETARIE_SCR | `monetarie.scr.event.*` | `scr_engine/nats/consumer.ex:20-24` |
| Core | `pg-writer` | MONETARIE_PIX_TBFIRST | `monetarie.pix.tbfirst.settled` | `pg_writer_worker.ex:30-33` |
| PIX | `inbound-processor` | MONETARIE_SPI | `monetarie.spi.inbound.>` | `inbound_processor.ex:79` |
| PIX | `outbound-sender` | MONETARIE_SPI | `monetarie.spi.outbound.>` | `outbound_sender.ex:32` |
| PIX | `status-updater` | MONETARIE_SPI | `monetarie.spi.transaction.>` | `status_updater.ex:14` |
| PIX | `return-processor` | MONETARIE_SPI | `monetarie.spi.return.>` | `return_processor.ex:14` |
| PIX | `recurrence-executor` | MONETARIE_SPI | `monetarie.spi.recurrence.execute` | `execution_worker.ex:27` |
| PIX | `med-resolution-consumer` | MONETARIE_SPI | `monetarie.spi.med.resolution_received` | `resolution_consumer.ex:19` |
| PIX | `med-infraction-responder` | MONETARIE_DICT | `monetarie.dict.med.infraction_received` | `infraction_responder.ex:16` |
| PIX | `med-infraction-response` | MONETARIE_DICT | `monetarie.dict.infractions.response` | `infraction_response_consumer.ex:28` |
| PIX | `claim-deadline-consumer` | MONETARIE_DICT | `monetarie.dict.deadlines.>` | `claim_deadline_consumer.ex:24` |
| PIX | `core-event-processor` | MONETARIE_CORE | `monetarie.core.pix.>` | `core_event_processor.ex:41` |
| PIX | `settlement-obligation-worker` | MONETARIE_SPI | `monetarie.spi.transaction.settled` | `settlement_obligation_worker.ex:45` |
| PIX | `settlement-scheduler` | MONETARIE_SETTLEMENT | `monetarie.settlement.schedule.>` | `scheduler.ex:15` |
| PIX | `file-importer` | MONETARIE_SETTLEMENT | `monetarie.settlement.file.>` | `file_importer.ex:15` |
| SPB | `bacen-gateway-sender` (pull) | BACEN_OUTBOUND | `bacen.outbound.>` | `message_consumer.ex:24-28` |
| SPB | `bacen-gateway-receiver` (pull) | BACEN_INBOUND | `bacen.inbound.>` | `inbound_consumer.ex:35-39` |
| SPB | `bacen-events-processor` (pull, audit-only) | BACEN_EVENTS | `bacen.events.>` | `events_consumer.ex:30-34` |
| SPB | `bacen-dlq-processor` (declarado) | BACEN_DLQ | `bacen.dlq.>` | `stream_manager.ex:116` |
| SPB | `bacen-core-event-processor` (declarado, NÃO usado em runtime) | MONETARIE_CORE | `monetarie.core.spb.>` | `stream_manager.ex:127` vs `core_event_consumer.ex:41` |

Satélites NPC/STA/CLST consomem por `Gnat.sub` (queue subscription core NATS), sem durable próprio; a durabilidade dos eventos deles está nos streams `MONETARIE_NPC/STA/CLST` consumidos pelo Core.
