# Relatório de Bugs (Gabriel Cardoso, 17/07) — Mapeamento completo + plano de atuação

Investigação ampla dos 28 itens do `Relatorio-Bugs-Monetarie.docx` (26 CoreAdmin + 2 STA). Cada item tem endpoint/componente `arquivo:linha`, causa-raiz e correção. As causas de maior severidade foram **provadas empiricamente em PRD** (read-only). Agrupado por CAUSA-RAIZ (não por tela), porque vários bugs distintos compartilham a mesma origem.

> Prints originais extraídos em `scratchpad/bugsdoc/extracted/word/media/image1..16.png`. Nada foi alterado em PRD nesta investigação.

---

## Sumário: 13 causas-raiz, prioridades

| # | Causa-raiz | Itens | Severidade | Custo do fix | Prova |
|---|-----------|-------|-----------|-------------|-------|
| R1 | **Login da integração cabine PIX errado (`admin@monetarie.com.br` vs `admin@monetarie.com`)** | CA-001, CA-002, CA-011 | Alta | 1 env var (sem rebuild) | **PROVADO VIVO** |
| R2 | Conta de liquidação COSIF com saldo negativo (sinal invertido) | CA-026 | Alta | análise contábil + correção de dado/lançamento | **PROVADO VIVO** |
| R3 | Mismatch de contrato backend↔frontend (nome/enum de campo) | CA-007, CA-019, CA-020 | Média | fix pontual no front | **PROVADO** (código + dado) |
| R4 | i18n de enums não traduzidos | CA-004, CA-008, CA-015 (+CA-005) | Baixa | helper único de tradução | mapeado |
| R5 | Exportação PDF quebrada (jspdf-autotable v5 não registra no protótipo) | CA-018, CA-021 | Média | 1 correção em ponto único | mapeado |
| R6 | `entity_id` nulo nos transactions vs filtro por entity da sessão | CA-003 | Média | ajuste de query | **PROVADO VIVO** |
| R7 | Grid de 5 cards de resumo quebra linha (auto-fit minmax 220px) | CA-017, CA-022 | Baixa | 1 CSS compartilhado | mapeado |
| R8 | Navegação/paginação (DataTable sem `:first`; rota sem param) | CA-023, CA-024 | Média/Baixa | fixes independentes | mapeado |
| R9 | Reconciliação Contábil PIX — `duplicate_e2e` incompleto | CA-009, CA-010 | Média/Baixa | completar serializer + coluna | mapeado |
| R10 | UX empty state / filtro default | CA-006, CA-013, CA-014 | Baixa | ajustes de UI (+1 decisão de produto) | mapeado |
| R11 | Rótulos/cosmético | CA-005, CA-012, CA-016 | Baixa | labels + cores | mapeado |
| R12 | Limpeza de menu | CA-025 | Baixa | remover/gatear item | mapeado |
| R13 | STA — gestão de usuários e "Meu perfil" ausentes | STA-001, STA-002 | Média | feature (controller + telas) | mapeado |

**Ordem sugerida de execução:** R1 (imediato, resolve 3 bugs com 1 env) → R6, R3, R5 (correções pontuais de alto valor) → R2 (precisa do contador/decisão) → R4, R7, R8, R9 (lote de UI) → R10, R11, R12 (acabamento) → R13 (feature, sessão própria).

---

## R1 — Login da integração cabine PIX errado ⭐ PROVADO VIVO EM PRD

**Impacto:** CA-001 (Disponível Agora: Indisponível — Alta), CA-002 (gráfico histórico vazio — Média), CA-011 (401 na reconciliação de tesouraria — Alta).

**Prova empírica (PRD, 17/07):** testei o login na cabine PIX de PRD (`http://pixadmin.monetarie.internal/api/v1/auth/login`) com a senha real do secret:
- `admin@monetarie.com` → **HTTP 200** (success, mfa_required false)
- `admin@monetarie.com.br` → **HTTP 401** (authentication_failed)

A task-def `monetarie-core-api-prod:64` está com `PIX_CABIN_ADMIN_LOGIN = admin@monetarie.com.br`, mas o admin real da cabine PIX de PRD é `admin@monetarie.com` (sem `.br`; o `.com.br` é de HML). Um único caractere derruba toda a leitura de saldo da cabine.

