O EscalaOper é uma aplicação desktop que monta e mantém a escala de uma equipe que trabalha em turnos: manhã, tarde, noite e horário comercial, com folgas, férias, ausências, sobreavisos, convocações, trocas de horário e o transporte de ida e volta de cada turno. Ele é escrito em Java, guarda os dados num arquivo do Microsoft Access e gera a imagem do transporte que a equipe recebe pelo WhatsApp.

Este caso técnico mostra como o sistema representa uma escala, o que acontece quando o dia real foge do planejado e os erros que viraram regra. Os números foram conferidos no código, na versão de 14/06/2026, a mais recente do repositório.

Transparência: o EscalaOper foi projetado e desenvolvido por Jeremias Cardoso, autor deste blog. O texto não cita empresa, pessoas nem cidade, e deixa de fora caminhos de pastas e credenciais.

Nota de atualização (30/10/2026): este post foi reescrito como caso técnico. A versão de 20/07/2026 descrevia um desenho idealizado: o dia calculado por uma conta a partir de uma data-âncora, os desvios guardados em registros à parte e a equipe consultando a escala por aplicativo, em tempo real. Conferido no código, o sistema grava uma linha por pessoa por dia, parte dos ajustes sobrescreve essa linha e a equipe recebe a escala por imagem e por e-mail. Este texto descreve o que o código faz.

O problema: a escala que não cabe na semana comercial

Escala de turno parece uma tabela simples até a primeira semana real. Uma equipe que cobre manhã, tarde e noite trabalha em ciclos que não respeitam a semana do calendário: cinco dias de trabalho e dois de folga que caem numa terça e numa quarta, seis de trabalho e três de folga, quatro e dois. Em cima do ciclo vêm as férias, os atestados, quem é chamado para cobrir uma falta e a pergunta que todo mundo faz na véspera: quem pega o transporte de qual turno amanhã?

Enquanto uma pessoa só mexe no controle, uma planilha dá conta, e há modelos prontos para a rotina. O problema começa quando a escala precisa de histórico, de perfis de acesso e de regras que a planilha não segura sozinha: não lançar duas vezes o mesmo dia, saber quem está de folga para convocar, avisar a pessoa quando o turno dela muda. No caso técnico do SIGCOT, outro sistema do autor, a escala de turno aparece como um programa à parte, com login e banco próprios: é este.

O sistema em números

Números do repositório em 14/06/2026, data do último commit.

O sistema em números
MedidaValor
Código da aplicação, sem linhas em branco e sem comentárioscerca de 8,4 mil linhas: 6.750 em Java, 1.073 nas 12 telas e 564 nos estilos
Código de testes109 linhas, com 12 testes em 2 classes
Tabelas que o sistema cria no banco6
Turnos possíveis5: Manhã, Tarde, Noite, Comercial e Folga
Histórico no Git52 commits, de 05/06 a 14/06/2026
Primeiro commit (05/06/2026)54 arquivos e 8.149 linhas: o sistema já existia quando passou a ser versionado
Versão1.0.0

O banco guarda dados reais da equipe e fica fora do controle de versão. As senhas são guardadas com PBKDF2, um método de hash feito para senhas, e quem entra pela primeira vez é obrigado a trocar a senha inicial.

A escala é uma receita de períodos

No EscalaOper, uma escala não é uma tabela de dias da semana. É uma lista ordenada de períodos, e cada período diz quatro coisas: quantos dias dura, qual é o turno, a hora de entrada e a hora de saída. Um 6x3 no turno da manhã vira dois períodos: seis dias de Manhã, por exemplo das 07:00 às 15:00, seguidos de três dias de Folga. Um ciclo que alterna turnos é só uma lista maior: cinco manhãs, duas folgas, cinco tardes, duas folgas, e assim por diante.

O cadastro aceita qualquer combinação dos cinco turnos, exige pelo menos um dia por período e confere se o horário está no formato de hora e minuto. Formato novo de escala é cadastro, não código: ninguém precisa programar um caso especial para um 4x2 ou um 6x4. O limite está na unidade: o modelo conta dias inteiros, não horas. Um ciclo que só se descreve em horas precisa ser traduzido para dias antes de entrar.

