# REAPROVEITAMENTO.md — auditoria do Cacalutia One (2026-09-11)

Auditoria somente-leitura de `/home/ccltglobal1/one.cacalutia.com`, nada foi alterado lá. Critério:
**reaproveitar** (copiar o arquivo e adaptar nomes/tabelas, lógica já validada em produção),
**adaptar** (o padrão serve, mas a implementação precisa mudar de verdade) ou **não serve**
(específico do One, não aplica aqui). Todo trecho de código citado foi lido direto do arquivo
real nesta data — se este documento for reaberto muito depois, confira se o arquivo ainda existe
antes de confiar cegamente nele.

## 1. Autenticação, papéis e multi-tenant — REAPROVEITAR quase inteiro

Este é o bloco que mais se aplica sem adaptação, porque o modelo de papéis do planejamento
(`admin/Bruno`, `gerente de contas`, `cliente`, `vendedor do cliente`) mapeia quase 1:1 no
`super_admin/agencia/parceiro/cliente` que já existe.

| Arquivo do One | Linhas | Uso aqui |
|---|---|---|
| `src/services/auth.js` | — | **Reaproveitar inteiro**: `login`, `issueRefreshToken`/`refresh`/`logout` (refresh token de 32 bytes hex, SHA256 no banco), `forgotPassword`/`resetPassword` (SMTP com fallback pra log em dev), `createUser`/`updateUser`/`listUsers`. Só trocar `role` enum e o texto dos e-mails. |
| `src/middleware/auth.js` (77 linhas, lido inteiro) | — | **Reaproveitar inteiro**: `authenticate` (JWT Bearer), `requireRole(...roles)`, `requireModule(module)` (super_admin sempre passa; resto checa `user_modules`), `canAccessClient`/`requireClientAccess` (super_admin/agencia = qualquer cliente da própria agência; parceiro/cliente = só o que está em `user_clients`). Este é exatamente o modelo "papéis: admin, gerente de contas, cliente, vendedor do cliente" que o planejamento pede na seção 4 — a única mudança é nomear os papéis certo (ex.: `agencia`→ gerente de contas, `cliente`→ vendedor do cliente logado no portal). |
| Tabelas `users`, `user_clients`, `user_modules`, `refresh_tokens`, `password_resets` | — | Reaproveitar schema como está. `user_clients` já é exatamente "vendedor só vê os leads do próprio cliente" (seção 6.6, Portal do cliente). |
| Padrão multi-tenant (`client_id` em toda query, `agency_id` em `clients`) | — | Reaproveitar o padrão. Regra 10 do planejamento ("toda query filtra por client_id") é literalmente a mesma disciplina que o One já segue — nenhuma query no One filtra por outro caminho. |

**Adaptar**: nada aqui precisa de token de cliente criptografado (regra 12 do planejamento) — o
One guarda credenciais OAuth como JSON puro em `integrations.credentials` (ver seção 2). Se
Leads vai criptografar tokens no banco, isso é uma camada NOVA, não existe hoje no One pra copiar.

## 2. Meta Ads (mídia paga) — REAPROVEITAR o padrão OAuth, mas falta Lead Ads inteiro

`src/services/meta.js` (121 linhas, lido inteiro) só faz **gastos/insights** (escopo `ads_read`).
Não existe, em lugar nenhum do código, um handler de webhook do Meta (`leadgen`) nem qualquer
recepção de evento — só OAuth de saída e polling de API. Isso é esperado (o One não precisa
disso), mas significa que **a parte mais crítica do planejamento pro Meta (captação via Lead
Ads, seção 6.1) não tem nada pronto pra copiar** além do esqueleto de autenticação.

| Componente | Reaproveitar / Adaptar / Não serve |
|---|---|
| `getAuthUrl`/`exchangeCode` (fluxo OAuth, troca short→long-lived token) | **Adaptar**: mesmo padrão, mas o escopo aqui precisa ser bem maior — `leads_retrieval`, `pages_manage_metadata`, `ads_management`, `business_management` (seção 11 do planejamento) em vez de só `ads_read`. Cada escopo novo exige nova App Review — **atenção real**: o CLAUDE.md do One documenta um incidente (`read_insights` quebrando OAuth de todos os clientes ao ser adicionado sem aprovação) — não adicionar escopo novo ao app de produção sem aprovação confirmada primeiro. |
| `saveTokens`/`getTokens` via tabela `integrations` (`credentials` JSON) | **Reaproveitar o padrão**, adaptar pro schema novo (`ad_accounts` conforme seção 9). |
| `syncInsights` (paginação via `paging.next`, upsert em `ads_spend`) | **Reaproveitar o padrão de paginação e upsert** pra sincronizar gasto/campanha aqui também — a métrica de mídia entra no `cost_ledger` (seção 6.7). |
| Webhook `leadgen` (Meta Lead Ads) | **Não existe — construir do zero.** Precisa: endpoint público de verificação (`hub.challenge`), verificação de assinatura (`X-Hub-Signature-256`), resposta rápida + gravação crua em `inbound_events` ANTES de processar (regra 3 do planejamento). Nenhum arquivo do One faz isso hoje — nem o Social Poster (que só faz OAuth + publish, não recebe webhook de ninguém). |
| Click-to-WhatsApp webhook (WhatsApp Cloud API) | **Não existe.** Mesma lacuna do item acima — Social Poster usa Graph API pra postar, não WhatsApp Cloud API pra conversar. Este é o componente novo mais crítico da Fase 1. |