**Cadeia no código:** `core/backend/lib/monetarie/services/pix_providers/in_house/cabin_status_lookup.ex` — `api_config/0` lê `PIX_CABIN_ADMIN_LOGIN`/`PIX_CABIN_ADMIN_PASSWORD`; `auth_headers/1` faz `POST /api/v1/auth/login` e retorna `{:error, {:auth_failed, 401}}`. `CabinTreasury.settlement_balance/0` (`.../in_house/cabin_treasury.ex:72`, `GET /api/v1/balance` + param `ispb` de `INSTITUTION_ISPB`) e `CabinReconciliation` (`use_cases/treasury/cabin_reconciliation.ex`) gravam snapshot `unavailable` em `treasury_reconciliation_snapshots` a cada tentativa (`cabin_balance_subcent = nil`). Daí "Indisponível / source: unavailable" (CA-001), snapshots sem valor → gráfico vazio (CA-002), e "autenticação na cabine PIX falhou (HTTP 401)" (CA-011, `humanize_error({:auth_failed, 401})` em `cabin_reconciliation.ex:545`).

**Correção:** trocar `PIX_CABIN_ADMIN_LOGIN` para `admin@monetarie.com` na task-def do core PRD (registrar nova revisão, sem rebuild). Conferir também HML (lá o `.com.br` provavelmente está certo). **Validação pós-fix:** clicar "Reconciliar agora" e confirmar que o card mostra o saldo real da Conta PI e o gráfico plota. Nota: a mensagem "Cabine PIX indisponível" deveria distinguir 401 de indisponibilidade (melhoria de texto, CA-011 sugestão 2).

**Follow-up estrutural:** a credencial da cabine deveria vir de secret coerente por ambiente, e o login não deveria ficar hardcoded numa string de env divergente de HML/PRD. Considerar validar no boot que o login autentica (fail-fast visível), em vez de degradar em silêncio para `unavailable`.

---

## R2 — Conta de liquidação COSIF negativa ⭐ PROVADO VIVO

**Impacto:** CA-026 (Dashboard "Tesouraria & Liquidez": DISPONIBILIDADES = **-R$ 253.845.344,62** — Alta).

**Prova empírica (PRD, balancete de 2026-07-17):** o grupo COSIF `1.1.%` tem **uma única** conta: `1.1.2.10.01.10.001 "Conta de liquidação / banco liquidante" = -25.384.534.462 centavos = -R$ 253.845.344,62`. Não é bug de agregação (não há bug 100x aqui): o dado COSIF está com **sinal invertido** — uma conta de disponibilidade (ativo, devedora) nunca deveria estar credora/negativa.

**Cadeia:** `core/backend/lib/monetarie/dashboard/aggregator.ex:section_tesouraria/0` (1040-1095) faz `disponibilidades = sum(balance_sheet)` das contas `code LIKE '1.1.%'` de `cosif_account_balances` na `latest_cosif_reference_date()`. O front (`TesourariaSection.vue`) divide por 100. Liquidez imediata = Disponibilidades/Passivo → zerada em cascata.

**Investigação necessária (não resolver às cegas):** o COSIF é a 3ª perna (espelho regulatório, não afeta TB/dinheiro real). Precisa entender por que a Conta de Liquidação acumula credora: o lançamento COSIF do PIX (débito/crédito na conta de liquidação por operação) está com D/C trocado, ou a natureza/registro da conta `1.1.2.10.01.10.001` está definido como credora. Vale confrontar com o contador (mandato pendente do balancete oficial). **Não é bloqueante de money-path**, mas o card do Dashboard mostra número absurdo — risco de decisão errada. Correção provável: acertar a convenção de sinal do lançamento da conta de liquidação (ou a natureza da folha COSIF). Item conexo do histórico: contabilização PIX Fase 1/2.

---

## R3 — Mismatch de contrato backend↔frontend

Tema recorrente: o backend emite uma chave/enum e o frontend lê outra.