O lançamento junta a receita com as pessoas. O administrador escolhe a escala, as pessoas e o intervalo de datas. A partir da data de início, o sistema caminha dia a dia: grava o turno do período atual, desconta um dia e, quando o período acaba, passa ao seguinte; quando a lista acaba, volta ao primeiro. Sem períodos cadastrados, o lançamento é recusado.

A data de início funciona como âncora do ciclo daquela pessoa. Duas pessoas na mesma escala, lançadas com datas de início diferentes, ficam defasadas, e é exatamente isso que uma escala de revezamento precisa para que sempre haja alguém em cada turno.

Uma linha por pessoa por dia

O resultado do lançamento não é uma fórmula guardada. É uma linha na tabela para cada pessoa em cada dia do intervalo, e a tabela tem uma regra que impede duas linhas para a mesma pessoa no mesmo dia.

Essa escolha tem uma vantagem grande e um custo que só aparece depois. A vantagem é que tudo o que vem a seguir fica simples. O painel de mais de 40 dias, o resumo de cobertura por turno, a lista de quem está de folga numa data e a imagem do transporte são consultas diretas: “traga as linhas entre tal e tal dia”. Ninguém precisa recalcular o ciclo para saber quem trabalha amanhã, e qualquer dia pode ser corrigido sem mexer na receita.

O custo é que o dia planejado e o dia real disputam a mesma linha. Como só existe uma linha por pessoa por dia, um ajuste não tem outro lugar para ficar a não ser em cima do planejado.

O dia real: convocação, ausência, troca e sobreaviso

Os ajustes do dia a dia ficam numa tela com abas, e cada tipo mexe na linha do dia de um jeito:

  • Convocação: para cobrir uma falta, o sistema lista quem está de folga na data. Ao confirmar, a linha da pessoa convocada recebe o novo turno, os novos horários e o tipo “Convocação”. A folga que estava ali deixa de existir no banco.
  • Ausência: muda só o tipo e a observação; o turno planejado fica. Por isso uma ausência num dia de folga continua mostrando “F” no painel, com uma borda tracejada, e uma ausência num dia de trabalho mostra o código do motivo: LME (atestado), LMA e LPA (licenças maternidade e paternidade), LGA (casamento), TRE (treinamento), VAS (viagem a serviço) ou CHE (compensação de horas extras).
  • Troca de horário: sobrescreve o turno. Quando duas pessoas trocam entre si, as duas linhas mudam numa transação só: ou as duas trocam, ou nenhuma troca.
  • Sobreaviso: é só uma marca na linha. Turno e tipo continuam como estavam.
  • Fora do transporte: quem não vai usar o transporte num dia ganha um marcador no campo de observação, sem apagar o que já estava escrito ali.

A ausência e o sobreaviso preservam o planejado. A convocação e a troca, não. Convocações, trocas e decisões de férias geram e-mail para a pessoa: são sete pontos de disparo no sistema.

Desfazer pede o turno certo

O preço de sobrescrever aparece na hora de desfazer. O sistema tem uma função para desfazer ajustes em lote: escolhe-se a pessoa e o período, e os dias voltam ao normal. Só que o sistema não sabe qual era o normal. A tela pergunta, com estas palavras: “Qual é o turno CORRETO agora?”. Depois grava o turno escolhido em todos os dias do período.

Isso funciona bem para desfazer uma semana de convocações num mesmo turno. Para um período que misturava dias de trabalho e de folga, quem desfaz precisa quebrar o intervalo em pedaços, um por turno, ou relançar a escala, e relançar tem efeito colateral próprio, descrito mais abaixo.

A lição é de modelagem e vale para qualquer sistema com planejado e realizado: o planejado precisa sobreviver ao ajuste. Guardar o turno original numa coluna própria no momento da convocação ou da troca bastaria para o desfazer saber, sozinho, para onde voltar. A versão anterior deste texto apresentava essa separação como se ela já existisse. No código, ela existe para a ausência e o sobreaviso, e não existe para a convocação e a troca.

