# Handoff: extrato com contraparte íntegra + aba Comprovante no coreadmin

Data: 2026-07-15
Branch: `feat/coreadmin-extrato-comprovante` (21 commits de código/docs sobre a main + este fechamento). SEM push; push só com autorização explícita do dono.
Design: `docs/plans/2026-07-15-coreadmin-extrato-contraparte-comprovante-design.md` (status atualizado para IMPLEMENTADO).
Diagnóstico e roteiro de backfill: `docs/reports/2026-07-15-extrato-contraparte-fase0-prod.md` (o §10 documenta a execução local do dry_run/apply/reconcile e serve de roteiro para HML/PROD).

## O que foi entregue

### Fase 0 — diagnóstico com evidência de PROD (read-only)

Commit `1a02b868`. O caso vivo (PIX enviado de R$ 2.500 com Recebedor "-") foi rastreado até a cadeia do envio manual da cabine, que descartava o recebedor em dois elos, mais o lookup HTTP do Core para a API admin da cabine PIX quebrado em PROD (401). Dimensionamento do backfill com contagens reais de PROD no relatório.

### Fase 1 — write-path do extrato em todos os trilhos

Commits `27e3081c`, `f6d556ba`, `e793170c`, `355b98eb`, `d08ebe3b`, `89b956c5`, `b86a2dbe`, `631ee525`, `1d99056c`, `e8d37a2f`. Em resumo:

- PIX recebido persiste CPF/CNPJ do pagador no extrato (antes o handler tinha `debtor_cpf_cnpj` em mãos e descartava); o caminho TB-first (PgWriter) idem.
- TED enviada passou a gerar lançamento no extrato (gap estrutural: o ramo settled do `spb_handler` só atualizava status/tarifa/webhook).
- TEF: o débito sai com a contraparte real (titular da conta destino) e o recebedor passou a ver o crédito no extrato ("Transferência recebida - <pagador>"), com hardening de idempotência (`on_conflict: :nothing`, `settled_at` determinístico).
- PIX interno (book-transfer) grava as duas pernas do extrato.
- O envio manual da cabine propaga o recebedor ao Core e ao evento settled; o registro de débito PIX persiste o recebedor na `outbound_request`; a cabine faz uma query por evento settled (amount+recebedor unificados).

### Fase 2 — backfill do acervo

Commits `44763f5c`, `d81dcf4f`, `d5e34f04`, `40f3116d`. `Monetarie.Release.StatementBackfill` com `dry_run/0`, `apply/1` e `reconcile/0`, projetado para rpc em HML/PROD:

- dry-run imprime contagens por trilho antes de escrever;
- apply é idempotente (mesmo par reference/source dos caminhos vivos — rodar duas vezes não duplica);
- reconcile compara acervo vs extrato e inclui entries reversed (senão conta com estorno aparecia como drift falso);
- as pernas `_RCV` internas são roteadas pelo par reference/source do caminho vivo (rotear pelo inbound comum duplicaria o crédito).

Executado e validado no ambiente local (relatório §10).

### Fase 3 — aba Comprovante no coreadmin

Commits `2245c23e`, `1953b609`, `f979218b`, `821fdba1`, `c4b1f829`, `1aa64b11`:

- Serializer do comprovante extraído para `Monetarie.UseCases.Receipts.Payload`, usado pelo v2 (IB, contrato inalterado) e pelo admin — o comprovante do admin é idêntico ao do IB por construção (teste de ouro compara os dois payloads campo a campo).
- `GET /api/admin/bank-accounts/:id/receipts` (débitos liquidados pix/ted/tef outbound, paginação server-side, filtros de período, gate EnsureAdmin) e `GET /api/admin/bank-accounts/:id/receipts/:transaction_id` (payload do comprovante).
- Aba "Comprovante" entre Extrato e Dados da Conta na tela Contas Correntes; Dialog no desenho do ib-front (marca Monetarie, valor, status, recebedor, pagador, chave PIX, E2E, autenticação, rodapé legal Lei 14.063/2020) com impressão.
- Comprovante rotula TEF ("Transferência interna") e reconhece liquidação interna como provada (status Concluído).

## Validação viva local (Task 16, regra #11)

Ambiente: banco isolado `mon_core_livecheck` (criado a partir do worktree, 303 migrations aplicadas), seeds mínimos (entities + rbac + platform_admin), fixtures gravados pelos caminhos REAIS (`StatementEntries.record_outbound_settled`/`record_inbound_settled`, `Tef.create_receiver_transaction` dentro de `Repo.transaction`), core-api `mix phx.server` (porta 4000) + admin vite (porta 5174), navegação e captura com Playwright. TigerBeetle ficou FORA (container parado há 3 semanas, não foi necessário): a validação não cobre a action de saldo TB — extrato, comprovante e cards da tela leem Postgres.

Screenshots (conferidos um a um, renderização real):

