# Legado PIX (CRK/Corner) — Alçada, Contábil, Conciliação, Saldos, Expurgo, Tarefas

Mapa extraído do decompilado em `/Users/luizpenha/monetarie/.scratch/legado-pix-decompiled/` e dos schemas SQL Server dos backups (`crk_spi`, `CRK_SPICONTABIL`, `CRK_SPIDOMINIO`, `crksecurityadminBKP`). Foco: extrair as regras para confronto com a nossa cabine (ênfase em alçada e contábil).

Convenção de unidade importante: no legado PIX o valor de alçada, limite acumulado, contábil e reserva é em **REAIS decimais** (`numeric(18,2)`, `decimal`), não em centavos/subcentavos. `Payment.Vlr` é reais. A nossa cabine trabalha em base_units/centavos — atenção ao confrontar.

---

## 1. ALÇADA (o coração do gate de aprovação do money-path)

### 1.1 Modelo de dados

Config: `crk_spi.dbo.SpiCadParamAlcada` -> `ParametroAlcada`/`ParametroAlcada2` (`SPI.Core.Domain.decompiled.cs:484,587`):

| Campo | Significado |
|---|---|
| `IdAlcada`, `IdInstFinanc`, `NmAlcada` | identidade da alçada, por instituição financeira |
| `Periodo` (`enumPeriodoVerificacao`) | `Diariamente=1`, `DiasUteis=2`, `DiasNaoUteis=3` |
| `NrQtdeVistos` | quantos vistos (aprovações) são necessários para liberar. **0 = auto-rejeita** quando estoura limite |
| `UsuariosAlcada` / `GruposAlcada` / `SistemasAlcada` | ESCOPO: a quem/qual sistema a alçada se aplica (listas de ids serializadas como `[id]`) |
| `UsuariosAprovadores` / `GruposAprovadores` | quem pode dar o visto (aprovar/rejeitar) |
| `VlrMinimo`, `VlrMaximo` | faixa de valor da operação que dispara a alçada |
| `VlrAcumulado` (coluna `VlrDiario`) | teto acumulado diário por cliente/conta |
| `HrInicioVerificacao`, `HrFimVerificacao` | janela de horário (suporta janela overnight quando início > fim) |
| `Ativa` | liga/desliga |
| `EstendeLimites` | estende a janela/regras para dias não úteis/feriados e madrugada da janela overnight |
| `JsonMsgs` / `Mensagens` (`List<MensagemAlcada>`) | por CdMsg, com `Regras` = `List<PropriedadeFiltro>` (filtro por campo da mensagem) |

`MensagemAlcada` (`SPI.Core.General:14416`): `{ CdMsg, Regras: List<PropriedadeFiltro> }`.
`PropriedadeFiltro` (`:13521`): `{ Id (caminho do campo, ex "PaymentData.FinalidadeTransacao"), Operador (enumOperadorSql), Filtro: List<string> }`.
`enumOperadorSql` (`:7679`): `Igual, Diferente, Maior, MaiorOuIgual, Menor, MenorOuIgual, In, NotIn`.

Runtime das ordens:
- `SpiRegAlcada` -> `RegistroAlcada` (`:1033`): `{ IdRegistroAlcada, IdOperacao, IdAlcada, DtHrEntrada, DtHrFinal?, DtBase?, ValorLimite, Status (enumStatusAlcada), NrQtdeVistos, Alcadas[], Vistos[] }`.
- `SpiRegVistoAlcada` -> `VistoAlcada` (`:1210`): `{ IdRegistroAlcada, IdUsuario, DtHrVisto, Status, DsVisto (justificativa) }`.
- `SpiRegLimitesOperacao` -> `RegistroLimiteOperacao` (`:1057`): acumulado diário por `DtBase + Cliente(CPF/CNPJ) + ISPB + Agencia + Conta + IdAlcada`; coluna computada `ValorDisponivel = ValorLimite + TotalCredito - TotalDebito`.
- `enumStatusAlcada` (`:8477`): `Pendente=37, Rejeitada=38, Aprovada=39`.

### 1.2 Motor de avaliação (na ENTRADA da mensagem, antes de enviar ao BACEN)

`ValidacaoAlcadaUseCase.ValidaAlcada(MessageFull)` — `SPI.Core.Worker.FilaEntrada.Application.decompiled.cs:72`:

