Comando: cat projects/edge-crm.md
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
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)