carlos@cesaints: ~/projects/edge-crm.md — zsh

Comando: cat projects/edge-crm.md

projects/edge-crm.md · 1,6 KB

Site institucional e CRM próprio na borda, com privacidade como requisito

Um grupo B2B trocou um CRM de mercado por um sistema próprio: um site em três idiomas que capta contatos por um diagnóstico interativo e por agendamento de reuniões, e um CRM com leads, funil de negócios, agenda, conteúdo e análises. Tudo roda num único Worker na borda, com cinco papéis de acesso, recorte por dono e a LGPD tratada como parte do produto.

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

Papel
Único engenheiro, do produto à operação
Período
jun/2026 – set/2026
O que eu fiz

Eu: Produto, arquitetura, modelo de dados, papéis e regras de acesso, todas as telas do site e do CRM, testes, deploy, operação e a documentação para quem não é técnico.

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

Diagrama

Site, CRM e rotina diária num único Worker

Tudo roda num único Worker na borda. O site institucional é pré-renderizado, e o que chega pelos formulários e pelo agendamento vai para o D1. O CRM e as APIs rodam sob demanda, com uma escada de papéis para o menu e para a API e recorte por dono; gravam no D1, onde ficam leads, negócios, reuniões e audiência, e guardam anexos e fotos no R2. Uma rotina diária anonimiza e poda os dados vencidos, e o Workers AI faz traduções que ficam marcadas para revisão humana.

Contexto

Um grupo B2B de expansão internacional e governança usava um CRM de mercado. Precisava de um site em três idiomas que qualificasse quem chega e de um CRM próprio para o time comercial, com os dados pessoais tratados pela LGPD desde o primeiro formulário.

O que eu construí

  • O site em três idiomas. Institucional pré-renderizado, um diagnóstico interativo de maturidade que vira lead com o questionário inteiro, landing pages com formulário em etapas, catálogo de imóveis, blog e agendamento de reuniões com horários calculados a partir das regras da agenda.
  • O CRM. Painel com fila de ação, leads com status e responsável editáveis na própria linha, funil de negócios em Kanban com anexos, tarefas da equipe, fila de reuniões, blog em blocos, imóveis, pessoas exibidas no site, análises comerciais e configurações que mudam o site sem novo deploy.
  • Tradução com revisão humana. Ao salvar um artigo, os outros dois idiomas são traduzidos em pedaços, sem nunca impedir o salvamento, e ficam marcados “a revisar” até uma pessoa revisar.
  • Privacidade de ponta a ponta. Consentimento no servidor, anonimização e exclusão com papéis diferentes, retenção automática diária e audiência medida sem cookie.
  • Operação escrita para pessoas. Runbook com rollback e um guia para quem não é técnico.

O que eu faria diferente

Centralizaria desde o começo cada regra de “quem pode” numa função só. Pessoas sumiam do seletor de anfitriões porque três arquivos tinham três versões da mesma regra; a correção virou uma regra única, com um teste que prova que é capaz de falhar.

Restrições

  • Site e CRM no mesmo Worker de borda, sem servidor próprio para manter.
  • Dados pessoais de leads, reuniões e visitantes sob a LGPD, do consentimento à exclusão.
  • Uma única pessoa técnica para construir e operar.
  • Números e contatos do site editáveis pelo time, sem novo deploy.

Decisões

Um Worker só, com o institucional pré-renderizado

Contexto
O site precisa de velocidade e de SEO em três idiomas; o CRM precisa de sessão e de banco. Dois projetos separados dobrariam deploy, domínio e configuração de segurança.
Escolha
Astro com as páginas institucionais pré-renderizadas e o CRM e as APIs sob demanda no mesmo Worker, com um ponto de entrada próprio só para acrescentar a rotina diária de retenção, que o adaptador do framework não expõe.
Ganhos
  • Um deploy, um domínio e um único conjunto de cabeçalhos de segurança.
  • Páginas institucionais servidas como arquivos, sem custo de servidor.
Custos
  • O ponto de entrada próprio precisa ser revisto a cada atualização do framework.

Uma escada de papéis para o menu e para a API, com recorte por dono

Contexto
Cinco papéis dividem o CRM. Esconder um item do menu não impede ninguém de chamar a API, e quem vende só deveria ver os próprios leads.
Escolha
Uma única escada de papéis decide o que o menu mostra e o que cada endpoint aceita. Para Vendas, leitura e escrita de leads e negócios são filtradas pelo dono.
Ganhos
  • O menu nunca oferece o que a API recusa.
  • O painel deixou de mostrar os dados pessoais de todos os leads a qualquer papel.