## 3. Google Ads — REAPROVEITAR quase inteiro (é o melhor exemplo de multi-tenant com conta de agência)

`src/services/googleAds.js` (281 linhas, lido inteiro) é o modelo mais maduro do One pra "uma
autorização da agência, N contas de cliente" — exatamente o padrão que a seção 15.4 do
planejamento ("BM da Cacalutia com N contas de cliente") precisa pro lado Google.

- **Reaproveitar inteiro**: `createOAuth2Client`/`getAuthUrl`/`exchangeCode` (escopo `adwords`
  isolado — comentário no topo do arquivo já avisa pra nunca misturar scope entre esse arquivo e
  GSC/GA4, por causa de um incidente real documentado); `saveAgencyTokens`/`getAgencyRow` em
  `agency_integrations` (token da agência, separado de `integrations` que é por cliente);
  `getAccessToken` com renovação automática via `oauth2.getAccessToken()`; `gaqlRequest` (POST
  cru pra Google Ads API via GAQL, sem lib nova); `detectMccId` (heurística real pra achar qual
  conta é o MCC entre as acessíveis — bug real corrigido, documentado inline); `acquireSyncLock`/
  `releaseSyncLock` (proteção contra sync duplicado via coluna `syncing`).
- **Adaptar**: `syncGoogleAds` grava em `ads_spend` (schema do One) — aqui viraria gravação em
  `cost_ledger`/tabela de campanha equivalente. O conceito (backfill 90 dias na 1ª sync, 7 dias
  depois) é reaproveitável direto.
- Webhook de formulário de lead do Google Ads (seção 6.1) — **não existe no One**, mesma lacuna
  do Meta. Mas a base de autenticação/API já pronta reduz bastante o trabalho aqui comparado ao
  Meta.

## 4. GA4 e GSC — REAPROVEITAR, uso mais restrito aqui

`src/services/google.js` (274 linhas, GSC) e `src/services/ga4.js` (469 linhas) cobrem OAuth +
sync + query. Pro planejamento, o uso é bem mais estreito: só "funil das landing pages" (seção
4) — não precisa de todo o aparato de keywords/tracking que o GSC tem no One.

- **Reaproveitar o padrão de OAuth** (`google.js` linhas 1-26: client, `getAuthUrl`, `exchangeCode`,
  `saveTokens`/`getTokens` em `integrations`) pra GA4 aqui — é o esqueleto mais simples de
  copiar, ignorando toda a parte de keywords/`gsc_pages`/`keyword_page_map` que não interessa.
- **Não serve**: a lógica de auto-track top-50 (`syncSearchAnalytics` linhas 156-171) e todo o
  aparato de keyword tracking — específico do Pilar de Atração do One, sem equivalente no
  planejamento de Leads.
- GA4 aqui mede só sessões/funil da landing page (comportamento) — reaproveitar apenas a parte
  de "sessões por dia" e "eventos de funil" de `ga4.js`, não a parte de e-commerce/receita (que
  nem existe pra usar — regra do One já proíbe GA4 como fonte de receita, e aqui a receita nem é
  medida via GA4 de jeito nenhum).

## 5. Frontend — Design tokens: ADAPTAR, não reaproveitar cegamente (achado importante)

**O planejamento (seção 16.1) descreve o One como tendo tema escuro `#0D0F12` por padrão, com
DM Sans/DM Mono.** Isso está desatualizado — o `referencia-visual.html` foi feito com base numa
versão anterior do One. Tokens reais, lidos direto de `client/src/main.css` nesta auditoria:

```css
--font-sans: "Inter"          /* não é DM Sans */
--color-bg: #F4F5F7           /* tema CLARO, não escuro */
--color-surface: #EDEEF1
--color-card: #FFFFFF
--color-border: #E5E7EB
--color-sidebar: #0B1120      /* só a sidebar é escura */
--color-lime: #CFFF06         /* única cor de marca — não existe azul/violeta/ciano no One */
--color-lime-dim: #9ABF04
--color-lime-dark: #4A5A02
--color-text: #1A1D26
--color-up: #16A34A / --color-down: #DC2626 / --color-warn: #D97706
```

Não existe `--color-primary`, nem paleta azul/violeta/ciano — é lima como cor única de destaque
sobre fundo claro, com sidebar escura fixa. O `referencia-visual.html` do planejamento (fundo
`#0D0F12`, azul `#4F8EF7`, violeta `#7B5CF0`, ciano `#22D3EE`, DM Sans/DM Mono) é uma direção
**completamente diferente** da atual do One — não "evolução", uma paleta nova do zero.

**Decisão que precisa ser tomada com o usuário antes de montar o design system** (não assumir):
(a) usar a base real do One (claro + Inter + lima) pra reconhecimento de marca entre os dois
produtos, ou (b) seguir a direção do `referencia-visual.html` (escuro + azul/violeta/ciano/lima +
DM Sans/DM Mono) como identidade própria do Leads, justificável pelo tom "sala de controle ao
vivo" que o próprio planejamento pede. Nos dois casos, `--color-lime #CFFF06` seria o fio comum
com o One (é a cor do logo da Cacalutia nos dois casos, conforme seção 16.2 do planejamento).

Stack de frontend: sem `client/package.json` separado — é **um único `package.json`** na raiz do
One com backend e frontend juntos (React 19, Tailwind 4 via `@tailwindcss/vite` — **sem arquivo
`tailwind.config.js`**, tokens vivem em `@theme` dentro do próprio CSS, Vite 8, Recharts 3.8,
`lucide-react` pros ícones, `react-router-dom` 7). **Reaproveitar essa stack exata** — é recente,
sem problema de compatibilidade conhecido, e mantém as duas equipes (se houver) na mesma stack.

| Componente/arquivo | Reaproveitar / Adaptar |
|---|---|
| `client/src/main.css` (tokens `@theme`, `.animate-live` pulse, `.skeleton` shimmer, foco de teclado) | **Reaproveitar o mecanismo** (Tailwind 4 `@theme`, sem config file) — trocar só os valores dos tokens conforme a decisão de paleta acima. `.animate-live` (pulse em lima) é literalmente o efeito "ponto pulsando pra ao vivo" que a seção 16.5 do planejamento pede — não reinventar. |
| `client/src/components/KPICard.jsx` (69 linhas, lido inteiro) | **Reaproveitar quase inteiro** — já tem sparkline SVG sem lib, formatação BRL (`toLocaleString('pt-BR')`), tag de variação ↑/↓ com cor semântica. É o componente-base certo pros KPIs do cockpit financeiro (seção 6.7). |
| `client/src/components/Layout.jsx` (90 linhas, lido inteiro) — padrão de cliente selecionado via URL (`/c/:clientSlug/...`), sidebar fixa, `Outlet context` pra passar `selectedClient` pras páginas | **Reaproveitar o padrão inteiro** — "a URL é a única fonte de verdade do cliente selecionado" é uma decisão de arquitetura madura (documentada no próprio comentário do arquivo) que evita bug de estado dessincronizado. Adaptar só o nome das rotas. |
| `Sidebar.jsx`, `TopBar.jsx` | **Adaptar**: estrutura (nav com grupos, badge de contagem tipo o `.count` do referencia-visual) reaproveitável, mas os itens de menu são todos do One (Cortex, Atração, etc.) — trocar pelos do planejamento (Visão geral, Central de conversas, Leads, Agentes e roteiros, Experimentos, Cockpit financeiro, Clientes e contratos, Prospecção). |
| Gráficos (Recharts) | **Não há wrapper genérico no One** — cada página do One monta o `<AreaChart>`/`<BarChart>` inline. O planejamento pede (seção 16, fim) "criar primeiro... wrappers do Recharts com os gradientes" — isso é trabalho novo aqui, não uma cópia. O `referencia-visual.html` usa SVG à mão (sem Recharts) pros gráficos da visão geral — decidir se mantém SVG à mão (visual mais controlado, zero dependência) ou migra pra Recharts (consistente com o resto do app, menos código pra manter). |

## 6. Padrões de infraestrutura — REAPROVEITAR a maioria, com uma lacuna grande (jobs duráveis)

