[🛠] Operations Automation #3: Migração da automação legada de férias para o NAS e conexão HTTPS externa
✨ Resumo do GPT-5.6 Sol
Um registro da migração das funções e dos dados existentes de férias para um novo ambiente NAS, incluindo a correção dos defeitos de interface revelados em um dispositivo móvel real depois da conexão HTTPS externa.
Levei as funções e os dados da automação legada de férias para um novo ambiente NAS e conectei o caminho que permite às solicitações HTTPS externas chegarem até a aplicação dentro do NAS. Não foi apenas uma questão de iniciar um container, mas de transferir um fluxo de trabalho existente para um novo ambiente operacional.
No entanto, ver a nova tela abrir não bastava para considerar a migração concluída. Os dados de funcionários e férias precisavam aparecer, e tanto os destinatários dos avisos quanto os textos das mensagens tinham que ser iguais aos do sistema anterior. As mensagens que ultrapassassem o limite diário de 130 precisavam passar para o dia seguinte, e a queue de envio e o histórico também deveriam continuar. Se faltasse uma única parte, seria outro serviço com apenas o mesmo nome.
Quando antes voltei a separar a automação de vendas da administração de funcionários, decidi primeiro reproduzir as funções existentes de incentivo ao uso de férias e só depois migrá-las. Quando comecei de fato, essa ordem se mostrou ainda mais importante. Adiei por algum tempo o deploy no NAS.
Reprodução das funções locais e restauração dos dados
Primeiro executei FastAPI, Next.js e MariaDB em um ambiente Compose local e isolado. Para não colidir com o serviço existente, também separei port, network, volume e credential. Entrei como administrador, abri os dados de funcionários e férias e comparei com o fluxo antigo os destinatários dos avisos, os textos gerados, os agendamentos acima do limite de 130, a queue e o histórico.
Eu não queria mexer diretamente no DB de produção. Restaurei o backup SQL existente em uma instância separada do MariaDB e comparei o schema e a contagem das principais table. Também confirmei se os dados permaneciam depois de reiniciar o backend. Só então passei a ter uma referência de funcionamento local. Caso surgisse um problema no NAS, eu poderia separar uma diferença no código de um erro na image ou na network.
O fato de o backup ter sido restaurado não significava que a transição operacional estava concluída. A conta de administrador, o celular de trabalho e as mensagens reais ainda não tinham passado pelo novo caminho.
Dupla limitação no caminho de envio real de SMS
O próximo ponto de bloqueio foi o SMS real. Sem enviar uma mensagem, eu não conseguiria observar até o fim o caminho que chega ao celular Android de trabalho. Ao mesmo tempo, não podia deixar o envio de production aberto para fazer um teste.
Por isso, dividi o mode de envio do server em três opções.
NO_SEND
ALLOWLIST_SEND
PRODUCTION
O estado normal é NO_SEND. Somente durante o teste coloquei um destinatário autorizado em ALLOWLIST_SEND. Em vez do número de telefone em texto puro, identifiquei o destinatário com um hash SHA-256 e limitei a um o número de mensagens que o server poderia reivindicar. Também adicionei um budget separado de uma mensagem dentro do aplicativo Android. Eu queria impedir o envio de uma segunda mensagem mesmo que o server ou o aplicativo fosse operado de forma incorreta.
Não validei esse estado apenas lendo o código. Com Computer Use, abri a tela real de administração e conferi NO_SEND, a quantidade que poderia ser reivindicada naquele momento, a queue e o histórico. Na mesma tela, comparei o resultado do trabalho do Codex com o código implementado.

