carlos@cesaints: ~/projects/luxury-registry.md — zsh

Comando: cat projects/luxury-registry.md

projects/luxury-registry.md · 2,1 KB

Registro de veículos e bens de luxo, do site editorial ao console de vendas

Duas gerações de produto para um cliente internacional do setor de luxo: um registro editorial com CMS próprio, login em dois fatores e medição de audiência sem cookie, e depois uma vitrine de veículos com um console para a mesa de vendas. Nenhuma das duas foi implantada; este case trata da engenharia e das decisões de produto, não de resultado de negócio.

abrir demonstraçãosimulação do sistema com dados fictícios · 6 telas

Papel
Único engenheiro, do sistema visual ao console de vendas
Período
jul/2026 – set/2026
O que eu fiz

Eu: Produto, sistema visual, arquitetura, modelo de dados, CMS, medição de audiência, vitrine, console da mesa de vendas, regras de acesso, testes de segurança e a revisão de veracidade da interface.

Projeto privado, descrito sem identificar cliente, produto ou empresa.

Diagrama

Do registro editorial à vitrine com console de vendas

Na primeira geração, o registro editorial com o catálogo alimenta a medição de audiência sem cookie, que guarda o IP só em hash, e o CMS, com segundo fator e portão de publicação, mostra o painel de audiência. Na segunda, a vitrine tem as páginas renderizadas no servidor, e só o tipo público de cada carro chega ao navegador; o interesse do comprador vai para o banco. O console da mesa de vendas confere os papéis no middleware, na página e na action. Os dois usam um Postgres com RLS, com carros, leads e perfis da equipe, e a trilha de auditoria é gravada só por uma função que deriva o autor da sessão.

Contexto

Um cliente internacional do setor de luxo vende veículos e outros bens de forma discreta. O produto precisava parecer um registro privado, e não uma revenda, e dar à mesa de vendas um lugar para trabalhar os interessados. Foram duas gerações: um registro editorial com CMS, entre julho e agosto de 2026, e uma vitrine com console de vendas, entre agosto e setembro. Nenhuma das duas foi implantada. A primeira roda inteira localmente; a segunda tem CI completo, mas nenhum alvo de deploy. Não há tráfego, venda nem outro resultado de negócio para mostrar.

O que eu construí

  • O registro editorial. Home com uma treliça geométrica desenhada só em CSS e uma faixa de luz que percorre o padrão, departamentos numerados, catálogo de automóveis com busca e filtros na URL, ficha de proveniência por lote e um interesse por lote em que o navegador manda só o identificador.
  • O CMS. Login com segundo fator, cadastro de lotes com portão de publicação, fotos conferidas e recodificadas e o painel “quem está no registro”: funil de interesse, lotes mais vistos, filtros usados e as buscas sem resultado, que apontam o que falta no inventário.
  • A vitrine. Busca por marca, modelo e motorização, preço em duas moedas com câmbio fixo, filtros de categoria, preço e potência, página por carro renderizada no servidor e um formulário de interesse que já leva o carro anexado e devolve ao comprador um protocolo para citar quando a mesa ligar.
  • O console da mesa de vendas. Funil de leads no fuso horário da mesa, com mudança de estado gravada e exportação CSV, e a gestão da frota com especificação verificada ou estimada e pré-visualização do anúncio como o comprador vê.

O que eu faria diferente

Começaria pela revisão de veracidade, em vez de terminar nela. Na primeira geração a home chegou a afirmar coisas que o catálogo não tinha, e a métrica de busca nunca era preenchida; na segunda, as alegações sem lastro só saíram na reta final. E escreveria testes já na primeira geração, que chegou ao fim com tipos e lint no CI, mas sem nenhum teste.

Restrições

  • Venda discreta, então o site precisa parecer um registro privado, não uma revenda.
  • O que a mesa de vendas lê sobre o carro ou o lote não pode vir do navegador do visitante.
  • Medir a audiência sem cookie e sem identificador persistente.
  • Preço só aparece quando a especificação do carro foi conferida.
  • Uma equipe com três papéis e contas criadas com senha temporária.

Decisões

Medição de audiência própria, sem cookie

Contexto
A casa precisava saber o que os visitantes procuram e não encontram, sem cookie e sem identificador persistente no caminho de um comprador discreto.
Escolha
Eventos próprios com sessão que vive só na aba por 30 minutos, respeito a Do-Not-Track e GPC, IP guardado apenas como hash com sal diário e apagado em 30 dias, texto livre sem e-mail nem telefone e eventos mantidos por 13 meses.
Ganhos
  • O painel mostra o funil de interesse e as buscas sem resultado, que viram lacunas de inventário.
  • Nenhum dado pessoal fica guardado em claro.
Custos
  • Sem identificador persistente, não dá para saber se o mesmo visitante voltou em outro dia.

Lote como máquina de estados, com portão de publicação

Contexto
Um lote passa por rascunho, disponível, em fechamento, adquirido e retirado, e um lote vendido continua valendo como prova de histórico da casa.
Escolha
Transições explícitas, "adquirido" como estado terminal e publicação bloqueada sem história de proveniência de pelo menos 180 caracteres e sem ao menos uma foto.
Ganhos
  • O catálogo nunca mostra lote sem história nem foto.
  • O lote vendido fica no registro como proveniência realizada, sem botão de interesse.