| Padrão | Arquivo | Reaproveitar / Adaptar / Não serve |
|---|---|---|
| Pool de conexão MySQL | `src/config/database.js` (18 linhas) | **Reaproveitar inteiro** — inclusive o comentário sobre `charset: 'utf8mb4'` (bug real de emoji virando `?` sem isso). |
| Cron agendado | `src/services/socialCron.js` (28 linhas, modelo mais simples), `analyticsCron.js` (429 linhas, modelo com `sync_log`) | **Adaptar**: o padrão de lock em memória (`let xRunning = false`, evita sobreposição de tick) é bom mas **não é o mesmo que jobs duráveis** — é só pra evitar overlap dentro do MESMO processo. O planejamento (seção 8.1) pede tabela `jobs` com retry/backoff/dead-letter sobrevivendo a reinício — isso **não existe em lugar nenhum do One**. Nenhum cron do One tem retry automático nem sobrevive a reinício de processo — cada cron falho só loga erro e tenta de novo no próximo ciclo agendado. **Este é o maior gap de infraestrutura pra construir do zero.** |
| Múltiplos processos PM2 no mesmo `server.js` | `src/server.js` (16 linhas) | **Não serve como está**: todos os crons do One rodam dentro do MESMO processo Express (`require()` depois do `app.listen`). O planejamento pede worker em **processo PM2 separado** do servidor web (seção 8.1) — arquitetura diferente, precisa de dois entry points e dois blocos no `ecosystem.config.js`, não um `server.js` que já existe. |
| Deploy PM2 | `ecosystem.config.js` do One (não lido em detalhe nesta auditoria, mas padrão já documentado no CLAUDE.md do projeto) | **Reaproveitar o padrão de deploy** (cwd, error_file, out_file por processo) — só duplicar a entrada pro worker novo. |
| Idempotência via `UNIQUE`+`ON DUPLICATE KEY UPDATE` | Usado em `meta.js`, `googleAds.js`, `google.js` (todo sync) | **Reaproveitar o padrão** — é exatamente a técnica que a regra 3 do planejamento pede pra idempotência de sync, só falta aplicar também a webhooks (que o One nunca recebeu) e a envios de mensagem (novo). |

## 7. IA / Claude — REAPROVEITAR o padrão de honestidade, adaptar o resto

O One já tem pelo menos 4 usos de Claude com o mesmo padrão de "nunca inventar além do dado
fornecido" (Agente de SEO, classificação de leads do módulo `leads_gen` que já existe no One —
ver abaixo, Kanban card generation, copiloto de imagem). Vale a pena ler `src/services/
leadsClassify.js` e `src/services/leadsEnrichment.js` do One antes de escrever os equivalentes
aqui — são o precedente mais próximo (mesmo domínio: qualificação de lead com IA + honestidade de
produto), só que mais simples (sem conversa multi-turno via WhatsApp, sem intenções, sem
handoff). Não reaproveitar client_id/schema deles diretamente — são de outro módulo, outro
propósito (o `leads_gen` do One é geração de leads PARA os clientes da Cacalutia dentro da
plataforma de marketing intelligence, não o serviço "Cacalutia Leads" novo — nomes parecidos,
produtos diferentes, não confundir os dois ao migrar/ler código).

**Atenção real, já documentada no CLAUDE.md do One**: variação de escopo/modelo em produção já
quebrou OAuth de todos os clientes uma vez (`read_insights`). Qualquer novo app/escopo do Meta
pra este projeto (WhatsApp Cloud API, Lead Ads) deve ser testado num app Meta separado ou com
extremo cuidado de não mexer no app de produção do One por engano.

## Resumo pra quem não é dev

- O que dá pra copiar quase pronto: login/permissões (admin, gerente, cliente), a forma como o
  sistema já conversa com o Google Ads (é o exemplo mais maduro do One), a base de como conectar
  ao Meta (só a parte de "gastos", não a de "receber leads"), o cartão de KPI da tela, e como o
  cliente selecionado fica sempre na URL.
- O que precisa ser adaptado, não copiado: a base de cores e fontes do One mudou desde que a
  referência visual foi desenhada — precisa decidir de novo se o Leads usa a paleta clara atual
  do One ou a paleta escura nova da referência.
- O que não existe em lugar nenhum e precisa ser construído do zero: receber leads do Facebook/
  Google automaticamente (webhook), conversar pelo WhatsApp, e principalmente o sistema de "não
  perder nenhum lead mesmo se o servidor reiniciar" (jobs duráveis) — hoje o One não tem nada
  parecido com isso, cada sincronização dele é mais simples e não precisa dessa garantia.