Férias, feriados e transporte

As férias têm fluxo próprio. A pessoa pede em até três períodos, com um mapa visual, e o RH aprova ou rejeita. O administrador também pode lançar ou estornar férias em lote. Esse lote já foi fonte de erro: cada dia era gravado sozinho, e uma falha no meio deixava a pessoa com férias pela metade na escala. Hoje o período inteiro roda numa transação, e qualquer falha desfaz tudo. O estorno passou pelo mesmo conserto: antes, a escala podia ficar estornada enquanto o pedido seguia como aprovado.

Os feriados nacionais são calculados pelo próprio sistema, inclusive os móveis: a Sexta-feira Santa, o Carnaval e o Corpus Christi saem da data da Páscoa, e o 20 de novembro entra desde 2024, quando virou feriado nacional. Os feriados estaduais e municipais vêm da configuração, como dia e mês (vale todo ano) ou como data completa (vale só naquele ano). O painel realça fins de semana e feriados.

O transporte segue uma regra curta, isolada num serviço com testes:

  1. quem é da manhã ou do comercial entra na janela da manhã e sai na da tarde;
  2. quem é da tarde entra na janela da tarde e sai na da noite;
  3. quem é da noite entra na janela da noite e sai na manhã do dia seguinte.

Com essa regra e a cidade de cada pessoa, o painel de logística mostra, por turno e por dia, quem chega e quem sai. O mesmo dado vira uma imagem quadrada para o WhatsApp, com seis nomes por grade e “+N” quando passa disso.

O banco: um arquivo e uma operação por vez

O banco é um arquivo do Access, que pode ficar numa pasta de rede. O driver usado para abri-lo em Java, o UCanAccess, recarrega o banco inteiro a cada conexão nova, e por isso o sistema mantém uma conexão só, aberta durante toda a execução. Um backup do arquivo roda uma vez por dia, no primeiro acesso, ou quando o administrador pede, e as cópias dos últimos 15 dias ficam guardadas.

Essa conexão única era segura enquanto tudo rodava na mesma linha de execução da interface. Deixou de ser quando o painel, o transporte e a imagem do WhatsApp passaram a consultar o banco em segundo plano, para a tela não travar: duas consultas podiam usar a mesma conexão ao mesmo tempo. O commit que corrigiu isso, em 10/06/2026, chama o problema de bug crítico. A correção foi uma trava que deixa passar uma operação de banco por vez, sem mudar nenhum dos pontos do código que usam o banco.

A trava vale dentro de um programa aberto. Ela não coordena dois computadores abertos no mesmo arquivo de rede. O que acontece nesse caso foi medido em outro sistema do autor, o Sentinela, que guarda dados no mesmo tipo de arquivo.

Incidentes que viraram regra

  1. O programa que só abria no ambiente de desenvolvimento (05/06/2026). Empacotado, o programa não achava a tela de login, porque as telas estavam numa pasta que o empacotamento não levava, e falhava ao abrir, porque os arquivos de assinatura de uma biblioteca de criptografia faziam o pacote parecer adulterado. As telas foram para a pasta de recursos, e o empacotamento passou a descartar essas assinaturas, com um comentário no arquivo de build explicando por quê.
  2. O acento que quebrava o filtro sem dar erro. Os nomes de turno e de tipo de registro eram digitados à mão em vários arquivos. Um “Convocaçao” sem til bastava para um filtro não achar nada e uma cor não aparecer, sem nenhuma mensagem. Os valores foram reunidos num único arquivo de constantes, com um aviso: eles também aparecem dentro dos comandos SQL e precisam ser idênticos.
  3. O build verde com telas quebradas (11/06/2026). Ao trocar os textos soltos pelas constantes, uma edição em massa não reconheceu o fim de linha do Windows, e a linha que trazia as constantes não entrou em três telas. O ambiente de desenvolvimento gerou classes com o erro embutido; o Maven, vendo classes mais novas que o código, não recompilou, empacotou o programa quebrado e terminou com sucesso. As telas só falhavam ao abrir. A regra que ficou: depois de edição em massa, compilar do zero e conferir que todas as telas carregam. É o mesmo tipo de falha silenciosa que derruba automações: a ferramenta diz que deu certo, e o efeito não aconteceu.
  4. O e-mail que nunca saiu (10/06/2026). O envio direto por servidor de e-mail não funcionava: a senha configurada era um exemplo, e a rede corporativa bloqueava a saída. O envio passou a usar o Outlook instalado na máquina, por um pequeno script temporário que monta a mensagem e envia sem abrir janela. O custo é depender do Outlook configurado, e o primeiro envio pode pedir confirmação.
  5. A cópia do banco apagada numa limpeza (11/06/2026). Ao limpar arquivos de um teste, uma cópia do banco, de 30/04, foi apagada por ser tomada como sobra do teste. O comando de apagar do terminal não passa pela lixeira. A cópia voltou idêntica de outra pasta de cópias, com o mesmo tamanho e a mesma data. Arquivo de banco que parece sobra precisa ter data e tamanho conferidos antes de sumir.