1. Se `msg.Sentido == Retorno` -> não há alçada (só operações de IDA/envio passam pela alçada).
2. `GetAlcadaAplicavelParaOperacao(msg)` seleciona a alçada aplicável (ver 1.3). Se nenhuma -> retorna null (segue sem alçada).
3. Se há valor de pagamento (`Payment.Vlr > 0`):
   - `ConsistirValorAcumulado` -> `(acumuladoOk, DtBase)`.
   - `dentroFaixa = Vlr <= VlrMaximo && Vlr >= VlrMinimo`.
   - Se `dentroFaixa && acumuladoOk` -> **Aprovada** (status operação `Aprovada`).
   - Senão, `DetalharMotivo` monta a mensagem (excede máximo / abaixo do mínimo / acumulado diário excedido) e:
     - `NrQtdeVistos == 0` -> **Rejeitada** (`Reprovada`).
     - `NrQtdeVistos > 0` -> **Pendente** (`PendenteAprovacao`).
4. Se não há valor (ex. mensagens sem `Payment`) -> **Pendente de aprovação**.

O `RegistroAlcada` e um `MessageHistory` são gravados junto da operação (`SetRegistroAlcada`, `:151`).

### 1.3 Seleção da alçada aplicável (escopo + horário + regras)

`ValidacaoAlcadaRepository.GetAlcadaAplicavelParaOperacao` — `SPI.Core.Worker.FilaEntrada.Shared.decompiled.cs:99`:

1. Filtra as alçadas por `IdInstFinanc == msg.IdInstFinanc`, `JsonMsgs.Contains(msg.CdMsg)`, `Ativa`.
2. Resolve grupos do usuário (`FindGrupos`) e feriados.
3. Escopo: aplica se (UsuariosAlcada vazio OU contém o usuário) E (GruposAlcada vazio OU intersecta grupos do usuário) E (SistemasAlcada vazio OU contém o sistema) E `ChecaHorario(dataOperacao, ehDiaNaoUtilOuFeriado)`.
4. Resolve por Período: em dia útil prioriza `DiasUteis`+`Diariamente` dentro da janela; fora dela cai em `DiasUteis EstendeLimites`; em dia não útil junta `Diariamente`+`DiasNaoUteis`+`DiasUteis EstendeLimites`+overnight. Janela overnight (`início > fim`) e madrugada de dia útil tratadas em `VerificaJanela`/`EstaEmMadrugadaDeJanelaOvernightDeDiaUtil`.
5. `FiltraRegras`: para cada alçada candidata avalia `RegraAlcadaEvaluator.Atende(regras, msg)` (regras por campo da mensagem). **Desempate: a alçada com MAIS regras (mais específica) vence** (`OrderByDescending Regras.Count`).

`RegraAlcadaEvaluator` (`:301`): resolve o caminho do campo por reflection (`ResolveCaminho`, suporta `a.b.c` e `?`), converte o filtro para o tipo do campo, aplica o operador. Todas as regras precisam passar (AND).

### 1.4 Acumulado diário

`ConsistirValorAcumulado` (`:215`): computa `DtBase` (via `ObtemDataBase`, respeitando janela/feriado/EstendeLimites), busca `RegistroLimiteOperacao` por `DtBase+Cliente+ISPB+Agencia+Conta+IdAlcada` e usa `ValorDisponivel` (ou `VlrAcumulado` se não há registro). Retorna `Vlr <= disponivel`.

### 1.5 Como bloqueia/libera o money-path

- Na gravação da mensagem (`TrataMensagem`/`GravaMensagem` — `FilaEntrada.Infrastructure:7076,7126`): se `RegistroAlcada.Status != Aprovada`, `param.IdStatus = (enumStatusOperacao)Status` (vira `PendenteAprovacao` ou `Reprovada`).
- `Verificar(msg, out bAlgumPendente, out bRejeitado)` (`:6121`): mensagens em `PendenteAprovacao`/`PendenteAprovacaoRestanteLote` NÃO são enviadas ao BACEN (ficam retidas); rejeitadas terminam. Vale para lote também (qualquer perna pendente segura).

### 1.6 Fluxo aprovar/rejeitar (o "visto") — `ManAlcada`

`TratamentoAlcadaUseCase.ManAlcada(ParamAcaoAlcada, idUsuario, status)` — `SPI.Core.Angular.Infrastructure.decompiled.cs:3476`. Regras (todas fail-closed):

