mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
docs(S9,S10): planos de intenção — captura de novidades na home + pixel Meta na página de campanha
This commit is contained in:
parent
484ed4a424
commit
d8d85de7be
6 changed files with 403 additions and 0 deletions
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-desktop.png
Normal file
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-desktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-mobile.png
Normal file
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-sucesso.png
Normal file
BIN
docs/plans/captura-novidades-home-campanha-ui-draft-sucesso.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
237
docs/plans/captura-novidades-home-campanha-ui-draft.html
Normal file
237
docs/plans/captura-novidades-home-campanha-ui-draft.html
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
<!doctype html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
<title>UI draft — Captura de novidades na home de campanha</title>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-100 antialiased">
|
||||
<main class="mx-auto max-w-5xl p-8">
|
||||
<p class="text-sm text-zinc-400">
|
||||
Visitante da home de campanha demonstra apoio e deixa o contato para receber comunicações
|
||||
(e-mail ou grupos de WhatsApp) — CTA do hero leva à seção de captura na própria página.
|
||||
</p>
|
||||
|
||||
<section data-shot="desktop" class="mt-6 overflow-hidden rounded-xl border border-zinc-800">
|
||||
<div class="bg-zinc-900 px-10 pt-12 pb-8">
|
||||
<div class="flex gap-8">
|
||||
<div class="flex-1">
|
||||
<div class="h-3 w-24 rounded bg-zinc-700"></div>
|
||||
<div class="mt-4 h-12 w-72 rounded bg-zinc-700"></div>
|
||||
<div class="mt-2 h-12 w-64 rounded bg-zinc-700"></div>
|
||||
<div class="mt-5 space-y-2">
|
||||
<div class="h-2 w-96 rounded bg-zinc-700"></div>
|
||||
<div class="h-2 w-80 rounded bg-zinc-700"></div>
|
||||
<div class="h-2 w-88 rounded bg-zinc-700"></div>
|
||||
</div>
|
||||
<div class="mt-7 flex gap-3">
|
||||
<div
|
||||
class="inline-flex h-11 items-center justify-center rounded-[10px] bg-red-600 px-5 text-sm font-extrabold text-white"
|
||||
>
|
||||
Quero apoiar
|
||||
</div>
|
||||
<div
|
||||
class="inline-flex h-11 items-center justify-center rounded-[10px] border-2 border-zinc-300 px-5 text-sm font-extrabold text-zinc-100"
|
||||
>
|
||||
Receba novidades
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 flex gap-8">
|
||||
<div class="h-2 w-40 rounded bg-zinc-700"></div>
|
||||
<div class="h-2 w-40 rounded bg-zinc-700"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden w-64 shrink-0 lg:block">
|
||||
<div class="h-72 w-48 rounded-lg bg-zinc-700/60"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-zinc-100 px-10 py-12 text-zinc-900">
|
||||
<div class="mx-auto max-w-2xl text-center">
|
||||
<div class="mx-auto h-2 w-28 rounded bg-zinc-400"></div>
|
||||
<div class="mx-auto mt-4 h-8 w-96 rounded bg-zinc-400"></div>
|
||||
<div class="mx-auto mt-3 h-2 w-80 rounded bg-zinc-400"></div>
|
||||
<div class="mx-auto mt-3 h-2 w-72 rounded bg-zinc-400"></div>
|
||||
</div>
|
||||
<div class="mx-auto mt-8 max-w-3xl space-y-4">
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Nome completo*
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
WhatsApp (com DDD)*
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
E-mail (opcional)
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Estado (opcional)
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Cidade (opcional)
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="h-20 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Comentário (opcional)
|
||||
</div>
|
||||
<div class="rounded-lg border border-zinc-300 bg-white p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
class="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded border border-red-600 bg-red-600 text-xs font-bold text-white"
|
||||
>
|
||||
✓
|
||||
</div>
|
||||
<div class="text-sm text-zinc-800">
|
||||
<strong>Quero fazer parte do time:</strong> receber novidades com frequência, ser
|
||||
adicionado(a) aos grupos de WhatsApp da campanha e participar das ações.
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Sem marcar, você recebe apenas comunicações esporádicas da campanha — sem grupos e
|
||||
sem envios frequentes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-auto mt-4 max-w-3xl">
|
||||
<div
|
||||
class="inline-flex h-12 w-full items-center justify-center rounded-lg bg-red-600 text-sm font-extrabold text-white"
|
||||
>
|
||||
QUERO RECEBER NOVIDADES
|
||||
</div>
|
||||
</div>
|
||||
<p class="mx-auto mt-4 max-w-xl text-center text-xs text-zinc-500">
|
||||
Ao enviar, você demonstra apoio à campanha e escolhe como quer acompanhar: comunicações
|
||||
frequentes e grupos de WhatsApp (marcando a opção acima) ou comunicações esporádicas —
|
||||
conforme a Política de Privacidade (LGPD).
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
data-shot="mobile"
|
||||
class="mt-6 w-[390px] overflow-hidden rounded-xl border border-zinc-800"
|
||||
>
|
||||
<div class="bg-zinc-900 px-5 pt-8 pb-6">
|
||||
<div class="h-3 w-20 rounded bg-zinc-700"></div>
|
||||
<div class="mt-4 h-9 w-56 rounded bg-zinc-700"></div>
|
||||
<div class="mt-2 h-9 w-48 rounded bg-zinc-700"></div>
|
||||
<div class="mt-4 space-y-2">
|
||||
<div class="h-2 w-72 rounded bg-zinc-700"></div>
|
||||
<div class="h-2 w-60 rounded bg-zinc-700"></div>
|
||||
</div>
|
||||
<div class="mt-6 flex flex-col gap-2">
|
||||
<div
|
||||
class="inline-flex h-11 items-center justify-center rounded-[10px] bg-red-600 px-5 text-sm font-extrabold text-white"
|
||||
>
|
||||
Quero apoiar
|
||||
</div>
|
||||
<div
|
||||
class="inline-flex h-11 items-center justify-center rounded-[10px] border-2 border-zinc-300 px-5 text-sm font-extrabold text-zinc-100"
|
||||
>
|
||||
Receba novidades
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-zinc-100 px-5 py-8 text-zinc-900">
|
||||
<div class="mx-auto h-2 w-24 rounded bg-zinc-400"></div>
|
||||
<div class="mx-auto mt-4 h-7 w-72 rounded bg-zinc-400"></div>
|
||||
<div class="mx-auto mt-3 h-2 w-64 rounded bg-zinc-400"></div>
|
||||
<div class="mt-6 space-y-3">
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Nome completo*
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
WhatsApp (com DDD)*
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
E-mail (opcional)
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Estado (opcional)
|
||||
</div>
|
||||
<div
|
||||
class="h-12 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Cidade (opcional)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div
|
||||
class="h-20 rounded-lg border border-zinc-300 bg-white px-4 py-3 text-sm text-zinc-500"
|
||||
>
|
||||
Comentário (opcional)
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 rounded-lg border border-zinc-300 bg-white p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
class="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded border border-red-600 bg-red-600 text-xs font-bold text-white"
|
||||
>
|
||||
✓
|
||||
</div>
|
||||
<div class="text-sm text-zinc-800">
|
||||
<strong>Quero fazer parte do time:</strong> receber novidades com frequência, ser
|
||||
adicionado(a) aos grupos de WhatsApp da campanha e participar das ações.
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-zinc-500">
|
||||
Sem marcar, você recebe apenas comunicações esporádicas da campanha — sem grupos e sem
|
||||
envios frequentes.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div
|
||||
class="inline-flex h-12 w-full items-center justify-center rounded-lg bg-red-600 text-sm font-extrabold text-white"
|
||||
>
|
||||
QUERO RECEBER NOVIDADES
|
||||
</div>
|
||||
</div>
|
||||
<p class="mx-auto mt-4 max-w-xs text-center text-xs text-zinc-500">
|
||||
Ao enviar, você demonstra apoio à campanha e escolhe como quer acompanhar: comunicações
|
||||
frequentes e grupos de WhatsApp (marcando a opção acima) ou comunicações esporádicas —
|
||||
conforme a Política de Privacidade (LGPD).
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section data-shot="sucesso" class="mt-6 overflow-hidden rounded-xl border border-zinc-800">
|
||||
<div class="bg-zinc-100 px-10 py-16 text-center text-zinc-900">
|
||||
<div class="mx-auto h-10 w-10 rounded-full border-2 border-zinc-400"></div>
|
||||
<div class="mx-auto mt-5 h-7 w-80 rounded bg-zinc-400"></div>
|
||||
<p class="mx-auto mt-4 max-w-md text-sm text-zinc-600">
|
||||
Você vai receber as novidades da campanha. Enquanto isso, acompanhe as bandeiras da
|
||||
campanha abaixo.
|
||||
</p>
|
||||
<div
|
||||
class="mx-auto mt-6 h-11 w-48 rounded-lg border-2 border-zinc-300 bg-white text-sm font-extrabold text-zinc-700"
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
90
docs/plans/captura-novidades-home-campanha.md
Normal file
90
docs/plans/captura-novidades-home-campanha.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Captura de novidades da campanha na home pública
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-19
|
||||
Issue: #93
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: B — encaixe na home de campanha (CTA do hero + nova seção de captura)
|
||||
Rascunho UI: docs/plans/captura-novidades-home-campanha-ui-draft.html + PNGs embutidos abaixo
|
||||
Appetite: ~1–1,5 dia eng; seção de captura na home + CTA no hero + ação transacional com consentimento novo fail-closed
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
O site público de campanha (home `jorgesolla1313.com.br`) hoje converte visitante em **doação** (CTA "Quero apoiar") e em **comunidade WhatsApp** (`/mandato-no-whatsapp`), mas não captura o visitante que demonstra apoio e quer acompanhar a campanha sem necessariamente doar. Sem esse degrau, o tráfego orgânico e pago da home sai sem deixar contato, e o time não tem lista própria de interesse para comunicações (novidades, agenda, ações) e para grupos de WhatsApp da campanha. A campanha está em janela eleitoral (propaganda iniciada 16/08, 1º turno 04/10) — cada visitante não capturado é audiência perdida para as semanas decisivas.
|
||||
|
||||
A captura tem dupla função, confirmada com produto: o contato é **um sinal de apoio** a Solla (a pessoa se dispõe a receber comunicações da campanha) **e** a porta de entrada para comunicações por e-mail **ou inclusão em grupos de WhatsApp da campanha** — por isso o telefone é campo obrigatório.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** visitante da home de campanha (eleitor simpatizante ou indeciso que quer acompanhar), navegando no celular ou no desktop; demonstra apoio deixando o contato para receber comunicações.
|
||||
- **Job principal:** deixar o contato em segundos (nome + WhatsApp) para receber novidades da campanha, sem sair da página, escolhendo o nível de engajamento.
|
||||
- **Fluxo desejado:**
|
||||
1. Chega na home e vê o CTA secundário do hero apontando para a captura (substitui "Conhecer bandeiras").
|
||||
2. Preenche nome + WhatsApp (obrigatórios) e, opcionalmente, e-mail, estado, cidade e comentário, numa seção da própria home.
|
||||
3. Decide o nível de engajamento num toggle **pré-selecionado** "Quero fazer parte do time": marcado = comunicações frequentes + inclusão em grupos de WhatsApp da campanha + participação nas ações; desmarcado = apenas comunicações esporádicas, sem grupos e sem envios frequentes.
|
||||
4. Envia; a seção vira confirmação in-place ("Inscrição confirmada").
|
||||
5. O registro vira um contato com consentimento próprio **e a escolha do toggle gravada** (nível "time" vs "esporádico"), visível no admin junto das demais listas públicas.
|
||||
- **Anti-goals de produto:** segundo cadastro de pessoa paralelo a `Contact`; gravar `supporter` (registro nominal interno da campanha — bloqueado pelo lote jurídico da Onda 0; este fluxo é captura pública com consentimento próprio, não o registro de apoiador interno); virar mini-CRM com segmentação/fase do funil; mesclar com o fluxo `/mandato-no-whatsapp` (comunidade do mandato, consentimento `whatsapp-inscricao` — canal e semântica diferentes).
|
||||
|
||||
### Rascunho UI (B)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Fonte iterável: `docs/plans/captura-novidades-home-campanha-ui-draft.html`.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Visitante da home consegue demonstrar apoio e deixar **nome + WhatsApp** (obrigatórios) para receber comunicações da campanha, com e-mail, estado, cidade e comentário opcionais, e confirmação imediata na própria página.
|
||||
- **Toggle "Quero fazer parte do time" pré-selecionado**: marcado = comunicações frequentes + inclusão em grupos de WhatsApp da campanha; desmarcado = apenas comunicações esporádicas (sem grupos, sem envios frequentes). A **escolha fica gravada no registro** — o admin distingue quem é "time" de quem é "esporádico".
|
||||
- O CTA secundário do hero ("Conhecer bandeiras") vira o atalho para a seção de captura — as bandeiras continuam acessíveis na navegação da própria home (âncora `#bandeiras` já existe; o fluxo de captura não pode escondê-las).
|
||||
- O registro é gravado como contato + vínculo de assinatura com **consentimento novo** (não reutiliza `whatsapp-inscricao`), no padrão fail-closed dos fluxos públicos existentes: sem o(s) texto(s) de consentimento aprovado(s) configurado(s) no admin, o form recusa a captura (nenhum dado é gravado).
|
||||
- O(s) texto(s) do consentimento cobre(m) os dois níveis — "fazer parte do time" (comunicações frequentes + grupos de WhatsApp) e "esporádico" — aprovado(s) pelo jurídico antes da ativação.
|
||||
- Guardrail LGPD: nenhuma captura antes do(s) documento(s) de consentimento (chave estável nova) existir(em) no admin — o executor resolve por chave, não por ID; a estrutura exata do consentimento (um texto com dois níveis vs. dois textos) é decisão de implementação junto do jurídico.
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — a captura é o dado; o consumo (quantidade de inscritos, crescimento) é leitura do admin existente, sem superfície nova.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** home `src/app/(frontend)/(home)/page.tsx` (nova seção + composição), hero `src/components/CampaignHero.tsx` (troca do CTA secundário), componente de formulário cliente em `src/components/` no padrão `WhatsappForm` (campos `NameInput`/`PhoneInput`/`EmailInput`/`StateSelect`/`CitySelect` já existem e são reutilizáveis), action em `src/app/(frontend)/actions/` no padrão `submitWhatsapp` (transação `Contact` + `Subscription` com consent por chave estável, `requireConsentByKey` fail-closed), chave nova em `src/lib/campaignConsentKeys.ts`.
|
||||
- **Precedente a olhar:** `src/app/(frontend)/actions/submitWhatsapp.ts` (transação + consent), `src/components/WhatsappForm.tsx` (form e inputs), `src/lib/schemas/whatsapp-form.ts` (schema base `contactSchema` — obrigatoriedade difere: aqui nome + telefone), `/mandato-no-whatsapp` (página irmã — **não** mesclada nesta fatia).
|
||||
- **Risco de acoplamento:** a home é superfície compartilhada do trilho S (últimos itens S1–S6) — toca o mesmo arquivo que o item S8 (pixel) tocará; serializado por dependência.
|
||||
|
||||
## Dependências
|
||||
|
||||
- Nenhuma dura. **S10** (pixel da home) depende deste item para disparar `Lead` no sucesso do form.
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Mescla com `/mandato-no-whatsapp` ou reuso do consentimento `whatsapp-inscricao`.
|
||||
- Gravação em `supporter` (registro nominal interno da campanha) — permanece bloqueado pelo lote jurídico da Onda 0.
|
||||
- Segmentação, tags de interesse, double opt-in por e-mail, integração com ferramenta de e-mail marketing — anotar como gatilho futuro se marketing pedir.
|
||||
- Redesign do hero ou da home (mudança de um CTA + uma seção).
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Mini-CRM.** Se alguém "só completar": campos extras, segmentação, fases de funil. **Corte neste item:** os 6 campos do rascunho (nome + WhatsApp obrigatórios; e-mail, estado, cidade, comentário opcionais) e nada mais; o vínculo reutiliza o modelo de assinatura existente.
|
||||
- **"Já que o telefone é obrigatório, vira apoiador do sistema interno".** Puxa o registro nominal bloqueado juridicamente. **Corte:** o registro vive nas listas públicas de contato/assinatura com consentimento próprio; `supporter` só quando o lote jurídico liberar.
|
||||
- **"Um consentimento só para tudo" ou "dois consents mas um só registro".** A escolha do toggle tem que sobreviver no dado, senão o time não sabe quem pode entrar em grupo. **Corte:** a escolha fica gravada e visível no admin; a forma (um texto com os dois níveis vs. dois textos) é decisão de implementação com o jurídico.
|
||||
- **Form igual ao do WhatsApp.** Copiar a semântica do "comunidade do mandato" arrasta canal e consentimento errados. **Corte:** consentimento novo; fluxos permanecem irmãos, não gêmeos.
|
||||
- **Double opt-in / verificação de e-mail.** Vira infraestrutura de e-mail marketing. **Corte:** confirmação in-place sem envio de e-mail; gatilho futuro se marketing pedir.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Texto(s) do consentimento?** Novo texto cobrindo os dois níveis — "fazer parte do time" (comunicações frequentes + grupos de WhatsApp + participação nas ações) e "esporádico" (comunicação direta, sem grupos/sem frequência) — com chave estável nova, resolvida fail-closed. **Recomendação:** o jurídico aprova o(s) texto(s) e o admin cria o(s) documento(s) antes da ativação — o app não captura sem ele(s); a chave exata e a estrutura (um vs. dois textos) ficam para a implementação junto do jurídico. _(decisões de campos/local/toggle/Lead já confirmadas com produto em 2026-08-19; só o texto jurídico fica pendente de aprovação)_
|
||||
|
||||
## Referências
|
||||
|
||||
- Rascunho UI (gate): `docs/plans/captura-novidades-home-campanha-ui-draft.html` + PNGs embutidos acima
|
||||
- `src/app/(frontend)/actions/submitWhatsapp.ts` — padrão de escrita transacional com consent fail-closed
|
||||
- `src/components/WhatsappForm.tsx`, `src/lib/schemas/whatsapp-form.ts` — padrão de form cliente e schema
|
||||
- `src/lib/campaignConsentKeys.ts` — keys estáveis existentes
|
||||
- `src/components/CampaignHero.tsx` — CTA "Conhecer bandeiras" (linha ~104–114) a substituir
|
||||
- `AGENTS.md` — `Contact` como pessoa normalizada + joins, consentimento por chave estável, transações multi-collection, bloqueio jurídico de `supporter` (Onda 0)
|
||||
76
docs/plans/pixel-meta-pagina-campanha.md
Normal file
76
docs/plans/pixel-meta-pagina-campanha.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Pixel do Meta (Facebook) na página pública de campanha
|
||||
|
||||
Status: registrado
|
||||
Atualizado em: 2026-08-19
|
||||
Issue: #94
|
||||
Priority: P1
|
||||
Model: composer-2.5
|
||||
Impeccable: A — N/A (campo único no admin replicando precedente aceito + script invisível ao visitante; zero superfície pública nova)
|
||||
Rascunho UI: N/A — sem UI
|
||||
Appetite: ~0,5–1 dia eng; campo admin + injeção do base code na home + `Lead` no sucesso do form de captura
|
||||
Responsável: —
|
||||
|
||||
## Intenção
|
||||
|
||||
O time de campanha paga roda tráfego no Meta direcionado à home pública de campanha, mas hoje não vê nada: sem Pixel, o Events Manager não registra visitas nem conversões dessa página, e as campanhas otimizam às cegas (sem retargeting, sem evento de conversão). Nos abaixo-assinados o time já configura o ID do Pixel por documento (`petition.tracking.facebookPixelId`, entregue 2026-07-21); a home de campanha precisa do mesmo instrumento em nível de site — um campo no admin para o ID numérico do Dataset, injetado na página pública de campanha, e o evento `Lead` quando a captura de novidades (S9) for concluída. Em janela eleitoral (1º turno 04/10), cada semana sem atribuição é verba paga sem feedback.
|
||||
|
||||
Este item revisita a decisão adiada do plano `pixel-meta-abaixo-assinado` ("Pixel / Dataset global em SiteSettings — revisitar quando o mesmo ID for colado em ≥3 petições e o admin reclamar de repetição"): produto agora pede explicitamente um Pixel de site para a página de campanha — o gatilho foi puxado, o precedente segue intacto para os abaixo-assinados.
|
||||
|
||||
## Persona e fluxo
|
||||
|
||||
- **Persona / contexto:** marketing digital / analista de campanha paga no Meta, no admin; quer ver visitas e conversões da home de campanha no Events Manager do Dataset.
|
||||
- **Job principal:** configurar um Pixel no admin (colar só o ID numérico) e ver a home de campanha alimentar o Dataset sem colar JavaScript.
|
||||
- **Fluxo desejado:**
|
||||
1. Editor no `/admin` cola o ID numérico do Pixel no campo de rastreamento das configurações do site.
|
||||
2. A home pública de campanha carrega o base code do Meta (`PageView`) quando o ID está presente e válido.
|
||||
3. Quando o visitante conclui a captura de novidades (S9), exatamente um `Lead` é disparado.
|
||||
4. O Events Manager mostra PageViews e Leads da página de campanha para otimização/retargeting.
|
||||
- **Anti-goals de produto:** colar snippet HTML no admin (XSS); Pixel vazando PageViews do resto do site (notícias, etc.); CAPI/Advanced Matching nesta fatia; cookie banner/CMP nesta fatia.
|
||||
|
||||
## Objetivo e aceite
|
||||
|
||||
- Campo opcional "ID do Pixel do Meta" nas configurações do site (admin), com a mesma validação dos abaixo-assinados (somente ID numérico, 5–20 dígitos, sem HTML) e a mesma normalização no save.
|
||||
- Quando o ID está configurado e válido, a home pública de campanha carrega o base code + `PageView`; sem ID, nada é carregado (fail-closed, zero impacto).
|
||||
- Quando a captura de novidades (S9) é concluída com Pixel ativo, dispara exatamente um `Lead` (nunca no page load) — mesmo padrão da petição.
|
||||
- Guardrails: nunca persistir nem executar HTML/JS do editor; sem env var obrigatória; cache da home revalidado pela edição do admin (o hook de revalidação do global já existe).
|
||||
|
||||
## Dados (intenção)
|
||||
|
||||
- **Vou apresentar dados?** Não — o dado (PageView/Lead) vive no Meta Events Manager; o app só emite o evento.
|
||||
|
||||
## Direção no codebase (hipótese)
|
||||
|
||||
- **Áreas prováveis:** global `src/globals/SiteSettings.ts` (campo único, provável dono — o plano anterior já apontava `SiteSettings` para um Pixel global; a revalidação `revalidateGlobal('site-settings')` já existe), home `src/app/(frontend)/(home)/page.tsx` (injeção do `<MetaPixel />`), `src/components/MetaPixel.tsx` + `src/lib/facebookPixel.ts` (reuso direto do precedente), form de captura do S9 (disparo do `Lead` no sucesso, no padrão `PetitionForm`).
|
||||
- **Precedente a olhar:** `docs/plans/pixel-meta-abaixo-assinado.md` (decisões travadas: persistir só o ID, nunca snippet; `Lead` só no sucesso; validação e normalização reutilizadas), `src/collections/Petition.ts` (grupo `tracking` + `validate` + `beforeChange`), `src/app/(frontend)/abaixo-assinado/[id]/page.tsx` (injeção condicional).
|
||||
- **Risco de acoplamento:** toca a home (mesmo arquivo do S9) e o `SiteSettings` (global lido por outras superfícies do site) — serializado por dependência; a leitura do global na home deve ser compatível com o caching da página (decisão de implementação, não de produto).
|
||||
|
||||
## Dependências
|
||||
|
||||
- **S9** (captura de novidades) — necessária só para o `Lead` no sucesso do form; o `PageView` na home é independente. Registrada como dependência para o `Lead` sair junto.
|
||||
|
||||
## Fora de escopo
|
||||
|
||||
- Pixel nas demais páginas do site (notícias, artigos, privacidade) — o pedido é a página pública de campanha; se marketing quiser site-wide, item futuro.
|
||||
- Conversions API (CAPI) / Advanced Matching / dedup `eventID` — herda os gatilhos do plano da petição.
|
||||
- Cookie banner/CMP, GTM, TikTok/Google pixels.
|
||||
- Uniqueness de Dataset — mesmo ID pode aparecer na petição e na home.
|
||||
|
||||
## Rabbit holes de produto
|
||||
|
||||
- **Colar snippet HTML "como o Meta manda".** XSS + HTML no CMS. **Corte:** campo só ID + description + validação server-side, idêntico ao precedente aceito.
|
||||
- **Pixel em tudo.** "Já que o campo existe, coloca em todas as páginas". **Corte:** só a home de campanha; site-wide é decisão separada de produto.
|
||||
- **CAPI "já que estamos no servidor".** Secrets, hashing PII, dedup, retries. **Corte:** fora, herda os gatilhos do plano da petição.
|
||||
|
||||
## Questões em aberto (produto)
|
||||
|
||||
- **Evento `Lead` no sucesso do form de captura?** Confirmado com produto em 2026-08-19: **sim** — PageView no load + `Lead` no sucesso da captura (S9), réplica do precedente da petição.
|
||||
- **Onde o campo mora?** **Opções:** (a) global `SiteSettings` (Configurações do site) | (b) novo global dedicado de rastreamento. **Recomendação:** (a) — dono existente com revalidação pronta; o plano da petição já o apontava como destino natural de um Pixel global. _(assumido — validar com produto)_
|
||||
|
||||
## Referências
|
||||
|
||||
- `docs/plans/pixel-meta-abaixo-assinado.md` — precedente integral (decisões, gatilhos, rejeitados)
|
||||
- `src/collections/Petition.ts` — campo `tracking.facebookPixelId` + validação/normalização
|
||||
- `src/components/MetaPixel.tsx` + `src/lib/facebookPixel.ts` — base code e `trackMetaLead` (reuso)
|
||||
- `src/globals/SiteSettings.ts` — global provável dono do campo
|
||||
- `src/app/(frontend)/(home)/page.tsx` — home pública de campanha
|
||||
- S9 — form de captura de novidades (dependência do `Lead`)
|
||||
Loading…
Reference in a new issue