# W1-F3 (docs do cliente, frente core): fechamento da implementação e nota de deploy

Data: 2026-07-18. Frente executada em worktree isolada, plano `docs/plans/2026-07-18-w1-f3-docs-cliente-core.md`, tasks T1 a T22 completas com TDD (RED antes de GREEN em toda task, commit local por task, sem push). A T23 (validação viva em HML com screenshots) fica para a janela do orquestrador.

## O que foi entregue (por fase)

### Fase 1: CCS
- `Monetarie.UseCases.Regulatory.Ccs.MovementsReport`: relatório de movimentações derivado de `ccs_files` (a fonte da verdade; `ccs_records` está vazia em HML e PRD), com as 8 colunas do cliente, modo analítico e consolidado, busca por CPF/CNPJ com máscara, nome e conta.
- Endpoint `GET /api/v1/regulatory/ccs/movements-report` (camelCase na borda, permissão `compliance.cadoc` view; rota acima do catch-all `/ccs/:id`).
- Tela `Relatórios > Movimentações CCS` (`CcsMovementsReportView.vue` + `useCcsMovementsReport.ts`), export CSV/XLSX/PDF via `dispatchReportDownload`, card no Hub (o item `compliance.ccs` saiu de coming_soon) e atalho na tela Operações CCS.
- E-mail CCS: `Monetarie.Mailer` saiu de código morto. `Ccs.Notifications` cobre 7 eventos (`generated`, `generation_failed`, `submitted`, `accs002_verdict` aceite e rejeição com `ErrorDictionary`, `accs003_received`, `accs009_received`, `daily_digest`); ganchos fail-soft em `StaInbound.apply_accs002`, `StaSubmission.submit`, `apply_inbound_accs003/009` e `CcsAccs001DailyJob`; worker `CcsEmailNotifier` (Oban `:regulatory`, 3 tentativas) e digest `CcsDailyDigestWorker` (cron `30 12 * * *` = 09:30 BRT, paridade config.exs e runtime.exs, `ObanCronParityTest` verde). Adapter fail-safe: sem `SMTP_HOST`, e-mail vira log estruturado (Swoosh Logger).

### Fase 2: relatórios Vulci
- Item 1: export server-side CSV/OFX do extrato por conta no coreadmin (`GET /api/admin/bank-accounts/:id/statement/export`, funil canônico `Statements.export_statement`, OFX 1.0.2 SGML mantido por decisão D2) + tela do extrato com 4 formatos (PDF, Excel, CSV, OFX). Desvio deliberado do plano: CSV e PDF seguem client-side porque carregam as colunas Pagador/Recebedor (ordem do dono de 14/07 que o CSV canônico do server não tem); o Excel novo tem as mesmas colunas; o OFX vem do server.
- Item 2: Avisos de Créditos Geral (`CreditNotices` + `GET /v1/reports/accounts/credit-notices[/export]` + tela no Hub com agrupamento diário e subtotais). Fonte `account_entries` com amount > 0 confirmed; pagador do metadata (`payer_*`, fallback `counterparty_name`), nunca inventado.
- Item 3 + parte core do 8: Movimentações Diárias analítico e sintético (`DailyMovements` + rotas + tela). Sintético agrega no SQL (dia x categoria x sinal), com totais de créditos, débitos e saldo líquido ao centavo.
- Item 14: gerente da conta (decisão D3: campo texto `accounts.manager_name`, editável na aba Dados da Conta, chave ausente preserva e string vazia limpa) + relatório Posição de Saldos por Gerente (`BalancesByManager` + rota + tela agrupada com KPIs; bucket "Sem gerente" para NULL).
- Unidade provada em teste em todos os relatórios: 24000 subcentavos viram 240 centavos na borda e R$ 2,40 na tela, nunca 100x.