1. Só **aprovadores** (`UsuariosAprovadores`/`GruposAprovadores`) podem operar; senão erro `NaoPermitido`.
2. A alçada tem que estar **Pendente**; senão "já se encontra {status}".
3. **Um usuário só vota uma vez** por operação (não repete visto).
4. **Segregação de função (maker != checker): o usuário que GEROU a operação (`messageFull.IdUsuario`) NÃO pode aprová-la.**
5. Grava `VistoAlcada` com `DsVisto` (justificativa) e timestamp.
6. **Rejeição é terminal imediata** (1 rejeição finaliza). **Aprovação só finaliza quando `Vistos.Count == NrQtdeVistos`** (esquema de N vistos).
7. Ao finalizar, `messageFull.IdStatus = (enumStatusOperacao)Status`; se `Aprovada`, seta `PaymentData.DtHrAcceptance = now` (libera para envio). Grava `MessageHistory` com o ator.

Monitor de alçada: `ITratamentoAlcadaUseCase.Filtro(PagedFiltroMonitorAlcada)`, `AlcadasDaOperacao(idOperacao)` e histórico; DTOs `RegistroGridAlcadaDTO`/`AlcadaOperacaoDTO` (`SPI.Core.Angular.Application:8480+`).

### 1.7 Alerta de alçada (worker dedicado)

`WorkerEnvioAlertaAlcada` (`SPI.Core.Worker.EnvioAlertaAlcada.decompiled.cs`): loop a cada `TempoPausaThreadEnvioAlertaAlcada` ms (default 60s) chamando `IEnvioEmailAlcada.Processamento()` — dispara e-mail aos aprovadores quando há operação pendente de visto. Log em `LogAlertaMsgAlcada` (`:1394`, e-mails enviados/não enviados). O detalhamento do e-mail está em `.EnvioAlertaAlcada.Infrastructure` (34 KB).

---

## 2. AUTH / SEGURANÇA (AdmWeb — banco `crksecurityadminBKP`, compartilhado PIX/SPB)

RBAC baseado em bitmap de permissões (`map_transacoes`/`map_grupos` varbinary) por sistema. Tabelas-chave:

- `spb_tb_cad_usuarios`: `{ id_usuario, ds_login, ds_nome_usuario, fl_ativo, ds_email, map_grupos, map_transacoes (bitmap de funcionalidades), dt_bloqueio_inicio/fim (lockout), nr_logins, ds_login_hash, ds_lang, emp_default/fil_default, tmp_expiracao_token, id_faixa_horario (janela de login), id_usuario_externo }`.
- `spb_tb_cad_usuarios_mfa`: `{ id_usuario, ds_Sec_Sec (segredo TOTP/2FA), ds_Sec_ad, ds_mfa_mod, ds_mfa_seen, nr_logins }` -> **MFA/TOTP por usuário**.
- `spb_tb_cad_usuarios_ad` / `spb_tb_cad_usuarios_siteminder`: integração Active Directory / SSO SiteMinder.
- `spb_tb_cad_usuarios_tokens` / `spb_tb_cad_usuarios_auth_pil`: tokens de sessão.
- `spb_tb_cad_grupo_usuarios`: `{ id_grupo_usuario, ds_grupo_usuario, sg_grupo_usuario, map_transacoes, fl_interno, id_sistema }` (grupos por sistema).
- `spb_tb_cad_usuarios_grupo` / `spb_tb_cad_sistemas_usuarios` / `spb_tb_cad_sistemas_grupos`: vínculos usuário<->grupo<->sistema.
- `spb_tb_cad_funcionalidades` (+ `_sistema`): funcionalidades/telas por módulo; `fl_acesso_mensagem` + `ds_tipo_msg` + `sigla_funcionalidade` -> **RBAC no nível de MENSAGEM** (qual usuário pode operar qual CdMsg).
- `spb_tb_cad_mens_func_grupo`: `{ id_grupo_usuario, id_funcionalidade, cd_msg }` -> permissão de mensagem por grupo.
- `spb_tb_cad_senhas` / `spb_tb_cad_restricoes_senhas`: histórico e política de senhas.
- `spb_tb_log_atividade` / `_mfa` / `_email` / `_rpt`: trilha de auditoria (login, MFA, ações).