- **CA-019** (card "CONTAS COM SALDO" = "undefined" — Média): front lê `k.accounts_with_balance_count` (`core/apps/admin/src/views/reports/accounts/CheckingDailyBalanceReportView.vue:44`), backend emite `members_with_balance_count` (`core/backend/lib/monetarie/use_cases/reports/accounts_balance.ex:99-103`). `String(undefined)` = `"undefined"`. Fix: front ler `members_with_balance_count` (ou back também emitir `accounts_with_balance_count`). O tipo TS em `useAccountsReports.ts:29` também está errado.
- **CA-020** (coluna "Código de Conta" = "-" em todas as linhas — Média): coluna lê `account_number` (`CheckingDailyBalanceReportView.vue:51`), backend entrega o número sob `member_number` (`accounts_balance.ex:84`, que recebe `row.account_number`). Fix: coluna ler `member_number`.
- **CA-007** (Gerar detalhe fica "Aguardando" para sempre — Média): **PROVADO VIVO** — os pedidos da conta 35 em PRD estão `status: "ready", row_count: 0, finished_at` preenchido (o worker rodou e completou; a fila `fee_exports` está ativa, limit 2). O problema é o FRONT: `RelatorioTaxasView.vue` trata como terminal só `done`/`failed` (`refreshStatuses:182`, `schedulePollIfNeeded:164`) e `statusLabel`/`statusSeverity` (219-230) não têm `ready` — o backend emite `pending→processing→ready|failed`, o front espera `...→done|failed`. O `ready` cai no limbo, o link de download (gate `status === 'done'`) nunca aparece. Fix: alinhar o enum (`ready` ≡ `done`) no front, ou o backend emitir `done`. A sugestão do cliente (validar período sem taxas antes de enfileirar, ou "Concluído — 0 linhas") vira UX bônus — o backend já faz o "0 linhas", só falta o front refletir.

---

## R4 — i18n de enums não traduzidos

Não existe helper central; cada tela tem um `Record<string,string>` local com fallback `map[v] ?? v`. Onde o valor cru vaza:
- **CA-004** (status "completed"/"settled" na Liquidação — Baixa): `core/apps/admin/src/views/treasury/SettlementBalanceView.vue:532-534` renderiza `row.status` cru.
- **CA-008** (`duplicate_e2e` na Reconciliação Contábil PIX — Baixa): `PixAccountingReconciliationView.vue:59-65` — `kindLabel` local **não** inclui `duplicate_e2e` (backend emite em `use_cases/cosif/pix_reconciliation.ex:149`). `kindSeverity` (67-72) idem.
- **CA-015** (categoria "deposit"/"transfer" no extrato — Baixa): `ClientStatementReportView.vue:87` — coluna `category` sem `format`.

**Correção recomendada (fecha os três + previne recorrência):** extrair um helper compartilhado `enumLabel(kind, value)` reaproveitando os mapas já existentes (`views/accounts/tabs/AccountExtratoTab.vue:120-134` para categoria; `ReconciliationDashboardView.vue:129` etc. para status) e aplicá-lo nas 3 telas. Adicionar `duplicate_e2e → "E2E duplicado"`.

---

## R5 — Exportação PDF quebrada (ponto único)

**Impacto:** CA-018 (PDF do Relatório de Movimentação CC — Média), CA-021 (PDF do Saldo Diário CC — Média). Recorrente porque o serviço é compartilhado.

**Causa técnica precisa:** `core/apps/admin/src/composables/useReportExport.ts:147` chama `doc.autoTable({...})`. Com `jspdf@4.2.1` + `jspdf-autotable@5.0.7`, o plugin só se anexa a `jsPDF.API.autoTable` se `window.jsPDF` existir no import (`node_modules/jspdf-autotable/dist/jspdf.plugin.autotable.mjs:2071`). No build ESM do Vite, jsPDF não está em `window` → `applyPlugin` nunca roda → `doc.autoTable` é `undefined` → `TypeError`. Como `handleExport` é `async` sem try/catch, a rejeição é engolida e nada baixa (XLSX/CSV funcionam por não dependerem do protótipo).

**Correção:** usar a API funcional da v5 — `import autoTable from 'jspdf-autotable'; autoTable(doc, {...})` (ou `applyPlugin(jsPDF)` explícito no bootstrap). Um único fix em `useReportExport.ts` conserta as duas telas (e qualquer outra que use `ReportExportMenu`). Adicionar try/catch com toast de erro no `handleExport`.

---

## R6 — `entity_id` nulo vs filtro por entity ⭐ PROVADO VIVO

**Impacto:** CA-003 (Consolidado diário (Core) = "Sem consolidado para o período" — Média).

**Prova empírica (PRD):** todos os 55 `transactions` dos últimos 7 dias têm `entity_id = NULL`. O endpoint `POST /api/admin/treasury/settlement-balance/consolidated-statement` (`coreproviders_parity_controller.ex:1667-1708`) faz SQL cru em `transactions` com `WHERE ($4::text::uuid IS NULL OR entity_id = $4)`, onde `$4 = entity_id(conn)` da sessão. Se a sessão admin resolve um entity não-nulo, `entity_id = <uuid>` **nunca** casa (todas as linhas são nil) → zero linhas → mensagem de vazio, mesmo com os movimentos listados logo abaixo (aquele bloco não filtra por entity).