Também criei um package de teste separado para não mexer diretamente no aplicativo operacional. No dispositivo Android conectado por USB, usei adb reverse para ligar o endpoint local. Assim, uma mensagem real terminou como SUCCESS, e eu a vi chegar ao dispositivo receptor.
Também apareceu um resultado ambíguo. O usuário recebeu a mensagem, mas o delivery callback do Android não foi capturado. SUCCESS significava que a operadora havia aceitado a solicitação de envio, não que o delivery callback estivesse concluído. Se eu tratasse o recebimento real e o estado do callback como o mesmo sucesso, decidir o que fazer com casos UNKNOWN depois ficaria ainda mais confuso.
Depois de observar uma mensagem, voltei imediatamente para NO_SEND. O Android readiness ficou em 0, e o claim do server retornou 204 No Content. Encerrei o teste em um estado no qual uma ação acidental adicional não poderia enviar outra mensagem.
Migração das imagens Docker linux/amd64 para o NAS
Instalei no NAS apenas o serviço de automação de férias, e não toda a plataforma de automação. Em vez de fazer build do source novamente no NAS, criei as image linux/amd64 no Mac, conferi seus hash e as transferi. Também separei o project do Compose do stack existente. Assim, a substituição de um único backend não recriaria MariaDB e Frontend ao mesmo tempo.
Conexão do HTTPS externo e do Reverse Proxy
A tela de login abriu no novo endereço, e os dados existentes de funcionários e férias também apareceram. Mas só com texto não era fácil enxergar de imediato como as solicitações de um navegador externo chegavam até o MariaDB. Em especial, ao explicar se 3101 era um port aberto à Internet ou usado apenas dentro do NAS, as fronteiras se misturavam. Transformei o caminho da solicitação em um diagrama.
No diagrama, ficou claro que externamente só era necessário HTTPS 443. O Router encaminha 443 para o NAS, e o reverse proxy do NAS verifica o hostname e envia a solicitação ao Frontend em 127.0.0.1:3101. Backend 8000 e MariaDB 3306 se conectam apenas dentro da Docker network. Como 3101 também está vinculado somente ao loopback do NAS, ele não pode ser acessado diretamente pela Internet.
Deixei o Cloudflare fora do caminho principal pelo mesmo motivo. Eu já tinha authoritative DNS, IP público fixo e controle direto do Router. Adicionar apenas o A record do serviço e gerenciar o certificado no NAS permitia eliminar um componente intermediário. Em compensação, eu mesmo teria de cuidar da renovação do certificado e do port forwarding. Com exceção do port 80 usado para emitir e renovar o certificado, as solicitações reais do serviço entram apenas por 443.
Verificação em dispositivo móvel real e correção da interface responsiva
O fato de o endereço HTTPS externo abrir não significava que a migração estava concluída. Em um dispositivo Android real conectado por USB, acessei o novo endereço pela rede móvel e percorri diretamente o login, o dashboard, a lista de funcionários, o histórico de SMS e a gestão de férias. As telas abriam, mas ainda não estavam prontas para uso.
Os problemas que eu havia perdido ao apenas estreitar a janela do navegador no PC apareceram de uma vez no dispositivo real. No dashboard, a sidebar de desktop ocupava quase toda a tela e esmagava os card e os textos em colunas verticais.
Em todas as comparações abaixo, o lado esquerdo mostra antes da correção e o lado direito mostra depois.

Na lista de funcionários, títulos e button quebravam um caractere por linha, e uma table larga era forçada para dentro da largura estreita. Mantive o título e a área de ações no fluxo horizontal e permiti que a table fosse deslocada para o lado o quanto fosse necessário, em vez de comprimir o conteúdo.

Os filter do histórico de SMS e da gestão de férias tinham o mesmo problema. Vários campos e um intervalo de datas eram espremidos em uma única linha. Em telas pequenas, organizei os elementos principalmente em duas colunas e movi o intervalo de datas para outra linha, para que cada item pudesse ser lido e tocado.


Depois das correções, fiz novamente o deploy de uma nova Docker image e entrei outra vez no mesmo celular. Abri o menu, percorri as telas e observei diretamente cada filter e table para confirmar se os defeitos encontrados no início haviam desaparecido. O que começou como uma verificação de que a network externa chegava ao container no NAS acabou levando à correção da interface que seria usada de verdade.
Estado da migração por etapas e verificação da interface administrativa/E2E
Depois de conectar a migração para o NAS, o acesso externo e uma mensagem interna, abri novamente o roadmap completo e vi que as etapas 1 a 3 já tinham sido superadas. A posição atual era a etapa 4: fazer o deploy da interface administrativa melhorada como uma nova image e revisar todas as page novamente com ADB e o dispositivo real.

Ao colocar esse diagrama junto do trabalho, o próximo limite também ficou claro. O acesso externo já havia passado, mas o dogfooding na sede não poderia começar antes da reverificação das telas administrativas no dispositivo real. Portanto, o próximo passo não era adicionar mais recursos, e sim verificar até o fim se a interface corrigida mantinha o mesmo fluxo de trabalho no desktop e no celular.
Estado seguro e rollback antes da transição operacional
Por enquanto, o novo stack está deliberadamente configurado para não fazer nada de forma automática.
ENABLE_SCHEDULER=False
SMS_SEND_MODE=NO_SEND
SMS_ALLOWLIST_MAX_CLAIMS=0
Não escrevi as credential de administrador no Compose nem nas image. No NAS, forneci-as por meio de um secret file com permissão 0600; no Mac, guardei-as no Keychain.
Eu já podia entrar no novo endereço e ler os dados, e, sob condições limitadas, uma mensagem também chegou. Em uma rede móvel externa, verifiquei todo o caminho, do login à consulta dos dados e à interação com as telas. Mesmo assim, antes de remover o serviço antigo de mensagens de férias, ainda é preciso definir como recuperar envios sem delivery callback e obter aprovação para as condições reais de envio.
Por isso, parei os container e volume existentes, mas os mantive intactos. O próximo passo não é acrescentar mais configuração. Preciso decidir como recuperar envios sem callback e então abrir o envio real, começando por uma quantidade limitada sob condições aprovadas.
Separadamente da migração técnica, escrevi em Quando você aprende a usar a IA de forma ativa, as possibilidades parecem infinitas sobre a mudança que senti ao permitir que a IA observasse comigo o celular real e as telas de administração do Router e do NAS.
Deixe um comentário