Certificados (backend `Adm.Aux` — `Adm.Aux.Application.decompiled.cs`, tabelas `TB_CERTIFICADO_*`, `TB_ORIGEM_AUTORIZADA`, `TB_DESTINO_AUTORIZADO`):
- `CertificadoAutorizado`/`CertificadoArquivo`: certificados X509 **autorizados a receber** (trust de origem — mTLS de entrada).
- `CertificadoEnvio`: certificado (.pfx com senha) **para assinar/enviar** (mTLS de saída), armazenado base64.
- `OrigemAutorizada` / `DestinoAutorizado`: whitelist de origens/destinos por host.
`CRK40.Security.Core.decompiled.cs`: cripto de string de acesso/licença (`MontaStrAcesso`, `ChecarAcessoCRK`), não é o RBAC.

---

## 3. CONTÁBIL / COSIF (banco `CRK_SPICONTABIL`)

**O legado PIX NÃO faz partida dobrada por operação num ledger interno.** É uma camada de CONFIGURAÇÃO + um MONITOR que agrega as operações liquidadas do dia e gera um ARQUIVO de exportação (posicional) para o sistema contábil externo importar. É um espelho regulatório batch/diário, D contra C sumarizado por evento.

### 3.1 Schema de configuração (`CRK_SPICONTABIL`)

- `PlanoConta`: `{ IdConta, IdInstFinanc, CdConta (conta COSIF), DsConta, FlAtivo, FlCentroCusto }` — plano de contas por IF.
- `CentroCusto`: `{ IdCentroCusto, IdInstFinanc, CdCentoCusto, DsCentroCusto, FlAtivo }`.
- `HistPadrao`: `{ IdHist, CdHist, DsHist, FlAtivo }` — histórico padrão do lançamento.
- `EventoContabil`: `{ IdEvento, IdInstFinanc, CdEvento, IdHist, IdContaDebito1, IdContaDebito2, IdContaCredito1, IdContaCredito2, IdCentroCusto{Debito1,Debito2,Credito1,Credito2}, FlAtivo }` — **evento contábil com até 2 contas de débito e 2 de crédito, cada uma com centro de custo, e um histórico**.
- `EventoMensagem`: `{ IdEventoMsg, CdMsg, IdEvento }` — **qual mensagem PIX dispara qual evento contábil**.
- `EventoMensagemTag`: `{ IdEventoMsgTag, IdEventoMsg, NmTag, VlTag }` — condições no nível de TAG/campo da mensagem (ex. FinalidadeTransacao, DebitoCredito).

### 3.2 Geração dos lançamentos — Monitor Contábil

`MonitorContabilUseCase.ObtemLancamentos` — `SPI.Core.Contabil.Application.decompiled.cs:715`:

1. Lê operações **liquidadas** (`msg.IdStatus == 9`) do dia (`DtMovto`, `IdInstFinanc`), join `MessageFull` + `Payments` -> `MsgPay` (com `FlDebitoCredito` D/C, `Vlr`, tags).
2. Monta as regras a partir de `EventoContabil`+`EventoMensagem`+`EventoMensagemTag`: cada evento gera uma query dinâmica `CdMsg==@0 && NmTag==@1 && ...`, com `Peso = nº de condições` (especificidade).
3. Ordena por `Peso desc, IdEvento`, e para cada evento casa as operações ainda não consumidas, **soma D e C**, `Vlr = |somaC - somaD|`, produz um `Lancamento` (conta débito/crédito 1 e 2, histórico, Qtd, VlrDeb, VlrCred). Remove as operações casadas (cada operação cai em um único evento, o mais específico).
4. Operações não casadas por nenhum evento caem no bucket **"NÃO CONTABILIZADO"** (visibilidade de gap).

### 3.3 Exportação

`DownloadArquivo(id, idEmpresa, idFilial, dtMovimento)` (`:884`): gera arquivo posicional (`id=1` `LayoutCRK`, `id=2` `LayoutCRKDinamico`). Formato: Header `H{yyyyMMdd}...0000001`, linhas `00090{conta:15}{D|C}{valor:17}{histórico}{seq:7}` — partida dobrada por evento, valor 17 dígitos, história e filial. Endpoints REST em `SPI.Web.Contabil.API` (`api/planoconta`, `api/evento`, `api/histpadrao`, `api/centrocusto`, `api/monitorcontabil` com `MonitorListar`+`BaixaArquivo`).