**Correção:** o consolidado não deve excluir linhas com `entity_id` nulo quando o filtro de entity está ativo (ou o admin de tesouraria não deveria filtrar por entity, ou o entity da sessão deveria ser tratado como "todos"). Alinhar com a semântica do bloco "Movimentos no Core" logo abaixo, que mostra os dados corretamente. (Investigar por que os transactions nascem com entity nil é follow-up próprio, mas não bloqueia o fix da tela.)

---

## R7 — Grid de 5 cards quebra linha (ponto único)

**Impacto:** CA-017 (card "Movimentos" — Baixa), CA-022 (card "IOF período" — Baixa).

**Causa:** `core/apps/admin/src/views/reports/components/shared/ReportKpis.vue:49` — `grid-template-columns: repeat(auto-fit, minmax(220px, 1fr))`. Com 5 cards (`ClientStatementReportView.vue:75-81`, `OverdraftConsolidatedReportView.vue:57-61`), o `auto-fit` empacota 4 por linha e o 5º cai. **Correção:** grid responsivo que acomode 5 colunas em telas largas (ex.: `repeat(5, 1fr)` acima de um breakpoint, `auto-fit` abaixo). Um CSS conserta todas as telas com 5 KPIs.

---

## R8 — Navegação e paginação

- **CA-024** (paginação da Gestão de Clientes volta pra página 1 — Média): `core/apps/admin/src/views/clients/ClientsListView.vue` — o `DataTable` (215-231) não tem `:first` (página não-controlada) e está dentro de `v-if="loading" ... v-else`, então **desmonta a cada fetch**; `useClients.ts:126` usa `queryKey: ['admin-clients', filters]` → cada página é query nova → `isLoading=true` → DataTable desmonta → remonta com `first=0` → volta pra pág 1. **Fix:** bindar `:first="(page-1)*perPage"` e não desmontar via `v-if="loading"` (usar `:loading` do próprio DataTable).
- **CA-023** (Extrato da conta do cliente abre busca vazia — Baixa): `ClientAccountsTab.vue:748` navega `router.push({ name: 'AccountStatement', params: { id } })`, mas a rota `AccountStatement` (`router/index.ts:917`) não tem `:id` → param descartado; a tela `StatementView.vue:24` pré-carrega por `query.accountId`. **Fix:** `{ name: 'AccountStatement', query: { accountId: data.id } }` (ou usar a rota paramétrica existente `AccountStatementById`, `router/index.ts:922`).

---

## R9 — Reconciliação Contábil PIX (`duplicate_e2e`)

- **CA-009** (Direção/Esperado/Lançado "-" para `duplicate_e2e` — Média): o tipo tem transação e lançamentos identificados (o Detalhe diz "1 transação e 2 lançamentos"), mas as colunas ficam vazias. Preencher Direção/Esperado/Lançado para esse tipo (ou "N/A" com tooltip). Backend: `use_cases/cosif/pix_reconciliation.ex` (o kind é emitido em :149/:274). Ver que campos o serializer entrega para `duplicate_e2e`.
- **CA-010** (falta coluna Data no grid apesar do filtro por período — Baixa): incluir coluna "Data" (data da transação/lançamento), ordenável. Componente: `PixAccountingReconciliationView.vue`.

---

## R10 — UX empty state e filtro default

- **CA-006** (grid de taxas vazio sem mensagem — Baixa): `RelatorioTaxasView.vue` — adicionar estado vazio ("Nenhuma tarifa cobrada no período").
- **CA-014** (filtro Créditos SPB abre em "Pendentes" — Baixa): `core/apps/admin/src/views/treasury/SpbCreditsView.vue:32` — `statusFilter = ref('suspense_pending')`. Backend não impõe default (`spb_credits_controller.ex:34`: sem status → todos). **Fix:** trocar valor inicial para `null` ("Todos").
- **CA-013** (cabine PIX não aparece em Disponibilidades; consolidado R$0; instrução "selecione um card" sem cards — Média): **decisão de produto.** Por design a cabine PIX **não** é uma `treasury_account` (a tela `treasury_dashboard` lista `treasury_accounts`, tabela vazia → sem cards). Duas frentes: (a) corrigir o empty state (instrução some ou "Nenhuma disponibilidade cadastrada"); (b) **decidir com o dono** se a cabine PIX (Conta PI) deve aparecer aqui como disponibilidade padrão — o que exige puxar o saldo via `CabinTreasury` (depende de R1 resolvido). Sem R1, qualquer leitura da cabine falha.