- `docs/reports/screenshots/2026-07-15-coreadmin-extrato-comprovante/01-extrato-pagador-recebedor.png` — aba Extrato da conta pagadora com Pagador E Recebedor populados nas 4 linhas (PIX enviado com nome+CNPJ do recebedor, PIX recebido com nome+CNPJ do pagador, TED enviada, TEF com contraparte) e saldo acumulado correto.
- `docs/reports/screenshots/2026-07-15-coreadmin-extrato-comprovante/02-comprovante-aba-lista-debitos.png` — aba Comprovante com os 3 débitos elegíveis (TEF, TED, PIX), recebedor com nome+documento, tags por tipo, paginação.
- `docs/reports/screenshots/2026-07-15-coreadmin-extrato-comprovante/03-comprovante-dialog-pix-emitido.png` e `03b-comprovante-dialog-pix-rodape.png` — Dialog do comprovante do PIX no desenho do IB: marca + "PIX Enviado", valor R$ 1.283,47, selo Concluído (prova de liquidação spi_cabin + spi_status_id 4), dados do recebedor (documento mascarado), chave PIX/tipo, dados do pagador (agência/conta), Data/Hora, ID da transação, TXID, E2E, autenticação, rodapé legal Lei 14.063/2020 e botão Imprimir comprovante.
- `docs/reports/screenshots/2026-07-15-coreadmin-extrato-comprovante/04-extrato-recebedor-credito-tef.png` — extrato do RECEBEDOR com o crédito da TEF ("Transferência recebida - M2 Validacao Ltda", pagador com CNPJ, R$ 320,10).

Console do navegador durante os fluxos validados: zero erros (os únicos 401 registrados são do bootstrap de sessão pré-login, esperados).

## Regressões finais

- Backend (`MIX_TEST_PARTITION=wt mix test test/monetarie/use_cases/pix test/monetarie/use_cases/payments test/monetarie/infra/nats test/monetarie/release test/monetarie_web/controllers/admin test/monetarie_web/controllers/v2`): 1 property, 1007 testes, 0 falhas (2 excluídos).
- Vitest admin (`pnpm --filter @monetarie/admin test`): 45 arquivos, 350/350 aprovados.

## O que falta (fora desta sessão)

1. Deploy HML e PROD: exige autorização explícita do dono e janela fora de operação de money-path ao vivo (regra dura: deploy troca liderança do ICOM e perde mensagem do BACEN).
2. Backfill do acervo em HML/PROD via rpc, seguindo o roteiro do relatório §10 (dry-run com contagens revisadas pelo dono antes do apply; reconcile depois).
3. Screenshot em HML (precisa de VPN) se o dono quiser evidência no ambiente.

## Follow-ups registrados nas reviews

a. Unificar o componente de comprovante (banking, merchant, admin) num shared — hoje o admin usa cópia adaptada do `ReceiptView.vue` do banking (decisão do design, unificação ficou como follow-up).
b. Unique index parcial `(reference, metadata->>'source')` em `account_entries` para fechar o TOCTOU do dedup por pré-checagem do `insert_entry` — migration com janela (acervo grande, criar `CONCURRENTLY`).
c. O lookup do Core para a API admin da cabine PIX responde 401 em PROD porque a credencial NUNCA foi liberada para o Core em produção (confirmado pelo dono em 15/07: não é defeito nem rotação pendente, é provisionamento que nunca existiu). Consequência prática: as categorias do backfill que consultariam a cabine degradam para `skipped` em PROD, como projetado; a alternativa documentada na Fase 0 é o dado da própria transação ou do banco da cabine (via `metadata.pix_transaction_id`). Se o dono quiser o lookup vivo (reconciliação pontual por E2E), a decisão é provisionar a credencial, não corrigir código.
d. Janela at-most-once do outbox do settled da cabine (estrutural, pré-existente): um settled publicado e perdido antes do consumo não re-emite o extrato sozinho; o backfill/reconcile cobre a cura.
e. `FeeCalculator` nil-compare: TED de conta sem `entity_id` nunca cobra tarifa e só emite warning silencioso — revisar a política de tarifa para contas sem entidade.
f. `:tef_missing_rcv_tx` no reconcile é informativa — criar as transações `_RCV` históricas que faltam exige decisão do dono (mexe em `transactions`, não só em extrato).
g. Gotcha antes do apply em PROD: há saldos derivados de `account_entries` (ex.: adiantamento) — revisar os consumidores desses saldos antes de inserir lançamentos históricos, para o backfill não alterar cálculo derivado sem o dono saber.

## Como retomar

- Worktree: `/Users/luizpenha/.config/superpowers/worktrees/monetarie/coreadmin-extrato-comprovante` (branch `feat/coreadmin-extrato-comprovante`).
- O banco `mon_core_livecheck` da validação foi descartado depois dos screenshots conferidos (recriável pelo roteiro acima em minutos).
- Nenhum container foi derrubado ou reiniciado; phx.server e vite da validação foram encerrados ao final.