---

## 4. SALDOS (Conta PI x Reserva SPI; banco `crk_spi`)

### 4.1 Tabelas

`SpiSaldo`, `SpiSaldoCAMT` (saldo vindo do BACEN via camt), `SpiSaldoSpb`, `SpiReqSaldo`/`SpiHistReqSaldo`, `SpiCadParamReqSaldo` (valor padrão da requisição por tipo), `SpiCadParamValoresSaldo` (min/max reserva).

### 4.2 Requisição de saldo (crédito/débito/aporte)

`ReqSaldo`/`ReqSaldoDTO` (`SPI.Core.Domain:1082`): `{ IdInstFinanc, Ispb, IspbVinculado, DtMovto, IdTipoMsg (enumMsgSaldo), IdTipoRequisicao (enumTipoMsgSaldo), Vlr, IdStatus, NumCtrlIF, ... }`.
- `enumMsgSaldo` (`SPI.Core.General:7649`): `SolicitacaoCredito=1` (traz recurso da Reserva -> Conta PI), `SolicitacaoDebito=2` (devolve PI -> Reserva), `Aporte=3`, `MetaSaldo=4`.
- `enumTipoMsgSaldo`: `Propria=1, Liquidante=2, SME=3`.
- `enumTipoValor`: `MinimoReservaSPI=1, MaximoReservaSPI=2` (thresholds que disparam crédito/débito automático para manter o saldo PI entre min e max).

### 4.3 Atualização de saldo

`AtualizacaoSaldoRepository` (`SPI.Core.Saldo.Infrastructure:226`) chama stored procs:
- `SPI_SPUPDSLDSPI @IdInstFinanc,@DtMovto,@DtContabil,@Vlr,@fldc,@flconf` (atualiza saldo; `fldc`=débito/crédito, `flconf`=confirmado).
- `SPI_SPUPDSLDSPI2 @TAB` (TVP `REGSALDO` em lote).
- `SPI_SPREFRESHSLDSPI @IdInstFinanc,@DtMovto` (recalcula).
A entrada é enfileirada (`IntegracaoSaldoParaProcessamentoUseCase` publica na fila de saldo por MQ; worker `EnvioMsgsAutomaticas`/saldo processa).

### 4.4 Ponte com a Reserva (SPB)

`ReqPagtoUseCase` (`SPI.Core.SPB.Application:182`): pega `ReqSaldo` pendentes (`ObtemPendentesEnvio`) e **integra com o sistema SPB (TOPAZ ou JD legado)** via `TIPOINTEGRACAOSPB`/`JD_URL`/`JD_USUARIO` etc. Ou seja, o PIX legado **não emite STR de reserva direto ao BACEN**; ele pede ao SPB para movimentar a Conta Reserva. `TratamentoRetornoR1E` trata o retorno R1/E.

### 4.5 CAMT de saldo / remuneração

`AutomacaoCAMT060` (ver 7) gera a consulta de saldo/movimento; o retorno popula `SpiSaldoCAMT`. Dashboard de saldos (`SPI.Web.Angular.Saldos.Api`): `montaDashboard`, `filtroOvernight`, `saldoTituloGarantia`, `ParamValoresPadraoSaldo` (min/max reserva), `ParamReqSaldo` (valor padrão da requisição). Remuneração da Conta PI não aparece como módulo próprio no PIX legado (é tratada no SPB/tesouraria).

---

## 5. CONCILIAÇÃO (CAMT.052/060 vs PACS.008/004; BACEN é a verdade)

`ConciliacaoUseCase` — `SPI.Core.Angular.Application.decompiled.cs:2455+`. Worker `WorkerConciliacao` roda D0 (dia corrente 00:00–23:59), loop ~60s (`SPI.Core.Worker.Conciliacao.decompiled.cs:137`), também acionável manual.

