Aplicação desktop desenvolvida em Java/JavaFX para consulta, validação e correção de informações tributárias, com integração a uma API REST em Go, autenticação por JWT para contribuidores e suporte a fluxos legados baseados em arquivos DBF.
Este repositório é um showcase técnico. O código-fonte original não é público, as imagens devem ser tratadas como material demonstrativo/sanitizado e o Themis não possui vínculo com nenhuma instituição governamental.
- Nota Importante
- Objetivo
- Principais recursos
- Stack técnica
- Arquitetura
- Fluxo resumido
- Screenshots e fluxos demonstrados
- 01. Login de contribuidor
- 02. Atualização da lista de NCMs
- 03. Consulta de NCMs
- 04. Edição de tributação
- 05. Validação de dados tributários
- 06. Consulta por código de barras
- 07. Edição de vínculo por código de barras
- 08. Abertura de arquivo DBF
- 09. DBF em regime Simples Nacional
- 10. Correção autônoma por código
- 11. Indicação de modo offline
- 12. Edição manual de produto
- 13. Produto com inconsistência
- 14. Contribuições pendentes offline
- Decisões Técnicas
- Exemplos de Implementação
O Themis foi desenvolvido por mim, Douglas Rocha de Oliveira, como uma ferramenta interna para auxiliar a mim e meus colegas em processos específicos de correção tributária necessários no ambiente de trabalho.
O projeto não representa, não substitui e não deve ser interpretado como ferramenta oficial de qualquer instituição governamental. Seu objetivo sempre foi atender a uma necessidade operacional real e específica, facilitando consultas, validações, correções e reaproveitamento de informações já conferidas.
Durante o desenvolvimento, procurei aplicar boas práticas de organização, separação de responsabilidades, responsividade da interface, persistência local, otimização de desempenho e segurança no acesso aos dados. Além disso, várias melhorias foram implementadas a partir de sugestões e dificuldades observadas pelos próprios usuários da ferramenta.
O Themis foi criado para auxiliar processos de correção tributária em bases de produtos, reduzindo a dependência de conferências manuais e reaproveitando informações já validadas. A aplicação combina uma interface desktop voltada à produtividade com um backend responsável por centralizar dados tributários contribuídos. Além da consulta e manutenção de informações remotas, o projeto foi desenvolvido para operar com bases legadas armazenadas em DBF. O aplicativo lê arquivos DBF, permite a correção dos produtos, mantém uma referência local em SQLite para retomada do trabalho e exporta um novo DBF preservando a estrutura original com os dados corrigidos.
- Interface desktop em JavaFX para consulta, validação e edição de dados tributários;
- Comunicação com API REST em Go usando JSON;
- Token da aplicação para restringir o acesso aos dados ao cliente autorizado;
- Login opcional de contribuidor com autenticação JWT;
- Separação entre consultas públicas e rotas protegidas para contribuição/manutenção;
- Cache em memória para reduzir chamadas remotas e manter a aplicação responsiva;
- Leitura e exportação de arquivos DBF usados por sistemas legados;
- Persistência local em SQLite para salvar itens editados, filtros, configurações e permitir retomada do trabalho;
- Workers locais e remotos com buffers descarregados periodicamente, desacoplando gravações da interface;
- Correção automática/sugerida por NCM e por código de barras;
- Modo offline com limitações claras e tratamento de contribuições pendentes;
- Exportação de relatório em Excel como recurso de apoio histórico/operacional.
| Área | Tecnologias e conceitos |
|---|---|
| Desktop | Java, JavaFX, workers/background tasks, cache local, validações de interface |
| Backend | Go, API REST, JSON, middlewares, autenticação JWT |
| Dados | MariaDB/SQL, SQLite local, arquivo JSON de apoio |
| Integração legado | Leitura/exportação DBF, exportação Excel, continuidade operacional em bases existentes |
| Segurança | Token da aplicação, rotas públicas de consulta, rotas protegidas para contribuidores |
| Processo | Git/GitHub, separação cliente-servidor, preocupação com responsividade e retomada de trabalho |
A aplicação foi organizada em camadas para separar interface, regras de negócio, cache, persistência local, integração com arquivos legados e comunicação com a API.
O diagrama agrupa algumas responsabilidades em
Worker,LocalDBeRemoteDBpara facilitar a leitura. Na implementação, cada entidade possui seus próprios services/DAOs, integrados ao banco local, aos workers e/ou à comunicação remota conforme a necessidade do fluxo.
| Componente | Responsabilidade |
|---|---|
| Cliente JavaFX | Interface, validações, filtros, edição de produtos e interação com arquivos locais. |
| Services/DAOs por entidade | Camada responsável por concentrar regras, consultas e persistência específicas de cada entidade, integrando interface, workers, LocalDB e RemoteDB. |
| LocalDB | Camada de acesso e manutenção do arquivo SQLite associado ao DBF, incluindo versionamento e scripts de atualização estrutural. |
| LocalDBWorker | Worker iniciado por arquivo DBF aberto; mantém buffer de gravação local e descarrega alterações periodicamente para preservar fluidez da interface. |
| RemoteDB | Camada de comunicação com a API remota, utilizada pelos serviços que dependem de dados centralizados. |
| RemoteDBWorker | Worker iniciado com a aplicação; gerencia cache remoto e buffer de contribuições para usuários autenticados. |
| API Go | Expõe endpoints JSON, valida token da aplicação, autentica contribuidores via JWT e acessa a base remota. |
| MariaDB | Persistência central das informações tributárias, usuários contribuidores e dados consultados pela aplicação. |
| SQLite local | Persistência de itens editados, marcações, filtros e configurações para retomada do trabalho. |
| DBF | Formato legado de entrada e saída usado para compatibilidade com o processo operacional existente. |
- Ao abrir a aplicação, o login é exibido quando o modo contribuidor está habilitado.
- O login é validado pela API e retorna um JWT usado nas chamadas protegidas.
- A aplicação verifica o arquivo JSON local de NCMs e pergunta sobre atualização quando ele possui mais de 24 horas.
- O RemoteDBWorker é iniciado e carrega em memória os dados tributários necessários para consulta e correção.
- Ao abrir um DBF, o Themis procura ou cria o SQLite correspondente e executa verificações de versão/estrutura quando necessário.
- As operações de persistência passam pelos LocalDBWorker/RemoteDBWorker, que mantêm buffers de escrita e encaminham os dados aos services/DAOs das entidades correspondentes. Esses services/DAOs, por sua vez, integram com LocalDB ou RemoteDB conforme a necessidade do fluxo.
- Produtos do DBF são comparados com o cache remoto; dados conhecidos podem ser preenchidos automaticamente e dados inválidos são sinalizados.
- Edições manuais ou correções por código são gravadas no buffer local e, para contribuidores, também no buffer remoto.
- Após a correção, o sistema exporta um DBF com a estrutura original e os dados atualizados para reimplantação no fluxo legado.
Requer cadastro como contribuidor e que a aplicação tenha o modo contribuidor ativo
A tela de login é exibida apenas quando o modo contribuidor está habilitado. Nesse fluxo, o usuário autenticado recebe um JWT gerado pela API e passa a poder enviar contribuições para a base remota, enquanto usuários comuns continuam com acesso apenas às consultas públicas necessárias para apoio às correções.
Ao iniciar o aplicativo, o Themis verifica a existência do arquivo local com a listagem de NCMs ativos. Quando esse arquivo já existe e possui mais de 24 horas, o usuário é questionado sobre a atualização; a mesma verificação também pode ser forçada manualmente pelo menu.
Tela de consulta dos NCMs e das informações tributárias vinculadas. Essa visualização permite localizar registros da base e apoiar tanto a conferência manual quanto os fluxos automatizados de preenchimento.
Requer cadastro/login como contribuidor
Permite editar as informações tributárias relacionadas a um NCM. No modo contribuidor, alterações válidas são encaminhadas para a API e disponibilizadas posteriormente para consulta por outros usuários.
Requer cadastro/login como contribuidor
Campos que não respeitam as regras esperadas são destacados visualmente e impedem o salvamento. Essa validação evita que informações inconsistentes sejam enviadas como contribuição.
Tela dedicada à consulta de códigos de barras e suas respectivas informações tributárias. Esse vínculo é utilizado pelo aplicativo para sugerir correções automáticas quando um produto possui código válido e encontrado na base remota.
Requer cadastro/login como contribuidor
Permite ajustar a relação entre código de barras e NCM/tributação. Essa informação alimenta o processo de correção por código e melhora a reutilização de dados já contribuídos.
Ao abrir um arquivo DBF em um padrão esperado, o Themis carrega os produtos, aplica filtros e confronta os NCMs com os dados em cache. Produtos com NCM válido e encontrado na base remota são preenchidos automaticamente e marcados para revisão; inconsistências são sinalizadas em vermelho.
Quando o regime Simples Nacional é selecionado e a opção de uso de CSOSN está habilitada, os valores exibidos passam a ser convertidos para os equivalentes esperados nesse regime, reduzindo ajustes manuais durante a conferência.
A ferramenta de conferência por código valida os códigos de barras disponíveis, cruza essas informações com a base remota e apresenta uma lista de sugestões de correção. O objetivo é acelerar a revisão dos produtos e reaproveitar informações tributárias já conhecidas.
Quando a aplicação identifica ausência de conexão com o servidor, um indicativo de modo offline é exibido. O usuário ainda consegue trabalhar com dados locais e cache, mas recursos dependentes de consulta remota ou operações online ficam limitados.
Produtos podem ser editados manualmente. Quando há conexão ou dados em cache, o aplicativo pode preencher informações automaticamente a partir do NCM informado, desde que ele seja válido e possua dados contribuídos disponíveis.
Ao informar dados que fogem das regras de validação, o sistema exibe um indicativo visual e uma descrição do problema. Isso ajuda o operador a entender o motivo da inconsistência antes de concluir a correção.
Requer cadastro/login como contribuidor
Contribuidores que perdem conexão com o servidor podem continuar trabalhando; as possíveis contribuições ficam armazenadas em buffer. Caso o usuário tente sair antes que elas sejam sincronizadas com sucesso, o aplicativo exibe um aviso sobre as pendências.
Algumas escolhas do Themis foram guiadas pelo contexto operacional do projeto: necessidade de trabalhar com bases legadas, volume elevado de produtos, reaproveitamento de dados já validados, baixa tolerância à perda de progresso e uma interface que precisava continuar responsiva durante consultas, validações e gravações.
O uso de uma aplicação desktop em Java/JavaFX fez sentido porque o fluxo principal envolvia manipulação direta de arquivos locais, especialmente arquivos DBF usados por sistemas legados. Além disso, o processo de correção exigia uma interface produtiva para filtros, validações visuais, edição manual e preenchimentos automáticos, com comportamento próximo ao de uma ferramenta interna de operação.
Essa abordagem também permitiu manter recursos locais importantes, como cache em memória, persistência auxiliar em SQLite, funcionamento parcial offline e workers em segundo plano para reduzir travamentos durante leituras, gravações e sincronizações.
Outro fator relevante foi a familiaridade com Java, linguagem com a qual eu já tinha mais experiência. Isso ajudou a reduzir o custo de desenvolvimento, facilitou a implementação da interface e permitiu focar mais na solução do problema operacional do que na adaptação a uma nova stack.
A API foi implementada em Go por ser uma opção simples, performática e adequada para serviços pequenos e objetivos. A linguagem facilita a geração de um binário único, simplifica o deploy e possui bom suporte nativo para concorrência, HTTP e construção de serviços REST.
Outro ponto importante foi a separação entre cliente e banco remoto. Em vez de o aplicativo desktop acessar diretamente a base central, a API passou a concentrar autenticação, validação de token da aplicação, rotas públicas de consulta e rotas protegidas por JWT para contribuidores. Isso reduziu a exposição de credenciais, organizou melhor as regras de acesso e permitiu evoluir o backend sem acoplar o cliente diretamente ao modelo do banco remoto.
A escolha de Go também foi amparada pelo baixo consumo de recursos, permitindo que a API fosse executada em uma VPS básica com bom desempenho. Spring Boot chegou a ser considerado para o projeto, mas o uso de recursos pela JVM era uma preocupação em um ambiente com hardware limitado.
As consultas paginadas foram importantes porque a base tributária pode crescer bastante, principalmente quando envolve NCMs, códigos de barras, produtos e contribuições acumuladas. Retornar grandes volumes de dados de uma só vez aumenta o consumo de memória, torna as respostas mais lentas e pode prejudicar tanto o servidor quanto o cliente.
Com paginação, o backend consegue entregar os dados em partes menores e previsíveis. Isso melhora a estabilidade da API, reduz o risco de sobrecarga no banco e permite que o cliente carregue ou atualize informações conforme a necessidade do fluxo, sem depender de respostas enormes para cada operação.
O cache em memória ajuda na velocidade das consultas durante o uso da aplicação, mas não seria suficiente para garantir continuidade do trabalho. Por isso, o Themis também utiliza SQLite local para manter referências aos produtos trabalhados, itens editados, marcações, filtros e configurações associadas ao arquivo DBF aberto.
Essa decisão permite que o usuário continue de onde parou mesmo após fechar a aplicação, perder conexão ou abrir novamente um DBF que tenha sofrido alterações. Também evita a necessidade de exportar e reimplantar o arquivo a cada etapa intermediária do processo, já que o progresso fica registrado em uma base auxiliar vinculada ao trabalho local.
As operações de persistência e sincronização foram desacopladas da interface por meio de workers locais e remotos. Em vez de bloquear a tela a cada gravação, as alterações entram em buffers e são descarregadas periodicamente para o SQLite local ou para a API, conforme o caso.
Essa escolha melhora a fluidez da aplicação e reduz a chance de travamentos perceptíveis durante tarefas repetitivas. No modo contribuidor, o buffer remoto também ajuda a lidar com quedas de conexão, mantendo contribuições pendentes até que possam ser sincronizadas com sucesso.
Apesar de o diagrama agrupar algumas responsabilidades em blocos como Worker, LocalDB e RemoteDB, a implementação foi organizada com services/DAOs por entidade. Essa separação ajuda a concentrar regras, consultas e persistência específicas de cada tipo de dado, evitando que a interface conheça detalhes de armazenamento ou comunicação remota.
Com isso, cada fluxo pode integrar o que precisa: banco local, workers, cache em memória, API remota ou arquivos legados. Essa divisão torna o projeto mais fácil de manter e reduz o acoplamento entre as partes.
O suporte a DBF foi adicionado por compatibilidade com o processo existente. A aplicação precisava se encaixar em um fluxo operacional que já utilizava esse formato, então ler e exportar DBF facilitou a adoção da ferramenta.
A exportação em Excel também foi implementada como recurso de apoio, especialmente para conferência e acompanhamento manual. Com a evolução dos processos automatizados, esse relatório perdeu parte da utilidade no fluxo principal, mas permanece como um exemplo de recurso criado para atender uma necessidade operacional específica do momento.
Inicialmente no desenvolvimento do Themis, os itens exibidos em tela eram armazenados em um ArrayList de produtos com problemas. Conforme eram corrigidos, esses itens eram transferidos para outra coleção com os produtos já ajustados.
Apesar de a gravação em disco já estar desacoplada da interface, grandes volumes de correções simultâneas ainda causavam lentidão e congelamentos, principalmente em operações de busca, remoção e verificação entre coleções.
Esse problema foi resolvido substituindo estruturas lineares por HashSet/LinkedHashSet onde fazia sentido. A mudança reduziu significativamente o custo dessas operações: procedimentos que antes levavam cerca de 10 segundos passaram a ser concluídos quase instantaneamente. Isso permitiu que a correção por código marcasse cerca de 15 mil produtos de uma vez, sem sinais perceptíveis de congelamento na aplicação.
Nos exemplos de código, o nome interno do projeto aparece como
VerificaNcm. Os arquivos incluídos são recortes sanitizados do código original e não foram organizados para compilação isolada.
Como o código-fonte original do Themis não é público, este showcase inclui alguns trechos sanitizados na pasta exemplos/. Esses arquivos não representam o projeto completo, mas demonstram algumas decisões de implementação usadas na aplicação.
Os exemplos foram selecionados para mostrar pontos relevantes da arquitetura, como comunicação com a API, autenticação, tratamento de respostas, uso de cache, buffers de gravação e execução de tarefas em segundo plano.
O arquivo ClientHttp.java demonstra a camada centralizada de comunicação HTTP utilizada pelo cliente desktop. Essa camada monta as requisições, aplica timeout, adiciona o token da aplicação e, quando o usuário está autenticado como contribuidor, também envia o JWT no cabeçalho Authorization.
Essa separação evita espalhar lógica de autenticação e montagem de requisições pela interface ou pelos serviços da aplicação.
O arquivo ApiClient.java demonstra uma abstração genérica para operações comuns contra a API, como GET, POST, PATCH e DELETE.
A ideia foi concentrar validação de resposta, tratamento de erro e conversão dos dados em um único ponto, permitindo que os services/DAOs de cada entidade utilizassem a mesma estrutura sem repetir código de comunicação.
A aplicação utiliza parsers e mergers específicos em vez de depender de desserialização automática.
Essa decisão foi importante porque o cliente desktop passa por ofuscação. Como bibliotecas de serialização baseadas em reflexão podem depender de nomes de classes, campos ou métodos, a ofuscação poderia quebrar mapeamentos automáticos ou exigir regras extras de preservação.
Com parsers manuais, o controle sobre o JSON fica explícito: cada entidade define como seus dados são exportados, lidos e atualizados. Já os mergers permitem aplicar respostas da API sobre os objetos originais em memória, por exemplo quando o backend retorna identificadores ou estados atualizados após uma operação de envio.
De forma simplificada, o fluxo segue a ideia:
String body = parser.toJson(originalList);
HttpResult response = ClientHttp.postJson(endpoint, body);
if (response.body != null && !response.body.isEmpty()) {
JsonObject json = JsonParser.parseString(response.body).getAsJsonObject();
merger.merge(json, originalList);
}Além de evitar problemas com desserialização automática em código ofuscado, o uso de parsers e mergers manuais também ajudou a reduzir criação desnecessária de objetos durante operações em massa.
Em alguns fluxos, a resposta da API não precisava gerar uma nova coleção completa de entidades já existentes em memória. Em vez disso, o merger aplicava apenas os dados retornados pelo backend, como identificadores gerados ou campos atualizados, diretamente sobre os objetos originais usados pela interface e pelos caches.
Essa abordagem preservava referências já utilizadas pela aplicação, evitava substituições completas de listas e reduzia a pressão sobre o garbage collector em cenários com muitos registros. Isso era especialmente relevante em operações envolvendo grandes volumes de produtos, códigos de barras e contribuições.
Veja um exemplo sanitizado em exemplos/ParserAndMergerExemplo.java.
O arquivo RemoteDBWorker.java demonstra o uso de um worker em segundo plano para lidar com cache remoto, estado offline e buffers de contribuições.
Em vez de bloquear a interface a cada alteração, as mudanças são acumuladas e sincronizadas periodicamente com a API. Isso contribui para manter a aplicação responsiva, especialmente em fluxos com muitas correções ou em situações de instabilidade de conexão.