Custos
  • Corrigir um lote adquirido exige retirá-lo, porque essa é a única saída do estado terminal.

Fronteira entre servidor e navegador medida

Contexto
O registro interno de cada carro tem 30 campos, e a vitrine renderizada no servidor mandava todos para o navegador.
Escolha
Um tipo público com 17 campos, montado no servidor, e um teste que reprova qualquer componente de cliente que importe o tipo interno.
Ganhos
  • Os dados serializados da vitrine caíram 28,7%.
  • Um campo novo no tipo interno não vaza por descuido.
Custos
  • Dois tipos para manter em sincronia sempre que a vitrine passa a mostrar um campo novo.

Autorização em três camadas, de propósito

Contexto
O console tem três papéis (administração, gerência de vendas e equipe de inventário), e toda conta nasce com senha temporária.
Escolha
Checagem no middleware, na página e na action ou rota; a troca da senha temporária é imposta nas mesmas três camadas; sessões assinadas com algoritmo fixo e emissor e público validados.
Ganhos
  • Esquecer a checagem numa camada não abre a tela nem a ação.
Custos
  • A mesma regra aparece em três lugares e precisa mudar junto.

A interface só afirma o que é verdade

Contexto
A vitrine exibia alegações de processo, instalações e serviços que não existiam, transações inventadas como prova social e dados de veículo gerados a partir de hash.
Escolha
Tirar tudo o que não tinha lastro, mostrar preço só em anúncio com especificação verificada e marcar no console a especificação estimada, que aguarda conferência.
Ganhos
  • O comprador não vê número que ninguém conferiu.
  • A mesa sabe quais anúncios ainda precisam de conferência.
Custos
  • Mais carros ficam "sob consulta" até alguém conferir a especificação.

Stack e por quê

Next.js
As duas gerações: páginas renderizadas no servidor, revalidação sob demanda e a fronteira com o navegador sob teste.
TypeScript e Zod
Validação em toda fronteira; o inventário vindo de fora passa pelo mesmo schema e falha fechado.
Supabase (Postgres com RLS)
Carros, leads e perfis da equipe, com trilha de auditoria gravada só por função que deriva o autor da sessão.
jose
Sessões do console assinadas, com algoritmo fixo e emissor e público validados.
sharp
Recodificação das fotos enviadas ao CMS, sem GPS nem EXIF.
Tailwind CSS v4
O sistema visual do registro em tokens, com a treliça desenhada só em CSS.
GitHub Actions
Tipos e lint na primeira geração; na segunda, também testes de segurança, varredura de segredos, auditoria de dependências e varredura do bundle.

Resultados

  • CI da segunda geração com tipos, lint sem aviso, 21 casos de teste de segurança, varredura de segredos, auditoria de dependências e build com varredura do bundle.

    repositório privado auditadoWorkflow e testes do repositório(Auditoria do repositório privado, set/2026)
  • Revisão adversarial do próprio código antes de fechar a segunda geração: 44 achados corrigidos, 1 deles crítico.

    repositório privado auditadoHistórico do repositório(Auditoria do repositório privado, set/2026)
  • Dados serializados da vitrine de 193.016 para 137.580 bytes (−28,7%) ao entregar só 17 dos 30 campos de cada carro.

    declaradoMedição registrada no projeto
  • Acervo de fotos de 663,8 MB para 51,2 MB (−92,3%) na conversão para WebP, e requisições de imagem na primeira carga de 306 para 66.

    declaradoMedição registrada no projeto

Ângulo de segurança

Superfície de ataque

  • Formulário público de interesse, que grava leads com dados de contato.
  • Console interno com três papéis e contas criadas com senha temporária.
  • CMS do registro com login e envio de fotos.
  • Coleta de eventos de audiência vinda do navegador.
  • Exportação CSV do funil de vendas.

Controles implementados

  • Teto de 16 KB contado em bytes antes do parse, validação estrita, dois limites por IP e campo-armadilha no formulário público.
  • Caracteres de controle e de inversão bidirecional recusados; IP derivado no servidor e nunca usado para autorizar.
  • Lead gravado só pelo servidor, com RLS no banco e trilha de auditoria gravada por função que deriva o autor da sessão.
  • Login do CMS com hash scrypt e TOTP com tolerância de um passo e bloqueio de reuso do mesmo código.
  • Interesse que envia só o identificador do lote; o servidor resolve título e código no registro.
  • Fotos conferidas pelo conteúdo e recodificadas sem metadados; CSV exportado com fórmulas neutralizadas.

O que eu testaria hoje

  • Um cadastro público tentando virar equipe com as migrations aplicadas juntas, o tipo de escalada que a revisão encontrou e fechou.
  • Contorno do limite por IP com cabeçalhos de proxy forjados.
  • Reuso do mesmo código TOTP dentro da janela de tolerância.

Evidências

  • repositório privado auditadoDois repositórios privados auditados(Auditoria do repositório privado, set/2026)