Fluxo `ExecutaVerificacaoArquivoInternal` (`:2549`):
1. Checa janela de horário; grava `ConciliacaoStatus` (por `ISPB + DtReferencia + manual`), com **guarda anti-concorrência** (`IniciaProcessamento` recusa se já executando; máquina de estados `enumConciliacaoStatus`: Iniciando, Processando, AguardandoDownload, ProcessandoDiferencas, Finalizado, Error).
2. Se não há arquivo, **gera CAMT.060** (consulta de movimento) e entra em `AguardandoDownload` (polling pelo arquivo de resposta).
3. Ao ter o arquivo, `PagedConciliacaoList` (`:2760`):
   - Carrega operações SPI do período (só `PACS.008` e `PACS.004`).
   - Carrega `MessageIDs` permitidos do CAMT.060 e os movimentos do **CAMT.052** (ordenados por EndToEndId).
   - `ExecutarConciliacaoPrincipal` (PACS.008) e `ExecutarConciliacaoDevolucao` (PACS.004) casando por EndToEndId.
   - `SincronizarOperacoesComDiferencas`: **atualiza o status das operações SPI para bater com o BACEN e INSERE no SPI as operações que existem no CAMT.052 mas não localmente** (`OperacoesCriadasSPI`) — o CAMT.052 do BACEN é a fonte de verdade; o SPI é corrigido para refletir.
   - Persiste (`AtualizaOperacao`, `InsereOperacao`) e loga diferenças.
`ConciliacaoStatus` (`SPI.Core.Domain:193`): `{ IdConciliacaoStatus, Ispb, DtReferencia, StatusAtual, MessageId, UltimaInicio/Fim, UltimoErro, AguardandoArquivo, ConciliacaoManual }`. Repo em `SPI.Core.Angular.Infrastructure:3578`.

---

## 6. EXPURGO (retenção = MOVE para base histórica)

`ExpurgoUseCase` — `SPI.Core.Worker.Expurgo.Application.decompiled.cs:30`. Parâmetro `ParametroExpurgo` (JSON no parâmetro de sistema): `{ Ativa, HoraInicio, HoraFim (janela de execução), QtdDiasManter }`. `dataCorte = hoje - QtdDiasManter`.

Não é DELETE puro: `PixRepository.LimparDadosSPI` (`Expurgo.Infrastructure:498`) **MOVE** operações com `DtMovto <= dataCorte` do banco operacional (`crk_spi`) para o histórico (`CRK_SPIHIST`) em lotes de 100: `BulkInsert` no HistContext (MessageFull, Payment, MessageHistory, MessageXMessageId, MessageXSystem, **RegistroAlcada + AlcadaParaOperacao + VistoAlcada** — a trilha de alçada é preservada) e depois `DELETE FROM SpiMessage WHERE IdOperacao IN (...)` no operacional, em transação.
Métodos irmãos: `ExecutaExpurgoLog` (`LimparDadosLog` -> CRK_SPILOG), `ExecutaExpurgoMensagem` (`LimparDadosMensagem` -> CRK_SPIMENSAGERIA), e limpeza de filas MQ/Rabbit (`IBMMQRepository`/`RabbitMQRepository`). Tudo respeitando a janela `HoraInicio..HoraFim`.

---

## 7. TAREFAS AUTOMÁTICAS e DOWNLOAD AUTOMÁTICO

### 7.1 Worker TarefasAutomaticas (`SPI.Core.Worker.TarefasAutomaticas`)

Hospeda vários BackgroundServices (`.decompiled.cs:104+`): `WorkerEnvioAlerta`, `WorkerEnvioAlertaAlcada`, `WorkerEnvioAlertaReprocessamento`, `WorkerDownloadAutomatico`, `WorkerEnvioAutomacaoMensagem`, `WorkerEnvioConsultaOperacao`.

Automação de mensagens: `ParametroAutomacaoMensagem` (tabela `SpiCadParamAutomacaoMsg`): `{ CdMsg, DataDe/DataAte, HoraDe/HoraAte, TipoConsulta, Periodicidade (time), IdInstFinanc, UltimaExecucao, CanalSecundario, IdAutomacao }`. `enumTipoAutomacao` (`SPI.Core.General:8458`): **`AutomacaoPIBR001=1` (echo/heartbeat PIBR.001)** e **`AutomacaoCAMT060=2` (consulta de saldo/movimento camt.060)**. Log em `SpiLogAutomacaoMsg` (`LogAutomacaoMsg`: IdInstFinanc, IdAutomacao, DtHrExecucao, HrRefExecucao). `WorkerEnvioConsultaOperacao` = consulta automática de status de operações pendentes ao BACEN.

### 7.2 Worker DownloadAutomatico (`SPI.Core.Worker.DownloadAutomatico`)