---

## R11 — Rótulos e cosmético (Baixa)

- **CA-005** (badge "NumCtrlSTR" técnico): trocar por "Nº Controle STR" / padronizar par "PIX (E2E)" e "TED (STR)". Componente da tabela de Movimentos (`SettlementBalanceView.vue`).
- **CA-012** ("SNAPSHOT 100" sem explicação): é o `id` (bigserial) do último `treasury_reconciliation_snapshots` (`cabin_reconciliation.ex:490`). Renomear para "Captura nº 100" + tooltip; padronizar termo "snapshot" nas telas.
- **CA-016** (Débito/Crédito/Saldo sem cores no grid do extrato): aplicar convenção contábil (débito vermelho, crédito verde) no grid, estendendo o padrão que os cards de resumo já usam. `ClientStatementReportView.vue`.

---

## R12 — Limpeza de menu

- **CA-025** (remover "Caixa Institucional" — Baixa): o módulo é stub (money-path dormente; a view mostra a mensagem hardcoded `CaixaInstitucionalView.vue:295` porque não há GET de estado → 404). Remover/gatear o item de menu em `core/apps/admin/src/layouts/AdminLayout.vue:251` (e opcionalmente a rota `router/index.ts:1118`). Reexibir via feature flag se o módulo for ativado.

---

## R13 — STA: gestão de usuários e "Meu perfil"

**Estado atual (o CLAUDE.md do STA está desatualizado — já NÃO é conta única por env):** o STA já tem `users` + auth por DB (bcrypt, roles `super_admin|operator|auditor`), RBAC completo (`groups`/`user_groups`/`features`), login `POST /api/auth/login` por email, `GET /api/auth/me`. Schema: `sta/backend/lib/sta_connector/auth/user.ex`; context `auth.ex`; migration `20260309100000_create_users_and_rbac.exs`; seed `rbac_seed.exs` (admin default + 3 grupos).

**O que falta:**
- **STA-001** (gestão de usuários — Média): não há `users_controller` nem rotas `/api/admin/users` (CRUD + atribuição de grupos). Construir controller + rotas usando o schema/RBAC já existentes, e a tela "Usuários" em pelo menos um dos frontends (`sta/frontend` Vue ou `sta/admin-portal` React — nenhum tem a tela hoje).
- **STA-002** (Meu perfil + troca de senha — Média): não há endpoint de troca de senha do próprio usuário nem edição de perfil. Adicionar `PUT /api/auth/password` (`current_password` + `new_password`, reusando `User.changeset` que já faz o hash) e `PUT /api/auth/profile` (nome), + tela "Meu perfil" no menu do usuário.

Ambos se resolvem juntos por um módulo de gestão de usuários. Alternativa mencionada pelo cliente: SSO corporativo (decisão de arquitetura). **Feature — sessão dedicada.**

---

## Validações empíricas realizadas em PRD (resumo)

| Item | Verificação | Resultado |
|------|-------------|-----------|
| R1 | Login cabine PIX PRD com `.com` vs `.com.br` | `.com` → 200; `.com.br` → 401 (task-def usa `.com.br`) |
| R2 | Grupo COSIF `1.1.%` no balancete 17/07 | 1 conta: Conta de liquidação = -R$ 253.845.344,62 (negativa) |
| R3/CA-007 | `fee_exports` da conta 35 + fila Oban | status `ready`/0 linhas/finished; fila ativa (limit 2) → bug é no front (`ready`≠`done`) |
| R6 | `entity_id` dos transactions (7d) | 55 tx, todos `entity_id = NULL` → filtro por entity zera o consolidado |

---

## Próximos passos

1. **R1 imediato:** trocar `PIX_CABIN_ADMIN_LOGIN` → `admin@monetarie.com` na task-def core PRD (e conferir HML). Validar Liquidação/Reconciliação vivas. Resolve CA-001, CA-002, CA-011 e destrava a decisão de CA-013(b).
2. **Lote de fixes pontuais de front (uma branch, TDD onde couber):** R3 (CA-007/019/020), R5 (PDF), R6 (consolidado), R7 (grid), R8 (nav/paginação), R4 (i18n), R9, R10, R11, R12. Todos são CoreAdmin `core/apps/admin` + poucos toques de backend.
3. **R2:** análise contábil da Conta de Liquidação (sinal COSIF) — envolver contador/dono; conecta ao mandato do balancete oficial.
4. **R13 (STA):** feature de gestão de usuários — sessão dedicada.
