← Projetos

Freedom Marine · CPQ

952 regras que ninguém nunca tinha escrito.

Uma plataforma multimarca de configuração e cotação de barcos. O time comercial monta o barco, precifica em CAD e envia a cotação, com cada passo registrado no CRM. Substituiu a cotação em planilha transformando opcionais, regras de dependência e lógica de preço de cada fabricante em dados.

Papel
Product lead e construção
Stack
Next.js 16 · React 19 · TypeScript strict · Supabase Postgres · Vercel
O problema

As regras existiam. Só nunca tinham sido escritas como regras.

A lista de opcionais de um fabricante parece um catálogo. Na verdade é um livro de regras disfarçado: uma nota de rodapé dizendo que um jogo de almofadas só serve em dois dos cinco modelos de sofá, um código de cor significando que dois layouts de deck nunca podem coexistir, um "ver nota 4" que no fim é ferragem obrigatória. Os vendedores carregavam essas regras na cabeça e em planilhas, e cotação saía errada.

Então o trabalho não era construir um formulário. Era transformar conhecimento implícito em dados que um sistema consegue impor a cada clique — e fazer isso para marcas cuja lógica comercial não tem nada em comum.

O que está dentro do sistema

1.016Itens de equipamento, 3.933 linhas de preço
952Regras de dependência, só na Axopar
10.660Casos golden de teste de preço
220Migrações de banco com checksum
Arquitetura

Uma aplicação, um banco, nada hard-coded.

Catálogo, regras, preços e ordem dos passos vivem no Postgres em vez do código, então um novo ano-modelo é mudança de dado e uma marca nova é configuração — não release.

CamadaO que faz
Front endConfigurador, painel comercial e painel administrativo. 14 passos principais, com ordem e visibilidade configuráveis por marca.
ServidorCotações, PDF renderizado no servidor, sincronismo com o CRM, mudanças de preço agendadas, ciclo de vida do lead, três cron jobs.
BancoCatálogo, preços, regras, fluxo de passos, cotações e log de auditoria, com row-level security e papéis.
PreçoUm módulo puro com todas as fórmulas e um esquema plugável por modelo.
IntegraçõesCRM e e-mail transacional, isolados atrás da própria camada, com escrita idempotente.
Decisões sob restrição

Seis vezes em que a resposta óbvia era a errada.

A parte interessante desta construção não é a lista de funcionalidades. É onde a primeira abordagem falhou e o que entrou no lugar.

  1. 01

    Quatro abordagens de parsing com IA não conseguiram ler as listas do fabricante

    Restrição · Regras codificadas em rodapés, cores e referências cruzadas

    Tentei interpretar as listas automaticamente de quatro formas diferentes. Nenhuma foi confiável o bastante para sustentar preço. As listas são implícitas por natureza — elas pressupõem um humano que conhece o produto. Então parei de tentar automatizar a leitura e movi o esforço para onde ele se sustentava: um modelo de regras tipado no banco, geradores que transformam uma lista revisada em regras, e sobrescritas por modelo acima das globais. A interpretação seguiu humana; tudo depois dela virou dado.

  2. 02

    Duas marcas cuja precificação não tem nada em comum

    Restrição · Um motor, duas lógicas comerciais sem relação

    Uma marca precifica a partir de uma lista europeia por etapas configuráveis de fórmula — margem, markup, impostos, frete, normas locais. A outra constrói o custo a partir do varejo do casco, com carrego e compra futura, delta de versão, custos fixos e MSRP do motor. Em vez de ramificar o código, o preço virou um esquema preso a cada modelo, com todas as fórmulas num módulo puro. O banco rejeita os campos de preço de uma marca num modelo da outra, para que não se misturem por engano.

  3. 03

    Opcionais que apareciam e sumiam sozinhos

    Restrição · Dependências em cascata que o vendedor não conseguia prever

    Impor as regras corretamente não basta se a tela muda na mão da pessoa. Cada clique passa por um planejador que calcula a consequência inteira antes e mostra: o que entra, o que sai, por quê, e o novo total. Onde a regra permite várias opções, o vendedor escolhe, e o confirmar fica desabilitado até ele escolher. As cascatas são calculadas contra o estado final, então trocar uma versão por outra preserva o que ambas exigem. O desfazer devolve tudo ao estado anterior ao clique.

  4. 04

    Sem câmbio ativo, sem preço — e não um chute

    Restrição · Uma fonte única de verdade para câmbio

    A taxa ativa é definida por um admin e vive numa tabela só. Se não houver taxa ativa, o configurador se recusa a precificar em vez de cair numa cotação velha. Um preço silenciosamente errado é pior do que preço nenhum, e o time comercial precisava confiar no número sem conferir.

  5. 05

    O modelo do CRM mudou três vezes em três meses

    Restrição · Um alvo de integração em movimento

    O formato foi de um lead por cotação, para deals, para leads com o configurador como fonte de verdade, e enfim para um lead por contato. Como a integração tinha sido construída como camada isolada desde o início, cada mudança ficou contida ali e nunca chegou ao configurador. Os envios carregam chave de idempotência, então repetir nunca duplica lead nem e-mail, e escritas externas ficam bloqueadas fora de produção.

  6. 06

    Preços mudam com cotações em aberto

    Restrição · Sistema no ar, sem banco de staging separado

    Um admin agenda a mudança de preço com data de vigência. Gatilhos no banco invalidam as cotações abertas afetadas, o PDF é regerado com marca d'água de preço antigo, e enviar e editar ficam desabilitados nelas. A restrição maior — mexer num sistema vivo sem cópia de staging — é tratada com feature flags por marca, migrações com checksum, e backup mais script de reversão para toda mudança em dado de produção.

Como foi construído

A IA escreveu a maior parte do código. O julgamento é que era o trabalho.

Cerca de 70 mil linhas de TypeScript, aproximadamente 630 horas de desenvolvimento ao longo de onze meses de calendário — algo como dezesseis semanas de um desenvolvedor em tempo integral. A proporção é o ponto: o código é gerado e revisado com IA sob direção humana, e foi isso que tornou esse escopo alcançável nesse orçamento.

O que não se delega é saber onde o modelo vai errar com confiança. Preço é o caso mais claro: as fórmulas vivem num módulo puro e 10.660 casos golden comparam cada saída contra snapshots guardados, incluindo um conjunto construído para reproduzir linha a linha a calculadora de preço do próprio cliente. Um teste de varredura reexecuta toda combinação de card e clique de um modelo, para que o que o card promete seja exatamente o que o clique faz.

A velocidade é segurada por controle de release, não por processo. Toda mudança é um pull request com deploy de preview próprio. Mudanças de dado passam por migrações numeradas e registradas com checksum. Marcas novas sobem atrás de feature flags.

O que eu faria diferente

A parte de que eu não gosto

O componente principal do configurador cresceu para cerca de 8.500 linhas. Funciona e está testado, mas atrasa qualquer pessoa nova lendo o código, e esse custo fui eu que criei, indo rápido num componente que foi absorvendo passo atrás de passo. Está sendo quebrado passo a passo, conforme cada um é tocado, em vez de uma reescrita arriscada de uma vez.

Tem um produto com regras assim?

Configuração, preço e cotação onde a lógica existe de verdade e ninguém escreveu ainda.