### Fase 3: SISBAJUD
- B.3: `judicial_orders` ganhou `titular_name` (resolvido no processamento com a mesma fonte do preview: Member por documento, fallback User; réu sem cadastro fica nil) e o processamento normaliza `vara_juizo_codigo` com pad de 5 nos cinco caminhos (BLOCK, CANCEL, UNBLOCK, TRANSFER, NOTIFICATION; herdados do bloqueio referenciado quando for o caso). O detalhe da ordem resolve a vara no catálogo 5305 (`Judicial.resolve_court`, com fallback por `court_code` sem zeros para acervo antigo) e serializa bloco `vara` com campos nulos honestos. Parser 5305 NÃO foi estendido (decisão D5: os campos ricos só entram com o leiaute oficial confirmado; comentário-gate no parser).
- Natureza da ação: `WireEnums.natureza_acao_label/1` data-driven com mapa VAZIO (decisão D4: a tabela oficial não está no repo; completar é insumo do dono/cliente); o serializer emite `%{codigo, label}` com fallback honesto "Código NN (aguardando tabela oficial)".
- B.4: bloco de atendimento editável (`atendimento_changeset` que por construção não toca campos de máquina; justificativa obrigatória em cumprida_parcialmente e nao_cumprida) + `PATCH /sisbajud/orders/:id/atendimento` com ator REAL do token (nunca do body) e linha de auditoria (action UPDATE + resource_type `sisbajud_atendimento`, before/after; o whitelist do `AuditLog.validate_action` não aceita ação livre, desvio registrado).
- Tela SISBAJUD: coluna Titular na lista, detalhe com Nome do titular, Natureza decodificada, seção Vara/Juízo e seção "4. Atendimento da Ordem" (Select de situação, data e hora, justificativa com obrigatoriedade client-side, observações, Salvar com toast e responsável exibido).

### Fase 4: AMES
- Fundação: tabela `ames_requests` (demanda, código STA por demanda conforme decisão D6, prazo, descrição, status aberta/respondida/enviada/aceita/rejeitada), report_type `AMES` no `regulatory_files`, e `StaDelivery.route_for_file/1` (AMES usa `sta_system_id` do metadata; sem ele recusa com `:missing_sta_system_id`, nunca cai no catch-all PGEN001).
- SONDA G1 EXECUTADA (obrigatória da T19): CloudWatch Insights em `/ecs/monetarie/homolog/sta-api`, janela de 30 dias, 242.034 registros varridos, ZERO ocorrências de "regulatory upload". A via NATS `monetarie.sta.regulatory.upload` NÃO tem prova de vida em HML. Seguindo a instrução do plano, o `Ames.deliver/2` usa a VIA HTTP do CCS (`Monetarie.Sta.Client.upload_file`, caminho com aceite BACEN provado em PRD 16/07), com `system_id = sta_file_code` e nome do arquivo SEMPRE prefixado pelo código (a cabine deriva o tipo do nome pelo regex `AMES\d{3}`).
- Use case `Regulatory.Ames` (criar, anexar resposta simples base64 ou SIMBA via gerador real, enviar, `refresh_status` espelhando o `regulatory_file` e com polling HTTP quando o webhook não chegou, reenvio a partir de rejeitada), controller com 6 endpoints em `/api/v1/regulatory/ames` (RBAC `compliance.cadoc`) e tela AMES (cards por status, tabela, diálogos Nova Solicitação e Responder, Enviar via STA, mensagem de rejeição, Reenviar) com item de menu na seção Regulatório (5 locales).

## Revisão adversarial da frente (Task 22, revisor fresh)