`DownloadAutomaticoUseCase.ExecutaVerificacaoEDownload` (`.Application.decompiled.cs:114`) roda 3 downloads diários (>24h, parametrizados por JSON `ParametroDownload{ URL, Ativa, UltimoDownload }`):
- `DownloadCertificado` (`DownloadCertificados`): cadeia/CRL ICP-Brasil, grava em arquivo.
- `DownloadParticipante` (`DownloadParticipantes`, só após 06:00): diretório de participantes SPI; URL com `AAAAMMDD`; campo 5 `DRCT`=Direto senão Indireto; faz upsert em `SpiParticipante` (nome, tipo, status ativo).
- `DownloadBanco` (`DownloadBancos`): diretório de bancos/COMPE, upsert em `SpiBanco`.

---

## 8. O que conferir de PARIDADE com a nossa cabine (ênfase alçada e contábil)

### Alçada (prioridade máxima — nossa cabine hoje NÃO tem engine de alçada equivalente)
1. **Existência do gate**: no legado, TODA operação de IDA com valor passa por `ValidaAlcada` ANTES de enviar ao BACEN, e fica RETIDA em `PendenteAprovacao` até os N vistos. Conferir se a nossa cabine tem retenção equivalente (ou se manda direto).
2. **Modelo por faixa+acumulado+janela+escopo+regra de campo**: `VlrMinimo/VlrMaximo` + `VlrAcumulado` diário por cliente/conta + janela de horário (com overnight/feriado e `EstendeLimites`) + escopo usuário/grupo/sistema + regras por campo da mensagem (operadores In/NotIn/>=/etc) + desempate pela alçada mais específica. Cada um é uma dimensão que precisa existir do nosso lado.
3. **N vistos + segregação maker/checker**: aprovação exige `NrQtdeVistos` vistos de aprovadores distintos; o autor da operação NÃO pode aprovar; 1 rejeição é terminal; `NrQtdeVistos==0` auto-rejeita quando estoura. Confirmar que replicamos esses invariantes (nossa cabine tem "alçada"? aprovação por 4-olhos?).
4. **Trilha**: `RegistroAlcada`+`VistoAlcada` com justificativa (`DsVisto`), ator, timestamp; e-mail automático aos aprovadores. Auditoria/idempotência do visto.
5. **Unidade**: legado em REAIS decimais; nossa cabine em centavos/base_units. Qualquer porte de parâmetros exige conversão explícita.

### Contábil / COSIF (segunda prioridade)
6. **Natureza**: legado gera COSIF **agregado diário por evento** (D/C sumarizado) exportado em arquivo posicional, casando operação->evento por `CdMsg`+tags com pesos e bucket "NÃO CONTABILIZADO". Nossa contabilização é journal por operação (Fase 1/2). Confrontar cobertura: garantir que todo `CdMsg`/tag que o legado mapeava tenha evento equivalente e que nada caia em "não contabilizado".
7. **Estrutura do evento**: até 2 contas D + 2 contas C, cada uma com centro de custo, + histórico padrão. Verificar se nosso plano/eventos suportam multi-perna e centro de custo.
8. **Gatilho = liquidada (IdStatus==9)**: o legado só contabiliza operação liquidada. Conferir nosso gatilho e a idempotência/reconciliação (a nossa Reconciliação Contábil PIX é o análogo do bucket "não contabilizado").

### Demais
9. **Saldos/Reserva**: o PIX legado NÃO movimenta a Reserva direto; requisita ao SPB (TOPAZ/JD) via `ReqSaldo` (crédito/débito/aporte) com min/max reserva. Conferir se a nossa cabine PIX faz requisição de saldo à cabine SPB ou emite direto (risco de divergência de responsabilidade).
10. **Conciliação**: legado concilia D0 CAMT.052/060 vs PACS.008/004 por E2E, com BACEN como verdade (corrige e INSERE operações faltantes localmente). Confrontar com a nossa PixReconciliation (escopo PACS.008/004, criação de operações órfãs).
11. **Expurgo**: legado MOVE (não deleta) para base histórica preservando alçada, em janela horária, por `QtdDiasManter`. Verificar nossa política de retenção.
12. **Automações**: só PIBR.001 (echo) e CAMT.060 (saldo) são as automações agendadas; download diário de certificados/participantes/bancos. Confirmar que temos heartbeat/consulta de saldo e sync de diretório equivalentes.