Testes: poucos, e no lugar em que a regra é pura

O sistema tem 12 testes em 2 classes. Os dois serviços testados nasceram em 11/06/2026, quando a regra das siglas do painel e a regra do transporte saíram de dentro das telas e foram para classes que não dependem do banco nem da interface. A convenção daquele dia: lógica de negócio nova vai para um serviço testável, não para a tela.

Todo o resto (lançamento, ajustes, férias, ponto de restauração e banco) não tem teste automático e é conferido à mão. É o maior risco do projeto, e os achados da próxima seção são do tipo que um teste de banco teria pegado antes.

O que ainda não está resolvido

Os itens abaixo vêm da leitura do código. O sistema não foi executado para esta revisão.

  • O ponto de restauração esquece parte do dia. Antes de mexer na escala, o administrador pode criar um ponto de restauração. Ele é um só, e criar outro substitui o anterior. A cópia leva oito colunas: identificação, escala, pessoa, data, turno, tipo, observação e autor. Os horários de entrada e saída, a justificativa e o sobreaviso não entram. Restaurar devolve os turnos, mas sem esses campos.
  • Relançar apaga os ajustes do período. Se a pessoa já tem dias lançados no intervalo, o sistema pergunta se deve sobrescrever. Se a resposta for sim, apaga todas as linhas da pessoa no período, sem olhar o tipo: férias, convocações e ausências vão junto. O pedido de férias aprovado continua na tabela própria, mas os dias somem da escala.
  • Férias em dia sem escala. Na tabela criada pelo sistema, todo dia lançado precisa pertencer a uma escala, e o lançamento de férias em lote insere dias sem dizer a escala. Se essa regra valer no banco em uso, lançar férias num período que tenha um dia ainda sem escala desfaz a operação inteira, graças à transação. Não foi testado.
  • O desfazer em lote depende de quem desfaz saber o turno certo de cada dia.
  • Um arquivo, várias máquinas. A trava do banco não coordena computadores diferentes.
  • Histórico parado. O repositório termina em 14/06/2026. Se o sistema mudou depois, a mudança não está nele.

Lições que valem fora da escala de turno

  1. Guarde o ciclo como receita, não como calendário. Formato novo vira cadastro, não código.
  2. Materializar o dia simplifica a leitura, mas o planejado precisa de um lugar próprio para sobreviver aos ajustes.
  3. Desfazer só é seguro se o sistema souber para onde voltar sem perguntar a ninguém.
  4. Valor que vai para o banco e para o SQL precisa de uma fonte única. Erro de acento não dá erro.
  5. Sucesso da ferramenta não é prova. Compile do zero e abra as telas.
  6. Operação de várias linhas é tudo ou nada. Meio lançamento é pior que nenhum.
  7. Ponto de restauração tem de copiar tudo o que a tela mostra, ou ele restaura outra coisa.

Fontes