Pular para o conteúdo
caua.tolentino
Todos os cases
IntegraçãoFuncionalidade

Um contrato de frete por perfil de cliente

Uma loja B2B tinha dois contratos com a transportadora e só conseguia usar um, e o token ficava em texto aberto na tela e no log. Projetei e implementei a escolha do token pelo perfil do cliente a cada cotação, com o token mascarado em todo lugar e 83 testes.

Papel
Desenvolvedor responsável, da análise à entrega
Contexto
Plataforma de e-commerce B2B e marketplace
Stack
PHP, Symfony, Doctrine, MySQL, JavaScript, PHPUnit
Time
Solo, a partir de uma história de produto
Período
2026

Case anonimizado: nomes de empresa, cliente e pessoas foram omitidos ou trocados.

01. Situação

Dois contratos de frete e só um token

A integração com uma transportadora aceitava um único token de acesso por configuração. Uma loja B2B tinha dois contratos com essa transportadora, um para revenda e outro para consumidor, e só conseguia usar um. O revendedor era cotado na tabela do consumidor, e o frete cobrado divergia do frete faturado. No marketplace, cada lojista tinha o mesmo limite.

Recebi a história de produto com as regras de negócio e fiquei responsável por tudo o que vinha depois: análise técnica, plano, implementação e testes. Havia ainda um problema de segurança: o token aparecia em texto aberto no HTML da tela de configuração e no log de cada cotação. Tratei os dois na mesma entrega.

02. Investigação

Duas premissas da história não se confirmaram no código

A história descrevia bem o comportamento esperado, mas partia de premissas técnicas. Antes de escrever qualquer código, verifiquei cada uma. Duas eram falsas, e implementar em cima delas teria gerado trabalho inútil e um defeito.

Procurei cache de frete em memória, sessão, Redis, Doctrine e HTTP. O único cache vive dentro da requisição; toda cotação chama a transportadora de novo. Não foi preciso mudar chave de cache. Descartada.

03. Solução

Resolver o token a cada cotação e nunca mostrá-lo

Desenhei a solução em torno de um modo de configuração: token geral ou token por perfil. No modo por perfil, cada perfil de cliente pode ter um token; visitantes e perfis sem token usam o geral.

Resolvi o token a cada cotação e por pacote, não por carrinho. Essa escolha cobre o marketplace: num carrinho com produtos de dois lojistas, cada um cota com o seu contrato.

  1. Cotação de um pacote
  2. Configuração do lojista dono do pacote
  3. Modo por perfil e perfil com token: usa o token do perfil
  4. Header montado e log com o token mascarado
  5. visitante, perfil sem token ou modo geral: usa o token geral

Fechei também o vazamento do token. O token não sai em texto aberto em lugar nenhum: a tela mostra só os quatro últimos caracteres, os logs e as exceções são mascarados, e o botão de testar credencial, que adicionei, busca o token salvo no servidor sem enviá-lo ao navegador.

Escolha

Tabela própria para os tokens

Guardar como atributos da configuração não garantiria um token por perfil. A tabela garante a unicidade e apaga tudo junto com a configuração.

Escolha

Lojas existentes não mudam

O modo nasce vazio, e vazio significa geral. Nenhuma loja muda de comportamento sem escolher o modo novo.

Cuidado

Token geral obrigatório com a integração ativa

O servidor recusa o salvamento antes de gravar qualquer coisa, inclusive as faixas de frete, para não deixar a configuração pela metade.

Desenvolvi com TDD: 83 testes em 9 arquivos. Testei as migrações em um schema temporário e montei roteiros ponta a ponta com requisições reais, cobrindo admin, lojista, cotação e o JavaScript da tela, incluindo cotações com três perfis seguidos e login e logout no meio da sessão.

04. Resultado

Cada perfil cota no seu contrato

testes automatizados
83
verificações end-to-end
69/69
premissas falsas descartadas antes de codar
2

Revendedor e consumidor são cotados cada um no seu contrato, inclusive em carrinhos com mais de um lojista, e o token não aparece mais na tela, nos logs nem nas exceções.

Além da funcionalidade, entreguei a recomendação de rotacionar os tokens e expurgar os logs antigos, e o registro de um problema antigo na seleção da opção de frete no checkout, que encontrei durante os testes.