O Dia em Que Decidimos Parar de Lutar contra o WordPress
Recebi a ligação do CTO da Cannect numa terça-feira à tarde. A plataforma de corretagem de hipotecas deles tinha acabado de reprovar em uma auditoria de segurança pela terceira vez seguida. Os auditores sinalizaram os mesmos problemas: dependências PHP desatualizadas, uma pilha de plugins que ninguém compreendia totalmente, e uma integração customizada com a API da Equifax implementada com PHP procedural que havia sobrevivido a três desenvolvedores diferentes. A plataforma estava processando aplicações reais de hipoteca — as casas das pessoas estavam em jogo — e a fundação havia apodrecido silenciosamente.
Este post é o relato completo do que fizemos a seguir. O planejamento, as decisões técnicas, a migração em si, e o que erramos no caminho. Se você está encarando uma plataforma legada em WordPress em uma indústria regulamentada e se perguntando se deve migrar ou continuar remendando, este é o estudo de caso que você precisa.
A Situação Legada
A plataforma original da Cannect era um caso clássico de crescimento orgânico que saiu do controle. Começou como um simples site de marketing no WordPress por volta de 2018. Então um desenvolvedor adicionou um formulário de contato. Depois um plugin de calculadora de empréstimo. Então alguém precisou puxar dados de bureau de crédito, então escreveram um plugin PHP customizado que chamava a API Equifax Decision Power diretamente. Depois precisaram de rastreamento de aplicações, então outra tabela customizada foi aparafusada no banco de dados WordPress junto com wp_posts e wp_options.
Quando me envolvi, o sistema estava assim:
- WordPress 5.9 rodando em uma única instância EC2 (t3.medium)
- 12 plugins ativos, 4 dos quais não recebiam atualizações há mais de dois anos
- Plugin PHP customizado (~3.200 linhas) gerenciando a integração com o bureau de crédito Equifax
- 3 ferramentas de calculadora de empréstimo construídas como funções PHP separadas baseadas em shortcode
- Banco de dados MySQL misturando tabelas core do WordPress com 11 tabelas customizadas de aplicação
- Sem ambiente de staging — mudanças iam diretamente para produção
- Deploy manual via SFTP do laptop de um desenvolvedor
- Zero cobertura de testes
A integração com a Equifax era a peça mais crítica e mais frágil. Ela gerenciava consultas de crédito para pré-qualificação de hipotecas, o que significava que estava tocando dados financeiros sensíveis em um arquivo PHP que vivia no diretório wp-content/plugins junto com um plugin de cupom e uma ferramenta de SEO quebrada.
A performance era outro problema. Os tempos de carregamento nas calculadoras de empréstimo regularmente chegavam a 4-6 segundos. O servidor disparava para 90%+ de CPU durante o horário comercial quando múltiplos corretores rodavam aplicações simultâneas. Não tinham sistema de filas — toda submissão de calculadora e toda chamada à API da Equifax rodava de forma síncrona na mesma requisição.
Por Que Decidimos Migrar
Eu sempre resisto a projetos de migração no início. Reescritas são caras, arriscadas e fáceis de subestimar. Disse à equipe para construir o caso claramente antes de eu concordar em planejar uma. Aqui está o que eles trouxeram de volta.
Postura de segurança. A plataforma armazenava números parciais de seguro social, dados de verificação de renda e scores de crédito. Conformidade PCI-DSS estava no roadmap para o ano seguinte. WordPress com uma arquitetura de plugins customizada não é onde você quer estar quando precisa de certificação SOC 2 ou PCI. A superfície de ataque — execução PHP, vulnerabilidades de plugins, nenhum gerenciamento de secrets — era grande demais para blindar sem essencialmente reconstruir a aplicação.
Velocidade do desenvolvedor. Integrar um novo desenvolvedor levava três semanas porque a base de código não tinha documentação, nem testes, e o sistema de plugins exigia entender os internos do WordPress antes de poder mudar qualquer coisa relacionada a lógica de negócio. Pull requests levavam dias porque ninguém conseguia avaliar com confiança o raio de impacto de uma mudança.
Teto de performance. Já tinham escalado verticalmente duas vezes. A arquitetura de servidor único não tinha caminho de escalabilidade horizontal sem retrabalho significativo. Durante períodos de pico de aplicações, sessões de corretores estavam dando timeout.
O custo de ficar. Este foi o argumento decisivo. Perguntei ao CTO para estimar as horas de engenharia gastas por trimestre em manutenção, patches de segurança e combate a incêndios. O número ficou em torno de 60-80 horas por trimestre — aproximadamente $18.000-$24.000 CAD em tempo de desenvolvedor — para uma plataforma que ainda tinha achados de auditoria de segurança abertos ano após ano.
Migrar não era barato. Mas ficar também não era de graça.
Planejando a Migração
Antes de escrever uma linha de código novo, passamos três semanas em uma auditoria. Quero ser específico sobre o que essa auditoria cobriu, porque pular este passo é como migrações falham.
Inventariar tudo que existe. Catalogamos cada endpoint, cada formulário, cada hook e filtro do WordPress que os plugins customizados usavam, cada tabela do banco de dados e cada chamada de API externa. Usamos uma combinação de análise estática, introspecção do banco de dados e simplesmente leitura do código. O inventário revelou duas integrações que ninguém na equipe atual sabia que estavam ativas — um provedor de SMS terceirizado e um webhook antigo do Slack que disparava em submissões de aplicações.
Identificar o que é realmente usado. A instalação WordPress tinha funcionalidades que foram construídas e abandonadas. Rodamos logs de acesso contra o inventário de URLs e descobrimos que aproximadamente 30% das páginas baseadas em shortcode customizado tinham recebido zero tráfego nos últimos seis meses. Essas foram cortadas completamente.
Entender o modelo de dados. As tabelas customizadas de aplicação eram mal normalizadas e continham várias colunas que existiam "por precaução" e eram sempre nulas. Antes de projetar o novo schema, rastreamos cada campo através da base de código para entender o que era realmente escrito, lido e usado downstream.
Mapear a integração com a Equifax precisamente. Isso exigiu o maior cuidado. A API Equifax Decision Power tem requisitos rigorosos em torno de manipulação de dados, segurança de transmissão e armazenamento de respostas. Documentamos cada tipo de requisição que o plugin existente fazia, os campos de resposta armazenados e a política de retenção (que acabou sendo "armazenado para sempre" — algo que endereçamos no novo design).
Com a auditoria completa, decidimos por uma abordagem de execução paralela em fases. A nova plataforma rodaria junto com o WordPress por aproximadamente seis semanas, com corretores migrados gradualmente por conta. Isso era mais caro que uma virada direta, mas crítico em um contexto regulamentado onde um deploy falho tem consequências reais para aplicações reais de hipoteca.
Escolhendo o Novo Stack
Fintech não é o lugar para experimentar com frameworks de ponta. O stack tinha que ser comprovado em produção, bem documentado e fácil de contratar.
Frontend: Next.js 14 (App Router) O portal voltado para corretores precisava de renderização no servidor para a melhoria de performance no carregamento inicial e SEO-friendliness para as páginas públicas de calculadora. Next.js com o App Router nos deu React Server Components para as partes estáticas e componentes client apenas onde interatividade era necessária.
Camada de API: Node.js com tRPC Escolhemos tRPC ao invés de REST porque a equipe era TypeScript-first, e ter segurança de tipos ponta a ponta entre o frontend Next.js e a camada de API eliminou uma classe inteira de bugs que assolavam a base de código PHP. Os contratos de tipo forçaram documentação por padrão.
Banco de dados: PostgreSQL no RDS (Aurora Serverless v2) PostgreSQL era a escolha óbvia — o modelo de dados era relacional, precisávamos de constraints de chave estrangeira adequadas (ausentes na configuração WordPress), e os dados financeiros exigiam garantias ACID. Aurora Serverless v2 nos deu auto-scaling sem o overhead operacional de gerenciar réplicas de leitura manualmente.
Jobs em background: BullMQ no Redis Toda chamada à API da Equifax foi movida para uma fila assíncrona. Uma consulta de crédito síncrona que podia falhar ou dar timeout não tinha razão de ser rodando em uma requisição web. BullMQ no ElastiCache Redis nos deu retentativas de jobs, filas de prioridade e visibilidade no estado dos jobs que a implementação PHP antiga não tinha.
Infraestrutura: AWS com CDK Toda infraestrutura como código. Sem mais acesso SSH a servidores de produção, sem mais deploys via SFTP. CDK em TypeScript significava que a infraestrutura era verificada por tipos junto com o código da aplicação.
Cronograma da Migração
Plataforma Cannect - 14 semanas no total
Auditoria e Planejamento
Inventário, modelo de dados, mapeamento da API Equifax, decisões de arquitetura
Banco de Dados e Camada de API
Design do schema, scripts de migração, configuração do router tRPC, sistema de autenticação
Frontend e Integrações
Portal Next.js, calculadoras de empréstimo, queue worker Equifax, integração SMS
Execução Paralela
20% dos corretores na nova plataforma, sincronização de dados do legado, resolução de problemas
Rollout Completo
Corretores restantes migrados, WordPress descomissionado, monitoramento reforçado
O Processo de Migração
Migração do Banco de Dados
A migração de dados foi a parte com que tive mais cautela. Tínhamos 11 tabelas customizadas, 6 anos de dados de aplicação e zero confiança na integridade dos registros existentes (o sistema antigo não tinha constraints de chave estrangeira, então registros órfãos eram comuns).
A migração rodou em três fases. Primeiro, uma sincronização somente leitura: escrevemos um script Node.js que continuamente puxava do banco MySQL do WordPress e escrevia registros normalizados no novo schema PostgreSQL, com uma coluna origin_legacy_id para rastrear cada registro de volta à sua origem. Isso rodou em background por duas semanas antes de qualquer corretor tocar no novo sistema.
Segundo, resolução de conflitos: identificamos ~1.400 registros de aplicação que falharam na validação contra o novo schema — majoritariamente nulos em campos que o novo modelo exigia, e um punhado de registros duplicados criados por uma condição de corrida na lógica de submissão antiga. Cada categoria recebeu uma regra de resolução.
Terceiro, virada: quando um corretor era migrado para a nova plataforma, sua conta se tornava a fonte de verdade no PostgreSQL. Uma camada fina de sincronização ainda escrevia nas tabelas MySQL legadas durante a execução paralela, para que as views de admin do WordPress permanecessem precisas para a equipe de operações até estarmos prontos para desligá-las.
Camada de API
Construímos a API tRPC em um monorepo junto com o frontend Next.js. A estrutura do router mapeava de perto os objetos de domínio: applications, brokers, calculators, creditPulls. Cada router tinha validação de input explícita usando schemas Zod — algo que a base de código PHP nunca tinha feito.
Uma decisão inicial que se pagou: mantivemos a API tRPC chamável de fora do Next.js expondo um adaptador HTTP. Isso significava que futuros clientes mobile ou integrações de terceiros poderiam usar a mesma API validada ao invés de contorná-la.
Frontend
As calculadoras de empréstimo públicas eram as páginas de maior tráfego e a vitória mais fácil. Os shortcodes PHP antigos renderizavam no servidor a cada requisição, incluindo todo o bootstrap do WordPress. Movê-los para React Server Components com shells estáticos pré-renderizados cortou o time-to-interactive de 4,2 segundos para menos de 800ms — antes de qualquer outra otimização.
O portal do corretor exigiu mais cuidado. Corretores tinham forte memória muscular da interface antiga, e havíamos sido avisados de que qualquer regressão visual geraria reclamações imediatas. Fizemos uma revisão lado a lado de cada tela com dois corretores durante a fase de execução paralela, e iteramos em três telas que causaram atrito antes de fazer o rollout para toda a base de corretores.
A Integração com a API Equifax
Esta foi a parte mais tecnicamente exigente da migração. A API Equifax Decision Power não é uma integração que perdoa — ela tem limites de taxa rigorosos, regras de validação de payload e requisitos de trilha de auditoria que o plugin PHP antigo gerenciava de forma inconsistente (às vezes nem gerenciava).
A nova integração tinha quatro componentes:
1. Um cliente Equifax tipado. Toda comunicação com a API centralizada em um único módulo com tipos TypeScript gerados a partir do XML schema da Equifax. Sem mais PHP procedural fazendo chamadas HTTP com parâmetros curl brutos.
2. Uma fila de jobs BullMQ. Requisições de consulta de crédito entravam em uma fila de prioridade. Corretores viam um estado imediato de "requisição recebida" na UI enquanto o job processava de forma assíncrona. Se a API da Equifax retornava um 429 ou um 5xx, o job retentava com backoff exponencial ao invés de falhar silenciosamente como a versão PHP frequentemente fazia.
3. Log de auditoria. Toda requisição e resposta da Equifax era registrada em uma tabela de auditoria imutável no PostgreSQL — timestamp da requisição, ID do corretor, ID da aplicação, código de resposta e um hash do payload da requisição. Essa trilha de auditoria era algo que os auditores de segurança tinham sinalizado como ausente por dois anos consecutivos.
4. Aplicação de política de retenção de dados. O sistema antigo armazenava respostas de crédito completas indefinidamente. O novo sistema aplicava uma política de retenção de 90 dias via um job agendado, mantendo apenas os campos derivados necessários para o processamento contínuo da aplicação. Isso reduziu significativamente a janela de exposição para dados sensíveis.
A abordagem de fila revelou algo interessante: a integração PHP antiga tinha uma taxa de falha silenciosa de aproximadamente 12% — requisições que erravam sem log ou notificação ao usuário. Descobrimos isso ao reproduzir requisições históricas contra a nova fila e comparar resultados. Esses 12% representavam aplicações reais onde corretores tinham feito follow-up manualmente com a Equifax por telefone sem saber que era uma falha da plataforma.
Estratégia de Testes e Rollout
Abordamos os testes em camadas.
Testes unitários cobriram o cliente Equifax, a lógica de cálculo de empréstimo e todos os handlers do router tRPC. Foram escritos antes da implementação usando Jest. Os testes da calculadora foram particularmente valiosos porque a implementação PHP antiga tinha três funções de cálculo diferentes que produziam resultados ligeiramente diferentes para os mesmos inputs — um bug que passou despercebido porque não havia testes para compará-los.
Testes de integração cobriram os scripts de migração de banco de dados e o queue worker. Usamos uma instância PostgreSQL de teste populada com snapshots sanitizados de dados de produção.
Testes end-to-end usando Playwright cobriram os cinco fluxos críticos do corretor: login, criação de aplicação, submissão de calculadora, requisição de consulta de crédito e atualização de status de aplicação. Esses rodavam em cada pull request contra um ambiente de staging que espelhava produção.
Para o rollout, usamos um sistema de feature flags (LaunchDarkly) para controlar quais contas de corretores eram direcionadas para a nova plataforma. Começamos com 5 contas de teste internas, depois passamos para 20% dos corretores (os mais confortáveis tecnicamente, selecionados deliberadamente), depois 60%, depois 100%. Cada fase tinha uma janela de observação de dois dias antes de avançar.
A execução paralela revelou três problemas que não teríamos capturado de outra forma: um bug de tratamento de timezone em timestamps de aplicação (o sistema antigo armazenava tudo em horário Eastern sem marcador de timezone; o novo sistema usava UTC), um campo faltando nos emails de notificação do corretor, e uma regressão de performance na view de lista de aplicações sob filtragem pesada. Os três foram corrigidos antes do rollout completo.
Antes e Depois: Os Números
Comparação de Performance da Plataforma
WordPress (legado) vs. Next.js + Node.js (novo)
| Métrica | WordPress | Novo Stack | Mudança |
|---|---|---|---|
| Carregamento página calculadora (p50) | 4,2s | 0,78s | -81% |
| Tempo de submissão de aplicação | 3,1s | 0,42s | -86% |
| Taxa de falha silenciosa Equifax | 12% | 0,3% | -97% |
| Utilização de CPU em pico | 91% | 23% | -75% |
| Custo mensal de infra (AWS) | $340 | $290 | -15% |
| Horas de manutenção dev (por trimestre) | ~70h | ~12h | -83% |
| Tempo para integrar novo desenvolvedor | 3 semanas | 3 dias | -93% |
| Achados de auditoria de segurança abertos | 7 | 0 | -100% |
A economia em custos de infraestrutura foi menor que a manchete, mas isso era esperado — adicionamos Redis gerenciado, Aurora Serverless e um pipeline de CI/CD adequado. O retorno financeiro real veio da redução da carga de manutenção: 58 horas por trimestre recuperadas a $150/hora é mais de $34.000 CAD anualmente em capacidade de engenharia redirecionada para desenvolvimento de produto.
Lições Aprendidas
A auditoria não é opcional. Toda vez que pulei ou abreviei uma auditoria de base de código em um projeto de migração, custou mais tempo downstream do que a auditoria teria custado. Você não consegue estimar o escopo da migração com precisão sem saber o que realmente está lá. As duas integrações misteriosas da Cannect — o provedor de SMS e o webhook do Slack — teriam quebrado produção se as tivéssemos perdido.
Async-first para APIs externas. Qualquer chamada a uma API de terceiros que afeta estado visível ao usuário deve ser enfileirada, não síncrona. A integração Equifax rodando in-process em uma requisição web PHP era sempre uma bomba-relógio. Movê-la para uma fila melhorou confiabilidade, visibilidade e comportamento de retentativa simultaneamente.
Execução paralela adiciona tempo mas reduz risco. Quase pulamos a execução paralela para economizar duas semanas. Em retrospecto, o bug de timezone e a regressão no email de notificação capturados durante a execução paralela teriam causado reclamações significativas dos corretores e potencialmente corrompido registros de aplicação se tivéssemos feito uma virada direta. Em indústrias regulamentadas, a execução paralela é um seguro.
Dívida de qualidade de dados vence no momento da migração. Os ~1.400 registros que falharam na validação de migração não eram um problema novo — eram anos de problemas de qualidade de dados que o sistema antigo havia silenciosamente aceitado. Uma migração força você a confrontar essa dívida. Reserve orçamento para isso.
A parte mais difícil não é a tecnologia. A parte mais difícil foi gerenciar a transição para corretores que usavam a mesma interface há anos. Três telas precisaram de iteração após a execução paralela porque tínhamos otimizado para o que achávamos ser melhor UX sem testar adequadamente com usuários reais. Inclua sessões de feedback com corretores mais cedo no plano.
Segurança de tipos se paga sozinha. Encontramos seis erros de cálculo durante a migração para tRPC + Zod que existiam na base de código PHP sem serem detectados — casos extremos onde a calculadora de empréstimo retornava resultados incorretos para combinações específicas de inputs. TypeScript e validação de schema em runtime capturam categorias inteiras de bugs antes de chegarem a produção.
Quando NÃO Migrar
Quero ser direto sobre isso, porque já vi clientes se convencerem de reescritas que não eram justificadas.
Não migre se a plataforma está performando adequadamente e o problema principal é estético. Um site WordPress que carrega em dois segundos, tem gerenciamento de plugins limpo e é mantido por pessoas que o conhecem bem não precisa de uma reescrita para satisfazer a preferência de alguém por React.
Não migre se sua equipe não consegue manter o novo stack. A Cannect tinha experiência em TypeScript na equipe e um pipeline de contratação que favorecia desenvolvedores Node.js. Se a equipe deles fosse exclusivamente PHP e não planejasse mudar isso, introduzir Next.js e tRPC teria trocado um problema de manutenção por um pior.
Não migre sem patrocínio executivo e um orçamento realista. Esta migração custou à Cannect aproximadamente CAD $65.000 em tempo de engenharia ao longo de 14 semanas. O ROI era claro e o período de payback era inferior a dois anos, mas projetos dessa magnitude emperram ou falham quando a liderança espera um trabalho de limpeza de $10.000.
Não migre sob pressão de prazo. Se o motivo da migração é um deadline de conformidade duro a seis semanas de distância, uma reescrita completa é a ferramenta errada. Reforço direcionado do sistema existente compra tempo. Faça a migração adequadamente, em um cronograma razoável, ou não faça.
Considere o estrangulamento incremental. O padrão Strangler Fig — substituir gradualmente partes do sistema legado por novos serviços, roteando tráfego incrementalmente — é frequentemente de menor risco que uma reescrita paralela completa. Para a Cannect, o modelo de dados era muito acoplado ao schema do WordPress para estrangular efetivamente, então uma construção paralela fez mais sentido. Mas para sistemas com fronteiras mais limpas, migração incremental reduz o raio de impacto de qualquer falha individual.
Onde a Cannect Está Agora
Oito meses após a plataforma WordPress ser descomissionada, a Cannect passou sua auditoria de segurança pela primeira vez. A equipe de desenvolvimento entregou quatro novos recursos no primeiro trimestre na nova plataforma — mais do que tinham entregado no ano anterior. A performance do portal do corretor não foi levantada como um problema desde o lançamento.
O log de auditoria da Equifax, que havia sido um achado recorrente por três anos, agora passa automaticamente. O job de retenção roda conforme programado. O queue worker processa requisições de consulta de crédito com 99,7% de taxa de sucesso, e quando uma falha ocorre, o corretor vê uma mensagem de erro significativa e a equipe de operações recebe uma notificação Slack com o contexto completo.
Não foi um projeto sem dor. A execução paralela se estendeu por uma semana, o bug de timezone exigiu um backfill de dados, e tomamos algumas decisões de UI que precisamos revisitar. Mas o sistema que a Cannect está rodando hoje é um que a equipe deles consegue entender, estender e confiar.
Isso é o que uma migração deve entregar — não apenas nova tecnologia, mas uma plataforma com a qual você realmente consegue trabalhar.
Passando por uma decisão similar? Se você tem uma plataforma legada em fintech ou outro espaço regulamentado e está tentando descobrir se deve migrar, modernizar no lugar ou continuar remendando, entre em contato pelo formulário. Terei prazer em conversar sobre os tradeoffs para a sua situação específica antes de você se comprometer com qualquer coisa.