13 KiB
Roteiro de Desenvolvimento — Comparador de Notas
Gerado em: 04/03/2026
Baseado em: PRD v1.7 + análise estática do código atual
1. Warnings do Compilador
São 7 warnings ativos (cargo build). Nenhum é crítico, mas todos devem ser eliminados para manter o código limpo.
W-01 — Nota.data nunca lida
Arquivo: src/domain/entities/nota.rs:17
Causa: O campo data: Option<NaiveDate> é armazenado na struct Nota, mas nenhum código de negócio ou de UI o consome atualmente.
Contexto PRD: O campo Data é definido no modelo de dados (seção 5) como opcional. O PRD diz que é "exibida como informação adicional no relatório PDF. Não participa de nenhuma regra de validação ou cálculo."
Solução: Usar o campo data na geração do PDF (pdf_generator.rs), exibindo a data da nota nas seções de faltantes ou duplicatas quando disponível. Isso resolve o warning e implementa o requisito do PRD.
W-02 — IntervaloSerie.minimo e IntervaloSerie.maximo nunca lidos
Arquivo: src/domain/entities/resultado_analise.rs:23-24
Causa: Os campos minimo: u64 e maximo: u64 existem na struct IntervaloSerie, mas nenhum código os consome após o cálculo.
Contexto PRD: RF04 define que o intervalo de faltantes é avaliado entre o menor e o maior número encontrado. O aviso de confirmação (RF04 — Proteção contra intervalos anormalmente grandes) exibe o intervalo calculado ao usuário.
Solução: Exibir minimo e maximo na mensagem de confirmação em app.rs quando o intervalo exceder 10.000. Exemplo: "Série 001 / NFE: intervalo de 999.996 faltantes detectado (de 1 a 1.000.000)". O PRD especifica exatamente esse formato de aviso.
W-03 — ResultadoAnalise::sem_inconsistencias nunca usada
Arquivo: src/domain/entities/resultado_analise.rs:51
Causa: O método pub fn sem_inconsistencias() está definido mas nunca chamado.
Contexto PRD: Nenhuma funcionalidade específica é mapeada diretamente para este método.
Solução (opção A — remover): Remover o método se não houver uso planejado próximo. É código morto.
Solução (opção B — usar): Usar o método na tela de resultado (resultado.rs) para exibir um badge "Sem inconsistências" ou mensagem de sucesso no topo quando sem_inconsistencias() for true. Melhora a UX e elimina o warning.
W-04 — EstadoModal::Informacao nunca construída
Arquivo: src/ui/app.rs:39
Causa: A variante Informacao { titulo, mensagem } existe no enum EstadoModal mas nenhum código a instancia. Existe Aviso e Erro para as demais situações.
Solução: Remover a variante Informacao do enum se não houver distinção visual planejada entre "Informação" e "Aviso". Alternativamente, usá-la onde hoje se usa Aviso para casos puramente informativos (sem cor amarela de alerta). A variante mais simples é a remoção.
W-05 — Message::CancelarExpansao nunca construída
Arquivo: src/ui/message.rs:76
Causa: A variante CancelarExpansao existe no enum Message e é tratada em update() (muda o estado para ConfigurandoColunas), mas nenhuma tela emite essa mensagem. O cancelamento do intervalo excessivo é feito via Message::ModalCancelado.
Solução: Remover Message::CancelarExpansao do enum. O comportamento de cancelar a expansão já está implementado em Message::ModalCancelado (app.rs:629-636).
W-06 — theme::cabecalho_tabela nunca usada
Arquivo: src/ui/theme.rs:140
Causa: A função de estilo cabecalho_tabela está definida mas nenhuma tela a usa.
Contexto: O componente tabela_preview.rs usa estilo inline para o cabeçalho em vez desta função.
Solução: Aplicar t::cabecalho_tabela no cabeçalho da tabela de preview em tabela_preview.rs, substituindo o estilo inline atual. Isso centraliza o estilo e elimina o warning.
W-07 — theme::badge_sucesso nunca usada
Arquivo: src/ui/theme.rs:149
Causa: A função de estilo badge_sucesso está definida mas nenhuma tela a usa. Os badges de sucesso são aplicados via t::badge_aviso (amarelo) ou texto colorido com t::SUCCESS.
Contexto PRD: A tela de resultado exibe indicador de completude por série. Quando 100% completo (sem faltantes), poderia exibir um badge verde.
Solução (opção A — usar): Exibir badge t::badge_sucesso na tela de resultado quando uma série não tem faltantes, em vez de apenas texto verde. Melhora a distinção visual.
Solução (opção B — remover): Remover se não houver uso planejado.
2. Funcionalidades Faltantes (vs. PRD v1.7)
F-01 — Campo data no PDF (RF07.1)
Status: Não implementado
PRD: Seção 5 e RF07.1 — "Data de emissão da nota. Exibida como informação adicional no relatório PDF."
Situação atual: O campo data é lido do arquivo (csv_reader.rs, xlsx_reader.rs) e armazenado em Nota.data, mas pdf_generator.rs não o utiliza em nenhuma seção.
O que falta: Exibir a data de cada nota nas seções de faltantes e/ou duplicatas do PDF quando disponível. Por exemplo, no detalhamento de duplicatas: "NF 42 / Série 001 — 3 ocorrências (última: 15/01/2025)".
F-02 — Mensagem de confirmação com intervalo exato (RF04)
Status: Parcialmente implementado
PRD: RF04 — "Exibir aviso informando o intervalo calculado (ex: 'Série 001 / NFE: intervalo de 999.996 faltantes detectado')"
Situação atual: O aviso de confirmação em app.rs:930-948 exibe apenas "Série X: intervalo de N faltantes detectado", mas minimo e maximo de IntervaloSerie não são incluídos na mensagem. Os campos existem mas não são usados (W-02 acima).
O que falta: Incluir minimo e maximo na mensagem de confirmação para que o usuário veja o intervalo completo.
F-03 — Limite de tamanho de arquivo 50 MB (RF01.3)
Status: Não implementado
PRD: RF01.3 — "O sistema deve recusar arquivos maiores que 50 MB e exibir mensagem de erro ao usuário."
Situação atual: Nenhuma verificação de tamanho de arquivo existe nos readers (csv_reader.rs, xlsx_reader.rs) nem em processar_arquivo_selecionado (app.rs).
O que falta: Verificar std::fs::metadata(caminho)?.len() antes de processar. Se > 50 MB, retornar ErroArquivo::TamanhoExcedido (o tipo já está definido em domain/errors.rs) e exibir modal de erro.
F-04 — Arquivo XLSX corrompido: limpar estado (RF01.2)
Status: Parcialmente implementado
PRD: RF01.2 — "Se o arquivo não puder ser lido, exibir mensagem de erro em modal e limpar o arquivo carregado; o estado anterior é descartado."
Situação atual: Message::XlsxErroAoCarregar exibe o erro em modal, mas não limpa self.caminho_arquivo nem self.nome_arquivo nem self.preview_arquivo. O estado anterior do arquivo permanece em memória.
O que falta: No handler de Message::XlsxErroAoCarregar, zerar self.caminho_arquivo = None, self.nome_arquivo = String::new(), self.preview_arquivo = None e self.notas_importadas.clear() antes de exibir o erro.
F-05 — Relatório de linhas malformadas ao usuário (RF01.1 / RF01.2)
Status: Parcialmente implementado
PRD: RF01.1/RF01.2 — "o sistema deve reportar ao usuário quais linhas foram descartadas, sem interromper a importação"
Situação atual: ResumoAvisos agrega contagens, e o modal de avisos exibe resumos do tipo "32 linhas descartadas por malformação". Porém, os números de linha específicos (ex: "linhas 15, 42, 103 descartadas") não são rastreados nem exibidos.
O que falta: Avaliar se o PRD exige listagem de números de linha individuais (o texto diz "quais linhas foram descartadas"). A interpretação atual (contagens por categoria) pode ser suficiente, mas merece revisão explícita com o product owner. Se linhas individuais forem necessárias, ResumoAvisos precisa armazenar Vec<usize> por categoria.
F-06 — Validação de campos duplicados no mapeamento (RF02.3)
Status: Não implementado
PRD: RF02 — Tratamento de Erros de Configuração: "Dois campos mapeados para o mesmo índice/posição → Bloquear e exibir erro de validação imediatamente, antes de executar a análise"
Situação atual: executar_importacao_sync delega a validação ao reader, mas não há verificação explícita de índices/posições duplicados antes do disparo da análise. Se o usuário mapear, por exemplo, Numero e Serie para o mesmo índice CSV, os dados serão importados incorretamente sem aviso.
O que falta: Adicionar validação em disparar_importacao (ou no use case importar_arquivo) que verifique se algum índice (CSV) ou posição (XLSX) aparece em mais de um campo mapeado e retorne erro descritivo antes de iniciar o processamento.
F-07 — Índice/posição inválido: identificar qual campo (RF02)
Status: Parcialmente implementado
PRD: RF02 — "Índice/posição configurado não existe no arquivo importado → Exibir erro ao usuário identificando qual campo está inválido"
Situação atual: Os readers retornam erros quando um índice não existe, mas a mensagem de erro pode não identificar claramente qual campo (Numero, Serie, Valor etc.) causou o problema.
O que falta: Garantir que as mensagens de erro de importação identifiquem o campo problemático pelo nome lógico (ex: "Campo 'Numero': índice 5 não existe — o arquivo tem 4 colunas").
F-08 — Spinner/indicador visual durante análise (RNF03 / RNF04)
Status: Minimamente implementado
PRD: RNF03 — "A análise é executada em uma thread separada para não bloquear a interface gráfica"
Situação atual: O estado EstadoApp::Analisando exibe apenas dois textos estáticos ("Analisando..." e "Aguarde...") sem nenhum indicador de progresso animado.
O que falta: Implementar um spinner ou progress bar indeterminado na tela de análise para dar feedback visual ao usuário de que o processamento está ativo. O iced suporta animações via Subscription com time::every.
F-09 — Paginação independente por série (RF07)
Status: Não implementado (limitação funcional)
PRD: RF07 — paginação para listas longas
Situação atual: app.pagina_faltantes e app.pagina_duplicatas são contadores globais únicos, compartilhados entre todas as séries. Ao navegar para a página 2 de faltantes da Série 001, a paginação também afeta a Série 002 se ambas aparecerem na mesma tela.
O que falta: Tornar a paginação independente por ChaveSerie, usando um HashMap<ChaveSerie, usize> no estado da aplicação em vez de um único usize global. Isso requer mudanças em App, em Message e na tela resultado.rs.
F-10 — Exportação do resultado em CSV (seção 4.2 / seção 14)
Status: Não incluído no MVP (seção 4.2)
PRD: Listado como "Não Incluído (MVP)" na seção 4.2 e como evolução futura na seção 14.
Nota: Não é um requisito do MVP. Documentado aqui apenas para rastreabilidade.
3. Resumo por Prioridade
| ID | Tipo | Arquivo(s) afetado(s) | Esforço estimado |
|---|---|---|---|
| W-01 | Warning → usar campo data |
pdf_generator.rs |
Baixo |
| W-02 | Warning → usar minimo/maximo |
app.rs |
Baixo |
| W-03 | Warning → remover ou usar | resultado_analise.rs, resultado.rs |
Baixo |
| W-04 | Warning → remover variante | app.rs |
Baixo |
| W-05 | Warning → remover variante | message.rs, app.rs |
Baixo |
| W-06 | Warning → aplicar estilo | tabela_preview.rs |
Baixo |
| W-07 | Warning → usar ou remover | resultado.rs ou theme.rs |
Baixo |
| F-01 | Funcionalidade faltante | pdf_generator.rs |
Baixo |
| F-02 | Funcionalidade incompleta | app.rs |
Baixo |
| F-03 | Funcionalidade faltante | csv_reader.rs, xlsx_reader.rs, app.rs |
Médio |
| F-04 | Funcionalidade incompleta | app.rs |
Baixo |
| F-05 | Revisão de requisito | domain/errors.rs, readers |
Médio |
| F-06 | Funcionalidade faltante | app.rs ou importar_arquivo.rs |
Médio |
| F-07 | Funcionalidade incompleta | csv_reader.rs, xlsx_reader.rs |
Médio |
| F-08 | UX faltante | app.rs |
Médio |
| F-09 | Limitação funcional | app.rs, message.rs, resultado.rs |
Alto |
| F-10 | Fora do MVP | — | — |
4. Ordem de Execução Sugerida
Fase 1 — Warnings (todos baixo esforço, fazem parte da limpeza)
- W-05: Remover
Message::CancelarExpansao - W-04: Remover
EstadoModal::Informacao - W-03: Decidir entre remover
sem_inconsistenciasou usá-la emresultado.rs - W-07: Decidir entre remover
badge_sucessoou usá-la emresultado.rs - W-06: Aplicar
t::cabecalho_tabelaemtabela_preview.rs - W-02 + F-02: Usar
minimo/maximona mensagem de confirmação de intervalo - W-01 + F-01: Usar
datano PDF
Fase 2 — Bugs e requisitos críticos
- F-04: Limpar estado ao falhar leitura XLSX
- F-03: Validar limite de 50 MB
- F-06: Validar campos duplicados no mapeamento
- F-07: Mensagens de erro com nome do campo
Fase 3 — Melhorias de UX
- F-08: Spinner animado na tela de análise
- F-09: Paginação independente por série
- F-05: Revisar requisito de rastreamento de linhas individuais
Fim do roteiro.