- 1 achado CRITICAL, CORRIGIDO no commit `e9066862`: `Monetarie.Sta.Client.Http.callback_url/1` só tinha cláusulas CADOC/CCS; qualquer `AMESnnn` caía no raise do catch-all e o envio AMES explodiria com 500 em todo ambiente real (invisível à suíte porque o Mock nunca passa pelo Http). Fix: AMES sobe SEM `callback_url` (opcional na cabine, files_controller v1) e o desfecho vem pelo polling do `Ames.refresh_status`; system_id realmente desconhecido segue falhando alto. Teste novo exercita o `Http.upload_file/4` com system_id AMES.
- Nota do revisor incorporada como característica documentada: AMES NÃO tem rota de webhook própria no Core (`/api/internal/ames/sta-callback` não existe; só cadoc e ccs). O acompanhamento é por polling no read, por design da Task 19. Se o dono quiser webhook dedicado, é follow-up separado.
- Todo o resto verificado limpo pelo revisor: unidades monetárias nos 4 relatórios (subcentavos para centavos, sem 100x), fail-soft dos ganchos de e-mail CCS, PATCH de atendimento sem tocar campos de máquina e com ator só do token, pad de vara sem corromper códigos, base64 do AMES sem dupla codificação, rotas sem colisão com catch-all, RBAC completo nas ações novas, migrations aditivas e idempotentes.

## Suítes (fecho da frente)

- Backend completo: `mix test` = 7931 testes, 1 falha PRÉ-EXISTENTE (`OutboxAtomicityTest` do TedController, pin de forma de código da sessão paralela de TED de 17/07, arquivo intocado pela F3 — diff vazio provado; a falha reproduz no mesmo estado base). Zero regressão nova da frente.
- Admin completo: vitest = 60 arquivos, 400/400. Builds `@monetarie/shared` e `@monetarie/admin` verdes (vue-tsc + vite).

## Nota de deploy (orquestrador)

- Migrations novas (aditivas, idempotentes, aplicar via `bin/monetarie rpc`, HML antes de PRD; sem backfill, `judicial_orders` está vazia em HML e PRD):
  - `20260718150000_add_manager_name_to_accounts`
  - `20260718151000_add_titular_atendimento_to_judicial_orders`
  - `20260718152000_create_ames_requests`
- Envs novas (todas nascem AUSENTES; sem elas o adapter de e-mail é Logger e nada quebra; ligar = decisão D1 do dono): `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD` (Secrets Manager), `EMAIL_FROM`, `CCS_NOTIFICATION_EMAILS`, `CCS_DIGEST_ALWAYS`.
- Cron novo: `CcsDailyDigestWorker` `30 12 * * *` (config.exs e runtime.exs em paridade). Sem queue Oban nova (usa `:regulatory`).
- Sem mudança nas cabines (a STA já reconhece o prefixo AMES no nome). Deploy core-api único, sem acoplamento pix/spb. Deploy dos frontends: core-admin-ui.

## Decisões D1 a D7 (default aplicado; pendências do dono)

- D1 (transporte de e-mail): fiação completa entregue com fail-safe Logger; SMTP vs SES pendente do dono; envs listadas acima.
- D2 (OFX): mantido 1.0.2 SGML.
- D3 (gerente): campo texto por conta, marcado `DECISAO D3 pendente` no commit; migra fácil para cadastro estruturado.
- D4 (natureza da ação): mapa nasce VAZIO com fallback honesto; completar com o manual SISBAJUD é insumo do dono/cliente (`wire_enums.ex`, marcado `DECISAO D4 pendente`).
- D5 (leiaute 5305): parser segue código+nome; campos ricos gateados por comentário no parser.
- D6 (código AMES): operador informa por demanda, default AMES001 no formulário; validar quando chegar a primeira demanda real.
- D7 (grade nominal de e-mails do AutBank): coberta por EVENTOS reais + digest 09:30 BRT; espelhar a grade nominal ficou fora deste plano.

## O que fica para a janela do orquestrador

- T23 completa (validação viva em HML tela a tela com screenshots, roteiro no plano, incluindo a remessa SISBAJUD de teste, a solicitação AMES real contra a cabine STA de HML e a conferência ao centavo dos relatórios contra rpc read-only).
- Merge na main + deploy (migrations e envs acima) + validação pós-deploy.
- Follow-up herdado do plano: unificação do gerador OFX redundante do `coreproviders_parity_controller.ex` (não tocado, por instrução da Task 5).
