# Design — Saldo em aberto de emprestimos no card do cliente

> Data: **2026-07-14**. Branch: `feat/loan-product-required-cosif-accounts`.
> Status: **aprovado no brainstorming**. Area: credito (`SimulationDialog` card + `/cooperative/members/:id`
> serializer + `Loans` context). Extensao do card de cliente (contas/saldo/risco).

## Problema

O card do cliente na criacao de emprestimo mostra o saldo em CONTA, mas nao o **saldo em aberto de
emprestimos** do cliente. O operador precisa ver quanto o cliente ainda deve em contratos abertos.

## Decisao (dono)
- **"Em aberto"** = `status ∈ [active, disbursed, overdue, defaulted]` (a MESMA regra de
  `open_for_renegotiation`, loans.ex:941).
- **Baixados (`written_off`) NAO entram.** **Prejuizo ENTRA** — confirmado no codigo: prejuizo e o loan
  >360d em atraso ainda no balanco (status `defaulted`/`active` aguardando write-off), nao um status
  proprio; `written_off` = baixa contabil. Logo o set acima ja inclui prejuizo e exclui baixados.

## Comportamento
- Somar `outstanding_balance` (centavos) dos emprestimos do cliente com status no set acima. Zero se nao ha.

## Backend
- `Loans.member_open_loans_balance/1` — `sum(outstanding_balance)` WHERE `member_id == ^id AND status IN
  [active, disbursed, overdue, defaulted]`; retorna integer centavos (0 se nil).
- `members_controller.show`: busca via `Loans.member_open_loans_balance(id)` e passa pro serializer.
- `serialize_member_full`: adiciona **`open_loans_balance`** (centavos).

## Frontend (`SimulationDialog.vue`)
- No card, uma linha **"Saldo em aberto (emprestimos): R$ X"** (perto do saldo em conta / risco), via
  `formatBRLLocal(foundMember.open_loans_balance)`. Mostra R$ 0,00 se nao houver.

## Testes
- **Backend:** `member_open_loans_balance` soma so os status abertos (inclui defaulted; exclui written_off
  e settled). Validacao viva via rpc (soma real de um cliente com emprestimo).
- **Front:** type-check.

## Fora de escopo (YAGNI)
- Detalhar contrato a contrato (so o total agregado).
- Incluir `written_off` (baixados) — excluidos por decisao do dono.

## Arquivos afetados
| Arquivo | Mudanca |
|---|---|
| `loans.ex` | `member_open_loans_balance/1` (soma outstanding dos abertos) |
| `members_controller.ex` | `show` + `serialize_member_full`: `open_loans_balance` |
| `SimulationDialog.vue` | linha "Saldo em aberto (emprestimos)" no card |