Custos
  • Cada tela nova precisa declarar o papel mínimo e o recorte, e ganhar testes para os dois.

Medição de audiência sem cookie

Contexto
A análise de tráfego da plataforma não contava visitantes únicos, e uma ferramenta de terceiros traria cookie, banner e dados saindo do sistema.
Escolha
Visitante único como um hash salgado de IP e navegador. O IP e o navegador nunca são gravados, o sal é gerado uma vez e fica fora da interface, e os registros vivem 120 dias.
Ganhos
  • Os números de que o time precisa, sem cookie e sem guardar dado pessoal.
Custos
  • Quem troca de rede ou de navegador conta como outra pessoa.

Reunião confirmada só quando uma pessoa assume

Contexto
Um agendamento automático prometeria uma reunião sem ninguém para conduzir, e dois pedidos simultâneos poderiam pegar o mesmo horário.
Escolha
O pedido nasce pendente e sem anfitrião, com o horário já travado no banco por inserção condicional e índice único parcial, com colisão por faixa sobreposta. O e-mail com o nome de quem conduz, o link da sala e o convite só sai quando alguém do time confirma.
Ganhos
  • O visitante nunca recebe uma promessa que ninguém vai cumprir.
  • Nenhum horário duplicado, nem com pedidos simultâneos.
Custos
  • Depende de o time esvaziar a fila; por isso ela fica no topo do painel e marca o horário que já passou.

Anonimizar e excluir com papéis diferentes

Contexto
Um titular pode pedir a exclusão dos seus dados, mas o funil precisa continuar somando certo.
Escolha
Gestor anonimiza: os dados pessoais somem e o registro fica nas métricas. Admin exclui de vez, e a auditoria guarda os metadados do que foi destruído. Uma rotina diária anonimiza leads não convertidos e reservas com mais de 24 meses e poda auditoria, visitantes e sessões vencidas.
Ganhos
  • As métricas do funil sobrevivem a um pedido de exclusão.
  • A retenção não depende de alguém lembrar.
Custos
  • Lead convertido fica fora da anonimização automática até a empresa decidir a janela.

Stack e por quê

Astro 5
Institucional pré-renderizado e CRM sob demanda no mesmo projeto.
TypeScript estrito
Regras de papel e de retenção tipadas de ponta a ponta.
Cloudflare Workers, D1 e R2
Site, APIs e CRM num Worker; banco SQLite e arquivos na borda.
Workers AI
Tradução do blog para os outros dois idiomas, sempre marcada para revisão humana.
Tailwind v4 e uma ilha React 19
Design system por tokens e JavaScript só no diagnóstico interativo.
Vitest
Testes de unidade, e suítes E2E que rodam contra o Worker construído.

Resultados

  • Cinco papéis numa única escada, usada pelo menu e pelos endpoints, com recorte por dono na leitura e na escrita.

    repositório privado auditadoCódigo de acesso e telas do CRM(Auditoria do repositório privado, set/2026)
  • 14 arquivos de teste de unidade com cerca de 200 casos, 5 suítes E2E que rodam contra o Worker construído e CI com checagem de tipos e testes.

    repositório privado auditadoTestes e workflow de CI do repositório(Auditoria do repositório privado, set/2026)
  • Revisão adversarial em sete dimensões, com cada achado confirmado por refutação antes de entrar na fila, e 54 correções numa única rodada.

    declaradoRegistro de auditoria do projeto

Ângulo de segurança

Superfície de ataque

  • Formulários públicos do site (diagnóstico, contato, aplicação e agendamento).
  • Sessões do CRM com cinco papéis.
  • Anexos de negócios e fotos de imóveis enviados pelo CRM.
  • Dados pessoais de leads, reuniões e visitantes.

Controles implementados

  • Sessão por token opaco, com só o hash no banco, e senhas com PBKDF2 e sal por usuário.
  • Checagem de mesma origem em todo POST e limite de tentativas de login por e-mail e por IP.
  • Consentimento exigido e carimbado no servidor.
  • Links de tarefa só em http e https, sempre mostrando o domínio de destino.
  • Source maps desligados em produção.

O que eu testaria hoje

  • Uma sessão de Vendas lendo ou alterando o lead de outra pessoa direto pela API.
  • Pedidos simultâneos para o mesmo horário ou para faixas sobrepostas.
  • Busca pelos dados de um lead depois da anonimização.

Evidências

  • repositório privado auditadoRepositório privado auditado(Auditoria do repositório privado, set/2026)